2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 #pragma warning(disable: 4005)
32 #include <rx/rx_prototypes.h>
33 #include <WINNT\afsreg.h>
37 #include "lanahelper.h"
39 #define STRSAFE_NO_DEPRECATE
42 /* These characters are illegal in Windows filenames */
43 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
45 static int smbShutdownFlag = 0;
46 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
48 int smb_LogoffTokenTransfer;
49 time_t smb_LogoffTransferTimeout;
51 int smb_StoreAnsiFilenames = 0;
53 DWORD last_msg_time = 0;
57 unsigned int sessionGen = 0;
59 extern void afsi_log(char *pattern, ...);
60 extern HANDLE afsi_file;
61 extern int powerStateSuspended;
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t smb_ListenerLock;
70 osi_mutex_t smb_StartedLock;
72 unsigned char smb_LANadapter = LANA_INVALID;
73 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
74 int smb_LanAdapterChangeDetected = 0;
75 afs_uint32 smb_AsyncStore = 1;
76 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
78 BOOL isGateway = FALSE;
81 long smb_maxObsConcurrentCalls=0;
82 long smb_concurrentCalls=0;
84 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
86 smb_packet_t *smb_packetFreeListp;
87 smb_ncb_t *smb_ncbFreeListp;
89 afs_uint32 smb_NumServerThreads;
91 afs_uint32 numNCBs, numSessions, numVCs;
93 int smb_maxVCPerServer;
94 int smb_maxMpxRequests;
96 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
98 ULONG smb_lsaSecPackage;
99 LSA_STRING smb_lsaLogonOrigin;
101 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
102 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
103 EVENT_HANDLE **NCBreturns;
104 EVENT_HANDLE **NCBShutdown;
105 EVENT_HANDLE *smb_ServerShutdown;
106 EVENT_HANDLE ListenerShutdown[256];
107 DWORD NCBsessions[NCB_MAX];
109 struct smb_packet *bufs[NCB_MAX];
111 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
112 EVENT_HANDLE SessionEvents[SESSION_MAX];
113 unsigned short LSNs[SESSION_MAX];
114 int lanas[SESSION_MAX];
115 BOOL dead_sessions[SESSION_MAX];
118 osi_mutex_t smb_RawBufLock;
121 #define SMB_MASKFLAG_TILDE 1
122 #define SMB_MASKFLAG_CASEFOLD 2
124 #define RAWTIMEOUT INFINITE
127 typedef struct raw_write_cont {
136 /* dir search stuff */
137 long smb_dirSearchCounter = 1;
138 smb_dirSearch_t *smb_firstDirSearchp;
139 smb_dirSearch_t *smb_lastDirSearchp;
141 /* Initial mode bits for files and directories. Set to 0 to use
143 int smb_unixModeDefaultFile = 0666;
144 int smb_unixModeDefaultDir = 0777;
146 /* hide dot files? */
147 int smb_hideDotFiles;
149 /* Negotiate Unicode support? */
152 /* global state about V3 protocols */
153 int smb_useV3; /* try to negotiate V3 */
155 static int showErrors = 0;
156 /* MessageBox or something like it */
157 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
161 * Time in Unix format of midnight, 1/1/1970 local time.
162 * When added to dosUTime, gives Unix (AFS) time.
164 time_t smb_localZero = 0;
166 char *smb_localNamep = NULL;
168 smb_vc_t *smb_allVCsp;
169 smb_vc_t *smb_deadVCsp;
171 smb_username_t *usernamesp = NULL;
173 smb_waitingLockRequest_t *smb_allWaitingLocks;
176 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
177 NCB *ncbp, raw_write_cont_t *rwcp);
178 int smb_NetbiosInit(int);
181 void smb_LogPacket(smb_packet_t *packet);
182 #endif /* LOG_PACKET */
184 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
185 int smb_ServerDomainNameLength = 0;
186 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
187 int smb_ServerOSLength = lengthof(smb_ServerOS);
188 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
189 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
191 /* Faux server GUID. This is never checked. */
192 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
194 void smb_InitReq(cm_req_t *reqp)
197 reqp->flags |= CM_REQ_SOURCE_SMB;
200 const char * ncb_error_string(int code)
204 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
205 case 0x03: s = "NRC_ILLCMD illegal command"; break;
206 case 0x05: s = "NRC_CMDTMO command timed out"; break;
207 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
208 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
209 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
210 case 0x09: s = "NRC_NORES no resource available"; break;
211 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
212 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
213 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
214 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
215 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
216 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
217 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
218 case 0x13: s = "NRC_ILLNN illegal name number"; break;
219 case 0x14: s = "NRC_NOCALL no callname"; break;
220 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
221 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
222 case 0x17: s = "NRC_NAMERR name deleted"; break;
223 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
224 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
225 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
226 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
227 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
228 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
229 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
230 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
231 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
232 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
233 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
234 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
235 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
236 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
237 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
238 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
239 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
240 case 0x40: s = "NRC_SYSTEM system error"; break;
241 default: s = "unknown error";
247 char * myCrt_Dispatch(int i)
252 return "(00)ReceiveCoreMakeDir";
254 return "(01)ReceiveCoreRemoveDir";
256 return "(02)ReceiveCoreOpen";
258 return "(03)ReceiveCoreCreate";
260 return "(04)ReceiveCoreClose";
262 return "(05)ReceiveCoreFlush";
264 return "(06)ReceiveCoreUnlink";
266 return "(07)ReceiveCoreRename";
268 return "(08)ReceiveCoreGetFileAttributes";
270 return "(09)ReceiveCoreSetFileAttributes";
272 return "(0a)ReceiveCoreRead";
274 return "(0b)ReceiveCoreWrite";
276 return "(0c)ReceiveCoreLockRecord";
278 return "(0d)ReceiveCoreUnlockRecord";
280 return "(0e)SendCoreBadOp";
282 return "(0f)ReceiveCoreCreate";
284 return "(10)ReceiveCoreCheckPath";
286 return "(11)SendCoreBadOp";
288 return "(12)ReceiveCoreSeek";
290 return "(1a)ReceiveCoreReadRaw";
292 return "(1d)ReceiveCoreWriteRawDummy";
294 return "(22)ReceiveV3SetAttributes";
296 return "(23)ReceiveV3GetAttributes";
298 return "(24)ReceiveV3LockingX";
300 return "(25)ReceiveV3Trans";
302 return "(26)ReceiveV3Trans[aux]";
304 return "(29)SendCoreBadOp";
306 return "(2b)ReceiveCoreEcho";
308 return "(2d)ReceiveV3OpenX";
310 return "(2e)ReceiveV3ReadX";
312 return "(2f)ReceiveV3WriteX";
314 return "(32)ReceiveV3Tran2A";
316 return "(33)ReceiveV3Tran2A[aux]";
318 return "(34)ReceiveV3FindClose";
320 return "(35)ReceiveV3FindNotifyClose";
322 return "(70)ReceiveCoreTreeConnect";
324 return "(71)ReceiveCoreTreeDisconnect";
326 return "(72)ReceiveNegotiate";
328 return "(73)ReceiveV3SessionSetupX";
330 return "(74)ReceiveV3UserLogoffX";
332 return "(75)ReceiveV3TreeConnectX";
334 return "(80)ReceiveCoreGetDiskAttributes";
336 return "(81)ReceiveCoreSearchDir";
340 return "(83)FindUnique";
342 return "(84)FindClose";
344 return "(A0)ReceiveNTTransact";
346 return "(A2)ReceiveNTCreateX";
348 return "(A4)ReceiveNTCancel";
350 return "(A5)ReceiveNTRename";
352 return "(C0)OpenPrintFile";
354 return "(C1)WritePrintFile";
356 return "(C2)ClosePrintFile";
358 return "(C3)GetPrintQueue";
360 return "(D8)ReadBulk";
362 return "(D9)WriteBulk";
364 return "(DA)WriteBulkData";
366 return "unknown SMB op";
370 char * myCrt_2Dispatch(int i)
375 return "unknown SMB op-2";
377 return "S(00)CreateFile_ReceiveTran2Open";
379 return "S(01)FindFirst_ReceiveTran2SearchDir";
381 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
383 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
385 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
387 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
389 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
391 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
393 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
395 return "S(09)_ReceiveTran2FSCTL";
397 return "S(0a)_ReceiveTran2IOCTL";
399 return "S(0b)_ReceiveTran2FindNotifyFirst";
401 return "S(0c)_ReceiveTran2FindNotifyNext";
403 return "S(0d)_ReceiveTran2CreateDirectory";
405 return "S(0e)_ReceiveTran2SessionSetup";
407 return "S(0f)_QueryFileSystemInformationFid";
409 return "S(10)_ReceiveTran2GetDfsReferral";
411 return "S(11)_ReceiveTran2ReportDfsInconsistency";
415 char * myCrt_RapDispatch(int i)
420 return "unknown RAP OP";
422 return "RAP(0)NetShareEnum";
424 return "RAP(1)NetShareGetInfo";
426 return "RAP(13)NetServerGetInfo";
428 return "RAP(63)NetWkStaGetInfo";
432 char * myCrt_NmpipeDispatch(int i)
435 case SMB_TRANS_SET_NMPIPE_STATE:
436 return "SET NMPIPE STATE";
438 case SMB_TRANS_RAW_READ_NMPIPE:
439 return "RAW READ NMPIPE";
441 case SMB_TRANS_QUERY_NMPIPE_STATE:
442 return "QUERY NMPIPE STATE";
444 case SMB_TRANS_QUERY_NMPIPE_INFO:
445 return "QUERY NMPIPE INFO";
447 case SMB_TRANS_PEEK_NMPIPE:
448 return "PEEK NMPIPE";
450 case SMB_TRANS_TRANSACT_NMPIPE:
451 return "TRANSACT NMPIPE";
453 case SMB_TRANS_RAW_WRITE_NMPIPE:
454 return "WRITE NMPIPE";
456 case SMB_TRANS_READ_NMPIPE:
457 return "READ NMPIPE";
459 case SMB_TRANS_WRITE_NMPIPE:
460 return "WRITE NMPIPE";
462 case SMB_TRANS_WAIT_NMPIPE:
463 return "WAIT NMPIPE";
465 case SMB_TRANS_CALL_NMPIPE:
466 return "CALL NMPIPE";
471 /* scache must be locked */
472 unsigned int smb_Attributes(cm_scache_t *scp)
476 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
477 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
478 scp->fileType == CM_SCACHETYPE_INVALID)
480 attrs = SMB_ATTR_DIRECTORY;
481 #ifdef SPECIAL_FOLDERS
482 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
483 #endif /* SPECIAL_FOLDERS */
484 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
485 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
490 * We used to mark a file RO if it was in an RO volume, but that
491 * turns out to be impolitic in NT. See defect 10007.
494 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
495 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
497 if ((scp->unixModeBits & 0200) == 0)
498 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
504 void smb_SetInitialModeBitsForFile(int smb_attr, cm_attr_t * attr)
506 if (smb_unixModeDefaultFile != 0) {
507 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
508 attr->unixModeBits = smb_unixModeDefaultFile;
509 if (smb_attr & SMB_ATTR_READONLY)
510 attr->unixModeBits &= ~0222;
514 void smb_SetInitialModeBitsForDir(int smb_attr, cm_attr_t * attr)
516 if (smb_unixModeDefaultDir != 0) {
517 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
518 attr->unixModeBits = smb_unixModeDefaultDir;
522 /* Check if the named file/dir is a dotfile/dotdir */
523 /* String pointed to by lastComp can have leading slashes, but otherwise should have
524 no other patch components */
525 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
529 /* skip over slashes */
530 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
535 /* nulls, curdir and parent dir doesn't count */
541 if(*(s+1) == _C('.') && !*(s + 2))
548 static int ExtractBits(WORD bits, short start, short len)
555 num = bits << (16 - end);
556 num = num >> ((16 - end) + start);
561 void ShowUnixTime(char *FuncName, time_t unixTime)
566 cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
568 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
569 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
571 int day, month, year, sec, min, hour;
574 day = ExtractBits(wDate, 0, 5);
575 month = ExtractBits(wDate, 5, 4);
576 year = ExtractBits(wDate, 9, 7) + 1980;
578 sec = ExtractBits(wTime, 0, 5);
579 min = ExtractBits(wTime, 5, 6);
580 hour = ExtractBits(wTime, 11, 5);
582 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
583 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
587 /* Determine if we are observing daylight savings time */
588 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
590 TIME_ZONE_INFORMATION timeZoneInformation;
591 SYSTEMTIME utc, local, localDST;
593 /* Get the time zone info. NT uses this to calc if we are in DST. */
594 GetTimeZoneInformation(&timeZoneInformation);
596 /* Return the daylight bias */
597 *pDstBias = timeZoneInformation.DaylightBias;
599 /* Return the bias */
600 *pBias = timeZoneInformation.Bias;
602 /* Now determine if DST is being observed */
604 /* Get the UTC (GMT) time */
607 /* Convert UTC time to local time using the time zone info. If we are
608 observing DST, the calculated local time will include this.
610 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
612 /* Set the daylight bias to 0. The daylight bias is the amount of change
613 * in time that we use for daylight savings time. By setting this to 0
614 * we cause there to be no change in time during daylight savings time.
616 timeZoneInformation.DaylightBias = 0;
618 /* Convert the utc time to local time again, but this time without any
619 adjustment for daylight savings time.
621 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
623 /* If the two times are different, then it means that the localDST that
624 we calculated includes the daylight bias, and therefore we are
625 observing daylight savings time.
627 *pDST = localDST.wHour != local.wHour;
631 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
633 BOOL dst; /* Will be TRUE if observing DST */
634 LONG dstBias; /* Offset from local time if observing DST */
635 LONG bias; /* Offset from GMT for local time */
638 * This function will adjust the last write time to compensate
639 * for two bugs in the smb client:
641 * 1) During Daylight Savings Time, the LastWriteTime is ahead
642 * in time by the DaylightBias (ignoring the sign - the
643 * DaylightBias is always stored as a negative number). If
644 * the DaylightBias is -60, then the LastWriteTime will be
645 * ahead by 60 minutes.
647 * 2) If the local time zone is a positive offset from GMT, then
648 * the LastWriteTime will be the correct local time plus the
649 * Bias (ignoring the sign - a positive offset from GMT is
650 * always stored as a negative Bias). If the Bias is -120,
651 * then the LastWriteTime will be ahead by 120 minutes.
653 * These bugs can occur at the same time.
656 GetTimeZoneInfo(&dst, &dstBias, &bias);
658 /* First adjust for DST */
660 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
662 /* Now adjust for a positive offset from GMT (a negative bias). */
664 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
667 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
669 time_t diff_t = unixTime - smb_localZero;
670 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
671 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
673 *dosUTimep = (afs_uint32)diff_t;
676 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
678 *unixTimep = dosTime + smb_localZero;
681 void smb_MarkAllVCsDead(smb_vc_t * exclude)
684 smb_vc_t **vcp_to_cleanup = NULL;
685 int n_to_cleanup = 0;
688 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
690 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
691 lock_ObtainWrite(&smb_rctLock);
692 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
694 if (vcp->magic != SMB_VC_MAGIC)
695 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
701 lock_ObtainMutex(&vcp->mx);
702 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
703 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
704 lock_ReleaseMutex(&vcp->mx);
705 dead_sessions[vcp->session] = TRUE;
707 lock_ReleaseMutex(&vcp->mx);
712 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
714 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
718 vcp_to_cleanup[i++] = vcp;
719 smb_HoldVCNoLock(vcp);
722 osi_assert(i == n_to_cleanup);
724 lock_ReleaseWrite(&smb_rctLock);
725 lock_ReleaseWrite(&smb_globalLock);
727 for (i=0; i < n_to_cleanup; i++) {
728 smb_CleanupDeadVC(vcp_to_cleanup[i]);
729 smb_ReleaseVC(vcp_to_cleanup[i]);
730 vcp_to_cleanup[i] = 0;
733 free(vcp_to_cleanup);
736 #ifdef DEBUG_SMB_REFCOUNT
737 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
739 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
744 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
745 lock_ObtainWrite(&smb_rctLock);
746 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
747 if (vcp->magic != SMB_VC_MAGIC)
748 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
751 lock_ObtainMutex(&vcp->mx);
752 if (lsn == vcp->lsn && lana == vcp->lana &&
753 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
754 lock_ReleaseMutex(&vcp->mx);
755 smb_HoldVCNoLock(vcp);
758 lock_ReleaseMutex(&vcp->mx);
760 if (!vcp && (flags & SMB_FLAG_CREATE)) {
761 vcp = malloc(sizeof(*vcp));
762 memset(vcp, 0, sizeof(*vcp));
763 vcp->vcID = ++numVCs;
764 vcp->magic = SMB_VC_MAGIC;
765 vcp->refCount = 2; /* smb_allVCsp and caller */
768 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
769 vcp->nextp = smb_allVCsp;
771 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
776 if (smb_authType == SMB_AUTH_NTLM) {
777 /* We must obtain a challenge for extended auth
778 * in case the client negotiates smb v3
780 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
781 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
782 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
783 ULONG lsaRespSize = 0;
785 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
787 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
794 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
795 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
796 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
797 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
798 nts, ntsEx, lsaRespSize);
800 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
802 if (ntsEx == STATUS_SUCCESS) {
803 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
806 * This will cause the subsequent authentication to fail but
807 * that is better than us dereferencing a NULL pointer and
810 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
813 LsaFreeReturnBuffer(lsaResp);
816 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
818 if (numVCs >= CM_SESSION_RESERVED) {
820 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
823 #ifdef DEBUG_SMB_REFCOUNT
825 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
826 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
829 lock_ReleaseWrite(&smb_rctLock);
830 lock_ReleaseWrite(&smb_globalLock);
834 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
839 for(i=0; i<11; i++) {
841 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
847 static int smb_IsStarMask(clientchar_t *maskp)
853 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
859 #ifdef DEBUG_SMB_REFCOUNT
860 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
861 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
863 void smb_ReleaseVCInternal(smb_vc_t *vcp)
869 lock_AssertWrite(&smb_rctLock);
872 if (vcp->refCount == 0) {
873 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
874 #ifdef DEBUG_SMB_REFCOUNT
875 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
876 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
878 /* remove VCP from smb_deadVCsp */
879 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
885 lock_FinalizeMutex(&vcp->mx);
886 memset(vcp,0,sizeof(smb_vc_t));
889 #ifdef DEBUG_SMB_REFCOUNT
890 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
892 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
896 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
897 avcp?"":"not ",vcp, vcp->refCount);
899 /* This is a wrong. However, I suspect that there is an undercount
900 * and I don't want to release 1.4.1 in a state that will allow
901 * smb_vc_t objects to be deallocated while still in the
902 * smb_allVCsp list. The list is supposed to keep a reference
903 * to the smb_vc_t. Put it back.
907 #ifdef DEBUG_SMB_REFCOUNT
908 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
909 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
913 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
914 /* The reference count is non-zero but the VC is dead.
915 * This implies that some FIDs, TIDs, etc on the VC have yet to
916 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
917 * add a reference that will be dropped by
918 * smb_CleanupDeadVC() and try to cleanup the VC again.
919 * Eventually the refCount will drop to zero when all of the
920 * active threads working with the VC end their task.
922 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
923 vcp->refCount++; /* put the refCount back */
924 lock_ReleaseWrite(&smb_rctLock);
925 smb_CleanupDeadVC(vcp);
926 #ifdef DEBUG_SMB_REFCOUNT
927 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
928 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
930 lock_ObtainWrite(&smb_rctLock);
933 #ifdef DEBUG_SMB_REFCOUNT
934 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
935 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
940 #ifdef DEBUG_SMB_REFCOUNT
941 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
943 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
946 lock_AssertWrite(&smb_rctLock);
947 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
948 smb_ReleaseVCInternal(vcp);
951 #ifdef DEBUG_SMB_REFCOUNT
952 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
954 void smb_ReleaseVC(smb_vc_t *vcp)
957 lock_ObtainWrite(&smb_rctLock);
958 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
959 smb_ReleaseVCInternal(vcp);
960 lock_ReleaseWrite(&smb_rctLock);
963 #ifdef DEBUG_SMB_REFCOUNT
964 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
966 void smb_HoldVCNoLock(smb_vc_t *vcp)
969 lock_AssertWrite(&smb_rctLock);
971 #ifdef DEBUG_SMB_REFCOUNT
972 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
973 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
975 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
979 #ifdef DEBUG_SMB_REFCOUNT
980 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
982 void smb_HoldVC(smb_vc_t *vcp)
985 lock_ObtainWrite(&smb_rctLock);
987 #ifdef DEBUG_SMB_REFCOUNT
988 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
989 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
991 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
993 lock_ReleaseWrite(&smb_rctLock);
996 void smb_CleanupDeadVC(smb_vc_t *vcp)
1001 smb_tid_t *tidpIter;
1002 smb_tid_t *tidpNext;
1004 smb_user_t *uidpIter;
1005 smb_user_t *uidpNext;
1007 afs_uint32 refCount = 0;
1009 lock_ObtainMutex(&vcp->mx);
1010 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1011 lock_ReleaseMutex(&vcp->mx);
1012 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1015 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1016 lock_ReleaseMutex(&vcp->mx);
1017 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1019 lock_ObtainWrite(&smb_rctLock);
1020 /* remove VCP from smb_allVCsp */
1021 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1022 if ((*vcpp)->magic != SMB_VC_MAGIC)
1023 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1024 __FILE__, __LINE__);
1027 vcp->nextp = smb_deadVCsp;
1029 /* Hold onto the reference until we are done with this function */
1034 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1035 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1037 if (fidpIter->deleteOk)
1040 fid = fidpIter->fid;
1041 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1043 smb_HoldFIDNoLock(fidpIter);
1044 lock_ReleaseWrite(&smb_rctLock);
1046 smb_CloseFID(vcp, fidpIter, NULL, 0);
1047 smb_ReleaseFID(fidpIter);
1049 lock_ObtainWrite(&smb_rctLock);
1050 fidpNext = vcp->fidsp;
1053 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1054 tidpNext = tidpIter->nextp;
1055 if (tidpIter->deleteOk)
1057 tidpIter->deleteOk = 1;
1059 tid = tidpIter->tid;
1060 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1062 smb_HoldTIDNoLock(tidpIter);
1063 smb_ReleaseTID(tidpIter, TRUE);
1064 tidpNext = vcp->tidsp;
1067 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1068 uidpNext = uidpIter->nextp;
1069 if (uidpIter->deleteOk)
1071 uidpIter->deleteOk = 1;
1073 /* do not add an additional reference count for the smb_user_t
1074 * as the smb_vc_t already is holding a reference */
1075 lock_ReleaseWrite(&smb_rctLock);
1077 smb_ReleaseUID(uidpIter);
1079 lock_ObtainWrite(&smb_rctLock);
1080 uidpNext = vcp->usersp;
1083 /* The vcp is now on the deadVCsp list. We intentionally drop the
1084 * reference so that the refcount can reach 0 and we can delete it
1086 * If the refCount == 1 going into the ReleaseVCNoLock call
1087 * the object will be freed and it won't be safe to clear
1090 refCount = vcp->refCount;
1091 smb_ReleaseVCNoLock(vcp);
1093 lock_ObtainMutex(&vcp->mx);
1094 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1095 lock_ReleaseMutex(&vcp->mx);
1098 lock_ReleaseWrite(&smb_rctLock);
1099 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1102 #ifdef DEBUG_SMB_REFCOUNT
1103 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1105 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1110 lock_ObtainWrite(&smb_rctLock);
1112 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1113 if (tidp->refCount == 0 && tidp->deleteOk) {
1115 smb_ReleaseTID(tidp, TRUE);
1119 if (tid == tidp->tid) {
1124 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1125 tidp = malloc(sizeof(*tidp));
1126 memset(tidp, 0, sizeof(*tidp));
1127 tidp->nextp = vcp->tidsp;
1130 smb_HoldVCNoLock(vcp);
1132 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1135 #ifdef DEBUG_SMB_REFCOUNT
1137 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1138 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1141 lock_ReleaseWrite(&smb_rctLock);
1145 #ifdef DEBUG_SMB_REFCOUNT
1146 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1148 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1151 lock_AssertWrite(&smb_rctLock);
1153 #ifdef DEBUG_SMB_REFCOUNT
1154 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1155 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1159 #ifdef DEBUG_SMB_REFCOUNT
1160 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1162 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1167 cm_user_t *userp = NULL;
1168 smb_vc_t *vcp = NULL;
1171 lock_ObtainWrite(&smb_rctLock);
1173 lock_AssertWrite(&smb_rctLock);
1175 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1176 #ifdef DEBUG_SMB_REFCOUNT
1177 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1178 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1180 if (tidp->refCount == 0) {
1181 if (tidp->deleteOk) {
1182 ltpp = &tidp->vcp->tidsp;
1183 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1187 osi_assertx(tp != NULL, "null smb_tid_t");
1189 lock_FinalizeMutex(&tidp->mx);
1190 userp = tidp->userp; /* remember to drop ref later */
1198 smb_ReleaseVCNoLock(vcp);
1200 lock_ReleaseWrite(&smb_rctLock);
1202 cm_ReleaseUser(userp);
1205 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1207 smb_user_t *uidp = NULL;
1209 lock_ObtainWrite(&smb_rctLock);
1210 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1211 if (uid == uidp->userID) {
1213 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1215 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1219 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1220 uidp = malloc(sizeof(*uidp));
1221 memset(uidp, 0, sizeof(*uidp));
1222 uidp->nextp = vcp->usersp;
1223 uidp->refCount = 2; /* one for the vcp and one for the caller */
1225 smb_HoldVCNoLock(vcp);
1227 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1229 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1231 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1233 lock_ReleaseWrite(&smb_rctLock);
1237 afs_int32 smb_userIsLocalSystem(smb_user_t *uidp)
1240 DWORD dwSize1 = 0, dwSize2 = 0;
1241 wchar_t *pszRefDomain = NULL;
1242 SID_NAME_USE snu = SidTypeGroup;
1243 clientchar_t * secSidString = NULL;
1245 afs_int32 isSystem = 0;
1247 if (uidp->unp->flags & SMB_USERNAMEFLAG_SID) {
1248 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, uidp->unp->name);
1253 * The input name is not a SID for the user. See if we can
1254 * obtain the SID for the specified name. If we can, use
1255 * that instead of the name provided for the comparison.
1258 LookupAccountNameW( NULL /* System Name to begin Search */,
1263 gle = GetLastError();
1264 if (gle == ERROR_INSUFFICIENT_BUFFER) {
1265 pSid = malloc(dwSize1);
1267 * Although dwSize2 is supposed to include the terminating
1268 * NUL character, on Win7 it does not.
1270 pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
1273 if ( pSid && pszRefDomain ) {
1274 memset(pSid, 0, dwSize1);
1276 if (LookupAccountNameW( NULL /* System Name to begin Search */,
1279 pszRefDomain, &dwSize2,
1281 ConvertSidToStringSidW(pSid, &secSidString);
1285 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, secSidString);
1286 LocalFree(secSidString);
1297 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1300 smb_username_t *unp= NULL;
1302 lock_ObtainWrite(&smb_rctLock);
1303 for(unp = usernamesp; unp; unp = unp->nextp) {
1304 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1305 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1310 if (!unp && (flags & SMB_FLAG_CREATE)) {
1311 unp = malloc(sizeof(*unp));
1312 memset(unp, 0, sizeof(*unp));
1314 unp->nextp = usernamesp;
1315 unp->name = cm_ClientStrDup(usern);
1316 unp->machine = cm_ClientStrDup(machine);
1318 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1319 if (flags & SMB_FLAG_AFSLOGON)
1320 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1323 lock_ReleaseWrite(&smb_rctLock);
1327 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1329 smb_user_t *uidp= NULL;
1331 lock_ObtainWrite(&smb_rctLock);
1332 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1335 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1337 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1338 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1343 lock_ReleaseWrite(&smb_rctLock);
1347 void smb_ReleaseUsername(smb_username_t *unp)
1350 smb_username_t **lupp;
1351 cm_user_t *userp = NULL;
1352 time_t now = osi_Time();
1354 lock_ObtainWrite(&smb_rctLock);
1355 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1356 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1357 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1359 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1363 osi_assertx(up != NULL, "null smb_username_t");
1365 up->nextp = NULL; /* do not remove this */
1366 lock_FinalizeMutex(&unp->mx);
1372 lock_ReleaseWrite(&smb_rctLock);
1374 cm_ReleaseUser(userp);
1377 void smb_HoldUIDNoLock(smb_user_t *uidp)
1379 lock_AssertWrite(&smb_rctLock);
1383 void smb_ReleaseUID(smb_user_t *uidp)
1387 smb_username_t *unp = NULL;
1389 lock_ObtainWrite(&smb_rctLock);
1390 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1391 if (uidp->refCount == 0) {
1392 lupp = &uidp->vcp->usersp;
1393 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1397 osi_assertx(up != NULL, "null smb_user_t");
1399 lock_FinalizeMutex(&uidp->mx);
1401 smb_ReleaseVCNoLock(uidp->vcp);
1405 lock_ReleaseWrite(&smb_rctLock);
1409 cm_ReleaseUserVCRef(unp->userp);
1410 smb_ReleaseUsername(unp);
1414 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1416 cm_user_t *up = NULL;
1421 lock_ObtainMutex(&uidp->mx);
1423 up = uidp->unp->userp;
1426 lock_ReleaseMutex(&uidp->mx);
1432 /* retrieve a held reference to a user structure corresponding to an incoming
1434 * corresponding release function is cm_ReleaseUser.
1436 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1439 cm_user_t *up = NULL;
1442 smbp = (smb_t *) inp;
1443 uidp = smb_FindUID(vcp, smbp->uid, 0);
1447 up = smb_GetUserFromUID(uidp);
1449 smb_ReleaseUID(uidp);
1454 * Return a pointer to a pathname extracted from a TID structure. The
1455 * TID structure is not held; assume it won't go away.
1457 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1462 tidp = smb_FindTID(vcp, tid, 0);
1466 if (tidp->flags & SMB_TIDFLAG_IPC) {
1467 code = CM_ERROR_TIDIPC;
1468 /* tidp->pathname would be NULL, but that's fine */
1470 *treepath = tidp->pathname;
1471 smb_ReleaseTID(tidp, FALSE);
1476 /* check to see if we have a chained fid, that is, a fid that comes from an
1477 * OpenAndX message that ran earlier in this packet. In this case, the fid
1478 * field in a read, for example, request, isn't set, since the value is
1479 * supposed to be inherited from the openAndX call.
1481 int smb_ChainFID(int fid, smb_packet_t *inp)
1483 if (inp->fid == 0 || inp->inCount == 0)
1489 /* are we a priv'd user? What does this mean on NT? */
1490 int smb_SUser(cm_user_t *userp)
1495 /* find a file ID. If we pass in 0 we select an unused File ID.
1496 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1497 * smb_fid_t data structure if desired File ID cannot be found.
1499 #ifdef DEBUG_SMB_REFCOUNT
1500 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1502 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1509 if (!(flags & SMB_FLAG_CREATE))
1514 lock_ObtainWrite(&smb_rctLock);
1516 fid = vcp->fidCounter;
1519 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1520 if (fidp->refCount == 0 && fidp->deleteOk) {
1522 lock_ReleaseWrite(&smb_rctLock);
1523 smb_ReleaseFID(fidp);
1524 lock_ObtainWrite(&smb_rctLock);
1526 * We dropped the smb_rctLock so the fid value we are using
1527 * may now be used by another thread. Start over with the
1528 * current vcp->fidCounter.
1531 fid = vcp->fidCounter;
1534 if (fid == fidp->fid) {
1536 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1538 if (fid == 0xFFFF) {
1540 "New FID number wraps on vcp 0x%x", vcp);
1550 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1551 char eventName[MAX_PATH];
1555 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1557 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1559 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1560 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1561 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1562 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1563 thrd_CloseHandle(event);
1565 if (fid == 0xFFFF) {
1566 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1572 fidp = malloc(sizeof(*fidp));
1573 memset(fidp, 0, sizeof(*fidp));
1574 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1577 smb_HoldVCNoLock(vcp);
1578 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1580 fidp->curr_chunk = fidp->prev_chunk = -2;
1581 fidp->raw_write_event = event;
1583 vcp->fidCounter = fid+1;
1584 if (vcp->fidCounter == 0xFFFF) {
1585 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1587 vcp->fidCounter = 1;
1592 #ifdef DEBUG_SMB_REFCOUNT
1594 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1598 lock_ReleaseWrite(&smb_rctLock);
1603 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1604 #ifdef DEBUG_SMB_REFCOUNT
1605 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1607 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1610 smb_fid_t *fidp = NULL, *nextp = NULL;
1616 * If the fidp->scp changes out from under us then
1617 * we must not grab a refCount. It means the *fidp
1618 * was processed by smb_CloseFID() and the *fidp is
1619 * no longer valid for use.
1621 lock_ObtainWrite(&smb_rctLock);
1622 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1623 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1627 if (scp == fidp->scp) {
1628 lock_ReleaseWrite(&smb_rctLock);
1629 lock_ObtainMutex(&fidp->mx);
1630 lock_ObtainWrite(&smb_rctLock);
1631 if (scp == fidp->scp) {
1632 lock_ReleaseMutex(&fidp->mx);
1635 lock_ReleaseMutex(&fidp->mx);
1638 if (fidp->refCount > 1) {
1641 lock_ReleaseWrite(&smb_rctLock);
1642 smb_ReleaseFID(fidp);
1643 lock_ObtainWrite(&smb_rctLock);
1648 if (nextp->refCount > 1) {
1651 lock_ReleaseWrite(&smb_rctLock);
1652 smb_ReleaseFID(nextp);
1653 lock_ObtainWrite(&smb_rctLock);
1657 #ifdef DEBUG_SMB_REFCOUNT
1659 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1660 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1663 lock_ReleaseWrite(&smb_rctLock);
1667 #ifdef DEBUG_SMB_REFCOUNT
1668 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1670 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1673 lock_AssertWrite(&smb_rctLock);
1675 #ifdef DEBUG_SMB_REFCOUNT
1676 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1677 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1682 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1683 /* the smb_fid_t->mx and smb_rctLock must not be held */
1684 #ifdef DEBUG_SMB_REFCOUNT
1685 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1687 void smb_ReleaseFID(smb_fid_t *fidp)
1690 cm_scache_t *scp = NULL;
1691 cm_user_t *userp = NULL;
1692 smb_vc_t *vcp = NULL;
1693 smb_ioctl_t *ioctlp;
1695 lock_ObtainMutex(&fidp->mx);
1696 lock_ObtainWrite(&smb_rctLock);
1697 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1698 #ifdef DEBUG_SMB_REFCOUNT
1699 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1700 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1702 if (fidp->refCount == 0) {
1703 if (fidp->deleteOk) {
1706 scp = fidp->scp; /* release after lock is released */
1708 lock_ObtainWrite(&scp->rw);
1709 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1710 lock_ReleaseWrite(&scp->rw);
1711 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1714 userp = fidp->userp;
1718 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1719 thrd_CloseHandle(fidp->raw_write_event);
1721 /* and see if there is ioctl stuff to free */
1722 ioctlp = fidp->ioctlp;
1725 cm_FreeSpace(ioctlp->prefix);
1726 if (ioctlp->ioctl.inAllocp)
1727 free(ioctlp->ioctl.inAllocp);
1728 if (ioctlp->ioctl.outAllocp)
1729 free(ioctlp->ioctl.outAllocp);
1733 smb_CleanupRPCFid(fidp);
1735 lock_ReleaseMutex(&fidp->mx);
1736 lock_FinalizeMutex(&fidp->mx);
1741 smb_ReleaseVCNoLock(vcp);
1745 lock_ReleaseMutex(&fidp->mx);
1747 lock_ReleaseWrite(&smb_rctLock);
1749 /* now release the scache structure */
1751 cm_ReleaseSCache(scp);
1754 cm_ReleaseUser(userp);
1758 * Case-insensitive search for one string in another;
1759 * used to find variable names in submount pathnames.
1761 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1763 clientchar_t *cursor;
1765 for (cursor = str1; *cursor; cursor++)
1766 if (cm_ClientStrCmpI(cursor, str2) == 0)
1773 * Substitute a variable value for its name in a submount pathname. Variable
1774 * name has been identified by smb_stristr() and is in substr. Variable name
1775 * length (plus one) is in substr_size. Variable value is in newstr.
1777 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1778 unsigned int substr_size, clientchar_t *newstr)
1780 clientchar_t temp[1024];
1782 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1783 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1784 cm_ClientStrCat(str1, cchstr1, temp);
1787 clientchar_t VNUserName[] = _C("%USERNAME%");
1788 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1789 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1790 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1792 typedef struct smb_findShare_rock {
1793 clientchar_t * shareName;
1794 clientchar_t * match;
1796 } smb_findShare_rock_t;
1798 #define SMB_FINDSHARE_EXACT_MATCH 1
1799 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1801 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1805 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1806 normchar_t normName[MAX_PATH];
1808 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1809 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1810 osi_LogSaveString(smb_logp, dep->name));
1814 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1815 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1816 matchType = SMB_FINDSHARE_EXACT_MATCH;
1818 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1821 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1822 vrock->matchType = matchType;
1824 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1825 return CM_ERROR_STOPNOW;
1831 /* find a shareName in the table of submounts */
1832 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1833 clientchar_t *shareName,
1834 clientchar_t **pathNamep)
1838 clientchar_t pathName[1024];
1841 clientchar_t *p, *q;
1842 fschar_t *cellname = NULL;
1845 DWORD allSubmount = 1;
1847 /* if allSubmounts == 0, only return the //mountRoot/all share
1848 * if in fact it has been been created in the subMounts table.
1849 * This is to allow sites that want to restrict access to the
1852 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1853 0, KEY_QUERY_VALUE, &parmKey);
1854 if (code == ERROR_SUCCESS) {
1855 cblen = sizeof(allSubmount);
1856 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1857 (BYTE *) &allSubmount, &cblen);
1858 if (code != ERROR_SUCCESS) {
1861 RegCloseKey (parmKey);
1864 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1869 /* In case, the all share is disabled we need to still be able
1870 * to handle ioctl requests
1872 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1873 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1877 if (MSRPC_IsWellKnownService(shareName) ||
1878 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1879 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1885 /* Check for volume references
1887 * They look like <cell>{%,#}<volume>
1889 if (cm_ClientStrChr(shareName, '%') != NULL ||
1890 cm_ClientStrChr(shareName, '#') != NULL) {
1891 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1892 /* make room for '/@vol:' + mountchar + NULL terminator*/
1894 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1895 osi_LogSaveClientString(smb_logp, shareName));
1897 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1898 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1899 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1901 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1903 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1904 cm_ClientStrLwr(*pathNamep);
1905 osi_Log1(smb_logp, " returning pathname [%S]",
1906 osi_LogSaveClientString(smb_logp, *pathNamep));
1914 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1915 0, KEY_QUERY_VALUE, &parmKey);
1916 if (code == ERROR_SUCCESS) {
1917 cblen = sizeof(pathName);
1918 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1919 (BYTE *) pathName, &cblen);
1920 if (code != ERROR_SUCCESS)
1922 RegCloseKey (parmKey);
1926 cchlen = cblen / sizeof(clientchar_t);
1927 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1928 /* We can accept either unix or PC style AFS pathnames. Convert
1929 * Unix-style to PC style here for internal use.
1932 cchlen = lengthof(pathName);
1934 /* within this code block, we maintain, cchlen = writable
1935 buffer length of p */
1937 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1938 p += cm_mountRootCLen; /* skip mount path */
1939 cchlen -= (DWORD)(p - pathName);
1944 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1950 clientchar_t temp[1024];
1952 if (var = smb_stristr(p, VNUserName)) {
1953 if (uidp && uidp->unp)
1954 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1956 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1958 else if (var = smb_stristr(p, VNLCUserName))
1960 if (uidp && uidp->unp)
1961 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1963 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1964 cm_ClientStrLwr(temp);
1965 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1967 else if (var = smb_stristr(p, VNComputerName))
1969 sizeTemp = lengthof(temp);
1970 GetComputerNameW(temp, &sizeTemp);
1971 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1973 else if (var = smb_stristr(p, VNLCComputerName))
1975 sizeTemp = lengthof(temp);
1976 GetComputerName((LPTSTR)temp, &sizeTemp);
1977 cm_ClientStrLwr(temp);
1978 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1983 *pathNamep = cm_ClientStrDup(p);
1988 /* First lookup shareName in root.afs */
1990 smb_findShare_rock_t vrock;
1992 fschar_t ftemp[1024];
1993 clientchar_t * p = shareName;
1998 /* attempt to locate a partial match in root.afs. This is because
1999 when using the ANSI RAP calls, the share name is limited to 13 chars
2000 and hence is truncated. Of course we prefer exact matches. */
2002 thyper.HighPart = 0;
2005 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2006 if (vrock.shareName == NULL)
2009 vrock.matchType = 0;
2011 userp = (uidp? (uidp->unp ? uidp->unp->userp : cm_rootUserp) : cm_rootUserp);
2012 rscp = cm_RootSCachep(userp, &req);
2013 cm_HoldSCache(rscp);
2014 code = cm_ApplyDir(rscp, smb_FindShareProc, &vrock, &thyper,
2016 cm_ReleaseSCache(rscp);
2018 free(vrock.shareName);
2019 vrock.shareName = NULL;
2021 if (vrock.matchType) {
2022 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2023 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2028 /* if we get here, there was no match for the share in root.afs */
2029 /* so try to create \\<netbiosName>\<cellname> */
2034 /* Get the full name for this cell */
2035 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2036 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2037 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2038 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2039 if (code && cm_dnsEnabled) {
2041 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2046 /* construct the path */
2048 clientchar_t temp[1024];
2050 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2051 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2052 rw ? _C("/.%S/") : _C("/%S/"), temp);
2053 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2063 /* Client-side offline caching policy types */
2064 #define CSC_POLICY_MANUAL 0
2065 #define CSC_POLICY_DOCUMENTS 1
2066 #define CSC_POLICY_PROGRAMS 2
2067 #define CSC_POLICY_DISABLE 3
2069 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2072 clientchar_t policy[1024];
2075 int retval = CSC_POLICY_MANUAL;
2077 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2078 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2081 REG_OPTION_NON_VOLATILE,
2085 NULL ) != ERROR_SUCCESS)
2086 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2088 len = sizeof(policy);
2089 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2091 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2093 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2095 retval = CSC_POLICY_MANUAL;
2097 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2099 retval = CSC_POLICY_DOCUMENTS;
2101 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2103 retval = CSC_POLICY_PROGRAMS;
2105 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2107 retval = CSC_POLICY_DISABLE;
2110 RegCloseKey(hkCSCPolicy);
2114 /* find a dir search structure by cookie value, and return it held.
2115 * Must be called with smb_globalLock held.
2117 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2119 smb_dirSearch_t *dsp;
2121 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2122 if (dsp->cookie == cookie) {
2123 if (dsp != smb_firstDirSearchp) {
2124 /* move to head of LRU queue, too, if we're not already there */
2125 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2126 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2127 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2128 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2129 if (!smb_lastDirSearchp)
2130 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2138 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2139 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2140 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2146 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2148 lock_ObtainMutex(&dsp->mx);
2149 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2150 dsp->cookie, dsp, dsp->scp);
2151 dsp->flags |= SMB_DIRSEARCH_DELETE;
2152 if (dsp->scp != NULL) {
2153 lock_ObtainWrite(&dsp->scp->rw);
2154 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2155 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2156 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2157 dsp->scp->bulkStatProgress = hzero;
2159 lock_ReleaseWrite(&dsp->scp->rw);
2161 lock_ReleaseMutex(&dsp->mx);
2164 /* Must be called with the smb_globalLock held */
2165 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2167 cm_scache_t *scp = NULL;
2169 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2170 if (dsp->refCount == 0) {
2171 lock_ObtainMutex(&dsp->mx);
2172 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2173 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2174 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2175 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2176 lock_ReleaseMutex(&dsp->mx);
2177 lock_FinalizeMutex(&dsp->mx);
2179 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2180 dsp->cookie, dsp, scp);
2183 lock_ReleaseMutex(&dsp->mx);
2186 /* do this now to avoid spurious locking hierarchy creation */
2188 cm_ReleaseSCache(scp);
2191 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2193 lock_ObtainWrite(&smb_globalLock);
2194 smb_ReleaseDirSearchNoLock(dsp);
2195 lock_ReleaseWrite(&smb_globalLock);
2198 /* find a dir search structure by cookie value, and return it held */
2199 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2201 smb_dirSearch_t *dsp;
2203 lock_ObtainWrite(&smb_globalLock);
2204 dsp = smb_FindDirSearchNoLock(cookie);
2205 lock_ReleaseWrite(&smb_globalLock);
2209 /* GC some dir search entries, in the address space expected by the specific protocol.
2210 * Must be called with smb_globalLock held; release the lock temporarily.
2212 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2213 void smb_GCDirSearches(int isV3)
2215 smb_dirSearch_t *prevp;
2216 smb_dirSearch_t *dsp;
2217 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2221 victimCount = 0; /* how many have we got so far */
2222 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2223 /* we'll move tp from queue, so
2226 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2227 /* if no one is using this guy, and we're either in the new protocol,
2228 * or we're in the old one and this is a small enough ID to be useful
2229 * to the old protocol, GC this guy.
2231 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2232 /* hold and delete */
2233 lock_ObtainMutex(&dsp->mx);
2234 dsp->flags |= SMB_DIRSEARCH_DELETE;
2235 lock_ReleaseMutex(&dsp->mx);
2236 victimsp[victimCount++] = dsp;
2240 /* don't do more than this */
2241 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2245 /* now release them */
2246 for (i = 0; i < victimCount; i++) {
2247 smb_ReleaseDirSearchNoLock(victimsp[i]);
2251 /* function for allocating a dir search entry. We need these to remember enough context
2252 * since we don't get passed the path from call to call during a directory search.
2254 * Returns a held dir search structure, and bumps the reference count on the vnode,
2255 * since it saves a pointer to the vnode.
2257 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2259 smb_dirSearch_t *dsp;
2265 lock_ObtainWrite(&smb_globalLock);
2268 /* what's the biggest ID allowed in this version of the protocol */
2269 /* TODO: do we really want a non v3 dir search request to wrap
2270 smb_dirSearchCounter? */
2271 maxAllowed = isV3 ? 65535 : 255;
2272 if (smb_dirSearchCounter > maxAllowed)
2273 smb_dirSearchCounter = 1;
2275 start = smb_dirSearchCounter;
2278 /* twice so we have enough tries to find guys we GC after one pass;
2279 * 10 extra is just in case I mis-counted.
2281 if (++counter > 2*maxAllowed+10)
2282 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2284 if (smb_dirSearchCounter > maxAllowed) {
2285 smb_dirSearchCounter = 1;
2287 if (smb_dirSearchCounter == start) {
2289 smb_GCDirSearches(isV3);
2292 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2294 /* don't need to watch for refcount zero and deleted, since
2295 * we haven't dropped the global lock.
2298 ++smb_dirSearchCounter;
2302 dsp = malloc(sizeof(*dsp));
2303 memset(dsp, 0, sizeof(*dsp));
2304 dsp->cookie = smb_dirSearchCounter;
2305 ++smb_dirSearchCounter;
2307 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2308 dsp->lastTime = osi_Time();
2309 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2310 if (!smb_lastDirSearchp)
2311 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2313 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2317 lock_ReleaseWrite(&smb_globalLock);
2321 static smb_packet_t *smb_GetPacket(void)
2325 lock_ObtainWrite(&smb_globalLock);
2326 tbp = smb_packetFreeListp;
2328 smb_packetFreeListp = tbp->nextp;
2329 lock_ReleaseWrite(&smb_globalLock);
2331 tbp = calloc(sizeof(*tbp),1);
2332 tbp->magic = SMB_PACKETMAGIC;
2335 tbp->resumeCode = 0;
2341 tbp->ncb_length = 0;
2344 tbp->stringsp = NULL;
2346 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2351 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2354 tbp = smb_GetPacket();
2355 memcpy(tbp, pkt, sizeof(smb_packet_t));
2356 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2357 tbp->stringsp = NULL;
2359 smb_HoldVC(tbp->vcp);
2363 static NCB *smb_GetNCB(void)
2368 lock_ObtainWrite(&smb_globalLock);
2369 tbp = smb_ncbFreeListp;
2371 smb_ncbFreeListp = tbp->nextp;
2372 lock_ReleaseWrite(&smb_globalLock);
2374 tbp = calloc(sizeof(*tbp),1);
2375 tbp->magic = SMB_NCBMAGIC;
2378 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2380 memset(&tbp->ncb, 0, sizeof(NCB));
2385 static void FreeSMBStrings(smb_packet_t * pkt)
2390 for (s = pkt->stringsp; s; s = ns) {
2394 pkt->stringsp = NULL;
2397 void smb_FreePacket(smb_packet_t *tbp)
2399 smb_vc_t * vcp = NULL;
2400 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2402 lock_ObtainWrite(&smb_globalLock);
2403 tbp->nextp = smb_packetFreeListp;
2404 smb_packetFreeListp = tbp;
2405 tbp->magic = SMB_PACKETMAGIC;
2409 tbp->resumeCode = 0;
2415 tbp->ncb_length = 0;
2417 FreeSMBStrings(tbp);
2418 lock_ReleaseWrite(&smb_globalLock);
2424 static void smb_FreeNCB(NCB *bufferp)
2428 tbp = (smb_ncb_t *) bufferp;
2429 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2431 lock_ObtainWrite(&smb_globalLock);
2432 tbp->nextp = smb_ncbFreeListp;
2433 smb_ncbFreeListp = tbp;
2434 lock_ReleaseWrite(&smb_globalLock);
2437 /* get a ptr to the data part of a packet, and its count */
2438 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2442 unsigned char *afterParmsp;
2444 parmBytes = *smbp->wctp << 1;
2445 afterParmsp = smbp->wctp + parmBytes + 1;
2447 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2448 if (nbytesp) *nbytesp = dataBytes;
2450 /* don't forget to skip the data byte count, since it follows
2451 * the parameters; that's where the "2" comes from below.
2453 return (unsigned char *) (afterParmsp + 2);
2456 /* must set all the returned parameters before playing around with the
2457 * data region, since the data region is located past the end of the
2458 * variable number of parameters.
2460 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2462 unsigned char *afterParmsp;
2464 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2466 *afterParmsp++ = dsize & 0xff;
2467 *afterParmsp = (dsize>>8) & 0xff;
2470 /* return the parm'th parameter in the smbp packet */
2471 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2474 unsigned char *parmDatap;
2476 parmCount = *smbp->wctp;
2478 if (parm >= parmCount) {
2481 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2482 parm, parmCount, smbp->ncb_length);
2483 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2484 parm, parmCount, smbp->ncb_length);
2485 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2486 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2487 osi_panic(s, __FILE__, __LINE__);
2489 parmDatap = smbp->wctp + (2*parm) + 1;
2491 return parmDatap[0] + (parmDatap[1] << 8);
2494 /* return the parm'th parameter in the smbp packet */
2495 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2498 unsigned char *parmDatap;
2500 parmCount = *smbp->wctp;
2502 if (parm >= parmCount) {
2505 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2506 parm, parmCount, smbp->ncb_length);
2507 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2508 parm, parmCount, smbp->ncb_length);
2509 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2510 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2511 osi_panic(s, __FILE__, __LINE__);
2513 parmDatap = smbp->wctp + (2*parm) + 1;
2515 return parmDatap[0];
2518 /* return the parm'th parameter in the smbp packet */
2519 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2522 unsigned char *parmDatap;
2524 parmCount = *smbp->wctp;
2526 if (parm + 1 >= parmCount) {
2529 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2530 parm, parmCount, smbp->ncb_length);
2531 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2532 parm, parmCount, smbp->ncb_length);
2533 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2534 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2535 osi_panic(s, __FILE__, __LINE__);
2537 parmDatap = smbp->wctp + (2*parm) + 1;
2539 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2542 /* return the parm'th parameter in the smbp packet */
2543 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2546 unsigned char *parmDatap;
2548 parmCount = *smbp->wctp;
2550 if (parm * 2 + offset >= parmCount * 2) {
2553 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2554 parm, offset, parmCount, smbp->ncb_length);
2555 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2556 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2557 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2558 parm, offset, parmCount, smbp->ncb_length);
2559 osi_panic(s, __FILE__, __LINE__);
2561 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2563 return parmDatap[0] + (parmDatap[1] << 8);
2566 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2568 unsigned char *parmDatap;
2570 /* make sure we have enough slots */
2571 if (*smbp->wctp <= slot)
2572 *smbp->wctp = slot+1;
2574 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2575 *parmDatap++ = parmValue & 0xff;
2576 *parmDatap = (parmValue>>8) & 0xff;
2579 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2581 unsigned char *parmDatap;
2583 /* make sure we have enough slots */
2584 if (*smbp->wctp <= slot)
2585 *smbp->wctp = slot+2;
2587 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2588 *parmDatap++ = parmValue & 0xff;
2589 *parmDatap++ = (parmValue>>8) & 0xff;
2590 *parmDatap++ = (parmValue>>16) & 0xff;
2591 *parmDatap = (parmValue>>24) & 0xff;
2594 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2596 unsigned char *parmDatap;
2599 /* make sure we have enough slots */
2600 if (*smbp->wctp <= slot)
2601 *smbp->wctp = slot+4;
2603 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2605 *parmDatap++ = *parmValuep++;
2608 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2610 unsigned char *parmDatap;
2612 /* make sure we have enough slots */
2613 if (*smbp->wctp <= slot) {
2614 if (smbp->oddByte) {
2616 *smbp->wctp = slot+1;
2621 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2622 *parmDatap++ = parmValue & 0xff;
2627 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2628 clientchar_t *inPathp)
2630 clientchar_t *lastSlashp;
2631 clientchar_t *streamp = NULL;
2632 clientchar_t *typep = NULL;
2634 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2635 if (lastComponentp) {
2636 *lastComponentp = lastSlashp;
2640 * If the name contains a stream name and a type
2641 * and the stream name is the nul-string and the
2642 * type is $DATA, then strip "::$DATA" from the
2643 * last component string that is returned.
2645 * Otherwise, return the full path name and allow
2646 * the file name to be rejected because it contains
2649 typep = cm_ClientStrRChr(lastSlashp, L':');
2650 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2652 streamp = cm_ClientStrRChr(lastSlashp, L':');
2653 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2657 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2658 osi_LogSaveClientString(smb_logp,streamp),
2659 osi_LogSaveClientString(smb_logp,typep));
2663 if (inPathp == lastSlashp)
2665 *outPathp++ = *inPathp++;
2674 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2675 char **chainpp, int flags)
2678 afs_uint32 type = *inp++;
2681 * The first byte specifies the type of the input string.
2682 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2686 /* Length Counted */
2687 case 0x1: /* Data Block */
2688 case 0x5: /* Variable Block */
2689 cb = *inp++ << 16 | *inp++;
2692 /* Null-terminated string */
2693 case 0x4: /* ASCII */
2694 case 0x3: /* Pathname */
2695 case 0x2: /* Dialect */
2696 cb = sizeof(pktp->data) - (inp - pktp->data);
2697 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2698 #ifdef DEBUG_UNICODE
2701 cb = sizeof(pktp->data);
2706 return NULL; /* invalid input */
2710 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2711 flags |= SMB_STRF_FORCEASCII;
2714 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2717 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2718 char ** chainpp, int flags)
2723 if (!WANTS_UNICODE(pktp))
2724 flags |= SMB_STRF_FORCEASCII;
2727 cb = sizeof(pktp->data) - (inp - pktp->data);
2728 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2729 #ifdef DEBUG_UNICODE
2732 cb = sizeof(pktp->data);
2734 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2735 flags | SMB_STRF_SRCNULTERM);
2738 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2739 size_t cb, char ** chainpp, int flags)
2742 if (!WANTS_UNICODE(pktp))
2743 flags |= SMB_STRF_FORCEASCII;
2746 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2749 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2750 size_t cch, char ** chainpp, int flags)
2755 if (!WANTS_UNICODE(pktp))
2756 flags |= SMB_STRF_FORCEASCII;
2758 cb = cch * sizeof(wchar_t);
2761 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2765 smb_ParseStringBuf(const unsigned char * bufbase,
2766 cm_space_t ** stringspp,
2767 unsigned char *inp, size_t *pcb_max,
2768 char **chainpp, int flags)
2771 if (!(flags & SMB_STRF_FORCEASCII)) {
2773 cm_space_t * spacep;
2776 if (bufbase && ((inp - bufbase) % 2) != 0) {
2777 inp++; /* unicode strings are always word aligned */
2781 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2783 cch_src = *pcb_max / sizeof(wchar_t);
2787 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2794 spacep = cm_GetSpace();
2795 spacep->nextp = *stringspp;
2796 *stringspp = spacep;
2800 *chainpp = inp + sizeof(wchar_t);
2803 *(spacep->wdata) = 0;
2804 return spacep->wdata;
2807 StringCchCopyNW(spacep->wdata,
2808 lengthof(spacep->wdata),
2809 (const clientchar_t *) inp, cch_src);
2812 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2814 return spacep->wdata;
2818 cm_space_t * spacep;
2821 /* Not using Unicode */
2823 *chainpp = inp + strlen(inp) + 1;
2826 spacep = cm_GetSpace();
2827 spacep->nextp = *stringspp;
2828 *stringspp = spacep;
2830 cchdest = lengthof(spacep->wdata);
2831 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2832 spacep->wdata, cchdest);
2834 return spacep->wdata;
2840 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2842 size_t * plen, int flags)
2848 /* we are only calculating the required size */
2855 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2857 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2858 if (!(flags & SMB_STRF_IGNORENUL))
2859 *plen += sizeof(wchar_t);
2861 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2871 cch_str = cm_ClientStrLen(str);
2872 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2875 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2883 /* if outp != NULL ... */
2885 /* Number of bytes left in the buffer.
2887 If outp lies inside the packet data buffer, we assume that the
2888 buffer is the packet data buffer. Otherwise we assume that the
2889 buffer is sizeof(packet->data).
2892 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2893 align = (int)((outp - pktp->data) % 2);
2894 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2896 align = (int)(((size_t) outp) % 2);
2897 buffersize = (int)sizeof(pktp->data);
2902 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2908 if (*str == _C('\0')) {
2910 if (buffersize < sizeof(wchar_t))
2913 *((wchar_t *) outp) = L'\0';
2914 if (plen && !(flags & SMB_STRF_IGNORENUL))
2915 *plen += sizeof(wchar_t);
2916 return outp + sizeof(wchar_t);
2919 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2921 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2922 osi_LogSaveClientString(smb_logp, str),
2928 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2930 return outp + sizeof(wchar_t) * nchars;
2938 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2941 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2943 return outp + cch_dest;
2947 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2953 tlen = inp[0] + (inp[1]<<8);
2954 inp += 2; /* skip length field */
2957 *chainpp = inp + tlen;
2966 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2970 if (*inp++ != 0x1) return NULL;
2971 tlen = inp[0] + (inp[1]<<8);
2972 inp += 2; /* skip length field */
2975 *chainpp = inp + tlen;
2978 if (lengthp) *lengthp = tlen;
2983 /* format a packet as a response */
2984 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2989 outp = (smb_t *) op;
2991 /* zero the basic structure through the smb_wct field, and zero the data
2992 * size field, assuming that wct stays zero; otherwise, you have to
2993 * explicitly set the data size field, too.
2995 inSmbp = (smb_t *) inp;
2996 memset(outp, 0, sizeof(smb_t)+2);
3002 outp->com = inSmbp->com;
3003 outp->tid = inSmbp->tid;
3004 outp->pid = inSmbp->pid;
3005 outp->uid = inSmbp->uid;
3006 outp->mid = inSmbp->mid;
3007 outp->res[0] = inSmbp->res[0];
3008 outp->res[1] = inSmbp->res[1];
3009 op->inCom = inSmbp->com;
3011 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3012 #ifdef SEND_CANONICAL_PATHNAMES
3013 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3015 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3017 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3018 outp->flg2 |= SMB_FLAGS2_UNICODE;
3021 /* copy fields in generic packet area */
3022 op->wctp = &outp->wct;
3025 /* send a (probably response) packet; vcp tells us to whom to send it.
3026 * we compute the length by looking at wct and bcc fields.
3028 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3038 ncbp = smb_GetNCB();
3042 memset(ncbp, 0, sizeof(NCB));
3044 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3045 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3046 extra += tp[0] + (tp[1]<<8);
3047 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3048 extra += 3; /* wct and length fields */
3050 ncbp->ncb_length = extra; /* bytes to send */
3051 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3052 ncbp->ncb_lana_num = vcp->lana;
3053 ncbp->ncb_command = NCBSEND; /* op means send data */
3054 ncbp->ncb_buffer = (char *) inp;/* packet */
3055 code = Netbios(ncbp);
3058 const char * s = ncb_error_string(code);
3059 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3060 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3062 lock_ObtainMutex(&vcp->mx);
3063 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3064 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3066 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3067 lock_ReleaseMutex(&vcp->mx);
3068 lock_ObtainWrite(&smb_globalLock);
3069 dead_sessions[vcp->session] = TRUE;
3070 lock_ReleaseWrite(&smb_globalLock);
3071 smb_CleanupDeadVC(vcp);
3073 lock_ReleaseMutex(&vcp->mx);
3081 void smb_MapNTError(long code, unsigned long *NTStatusp, afs_uint32 redir)
3083 unsigned long NTStatus;
3085 /* map CM_ERROR_* errors to NT 32-bit status codes */
3086 /* NT Status codes are listed in ntstatus.h not winerror.h */
3090 else if (code == CM_ERROR_NOSUCHCELL) {
3091 NTStatus = 0xC0000034L; /* Name not found */
3093 else if (code == CM_ERROR_NOSUCHVOLUME) {
3094 NTStatus = 0xC0000034L; /* Name not found */
3096 else if (code == CM_ERROR_TIMEDOUT) {
3098 NTStatus = 0xC0020052L; /* RPC_NT_COMM_FAILURE */
3101 NTStatus = 0xC00000CFL; /* Sharing Paused */
3103 /* Do not send Timeout to the SMB redirector.
3104 * It causes the redirector to drop the connection */
3105 NTStatus = 0x00000102L; /* Timeout */
3106 /* do not send Retry to the SMB redirector.
3107 * It believes the error comes from the transport
3108 * layer not from the SMB server. */
3109 NTStatus = 0xC000022DL; /* Retry */
3111 NTStatus = 0xC00000B5L; /* I/O Timeout */
3115 else if (code == CM_ERROR_RETRY) {
3117 NTStatus = 0xC000022DL; /* Retry */
3120 NTStatus = 0xC000022DL; /* Retry */
3122 NTStatus = 0xC00000B5L; /* I/O Timeout */
3126 else if (code == CM_ERROR_NOACCESS) {
3127 NTStatus = 0xC0000022L; /* Access denied */
3129 else if (code == CM_ERROR_READONLY) {
3130 NTStatus = 0xC00000A2L; /* Write protected */
3132 else if (code == CM_ERROR_NOSUCHFILE ||
3133 code == CM_ERROR_BPLUS_NOMATCH) {
3134 NTStatus = 0xC0000034L; /* Name not found */
3136 else if (code == CM_ERROR_NOSUCHPATH) {
3137 NTStatus = 0xC000003AL; /* Object path not found */
3139 else if (code == CM_ERROR_TOOBIG) {
3140 NTStatus = 0xC000007BL; /* Invalid image format */
3142 else if (code == CM_ERROR_INVAL) {
3143 NTStatus = 0xC000000DL; /* Invalid parameter */
3145 else if (code == CM_ERROR_BADFD) {
3146 NTStatus = 0xC0000008L; /* Invalid handle */
3148 else if (code == CM_ERROR_BADFDOP) {
3149 NTStatus = 0xC0000022L; /* Access denied */
3151 else if (code == CM_ERROR_UNKNOWN) {
3152 NTStatus = 0xC0000022L; /* Access denied */
3154 else if (code == CM_ERROR_EXISTS) {
3155 NTStatus = 0xC0000035L; /* Object name collision */
3157 else if (code == CM_ERROR_NOTEMPTY) {
3158 NTStatus = 0xC0000101L; /* Directory not empty */
3160 else if (code == CM_ERROR_CROSSDEVLINK) {
3161 NTStatus = 0xC00000D4L; /* Not same device */
3163 else if (code == CM_ERROR_NOTDIR) {
3164 NTStatus = 0xC0000103L; /* Not a directory */
3166 else if (code == CM_ERROR_ISDIR) {
3167 NTStatus = 0xC00000BAL; /* File is a directory */
3169 else if (code == CM_ERROR_BADOP) {
3171 /* I have no idea where this comes from */
3172 NTStatus = 0xC09820FFL; /* SMB no support */
3174 NTStatus = 0xC00000BBL; /* Not supported */
3175 #endif /* COMMENT */
3177 else if (code == CM_ERROR_BADSHARENAME) {
3178 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3180 else if (code == CM_ERROR_NOIPC) {
3182 NTStatus = 0xC0000022L; /* Access Denied */
3184 NTStatus = 0xC000013DL; /* Remote Resources */
3187 else if (code == CM_ERROR_CLOCKSKEW ||
3188 code == RXKADNOAUTH) {
3189 NTStatus = 0xC0000133L; /* Time difference at DC */
3191 else if (code == CM_ERROR_BADTID) {
3192 NTStatus = 0xC0982005L; /* SMB bad TID */
3194 else if (code == CM_ERROR_USESTD) {
3195 NTStatus = 0xC09820FBL; /* SMB use standard */
3197 else if (code == CM_ERROR_QUOTA) {
3198 NTStatus = 0xC0000044L; /* Quota exceeded */
3200 else if (code == CM_ERROR_SPACE) {
3201 NTStatus = 0xC000007FL; /* Disk full */
3203 else if (code == CM_ERROR_ATSYS) {
3204 NTStatus = 0xC0000033L; /* Object name invalid */
3206 else if (code == CM_ERROR_BADNTFILENAME) {
3207 NTStatus = 0xC0000033L; /* Object name invalid */
3209 else if (code == CM_ERROR_WOULDBLOCK) {
3210 NTStatus = 0xC00000D8L; /* Can't wait */
3212 else if (code == CM_ERROR_SHARING_VIOLATION) {
3213 NTStatus = 0xC0000043L; /* Sharing violation */
3215 else if (code == CM_ERROR_LOCK_CONFLICT) {
3216 NTStatus = 0xC0000054L; /* Lock conflict */
3218 else if (code == CM_ERROR_PARTIALWRITE) {
3219 NTStatus = 0xC000007FL; /* Disk full */
3221 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3222 NTStatus = 0xC0000023L; /* Buffer too small */
3224 else if (code == CM_ERROR_BUFFER_OVERFLOW) {
3225 NTStatus = 0x80000005L; /* Buffer overflow */
3227 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3228 NTStatus = 0xC0000035L; /* Object name collision */
3230 else if (code == CM_ERROR_BADPASSWORD) {
3231 NTStatus = 0xC000006DL; /* unknown username or bad password */
3233 else if (code == CM_ERROR_BADLOGONTYPE) {
3234 NTStatus = 0xC000015BL; /* logon type not granted */
3236 else if (code == CM_ERROR_GSSCONTINUE) {
3237 NTStatus = 0xC0000016L; /* more processing required */
3239 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3241 NTStatus = 0xC0000280L; /* reparse point not resolved */
3243 NTStatus = 0xC0000022L; /* Access Denied */
3246 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3247 NTStatus = 0xC0000257L; /* Path Not Covered */
3249 else if (code == CM_ERROR_ALLBUSY) {
3251 NTStatus = 0xC000022DL; /* Retry */
3253 NTStatus = 0xC0020018L; /* RPC_NT_SERVER_TOO_BUSY */
3256 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3258 NTStatus = 0xC000003AL; /* Path not found */
3260 NTStatus = 0xC0020017L; /* RPC_NT_SERVER_UNAVAILABLE */
3263 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3264 NTStatus = 0xC0000322L; /* No Kerberos key */
3266 else if (code == CM_ERROR_BAD_LEVEL) {
3267 NTStatus = 0xC0000148L; /* Invalid Level */
3269 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3270 NTStatus = 0xC000007EL; /* Range Not Locked */
3272 else if (code == CM_ERROR_NOSUCHDEVICE) {
3273 NTStatus = 0xC000000EL; /* No Such Device */
3275 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3276 NTStatus = 0xC0000055L; /* Lock Not Granted */
3278 else if (code == ENOMEM) {
3279 NTStatus = 0xC0000017L; /* Out of Memory */
3281 else if (code == CM_ERROR_RPC_MOREDATA) {
3282 NTStatus = 0x80000005L; /* Buffer overflow */
3286 sprintf(foo, "No mapping for 0x%X using 0xC0982001\r\n", code);
3287 OutputDebugString(foo);
3288 NTStatus = 0xC0982001L; /* SMB non-specific error */
3291 *NTStatusp = NTStatus;
3292 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3296 * NTSTATUS <-> Win32 Error Translation
3297 * http://support.microsoft.com/kb/113996
3299 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3301 unsigned long Win32E;
3303 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3307 else if (code == CM_ERROR_NOSUCHCELL) {
3308 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3310 else if (code == CM_ERROR_NOSUCHVOLUME) {
3311 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3313 else if (code == CM_ERROR_TIMEDOUT) {
3315 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3317 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3320 else if (code == CM_ERROR_RETRY) {
3321 Win32E = ERROR_RETRY; /* Retry */
3323 else if (code == CM_ERROR_NOACCESS) {
3324 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3326 else if (code == CM_ERROR_READONLY) {
3327 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3329 else if (code == CM_ERROR_NOSUCHFILE ||
3330 code == CM_ERROR_BPLUS_NOMATCH) {
3331 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3333 else if (code == CM_ERROR_NOSUCHPATH) {
3334 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3336 else if (code == CM_ERROR_TOOBIG) {
3337 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3339 else if (code == CM_ERROR_INVAL) {
3340 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3342 else if (code == CM_ERROR_BADFD) {
3343 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3345 else if (code == CM_ERROR_BADFDOP) {
3346 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3348 else if (code == CM_ERROR_UNKNOWN) {
3349 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3351 else if (code == CM_ERROR_EXISTS) {
3352 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3354 else if (code == CM_ERROR_NOTEMPTY) {
3355 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3357 else if (code == CM_ERROR_CROSSDEVLINK) {
3358 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3360 else if (code == CM_ERROR_NOTDIR) {
3361 Win32E = ERROR_DIRECTORY; /* Not a directory */
3363 else if (code == CM_ERROR_ISDIR) {
3364 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3366 else if (code == CM_ERROR_BADOP) {
3367 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3369 else if (code == CM_ERROR_BADSHARENAME) {
3370 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3372 else if (code == CM_ERROR_NOIPC) {
3374 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3376 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3379 else if (code == CM_ERROR_CLOCKSKEW ||
3380 code == RXKADNOAUTH) {
3381 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3383 else if (code == CM_ERROR_BADTID) {
3384 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3386 else if (code == CM_ERROR_USESTD) {
3387 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3389 else if (code == CM_ERROR_QUOTA) {
3390 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3392 else if (code == CM_ERROR_SPACE) {
3393 Win32E = ERROR_DISK_FULL; /* Disk full */
3395 else if (code == CM_ERROR_ATSYS) {
3396 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3398 else if (code == CM_ERROR_BADNTFILENAME) {
3399 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3401 else if (code == CM_ERROR_WOULDBLOCK) {
3402 Win32E = WAIT_TIMEOUT; /* Can't wait */
3404 else if (code == CM_ERROR_SHARING_VIOLATION) {
3405 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3407 else if (code == CM_ERROR_LOCK_CONFLICT) {
3408 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3410 else if (code == CM_ERROR_PARTIALWRITE) {
3411 Win32E = ERROR_DISK_FULL; /* Disk full */
3413 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3414 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3416 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3417 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3419 else if (code == CM_ERROR_BADPASSWORD) {
3420 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3422 else if (code == CM_ERROR_BADLOGONTYPE) {
3423 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3425 else if (code == CM_ERROR_GSSCONTINUE) {
3426 Win32E = ERROR_MORE_DATA; /* more processing required */
3428 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3430 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3432 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3435 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3436 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3438 else if (code == CM_ERROR_ALLBUSY) {
3439 Win32E = ERROR_RETRY; /* Retry */
3441 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3442 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3444 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3445 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3447 else if (code == CM_ERROR_BAD_LEVEL) {
3448 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3450 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3451 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3453 else if (code == CM_ERROR_NOSUCHDEVICE) {
3454 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3456 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3457 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3459 else if (code == ENOMEM) {
3460 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3462 else if (code == CM_ERROR_RPC_MOREDATA) {
3463 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3466 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3470 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3473 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3474 unsigned char *classp)
3476 unsigned char class;
3477 unsigned short error;
3479 /* map CM_ERROR_* errors to SMB errors */
3480 if (code == CM_ERROR_NOSUCHCELL) {
3482 error = 3; /* bad path */
3484 else if (code == CM_ERROR_NOSUCHVOLUME) {
3486 error = 3; /* bad path */
3488 else if (code == CM_ERROR_TIMEDOUT) {
3490 error = 81; /* server is paused */
3492 else if (code == CM_ERROR_RETRY) {
3493 class = 2; /* shouldn't happen */
3496 else if (code == CM_ERROR_NOACCESS) {
3498 error = 4; /* bad access */
3500 else if (code == CM_ERROR_READONLY) {
3502 error = 19; /* read only */
3504 else if (code == CM_ERROR_NOSUCHFILE ||
3505 code == CM_ERROR_BPLUS_NOMATCH) {
3507 error = 2; /* ENOENT! */
3509 else if (code == CM_ERROR_NOSUCHPATH) {
3511 error = 3; /* Bad path */
3513 else if (code == CM_ERROR_TOOBIG) {
3515 error = 11; /* bad format */
3517 else if (code == CM_ERROR_INVAL) {
3518 class = 2; /* server non-specific error code */
3521 else if (code == CM_ERROR_BADFD) {
3523 error = 6; /* invalid file handle */
3525 else if (code == CM_ERROR_BADFDOP) {
3526 class = 1; /* invalid op on FD */
3529 else if (code == CM_ERROR_EXISTS) {
3531 error = 80; /* file already exists */
3533 else if (code == CM_ERROR_NOTEMPTY) {
3535 error = 5; /* delete directory not empty */
3537 else if (code == CM_ERROR_CROSSDEVLINK) {
3539 error = 17; /* EXDEV */
3541 else if (code == CM_ERROR_NOTDIR) {
3542 class = 1; /* bad path */
3545 else if (code == CM_ERROR_ISDIR) {
3546 class = 1; /* access denied; DOS doesn't have a good match */
3549 else if (code == CM_ERROR_BADOP) {
3553 else if (code == CM_ERROR_BADSHARENAME) {
3557 else if (code == CM_ERROR_NOIPC) {
3559 error = 4; /* bad access */
3561 else if (code == CM_ERROR_CLOCKSKEW) {
3562 class = 1; /* invalid function */
3565 else if (code == CM_ERROR_BADTID) {
3569 else if (code == CM_ERROR_USESTD) {
3573 else if (code == CM_ERROR_REMOTECONN) {
3577 else if (code == CM_ERROR_QUOTA) {
3578 if (vcp->flags & SMB_VCFLAG_USEV3) {
3580 error = 39; /* disk full */
3584 error = 5; /* access denied */
3587 else if (code == CM_ERROR_SPACE) {
3588 if (vcp->flags & SMB_VCFLAG_USEV3) {
3590 error = 39; /* disk full */
3594 error = 5; /* access denied */
3597 else if (code == CM_ERROR_PARTIALWRITE) {
3599 error = 39; /* disk full */
3601 else if (code == CM_ERROR_ATSYS) {
3603 error = 2; /* ENOENT */
3605 else if (code == CM_ERROR_WOULDBLOCK) {
3607 error = 33; /* lock conflict */
3609 else if (code == CM_ERROR_LOCK_CONFLICT) {
3611 error = 33; /* lock conflict */
3613 else if (code == CM_ERROR_SHARING_VIOLATION) {
3615 error = 33; /* lock conflict */
3617 else if (code == CM_ERROR_NOFILES) {
3619 error = 18; /* no files in search */
3621 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3623 error = 183; /* Samba uses this */
3625 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3626 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3628 error = 2; /* bad password */
3630 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3632 error = 3; /* bad path */
3641 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3644 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3646 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3647 return CM_ERROR_BADOP;
3651 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3653 unsigned short EchoCount, i;
3654 char *data, *outdata;
3657 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3659 for (i=1; i<=EchoCount; i++) {
3660 data = smb_GetSMBData(inp, &dataSize);
3661 smb_SetSMBParm(outp, 0, i);
3662 smb_SetSMBDataLength(outp, dataSize);
3663 outdata = smb_GetSMBData(outp, NULL);
3664 memcpy(outdata, data, dataSize);
3665 smb_SendPacket(vcp, outp);
3671 /* SMB_COM_READ_RAW */
3672 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3675 long count, minCount, finalCount;
3679 smb_t *smbp = (smb_t*) inp;
3681 cm_user_t *userp = NULL;
3684 char *rawBuf = NULL;
3689 fd = smb_GetSMBParm(inp, 0);
3690 count = smb_GetSMBParm(inp, 3);
3691 minCount = smb_GetSMBParm(inp, 4);
3692 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3694 if (*inp->wctp == 10) {
3695 /* we were sent a request with 64-bit file offsets */
3696 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3698 if (LargeIntegerLessThanZero(offset)) {
3699 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3703 /* we were sent a request with 32-bit file offsets */
3704 offset.HighPart = 0;
3707 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3708 fd, offset.HighPart, offset.LowPart, count);
3710 fidp = smb_FindFID(vcp, fd, 0);
3712 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3716 lock_ObtainMutex(&fidp->mx);
3718 lock_ReleaseMutex(&fidp->mx);
3719 smb_ReleaseFID(fidp);
3720 return CM_ERROR_BADFD;
3723 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3724 lock_ReleaseMutex(&fidp->mx);
3725 smb_CloseFID(vcp, fidp, NULL, 0);
3726 code = CM_ERROR_NOSUCHFILE;
3732 LARGE_INTEGER LOffset, LLength;
3735 key = cm_GenerateKey(vcp->vcID, pid, fd);
3737 LOffset.HighPart = offset.HighPart;
3738 LOffset.LowPart = offset.LowPart;
3739 LLength.HighPart = 0;
3740 LLength.LowPart = count;
3742 lock_ObtainWrite(&fidp->scp->rw);
3743 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3744 lock_ReleaseWrite(&fidp->scp->rw);
3747 lock_ReleaseMutex(&fidp->mx);
3751 lock_ObtainMutex(&smb_RawBufLock);
3753 /* Get a raw buf, from head of list */
3754 rawBuf = smb_RawBufs;
3755 smb_RawBufs = *(char **)smb_RawBufs;
3757 lock_ReleaseMutex(&smb_RawBufLock);
3759 lock_ReleaseMutex(&fidp->mx);
3763 if (fidp->flags & SMB_FID_IOCTL)
3765 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3767 /* Give back raw buffer */
3768 lock_ObtainMutex(&smb_RawBufLock);
3769 *((char **) rawBuf) = smb_RawBufs;
3771 smb_RawBufs = rawBuf;
3772 lock_ReleaseMutex(&smb_RawBufLock);
3775 lock_ReleaseMutex(&fidp->mx);
3776 smb_ReleaseFID(fidp);
3779 lock_ReleaseMutex(&fidp->mx);
3781 userp = smb_GetUserFromVCP(vcp, inp);
3783 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3789 cm_ReleaseUser(userp);
3792 smb_ReleaseFID(fidp);
3796 memset(ncbp, 0, sizeof(NCB));
3798 ncbp->ncb_length = (unsigned short) finalCount;
3799 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3800 ncbp->ncb_lana_num = vcp->lana;
3801 ncbp->ncb_command = NCBSEND;
3802 ncbp->ncb_buffer = rawBuf;
3804 code = Netbios(ncbp);
3806 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3809 /* Give back raw buffer */
3810 lock_ObtainMutex(&smb_RawBufLock);
3811 *((char **) rawBuf) = smb_RawBufs;
3813 smb_RawBufs = rawBuf;
3814 lock_ReleaseMutex(&smb_RawBufLock);
3820 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3822 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3827 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3829 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3834 /* SMB_COM_NEGOTIATE */
3835 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3842 int VistaProtoIndex;
3843 int protoIndex; /* index we're using */
3848 char protocol_array[10][1024]; /* protocol signature of the client */
3849 int caps; /* capabilities */
3852 TIME_ZONE_INFORMATION tzi;
3854 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3857 namep = smb_GetSMBData(inp, &dbytes);
3860 coreProtoIndex = -1; /* not found */
3863 VistaProtoIndex = -1;
3864 while(namex < dbytes) {
3865 osi_Log1(smb_logp, "Protocol %s",
3866 osi_LogSaveString(smb_logp, namep+1));
3867 strcpy(protocol_array[tcounter], namep+1);
3869 /* namep points at the first protocol, or really, a 0x02
3870 * byte preceding the null-terminated ASCII name.
3872 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3873 coreProtoIndex = tcounter;
3875 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3876 v3ProtoIndex = tcounter;
3878 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3879 NTProtoIndex = tcounter;
3881 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3882 VistaProtoIndex = tcounter;
3885 /* compute size of protocol entry */
3886 entryLength = (int)strlen(namep+1);
3887 entryLength += 2; /* 0x02 bytes and null termination */
3889 /* advance over this protocol entry */
3890 namex += entryLength;
3891 namep += entryLength;
3892 tcounter++; /* which proto entry we're looking at */
3895 lock_ObtainMutex(&vcp->mx);
3897 if (VistaProtoIndex != -1) {
3898 protoIndex = VistaProtoIndex;
3899 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3902 if (NTProtoIndex != -1) {
3903 protoIndex = NTProtoIndex;
3904 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3906 else if (v3ProtoIndex != -1) {
3907 protoIndex = v3ProtoIndex;
3908 vcp->flags |= SMB_VCFLAG_USEV3;
3910 else if (coreProtoIndex != -1) {
3911 protoIndex = coreProtoIndex;
3912 vcp->flags |= SMB_VCFLAG_USECORE;
3914 else protoIndex = -1;
3915 lock_ReleaseMutex(&vcp->mx);
3917 if (protoIndex == -1)
3918 return CM_ERROR_INVAL;
3919 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3920 smb_SetSMBParm(outp, 0, protoIndex);
3921 if (smb_authType != SMB_AUTH_NONE) {
3922 smb_SetSMBParmByte(outp, 1,
3923 NEGOTIATE_SECURITY_USER_LEVEL |
3924 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3926 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3928 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3929 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3930 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3931 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3932 /* The session key is not a well documented field however most clients
3933 * will echo back the session key to the server. Currently we are using
3934 * the same value for all sessions. We should generate a random value
3935 * and store it into the vcp
3937 smb_SetSMBParmLong(outp, 7, 0x1a2b3c4d); /* session key */
3939 * Tried changing the capabilities to support for W2K - defect 117695
3940 * Maybe something else needs to be changed here?
3944 smb_SetSMBParmLong(outp, 9, 0x43fd);
3946 smb_SetSMBParmLong(outp, 9, 0x251);
3949 * 32-bit error codes *
3955 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3957 NTNEGOTIATE_CAPABILITY_DFS |
3959 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3960 NTNEGOTIATE_CAPABILITY_NTFIND |
3961 NTNEGOTIATE_CAPABILITY_RAWMODE |
3962 NTNEGOTIATE_CAPABILITY_NTSMB;
3964 if ( smb_authType == SMB_AUTH_EXTENDED )
3965 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3968 if ( smb_UseUnicode ) {
3969 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3973 smb_SetSMBParmLong(outp, 9, caps);
3975 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3976 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3977 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3979 GetTimeZoneInformation(&tzi);
3980 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3982 if (smb_authType == SMB_AUTH_NTLM) {
3983 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3984 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3985 /* paste in encryption key */
3986 datap = smb_GetSMBData(outp, NULL);
3987 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3988 /* and the faux domain name */
3989 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3990 datap + MSV1_0_CHALLENGE_LENGTH,
3991 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3992 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3993 void * secBlob = NULL;
3994 int secBlobLength = 0;
3996 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3999 * The SMB specification permits the server to save a round trip
4000 * in the GSS negotiation by sending an initial security blob.
4001 * Unfortunately, doing so trips a bug in Windows 7 and Server 2008 R2
4002 * whereby the SMB 1.x redirector drops the blob on the floor after
4003 * the first connection to the server and simply attempts to reuse
4004 * the previous authentication context. This bug can be avoided by
4005 * the server sending no security blob in the SMB_COM_NEGOTIATE
4006 * response. This forces the client to send an initial GSS init_sec_context
4007 * blob under all circumstances which works around the bug in Microsoft's
4010 * Do not call smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
4013 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
4014 datap = smb_GetSMBData(outp, NULL);
4016 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
4017 datap += sizeof(smb_ServerGUID);
4020 memcpy(datap, secBlob, secBlobLength);
4022 datap += sizeof(secBlobLength);
4025 smb_SetSMBParmByte(outp, 16, 0);/* Challenge length */
4026 smb_SetSMBDataLength(outp, smb_ServerDomainNameLength);
4027 datap = smb_GetSMBData(outp, NULL);
4028 /* the faux domain name */
4029 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4031 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4034 else if (v3ProtoIndex != -1) {
4035 smb_SetSMBParm(outp, 0, protoIndex);
4037 /* NOTE: Extended authentication cannot be negotiated with v3
4038 * therefore we fail over to NTLM
4040 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4041 smb_SetSMBParm(outp, 1,
4042 NEGOTIATE_SECURITY_USER_LEVEL |
4043 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
4045 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4047 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4048 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
4049 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
4050 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
4051 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
4052 smb_SetSMBParm(outp, 7, 1);
4054 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
4055 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
4056 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
4058 GetTimeZoneInformation(&tzi);
4059 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
4061 /* NOTE: Extended authentication cannot be negotiated with v3
4062 * therefore we fail over to NTLM
4064 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4065 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
4066 smb_SetSMBParm(outp, 12, 0); /* resvd */
4067 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
4068 datap = smb_GetSMBData(outp, NULL);
4069 /* paste in a new encryption key */
4070 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4071 /* and the faux domain name */
4072 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4073 datap + MSV1_0_CHALLENGE_LENGTH,
4074 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4076 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4077 smb_SetSMBParm(outp, 12, 0); /* resvd */
4078 smb_SetSMBDataLength(outp, 0);
4081 else if (coreProtoIndex != -1) { /* not really supported anymore */
4082 smb_SetSMBParm(outp, 0, protoIndex);
4083 smb_SetSMBDataLength(outp, 0);
4088 void smb_CheckVCs(void)
4090 smb_vc_t * vcp, *nextp;
4091 smb_packet_t * outp = smb_GetPacket();
4094 lock_ObtainWrite(&smb_rctLock);
4095 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4097 if (vcp->magic != SMB_VC_MAGIC)
4098 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4099 __FILE__, __LINE__);
4101 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4103 smb_HoldVCNoLock(vcp);
4106 * obtain a reference to 'nextp' now because we drop the
4107 * smb_rctLock later and the list contents could change
4108 * or 'vcp' could be destroyed when released.
4112 smb_HoldVCNoLock(nextp);
4114 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4115 smb_ReleaseVCNoLock(vcp);
4119 smb_FormatResponsePacket(vcp, NULL, outp);
4120 smbp = (smb_t *)outp;
4121 outp->inCom = smbp->com = 0x2b /* Echo */;
4129 smb_SetSMBParm(outp, 0, 0);
4130 smb_SetSMBDataLength(outp, 0);
4131 lock_ReleaseWrite(&smb_rctLock);
4133 smb_SendPacket(vcp, outp);
4135 lock_ObtainWrite(&smb_rctLock);
4136 smb_ReleaseVCNoLock(vcp);
4138 lock_ReleaseWrite(&smb_rctLock);
4139 smb_FreePacket(outp);
4142 void smb_Daemon(void *parmp)
4144 afs_uint32 count = 0;
4145 smb_username_t **unpp;
4148 while(smbShutdownFlag == 0) {
4152 if (smbShutdownFlag == 1)
4155 if ((count % 72) == 0) { /* every five minutes */
4157 time_t old_localZero = smb_localZero;
4159 /* Initialize smb_localZero */
4160 myTime.tm_isdst = -1; /* compute whether on DST or not */
4161 myTime.tm_year = 70;
4167 smb_localZero = mktime(&myTime);
4169 #ifdef AFS_FREELANCE
4170 if ( smb_localZero != old_localZero )
4171 cm_noteLocalMountPointChange(FALSE);
4177 /* GC smb_username_t objects that will no longer be used */
4179 lock_ObtainWrite(&smb_rctLock);
4180 for ( unpp=&usernamesp; *unpp; ) {
4182 smb_username_t *unp;
4184 lock_ObtainMutex(&(*unpp)->mx);
4185 if ( (*unpp)->refCount > 0 ||
4186 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4187 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4189 else if (!smb_LogoffTokenTransfer ||
4190 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4192 lock_ReleaseMutex(&(*unpp)->mx);
4200 lock_FinalizeMutex(&unp->mx);
4206 cm_ReleaseUser(userp);
4208 unpp = &(*unpp)->nextp;
4211 lock_ReleaseWrite(&smb_rctLock);
4213 /* XXX GC dir search entries */
4217 void smb_WaitingLocksDaemon()
4219 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4220 smb_waitingLock_t *wl, *wlNext;
4223 smb_packet_t *inp, *outp;
4227 while (smbShutdownFlag == 0) {
4228 lock_ObtainWrite(&smb_globalLock);
4229 nwlRequest = smb_allWaitingLocks;
4230 if (nwlRequest == NULL) {
4231 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4236 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4243 lock_ObtainWrite(&smb_globalLock);
4245 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4247 wlRequest = nwlRequest;
4248 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4249 lock_ReleaseWrite(&smb_globalLock);
4253 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4254 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4257 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4258 code = CM_ERROR_LOCK_NOT_GRANTED;
4262 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4264 /* wl->state is either _DONE or _WAITING. _ERROR
4265 would no longer be on the queue. */
4266 code = cm_RetryLock( wl->lockp,
4267 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4270 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4271 } else if (code != CM_ERROR_WOULDBLOCK) {
4272 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4277 if (code == CM_ERROR_WOULDBLOCK) {
4280 if (wlRequest->msTimeout != 0xffffffff
4281 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4293 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4296 scp = wlRequest->scp;
4297 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4301 lock_ObtainWrite(&scp->rw);
4303 for (wl = wlRequest->locks; wl; wl = wlNext) {
4304 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4306 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4307 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4308 wl->LLength, wl->key, 0, NULL, &req);
4310 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4315 lock_ReleaseWrite(&scp->rw);
4319 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4322 for (wl = wlRequest->locks; wl; wl = wlNext) {
4323 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4324 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4329 vcp = wlRequest->vcp;
4330 inp = wlRequest->inp;
4331 outp = wlRequest->outp;
4332 ncbp = smb_GetNCB();
4333 ncbp->ncb_length = inp->ncb_length;
4334 inp->spacep = cm_GetSpace();
4336 /* Remove waitingLock from list */
4337 lock_ObtainWrite(&smb_globalLock);
4338 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4340 lock_ReleaseWrite(&smb_globalLock);
4342 /* Resume packet processing */
4344 smb_SetSMBDataLength(outp, 0);
4345 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4346 outp->resumeCode = code;
4348 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4351 cm_FreeSpace(inp->spacep);
4352 smb_FreePacket(inp);
4353 smb_FreePacket(outp);
4355 cm_ReleaseSCache(wlRequest->scp);
4358 } while (nwlRequest && smbShutdownFlag == 0);
4363 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4365 osi_Log0(smb_logp, "SMB receive get disk attributes");
4367 smb_SetSMBParm(outp, 0, 32000);
4368 smb_SetSMBParm(outp, 1, 64);
4369 smb_SetSMBParm(outp, 2, 1024);
4370 smb_SetSMBParm(outp, 3, 30000);
4371 smb_SetSMBParm(outp, 4, 0);
4372 smb_SetSMBDataLength(outp, 0);
4376 /* SMB_COM_TREE_CONNECT */
4377 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4381 unsigned short newTid;
4382 clientchar_t shareName[AFSPATHMAX];
4383 clientchar_t *sharePath;
4386 clientchar_t *pathp;
4389 osi_Log0(smb_logp, "SMB receive tree connect");
4391 /* parse input parameters */
4394 tbp = smb_GetSMBData(inp, NULL);
4395 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4397 return CM_ERROR_BADSMB;
4399 tp = cm_ClientStrRChr(pathp, '\\');
4401 return CM_ERROR_BADSMB;
4402 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4404 lock_ObtainMutex(&vcp->mx);
4405 newTid = vcp->tidCounter++;
4406 lock_ReleaseMutex(&vcp->mx);
4408 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4409 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4411 return CM_ERROR_BADSMB;
4412 userp = smb_GetUserFromUID(uidp);
4413 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4414 smb_ReleaseUID(uidp);
4416 smb_ReleaseTID(tidp, FALSE);
4417 return CM_ERROR_BADSHARENAME;
4419 lock_ObtainMutex(&tidp->mx);
4420 tidp->userp = userp;
4421 tidp->pathname = sharePath;
4422 lock_ReleaseMutex(&tidp->mx);
4423 smb_ReleaseTID(tidp, FALSE);
4425 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4426 smb_SetSMBParm(rsp, 1, newTid);
4427 smb_SetSMBDataLength(rsp, 0);
4429 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4433 /* set maskp to the mask part of the incoming path.
4434 * Mask is 11 bytes long (8.3 with the dot elided).
4435 * Returns true if succeeds with a valid name, otherwise it does
4436 * its best, but returns false.
4438 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4446 /* starts off valid */
4449 /* mask starts out all blanks */
4450 memset(maskp, ' ', 11);
4453 /* find last backslash, or use whole thing if there is none */
4454 tp = cm_ClientStrRChr(pathp, '\\');
4458 tp++; /* skip slash */
4462 /* names starting with a dot are illegal */
4470 if (tc == '.' || tc == '"')
4478 /* if we get here, tp point after the dot */
4479 up = maskp+8; /* ext goes here */
4486 if (tc == '.' || tc == '"')
4489 /* copy extension if not too long */
4499 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4501 clientchar_t umask[11];
4509 /* XXX redo this, calling cm_MatchMask with a converted mask */
4511 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4515 /* otherwise, we have a valid 8.3 name; see if we have a match,
4516 * treating '?' as a wildcard in maskp (but not in the file name).
4518 tp1 = umask; /* real name, in mask format */
4519 tp2 = maskp; /* mask, in mask format */
4520 for(i=0; i<11; i++) {
4521 tc1 = *tp1++; /* clientchar_t from real name */
4522 tc2 = *tp2++; /* clientchar_t from mask */
4523 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4524 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4527 if (tc2 == '?' && tc1 != ' ')
4534 /* we got a match */
4538 clientchar_t *smb_FindMask(clientchar_t *pathp)
4542 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4545 return tp+1; /* skip the slash */
4547 return pathp; /* no slash, return the entire path */
4550 /* SMB_COM_SEARCH for a volume label
4552 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4553 dispatch function.) */
4554 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4556 clientchar_t *pathp;
4558 clientchar_t mask[12];
4559 unsigned char *statBlockp;
4560 unsigned char initStatBlock[21];
4563 osi_Log0(smb_logp, "SMB receive search volume");
4565 /* pull pathname and stat block out of request */
4566 tp = smb_GetSMBData(inp, NULL);
4567 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4568 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4570 return CM_ERROR_BADSMB;
4571 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4572 osi_assertx(statBlockp != NULL, "null statBlock");
4574 statBlockp = initStatBlock;
4578 /* for returning to caller */
4579 smb_Get8Dot3MaskFromPath(mask, pathp);
4581 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4582 tp = smb_GetSMBData(outp, NULL);
4584 *tp++ = 43; /* bytes in a dir entry */
4585 *tp++ = 0; /* high byte in counter */
4587 /* now marshall the dir entry, starting with the search status */
4588 *tp++ = statBlockp[0]; /* Reserved */
4589 memcpy(tp, mask, 11); tp += 11; /* FileName */
4591 /* now pass back server use info, with 1st byte non-zero */
4593 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4595 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4597 *tp++ = 0x8; /* attribute: volume */
4607 /* 4 byte file size */
4613 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4616 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4617 memset(tp, ' ', 13);
4620 /* set the length of the data part of the packet to 43 + 3, for the dir
4621 * entry plus the 5 and the length fields.
4623 smb_SetSMBDataLength(outp, 46);
4628 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4629 clientchar_t * tidPathp, clientchar_t * relPathp,
4630 cm_user_t *userp, cm_req_t *reqp)
4638 smb_dirListPatch_t *patchp;
4639 smb_dirListPatch_t *npatchp;
4640 clientchar_t path[AFSPATHMAX];
4642 afs_int32 mustFake = 0;
4644 code = cm_FindACLCache(dscp, userp, &rights);
4646 lock_ObtainWrite(&dscp->rw);
4647 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4648 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4649 lock_ReleaseWrite(&dscp->rw);
4650 if (code == CM_ERROR_NOACCESS) {
4658 if (!mustFake) { /* Bulk Stat */
4660 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4662 memset(bsp, 0, sizeof(cm_bulkStat_t));
4664 for (patchp = *dirPatchespp, count=0;
4666 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4667 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4671 if (lock_TryWrite(&tscp->rw)) {
4672 /* we have an entry that we can look at */
4673 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4674 /* we have a callback on it. Don't bother
4675 * fetching this stat entry, since we're happy
4676 * with the info we have.
4678 lock_ReleaseWrite(&tscp->rw);
4679 cm_ReleaseSCache(tscp);
4682 lock_ReleaseWrite(&tscp->rw);
4684 cm_ReleaseSCache(tscp);
4688 bsp->fids[i].Volume = patchp->fid.volume;
4689 bsp->fids[i].Vnode = patchp->fid.vnode;
4690 bsp->fids[i].Unique = patchp->fid.unique;
4692 if (bsp->counter == AFSCBMAX) {
4693 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4694 memset(bsp, 0, sizeof(cm_bulkStat_t));
4698 if (bsp->counter > 0)
4699 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4704 for (patchp = *dirPatchespp; patchp; patchp =
4705 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4707 dptr = patchp->dptr;
4709 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4710 relPathp ? relPathp : _C(""), patchp->dep->name);
4711 reqp->relPathp = path;
4712 reqp->tidPathp = tidPathp;
4714 code = cm_GetSCache(&patchp->fid, &dscp->fid, &scp, userp, reqp);
4715 reqp->relPathp = reqp->tidPathp = NULL;
4718 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4719 *dptr++ = SMB_ATTR_HIDDEN;
4722 lock_ObtainWrite(&scp->rw);
4723 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4724 lock_ReleaseWrite(&scp->rw);
4726 /* set the attribute */
4727 switch (scp->fileType) {
4728 case CM_SCACHETYPE_DIRECTORY:
4729 case CM_SCACHETYPE_MOUNTPOINT:
4730 case CM_SCACHETYPE_INVALID:
4731 attr = SMB_ATTR_DIRECTORY;
4733 case CM_SCACHETYPE_SYMLINK:
4734 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4735 attr = SMB_ATTR_DIRECTORY;
4737 attr = SMB_ATTR_NORMAL;
4740 /* if we get here we either have a normal file
4741 * or we have a file for which we have never
4742 * received status info. In this case, we can
4743 * check the even/odd value of the entry's vnode.
4744 * odd means it is to be treated as a directory
4745 * and even means it is to be treated as a file.
4747 if (mustFake && (scp->fid.vnode & 0x1))
4748 attr = SMB_ATTR_DIRECTORY;
4750 attr = SMB_ATTR_NORMAL;
4754 /* 1969-12-31 23:59:58 +00*/
4755 dosTime = 0xEBBFBF7D;
4758 shortTemp = (unsigned short) (dosTime & 0xffff);
4759 *((u_short *)dptr) = shortTemp;
4762 /* and copy out date */
4763 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4764 *((u_short *)dptr) = shortTemp;
4767 /* copy out file length */
4768 *((u_long *)dptr) = 0;
4771 lock_ConvertWToR(&scp->rw);
4772 attr = smb_Attributes(scp);
4773 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4774 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4775 attr |= SMB_ATTR_HIDDEN;
4779 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4782 shortTemp = (unsigned short) (dosTime & 0xffff);
4783 *((u_short *)dptr) = shortTemp;
4786 /* and copy out date */
4787 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4788 *((u_short *)dptr) = shortTemp;
4791 /* copy out file length */
4792 *((u_long *)dptr) = scp->length.LowPart;
4794 lock_ReleaseRead(&scp->rw);
4796 cm_ReleaseSCache(scp);
4799 /* now free the patches */
4800 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4801 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4805 /* and mark the list as empty */
4806 *dirPatchespp = NULL;
4812 /* SMB_COM_SEARCH */
4813 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4819 clientchar_t *pathp;
4820 cm_dirEntry_t *dep = 0;
4822 smb_dirListPatch_t *dirListPatchesp;
4823 smb_dirListPatch_t *curPatchp;
4827 osi_hyper_t dirLength;
4828 osi_hyper_t bufferOffset;
4829 osi_hyper_t curOffset;
4831 unsigned char *inCookiep;
4832 smb_dirSearch_t *dsp;
4836 unsigned long clientCookie;
4837 cm_pageHeader_t *pageHeaderp;
4838 cm_user_t *userp = NULL;
4840 clientchar_t mask[12];
4842 long nextEntryCookie;
4843 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4844 char resByte; /* reserved byte from the cookie */
4845 char *op; /* output data ptr */
4846 char *origOp; /* original value of op */
4847 cm_space_t *spacep; /* for pathname buffer */
4851 clientchar_t *tidPathp = 0;
4858 maxCount = smb_GetSMBParm(inp, 0);
4860 dirListPatchesp = NULL;
4862 caseFold = CM_FLAG_CASEFOLD;
4864 tp = smb_GetSMBData(inp, NULL);
4865 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4866 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4868 return CM_ERROR_BADSMB;
4870 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4872 return CM_ERROR_BADSMB;
4874 /* We can handle long names */
4875 if (vcp->flags & SMB_VCFLAG_USENT)
4876 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4878 /* make sure we got a whole search status */
4879 if (dataLength < 21) {
4880 nextCookie = 0; /* start at the beginning of the dir */
4883 attribute = smb_GetSMBParm(inp, 1);
4885 /* handle volume info in another function */
4886 if (attribute & 0x8)
4887 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4889 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4890 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4892 if (*pathp == 0) { /* null pathp, treat as root dir */
4893 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4894 return CM_ERROR_NOFILES;
4898 dsp = smb_NewDirSearch(0);
4899 dsp->attribute = attribute;
4900 smb_Get8Dot3MaskFromPath(mask, pathp);
4901 memcpy(dsp->mask, mask, 12);
4903 /* track if this is likely to match a lot of entries */
4904 if (smb_Is8Dot3StarMask(mask))
4909 /* pull the next cookie value out of the search status block */
4910 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4911 + (inCookiep[16]<<24);
4912 dsp = smb_FindDirSearch(inCookiep[12]);
4914 /* can't find dir search status; fatal error */
4915 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4916 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4917 return CM_ERROR_BADFD;
4919 attribute = dsp->attribute;
4920 resByte = inCookiep[0];
4922 /* copy out client cookie, in host byte order. Don't bother
4923 * interpreting it, since we're just passing it through, anyway.
4925 memcpy(&clientCookie, &inCookiep[17], 4);
4927 memcpy(mask, dsp->mask, 12);
4929 /* assume we're doing a star match if it has continued for more
4935 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4936 nextCookie, dsp->cookie, attribute);
4938 userp = smb_GetUserFromVCP(vcp, inp);
4940 /* try to get the vnode for the path name next */
4941 lock_ObtainMutex(&dsp->mx);
4944 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4948 spacep = inp->spacep;
4949 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4950 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4952 lock_ReleaseMutex(&dsp->mx);
4953 cm_ReleaseUser(userp);
4954 smb_DeleteDirSearch(dsp);
4955 smb_ReleaseDirSearch(dsp);
4956 return CM_ERROR_NOFILES;
4958 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4959 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4961 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
4962 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4965 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4968 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4969 cm_ReleaseSCache(scp);
4970 lock_ReleaseMutex(&dsp->mx);
4971 cm_ReleaseUser(userp);
4972 smb_DeleteDirSearch(dsp);
4973 smb_ReleaseDirSearch(dsp);
4974 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4975 return CM_ERROR_PATH_NOT_COVERED;
4977 return CM_ERROR_NOSUCHPATH;
4979 #endif /* DFS_SUPPORT */
4982 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4983 /* we need one hold for the entry we just stored into,
4984 * and one for our own processing. When we're done with this
4985 * function, we'll drop the one for our own processing.
4986 * We held it once from the namei call, and so we do another hold
4990 lock_ObtainWrite(&scp->rw);
4991 dsp->flags |= SMB_DIRSEARCH_BULKST;
4992 lock_ReleaseWrite(&scp->rw);
4995 lock_ReleaseMutex(&dsp->mx);
4997 cm_ReleaseUser(userp);
4998 smb_DeleteDirSearch(dsp);
4999 smb_ReleaseDirSearch(dsp);
5003 /* reserves space for parameter; we'll adjust it again later to the
5004 * real count of the # of entries we returned once we've actually
5005 * assembled the directory listing.
5007 smb_SetSMBParm(outp, 0, 0);
5009 /* get the directory size */
5010 lock_ObtainWrite(&scp->rw);
5011 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5012 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5014 lock_ReleaseWrite(&scp->rw);
5015 cm_ReleaseSCache(scp);
5016 cm_ReleaseUser(userp);
5017 smb_DeleteDirSearch(dsp);
5018 smb_ReleaseDirSearch(dsp);
5022 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5024 dirLength = scp->length;
5026 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5027 curOffset.HighPart = 0;
5028 curOffset.LowPart = nextCookie;
5029 origOp = op = smb_GetSMBData(outp, NULL);
5030 /* and write out the basic header */
5031 *op++ = 5; /* variable block */
5032 op += 2; /* skip vbl block length; we'll fill it in later */
5036 clientchar_t *actualName = NULL;
5037 int free_actualName = 0;
5038 clientchar_t shortName[13];
5039 clientchar_t *shortNameEnd;
5041 /* make sure that curOffset.LowPart doesn't point to the first
5042 * 32 bytes in the 2nd through last dir page, and that it doesn't
5043 * point at the first 13 32-byte chunks in the first dir page,
5044 * since those are dir and page headers, and don't contain useful
5047 temp = curOffset.LowPart & (2048-1);
5048 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5049 /* we're in the first page */
5050 if (temp < 13*32) temp = 13*32;
5053 /* we're in a later dir page */
5054 if (temp < 32) temp = 32;
5057 /* make sure the low order 5 bits are zero */
5060 /* now put temp bits back ito curOffset.LowPart */
5061 curOffset.LowPart &= ~(2048-1);
5062 curOffset.LowPart |= temp;
5064 /* check if we've returned all the names that will fit in the
5067 if (returnedNames >= maxCount) {
5068 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5069 returnedNames, maxCount);
5073 /* check if we've passed the dir's EOF */
5074 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5076 /* see if we can use the bufferp we have now; compute in which page
5077 * the current offset would be, and check whether that's the offset
5078 * of the buffer we have. If not, get the buffer.
5080 thyper.HighPart = curOffset.HighPart;
5081 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5082 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5085 buf_Release(bufferp);
5088 lock_ReleaseWrite(&scp->rw);
5089 code = buf_Get(scp, &thyper, &req, &bufferp);
5090 lock_ObtainMutex(&dsp->mx);
5092 /* now, if we're doing a star match, do bulk fetching of all of
5093 * the status info for files in the dir.
5096 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5098 lock_ObtainWrite(&scp->rw);
5099 lock_ReleaseMutex(&dsp->mx);
5101 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5105 bufferOffset = thyper;
5107 /* now get the data in the cache */
5109 code = cm_SyncOp(scp, bufferp, userp, &req,
5111 CM_SCACHESYNC_NEEDCALLBACK |
5112 CM_SCACHESYNC_READ);
5114 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5118 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5120 if (cm_HaveBuffer(scp, bufferp, 0)) {
5121 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5125 /* otherwise, load the buffer and try again */
5126 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5128 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5129 scp, bufferp, code);
5134 buf_Release(bufferp);
5138 } /* if (wrong buffer) ... */
5140 /* now we have the buffer containing the entry we're interested in; copy
5141 * it out if it represents a non-deleted entry.
5143 entryInDir = curOffset.LowPart & (2048-1);
5144 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5146 /* page header will help tell us which entries are free. Page header
5147 * can change more often than once per buffer, since AFS 3 dir page size
5148 * may be less than (but not more than a buffer package buffer.
5150 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5151 temp &= ~(2048 - 1); /* turn off intra-page bits */
5152 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5154 /* now determine which entry we're looking at in the page. If it is
5155 * free (there's a free bitmap at the start of the dir), we should
5156 * skip these 32 bytes.
5158 slotInPage = (entryInDir & 0x7e0) >> 5;
5159 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5160 /* this entry is free */
5161 numDirChunks = 1; /* only skip this guy */
5165 tp = bufferp->datap + entryInBuffer;
5166 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5168 /* while we're here, compute the next entry's location, too,
5169 * since we'll need it when writing out the cookie into the dir
5172 * XXXX Probably should do more sanity checking.
5174 numDirChunks = cm_NameEntries(dep->name, NULL);
5176 /* compute the offset of the cookie representing the next entry */
5177 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5179 /* Compute 8.3 name if necessary */
5180 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5181 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5184 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5185 actualName = shortName;
5186 free_actualName = 0;
5188 free_actualName = 1;
5191 if (actualName == NULL) {
5192 /* Couldn't convert the name for some reason */
5193 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5194 osi_LogSaveString(smb_logp, dep->name));
5198 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5199 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5200 osi_LogSaveClientString(smb_logp, actualName));
5202 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5203 /* this is one of the entries to use: it is not deleted
5204 * and it matches the star pattern we're looking for.
5207 /* Eliminate entries that don't match requested
5210 /* no hidden files */
5211 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5212 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5216 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5218 /* We have already done the cm_TryBulkStat above */
5219 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5220 fileType = cm_FindFileType(&fid);
5221 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5222 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5224 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5225 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5226 fileType == CM_SCACHETYPE_DFSLINK ||
5227 fileType == CM_SCACHETYPE_INVALID)
5228 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5233 memcpy(op, mask, 11); op += 11;
5234 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5235 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5236 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5237 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5238 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5239 memcpy(op, &clientCookie, 4); op += 4;
5241 /* now we emit the attribute. This is sort of tricky,
5242 * since we need to really stat the file to find out
5243 * what type of entry we've got. Right now, we're
5244 * copying out data from a buffer, while holding the
5245 * scp locked, so it isn't really convenient to stat
5246 * something now. We'll put in a place holder now,
5247 * and make a second pass before returning this to get
5248 * the real attributes. So, we just skip the data for
5249 * now, and adjust it later. We allocate a patch
5250 * record to make it easy to find this point later.
5251 * The replay will happen at a time when it is safe to
5252 * unlock the directory.
5254 curPatchp = malloc(sizeof(*curPatchp));
5255 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5256 curPatchp->dptr = op;
5257 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5259 /* do hidden attribute here since name won't be around when applying
5263 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5264 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5266 curPatchp->flags = 0;
5268 op += 9; /* skip attr, time, date and size */
5270 /* zero out name area. The spec says to pad with
5271 * spaces, but Samba doesn't, and neither do we.
5275 /* finally, we get to copy out the name; we know that
5276 * it fits in 8.3 or the pattern wouldn't match, but it
5277 * never hurts to be sure.
5279 cm_ClientStringToUtf8(actualName, -1, op, 13);
5280 if (smb_StoreAnsiFilenames)
5282 /* This is a UCHAR field, which is ASCII even if Unicode
5285 /* Uppercase if requested by client */
5286 if (!KNOWS_LONG_NAMES(inp))
5291 /* now, adjust the # of entries copied */
5293 } /* if we're including this name */
5296 if (free_actualName && actualName) {
5301 /* and adjust curOffset to be where the new cookie is */
5302 thyper.HighPart = 0;
5303 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5304 curOffset = LargeIntegerAdd(thyper, curOffset);
5305 } /* while copying data for dir listing */
5307 /* release the mutex */
5308 lock_ReleaseWrite(&scp->rw);
5310 buf_Release(bufferp);
5314 /* apply and free last set of patches; if not doing a star match, this
5315 * will be empty, but better safe (and freeing everything) than sorry.
5317 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5319 /* special return code for unsuccessful search */
5320 if (code == 0 && dataLength < 21 && returnedNames == 0)
5321 code = CM_ERROR_NOFILES;
5323 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5324 returnedNames, code);
5327 smb_DeleteDirSearch(dsp);
5328 smb_ReleaseDirSearch(dsp);
5329 cm_ReleaseSCache(scp);
5330 cm_ReleaseUser(userp);
5334 /* finalize the output buffer */
5335 smb_SetSMBParm(outp, 0, returnedNames);
5336 temp = (long) (op - origOp);
5337 smb_SetSMBDataLength(outp, temp);
5339 /* the data area is a variable block, which has a 5 (already there)
5340 * followed by the length of the # of data bytes. We now know this to
5341 * be "temp," although that includes the 3 bytes of vbl block header.
5342 * Deduct for them and fill in the length field.
5344 temp -= 3; /* deduct vbl block info */
5345 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5346 origOp[1] = (unsigned char)(temp & 0xff);
5347 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5348 if (returnedNames == 0)
5349 smb_DeleteDirSearch(dsp);
5350 smb_ReleaseDirSearch(dsp);
5351 cm_ReleaseSCache(scp);
5352 cm_ReleaseUser(userp);
5357 /* verify that this is a valid path to a directory. I don't know why they
5358 * don't use the get file attributes call.
5360 * SMB_COM_CHECK_DIRECTORY
5362 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5364 clientchar_t *pathp;
5366 cm_scache_t *rootScp;
5367 cm_scache_t *newScp;
5371 clientchar_t *tidPathp;
5377 pdata = smb_GetSMBData(inp, NULL);
5378 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5380 return CM_ERROR_BADSMB;
5381 osi_Log1(smb_logp, "SMB receive check path %S",
5382 osi_LogSaveClientString(smb_logp, pathp));
5384 userp = smb_GetUserFromVCP(vcp, inp);
5386 rootScp = cm_RootSCachep(userp, &req);
5388 caseFold = CM_FLAG_CASEFOLD;
5390 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5392 cm_ReleaseUser(userp);
5393 return CM_ERROR_NOSUCHPATH;
5395 code = cm_NameI(rootScp, pathp,
5396 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5397 userp, tidPathp, &req, &newScp);
5400 cm_ReleaseUser(userp);
5405 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5406 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5407 cm_ReleaseSCache(newScp);
5408 cm_ReleaseUser(userp);
5409 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5410 return CM_ERROR_PATH_NOT_COVERED;
5412 return CM_ERROR_NOSUCHPATH;
5414 #endif /* DFS_SUPPORT */
5416 /* now lock the vnode with a callback; returns with newScp locked */
5417 lock_ObtainWrite(&newScp->rw);
5418 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5419 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5421 if (code != CM_ERROR_NOACCESS) {
5422 lock_ReleaseWrite(&newScp->rw);
5423 cm_ReleaseSCache(newScp);
5424 cm_ReleaseUser(userp);
5428 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5431 attrs = smb_Attributes(newScp);
5433 if (!(attrs & SMB_ATTR_DIRECTORY))
5434 code = CM_ERROR_NOTDIR;
5436 lock_ReleaseWrite(&newScp->rw);
5438 cm_ReleaseSCache(newScp);
5439 cm_ReleaseUser(userp);
5443 /* SMB_COM_SET_INFORMATION */
5444 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5446 clientchar_t *pathp;
5448 cm_scache_t *rootScp;
5449 unsigned short attribute;
5451 cm_scache_t *newScp;
5455 clientchar_t *tidPathp;
5461 /* decode basic attributes we're passed */
5462 attribute = smb_GetSMBParm(inp, 0);
5463 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5465 datap = smb_GetSMBData(inp, NULL);
5466 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5468 return CM_ERROR_BADSMB;
5470 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5471 dosTime, attribute);
5473 userp = smb_GetUserFromVCP(vcp, inp);
5475 rootScp = cm_RootSCachep(userp, &req);
5477 caseFold = CM_FLAG_CASEFOLD;
5479 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5481 cm_ReleaseUser(userp);
5482 return CM_ERROR_NOSUCHFILE;
5484 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5485 tidPathp, &req, &newScp);
5488 cm_ReleaseUser(userp);
5493 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5494 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5495 cm_ReleaseSCache(newScp);
5496 cm_ReleaseUser(userp);
5497 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5498 return CM_ERROR_PATH_NOT_COVERED;
5500 return CM_ERROR_NOSUCHPATH;
5502 #endif /* DFS_SUPPORT */
5504 /* now lock the vnode with a callback; returns with newScp locked; we
5505 * need the current status to determine what the new status is, in some
5508 lock_ObtainWrite(&newScp->rw);
5509 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5510 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5512 lock_ReleaseWrite(&newScp->rw);
5513 cm_ReleaseSCache(newScp);
5514 cm_ReleaseUser(userp);
5518 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5520 /* Check for RO volume */
5521 if (newScp->flags & CM_SCACHEFLAG_RO) {
5522 lock_ReleaseWrite(&newScp->rw);
5523 cm_ReleaseSCache(newScp);
5524 cm_ReleaseUser(userp);
5525 return CM_ERROR_READONLY;
5528 /* prepare for setattr call */
5531 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5532 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5534 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5535 /* we're told to make a writable file read-only */
5536 attr.unixModeBits = newScp->unixModeBits & ~0222;
5537 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5539 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5540 /* we're told to make a read-only file writable */
5541 attr.unixModeBits = newScp->unixModeBits | 0222;
5542 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5544 lock_ReleaseWrite(&newScp->rw);
5546 /* now call setattr */
5548 code = cm_SetAttr(newScp, &attr, userp, &req);
5552 cm_ReleaseSCache(newScp);
5553 cm_ReleaseUser(userp);
5559 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5561 clientchar_t *pathp;
5563 cm_scache_t *rootScp;
5564 cm_scache_t *newScp, *dscp;
5569 clientchar_t *tidPathp;
5571 clientchar_t *lastComp;
5577 datap = smb_GetSMBData(inp, NULL);
5578 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5580 return CM_ERROR_BADSMB;
5582 if (*pathp == 0) /* null path */
5585 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5586 osi_LogSaveClientString(smb_logp, pathp));
5588 userp = smb_GetUserFromVCP(vcp, inp);
5590 rootScp = cm_RootSCachep(userp, &req);
5592 /* we shouldn't need this for V3 requests, but we seem to */
5593 caseFold = CM_FLAG_CASEFOLD;
5595 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5597 cm_ReleaseUser(userp);
5598 return CM_ERROR_NOSUCHFILE;
5602 * XXX Strange hack XXX
5604 * As of Patch 5 (16 July 97), we are having the following problem:
5605 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5606 * requests to look up "desktop.ini" in all the subdirectories.
5607 * This can cause zillions of timeouts looking up non-existent cells
5608 * and volumes, especially in the top-level directory.
5610 * We have not found any way to avoid this or work around it except
5611 * to explicitly ignore the requests for mount points that haven't
5612 * yet been evaluated and for directories that haven't yet been
5615 * We should modify this hack to provide a fake desktop.ini file
5616 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5618 spacep = inp->spacep;
5619 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5620 #ifndef SPECIAL_FOLDERS
5621 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5622 code = cm_NameI(rootScp, spacep->wdata,
5623 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5624 userp, tidPathp, &req, &dscp);
5627 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5628 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5630 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5631 return CM_ERROR_PATH_NOT_COVERED;
5633 return CM_ERROR_NOSUCHPATH;
5635 #endif /* DFS_SUPPORT */
5636 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5637 code = CM_ERROR_NOSUCHFILE;
5638 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5639 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
5644 code = CM_ERROR_NOSUCHFILE;
5646 cm_ReleaseSCache(dscp);
5648 cm_ReleaseUser(userp);
5652 else if (code != CM_ERROR_NOSUCHFILE &&
5653 code != CM_ERROR_NOSUCHPATH &&
5654 code != CM_ERROR_BPLUS_NOMATCH)
5656 cm_ReleaseUser(userp);
5660 #endif /* SPECIAL_FOLDERS */
5662 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5663 tidPathp, &req, &newScp);
5665 cm_ReleaseUser(userp);
5670 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5671 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5672 cm_ReleaseSCache(newScp);
5673 cm_ReleaseUser(userp);
5674 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5675 return CM_ERROR_PATH_NOT_COVERED;
5677 return CM_ERROR_NOSUCHPATH;
5679 #endif /* DFS_SUPPORT */
5681 /* now lock the vnode with a callback; returns with newScp locked */
5682 lock_ObtainWrite(&newScp->rw);
5683 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5684 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5686 lock_ReleaseWrite(&newScp->rw);
5687 cm_ReleaseSCache(newScp);
5688 cm_ReleaseUser(userp);
5692 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5694 attrs = smb_Attributes(newScp);
5696 smb_SetSMBParm(outp, 0, attrs);
5698 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5699 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5700 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5701 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5702 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5703 smb_SetSMBParm(outp, 5, 0);
5704 smb_SetSMBParm(outp, 6, 0);
5705 smb_SetSMBParm(outp, 7, 0);
5706 smb_SetSMBParm(outp, 8, 0);
5707 smb_SetSMBParm(outp, 9, 0);
5708 smb_SetSMBDataLength(outp, 0);
5709 lock_ReleaseWrite(&newScp->rw);
5711 cm_ReleaseSCache(newScp);
5712 cm_ReleaseUser(userp);
5717 /* SMB_COM_TREE_DISCONNECT */
5718 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5722 osi_Log0(smb_logp, "SMB receive tree disconnect");
5724 /* find the tree and free it */
5725 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5727 lock_ObtainWrite(&smb_rctLock);
5729 smb_ReleaseTID(tidp, TRUE);
5730 lock_ReleaseWrite(&smb_rctLock);
5737 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5740 clientchar_t *pathp;
5741 clientchar_t *lastNamep;
5750 clientchar_t *tidPathp;
5756 datap = smb_GetSMBData(inp, NULL);
5757 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5759 return CM_ERROR_BADSMB;
5761 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5763 #ifdef DEBUG_VERBOSE
5767 hexpath = osi_HexifyString( pathp );
5768 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5773 share = smb_GetSMBParm(inp, 0);
5774 attribute = smb_GetSMBParm(inp, 1);
5776 spacep = inp->spacep;
5777 /* smb_StripLastComponent will strip "::$DATA" if present */
5778 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5780 if (!cm_IsValidClientString(pathp)) {
5782 clientchar_t * hexp;
5784 hexp = cm_GetRawCharsAlloc(pathp, -1);
5785 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5786 osi_LogSaveClientString(smb_logp, hexp));
5790 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5792 return CM_ERROR_BADNTFILENAME;
5795 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5796 /* special case magic file name for receiving IOCTL requests
5797 * (since IOCTL calls themselves aren't getting through).
5799 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5800 smb_SetupIoctlFid(fidp, spacep);
5801 smb_SetSMBParm(outp, 0, fidp->fid);
5802 smb_SetSMBParm(outp, 1, 0); /* attrs */
5803 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5804 smb_SetSMBParm(outp, 3, 0);
5805 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5806 smb_SetSMBParm(outp, 5, 0x7fff);
5807 /* pass the open mode back */
5808 smb_SetSMBParm(outp, 6, (share & 0xf));
5809 smb_SetSMBDataLength(outp, 0);
5810 smb_ReleaseFID(fidp);
5814 userp = smb_GetUserFromVCP(vcp, inp);
5816 caseFold = CM_FLAG_CASEFOLD;
5818 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5820 cm_ReleaseUser(userp);
5821 return CM_ERROR_NOSUCHPATH;
5823 code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
5824 tidPathp, &req, &scp);
5827 cm_ReleaseUser(userp);
5832 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5833 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5834 cm_ReleaseSCache(scp);
5835 cm_ReleaseUser(userp);
5836 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5837 return CM_ERROR_PATH_NOT_COVERED;
5839 return CM_ERROR_NOSUCHPATH;
5841 #endif /* DFS_SUPPORT */
5843 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5845 cm_ReleaseSCache(scp);
5846 cm_ReleaseUser(userp);
5850 /* don't need callback to check file type, since file types never
5851 * change, and namei and cm_Lookup all stat the object at least once on
5852 * a successful return.
5854 if (scp->fileType != CM_SCACHETYPE_FILE) {
5855 cm_ReleaseSCache(scp);
5856 cm_ReleaseUser(userp);
5857 return CM_ERROR_ISDIR;
5860 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5861 osi_assertx(fidp, "null smb_fid_t");
5863 lock_ObtainMutex(&fidp->mx);
5864 if ((share & 0xf) == 0)
5865 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5866 else if ((share & 0xf) == 1)
5867 fidp->flags |= SMB_FID_OPENWRITE;
5869 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5873 fidp->userp = userp;
5875 /* and a pointer to the vnode */
5877 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5878 lock_ObtainWrite(&scp->rw);
5879 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5881 smb_SetSMBParm(outp, 0, fidp->fid);
5882 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5883 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5884 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5885 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5886 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5887 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5888 /* pass the open mode back; XXXX add access checks */
5889 smb_SetSMBParm(outp, 6, (share & 0xf));
5890 smb_SetSMBDataLength(outp, 0);
5891 lock_ReleaseMutex(&fidp->mx);
5892 lock_ReleaseRead(&scp->rw);
5895 cm_Open(scp, 0, userp);
5897 /* send and free packet */
5898 smb_ReleaseFID(fidp);
5899 cm_ReleaseUser(userp);
5900 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5904 typedef struct smb_unlinkRock {
5909 clientchar_t *maskp; /* pointer to the star pattern */
5912 cm_dirEntryList_t * matches;
5915 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5918 smb_unlinkRock_t *rockp;
5921 normchar_t matchName[MAX_PATH];
5925 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5926 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5927 caseFold |= CM_FLAG_8DOT3;
5929 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5930 /* Can't convert name */
5931 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5932 osi_LogSaveString(smb_logp, dep->name));
5936 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5938 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5939 !cm_Is8Dot3(matchName)) {
5940 cm_Gen8Dot3Name(dep, matchName, NULL);
5941 /* 8.3 matches are always case insensitive */
5942 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5945 osi_Log1(smb_logp, "Found match %S",
5946 osi_LogSaveClientString(smb_logp, matchName));
5948 cm_DirEntryListAdd(dep->name, &rockp->matches);
5952 /* If we made a case sensitive exact match, we might as well quit now. */
5953 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5954 code = CM_ERROR_STOPNOW;
5963 /* SMB_COM_DELETE */
5964 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5968 clientchar_t *pathp;
5972 clientchar_t *lastNamep;
5973 smb_unlinkRock_t rock;
5977 clientchar_t *tidPathp;
5981 memset(&rock, 0, sizeof(rock));
5983 attribute = smb_GetSMBParm(inp, 0);
5985 tp = smb_GetSMBData(inp, NULL);
5986 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5988 return CM_ERROR_BADSMB;
5990 osi_Log1(smb_logp, "SMB receive unlink %S",
5991 osi_LogSaveClientString(smb_logp, pathp));
5993 spacep = inp->spacep;
5994 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5996 userp = smb_GetUserFromVCP(vcp, inp);
5998 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6000 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6002 cm_ReleaseUser(userp);
6003 return CM_ERROR_NOSUCHPATH;
6005 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
6008 cm_ReleaseUser(userp);
6013 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6014 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6015 cm_ReleaseSCache(dscp);
6016 cm_ReleaseUser(userp);
6017 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6018 return CM_ERROR_PATH_NOT_COVERED;
6020 return CM_ERROR_NOSUCHPATH;
6022 #endif /* DFS_SUPPORT */
6024 /* otherwise, scp points to the parent directory. */
6031 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
6033 code = CM_ERROR_NOSUCHFILE;
6036 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6039 thyper.HighPart = 0;
6044 rock.matches = NULL;
6046 /* Now, if we aren't dealing with a wildcard match, we first try an exact
6047 * match. If that fails, we do a case insensitve match.
6049 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6050 !smb_IsStarMask(rock.maskp)) {
6051 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6054 thyper.HighPart = 0;
6055 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6060 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6062 if (code == CM_ERROR_STOPNOW)
6065 if (code == 0 && rock.matches) {
6066 cm_dirEntryList_t * entry;
6068 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6069 normchar_t normalizedName[MAX_PATH];
6071 /* Note: entry->name is a non-normalized name */
6073 osi_Log1(smb_logp, "Unlinking %s",
6074 osi_LogSaveString(smb_logp, entry->name));
6076 /* We assume this works because entry->name was
6077 successfully converted in smb_UnlinkProc() once. */
6078 cm_FsStringToNormString(entry->name, -1,
6079 normalizedName, lengthof(normalizedName));
6081 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6083 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6084 smb_NotifyChange(FILE_ACTION_REMOVED,
6085 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6086 dscp, normalizedName, NULL, TRUE);
6090 cm_DirEntryListFree(&rock.matches);
6094 cm_ReleaseUser(userp);
6097 cm_ReleaseSCache(dscp);
6102 if (code == 0 && !rock.any)
6103 code = CM_ERROR_NOSUCHFILE;
6107 typedef struct smb_renameRock {
6108 cm_scache_t *odscp; /* old dir */
6109 cm_scache_t *ndscp; /* new dir */
6110 cm_user_t *userp; /* user */
6111 cm_req_t *reqp; /* request struct */
6112 smb_vc_t *vcp; /* virtual circuit */
6113 normchar_t *maskp; /* pointer to star pattern of old file name */
6114 int flags; /* tilde, casefold, etc */
6115 clientchar_t *newNamep; /* ptr to the new file's name */
6116 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6117 clientchar_t clOldName[MAX_PATH]; /* client name */
6121 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6124 smb_renameRock_t *rockp;
6127 normchar_t matchName[MAX_PATH];
6129 rockp = (smb_renameRock_t *) vrockp;
6131 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6132 /* Can't convert string */
6133 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6134 osi_LogSaveString(smb_logp, dep->name));
6138 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6139 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6140 caseFold |= CM_FLAG_8DOT3;
6142 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6144 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6145 !cm_Is8Dot3(matchName)) {
6146 cm_Gen8Dot3Name(dep, matchName, NULL);
6147 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6152 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6153 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6155 code = CM_ERROR_STOPNOW;
6165 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6168 cm_space_t *spacep = NULL;
6169 smb_renameRock_t rock;
6170 cm_scache_t *oldDscp = NULL;
6171 cm_scache_t *newDscp = NULL;
6172 cm_scache_t *tmpscp= NULL;
6173 cm_scache_t *tmpscp2 = NULL;
6174 clientchar_t *oldLastNamep;
6175 clientchar_t *newLastNamep;
6179 clientchar_t *tidPathp;
6183 userp = smb_GetUserFromVCP(vcp, inp);
6184 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6186 cm_ReleaseUser(userp);
6187 return CM_ERROR_NOSUCHPATH;
6191 memset(&rock, 0, sizeof(rock));
6193 spacep = inp->spacep;
6194 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6196 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6197 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6198 userp, tidPathp, &req, &oldDscp);
6200 cm_ReleaseUser(userp);
6205 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6206 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6207 cm_ReleaseSCache(oldDscp);
6208 cm_ReleaseUser(userp);
6209 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6210 return CM_ERROR_PATH_NOT_COVERED;
6212 return CM_ERROR_NOSUCHPATH;
6214 #endif /* DFS_SUPPORT */
6216 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6217 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6218 userp, tidPathp, &req, &newDscp);
6221 cm_ReleaseSCache(oldDscp);
6222 cm_ReleaseUser(userp);
6227 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6228 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6229 cm_ReleaseSCache(oldDscp);
6230 cm_ReleaseSCache(newDscp);
6231 cm_ReleaseUser(userp);
6232 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6233 return CM_ERROR_PATH_NOT_COVERED;
6235 return CM_ERROR_NOSUCHPATH;
6237 #endif /* DFS_SUPPORT */
6240 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6241 * next, get the component names, and lower case them.
6244 /* handle the old name first */
6246 oldLastNamep = oldPathp;
6250 /* and handle the new name, too */
6252 newLastNamep = newPathp;
6256 /* TODO: The old name could be a wildcard. The new name must not be */
6258 /* Check if the file already exists; if so return error */
6259 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6260 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6261 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6263 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6264 osi_LogSaveClientString(smb_logp, newLastNamep));
6266 /* Check if the old and the new names differ only in case. If so return
6267 * success, else return CM_ERROR_EXISTS
6269 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6271 /* This would be a success only if the old file is *as same as* the new file */
6272 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6274 if (tmpscp == tmpscp2)
6277 code = CM_ERROR_EXISTS;
6278 cm_ReleaseSCache(tmpscp2);
6281 code = CM_ERROR_NOSUCHFILE;
6284 /* file exist, do not rename, also fixes move */
6285 osi_Log0(smb_logp, "Can't rename. Target already exists");
6286 code = CM_ERROR_EXISTS;
6291 /* do the vnode call */
6292 rock.odscp = oldDscp;
6293 rock.ndscp = newDscp;
6297 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6299 code = CM_ERROR_NOSUCHFILE;
6302 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6303 rock.newNamep = newLastNamep;
6304 rock.fsOldName[0] = '\0';
6305 rock.clOldName[0] = '\0';
6308 /* Now search the directory for the pattern, and do the appropriate rename when found */
6309 thyper.LowPart = 0; /* search dir from here */
6310 thyper.HighPart = 0;
6312 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6313 if (code == 0 && !rock.any) {
6315 thyper.HighPart = 0;
6316 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6317 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6319 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6321 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6322 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6323 rock.ndscp, rock.newNamep, rock.userp,
6325 /* if the call worked, stop doing the search now, since we
6326 * really only want to rename one file.
6329 osi_Log0(smb_logp, "cm_Rename failure");
6330 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6331 } else if (code == 0) {
6332 code = CM_ERROR_NOSUCHFILE;
6335 /* Handle Change Notification */
6337 * Being lazy, not distinguishing between files and dirs in this
6338 * filter, since we'd have to do a lookup.
6341 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6342 if (oldDscp == newDscp) {
6343 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6344 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6345 filter, oldDscp, rock.clOldName,
6346 newLastNamep, TRUE);
6348 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6349 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6350 filter, oldDscp, rock.clOldName,
6352 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6353 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6354 filter, newDscp, newLastNamep,
6361 cm_ReleaseSCache(tmpscp);
6363 cm_ReleaseUser(userp);
6365 cm_ReleaseSCache(oldDscp);
6367 cm_ReleaseSCache(newDscp);
6375 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6378 cm_space_t *spacep = NULL;
6379 cm_scache_t *oldDscp = NULL;
6380 cm_scache_t *newDscp = NULL;
6381 cm_scache_t *tmpscp= NULL;
6382 cm_scache_t *tmpscp2 = NULL;
6383 cm_scache_t *sscp = NULL;
6384 clientchar_t *oldLastNamep;
6385 clientchar_t *newLastNamep;
6388 clientchar_t *tidPathp;
6392 userp = smb_GetUserFromVCP(vcp, inp);
6394 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6396 cm_ReleaseUser(userp);
6397 return CM_ERROR_NOSUCHPATH;
6402 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6404 spacep = inp->spacep;
6405 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6407 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6408 userp, tidPathp, &req, &oldDscp);
6410 cm_ReleaseUser(userp);
6415 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6416 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6417 cm_ReleaseSCache(oldDscp);
6418 cm_ReleaseUser(userp);
6419 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6420 return CM_ERROR_PATH_NOT_COVERED;
6422 return CM_ERROR_NOSUCHPATH;
6424 #endif /* DFS_SUPPORT */
6426 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6427 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6428 userp, tidPathp, &req, &newDscp);
6430 cm_ReleaseSCache(oldDscp);
6431 cm_ReleaseUser(userp);
6436 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6437 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6438 cm_ReleaseSCache(newDscp);
6439 cm_ReleaseSCache(oldDscp);
6440 cm_ReleaseUser(userp);
6441 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6442 return CM_ERROR_PATH_NOT_COVERED;
6444 return CM_ERROR_NOSUCHPATH;
6446 #endif /* DFS_SUPPORT */
6448 /* Now, although we did two lookups for the two directories (because the same
6449 * directory can be referenced through different paths), we only allow hard links
6450 * within the same directory. */
6451 if (oldDscp != newDscp) {
6452 cm_ReleaseSCache(oldDscp);
6453 cm_ReleaseSCache(newDscp);
6454 cm_ReleaseUser(userp);
6455 return CM_ERROR_CROSSDEVLINK;
6458 /* handle the old name first */
6460 oldLastNamep = oldPathp;
6464 /* and handle the new name, too */
6466 newLastNamep = newPathp;
6470 /* now lookup the old name */
6471 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6472 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6474 cm_ReleaseSCache(oldDscp);
6475 cm_ReleaseSCache(newDscp);
6476 cm_ReleaseUser(userp);
6480 /* Check if the file already exists; if so return error */
6481 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6482 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6483 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6485 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6486 osi_LogSaveClientString(smb_logp, newLastNamep));
6488 /* if the existing link is to the same file, then we return success */
6490 if(sscp == tmpscp) {
6493 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6494 code = CM_ERROR_EXISTS;
6499 cm_ReleaseSCache(tmpscp);
6500 cm_ReleaseSCache(sscp);
6501 cm_ReleaseSCache(newDscp);
6502 cm_ReleaseSCache(oldDscp);
6503 cm_ReleaseUser(userp);
6507 /* now create the hardlink */
6508 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6509 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6510 osi_Log1(smb_logp," Link returns 0x%x", code);
6512 /* Handle Change Notification */
6514 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6515 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6516 smb_NotifyChange(FILE_ACTION_ADDED,
6517 filter, newDscp, newLastNamep,
6522 cm_ReleaseSCache(tmpscp);
6523 cm_ReleaseUser(userp);
6524 cm_ReleaseSCache(sscp);
6525 cm_ReleaseSCache(oldDscp);
6526 cm_ReleaseSCache(newDscp);
6530 /* SMB_COM_RENAME */
6532 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6534 clientchar_t *oldPathp;
6535 clientchar_t *newPathp;
6539 tp = smb_GetSMBData(inp, NULL);
6540 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6542 return CM_ERROR_BADSMB;
6543 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6545 return CM_ERROR_BADSMB;
6547 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6548 osi_LogSaveClientString(smb_logp, oldPathp),
6549 osi_LogSaveClientString(smb_logp, newPathp));
6551 if (!cm_IsValidClientString(newPathp)) {
6553 clientchar_t * hexp;
6555 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6556 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6557 osi_LogSaveClientString(smb_logp, hexp));
6561 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6563 return CM_ERROR_BADNTFILENAME;
6566 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6568 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6574 typedef struct smb_rmdirRock {
6578 normchar_t *maskp; /* pointer to the star pattern */
6581 cm_dirEntryList_t * matches;
6584 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6587 smb_rmdirRock_t *rockp;
6589 normchar_t matchName[MAX_PATH];
6591 rockp = (smb_rmdirRock_t *) vrockp;
6593 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6594 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6595 osi_LogSaveString(smb_logp, dep->name));
6599 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6600 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6602 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6604 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6605 !cm_Is8Dot3(matchName)) {
6606 cm_Gen8Dot3Name(dep, matchName, NULL);
6607 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6612 cm_DirEntryListAdd(dep->name, &rockp->matches);
6619 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6622 clientchar_t *pathp;
6626 clientchar_t *lastNamep;
6627 smb_rmdirRock_t rock;
6631 clientchar_t *tidPathp;
6635 memset(&rock, 0, sizeof(rock));
6637 tp = smb_GetSMBData(inp, NULL);
6638 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6640 return CM_ERROR_BADSMB;
6642 spacep = inp->spacep;
6643 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6645 userp = smb_GetUserFromVCP(vcp, inp);
6647 caseFold = CM_FLAG_CASEFOLD;
6649 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6651 cm_ReleaseUser(userp);
6652 return CM_ERROR_NOSUCHPATH;
6654 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6655 userp, tidPathp, &req, &dscp);
6658 cm_ReleaseUser(userp);
6663 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6664 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6665 cm_ReleaseSCache(dscp);
6666 cm_ReleaseUser(userp);
6667 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6668 return CM_ERROR_PATH_NOT_COVERED;
6670 return CM_ERROR_NOSUCHPATH;
6672 #endif /* DFS_SUPPORT */
6674 /* otherwise, scp points to the parent directory. */
6681 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6683 code = CM_ERROR_NOSUCHFILE;
6686 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6689 thyper.HighPart = 0;
6693 rock.matches = NULL;
6695 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6696 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6697 if (code == 0 && !rock.any) {
6699 thyper.HighPart = 0;
6700 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6701 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6704 if (code == 0 && rock.matches) {
6705 cm_dirEntryList_t * entry;
6707 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6708 clientchar_t clientName[MAX_PATH];
6710 /* We assume this will succeed because smb_RmdirProc()
6711 successfully converted entry->name once above. */
6712 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6714 osi_Log1(smb_logp, "Removing directory %s",
6715 osi_LogSaveString(smb_logp, entry->name));
6717 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6719 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6720 smb_NotifyChange(FILE_ACTION_REMOVED,
6721 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6722 dscp, clientName, NULL, TRUE);
6728 cm_DirEntryListFree(&rock.matches);
6731 cm_ReleaseUser(userp);
6734 cm_ReleaseSCache(dscp);
6736 if (code == 0 && !rock.any)
6737 code = CM_ERROR_NOSUCHFILE;
6746 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6756 fid = smb_GetSMBParm(inp, 0);
6758 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6760 fid = smb_ChainFID(fid, inp);
6761 fidp = smb_FindFID(vcp, fid, 0);
6763 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6765 return CM_ERROR_BADFD;
6767 userp = smb_GetUserFromVCP(vcp, inp);
6769 lock_ObtainMutex(&fidp->mx);
6770 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6771 cm_ReleaseUser(userp);
6772 lock_ReleaseMutex(&fidp->mx);
6773 smb_ReleaseFID(fidp);
6774 return CM_ERROR_BADFD;
6777 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6778 lock_ReleaseMutex(&fidp->mx);
6779 cm_ReleaseUser(userp);
6780 smb_CloseFID(vcp, fidp, NULL, 0);
6781 smb_ReleaseFID(fidp);
6782 return CM_ERROR_NOSUCHFILE;
6785 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6786 cm_scache_t * scp = fidp->scp;
6788 lock_ReleaseMutex(&fidp->mx);
6789 code = cm_FSync(scp, userp, &req, FALSE);
6790 cm_ReleaseSCache(scp);
6792 lock_ReleaseMutex(&fidp->mx);
6796 cm_ReleaseUser(userp);
6797 smb_ReleaseFID(fidp);
6801 struct smb_FullNameRock {
6804 clientchar_t *fullName;
6805 fschar_t *originalName;
6808 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6811 normchar_t matchName[MAX_PATH];
6812 struct smb_FullNameRock *vrockp;
6814 vrockp = (struct smb_FullNameRock *)rockp;
6816 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6817 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6818 osi_LogSaveString(smb_logp, dep->name));
6822 if (!cm_Is8Dot3(matchName)) {
6823 clientchar_t shortName[13];
6825 cm_Gen8Dot3Name(dep, shortName, NULL);
6827 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6828 vrockp->fullName = cm_ClientStrDup(matchName);
6829 vrockp->originalName = cm_FsStrDup(dep->name);
6830 return CM_ERROR_STOPNOW;
6833 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6834 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6835 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6836 vrockp->fullName = cm_ClientStrDup(matchName);
6837 vrockp->originalName = cm_FsStrDup(dep->name);
6838 return CM_ERROR_STOPNOW;
6843 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6844 clientchar_t **newPathp, fschar_t ** originalPathp,
6845 cm_user_t *userp, cm_req_t *reqp)
6847 struct smb_FullNameRock rock;
6850 memset(&rock, 0, sizeof(rock));
6854 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6855 if (code == CM_ERROR_STOPNOW) {
6856 *newPathp = rock.fullName;
6857 *originalPathp = rock.originalName;
6859 *newPathp = cm_ClientStrDup(pathp);
6860 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6864 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6865 afs_uint32 dosTime) {
6868 cm_scache_t *dscp = NULL;
6869 clientchar_t *pathp = NULL;
6870 cm_scache_t * scp = NULL;
6871 cm_scache_t *delscp = NULL;
6872 int nullcreator = 0;
6874 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6875 fidp, fidp->fid, scp, vcp);
6878 lock_ObtainMutex(&fidp->mx);
6879 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6881 lock_ReleaseMutex(&fidp->mx);
6882 osi_Log0(smb_logp, " No user specified. Not closing fid");
6883 return CM_ERROR_BADFD;
6886 userp = fidp->userp; /* no hold required since fidp is held
6887 throughout the function */
6888 lock_ReleaseMutex(&fidp->mx);
6893 lock_ObtainWrite(&smb_rctLock);
6894 if (fidp->deleteOk) {
6895 osi_Log0(smb_logp, " Fid already closed.");
6896 lock_ReleaseWrite(&smb_rctLock);
6897 return CM_ERROR_BADFD;
6900 lock_ReleaseWrite(&smb_rctLock);
6902 lock_ObtainMutex(&fidp->mx);
6903 if (fidp->NTopen_dscp) {
6904 dscp = fidp->NTopen_dscp;
6905 cm_HoldSCache(dscp);
6908 if (fidp->NTopen_pathp)
6909 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6916 /* Don't jump the gun on an async raw write */
6917 while (fidp->raw_writers) {
6918 lock_ReleaseMutex(&fidp->mx);
6919 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6920 lock_ObtainMutex(&fidp->mx);
6923 /* watch for ioctl closes, and read-only opens */
6925 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6926 == SMB_FID_OPENWRITE) {
6927 if (dosTime != 0 && dosTime != -1) {
6928 lock_ObtainWrite(&fidp->scp->rw);
6929 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6930 /* This fixes defect 10958 */
6931 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6932 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6933 lock_ReleaseWrite(&fidp->scp->rw);
6935 if (smb_AsyncStore != 2) {
6936 lock_ReleaseMutex(&fidp->mx);
6937 code = cm_FSync(scp, userp, &req, FALSE);
6938 lock_ObtainMutex(&fidp->mx);
6944 /* unlock any pending locks */
6945 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6946 scp->fileType == CM_SCACHETYPE_FILE) {
6950 lock_ReleaseMutex(&fidp->mx);
6953 * CM_UNLOCK_FLAG_BY_FID doesn't look at the process ID.
6956 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6957 lock_ObtainWrite(&scp->rw);
6959 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6960 CM_SCACHESYNC_NEEDCALLBACK
6961 | CM_SCACHESYNC_GETSTATUS
6962 | CM_SCACHESYNC_LOCK);
6966 "smb CoreClose SyncOp failure code 0x%x", tcode);
6967 goto post_syncopdone;
6970 cm_UnlockByKey(scp, key, CM_UNLOCK_FLAG_BY_FID, userp, &req);
6972 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6976 lock_ReleaseWrite(&scp->rw);
6977 lock_ObtainMutex(&fidp->mx);
6980 if (fidp->flags & SMB_FID_DELONCLOSE) {
6981 clientchar_t *fullPathp = NULL;
6982 fschar_t *originalNamep = NULL;
6984 lock_ReleaseMutex(&fidp->mx);
6986 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6991 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6992 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6993 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6995 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6996 smb_NotifyChange(FILE_ACTION_REMOVED,
6997 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6998 dscp, fullPathp, NULL, TRUE);
7001 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
7003 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7004 smb_NotifyChange(FILE_ACTION_REMOVED,
7005 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7006 dscp, fullPathp, NULL, TRUE);
7013 free(originalNamep);
7015 lock_ObtainMutex(&fidp->mx);
7016 fidp->flags &= ~SMB_FID_DELONCLOSE;
7019 /* if this was a newly created file, then clear the creator
7020 * in the stat cache entry. */
7021 if (fidp->flags & SMB_FID_CREATED) {
7023 fidp->flags &= ~SMB_FID_CREATED;
7026 if (fidp->flags & SMB_FID_NTOPEN) {
7027 cm_ReleaseSCache(fidp->NTopen_dscp);
7028 fidp->NTopen_dscp = NULL;
7029 free(fidp->NTopen_pathp);
7030 fidp->NTopen_pathp = NULL;
7031 fidp->flags &= ~SMB_FID_NTOPEN;
7033 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
7034 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7037 if (fidp->NTopen_wholepathp) {
7038 free(fidp->NTopen_wholepathp);
7039 fidp->NTopen_wholepathp = NULL;
7043 cm_ReleaseSCache(fidp->scp);
7046 lock_ReleaseMutex(&fidp->mx);
7049 cm_ReleaseSCache(dscp);
7052 cm_ReleaseSCache(delscp);
7056 lock_ObtainWrite(&scp->rw);
7057 if (nullcreator && scp->creator == userp)
7058 scp->creator = NULL;
7059 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7060 lock_ReleaseWrite(&scp->rw);
7061 cm_ReleaseSCache(scp);
7071 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7079 fid = smb_GetSMBParm(inp, 0);
7080 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7082 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7084 fid = smb_ChainFID(fid, inp);
7085 fidp = smb_FindFID(vcp, fid, 0);
7087 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
7089 return CM_ERROR_BADFD;
7092 userp = smb_GetUserFromVCP(vcp, inp);
7094 code = smb_CloseFID(vcp, fidp, userp, dosTime);
7096 smb_ReleaseFID(fidp);
7097 cm_ReleaseUser(userp);
7102 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7104 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7105 cm_user_t *userp, long *readp)
7111 osi_hyper_t fileLength;
7113 osi_hyper_t lastByte;
7114 osi_hyper_t bufferOffset;
7118 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7121 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7122 fidp->fid, offsetp->LowPart, count);
7126 lock_ObtainMutex(&fidp->mx);
7127 /* make sure we have a readable FD */
7128 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7129 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7130 fidp->fid, fidp->flags);
7131 lock_ReleaseMutex(&fidp->mx);
7132 code = CM_ERROR_BADFDOP;
7137 lock_ReleaseMutex(&fidp->mx);
7138 code = CM_ERROR_BADFD;
7149 lock_ObtainWrite(&scp->rw);
7151 if (offset.HighPart == 0) {
7152 chunk = offset.LowPart >> cm_logChunkSize;
7153 if (chunk != fidp->curr_chunk) {
7154 fidp->prev_chunk = fidp->curr_chunk;
7155 fidp->curr_chunk = chunk;
7157 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7160 lock_ReleaseMutex(&fidp->mx);
7162 /* start by looking up the file's end */
7163 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7164 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7168 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7170 /* now we have the entry locked, look up the length */
7171 fileLength = scp->length;
7173 /* adjust count down so that it won't go past EOF */
7174 thyper.LowPart = count;
7175 thyper.HighPart = 0;
7176 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7178 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7179 /* we'd read past EOF, so just stop at fileLength bytes.
7180 * Start by computing how many bytes remain in the file.
7182 thyper = LargeIntegerSubtract(fileLength, offset);
7184 /* if we are past EOF, read 0 bytes */
7185 if (LargeIntegerLessThanZero(thyper))
7188 count = thyper.LowPart;
7193 /* now, copy the data one buffer at a time,
7194 * until we've filled the request packet
7197 /* if we've copied all the data requested, we're done */
7198 if (count <= 0) break;
7200 /* otherwise, load up a buffer of data */
7201 thyper.HighPart = offset.HighPart;
7202 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7203 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7206 buf_Release(bufferp);
7209 lock_ReleaseWrite(&scp->rw);
7211 code = buf_Get(scp, &thyper, &req, &bufferp);
7213 lock_ObtainWrite(&scp->rw);
7214 if (code) goto done;
7215 bufferOffset = thyper;
7217 /* now get the data in the cache */
7219 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7220 CM_SCACHESYNC_NEEDCALLBACK |
7221 CM_SCACHESYNC_READ);
7225 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7227 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7229 /* otherwise, load the buffer and try again */
7230 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7234 buf_Release(bufferp);
7238 } /* if (wrong buffer) ... */
7240 /* now we have the right buffer loaded. Copy out the
7241 * data from here to the user's buffer.
7243 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7245 /* and figure out how many bytes we want from this buffer */
7246 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7247 if (nbytes > count) nbytes = count; /* don't go past EOF */
7249 /* now copy the data */
7250 memcpy(op, bufferp->datap + bufIndex, nbytes);
7252 /* adjust counters, pointers, etc. */
7255 thyper.LowPart = nbytes;
7256 thyper.HighPart = 0;
7257 offset = LargeIntegerAdd(thyper, offset);
7261 lock_ReleaseWrite(&scp->rw);
7263 buf_Release(bufferp);
7265 if (code == 0 && sequential)
7266 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7268 cm_ReleaseSCache(scp);
7271 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7272 fidp->fid, code, *readp);
7277 * smb_WriteData -- common code for Write and Raw Write
7279 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7280 cm_user_t *userp, long *writtenp)
7282 osi_hyper_t offset = *offsetp;
7285 cm_scache_t *scp = NULL;
7286 osi_hyper_t fileLength; /* file's length at start of write */
7287 osi_hyper_t minLength; /* don't read past this */
7288 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7289 cm_buf_t *bufferp = NULL;
7290 osi_hyper_t thyper; /* hyper tmp variable */
7291 osi_hyper_t bufferOffset;
7292 afs_uint32 bufIndex; /* index in buffer where our data is */
7293 int doWriteBack = 0;
7294 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7297 int needSyncOpDone = 0;
7299 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7300 fidp->fid, offsetp->LowPart, count);
7304 lock_ObtainMutex(&fidp->mx);
7305 /* make sure we have a writable FD */
7306 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7307 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7308 fidp->fid, fidp->flags);
7309 lock_ReleaseMutex(&fidp->mx);
7310 code = CM_ERROR_BADFDOP;
7318 lock_ReleaseMutex(&fidp->mx);
7320 lock_ObtainWrite(&scp->rw);
7321 /* start by looking up the file's end */
7322 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7323 CM_SCACHESYNC_NEEDCALLBACK
7324 | CM_SCACHESYNC_SETSTATUS
7325 | CM_SCACHESYNC_GETSTATUS);
7329 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7331 /* now we have the entry locked, look up the length */
7332 fileLength = scp->length;
7333 minLength = fileLength;
7334 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7335 minLength = scp->serverLength;
7337 /* adjust file length if we extend past EOF */
7338 thyper.LowPart = count;
7339 thyper.HighPart = 0;
7340 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7341 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7342 /* we'd write past EOF, so extend the file */
7343 scp->mask |= CM_SCACHEMASK_LENGTH;
7344 scp->length = thyper;
7345 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7347 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7349 /* now, if the new position (thyper) and the old (offset) are in
7350 * different storeback windows, remember to store back the previous
7351 * storeback window when we're done with the write.
7353 * the purpose of this logic is to slow down the CIFS client
7354 * in order to avoid the client disconnecting during the CLOSE
7355 * operation if there are too many dirty buffers left to write
7356 * than can be accomplished during 45 seconds. This used to be
7357 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7358 * so that we can read larger amounts of data at a time.
7360 if (smb_AsyncStore == 1 &&
7361 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7362 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7363 /* they're different */
7365 writeBackOffset.HighPart = offset.HighPart;
7366 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7371 /* now, copy the data one buffer at a time, until we've filled the
7373 while (count != 0) {
7375 /* handle over quota or out of space */
7376 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7377 *writtenp = written;
7378 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7382 /* otherwise, load up a buffer of data */
7383 thyper.HighPart = offset.HighPart;
7384 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7385 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7388 if (needSyncOpDone) {
7389 cm_SyncOpDone(scp, bufferp,
7390 CM_SCACHESYNC_NEEDCALLBACK
7391 | CM_SCACHESYNC_WRITE
7392 | CM_SCACHESYNC_BUFLOCKED);
7395 lock_ReleaseMutex(&bufferp->mx);
7396 buf_Release(bufferp);
7399 lock_ReleaseWrite(&scp->rw);
7401 code = buf_Get(scp, &thyper, &req, &bufferp);
7403 lock_ObtainMutex(&bufferp->mx);
7404 lock_ObtainWrite(&scp->rw);
7405 if (code) goto done;
7407 bufferOffset = thyper;
7409 /* now get the data in the cache */
7411 if (!needSyncOpDone) {
7412 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7413 CM_SCACHESYNC_NEEDCALLBACK
7414 | CM_SCACHESYNC_WRITE
7415 | CM_SCACHESYNC_BUFLOCKED);
7422 /* If we're overwriting the entire buffer, or
7423 * if we're writing at or past EOF, mark the
7424 * buffer as current so we don't call
7425 * cm_GetBuffer. This skips the fetch from the
7426 * server in those cases where we're going to
7427 * obliterate all the data in the buffer anyway,
7428 * or in those cases where there is no useful
7429 * data at the server to start with.
7431 * Use minLength instead of scp->length, since
7432 * the latter has already been updated by this
7435 * The scp lock has been dropped multiple times
7436 * so the minLength must be refreshed before it
7440 minLength = scp->length;
7441 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7442 minLength = scp->serverLength;
7444 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7445 || LargeIntegerEqualTo(offset, bufferp->offset)
7446 && (count >= cm_data.buf_blockSize
7447 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7448 ConvertLongToLargeInteger(count)),
7450 if (count < cm_data.buf_blockSize
7451 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7452 memset(bufferp->datap, 0,
7453 cm_data.buf_blockSize);
7454 bufferp->dataVersion = scp->dataVersion;
7457 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7459 /* otherwise, load the buffer and try again */
7460 cm_SyncOpDone(scp, bufferp,
7461 CM_SCACHESYNC_NEEDCALLBACK
7462 | CM_SCACHESYNC_WRITE
7463 | CM_SCACHESYNC_BUFLOCKED);
7466 lock_ReleaseMutex(&bufferp->mx);
7467 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7469 lock_ReleaseWrite(&scp->rw);
7470 lock_ObtainMutex(&bufferp->mx);
7471 lock_ObtainWrite(&scp->rw);
7475 } /* if (wrong buffer) ... */
7477 /* now we have the right buffer loaded. Copy out the
7478 * data from here to the user's buffer.
7480 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7482 /* and figure out how many bytes we want from this buffer */
7483 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7485 nbytes = count; /* don't go past end of request */
7487 /* now copy the data */
7488 memcpy(bufferp->datap + bufIndex, op, nbytes);
7489 buf_SetDirty(bufferp, &req, bufIndex, nbytes, userp);
7491 /* adjust counters, pointers, etc. */
7495 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7496 } /* while count != 0 */
7499 if (bufferp && needSyncOpDone) {
7500 cm_SyncOpDone(scp, bufferp,
7501 CM_SCACHESYNC_NEEDCALLBACK
7502 | CM_SCACHESYNC_WRITE
7503 | CM_SCACHESYNC_BUFLOCKED);
7506 lock_ReleaseWrite(&scp->rw);
7509 lock_ReleaseMutex(&bufferp->mx);
7510 buf_Release(bufferp);
7513 lock_ObtainMutex(&fidp->mx);
7514 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7515 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7517 lock_ReleaseMutex(&fidp->mx);
7518 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7519 fidp->NTopen_dscp, fidp->NTopen_pathp,
7522 lock_ReleaseMutex(&fidp->mx);
7526 if (smb_AsyncStore > 0) {
7530 lock_ObtainWrite(&scp->rw);
7531 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7533 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7534 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7536 lock_ReleaseWrite(&scp->rw);
7537 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7538 writeBackOffset.HighPart,
7539 smb_AsyncStoreSize, 0, userp, &req);
7540 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7543 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7547 cm_ReleaseSCache(scp);
7550 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7551 fidp->fid, code, *writtenp);
7556 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7559 unsigned short count;
7561 unsigned short hint;
7562 long written = 0, total_written = 0;
7565 smb_t* smbp = (smb_t*) inp;
7569 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7571 int inDataBlockCount;
7573 fd = smb_GetSMBParm(inp, 0);
7574 count = smb_GetSMBParm(inp, 1);
7575 offset.HighPart = 0; /* too bad */
7576 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7577 hint = smb_GetSMBParm(inp, 4);
7579 op = smb_GetSMBData(inp, NULL);
7580 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7582 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7583 fd, offset.LowPart, count);
7585 fd = smb_ChainFID(fd, inp);
7586 fidp = smb_FindFID(vcp, fd, 0);
7588 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7590 return CM_ERROR_BADFD;
7593 lock_ObtainMutex(&fidp->mx);
7594 if (fidp->flags & SMB_FID_IOCTL) {
7595 lock_ReleaseMutex(&fidp->mx);
7596 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7597 smb_ReleaseFID(fidp);
7598 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7602 if (fidp->flags & SMB_FID_RPC) {
7603 lock_ReleaseMutex(&fidp->mx);
7604 code = smb_RPCWrite(fidp, vcp, inp, outp);
7605 smb_ReleaseFID(fidp);
7606 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7611 lock_ReleaseMutex(&fidp->mx);
7612 smb_ReleaseFID(fidp);
7613 return CM_ERROR_BADFD;
7616 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7617 lock_ReleaseMutex(&fidp->mx);
7618 smb_CloseFID(vcp, fidp, NULL, 0);
7619 smb_ReleaseFID(fidp);
7620 return CM_ERROR_NOSUCHFILE;
7625 lock_ReleaseMutex(&fidp->mx);
7626 userp = smb_GetUserFromVCP(vcp, inp);
7630 LARGE_INTEGER LOffset;
7631 LARGE_INTEGER LLength;
7634 key = cm_GenerateKey(vcp->vcID, pid, fd);
7636 LOffset.HighPart = offset.HighPart;
7637 LOffset.LowPart = offset.LowPart;
7638 LLength.HighPart = 0;
7639 LLength.LowPart = count;
7641 lock_ObtainWrite(&scp->rw);
7642 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7643 lock_ReleaseWrite(&scp->rw);
7646 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7651 /* special case: 0 bytes transferred means truncate to this position */
7655 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7659 truncAttr.mask = CM_ATTRMASK_LENGTH;
7660 truncAttr.length.LowPart = offset.LowPart;
7661 truncAttr.length.HighPart = 0;
7662 lock_ObtainMutex(&fidp->mx);
7663 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7664 fidp->flags |= SMB_FID_LENGTHSETDONE;
7665 lock_ReleaseMutex(&fidp->mx);
7666 smb_SetSMBParm(outp, 0, 0 /* count */);
7667 smb_SetSMBDataLength(outp, 0);
7672 * Work around bug in NT client
7674 * When copying a file, the NT client should first copy the data,
7675 * then copy the last write time. But sometimes the NT client does
7676 * these in the wrong order, so the data copies would inadvertently
7677 * cause the last write time to be overwritten. We try to detect this,
7678 * and don't set client mod time if we think that would go against the
7681 lock_ObtainMutex(&fidp->mx);
7682 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7683 lock_ObtainWrite(&fidp->scp->rw);
7684 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7685 fidp->scp->clientModTime = time(NULL);
7686 lock_ReleaseWrite(&fidp->scp->rw);
7688 lock_ReleaseMutex(&fidp->mx);
7691 while ( code == 0 && count > 0 ) {
7692 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7693 if (code == 0 && written == 0)
7694 code = CM_ERROR_PARTIALWRITE;
7696 offset = LargeIntegerAdd(offset,
7697 ConvertLongToLargeInteger(written));
7698 count -= (unsigned short)written;
7699 total_written += written;
7703 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7704 total_written, code);
7706 /* set the packet data length to 3 bytes for the data block header,
7707 * plus the size of the data.
7709 smb_SetSMBParm(outp, 0, total_written);
7710 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7711 smb_SetSMBParm(outp, 3, hint);
7712 smb_SetSMBDataLength(outp, 0);
7715 smb_ReleaseFID(fidp);
7716 cm_ReleaseUser(userp);
7717 cm_ReleaseSCache(scp);
7722 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7723 NCB *ncbp, raw_write_cont_t *rwcp)
7732 fd = smb_GetSMBParm(inp, 0);
7733 fidp = smb_FindFID(vcp, fd, 0);
7735 lock_ObtainMutex(&fidp->mx);
7737 lock_ReleaseMutex(&fidp->mx);
7738 smb_ReleaseFID(fidp);
7742 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7743 lock_ReleaseMutex(&fidp->mx);
7744 smb_CloseFID(vcp, fidp, NULL, 0);
7745 smb_ReleaseFID(fidp);
7748 lock_ReleaseMutex(&fidp->mx);
7750 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7751 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7753 userp = smb_GetUserFromVCP(vcp, inp);
7756 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7758 if (rwcp->writeMode & 0x1) { /* synchronous */
7761 smb_FormatResponsePacket(vcp, inp, outp);
7762 op = (smb_t *) outp;
7763 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7764 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7765 smb_SetSMBDataLength(outp, 0);
7766 smb_SendPacket(vcp, outp);
7767 smb_FreePacket(outp);
7769 else { /* asynchronous */
7770 lock_ObtainMutex(&fidp->mx);
7771 fidp->raw_writers--;
7772 if (fidp->raw_writers == 0)
7773 thrd_SetEvent(fidp->raw_write_event);
7774 lock_ReleaseMutex(&fidp->mx);
7777 /* Give back raw buffer */
7778 lock_ObtainMutex(&smb_RawBufLock);
7779 *((char **)rawBuf) = smb_RawBufs;
7780 smb_RawBufs = rawBuf;
7781 lock_ReleaseMutex(&smb_RawBufLock);
7783 smb_ReleaseFID(fidp);
7784 cm_ReleaseUser(userp);
7787 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7792 /* SMB_COM_WRITE_RAW */
7793 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7796 long count, written = 0, total_written = 0;
7800 smb_t *smbp = (smb_t*) inp;
7805 unsigned short writeMode;
7807 fd = smb_GetSMBParm(inp, 0);
7808 totalCount = smb_GetSMBParm(inp, 1);
7809 count = smb_GetSMBParm(inp, 10);
7810 writeMode = smb_GetSMBParm(inp, 7);
7812 op = (char *) inp->data;
7813 op += smb_GetSMBParm(inp, 11);
7815 offset.HighPart = 0;
7816 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7818 if (*inp->wctp == 14) {
7819 /* we received a 64-bit file offset */
7820 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7822 if (LargeIntegerLessThanZero(offset)) {
7824 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7825 offset.HighPart, offset.LowPart);
7826 return CM_ERROR_BADSMB;
7829 offset.HighPart = 0; /* 32-bit file offset */
7833 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7834 fd, offset.HighPart, offset.LowPart, count);
7836 " WriteRaw WriteMode 0x%x",
7839 fd = smb_ChainFID(fd, inp);
7840 fidp = smb_FindFID(vcp, fd, 0);
7842 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7844 return CM_ERROR_BADFD;
7846 lock_ObtainMutex(&fidp->mx);
7848 lock_ReleaseMutex(&fidp->mx);
7849 smb_ReleaseFID(fidp);
7850 return CM_ERROR_BADFD;
7853 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7854 lock_ReleaseMutex(&fidp->mx);
7855 smb_CloseFID(vcp, fidp, NULL, 0);
7856 smb_ReleaseFID(fidp);
7857 return CM_ERROR_NOSUCHFILE;
7862 lock_ReleaseMutex(&fidp->mx);
7867 LARGE_INTEGER LOffset;
7868 LARGE_INTEGER LLength;
7871 key = cm_GenerateKey(vcp->vcID, pid, fd);
7873 LOffset.HighPart = offset.HighPart;
7874 LOffset.LowPart = offset.LowPart;
7875 LLength.HighPart = 0;
7876 LLength.LowPart = count;
7878 lock_ObtainWrite(&scp->rw);
7879 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7880 lock_ReleaseWrite(&scp->rw);
7883 cm_ReleaseSCache(scp);
7884 smb_ReleaseFID(fidp);
7889 userp = smb_GetUserFromVCP(vcp, inp);
7892 * Work around bug in NT client
7894 * When copying a file, the NT client should first copy the data,
7895 * then copy the last write time. But sometimes the NT client does
7896 * these in the wrong order, so the data copies would inadvertently
7897 * cause the last write time to be overwritten. We try to detect this,
7898 * and don't set client mod time if we think that would go against the
7901 lock_ObtainMutex(&fidp->mx);
7902 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7903 lock_ObtainWrite(&fidp->scp->rw);
7904 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7905 fidp->scp->clientModTime = time(NULL);
7906 lock_ReleaseWrite(&fidp->scp->rw);
7908 lock_ReleaseMutex(&fidp->mx);
7911 while ( code == 0 && count > 0 ) {
7912 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7913 if (code == 0 && written == 0)
7914 code = CM_ERROR_PARTIALWRITE;
7916 offset = LargeIntegerAdd(offset,
7917 ConvertLongToLargeInteger(written));
7920 total_written += written;
7924 /* Get a raw buffer */
7927 lock_ObtainMutex(&smb_RawBufLock);
7929 /* Get a raw buf, from head of list */
7930 rawBuf = smb_RawBufs;
7931 smb_RawBufs = *(char **)smb_RawBufs;
7934 code = CM_ERROR_USESTD;
7936 lock_ReleaseMutex(&smb_RawBufLock);
7939 /* Don't allow a premature Close */
7940 if (code == 0 && (writeMode & 1) == 0) {
7941 lock_ObtainMutex(&fidp->mx);
7942 fidp->raw_writers++;
7943 thrd_ResetEvent(fidp->raw_write_event);
7944 lock_ReleaseMutex(&fidp->mx);
7947 smb_ReleaseFID(fidp);
7948 cm_ReleaseUser(userp);
7949 cm_ReleaseSCache(scp);
7952 smb_SetSMBParm(outp, 0, total_written);
7953 smb_SetSMBDataLength(outp, 0);
7954 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7959 offset = LargeIntegerAdd(offset,
7960 ConvertLongToLargeInteger(count));
7964 rwcp->offset.HighPart = offset.HighPart;
7965 rwcp->offset.LowPart = offset.LowPart;
7966 rwcp->count = totalCount - count;
7967 rwcp->writeMode = writeMode;
7968 rwcp->alreadyWritten = total_written;
7970 /* set the packet data length to 3 bytes for the data block header,
7971 * plus the size of the data.
7973 smb_SetSMBParm(outp, 0, 0xffff);
7974 smb_SetSMBDataLength(outp, 0);
7980 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7983 long count, finalCount;
7987 smb_t *smbp = (smb_t*) inp;
7993 fd = smb_GetSMBParm(inp, 0);
7994 count = smb_GetSMBParm(inp, 1);
7995 offset.HighPart = 0; /* too bad */
7996 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7998 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7999 fd, offset.LowPart, count);
8001 fd = smb_ChainFID(fd, inp);
8002 fidp = smb_FindFID(vcp, fd, 0);
8004 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
8006 return CM_ERROR_BADFD;
8008 lock_ObtainMutex(&fidp->mx);
8009 if (fidp->flags & SMB_FID_IOCTL) {
8010 lock_ReleaseMutex(&fidp->mx);
8011 code = smb_IoctlRead(fidp, vcp, inp, outp);
8012 smb_ReleaseFID(fidp);
8016 if (fidp->flags & SMB_FID_RPC) {
8017 lock_ReleaseMutex(&fidp->mx);
8018 code = smb_RPCRead(fidp, vcp, inp, outp);
8019 smb_ReleaseFID(fidp);
8024 lock_ReleaseMutex(&fidp->mx);
8025 smb_ReleaseFID(fidp);
8026 return CM_ERROR_BADFD;
8029 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8030 lock_ReleaseMutex(&fidp->mx);
8031 smb_CloseFID(vcp, fidp, NULL, 0);
8032 smb_ReleaseFID(fidp);
8033 return CM_ERROR_NOSUCHFILE;
8038 lock_ReleaseMutex(&fidp->mx);
8041 LARGE_INTEGER LOffset, LLength;
8045 key = cm_GenerateKey(vcp->vcID, pid, fd);
8047 LOffset.HighPart = 0;
8048 LOffset.LowPart = offset.LowPart;
8049 LLength.HighPart = 0;
8050 LLength.LowPart = count;
8052 lock_ObtainWrite(&scp->rw);
8053 code = cm_LockCheckRead(scp, LOffset, LLength, key);
8054 lock_ReleaseWrite(&scp->rw);
8057 cm_ReleaseSCache(scp);
8058 smb_ReleaseFID(fidp);
8062 userp = smb_GetUserFromVCP(vcp, inp);
8064 /* remember this for final results */
8065 smb_SetSMBParm(outp, 0, count);
8066 smb_SetSMBParm(outp, 1, 0);
8067 smb_SetSMBParm(outp, 2, 0);
8068 smb_SetSMBParm(outp, 3, 0);
8069 smb_SetSMBParm(outp, 4, 0);
8071 /* set the packet data length to 3 bytes for the data block header,
8072 * plus the size of the data.
8074 smb_SetSMBDataLength(outp, count+3);
8076 /* get op ptr after putting in the parms, since otherwise we don't
8077 * know where the data really is.
8079 op = smb_GetSMBData(outp, NULL);
8081 /* now emit the data block header: 1 byte of type and 2 bytes of length */
8082 *op++ = 1; /* data block marker */
8083 *op++ = (unsigned char) (count & 0xff);
8084 *op++ = (unsigned char) ((count >> 8) & 0xff);
8086 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8088 /* fix some things up */
8089 smb_SetSMBParm(outp, 0, finalCount);
8090 smb_SetSMBDataLength(outp, finalCount+3);
8092 smb_ReleaseFID(fidp);
8094 cm_ReleaseUser(userp);
8095 cm_ReleaseSCache(scp);
8099 /* SMB_COM_CREATE_DIRECTORY */
8100 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8102 clientchar_t *pathp;
8107 cm_scache_t *dscp; /* dir we're dealing with */
8108 cm_scache_t *scp; /* file we're creating */
8110 int initialModeBits;
8111 clientchar_t *lastNamep;
8113 clientchar_t *tidPathp;
8120 /* compute initial mode bits based on read-only flag in attributes */
8121 initialModeBits = 0777;
8123 tp = smb_GetSMBData(inp, NULL);
8124 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8126 return CM_ERROR_BADSMB;
8128 spacep = inp->spacep;
8129 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8131 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8132 return CM_ERROR_EXISTS;
8134 userp = smb_GetUserFromVCP(vcp, inp);
8136 caseFold = CM_FLAG_CASEFOLD;
8138 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8140 cm_ReleaseUser(userp);
8141 return CM_ERROR_NOSUCHPATH;
8144 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
8145 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8146 userp, tidPathp, &req, &dscp);
8149 cm_ReleaseUser(userp);
8154 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8155 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8156 cm_ReleaseSCache(dscp);
8157 cm_ReleaseUser(userp);
8158 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8159 return CM_ERROR_PATH_NOT_COVERED;
8161 return CM_ERROR_NOSUCHPATH;
8163 #endif /* DFS_SUPPORT */
8165 /* otherwise, scp points to the parent directory. Do a lookup, and
8166 * fail if we find it. Otherwise, we do the create.
8172 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8173 if (scp) cm_ReleaseSCache(scp);
8174 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8175 if (code == 0) code = CM_ERROR_EXISTS;
8176 cm_ReleaseSCache(dscp);
8177 cm_ReleaseUser(userp);
8181 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8182 setAttr.clientModTime = time(NULL);
8183 smb_SetInitialModeBitsForDir(0, &setAttr);
8185 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8186 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8187 smb_NotifyChange(FILE_ACTION_ADDED,
8188 FILE_NOTIFY_CHANGE_DIR_NAME,
8189 dscp, lastNamep, NULL, TRUE);
8191 /* we don't need this any longer */
8192 cm_ReleaseSCache(dscp);
8195 /* something went wrong creating or truncating the file */
8196 cm_ReleaseUser(userp);
8200 /* otherwise we succeeded */
8201 smb_SetSMBDataLength(outp, 0);
8202 cm_ReleaseUser(userp);
8207 BOOL smb_IsLegalFilename(clientchar_t *filename)
8210 * Find the longest substring of filename that does not contain
8211 * any of the chars in illegalChars. If that substring is less
8212 * than the length of the whole string, then one or more of the
8213 * illegal chars is in filename.
8215 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8221 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8222 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8224 clientchar_t *pathp;
8230 cm_scache_t *dscp; /* dir we're dealing with */
8231 cm_scache_t *scp; /* file we're creating */
8235 clientchar_t *lastNamep;
8238 clientchar_t *tidPathp;
8240 int created = 0; /* the file was new */
8245 excl = (inp->inCom == 0x03)? 0 : 1;
8247 attributes = smb_GetSMBParm(inp, 0);
8248 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8250 tp = smb_GetSMBData(inp, NULL);
8251 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8253 return CM_ERROR_BADSMB;
8255 spacep = inp->spacep;
8256 /* smb_StripLastComponent will strip "::$DATA" if present */
8257 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8259 if (!cm_IsValidClientString(pathp)) {
8261 clientchar_t * hexp;
8263 hexp = cm_GetRawCharsAlloc(pathp, -1);
8264 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8265 osi_LogSaveClientString(smb_logp, hexp));
8269 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8271 return CM_ERROR_BADNTFILENAME;
8274 userp = smb_GetUserFromVCP(vcp, inp);
8276 caseFold = CM_FLAG_CASEFOLD;
8278 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8280 cm_ReleaseUser(userp);
8281 return CM_ERROR_NOSUCHPATH;
8283 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8284 userp, tidPathp, &req, &dscp);
8287 cm_ReleaseUser(userp);
8292 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8293 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8294 cm_ReleaseSCache(dscp);
8295 cm_ReleaseUser(userp);
8296 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8297 return CM_ERROR_PATH_NOT_COVERED;
8299 return CM_ERROR_NOSUCHPATH;
8301 #endif /* DFS_SUPPORT */
8303 /* otherwise, scp points to the parent directory. Do a lookup, and
8304 * truncate the file if we find it, otherwise we create the file.
8311 if (!smb_IsLegalFilename(lastNamep))
8312 return CM_ERROR_BADNTFILENAME;
8314 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8315 #ifdef DEBUG_VERBOSE
8318 hexp = osi_HexifyString( lastNamep );
8319 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8324 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8325 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8326 cm_ReleaseSCache(dscp);
8327 cm_ReleaseUser(userp);
8331 /* if we get here, if code is 0, the file exists and is represented by
8332 * scp. Otherwise, we have to create it.
8336 /* oops, file shouldn't be there */
8337 cm_ReleaseSCache(dscp);
8338 cm_ReleaseSCache(scp);
8339 cm_ReleaseUser(userp);
8340 return CM_ERROR_EXISTS;
8343 setAttr.mask = CM_ATTRMASK_LENGTH;
8344 setAttr.length.LowPart = 0;
8345 setAttr.length.HighPart = 0;
8346 code = cm_SetAttr(scp, &setAttr, userp, &req);
8349 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8350 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8351 smb_SetInitialModeBitsForFile(attributes, &setAttr);
8353 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8357 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8358 smb_NotifyChange(FILE_ACTION_ADDED,
8359 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8360 dscp, lastNamep, NULL, TRUE);
8361 } else if (!excl && code == CM_ERROR_EXISTS) {
8362 /* not an exclusive create, and someone else tried
8363 * creating it already, then we open it anyway. We
8364 * don't bother retrying after this, since if this next
8365 * fails, that means that the file was deleted after
8366 * we started this call.
8368 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8371 setAttr.mask = CM_ATTRMASK_LENGTH;
8372 setAttr.length.LowPart = 0;
8373 setAttr.length.HighPart = 0;
8374 code = cm_SetAttr(scp, &setAttr, userp, &req);
8379 /* we don't need this any longer */
8380 cm_ReleaseSCache(dscp);
8383 /* something went wrong creating or truncating the file */
8384 if (scp) cm_ReleaseSCache(scp);
8385 cm_ReleaseUser(userp);
8389 /* make sure we only open files */
8390 if (scp->fileType != CM_SCACHETYPE_FILE) {
8391 cm_ReleaseSCache(scp);
8392 cm_ReleaseUser(userp);
8393 return CM_ERROR_ISDIR;
8396 /* now all we have to do is open the file itself */
8397 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8398 osi_assertx(fidp, "null smb_fid_t");
8402 lock_ObtainMutex(&fidp->mx);
8403 /* always create it open for read/write */
8404 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8406 /* remember that the file was newly created */
8408 fidp->flags |= SMB_FID_CREATED;
8410 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8412 /* save a pointer to the vnode */
8414 lock_ObtainWrite(&scp->rw);
8415 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8416 lock_ReleaseWrite(&scp->rw);
8419 fidp->userp = userp;
8420 lock_ReleaseMutex(&fidp->mx);
8422 smb_SetSMBParm(outp, 0, fidp->fid);
8423 smb_SetSMBDataLength(outp, 0);
8425 cm_Open(scp, 0, userp);
8427 smb_ReleaseFID(fidp);
8428 cm_ReleaseUser(userp);
8429 /* leave scp held since we put it in fidp->scp */
8434 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8437 osi_hyper_t new_offset;
8448 fd = smb_GetSMBParm(inp, 0);
8449 whence = smb_GetSMBParm(inp, 1);
8450 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8452 /* try to find the file descriptor */
8453 fd = smb_ChainFID(fd, inp);
8454 fidp = smb_FindFID(vcp, fd, 0);
8456 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8458 return CM_ERROR_BADFD;
8460 lock_ObtainMutex(&fidp->mx);
8461 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8462 lock_ReleaseMutex(&fidp->mx);
8463 smb_ReleaseFID(fidp);
8464 return CM_ERROR_BADFD;
8467 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8468 lock_ReleaseMutex(&fidp->mx);
8469 smb_CloseFID(vcp, fidp, NULL, 0);
8470 smb_ReleaseFID(fidp);
8471 return CM_ERROR_NOSUCHFILE;
8474 lock_ReleaseMutex(&fidp->mx);
8476 userp = smb_GetUserFromVCP(vcp, inp);
8478 lock_ObtainMutex(&fidp->mx);
8481 lock_ReleaseMutex(&fidp->mx);
8482 lock_ObtainWrite(&scp->rw);
8483 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8484 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8486 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8488 /* offset from current offset */
8489 new_offset = LargeIntegerAdd(fidp->offset,
8490 ConvertLongToLargeInteger(offset));
8492 else if (whence == 2) {
8493 /* offset from current EOF */
8494 new_offset = LargeIntegerAdd(scp->length,
8495 ConvertLongToLargeInteger(offset));
8497 new_offset = ConvertLongToLargeInteger(offset);
8500 fidp->offset = new_offset;
8501 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8502 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8503 smb_SetSMBDataLength(outp, 0);
8505 lock_ReleaseWrite(&scp->rw);
8506 smb_ReleaseFID(fidp);
8507 cm_ReleaseSCache(scp);
8508 cm_ReleaseUser(userp);
8512 /* dispatch all of the requests received in a packet. Due to chaining, this may
8513 * be more than one request.
8515 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8516 NCB *ncbp, raw_write_cont_t *rwcp)
8520 unsigned long code = 0;
8521 unsigned char *outWctp;
8522 int nparms; /* # of bytes of parameters */
8524 int nbytes; /* bytes of data, excluding count */
8527 unsigned short errCode;
8528 unsigned long NTStatus;
8530 unsigned char errClass;
8531 unsigned int oldGen;
8532 DWORD oldTime, newTime;
8534 /* get easy pointer to the data */
8535 smbp = (smb_t *) inp->data;
8537 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8538 /* setup the basic parms for the initial request in the packet */
8539 inp->inCom = smbp->com;
8540 inp->wctp = &smbp->wct;
8542 inp->ncb_length = ncbp->ncb_length;
8547 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8548 /* log it and discard it */
8549 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8550 __FILE__, __LINE__, ncbp->ncb_length);
8551 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8555 /* We are an ongoing op */
8556 thrd_Increment(&ongoingOps);
8558 /* set up response packet for receiving output */
8559 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8560 smb_FormatResponsePacket(vcp, inp, outp);
8561 outWctp = outp->wctp;
8563 /* Remember session generation number and time */
8564 oldGen = sessionGen;
8565 oldTime = GetTickCount();
8567 while (inp->inCom != 0xff) {
8568 dp = &smb_dispatchTable[inp->inCom];
8570 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8571 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8572 code = outp->resumeCode;
8576 /* process each request in the packet; inCom, wctp and inCount
8577 * are already set up.
8579 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8582 /* now do the dispatch */
8583 /* start by formatting the response record a little, as a default */
8584 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8586 outWctp[1] = 0xff; /* no operation */
8587 outWctp[2] = 0; /* padding */
8592 /* not a chained request, this is a more reasonable default */
8593 outWctp[0] = 0; /* wct of zero */
8594 outWctp[1] = 0; /* and bcc (word) of zero */
8598 /* once set, stays set. Doesn't matter, since we never chain
8599 * "no response" calls.
8601 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8605 /* we have a recognized operation */
8606 char * opName = myCrt_Dispatch(inp->inCom);
8609 smbp = (smb_t *) inp;
8611 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8612 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8613 if (inp->inCom == 0x1d) {
8615 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8617 code = (*(dp->procp)) (vcp, inp, outp);
8619 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8620 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8622 newTime = GetTickCount();
8623 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8624 opName, smbp->mid, newTime - oldTime);
8627 if ( code == CM_ERROR_BADSMB ||
8628 code == CM_ERROR_BADOP )
8630 #endif /* LOG_PACKET */
8632 /* ReceiveV3Tran2A handles its own logging */
8633 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8636 clientchar_t *treepath = NULL; /* do not free */
8637 clientchar_t *pathname = NULL;
8638 cm_fid_t afid = {0,0,0,0,0};
8640 uidp = smb_FindUID(vcp, smbp->uid, 0);
8641 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8642 fidp = smb_FindFID(vcp, inp->fid, 0);
8645 lock_ObtainMutex(&fidp->mx);
8646 if (fidp->NTopen_pathp)
8647 pathname = fidp->NTopen_pathp;
8649 afid = fidp->scp->fid;
8651 if (inp->stringsp->wdata)
8652 pathname = inp->stringsp->wdata;
8655 afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
8656 opName, newTime - oldTime,
8657 smbp->uid, uidp ? uidp->unp->name : NULL,
8658 smbp->pid, smbp->mid, smbp->tid,
8661 afid.cell, afid.volume, afid.vnode, afid.unique);
8664 lock_ReleaseMutex(&fidp->mx);
8667 smb_ReleaseUID(uidp);
8669 smb_ReleaseFID(fidp);
8672 if (oldGen != sessionGen) {
8673 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8674 newTime - oldTime, ncbp->ncb_length);
8675 osi_Log3(smb_logp, "Request %s straddled session startup, "
8676 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8679 FreeSMBStrings(inp);
8681 /* bad opcode, fail the request, after displaying it */
8682 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8685 #endif /* LOG_PACKET */
8688 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8689 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8690 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8691 if (code == IDCANCEL)
8694 code = CM_ERROR_BADOP;
8697 /* catastrophic failure: log as much as possible */
8698 if (code == CM_ERROR_BADSMB) {
8699 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8703 #endif /* LOG_PACKET */
8704 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8707 code = CM_ERROR_INVAL;
8710 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8711 thrd_Decrement(&ongoingOps);
8716 /* now, if we failed, turn the current response into an empty
8717 * one, and fill in the response packet's error code.
8720 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8721 smb_MapNTError(code, &NTStatus, FALSE);
8722 outWctp = outp->wctp;
8723 smbp = (smb_t *) &outp->data;
8724 if (code != CM_ERROR_PARTIALWRITE
8725 && code != CM_ERROR_BUFFERTOOSMALL
8726 && code != CM_ERROR_GSSCONTINUE) {
8727 /* nuke wct and bcc. For a partial
8728 * write or an in-process authentication handshake,
8729 * assume they're OK.
8735 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8736 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8737 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8738 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8739 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8743 smb_MapCoreError(code, vcp, &errCode, &errClass);
8744 outWctp = outp->wctp;
8745 smbp = (smb_t *) &outp->data;
8746 if (code != CM_ERROR_PARTIALWRITE) {
8747 /* nuke wct and bcc. For a partial
8748 * write, assume they're OK.
8754 smbp->errLow = (unsigned char) (errCode & 0xff);
8755 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8756 smbp->rcls = errClass;
8759 } /* error occurred */
8761 /* if we're here, we've finished one request. Look to see if
8762 * this is a chained opcode. If it is, setup things to process
8763 * the chained request, and setup the output buffer to hold the
8764 * chained response. Start by finding the next input record.
8766 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8767 break; /* not a chained req */
8768 tp = inp->wctp; /* points to start of last request */
8769 /* in a chained request, the first two
8770 * parm fields are required, and are
8771 * AndXCommand/AndXReserved and
8773 if (tp[0] < 2) break;
8774 if (tp[1] == 0xff) break; /* no more chained opcodes */
8776 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8779 /* and now append the next output request to the end of this
8780 * last request. Begin by finding out where the last response
8781 * ends, since that's where we'll put our new response.
8783 outWctp = outp->wctp; /* ptr to out parameters */
8784 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8785 nparms = outWctp[0] << 1;
8786 tp = outWctp + nparms + 1; /* now points to bcc field */
8787 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8788 tp += 2 /* for the count itself */ + nbytes;
8789 /* tp now points to the new output record; go back and patch the
8790 * second parameter (off2) to point to the new record.
8792 temp = (unsigned int)(tp - outp->data);
8793 outWctp[3] = (unsigned char) (temp & 0xff);
8794 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8795 outWctp[2] = 0; /* padding */
8796 outWctp[1] = inp->inCom; /* next opcode */
8798 /* finally, setup for the next iteration */
8801 } /* while loop over all requests in the packet */
8803 /* now send the output packet, and return */
8805 smb_SendPacket(vcp, outp);
8806 thrd_Decrement(&ongoingOps);
8811 /* Wait for Netbios() calls to return, and make the results available to server
8812 * threads. Note that server threads can't wait on the NCBevents array
8813 * themselves, because NCB events are manual-reset, and the servers would race
8814 * each other to reset them.
8816 void smb_ClientWaiter(void *parmp)
8821 while (smbShutdownFlag == 0) {
8822 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8824 if (code == WAIT_OBJECT_0)
8827 /* error checking */
8828 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8830 int abandonIdx = code - WAIT_ABANDONED_0;
8831 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8834 if (code == WAIT_IO_COMPLETION)
8836 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8840 if (code == WAIT_TIMEOUT)
8842 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8845 if (code == WAIT_FAILED)
8847 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8850 idx = code - WAIT_OBJECT_0;
8852 /* check idx range! */
8853 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8855 /* this is fatal - log as much as possible */
8856 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8857 osi_assertx(0, "invalid index");
8860 thrd_ResetEvent(NCBevents[idx]);
8861 thrd_SetEvent(NCBreturns[0][idx]);
8866 * Try to have one NCBRECV request waiting for every live session. Not more
8867 * than one, because if there is more than one, it's hard to handle Write Raw.
8869 void smb_ServerWaiter(void *parmp)
8872 int idx_session, idx_NCB;
8875 while (smbShutdownFlag == 0) {
8877 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8879 if (code == WAIT_OBJECT_0)
8882 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8884 int abandonIdx = code - WAIT_ABANDONED_0;
8885 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8888 if (code == WAIT_IO_COMPLETION)
8890 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8894 if (code == WAIT_TIMEOUT)
8896 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8899 if (code == WAIT_FAILED)
8901 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8904 idx_session = code - WAIT_OBJECT_0;
8906 /* check idx range! */
8907 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8909 /* this is fatal - log as much as possible */
8910 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8911 osi_assertx(0, "invalid index");
8916 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8918 if (code == WAIT_OBJECT_0) {
8919 if (smbShutdownFlag == 1)
8925 /* error checking */
8926 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8928 int abandonIdx = code - WAIT_ABANDONED_0;
8929 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8932 if (code == WAIT_IO_COMPLETION)
8934 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8938 if (code == WAIT_TIMEOUT)
8940 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8943 if (code == WAIT_FAILED)
8945 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8948 idx_NCB = code - WAIT_OBJECT_0;
8950 /* check idx range! */
8951 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8953 /* this is fatal - log as much as possible */
8954 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8955 osi_assertx(0, "invalid index");
8958 /* Link them together */
8959 NCBsessions[idx_NCB] = idx_session;
8962 ncbp = NCBs[idx_NCB];
8963 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8964 ncbp->ncb_command = NCBRECV | ASYNCH;
8965 ncbp->ncb_lana_num = lanas[idx_session];
8966 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8967 ncbp->ncb_event = NCBevents[idx_NCB];
8968 ncbp->ncb_length = SMB_PACKETSIZE;
8973 typedef struct _monitored_task {
8976 LARGE_INTEGER start_time;
8978 BOOL trace_timer_hit;
8979 BOOL dump_timer_hit;
8982 typedef struct osi_queueHT {
8983 osi_queue_t * headp;
8984 osi_queue_t * tailp;
8987 static osi_queue_t *smb_monitored_tasks = NULL;
8988 static osi_queue_t *smb_free_monitored_tasks = NULL;
8990 static osi_mutex_t _monitor_mx;
8992 static HANDLE h_monitored_task_queue = NULL;
8993 static HANDLE h_monitored_task_shutdown = NULL;
8995 static time_t smb_last_dump_time = 0;
8997 DWORD smb_monitorReqs = 0;
8999 /* FILETIME comparison fuzz */
9000 #define MONITOR_FUZZ_TIMEOUT (1 * 10000000i64)
9002 /* Trace timeout is at 60 seconds */
9003 #define MONITOR_TRACE_TIMEOUT (60 * 10000000i64)
9005 /* Dump timeout is at 120 seconds */
9006 #define MONITOR_DUMP_TIMEOUT (120 * 10000000i64)
9008 /* Time before another dump is performed in seconds*/
9009 #define MONITOR_DUMP_RESET_TIMEOUT (600)
9011 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
9014 LARGE_INTEGER earliest;
9017 GetSystemTimeAsFileTime(&now);
9018 earliest.LowPart = now.dwLowDateTime;
9019 earliest.HighPart = now.dwHighDateTime;
9020 earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
9022 while ((t = (monitored_task *) taskmq->headp) != NULL &&
9024 (t->start_time.QuadPart < earliest.QuadPart ||
9026 t->dump_timer_hit)) {
9028 osi_QRemoveHT(&taskmq->headp,
9032 lock_ObtainMutex(&_monitor_mx);
9033 osi_QAdd(&smb_free_monitored_tasks, &t->q);
9034 lock_ReleaseMutex(&_monitor_mx);
9037 #ifdef INVARIANT_CHECK
9043 for (t = (monitored_task *) taskmq->headp;
9045 t = (monitored_task *) osi_QNext(&t->q)) {
9046 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9047 last.QuadPart = t->start_time.QuadPart;
9053 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
9055 monitored_task * task;
9056 monitored_task * tasks;
9058 lock_ObtainMutex(&_monitor_mx);
9059 tasks = (monitored_task *) smb_monitored_tasks;
9060 smb_monitored_tasks = NULL;
9061 lock_ReleaseMutex(&_monitor_mx);
9066 osi_QRemove((osi_queue_t **) &tasks, &task->q);
9068 if (task->started) {
9074 q.prevp = taskmq->tailp;
9076 /* Insertion sort by start_time. Earliest request is
9077 first. Since we are likely to receive new requests
9078 later, we start inserting from the back. */
9081 ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
9085 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
9086 else if (p->prevp == NULL)
9087 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
9089 osi_queue_t *o = p->prevp;
9091 osi_assert(o->nextp == p);
9095 p->prevp = &task->q;
9096 o->nextp = &task->q;
9100 /* Some task ending */
9104 for (p = taskmq->headp;
9108 monitored_task * mt = (monitored_task *) p;
9110 if (mt->task_id == task->task_id) {
9112 osi_QRemoveHT(&taskmq->headp,
9115 lock_ObtainMutex(&_monitor_mx);
9116 osi_QAdd(&smb_free_monitored_tasks, p);
9117 lock_ReleaseMutex(&_monitor_mx);
9123 lock_ObtainMutex(&_monitor_mx);
9124 osi_QAdd(&smb_free_monitored_tasks, &task->q);
9125 lock_ReleaseMutex(&_monitor_mx);
9129 #ifdef INVARIANT_CHECK
9136 for (t = (monitored_task *) taskmq->headp;
9138 t = (monitored_task *) osi_QNext(&t->q)) {
9139 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9140 last.QuadPart = t->start_time.QuadPart;
9146 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9148 if (!task->trace_timer_hit) {
9150 task->trace_timer_hit = TRUE;
9152 osi_LogEnable(afsd_logp);
9153 rx_DebugOnOff(TRUE);
9155 } else if (!task->dump_timer_hit) {
9160 if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9161 task->dump_timer_hit = TRUE;
9162 smb_last_dump_time = now;
9164 GenerateMiniDump(NULL);
9170 * Server request monitoring
9172 * The server monitor runs in a separate thread and monitors server
9173 * requests for potential timeouts. It examines notifcations queued
9174 * by smb_NotifyRequestEvent() and waits for potential timeout events:
9176 * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9177 * enables trace logging.
9179 * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9180 * out a dump file that will hopefully contain enough evidence to
9181 * figure out why the timeout event occurred.
9184 void smb_ServerMonitor(VOID * parmp)
9186 osi_queueHT_t in_progress = { NULL, NULL };
9187 HANDLE h_timer = NULL;
9191 h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9192 h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9193 h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9195 lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9197 h_all[0] = h_monitored_task_queue;
9199 h_all[2] = h_monitored_task_shutdown;
9204 rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9206 if (rv == WAIT_OBJECT_0) {
9208 smb_SlurpNewTaskMonitors(&in_progress);
9210 } else if (rv == WAIT_OBJECT_0 + 1) {
9212 smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9220 /* refresh timers */
9224 smb_PurgeOldTaskMonitors(&in_progress);
9225 t = (monitored_task *) in_progress.headp;
9227 if (t && !t->trace_timer_hit) {
9230 due = t->start_time;
9231 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9233 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9234 } else if (t && !t->dump_timer_hit) {
9238 due = t->start_time;
9239 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9241 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9243 CancelWaitableTimer(h_timer);
9245 /* CancelWaitableTimer() doesn't reset the timer if it
9246 was already signalled. */
9247 WaitForSingleObject(h_timer, 0);
9255 h = h_monitored_task_queue;
9256 h_monitored_task_queue = NULL;
9259 h = h_monitored_task_shutdown;
9260 h_monitored_task_shutdown = NULL;
9263 CloseHandle(h_timer);
9265 lock_FinalizeMutex(&_monitor_mx);
9269 monitored_task * task;
9271 while (in_progress.headp) {
9272 task = (monitored_task *) in_progress.headp;
9273 osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9277 for (task = (monitored_task *) smb_free_monitored_tasks;
9278 task; task = (monitored_task *) smb_free_monitored_tasks) {
9279 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9283 for (task = (monitored_task *) smb_monitored_tasks;
9284 task; task = (monitored_task *) smb_monitored_tasks) {
9285 osi_QRemove(&smb_monitored_tasks, &task->q);
9291 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9293 monitored_task * task;
9295 lock_ObtainMutex(&_monitor_mx);
9296 task = (monitored_task *) smb_free_monitored_tasks;
9298 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9299 lock_ReleaseMutex(&_monitor_mx);
9302 task = malloc(sizeof(monitored_task));
9303 memset(task, 0, sizeof(*task));
9305 task->task_id = task_id;
9306 task->started = started;
9311 GetSystemTimeAsFileTime(&now);
9312 task->start_time.HighPart = now.dwHighDateTime;
9313 task->start_time.LowPart = now.dwLowDateTime;
9316 lock_ObtainMutex(&_monitor_mx);
9317 osi_QAdd(&smb_monitored_tasks, &task->q);
9318 lock_ReleaseMutex(&_monitor_mx);
9320 SetEvent(h_monitored_task_queue);
9323 void smb_ShutdownMonitor()
9325 SetEvent(h_monitored_task_shutdown);
9329 * The top level loop for handling SMB request messages. Each server thread
9330 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9331 * NCB and buffer for the incoming request are loaned to us.
9333 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
9334 * to immediately send a request for the rest of the data. This must come
9335 * before any other traffic for that session, so we delay setting the session
9336 * event until that data has come in.
9338 void smb_Server(VOID *parmp)
9340 INT_PTR myIdx = (INT_PTR) parmp;
9344 smb_packet_t *outbufp;
9346 int idx_NCB, idx_session;
9348 smb_vc_t *vcp = NULL;
9351 rx_StartClientThread();
9353 outncbp = smb_GetNCB();
9354 outbufp = smb_GetPacket();
9355 outbufp->ncbp = outncbp;
9363 cm_ResetServerPriority();
9365 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9368 /* terminate silently if shutdown flag is set */
9369 if (code == WAIT_OBJECT_0) {
9370 if (smbShutdownFlag == 1) {
9371 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9377 /* error checking */
9378 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9380 int abandonIdx = code - WAIT_ABANDONED_0;
9381 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9384 if (code == WAIT_IO_COMPLETION)
9386 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9390 if (code == WAIT_TIMEOUT)
9392 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9395 if (code == WAIT_FAILED)
9397 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9400 idx_NCB = code - WAIT_OBJECT_0;
9402 /* check idx range! */
9403 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9405 /* this is fatal - log as much as possible */
9406 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9407 osi_assertx(0, "invalid index");
9410 ncbp = NCBs[idx_NCB];
9411 idx_session = NCBsessions[idx_NCB];
9412 rc = ncbp->ncb_retcode;
9414 if (rc != NRC_PENDING && rc != NRC_GOODRET)
9415 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9419 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9423 /* Can this happen? Or is it just my UNIX paranoia? */
9424 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9429 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9432 /* Client closed session */
9433 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9435 lock_ObtainMutex(&vcp->mx);
9436 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9437 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9439 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9440 lock_ReleaseMutex(&vcp->mx);
9441 lock_ObtainWrite(&smb_globalLock);
9442 dead_sessions[vcp->session] = TRUE;
9443 lock_ReleaseWrite(&smb_globalLock);
9445 lock_ReleaseMutex(&vcp->mx);
9447 smb_CleanupDeadVC(vcp);
9454 /* Treat as transient error */
9455 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9458 "dispatch smb recv failed, message incomplete, ncb_length %d",
9461 "SMB message incomplete, "
9462 "length %d", ncbp->ncb_length);
9465 * We used to discard the packet.
9466 * Instead, try handling it normally.
9470 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9474 /* A weird error code. Log it, sleep, and continue. */
9475 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9477 lock_ObtainMutex(&vcp->mx);
9478 if (vcp->errorCount++ > 3) {
9479 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9480 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9481 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9483 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9484 lock_ReleaseMutex(&vcp->mx);
9485 lock_ObtainWrite(&smb_globalLock);
9486 dead_sessions[vcp->session] = TRUE;
9487 lock_ReleaseWrite(&smb_globalLock);
9489 lock_ReleaseMutex(&vcp->mx);
9491 smb_CleanupDeadVC(vcp);
9497 lock_ReleaseMutex(&vcp->mx);
9501 thrd_SetEvent(SessionEvents[idx_session]);
9507 /* Success, so now dispatch on all the data in the packet */
9509 smb_concurrentCalls++;
9510 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9511 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9514 * If at this point vcp is NULL (implies that packet was invalid)
9515 * then we are in big trouble. This means either :
9516 * a) we have the wrong NCB.
9517 * b) Netbios screwed up the call.
9518 * c) The VC was already marked dead before we were able to
9520 * Obviously this implies that
9521 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9522 * lanas[idx_session] != ncbp->ncb_lana_num )
9523 * Either way, we can't do anything with this packet.
9524 * Log, sleep and resume.
9527 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9531 ncbp->ncb_lana_num);
9533 /* Also log in the trace log. */
9534 osi_Log4(smb_logp, "Server: VCP does not exist!"
9535 "LSNs[idx_session]=[%d],"
9536 "lanas[idx_session]=[%d],"
9537 "ncbp->ncb_lsn=[%d],"
9538 "ncbp->ncb_lana_num=[%d]",
9542 ncbp->ncb_lana_num);
9544 /* thrd_Sleep(1000); Don't bother sleeping */
9545 thrd_SetEvent(SessionEvents[idx_session]);
9546 smb_concurrentCalls--;
9550 cm_SetRequestStartTime();
9551 if (smb_monitorReqs) {
9552 smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9555 vcp->errorCount = 0;
9556 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9557 smbp = (smb_t *)bufp->data;
9564 if (smbp->com == 0x1d) {
9565 /* Special handling for Write Raw */
9566 raw_write_cont_t rwc;
9568 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9569 if (rwc.code == 0) {
9570 EVENT_HANDLE rwevent;
9571 char eventName[MAX_PATH];
9573 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9574 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9575 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9576 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9578 ncbp->ncb_command = NCBRECV | ASYNCH;
9579 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9580 ncbp->ncb_lana_num = vcp->lana;
9581 ncbp->ncb_buffer = rwc.buf;
9582 ncbp->ncb_length = 65535;
9583 ncbp->ncb_event = rwevent;
9585 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9586 thrd_CloseHandle(rwevent);
9588 thrd_SetEvent(SessionEvents[idx_session]);
9590 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9592 else if (smbp->com == 0xa0) {
9594 * Serialize the handling for NT Transact
9597 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9598 thrd_SetEvent(SessionEvents[idx_session]);
9600 thrd_SetEvent(SessionEvents[idx_session]);
9601 /* TODO: what else needs to be serialized? */
9602 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9606 __except( smb_ServerExceptionFilter() ) {
9610 if (smb_monitorReqs) {
9611 smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9613 smb_concurrentCalls--;
9616 thrd_SetEvent(NCBavails[idx_NCB]);
9621 smb_FreePacket(outbufp);
9623 smb_FreeNCB(outncbp);
9627 * Exception filter for the server threads. If an exception occurs in the
9628 * dispatch routines, which is where exceptions are most common, then do a
9629 * force trace and give control to upstream exception handlers. Useful for
9632 DWORD smb_ServerExceptionFilter(void) {
9633 /* While this is not the best time to do a trace, if it succeeds, then
9634 * we have a trace (assuming tracing was enabled). Otherwise, this should
9635 * throw a second exception.
9637 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9638 afsd_ForceTrace(TRUE);
9639 buf_ForceTrace(TRUE);
9640 return EXCEPTION_CONTINUE_SEARCH;
9644 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9645 * If the number of server threads is M, and the number of live sessions is
9646 * N, then the number of NCB's in use at any time either waiting for, or
9647 * holding, received messages is M + N, so that is how many NCB's get created.
9649 void InitNCBslot(int idx)
9651 struct smb_packet *bufp;
9652 EVENT_HANDLE retHandle;
9654 char eventName[MAX_PATH];
9656 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9658 NCBs[idx] = smb_GetNCB();
9659 sprintf(eventName,"NCBavails[%d]", idx);
9660 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9661 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9662 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9663 sprintf(eventName,"NCBevents[%d]", idx);
9664 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9665 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9666 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9667 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9668 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9669 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9670 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9671 for (i=0; i<smb_NumServerThreads; i++)
9672 NCBreturns[i][idx] = retHandle;
9673 bufp = smb_GetPacket();
9674 bufp->spacep = cm_GetSpace();
9678 /* listen for new connections */
9679 void smb_Listener(void *parmp)
9685 afs_uint32 session, thread;
9686 smb_vc_t *vcp = NULL;
9688 char rname[NCBNAMSZ+1];
9689 char cname[MAX_COMPUTERNAME_LENGTH+1];
9690 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9691 INT_PTR lana = (INT_PTR) parmp;
9692 char eventName[MAX_PATH];
9693 int bridgeCount = 0;
9694 int nowildCount = 0;
9696 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9697 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9698 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9699 thrd_ResetEvent(ListenerShutdown[lana]);
9701 ncbp = smb_GetNCB();
9703 /* retrieve computer name */
9704 GetComputerName(cname, &cnamelen);
9707 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9708 memset(ncbp, 0, sizeof(NCB));
9711 ncbp->ncb_command = NCBLISTEN;
9712 ncbp->ncb_rto = 0; /* No receive timeout */
9713 ncbp->ncb_sto = 0; /* No send timeout */
9715 /* pad out with spaces instead of null termination */
9716 len = (long)strlen(smb_localNamep);
9717 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9718 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9720 strcpy(ncbp->ncb_callname, "*");
9721 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9723 ncbp->ncb_lana_num = (UCHAR)lana;
9725 code = Netbios(ncbp);
9727 if (code == NRC_NAMERR) {
9728 /* An smb shutdown or Vista resume must have taken place */
9730 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9731 ncbp->ncb_lana_num);
9732 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9734 if (lock_TryMutex(&smb_StartedLock)) {
9735 lana_list.lana[i] = LANA_INVALID;
9736 lock_ReleaseMutex(&smb_StartedLock);
9739 } else if (code == NRC_BRIDGE || code != 0) {
9740 int lanaRemaining = 0;
9742 if (code == NRC_BRIDGE) {
9743 if (++bridgeCount <= 5) {
9744 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9747 } else if (code == NRC_NOWILD) {
9748 if (++nowildCount <= 5) {
9749 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9751 if (bridgeCount > 0) {
9752 memset(ncbp, 0, sizeof(*ncbp));
9753 ncbp->ncb_command = NCBADDNAME;
9754 ncbp->ncb_lana_num = (UCHAR)lana;
9755 /* pad out with spaces instead of null termination */
9756 len = (long)strlen(smb_localNamep);
9757 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9758 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9759 code = Netbios(ncbp);
9765 while (!lock_TryMutex(&smb_StartedLock)) {
9766 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9772 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9773 ncbp->ncb_lana_num, ncb_error_string(code));
9774 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9775 ncbp->ncb_lana_num, ncb_error_string(code));
9777 for (i = 0; i < lana_list.length; i++) {
9778 if (lana_list.lana[i] == lana) {
9779 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9780 lana_list.lana[i] = LANA_INVALID;
9782 if (lana_list.lana[i] != LANA_INVALID)
9786 if (lanaRemaining == 0) {
9787 cm_VolStatus_Network_Stopped(cm_NetbiosName
9792 smb_ListenerState = SMB_LISTENER_STOPPED;
9793 smb_LANadapter = LANA_INVALID;
9794 lana_list.length = 0;
9796 lock_ReleaseMutex(&smb_StartedLock);
9800 else if (code != 0) {
9801 char tbuffer[AFSPATHMAX];
9803 /* terminate silently if shutdown flag is set */
9804 while (!lock_TryMutex(&smb_StartedLock)) {
9805 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9811 "NCBLISTEN lana=%d failed with code %d [%s]",
9812 ncbp->ncb_lana_num, code, ncb_error_string(code));
9814 "Client exiting due to network failure. Please restart client.\n");
9817 "Client exiting due to network failure. Please restart client.\n"
9818 "NCBLISTEN lana=%d failed with code %d [%s]",
9819 ncbp->ncb_lana_num, code, ncb_error_string(code));
9821 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9822 MB_OK|MB_SERVICE_NOTIFICATION);
9823 osi_panic(tbuffer, __FILE__, __LINE__);
9825 lock_ReleaseMutex(&smb_StartedLock);
9830 /* a successful packet received. clear bridge error count */
9834 /* check for remote conns */
9835 /* first get remote name and insert null terminator */
9836 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9837 for (i=NCBNAMSZ; i>0; i--) {
9838 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9844 /* compare with local name */
9846 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9847 flags |= SMB_VCFLAG_REMOTECONN;
9850 lock_ObtainMutex(&smb_ListenerLock);
9852 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9853 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9855 /* now ncbp->ncb_lsn is the connection ID */
9856 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9857 if (vcp->session == 0) {
9858 /* New generation */
9859 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9862 /* Log session startup */
9864 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9865 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9866 #endif /* NOTSERVICE */
9867 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9868 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9870 if (reportSessionStartups) {
9871 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9874 lock_ObtainMutex(&vcp->mx);
9875 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9876 vcp->flags |= flags;
9877 lock_ReleaseMutex(&vcp->mx);
9879 /* Allocate slot in session arrays */
9880 /* Re-use dead session if possible, otherwise add one more */
9881 /* But don't look at session[0], it is reserved */
9882 lock_ObtainWrite(&smb_globalLock);
9883 for (session = 1; session < numSessions; session++) {
9884 if (dead_sessions[session]) {
9885 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9886 dead_sessions[session] = FALSE;
9890 lock_ReleaseWrite(&smb_globalLock);
9892 /* We are re-using an existing VC because the lsn and lana
9894 session = vcp->session;
9896 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9898 /* Log session startup */
9900 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9901 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9902 #endif /* NOTSERVICE */
9903 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9904 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9906 if (reportSessionStartups) {
9907 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9911 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9912 unsigned long code = CM_ERROR_ALLBUSY;
9913 smb_packet_t * outp = smb_GetPacket();
9914 unsigned char *outWctp;
9917 smb_FormatResponsePacket(vcp, NULL, outp);
9920 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9921 unsigned long NTStatus;
9922 smb_MapNTError(code, &NTStatus, FALSE);
9923 outWctp = outp->wctp;
9924 smbp = (smb_t *) &outp->data;
9928 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9929 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9930 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9931 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9932 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9934 unsigned short errCode;
9935 unsigned char errClass;
9936 smb_MapCoreError(code, vcp, &errCode, &errClass);
9937 outWctp = outp->wctp;
9938 smbp = (smb_t *) &outp->data;
9942 smbp->errLow = (unsigned char) (errCode & 0xff);
9943 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9944 smbp->rcls = errClass;
9947 smb_SendPacket(vcp, outp);
9948 smb_FreePacket(outp);
9950 lock_ObtainMutex(&vcp->mx);
9951 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9952 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9954 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9955 lock_ReleaseMutex(&vcp->mx);
9956 lock_ObtainWrite(&smb_globalLock);
9957 dead_sessions[vcp->session] = TRUE;
9958 lock_ReleaseWrite(&smb_globalLock);
9959 smb_CleanupDeadVC(vcp);
9961 lock_ReleaseMutex(&vcp->mx);
9964 /* assert that we do not exceed the maximum number of sessions or NCBs.
9965 * we should probably want to wait for a session to be freed in case
9968 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9969 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9971 lock_ObtainMutex(&vcp->mx);
9972 vcp->session = session;
9973 lock_ReleaseMutex(&vcp->mx);
9974 lock_ObtainWrite(&smb_globalLock);
9975 LSNs[session] = ncbp->ncb_lsn;
9976 lanas[session] = ncbp->ncb_lana_num;
9977 lock_ReleaseWrite(&smb_globalLock);
9979 if (session == numSessions) {
9980 /* Add new NCB for new session */
9981 char eventName[MAX_PATH];
9983 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9985 InitNCBslot(numNCBs);
9986 lock_ObtainWrite(&smb_globalLock);
9988 lock_ReleaseWrite(&smb_globalLock);
9989 thrd_SetEvent(NCBavails[0]);
9990 thrd_SetEvent(NCBevents[0]);
9991 for (thread = 0; thread < smb_NumServerThreads; thread++)
9992 thrd_SetEvent(NCBreturns[thread][0]);
9993 /* Also add new session event */
9994 sprintf(eventName, "SessionEvents[%d]", session);
9995 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9996 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9997 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9998 lock_ObtainWrite(&smb_globalLock);
10000 lock_ReleaseWrite(&smb_globalLock);
10001 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
10002 thrd_SetEvent(SessionEvents[0]);
10004 thrd_SetEvent(SessionEvents[session]);
10007 smb_ReleaseVC(vcp);
10010 lock_ReleaseMutex(&smb_ListenerLock);
10011 } /* dispatch while loop */
10015 thrd_SetEvent(ListenerShutdown[lana]);
10020 smb_configureBackConnectionHostNames(int bEnable)
10022 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
10023 * there is a restriction on the use of SMB authentication on loopback connections.
10024 * There are two work arounds available:
10026 * (1) We can disable the check for matching host names. This does not
10027 * require a reboot:
10028 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
10029 * "DisableLoopbackCheck"=dword:00000001
10031 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
10032 * does require a reboot:
10033 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
10034 * "BackConnectionHostNames"=multi-sz
10036 * The algorithm will be:
10037 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
10038 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
10039 * (2b1) and check to see if DisableLoopbackCheck is set.
10040 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
10041 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
10042 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
10043 * check for the UnsetDisableLoopbackCheck value.
10044 * If set, set the DisableLoopbackCheck flag to 0x0
10045 * and delete the UnsetDisableLoopbackCheck value
10047 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
10048 * force Windows to use the loopback authentication mechanism for the specified
10051 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
10052 * service session that set it.
10058 DWORD dwSize, dwAllocSize;
10060 PBYTE pHostNames = NULL, pName = NULL;
10061 PBYTE pOrigNames = NULL, pOrig = NULL;
10062 BOOL bNameFound = FALSE;
10063 DWORD dwLoopbackCheckDisabled;
10064 DWORD dwszBackConnectionHostNames;
10065 size_t nbsize = strlen(cm_NetbiosName) + 2;
10067 static BOOL bLoopbackCheckDisabled = FALSE;
10069 /* DisableLoopbackCheck */
10070 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10071 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10073 KEY_READ|KEY_WRITE,
10074 &hkLsa) == ERROR_SUCCESS )
10076 dwSize = sizeof(DWORD);
10077 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwLoopbackCheckDisabled, &dwSize) != ERROR_SUCCESS)
10079 dwLoopbackCheckDisabled = 0;
10082 hkLsa = INVALID_HANDLE_VALUE;
10085 /* BackConnectionHostNames */
10086 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10087 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
10089 KEY_READ|KEY_WRITE,
10090 &hkMSV10) == ERROR_SUCCESS )
10092 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
10093 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10094 (dwType == REG_MULTI_SZ))
10096 dwAllocSize += 1 /* in case the source string is not nul terminated */
10097 + (DWORD)strlen(cm_NetbiosName) + 2;
10098 pHostNames = malloc(dwAllocSize);
10099 dwszBackConnectionHostNames = dwAllocSize;
10100 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
10101 pHostNames, &dwszBackConnectionHostNames) == ERROR_SUCCESS)
10103 for (pName = pHostNames;
10104 (pName - pHostNames < (int) dwszBackConnectionHostNames) && *pName ;
10105 pName += strlen(pName) + 1)
10107 if ( !stricmp(pName, cm_NetbiosName) ) {
10116 if ( !bNameFound ) {
10117 size_t size = strlen(cm_NetbiosName) + 2;
10118 if ( !pHostNames ) {
10119 pHostNames = malloc(size);
10120 pName = pHostNames;
10122 StringCbCopyA(pName, size, cm_NetbiosName);
10124 *pName = '\0'; /* add a second nul terminator */
10126 dwType = REG_MULTI_SZ;
10127 dwSize = (DWORD)(pName - pHostNames + 1);
10128 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10130 if ( hkLsa != INVALID_HANDLE_VALUE && !dwLoopbackCheckDisabled)
10132 dwType = REG_DWORD;
10133 dwSize = sizeof(DWORD);
10134 dwLoopbackCheckDisabled = 1;
10135 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwLoopbackCheckDisabled, dwSize);
10137 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10138 AFSREG_CLT_OPENAFS_SUBKEY,
10141 REG_OPTION_NON_VOLATILE,
10142 KEY_READ|KEY_WRITE,
10145 NULL) == ERROR_SUCCESS) {
10147 dwType = REG_DWORD;
10148 dwSize = sizeof(DWORD);
10150 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10151 bLoopbackCheckDisabled = TRUE;
10152 RegCloseKey(hkClient);
10155 } else if (!bLoopbackCheckDisabled && hkLsa != INVALID_HANDLE_VALUE) {
10156 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10157 AFSREG_CLT_OPENAFS_SUBKEY,
10160 REG_OPTION_NON_VOLATILE,
10161 KEY_READ|KEY_WRITE,
10164 NULL) == ERROR_SUCCESS) {
10166 dwSize = sizeof(DWORD);
10167 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10169 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10172 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10173 RegCloseKey(hkClient);
10177 * Disable SMB. Start by removing the DisableLoopbackCheck value if present.
10179 if (hkLsa != INVALID_HANDLE_VALUE) {
10180 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10181 AFSREG_CLT_OPENAFS_SUBKEY,
10184 REG_OPTION_NON_VOLATILE,
10185 KEY_READ|KEY_WRITE,
10188 NULL) == ERROR_SUCCESS) {
10190 dwSize = sizeof(DWORD);
10191 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10193 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10196 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10197 RegCloseKey(hkClient);
10200 /* Then remove our NetbiosName from the BackConnectionHostNames list */
10201 if ( bNameFound ) {
10203 * we found our name so if the size of the value is smaller
10204 * or equal to the length of our name alone, we are done.
10206 if ( dwszBackConnectionHostNames <= nbsize ) {
10207 RegDeleteValue( hkMSV10, "BackConnectionHostNames");
10209 pOrigNames = pHostNames;
10210 pHostNames = malloc(dwAllocSize);
10212 pOrig = pOrigNames;
10213 pName = pHostNames;
10214 while (pOrig - pOrigNames < dwszBackConnectionHostNames) {
10215 len = strlen(pOrig);
10216 if ( stricmp(pOrig, cm_NetbiosName)) {
10218 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10223 *pName = '\0'; /* add a second nul terminator */
10226 dwType = REG_MULTI_SZ;
10227 dwSize = (DWORD)(pName - pHostNames + 1);
10228 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10243 RegCloseKey(hkMSV10);
10246 if ( hkLsa != INVALID_HANDLE_VALUE ) {
10247 RegCloseKey(hkLsa);
10253 smb_configureExtendedSMBSessionTimeouts(int bEnable)
10256 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10257 * new functionality:
10259 * [HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters]
10260 * "ReconnectableServers" REG_MULTI_SZ
10261 * "ExtendedSessTimeout" REG_DWORD (seconds)
10262 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
10264 * These values can be used to prevent the smb redirector from timing out
10265 * smb connection to the afs smb server prematurely.
10269 DWORD dwSize, dwAllocSize;
10271 PBYTE pHostNames = NULL, pOrigNames = NULL, pName = NULL, pOrig = NULL;
10272 BOOL bNameFound = FALSE;
10273 DWORD dwszReconnectableServers;
10274 DWORD dwszServersWithExtendedSessTimeout;
10275 size_t nbsize = strlen(cm_NetbiosName) + 2;
10278 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10279 "SYSTEM\\CurrentControlSet\\Services\\LanmanWorkstation\\Parameters",
10281 KEY_READ|KEY_WRITE,
10282 &hkLanman) == ERROR_SUCCESS )
10284 if ((RegQueryValueEx( hkLanman, "ReconnectableServers", 0,
10285 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10286 (dwType == REG_MULTI_SZ))
10288 dwAllocSize += 1 /* in case the source string is not nul terminated */
10289 + (DWORD)strlen(cm_NetbiosName) + 2;
10290 pHostNames = malloc(dwAllocSize);
10291 dwszReconnectableServers = dwAllocSize;
10292 if (RegQueryValueEx( hkLanman, "ReconnectableServers", 0, &dwType,
10293 pHostNames, &dwszReconnectableServers) == ERROR_SUCCESS)
10295 for (pName = pHostNames;
10296 (pName - pHostNames < (int) dwszReconnectableServers) && *pName ;
10297 pName += strlen(pName) + 1)
10299 if ( !stricmp(pName, cm_NetbiosName) ) {
10308 * If our name was not found and we are enabling SMB,
10309 * add our name to the current value.
10311 if ( bEnable && !bNameFound ) {
10312 if ( !pHostNames ) {
10313 pHostNames = malloc(nbsize);
10314 pName = pHostNames;
10316 StringCbCopyA(pName, nbsize, cm_NetbiosName);
10317 pName += nbsize - 1;
10318 *pName = '\0'; /* add a second nul terminator */
10320 dwType = REG_MULTI_SZ;
10321 dwSize = (DWORD)(pName - pHostNames + 1);
10322 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10326 * If our name was found and we are disabling SMB,
10327 * remove our name from the list and update the value.
10328 * If our name is the only entry, remove the value.
10330 if ( !bEnable && bNameFound ) {
10332 * we found our name so if the size of the value is smaller
10333 * or equal to the length of our name alone, we are done.
10335 if ( dwszReconnectableServers <= nbsize ) {
10336 RegDeleteValue( hkLanman, "ReconnectableServers");
10338 pOrigNames = pHostNames;
10339 pHostNames = malloc(dwAllocSize);
10341 pOrig = pOrigNames;
10342 pName = pHostNames;
10343 while (pOrig - pOrigNames <dwszReconnectableServers ) {
10344 len = strlen(pOrig);
10345 if ( stricmp(pOrig, cm_NetbiosName)) {
10347 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10352 *pName = '\0'; /* add a second nul terminator */
10355 dwType = REG_MULTI_SZ;
10356 dwSize = (DWORD)(pName - pHostNames + 1);
10357 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10371 if ((RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0,
10372 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10373 (dwType == REG_MULTI_SZ))
10375 dwAllocSize += 1 /* in case the source string is not nul terminated */
10376 + (DWORD)strlen(cm_NetbiosName) + 2;
10377 pHostNames = malloc(dwAllocSize);
10378 dwszServersWithExtendedSessTimeout = dwAllocSize;
10379 if (RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, &dwType,
10380 pHostNames, &dwszServersWithExtendedSessTimeout) == ERROR_SUCCESS)
10382 for (pName = pHostNames;
10383 (pName - pHostNames < (int) dwszServersWithExtendedSessTimeout) && *pName ;
10384 pName += strlen(pName) + 1)
10386 if ( !stricmp(pName, cm_NetbiosName) ) {
10395 * If our name was not found and we are enabling SMB,
10396 * add our name to the current value.
10398 if ( bEnable && !bNameFound ) {
10399 size_t size = strlen(cm_NetbiosName) + 2;
10400 if ( !pHostNames ) {
10401 pHostNames = malloc(size);
10402 pName = pHostNames;
10404 StringCbCopyA(pName, size, cm_NetbiosName);
10406 *pName = '\0'; /* add a second nul terminator */
10408 dwType = REG_MULTI_SZ;
10409 dwSize = (DWORD)(pName - pHostNames + 1);
10410 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10414 * If our name was found and we are disabling SMB,
10415 * remove our name from the list and update the value.
10416 * If our name is the only entry, remove the value.
10418 if ( !bEnable && bNameFound ) {
10420 * we found our name so if the size of the value is smaller
10421 * or equal to the length of our name alone, we are done.
10423 if ( dwszServersWithExtendedSessTimeout <= nbsize ) {
10424 RegDeleteValue( hkLanman, "ServersWithExtendedSessTimeout");
10426 pOrigNames = pHostNames;
10427 pHostNames = malloc(dwAllocSize);
10429 pOrig = pOrigNames;
10430 pName = pHostNames;
10431 while (pOrig - pOrigNames < dwszServersWithExtendedSessTimeout) {
10432 len = strlen(pOrig);
10433 if ( stricmp(pOrig, cm_NetbiosName)) {
10435 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10440 *pName = '\0'; /* add a second nul terminator */
10443 dwType = REG_MULTI_SZ;
10444 dwSize = (DWORD)(pName - pHostNames + 1);
10445 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10460 if ((RegQueryValueEx( hkLanman, "ExtendedSessTimeout", 0,
10461 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10462 (dwType != REG_DWORD))
10464 dwType = REG_DWORD;
10465 dwSize = sizeof(dwValue);
10466 dwValue = 300; /* 5 minutes */
10467 RegSetValueEx( hkLanman, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10470 RegCloseKey(hkLanman);
10475 smb_LanAdapterChangeThread(void *param)
10478 * Give the IPAddrDaemon thread a chance
10479 * to block before we trigger.
10482 smb_LanAdapterChange(0);
10485 void smb_SetLanAdapterChangeDetected(void)
10490 lock_ObtainMutex(&smb_StartedLock);
10492 if (!powerStateSuspended) {
10493 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10494 NULL, 0, &lpid, "smb_LanAdapterChange");
10495 if (phandle == NULL) {
10499 gle = GetLastError();
10500 StringCchPrintf( msg, sizeof(msg)/sizeof(msg[0]),
10501 "smb_LanAdapterChangeThread thread creation failure - gle 0x%x",
10503 osi_assertx(TRUE, msg);
10505 thrd_CloseHandle(phandle);
10508 smb_LanAdapterChangeDetected = 1;
10509 lock_ReleaseMutex(&smb_StartedLock);
10512 void smb_LanAdapterChange(int locked) {
10513 lana_number_t lanaNum;
10515 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
10517 LANA_ENUM temp_list;
10522 afsi_log("smb_LanAdapterChange");
10525 lock_ObtainMutex(&smb_StartedLock);
10527 smb_LanAdapterChangeDetected = 0;
10529 if (!powerStateSuspended &&
10530 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10531 LANA_NETBIOS_NAME_FULL | LANA_NETBIOS_NO_RESET)) &&
10532 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10533 if ( isGateway != bGateway ) {
10534 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10535 smb_LANadapter, lanaNum, isGateway, bGateway);
10537 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10538 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10539 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10542 NCB *ncbp = smb_GetNCB();
10543 ncbp->ncb_command = NCBENUM;
10544 ncbp->ncb_buffer = (PUCHAR)&temp_list;
10545 ncbp->ncb_length = sizeof(temp_list);
10546 code = Netbios(ncbp);
10548 if (temp_list.length != lana_list.length) {
10549 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10550 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10553 for (i=0; i<lana_list.length; i++) {
10554 if ( temp_list.lana[i] != lana_list.lana[i] ) {
10555 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10556 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10568 smb_StopListeners(1);
10569 smb_RestartListeners(1);
10572 lock_ReleaseMutex(&smb_StartedLock);
10575 /* initialize Netbios */
10576 int smb_NetbiosInit(int locked)
10579 int i, lana, code, l;
10581 int delname_tried=0;
10583 int lana_found = 0;
10584 lana_number_t lanaNum;
10590 lock_ObtainMutex(&smb_StartedLock);
10592 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10593 smb_ListenerState != SMB_LISTENER_STOPPED) {
10596 lock_ReleaseMutex(&smb_StartedLock);
10599 /* setup the NCB system */
10600 ncbp = smb_GetNCB();
10603 * Call lanahelper to get Netbios name, lan adapter number and gateway flag
10604 * This will reset all of the network adapter's netbios state.
10606 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10607 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10609 if (smb_LANadapter != LANA_INVALID)
10610 afsi_log("LAN adapter number %d", smb_LANadapter);
10612 afsi_log("LAN adapter number not determined");
10615 afsi_log("Set for gateway service");
10617 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10619 /* something went horribly wrong. We can't proceed without a netbios name */
10621 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10622 osi_panic(buf, __FILE__, __LINE__);
10625 /* remember the name */
10626 len = (int)strlen(cm_NetbiosName);
10627 if (smb_localNamep)
10628 free(smb_localNamep);
10629 smb_localNamep = malloc(len+1);
10630 strcpy(smb_localNamep, cm_NetbiosName);
10631 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10633 /* Also copy the value to the client character encoded string */
10634 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10636 if (smb_LANadapter == LANA_INVALID) {
10637 ncbp->ncb_command = NCBENUM;
10638 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10639 ncbp->ncb_length = sizeof(lana_list);
10640 code = Netbios(ncbp);
10642 afsi_log("Netbios NCBENUM error code %d", code);
10643 osi_panic(s, __FILE__, __LINE__);
10647 lana_list.length = 1;
10648 lana_list.lana[0] = smb_LANadapter;
10651 for (i = 0; i < lana_list.length; i++) {
10652 /* reset the adaptor: in Win32, this is required for every process, and
10653 * acts as an init call, not as a real hardware reset.
10655 ncbp->ncb_command = NCBRESET;
10656 ncbp->ncb_callname[0] = 100;
10657 ncbp->ncb_callname[2] = 100;
10658 ncbp->ncb_lana_num = lana_list.lana[i];
10659 code = Netbios(ncbp);
10661 code = ncbp->ncb_retcode;
10663 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10664 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10666 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10670 /* and declare our name so we can receive connections */
10671 memset(ncbp, 0, sizeof(*ncbp));
10672 len=lstrlen(smb_localNamep);
10673 memset(smb_sharename,' ',NCBNAMSZ);
10674 memcpy(smb_sharename,smb_localNamep,len);
10675 afsi_log("lana_list.length %d", lana_list.length);
10677 /* Keep the name so we can unregister it later */
10678 for (l = 0; l < lana_list.length; l++) {
10679 lana = lana_list.lana[l];
10681 ncbp->ncb_command = NCBADDNAME;
10682 ncbp->ncb_lana_num = lana;
10683 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10684 code = Netbios(ncbp);
10686 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10687 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10689 char name[NCBNAMSZ+1];
10691 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10692 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10696 code = ncbp->ncb_retcode;
10699 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10702 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10703 if (code == NRC_BRIDGE) { /* invalid LANA num */
10704 lana_list.lana[l] = LANA_INVALID;
10707 else if (code == NRC_DUPNAME) {
10708 afsi_log("Name already exists; try to delete it");
10709 memset(ncbp, 0, sizeof(*ncbp));
10710 ncbp->ncb_command = NCBDELNAME;
10711 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10712 ncbp->ncb_lana_num = lana;
10713 code = Netbios(ncbp);
10715 code = ncbp->ncb_retcode;
10717 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10719 if (code != 0 || delname_tried) {
10720 lana_list.lana[l] = LANA_INVALID;
10722 else if (code == 0) {
10723 if (!delname_tried) {
10731 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10732 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10736 smb_LANadapter = lana;
10737 lana_found = 1; /* at least one worked */
10741 osi_assertx(lana_list.length >= 0, "empty lana list");
10743 afsi_log("No valid LANA numbers found!");
10744 lana_list.length = 0;
10745 smb_LANadapter = LANA_INVALID;
10746 smb_ListenerState = SMB_LISTENER_STOPPED;
10747 cm_VolStatus_Network_Stopped(cm_NetbiosName
10754 /* we're done with the NCB now */
10757 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10758 if (lana_list.length > 0)
10759 osi_assert(smb_LANadapter != LANA_INVALID);
10762 lock_ReleaseMutex(&smb_StartedLock);
10764 return (lana_list.length > 0 ? 1 : 0);
10767 void smb_StartListeners(int locked)
10777 lock_ObtainMutex(&smb_StartedLock);
10779 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10781 lock_ReleaseMutex(&smb_StartedLock);
10785 afsi_log("smb_StartListeners");
10786 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10787 smb_configureBackConnectionHostNames(TRUE);
10789 /* Configure Extended SMB Session Timeouts */
10790 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10791 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10792 smb_configureExtendedSMBSessionTimeouts(TRUE);
10795 smb_ListenerState = SMB_LISTENER_STARTED;
10796 cm_VolStatus_Network_Started(cm_NetbiosName
10802 for (i = 0; i < lana_list.length; i++) {
10803 if (lana_list.lana[i] == LANA_INVALID)
10805 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10806 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10807 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10808 thrd_CloseHandle(phandle);
10811 lock_ReleaseMutex(&smb_StartedLock);
10814 void smb_RestartListeners(int locked)
10820 lock_ObtainMutex(&smb_StartedLock);
10822 if (powerStateSuspended)
10823 afsi_log("smb_RestartListeners called while suspended");
10825 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10826 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10827 if (smb_NetbiosInit(1))
10828 smb_StartListeners(1);
10829 } else if (smb_LanAdapterChangeDetected) {
10830 smb_LanAdapterChange(1);
10834 lock_ReleaseMutex(&smb_StartedLock);
10837 void smb_StopListener(NCB *ncbp, int lana, int wait)
10841 memset(ncbp, 0, sizeof(*ncbp));
10842 ncbp->ncb_command = NCBDELNAME;
10843 ncbp->ncb_lana_num = lana;
10844 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10845 code = Netbios(ncbp);
10847 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10848 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10850 /* and then reset the LANA; this will cause the listener threads to exit */
10851 ncbp->ncb_command = NCBRESET;
10852 ncbp->ncb_callname[0] = 100;
10853 ncbp->ncb_callname[2] = 100;
10854 ncbp->ncb_lana_num = lana;
10855 code = Netbios(ncbp);
10857 code = ncbp->ncb_retcode;
10859 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10861 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10865 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10868 void smb_StopListeners(int locked)
10877 lock_ObtainMutex(&smb_StartedLock);
10879 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10881 lock_ReleaseMutex(&smb_StartedLock);
10885 afsi_log("smb_StopListeners");
10886 smb_ListenerState = SMB_LISTENER_STOPPED;
10887 cm_VolStatus_Network_Stopped(cm_NetbiosName
10893 ncbp = smb_GetNCB();
10895 /* Unregister the SMB name */
10896 for (l = 0; l < lana_list.length; l++) {
10897 lana = lana_list.lana[l];
10899 if (lana != LANA_INVALID) {
10900 smb_StopListener(ncbp, lana, TRUE);
10902 /* mark the adapter invalid */
10903 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10907 /* force a re-evaluation of the network adapters */
10908 lana_list.length = 0;
10909 smb_LANadapter = LANA_INVALID;
10912 lock_ReleaseMutex(&smb_StartedLock);
10915 void smb_Init(osi_log_t *logp, int useV3,
10925 EVENT_HANDLE retHandle;
10926 char eventName[MAX_PATH];
10927 int startListeners = 0;
10932 smb_MBfunc = aMBfunc;
10936 /* Initialize smb_localZero */
10937 myTime.tm_isdst = -1; /* compute whether on DST or not */
10938 myTime.tm_year = 70;
10940 myTime.tm_mday = 1;
10941 myTime.tm_hour = 0;
10944 smb_localZero = mktime(&myTime);
10946 #ifdef AFS_FREELANCE_CLIENT
10947 /* Make sure the root.afs volume has the correct time */
10948 cm_noteLocalMountPointChange(FALSE);
10951 /* initialize the remote debugging log */
10954 /* and the global lock */
10955 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10956 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10958 /* Raw I/O data structures */
10959 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10961 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10962 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10964 /* 4 Raw I/O buffers */
10965 smb_RawBufs = calloc(65536,1);
10966 *((char **)smb_RawBufs) = NULL;
10967 for (i=0; i<3; i++) {
10968 char *rawBuf = calloc(65536,1);
10969 *((char **)rawBuf) = smb_RawBufs;
10970 smb_RawBufs = rawBuf;
10973 /* global free lists */
10974 smb_ncbFreeListp = NULL;
10975 smb_packetFreeListp = NULL;
10977 lock_ObtainMutex(&smb_StartedLock);
10978 startListeners = smb_NetbiosInit(1);
10980 /* Initialize listener and server structures */
10982 memset(dead_sessions, 0, sizeof(dead_sessions));
10983 sprintf(eventName, "SessionEvents[0]");
10984 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10985 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10986 afsi_log("Event Object Already Exists: %s", eventName);
10988 smb_NumServerThreads = nThreads;
10989 sprintf(eventName, "NCBavails[0]");
10990 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10991 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10992 afsi_log("Event Object Already Exists: %s", eventName);
10993 sprintf(eventName, "NCBevents[0]");
10994 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10995 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10996 afsi_log("Event Object Already Exists: %s", eventName);
10997 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10998 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10999 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11000 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11001 afsi_log("Event Object Already Exists: %s", eventName);
11002 for (i = 0; i < smb_NumServerThreads; i++) {
11003 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
11004 NCBreturns[i][0] = retHandle;
11007 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
11008 for (i = 0; i < smb_NumServerThreads; i++) {
11009 sprintf(eventName, "smb_ServerShutdown[%d]", i);
11010 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11011 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11012 afsi_log("Event Object Already Exists: %s", eventName);
11013 InitNCBslot((int)(i+1));
11015 numNCBs = smb_NumServerThreads + 1;
11017 /* Initialize dispatch table */
11018 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
11019 /* Prepare the table for unknown operations */
11020 for(i=0; i<= SMB_NOPCODES; i++) {
11021 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
11023 /* Fill in the ones we do know */
11024 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
11025 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
11026 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
11027 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
11028 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
11029 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
11030 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
11031 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
11032 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
11033 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
11034 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
11035 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
11036 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
11037 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
11038 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
11039 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
11040 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
11041 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
11042 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
11043 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
11044 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
11045 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11046 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
11047 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
11048 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
11049 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
11050 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
11051 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
11052 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11053 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
11054 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11055 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
11056 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
11057 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
11058 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11059 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
11060 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
11061 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
11062 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
11063 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
11064 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
11065 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
11066 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11067 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
11068 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11069 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
11070 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
11071 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
11072 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
11073 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
11074 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
11075 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
11076 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
11077 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
11078 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
11079 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
11080 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
11081 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
11082 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
11083 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
11084 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
11085 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
11086 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
11087 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
11088 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
11089 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11090 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
11091 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
11092 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
11093 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
11094 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
11095 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
11096 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
11097 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
11099 /* setup tran 2 dispatch table */
11100 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
11101 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
11102 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
11103 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
11104 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
11105 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
11106 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
11107 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
11108 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
11109 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
11110 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
11111 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
11112 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
11113 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
11114 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
11115 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
11116 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
11117 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
11119 /* setup the rap dispatch table */
11120 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
11121 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
11122 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
11123 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
11124 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
11128 /* if we are doing SMB authentication we have register outselves as a logon process */
11129 if (smb_authType != SMB_AUTH_NONE) {
11130 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
11131 LSA_STRING afsProcessName;
11132 LSA_OPERATIONAL_MODE dummy; /*junk*/
11134 afsProcessName.Buffer = "OpenAFSClientDaemon";
11135 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
11136 afsProcessName.MaximumLength = afsProcessName.Length + 1;
11138 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
11140 if (nts == STATUS_SUCCESS) {
11141 LSA_STRING packageName;
11142 /* we are registered. Find out the security package id */
11143 packageName.Buffer = MSV1_0_PACKAGE_NAME;
11144 packageName.Length = (USHORT)strlen(packageName.Buffer);
11145 packageName.MaximumLength = packageName.Length + 1;
11146 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
11147 if (nts == STATUS_SUCCESS) {
11149 * This code forces Windows to authenticate against the Logon Cache
11150 * first instead of attempting to authenticate against the Domain
11151 * Controller. When the Windows logon cache is enabled this improves
11152 * performance by removing the network access and works around a bug
11153 * seen at sites which are using a MIT Kerberos principal to login
11154 * to machines joined to a non-root domain in a multi-domain forest.
11155 * MsV1_0SetProcessOption was added in Windows XP.
11157 PVOID pResponse = NULL;
11158 ULONG cbResponse = 0;
11159 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
11161 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
11162 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
11163 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
11164 OptionsRequest.DisableOptions = FALSE;
11166 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
11169 sizeof(OptionsRequest),
11175 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
11176 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
11179 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
11181 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
11182 afsi_log("MsV1_0SetProcessOption success");
11184 /* END - code from Larry */
11186 smb_lsaLogonOrigin.Buffer = "OpenAFS";
11187 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
11188 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
11190 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
11192 /* something went wrong. We report the error and revert back to no authentication
11193 because we can't perform any auth requests without a successful lsa handle
11194 or sec package id. */
11195 afsi_log("Reverting to NO SMB AUTH");
11196 smb_authType = SMB_AUTH_NONE;
11199 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
11201 /* something went wrong. We report the error and revert back to no authentication
11202 because we can't perform any auth requests without a successful lsa handle
11203 or sec package id. */
11204 afsi_log("Reverting to NO SMB AUTH");
11205 smb_authType = SMB_AUTH_NONE;
11209 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
11210 * time prevents the failure of authentication when logged into Windows with an
11211 * external Kerberos principal mapped to a local account.
11213 else if ( smb_authType == SMB_AUTH_EXTENDED) {
11214 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
11215 * then the only option is NTLMSSP anyway; so just fallback.
11220 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
11221 if (secBlobLength == 0) {
11222 smb_authType = SMB_AUTH_NTLM;
11223 afsi_log("Reverting to SMB AUTH NTLM");
11232 /* Now get ourselves a domain name. */
11233 /* For now we are using the local computer name as the domain name.
11234 * It is actually the domain for local logins, and we are acting as
11235 * a local SMB server.
11237 bufsize = lengthof(smb_ServerDomainName) - 1;
11238 GetComputerNameW(smb_ServerDomainName, &bufsize);
11239 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
11240 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
11243 /* Start listeners, waiters, servers, and daemons */
11244 if (startListeners)
11245 smb_StartListeners(1);
11247 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
11248 NULL, 0, &lpid, "smb_ClientWaiter");
11249 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
11250 thrd_CloseHandle(phandle);
11252 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
11253 NULL, 0, &lpid, "smb_ServerWaiter");
11254 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
11255 thrd_CloseHandle(phandle);
11257 for (i=0; i<smb_NumServerThreads; i++) {
11258 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
11259 (void *) i, 0, &lpid, "smb_Server");
11260 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
11261 thrd_CloseHandle(phandle);
11264 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
11265 NULL, 0, &lpid, "smb_Daemon");
11266 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
11267 thrd_CloseHandle(phandle);
11269 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
11270 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
11271 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
11272 thrd_CloseHandle(phandle);
11274 if (smb_monitorReqs) {
11275 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
11276 NULL, 0, &lpid, "smb_ServerMonitor");
11277 osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
11278 thrd_CloseHandle(phandle);
11281 lock_ReleaseMutex(&smb_StartedLock);
11285 void smb_Shutdown(void)
11295 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11297 /* setup the NCB system */
11298 ncbp = smb_GetNCB();
11300 /* Block new sessions by setting shutdown flag */
11301 smbShutdownFlag = 1;
11303 /* Hang up all sessions */
11304 memset(ncbp, 0, sizeof(NCB));
11305 for (i = 1; i < numSessions; i++)
11307 if (dead_sessions[i])
11310 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11311 ncbp->ncb_command = NCBHANGUP;
11312 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
11313 ncbp->ncb_lsn = (UCHAR)LSNs[i];
11314 code = Netbios(ncbp);
11315 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11316 if (code == 0) code = ncbp->ncb_retcode;
11318 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11319 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11323 /* Trigger the shutdown of all SMB threads */
11324 for (i = 0; i < smb_NumServerThreads; i++)
11325 thrd_SetEvent(NCBreturns[i][0]);
11327 thrd_SetEvent(NCBevents[0]);
11328 thrd_SetEvent(SessionEvents[0]);
11329 thrd_SetEvent(NCBavails[0]);
11331 for (i = 0;i < smb_NumServerThreads; i++) {
11332 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11333 if (code == WAIT_OBJECT_0) {
11336 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11337 thrd_SetEvent(NCBreturns[i--][0]);
11341 /* Delete Netbios name */
11342 memset(ncbp, 0, sizeof(NCB));
11343 for (i = 0; i < lana_list.length; i++) {
11344 if (lana_list.lana[i] == LANA_INVALID) continue;
11345 ncbp->ncb_command = NCBDELNAME;
11346 ncbp->ncb_lana_num = lana_list.lana[i];
11347 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11348 code = Netbios(ncbp);
11350 code = ncbp->ncb_retcode;
11352 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11353 ncbp->ncb_lana_num, code);
11358 /* Release the reference counts held by the VCs */
11359 lock_ObtainWrite(&smb_rctLock);
11360 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11365 if (vcp->magic != SMB_VC_MAGIC)
11366 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11367 __FILE__, __LINE__);
11369 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11371 if (fidp->scp != NULL) {
11374 lock_ReleaseWrite(&smb_rctLock);
11375 lock_ObtainMutex(&fidp->mx);
11376 if (fidp->scp != NULL) {
11379 lock_ObtainWrite(&scp->rw);
11380 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11381 lock_ReleaseWrite(&scp->rw);
11382 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11383 cm_ReleaseSCache(scp);
11385 lock_ReleaseMutex(&fidp->mx);
11386 lock_ObtainWrite(&smb_rctLock);
11390 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11392 smb_ReleaseVCNoLock(tidp->vcp);
11394 cm_user_t *userp = tidp->userp;
11395 tidp->userp = NULL;
11396 cm_ReleaseUser(userp);
11400 lock_ReleaseWrite(&smb_rctLock);
11403 if (smb_monitorReqs) {
11404 smb_ShutdownMonitor();
11408 /* Get the UNC \\<servername>\<sharename> prefix. */
11409 char *smb_GetSharename()
11414 /* Make sure we have been properly initialized. */
11415 if (smb_localNamep == NULL)
11418 /* Allocate space for \\<servername>\<sharename>, plus the
11421 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11422 name = malloc(len);
11423 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11429 void smb_LogPacket(smb_packet_t *packet)
11433 unsigned length, paramlen, datalen, i, j;
11435 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11437 if (!packet) return;
11439 osi_Log0(smb_logp, "*** SMB packet dump ***");
11441 smbp = (smb_t *) packet->data;
11442 vp = (BYTE *) packet->data;
11444 paramlen = smbp->wct * 2;
11445 datalen = *((WORD *) (smbp->vdata + paramlen));
11446 length = sizeof(*smbp) + paramlen + 1 + datalen;
11448 for (i=0;i < length; i+=16)
11450 memset( buf, ' ', 80 );
11453 itoa( i, buf, 16 );
11455 buf[strlen(buf)] = ' ';
11457 cp = (BYTE*) buf + 7;
11459 for (j=0;j < 16 && (i+j)<length; j++)
11461 *(cp++) = hex[vp[i+j] >> 4];
11462 *(cp++) = hex[vp[i+j] & 0xf];
11472 for (j=0;j < 16 && (i+j)<length;j++)
11474 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11485 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11488 osi_Log0(smb_logp, "*** End SMB packet dump ***");
11490 #endif /* LOG_PACKET */
11493 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11499 smb_username_t *unp;
11500 smb_waitingLockRequest_t *wlrp;
11503 lock_ObtainRead(&smb_rctLock);
11505 sprintf(output, "begin dumping smb_username_t\r\n");
11506 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11507 for (unp = usernamesp; unp; unp=unp->nextp)
11509 cm_ucell_t *ucellp;
11511 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11512 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11513 unp->name ? unp->name : _C("NULL"),
11514 unp->machine ? unp->machine : _C("NULL"));
11515 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11517 sprintf(output, " begin dumping cm_ucell_t\r\n");
11518 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11520 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11521 sprintf(output, " %s -- ucellp=0x%p, cellp=0x%p, flags=0x%x, tktLen=%04u, kvno=%03u, expires=%I64u, gen=%d, name=%s, cellname=%s\r\n",
11522 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11523 ucellp->expirationTime, ucellp->gen,
11525 ucellp->cellp->name);
11526 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11529 sprintf(output, " done dumping cm_ucell_t\r\n");
11530 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11533 sprintf(output, "done dumping smb_username_t\r\n");
11534 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11540 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11541 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11543 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11544 smb_waitingLock_t *lockp;
11546 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11547 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11548 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11550 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
11551 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11552 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11553 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11554 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11555 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11557 sprintf(output, " done dumping smb_waitingLock_t\r\n");
11558 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11561 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11562 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11564 sprintf(output, "begin dumping smb_vc_t\r\n");
11565 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11567 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11573 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11574 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11575 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11577 sprintf(output, " begin dumping smb_user_t\r\n");
11578 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11579 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11580 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11581 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11582 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11584 sprintf(output, " done dumping smb_user_t\r\n");
11585 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11587 sprintf(output, " begin dumping smb_tid_t\r\n");
11588 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11589 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11590 sprintf(output, " %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
11591 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11592 tidp->pathname ? tidp->pathname : _C("NULL"));
11593 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11595 sprintf(output, " done dumping smb_tid_t\r\n");
11596 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11598 sprintf(output, " begin dumping smb_fid_t\r\n");
11599 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11601 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11603 sprintf(output, " %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
11604 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11605 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11606 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11607 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11610 sprintf(output, " done dumping smb_fid_t\r\n");
11611 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11614 sprintf(output, "done dumping smb_vc_t\r\n");
11615 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11617 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11618 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11620 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11626 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11627 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11628 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11630 sprintf(output, " begin dumping smb_user_t\r\n");
11631 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11632 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11633 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11634 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11635 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11637 sprintf(output, " done dumping smb_user_t\r\n");
11638 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11640 sprintf(output, " begin dumping smb_tid_t\r\n");
11641 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11642 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11643 sprintf(output, " %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
11644 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11645 tidp->pathname ? tidp->pathname : _C("NULL"));
11646 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11648 sprintf(output, " done dumping smb_tid_t\r\n");
11649 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11651 sprintf(output, " begin dumping smb_fid_t\r\n");
11652 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11654 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11656 sprintf(output, " %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
11657 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11658 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11659 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11660 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11663 sprintf(output, " done dumping smb_fid_t\r\n");
11664 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11667 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11668 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11672 lock_ReleaseRead(&smb_rctLock);
11676 long smb_IsNetworkStarted(void)
11683 lock_ObtainWrite(&smb_globalLock);
11684 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11685 lock_ReleaseWrite(&smb_globalLock);