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 <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
33 #include "lanahelper.h"
35 #define STRSAFE_NO_DEPRECATE
38 /* These characters are illegal in Windows filenames */
39 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
41 static int smbShutdownFlag = 0;
42 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
44 int smb_LogoffTokenTransfer;
45 time_t smb_LogoffTransferTimeout;
47 int smb_StoreAnsiFilenames = 0;
49 DWORD last_msg_time = 0;
53 unsigned int sessionGen = 0;
55 extern void afsi_log(char *pattern, ...);
56 extern HANDLE afsi_file;
57 extern int powerStateSuspended;
59 osi_hyper_t hzero = {0, 0};
60 osi_hyper_t hones = {0xFFFFFFFF, -1};
63 osi_rwlock_t smb_globalLock;
64 osi_rwlock_t smb_rctLock;
65 osi_mutex_t smb_ListenerLock;
66 osi_mutex_t smb_StartedLock;
68 unsigned char smb_LANadapter = LANA_INVALID;
69 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
70 int smb_LanAdapterChangeDetected = 0;
71 afs_uint32 smb_AsyncStore = 1;
72 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
74 BOOL isGateway = FALSE;
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
85 afs_uint32 smb_NumServerThreads;
87 afs_uint32 numNCBs, numSessions, numVCs;
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
92 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
94 ULONG smb_lsaSecPackage;
95 LSA_STRING smb_lsaLogonOrigin;
97 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
99 EVENT_HANDLE **NCBreturns;
100 EVENT_HANDLE **NCBShutdown;
101 EVENT_HANDLE *smb_ServerShutdown;
102 EVENT_HANDLE ListenerShutdown[256];
103 DWORD NCBsessions[NCB_MAX];
105 struct smb_packet *bufs[NCB_MAX];
107 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
108 EVENT_HANDLE SessionEvents[SESSION_MAX];
109 unsigned short LSNs[SESSION_MAX];
110 int lanas[SESSION_MAX];
111 BOOL dead_sessions[SESSION_MAX];
114 osi_mutex_t smb_RawBufLock;
117 #define SMB_MASKFLAG_TILDE 1
118 #define SMB_MASKFLAG_CASEFOLD 2
120 #define RAWTIMEOUT INFINITE
123 typedef struct raw_write_cont {
132 /* dir search stuff */
133 long smb_dirSearchCounter = 1;
134 smb_dirSearch_t *smb_firstDirSearchp;
135 smb_dirSearch_t *smb_lastDirSearchp;
137 /* hide dot files? */
138 int smb_hideDotFiles;
140 /* Negotiate Unicode support? */
143 /* global state about V3 protocols */
144 int smb_useV3; /* try to negotiate V3 */
146 static int showErrors = 0;
147 /* MessageBox or something like it */
148 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
152 * Time in Unix format of midnight, 1/1/1970 local time.
153 * When added to dosUTime, gives Unix (AFS) time.
155 time_t smb_localZero = 0;
157 char *smb_localNamep = NULL;
159 smb_vc_t *smb_allVCsp;
160 smb_vc_t *smb_deadVCsp;
162 smb_username_t *usernamesp = NULL;
164 smb_waitingLockRequest_t *smb_allWaitingLocks;
167 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
168 NCB *ncbp, raw_write_cont_t *rwcp);
169 int smb_NetbiosInit(int);
172 void smb_LogPacket(smb_packet_t *packet);
173 #endif /* LOG_PACKET */
175 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
176 int smb_ServerDomainNameLength = 0;
177 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
178 int smb_ServerOSLength = lengthof(smb_ServerOS);
179 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
180 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
182 /* Faux server GUID. This is never checked. */
183 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
185 void smb_InitReq(cm_req_t *reqp)
188 reqp->flags |= CM_REQ_SOURCE_SMB;
191 const char * ncb_error_string(int code)
195 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
196 case 0x03: s = "NRC_ILLCMD illegal command"; break;
197 case 0x05: s = "NRC_CMDTMO command timed out"; break;
198 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
199 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
200 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
201 case 0x09: s = "NRC_NORES no resource available"; break;
202 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
203 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
204 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
205 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
206 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
207 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
208 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
209 case 0x13: s = "NRC_ILLNN illegal name number"; break;
210 case 0x14: s = "NRC_NOCALL no callname"; break;
211 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
212 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
213 case 0x17: s = "NRC_NAMERR name deleted"; break;
214 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
215 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
216 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
217 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
218 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
219 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
220 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
221 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
222 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
223 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
224 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
225 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
226 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
227 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
228 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
229 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
230 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
231 case 0x40: s = "NRC_SYSTEM system error"; break;
232 default: s = "unknown error";
238 char * myCrt_Dispatch(int i)
243 return "(00)ReceiveCoreMakeDir";
245 return "(01)ReceiveCoreRemoveDir";
247 return "(02)ReceiveCoreOpen";
249 return "(03)ReceiveCoreCreate";
251 return "(04)ReceiveCoreClose";
253 return "(05)ReceiveCoreFlush";
255 return "(06)ReceiveCoreUnlink";
257 return "(07)ReceiveCoreRename";
259 return "(08)ReceiveCoreGetFileAttributes";
261 return "(09)ReceiveCoreSetFileAttributes";
263 return "(0a)ReceiveCoreRead";
265 return "(0b)ReceiveCoreWrite";
267 return "(0c)ReceiveCoreLockRecord";
269 return "(0d)ReceiveCoreUnlockRecord";
271 return "(0e)SendCoreBadOp";
273 return "(0f)ReceiveCoreCreate";
275 return "(10)ReceiveCoreCheckPath";
277 return "(11)SendCoreBadOp";
279 return "(12)ReceiveCoreSeek";
281 return "(1a)ReceiveCoreReadRaw";
283 return "(1d)ReceiveCoreWriteRawDummy";
285 return "(22)ReceiveV3SetAttributes";
287 return "(23)ReceiveV3GetAttributes";
289 return "(24)ReceiveV3LockingX";
291 return "(25)ReceiveV3Trans";
293 return "(26)ReceiveV3Trans[aux]";
295 return "(29)SendCoreBadOp";
297 return "(2b)ReceiveCoreEcho";
299 return "(2d)ReceiveV3OpenX";
301 return "(2e)ReceiveV3ReadX";
303 return "(2f)ReceiveV3WriteX";
305 return "(32)ReceiveV3Tran2A";
307 return "(33)ReceiveV3Tran2A[aux]";
309 return "(34)ReceiveV3FindClose";
311 return "(35)ReceiveV3FindNotifyClose";
313 return "(70)ReceiveCoreTreeConnect";
315 return "(71)ReceiveCoreTreeDisconnect";
317 return "(72)ReceiveNegotiate";
319 return "(73)ReceiveV3SessionSetupX";
321 return "(74)ReceiveV3UserLogoffX";
323 return "(75)ReceiveV3TreeConnectX";
325 return "(80)ReceiveCoreGetDiskAttributes";
327 return "(81)ReceiveCoreSearchDir";
331 return "(83)FindUnique";
333 return "(84)FindClose";
335 return "(A0)ReceiveNTTransact";
337 return "(A2)ReceiveNTCreateX";
339 return "(A4)ReceiveNTCancel";
341 return "(A5)ReceiveNTRename";
343 return "(C0)OpenPrintFile";
345 return "(C1)WritePrintFile";
347 return "(C2)ClosePrintFile";
349 return "(C3)GetPrintQueue";
351 return "(D8)ReadBulk";
353 return "(D9)WriteBulk";
355 return "(DA)WriteBulkData";
357 return "unknown SMB op";
361 char * myCrt_2Dispatch(int i)
366 return "unknown SMB op-2";
368 return "S(00)CreateFile_ReceiveTran2Open";
370 return "S(01)FindFirst_ReceiveTran2SearchDir";
372 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
374 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
376 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
378 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
380 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
382 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
384 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
386 return "S(09)_ReceiveTran2FSCTL";
388 return "S(0a)_ReceiveTran2IOCTL";
390 return "S(0b)_ReceiveTran2FindNotifyFirst";
392 return "S(0c)_ReceiveTran2FindNotifyNext";
394 return "S(0d)_ReceiveTran2CreateDirectory";
396 return "S(0e)_ReceiveTran2SessionSetup";
398 return "S(0f)_QueryFileSystemInformationFid";
400 return "S(10)_ReceiveTran2GetDfsReferral";
402 return "S(11)_ReceiveTran2ReportDfsInconsistency";
406 char * myCrt_RapDispatch(int i)
411 return "unknown RAP OP";
413 return "RAP(0)NetShareEnum";
415 return "RAP(1)NetShareGetInfo";
417 return "RAP(13)NetServerGetInfo";
419 return "RAP(63)NetWkStaGetInfo";
423 char * myCrt_NmpipeDispatch(int i)
426 case SMB_TRANS_SET_NMPIPE_STATE:
427 return "SET NMPIPE STATE";
429 case SMB_TRANS_RAW_READ_NMPIPE:
430 return "RAW READ NMPIPE";
432 case SMB_TRANS_QUERY_NMPIPE_STATE:
433 return "QUERY NMPIPE STATE";
435 case SMB_TRANS_QUERY_NMPIPE_INFO:
436 return "QUERY NMPIPE INFO";
438 case SMB_TRANS_PEEK_NMPIPE:
439 return "PEEK NMPIPE";
441 case SMB_TRANS_TRANSACT_NMPIPE:
442 return "TRANSACT NMPIPE";
444 case SMB_TRANS_RAW_WRITE_NMPIPE:
445 return "WRITE NMPIPE";
447 case SMB_TRANS_READ_NMPIPE:
448 return "READ NMPIPE";
450 case SMB_TRANS_WRITE_NMPIPE:
451 return "WRITE NMPIPE";
453 case SMB_TRANS_WAIT_NMPIPE:
454 return "WAIT NMPIPE";
456 case SMB_TRANS_CALL_NMPIPE:
457 return "CALL NMPIPE";
462 /* scache must be locked */
463 unsigned int smb_Attributes(cm_scache_t *scp)
467 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
468 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
469 scp->fileType == CM_SCACHETYPE_INVALID)
471 attrs = SMB_ATTR_DIRECTORY;
472 #ifdef SPECIAL_FOLDERS
473 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
474 #endif /* SPECIAL_FOLDERS */
475 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
476 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
481 * We used to mark a file RO if it was in an RO volume, but that
482 * turns out to be impolitic in NT. See defect 10007.
485 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
486 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
488 if ((scp->unixModeBits & 0222) == 0)
489 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
495 /* Check if the named file/dir is a dotfile/dotdir */
496 /* String pointed to by lastComp can have leading slashes, but otherwise should have
497 no other patch components */
498 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
502 /* skip over slashes */
503 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
508 /* nulls, curdir and parent dir doesn't count */
514 if(*(s+1) == _C('.') && !*(s + 2))
521 static int ExtractBits(WORD bits, short start, short len)
528 num = bits << (16 - end);
529 num = num >> ((16 - end) + start);
534 void ShowUnixTime(char *FuncName, time_t unixTime)
539 cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
541 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
542 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
544 int day, month, year, sec, min, hour;
547 day = ExtractBits(wDate, 0, 5);
548 month = ExtractBits(wDate, 5, 4);
549 year = ExtractBits(wDate, 9, 7) + 1980;
551 sec = ExtractBits(wTime, 0, 5);
552 min = ExtractBits(wTime, 5, 6);
553 hour = ExtractBits(wTime, 11, 5);
555 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
556 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
560 /* Determine if we are observing daylight savings time */
561 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
563 TIME_ZONE_INFORMATION timeZoneInformation;
564 SYSTEMTIME utc, local, localDST;
566 /* Get the time zone info. NT uses this to calc if we are in DST. */
567 GetTimeZoneInformation(&timeZoneInformation);
569 /* Return the daylight bias */
570 *pDstBias = timeZoneInformation.DaylightBias;
572 /* Return the bias */
573 *pBias = timeZoneInformation.Bias;
575 /* Now determine if DST is being observed */
577 /* Get the UTC (GMT) time */
580 /* Convert UTC time to local time using the time zone info. If we are
581 observing DST, the calculated local time will include this.
583 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
585 /* Set the daylight bias to 0. The daylight bias is the amount of change
586 * in time that we use for daylight savings time. By setting this to 0
587 * we cause there to be no change in time during daylight savings time.
589 timeZoneInformation.DaylightBias = 0;
591 /* Convert the utc time to local time again, but this time without any
592 adjustment for daylight savings time.
594 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
596 /* If the two times are different, then it means that the localDST that
597 we calculated includes the daylight bias, and therefore we are
598 observing daylight savings time.
600 *pDST = localDST.wHour != local.wHour;
604 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
606 BOOL dst; /* Will be TRUE if observing DST */
607 LONG dstBias; /* Offset from local time if observing DST */
608 LONG bias; /* Offset from GMT for local time */
611 * This function will adjust the last write time to compensate
612 * for two bugs in the smb client:
614 * 1) During Daylight Savings Time, the LastWriteTime is ahead
615 * in time by the DaylightBias (ignoring the sign - the
616 * DaylightBias is always stored as a negative number). If
617 * the DaylightBias is -60, then the LastWriteTime will be
618 * ahead by 60 minutes.
620 * 2) If the local time zone is a positive offset from GMT, then
621 * the LastWriteTime will be the correct local time plus the
622 * Bias (ignoring the sign - a positive offset from GMT is
623 * always stored as a negative Bias). If the Bias is -120,
624 * then the LastWriteTime will be ahead by 120 minutes.
626 * These bugs can occur at the same time.
629 GetTimeZoneInfo(&dst, &dstBias, &bias);
631 /* First adjust for DST */
633 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
635 /* Now adjust for a positive offset from GMT (a negative bias). */
637 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
640 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
642 time_t diff_t = unixTime - smb_localZero;
643 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
644 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
646 *dosUTimep = (afs_uint32)diff_t;
649 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
651 *unixTimep = dosTime + smb_localZero;
654 void smb_MarkAllVCsDead(smb_vc_t * exclude)
657 smb_vc_t **vcp_to_cleanup = NULL;
658 int n_to_cleanup = 0;
661 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
663 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
664 lock_ObtainWrite(&smb_rctLock);
665 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
667 if (vcp->magic != SMB_VC_MAGIC)
668 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
674 lock_ObtainMutex(&vcp->mx);
675 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
676 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
677 lock_ReleaseMutex(&vcp->mx);
678 dead_sessions[vcp->session] = TRUE;
680 lock_ReleaseMutex(&vcp->mx);
685 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
687 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
691 vcp_to_cleanup[i++] = vcp;
692 smb_HoldVCNoLock(vcp);
695 osi_assert(i == n_to_cleanup);
697 lock_ReleaseWrite(&smb_rctLock);
698 lock_ReleaseWrite(&smb_globalLock);
700 for (i=0; i < n_to_cleanup; i++) {
701 smb_CleanupDeadVC(vcp_to_cleanup[i]);
702 smb_ReleaseVC(vcp_to_cleanup[i]);
703 vcp_to_cleanup[i] = 0;
706 free(vcp_to_cleanup);
709 #ifdef DEBUG_SMB_REFCOUNT
710 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
712 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
717 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
718 lock_ObtainWrite(&smb_rctLock);
719 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
720 if (vcp->magic != SMB_VC_MAGIC)
721 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
724 lock_ObtainMutex(&vcp->mx);
725 if (lsn == vcp->lsn && lana == vcp->lana &&
726 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
727 lock_ReleaseMutex(&vcp->mx);
728 smb_HoldVCNoLock(vcp);
731 lock_ReleaseMutex(&vcp->mx);
733 if (!vcp && (flags & SMB_FLAG_CREATE)) {
734 vcp = malloc(sizeof(*vcp));
735 memset(vcp, 0, sizeof(*vcp));
736 vcp->vcID = ++numVCs;
737 vcp->magic = SMB_VC_MAGIC;
738 vcp->refCount = 2; /* smb_allVCsp and caller */
741 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
742 vcp->nextp = smb_allVCsp;
744 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
749 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
750 /* We must obtain a challenge for extended auth
751 * in case the client negotiates smb v3
753 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
754 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
755 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
756 ULONG lsaRespSize = 0;
758 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
760 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
767 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
768 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
769 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
770 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
771 nts, ntsEx, lsaRespSize);
773 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
775 if (ntsEx == STATUS_SUCCESS) {
776 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
779 * This will cause the subsequent authentication to fail but
780 * that is better than us dereferencing a NULL pointer and
783 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
786 LsaFreeReturnBuffer(lsaResp);
789 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
791 if (numVCs >= CM_SESSION_RESERVED) {
793 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
796 #ifdef DEBUG_SMB_REFCOUNT
798 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
799 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
802 lock_ReleaseWrite(&smb_rctLock);
803 lock_ReleaseWrite(&smb_globalLock);
807 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
812 for(i=0; i<11; i++) {
814 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
820 static int smb_IsStarMask(clientchar_t *maskp)
826 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
832 #ifdef DEBUG_SMB_REFCOUNT
833 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
834 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
836 void smb_ReleaseVCInternal(smb_vc_t *vcp)
842 lock_AssertWrite(&smb_rctLock);
845 if (vcp->refCount == 0) {
846 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
847 #ifdef DEBUG_SMB_REFCOUNT
848 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
849 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
851 /* remove VCP from smb_deadVCsp */
852 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
858 lock_FinalizeMutex(&vcp->mx);
859 memset(vcp,0,sizeof(smb_vc_t));
862 #ifdef DEBUG_SMB_REFCOUNT
863 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
865 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
869 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
870 avcp?"":"not ",vcp, vcp->refCount);
872 /* This is a wrong. However, I suspect that there is an undercount
873 * and I don't want to release 1.4.1 in a state that will allow
874 * smb_vc_t objects to be deallocated while still in the
875 * smb_allVCsp list. The list is supposed to keep a reference
876 * to the smb_vc_t. Put it back.
880 #ifdef DEBUG_SMB_REFCOUNT
881 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
882 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
886 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
887 /* The reference count is non-zero but the VC is dead.
888 * This implies that some FIDs, TIDs, etc on the VC have yet to
889 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
890 * add a reference that will be dropped by
891 * smb_CleanupDeadVC() and try to cleanup the VC again.
892 * Eventually the refCount will drop to zero when all of the
893 * active threads working with the VC end their task.
895 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
896 vcp->refCount++; /* put the refCount back */
897 lock_ReleaseWrite(&smb_rctLock);
898 smb_CleanupDeadVC(vcp);
899 #ifdef DEBUG_SMB_REFCOUNT
900 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
901 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
903 lock_ObtainWrite(&smb_rctLock);
906 #ifdef DEBUG_SMB_REFCOUNT
907 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
908 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
913 #ifdef DEBUG_SMB_REFCOUNT
914 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
916 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
919 lock_AssertWrite(&smb_rctLock);
920 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
921 smb_ReleaseVCInternal(vcp);
924 #ifdef DEBUG_SMB_REFCOUNT
925 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
927 void smb_ReleaseVC(smb_vc_t *vcp)
930 lock_ObtainWrite(&smb_rctLock);
931 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
932 smb_ReleaseVCInternal(vcp);
933 lock_ReleaseWrite(&smb_rctLock);
936 #ifdef DEBUG_SMB_REFCOUNT
937 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
939 void smb_HoldVCNoLock(smb_vc_t *vcp)
942 lock_AssertWrite(&smb_rctLock);
944 #ifdef DEBUG_SMB_REFCOUNT
945 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
946 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
948 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
952 #ifdef DEBUG_SMB_REFCOUNT
953 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
955 void smb_HoldVC(smb_vc_t *vcp)
958 lock_ObtainWrite(&smb_rctLock);
960 #ifdef DEBUG_SMB_REFCOUNT
961 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
962 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
964 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
966 lock_ReleaseWrite(&smb_rctLock);
969 void smb_CleanupDeadVC(smb_vc_t *vcp)
977 smb_user_t *uidpIter;
978 smb_user_t *uidpNext;
980 afs_uint32 refCount = 0;
982 lock_ObtainMutex(&vcp->mx);
983 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
984 lock_ReleaseMutex(&vcp->mx);
985 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
988 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
989 lock_ReleaseMutex(&vcp->mx);
990 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
992 lock_ObtainWrite(&smb_rctLock);
993 /* remove VCP from smb_allVCsp */
994 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
995 if ((*vcpp)->magic != SMB_VC_MAGIC)
996 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1000 vcp->nextp = smb_deadVCsp;
1002 /* Hold onto the reference until we are done with this function */
1007 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1008 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1010 if (fidpIter->deleteOk)
1013 fid = fidpIter->fid;
1014 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1016 smb_HoldFIDNoLock(fidpIter);
1017 lock_ReleaseWrite(&smb_rctLock);
1019 smb_CloseFID(vcp, fidpIter, NULL, 0);
1020 smb_ReleaseFID(fidpIter);
1022 lock_ObtainWrite(&smb_rctLock);
1023 fidpNext = vcp->fidsp;
1026 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1027 tidpNext = tidpIter->nextp;
1028 if (tidpIter->deleteOk)
1030 tidpIter->deleteOk = 1;
1032 tid = tidpIter->tid;
1033 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1035 smb_HoldTIDNoLock(tidpIter);
1036 smb_ReleaseTID(tidpIter, TRUE);
1037 tidpNext = vcp->tidsp;
1040 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1041 uidpNext = uidpIter->nextp;
1042 if (uidpIter->deleteOk)
1044 uidpIter->deleteOk = 1;
1046 /* do not add an additional reference count for the smb_user_t
1047 * as the smb_vc_t already is holding a reference */
1048 lock_ReleaseWrite(&smb_rctLock);
1050 smb_ReleaseUID(uidpIter);
1052 lock_ObtainWrite(&smb_rctLock);
1053 uidpNext = vcp->usersp;
1056 /* The vcp is now on the deadVCsp list. We intentionally drop the
1057 * reference so that the refcount can reach 0 and we can delete it
1059 * If the refCount == 1 going into the ReleaseVCNoLock call
1060 * the object will be freed and it won't be safe to clear
1063 refCount = vcp->refCount;
1064 smb_ReleaseVCNoLock(vcp);
1066 lock_ObtainMutex(&vcp->mx);
1067 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1068 lock_ReleaseMutex(&vcp->mx);
1071 lock_ReleaseWrite(&smb_rctLock);
1072 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1075 #ifdef DEBUG_SMB_REFCOUNT
1076 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1078 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1083 lock_ObtainWrite(&smb_rctLock);
1085 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1086 if (tidp->refCount == 0 && tidp->deleteOk) {
1088 smb_ReleaseTID(tidp, TRUE);
1092 if (tid == tidp->tid) {
1097 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1098 tidp = malloc(sizeof(*tidp));
1099 memset(tidp, 0, sizeof(*tidp));
1100 tidp->nextp = vcp->tidsp;
1103 smb_HoldVCNoLock(vcp);
1105 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1108 #ifdef DEBUG_SMB_REFCOUNT
1110 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1111 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1114 lock_ReleaseWrite(&smb_rctLock);
1118 #ifdef DEBUG_SMB_REFCOUNT
1119 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1121 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1124 lock_AssertWrite(&smb_rctLock);
1126 #ifdef DEBUG_SMB_REFCOUNT
1127 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1128 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1132 #ifdef DEBUG_SMB_REFCOUNT
1133 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1135 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1140 cm_user_t *userp = NULL;
1141 smb_vc_t *vcp = NULL;
1144 lock_ObtainWrite(&smb_rctLock);
1146 lock_AssertWrite(&smb_rctLock);
1148 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1149 #ifdef DEBUG_SMB_REFCOUNT
1150 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1151 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1153 if (tidp->refCount == 0) {
1154 if (tidp->deleteOk) {
1155 ltpp = &tidp->vcp->tidsp;
1156 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1160 osi_assertx(tp != NULL, "null smb_tid_t");
1162 lock_FinalizeMutex(&tidp->mx);
1163 userp = tidp->userp; /* remember to drop ref later */
1171 smb_ReleaseVCNoLock(vcp);
1173 lock_ReleaseWrite(&smb_rctLock);
1175 cm_ReleaseUser(userp);
1178 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1180 smb_user_t *uidp = NULL;
1182 lock_ObtainWrite(&smb_rctLock);
1183 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1184 if (uid == uidp->userID) {
1186 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1188 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1192 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1193 uidp = malloc(sizeof(*uidp));
1194 memset(uidp, 0, sizeof(*uidp));
1195 uidp->nextp = vcp->usersp;
1196 uidp->refCount = 2; /* one for the vcp and one for the caller */
1198 smb_HoldVCNoLock(vcp);
1200 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1202 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1204 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1206 lock_ReleaseWrite(&smb_rctLock);
1210 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1213 smb_username_t *unp= NULL;
1215 lock_ObtainWrite(&smb_rctLock);
1216 for(unp = usernamesp; unp; unp = unp->nextp) {
1217 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1218 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1223 if (!unp && (flags & SMB_FLAG_CREATE)) {
1224 unp = malloc(sizeof(*unp));
1225 memset(unp, 0, sizeof(*unp));
1227 unp->nextp = usernamesp;
1228 unp->name = cm_ClientStrDup(usern);
1229 unp->machine = cm_ClientStrDup(machine);
1231 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1232 if (flags & SMB_FLAG_AFSLOGON)
1233 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1236 lock_ReleaseWrite(&smb_rctLock);
1240 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1242 smb_user_t *uidp= NULL;
1244 lock_ObtainWrite(&smb_rctLock);
1245 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1248 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1250 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1251 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1256 lock_ReleaseWrite(&smb_rctLock);
1260 void smb_ReleaseUsername(smb_username_t *unp)
1263 smb_username_t **lupp;
1264 cm_user_t *userp = NULL;
1265 time_t now = osi_Time();
1267 lock_ObtainWrite(&smb_rctLock);
1268 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1269 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1270 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1272 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1276 osi_assertx(up != NULL, "null smb_username_t");
1278 up->nextp = NULL; /* do not remove this */
1279 lock_FinalizeMutex(&unp->mx);
1285 lock_ReleaseWrite(&smb_rctLock);
1287 cm_ReleaseUser(userp);
1290 void smb_HoldUIDNoLock(smb_user_t *uidp)
1292 lock_AssertWrite(&smb_rctLock);
1296 void smb_ReleaseUID(smb_user_t *uidp)
1300 smb_username_t *unp = NULL;
1302 lock_ObtainWrite(&smb_rctLock);
1303 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1304 if (uidp->refCount == 0) {
1305 lupp = &uidp->vcp->usersp;
1306 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1310 osi_assertx(up != NULL, "null smb_user_t");
1312 lock_FinalizeMutex(&uidp->mx);
1314 smb_ReleaseVCNoLock(uidp->vcp);
1318 lock_ReleaseWrite(&smb_rctLock);
1322 cm_ReleaseUserVCRef(unp->userp);
1323 smb_ReleaseUsername(unp);
1327 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1329 cm_user_t *up = NULL;
1334 lock_ObtainMutex(&uidp->mx);
1336 up = uidp->unp->userp;
1339 lock_ReleaseMutex(&uidp->mx);
1345 /* retrieve a held reference to a user structure corresponding to an incoming
1347 * corresponding release function is cm_ReleaseUser.
1349 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1352 cm_user_t *up = NULL;
1355 smbp = (smb_t *) inp;
1356 uidp = smb_FindUID(vcp, smbp->uid, 0);
1360 up = smb_GetUserFromUID(uidp);
1362 smb_ReleaseUID(uidp);
1367 * Return a pointer to a pathname extracted from a TID structure. The
1368 * TID structure is not held; assume it won't go away.
1370 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1375 tidp = smb_FindTID(vcp, tid, 0);
1379 if (tidp->flags & SMB_TIDFLAG_IPC) {
1380 code = CM_ERROR_TIDIPC;
1381 /* tidp->pathname would be NULL, but that's fine */
1383 *treepath = tidp->pathname;
1384 smb_ReleaseTID(tidp, FALSE);
1389 /* check to see if we have a chained fid, that is, a fid that comes from an
1390 * OpenAndX message that ran earlier in this packet. In this case, the fid
1391 * field in a read, for example, request, isn't set, since the value is
1392 * supposed to be inherited from the openAndX call.
1394 int smb_ChainFID(int fid, smb_packet_t *inp)
1396 if (inp->fid == 0 || inp->inCount == 0)
1402 /* are we a priv'd user? What does this mean on NT? */
1403 int smb_SUser(cm_user_t *userp)
1408 /* find a file ID. If we pass in 0 we select an unused File ID.
1409 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1410 * smb_fid_t data structure if desired File ID cannot be found.
1412 #ifdef DEBUG_SMB_REFCOUNT
1413 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1415 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1421 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1424 lock_ObtainWrite(&smb_rctLock);
1425 /* figure out if we need to allocate a new file ID */
1428 fid = vcp->fidCounter;
1432 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1433 if (fidp->refCount == 0 && fidp->deleteOk) {
1435 lock_ReleaseWrite(&smb_rctLock);
1436 smb_ReleaseFID(fidp);
1437 lock_ObtainWrite(&smb_rctLock);
1440 if (fid == fidp->fid) {
1443 if (fid == 0xFFFF) {
1445 "New FID number wraps on vcp 0x%x", vcp);
1455 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1456 char eventName[MAX_PATH];
1458 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1459 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1460 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1461 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1462 thrd_CloseHandle(event);
1464 if (fid == 0xFFFF) {
1465 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1471 fidp = malloc(sizeof(*fidp));
1472 memset(fidp, 0, sizeof(*fidp));
1473 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1476 smb_HoldVCNoLock(vcp);
1477 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1479 fidp->curr_chunk = fidp->prev_chunk = -2;
1480 fidp->raw_write_event = event;
1482 vcp->fidCounter = fid+1;
1483 if (vcp->fidCounter == 0xFFFF) {
1484 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1486 vcp->fidCounter = 1;
1491 #ifdef DEBUG_SMB_REFCOUNT
1493 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1494 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1497 lock_ReleaseWrite(&smb_rctLock);
1502 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1503 #ifdef DEBUG_SMB_REFCOUNT
1504 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1506 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1509 smb_fid_t *fidp = NULL, *nextp = NULL;
1515 * If the fidp->scp changes out from under us then
1516 * we must not grab a refCount. It means the *fidp
1517 * was processed by smb_CloseFID() and the *fidp is
1518 * no longer valid for use.
1520 lock_ObtainWrite(&smb_rctLock);
1521 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1522 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1526 if (scp == fidp->scp) {
1527 lock_ReleaseWrite(&smb_rctLock);
1528 lock_ObtainMutex(&fidp->mx);
1529 lock_ObtainWrite(&smb_rctLock);
1530 if (scp == fidp->scp) {
1531 lock_ReleaseMutex(&fidp->mx);
1534 lock_ReleaseMutex(&fidp->mx);
1537 if (fidp->refCount > 1) {
1540 lock_ReleaseWrite(&smb_rctLock);
1541 smb_ReleaseFID(fidp);
1542 lock_ObtainWrite(&smb_rctLock);
1547 if (nextp->refCount > 1) {
1550 lock_ReleaseWrite(&smb_rctLock);
1551 smb_ReleaseFID(nextp);
1552 lock_ObtainWrite(&smb_rctLock);
1556 #ifdef DEBUG_SMB_REFCOUNT
1558 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1559 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1562 lock_ReleaseWrite(&smb_rctLock);
1566 #ifdef DEBUG_SMB_REFCOUNT
1567 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1569 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1572 lock_AssertWrite(&smb_rctLock);
1574 #ifdef DEBUG_SMB_REFCOUNT
1575 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1576 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1581 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1582 /* the smb_fid_t->mx and smb_rctLock must not be held */
1583 #ifdef DEBUG_SMB_REFCOUNT
1584 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1586 void smb_ReleaseFID(smb_fid_t *fidp)
1589 cm_scache_t *scp = NULL;
1590 cm_user_t *userp = NULL;
1591 smb_vc_t *vcp = NULL;
1592 smb_ioctl_t *ioctlp;
1594 lock_ObtainMutex(&fidp->mx);
1595 lock_ObtainWrite(&smb_rctLock);
1596 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1597 #ifdef DEBUG_SMB_REFCOUNT
1598 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1599 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1601 if (fidp->refCount == 0) {
1602 if (fidp->deleteOk) {
1605 scp = fidp->scp; /* release after lock is released */
1607 lock_ObtainWrite(&scp->rw);
1608 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1609 lock_ReleaseWrite(&scp->rw);
1610 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1613 userp = fidp->userp;
1617 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1618 thrd_CloseHandle(fidp->raw_write_event);
1620 /* and see if there is ioctl stuff to free */
1621 ioctlp = fidp->ioctlp;
1624 cm_FreeSpace(ioctlp->prefix);
1625 if (ioctlp->ioctl.inAllocp)
1626 free(ioctlp->ioctl.inAllocp);
1627 if (ioctlp->ioctl.outAllocp)
1628 free(ioctlp->ioctl.outAllocp);
1632 smb_CleanupRPCFid(fidp);
1634 lock_ReleaseMutex(&fidp->mx);
1635 lock_FinalizeMutex(&fidp->mx);
1640 smb_ReleaseVCNoLock(vcp);
1644 lock_ReleaseMutex(&fidp->mx);
1646 lock_ReleaseWrite(&smb_rctLock);
1648 /* now release the scache structure */
1650 cm_ReleaseSCache(scp);
1653 cm_ReleaseUser(userp);
1657 * Case-insensitive search for one string in another;
1658 * used to find variable names in submount pathnames.
1660 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1662 clientchar_t *cursor;
1664 for (cursor = str1; *cursor; cursor++)
1665 if (cm_ClientStrCmpI(cursor, str2) == 0)
1672 * Substitute a variable value for its name in a submount pathname. Variable
1673 * name has been identified by smb_stristr() and is in substr. Variable name
1674 * length (plus one) is in substr_size. Variable value is in newstr.
1676 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1677 unsigned int substr_size, clientchar_t *newstr)
1679 clientchar_t temp[1024];
1681 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1682 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1683 cm_ClientStrCat(str1, cchstr1, temp);
1686 clientchar_t VNUserName[] = _C("%USERNAME%");
1687 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1688 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1689 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1691 typedef struct smb_findShare_rock {
1692 clientchar_t * shareName;
1693 clientchar_t * match;
1695 } smb_findShare_rock_t;
1697 #define SMB_FINDSHARE_EXACT_MATCH 1
1698 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1700 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1704 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1705 normchar_t normName[MAX_PATH];
1707 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1708 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1709 osi_LogSaveString(smb_logp, dep->name));
1713 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1714 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1715 matchType = SMB_FINDSHARE_EXACT_MATCH;
1717 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1720 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1721 vrock->matchType = matchType;
1723 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1724 return CM_ERROR_STOPNOW;
1730 /* find a shareName in the table of submounts */
1731 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1732 clientchar_t *shareName,
1733 clientchar_t **pathNamep)
1737 clientchar_t pathName[1024];
1740 clientchar_t *p, *q;
1741 fschar_t *cellname = NULL;
1744 DWORD allSubmount = 1;
1746 /* if allSubmounts == 0, only return the //mountRoot/all share
1747 * if in fact it has been been created in the subMounts table.
1748 * This is to allow sites that want to restrict access to the
1751 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1752 0, KEY_QUERY_VALUE, &parmKey);
1753 if (code == ERROR_SUCCESS) {
1754 cblen = sizeof(allSubmount);
1755 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1756 (BYTE *) &allSubmount, &cblen);
1757 if (code != ERROR_SUCCESS) {
1760 RegCloseKey (parmKey);
1763 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1768 /* In case, the all share is disabled we need to still be able
1769 * to handle ioctl requests
1771 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1772 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1776 if (MSRPC_IsWellKnownService(shareName) ||
1777 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1778 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1784 /* Check for volume references
1786 * They look like <cell>{%,#}<volume>
1788 if (cm_ClientStrChr(shareName, '%') != NULL ||
1789 cm_ClientStrChr(shareName, '#') != NULL) {
1790 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1791 /* make room for '/@vol:' + mountchar + NULL terminator*/
1793 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1794 osi_LogSaveClientString(smb_logp, shareName));
1796 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1797 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1798 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1800 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1802 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1803 cm_ClientStrLwr(*pathNamep);
1804 osi_Log1(smb_logp, " returning pathname [%S]",
1805 osi_LogSaveClientString(smb_logp, *pathNamep));
1813 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1814 0, KEY_QUERY_VALUE, &parmKey);
1815 if (code == ERROR_SUCCESS) {
1816 cblen = sizeof(pathName);
1817 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1818 (BYTE *) pathName, &cblen);
1819 if (code != ERROR_SUCCESS)
1821 RegCloseKey (parmKey);
1825 cchlen = cblen / sizeof(clientchar_t);
1826 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1827 /* We can accept either unix or PC style AFS pathnames. Convert
1828 * Unix-style to PC style here for internal use.
1831 cchlen = lengthof(pathName);
1833 /* within this code block, we maintain, cchlen = writeable
1834 buffer length of p */
1836 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1837 p += cm_mountRootCLen; /* skip mount path */
1838 cchlen -= (DWORD)(p - pathName);
1843 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1849 clientchar_t temp[1024];
1851 if (var = smb_stristr(p, VNUserName)) {
1852 if (uidp && uidp->unp)
1853 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1855 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1857 else if (var = smb_stristr(p, VNLCUserName))
1859 if (uidp && uidp->unp)
1860 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1862 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1863 cm_ClientStrLwr(temp);
1864 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1866 else if (var = smb_stristr(p, VNComputerName))
1868 sizeTemp = lengthof(temp);
1869 GetComputerNameW(temp, &sizeTemp);
1870 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1872 else if (var = smb_stristr(p, VNLCComputerName))
1874 sizeTemp = lengthof(temp);
1875 GetComputerName((LPTSTR)temp, &sizeTemp);
1876 cm_ClientStrLwr(temp);
1877 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1882 *pathNamep = cm_ClientStrDup(p);
1887 /* First lookup shareName in root.afs */
1889 smb_findShare_rock_t vrock;
1891 fschar_t ftemp[1024];
1892 clientchar_t * p = shareName;
1895 /* attempt to locate a partial match in root.afs. This is because
1896 when using the ANSI RAP calls, the share name is limited to 13 chars
1897 and hence is truncated. Of course we prefer exact matches. */
1899 thyper.HighPart = 0;
1902 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1903 if (vrock.shareName == NULL)
1906 vrock.matchType = 0;
1908 cm_HoldSCache(cm_data.rootSCachep);
1909 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1910 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1911 cm_ReleaseSCache(cm_data.rootSCachep);
1913 free(vrock.shareName);
1914 vrock.shareName = NULL;
1916 if (vrock.matchType) {
1917 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1918 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1923 /* if we get here, there was no match for the share in root.afs */
1924 /* so try to create \\<netbiosName>\<cellname> */
1929 /* Get the full name for this cell */
1930 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1931 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
1932 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
1933 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1934 #ifdef AFS_AFSDB_ENV
1935 if (code && cm_dnsEnabled) {
1937 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1943 /* construct the path */
1945 clientchar_t temp[1024];
1947 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
1948 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
1949 rw ? _C("/.%S/") : _C("/%S/"), temp);
1950 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1960 /* Client-side offline caching policy types */
1961 #define CSC_POLICY_MANUAL 0
1962 #define CSC_POLICY_DOCUMENTS 1
1963 #define CSC_POLICY_PROGRAMS 2
1964 #define CSC_POLICY_DISABLE 3
1966 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1969 clientchar_t policy[1024];
1972 int retval = CSC_POLICY_MANUAL;
1974 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1975 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1978 REG_OPTION_NON_VOLATILE,
1984 len = sizeof(policy);
1985 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
1987 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1989 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
1991 retval = CSC_POLICY_DOCUMENTS;
1993 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
1995 retval = CSC_POLICY_PROGRAMS;
1997 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
1999 retval = CSC_POLICY_DISABLE;
2002 RegCloseKey(hkCSCPolicy);
2006 /* find a dir search structure by cookie value, and return it held.
2007 * Must be called with smb_globalLock held.
2009 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2011 smb_dirSearch_t *dsp;
2013 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2014 if (dsp->cookie == cookie) {
2015 if (dsp != smb_firstDirSearchp) {
2016 /* move to head of LRU queue, too, if we're not already there */
2017 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2018 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2019 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2020 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2021 if (!smb_lastDirSearchp)
2022 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2030 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2031 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2032 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2038 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2040 lock_ObtainMutex(&dsp->mx);
2041 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2042 dsp->cookie, dsp, dsp->scp);
2043 dsp->flags |= SMB_DIRSEARCH_DELETE;
2044 if (dsp->scp != NULL) {
2045 lock_ObtainWrite(&dsp->scp->rw);
2046 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2047 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2048 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2049 dsp->scp->bulkStatProgress = hzero;
2051 lock_ReleaseWrite(&dsp->scp->rw);
2053 lock_ReleaseMutex(&dsp->mx);
2056 /* Must be called with the smb_globalLock held */
2057 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2059 cm_scache_t *scp = NULL;
2061 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2062 if (dsp->refCount == 0) {
2063 lock_ObtainMutex(&dsp->mx);
2064 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2065 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2066 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2067 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2068 lock_ReleaseMutex(&dsp->mx);
2069 lock_FinalizeMutex(&dsp->mx);
2071 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2072 dsp->cookie, dsp, scp);
2075 lock_ReleaseMutex(&dsp->mx);
2078 /* do this now to avoid spurious locking hierarchy creation */
2080 cm_ReleaseSCache(scp);
2083 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2085 lock_ObtainWrite(&smb_globalLock);
2086 smb_ReleaseDirSearchNoLock(dsp);
2087 lock_ReleaseWrite(&smb_globalLock);
2090 /* find a dir search structure by cookie value, and return it held */
2091 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2093 smb_dirSearch_t *dsp;
2095 lock_ObtainWrite(&smb_globalLock);
2096 dsp = smb_FindDirSearchNoLock(cookie);
2097 lock_ReleaseWrite(&smb_globalLock);
2101 /* GC some dir search entries, in the address space expected by the specific protocol.
2102 * Must be called with smb_globalLock held; release the lock temporarily.
2104 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2105 void smb_GCDirSearches(int isV3)
2107 smb_dirSearch_t *prevp;
2108 smb_dirSearch_t *dsp;
2109 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2113 victimCount = 0; /* how many have we got so far */
2114 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2115 /* we'll move tp from queue, so
2118 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2119 /* if no one is using this guy, and we're either in the new protocol,
2120 * or we're in the old one and this is a small enough ID to be useful
2121 * to the old protocol, GC this guy.
2123 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2124 /* hold and delete */
2125 lock_ObtainMutex(&dsp->mx);
2126 dsp->flags |= SMB_DIRSEARCH_DELETE;
2127 lock_ReleaseMutex(&dsp->mx);
2128 victimsp[victimCount++] = dsp;
2132 /* don't do more than this */
2133 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2137 /* now release them */
2138 for (i = 0; i < victimCount; i++) {
2139 smb_ReleaseDirSearchNoLock(victimsp[i]);
2143 /* function for allocating a dir search entry. We need these to remember enough context
2144 * since we don't get passed the path from call to call during a directory search.
2146 * Returns a held dir search structure, and bumps the reference count on the vnode,
2147 * since it saves a pointer to the vnode.
2149 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2151 smb_dirSearch_t *dsp;
2157 lock_ObtainWrite(&smb_globalLock);
2160 /* what's the biggest ID allowed in this version of the protocol */
2161 /* TODO: do we really want a non v3 dir search request to wrap
2162 smb_dirSearchCounter? */
2163 maxAllowed = isV3 ? 65535 : 255;
2164 if (smb_dirSearchCounter > maxAllowed)
2165 smb_dirSearchCounter = 1;
2167 start = smb_dirSearchCounter;
2170 /* twice so we have enough tries to find guys we GC after one pass;
2171 * 10 extra is just in case I mis-counted.
2173 if (++counter > 2*maxAllowed+10)
2174 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2176 if (smb_dirSearchCounter > maxAllowed) {
2177 smb_dirSearchCounter = 1;
2179 if (smb_dirSearchCounter == start) {
2181 smb_GCDirSearches(isV3);
2184 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2186 /* don't need to watch for refcount zero and deleted, since
2187 * we haven't dropped the global lock.
2190 ++smb_dirSearchCounter;
2194 dsp = malloc(sizeof(*dsp));
2195 memset(dsp, 0, sizeof(*dsp));
2196 dsp->cookie = smb_dirSearchCounter;
2197 ++smb_dirSearchCounter;
2199 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2200 dsp->lastTime = osi_Time();
2201 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2202 if (!smb_lastDirSearchp)
2203 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2205 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2209 lock_ReleaseWrite(&smb_globalLock);
2213 static smb_packet_t *smb_GetPacket(void)
2217 lock_ObtainWrite(&smb_globalLock);
2218 tbp = smb_packetFreeListp;
2220 smb_packetFreeListp = tbp->nextp;
2221 lock_ReleaseWrite(&smb_globalLock);
2223 tbp = calloc(sizeof(*tbp),1);
2224 tbp->magic = SMB_PACKETMAGIC;
2227 tbp->resumeCode = 0;
2233 tbp->ncb_length = 0;
2236 tbp->stringsp = NULL;
2238 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2243 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2246 tbp = smb_GetPacket();
2247 memcpy(tbp, pkt, sizeof(smb_packet_t));
2248 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2249 tbp->stringsp = NULL;
2251 smb_HoldVC(tbp->vcp);
2255 static NCB *smb_GetNCB(void)
2260 lock_ObtainWrite(&smb_globalLock);
2261 tbp = smb_ncbFreeListp;
2263 smb_ncbFreeListp = tbp->nextp;
2264 lock_ReleaseWrite(&smb_globalLock);
2266 tbp = calloc(sizeof(*tbp),1);
2267 tbp->magic = SMB_NCBMAGIC;
2270 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2272 memset(&tbp->ncb, 0, sizeof(NCB));
2277 static void FreeSMBStrings(smb_packet_t * pkt)
2282 for (s = pkt->stringsp; s; s = ns) {
2286 pkt->stringsp = NULL;
2289 void smb_FreePacket(smb_packet_t *tbp)
2291 smb_vc_t * vcp = NULL;
2292 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2294 lock_ObtainWrite(&smb_globalLock);
2295 tbp->nextp = smb_packetFreeListp;
2296 smb_packetFreeListp = tbp;
2297 tbp->magic = SMB_PACKETMAGIC;
2301 tbp->resumeCode = 0;
2307 tbp->ncb_length = 0;
2309 FreeSMBStrings(tbp);
2310 lock_ReleaseWrite(&smb_globalLock);
2316 static void smb_FreeNCB(NCB *bufferp)
2320 tbp = (smb_ncb_t *) bufferp;
2321 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2323 lock_ObtainWrite(&smb_globalLock);
2324 tbp->nextp = smb_ncbFreeListp;
2325 smb_ncbFreeListp = tbp;
2326 lock_ReleaseWrite(&smb_globalLock);
2329 /* get a ptr to the data part of a packet, and its count */
2330 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2334 unsigned char *afterParmsp;
2336 parmBytes = *smbp->wctp << 1;
2337 afterParmsp = smbp->wctp + parmBytes + 1;
2339 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2340 if (nbytesp) *nbytesp = dataBytes;
2342 /* don't forget to skip the data byte count, since it follows
2343 * the parameters; that's where the "2" comes from below.
2345 return (unsigned char *) (afterParmsp + 2);
2348 /* must set all the returned parameters before playing around with the
2349 * data region, since the data region is located past the end of the
2350 * variable number of parameters.
2352 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2354 unsigned char *afterParmsp;
2356 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2358 *afterParmsp++ = dsize & 0xff;
2359 *afterParmsp = (dsize>>8) & 0xff;
2362 /* return the parm'th parameter in the smbp packet */
2363 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2366 unsigned char *parmDatap;
2368 parmCount = *smbp->wctp;
2370 if (parm >= parmCount) {
2373 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2374 parm, parmCount, smbp->ncb_length);
2375 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2376 parm, parmCount, smbp->ncb_length);
2377 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2378 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2379 osi_panic(s, __FILE__, __LINE__);
2381 parmDatap = smbp->wctp + (2*parm) + 1;
2383 return parmDatap[0] + (parmDatap[1] << 8);
2386 /* return the parm'th parameter in the smbp packet */
2387 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2390 unsigned char *parmDatap;
2392 parmCount = *smbp->wctp;
2394 if (parm >= parmCount) {
2397 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2398 parm, parmCount, smbp->ncb_length);
2399 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2400 parm, parmCount, smbp->ncb_length);
2401 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2402 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2403 osi_panic(s, __FILE__, __LINE__);
2405 parmDatap = smbp->wctp + (2*parm) + 1;
2407 return parmDatap[0];
2410 /* return the parm'th parameter in the smbp packet */
2411 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2414 unsigned char *parmDatap;
2416 parmCount = *smbp->wctp;
2418 if (parm + 1 >= parmCount) {
2421 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2422 parm, parmCount, smbp->ncb_length);
2423 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2424 parm, parmCount, smbp->ncb_length);
2425 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2426 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2427 osi_panic(s, __FILE__, __LINE__);
2429 parmDatap = smbp->wctp + (2*parm) + 1;
2431 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2434 /* return the parm'th parameter in the smbp packet */
2435 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2438 unsigned char *parmDatap;
2440 parmCount = *smbp->wctp;
2442 if (parm * 2 + offset >= parmCount * 2) {
2445 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2446 parm, offset, parmCount, smbp->ncb_length);
2447 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2448 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2449 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2450 parm, offset, parmCount, smbp->ncb_length);
2451 osi_panic(s, __FILE__, __LINE__);
2453 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2455 return parmDatap[0] + (parmDatap[1] << 8);
2458 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2460 unsigned char *parmDatap;
2462 /* make sure we have enough slots */
2463 if (*smbp->wctp <= slot)
2464 *smbp->wctp = slot+1;
2466 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2467 *parmDatap++ = parmValue & 0xff;
2468 *parmDatap = (parmValue>>8) & 0xff;
2471 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2473 unsigned char *parmDatap;
2475 /* make sure we have enough slots */
2476 if (*smbp->wctp <= slot)
2477 *smbp->wctp = slot+2;
2479 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2480 *parmDatap++ = parmValue & 0xff;
2481 *parmDatap++ = (parmValue>>8) & 0xff;
2482 *parmDatap++ = (parmValue>>16) & 0xff;
2483 *parmDatap = (parmValue>>24) & 0xff;
2486 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2488 unsigned char *parmDatap;
2491 /* make sure we have enough slots */
2492 if (*smbp->wctp <= slot)
2493 *smbp->wctp = slot+4;
2495 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2497 *parmDatap++ = *parmValuep++;
2500 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2502 unsigned char *parmDatap;
2504 /* make sure we have enough slots */
2505 if (*smbp->wctp <= slot) {
2506 if (smbp->oddByte) {
2508 *smbp->wctp = slot+1;
2513 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2514 *parmDatap++ = parmValue & 0xff;
2519 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2520 clientchar_t *inPathp)
2522 clientchar_t *lastSlashp;
2524 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2526 *lastComponentp = lastSlashp;
2529 if (inPathp == lastSlashp)
2531 *outPathp++ = *inPathp++;
2540 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2541 char **chainpp, int flags)
2544 afs_uint32 type = *inp++;
2547 * The first byte specifies the type of the input string.
2548 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2552 /* Length Counted */
2553 case 0x1: /* Data Block */
2554 case 0x5: /* Variable Block */
2555 cb = *inp++ << 16 | *inp++;
2558 /* Null-terminated string */
2559 case 0x4: /* ASCII */
2560 case 0x3: /* Pathname */
2561 case 0x2: /* Dialect */
2562 cb = sizeof(pktp->data) - (inp - pktp->data);
2563 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2564 #ifdef DEBUG_UNICODE
2567 cb = sizeof(pktp->data);
2572 return NULL; /* invalid input */
2576 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2577 flags |= SMB_STRF_FORCEASCII;
2580 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2583 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2584 char ** chainpp, int flags)
2589 if (!WANTS_UNICODE(pktp))
2590 flags |= SMB_STRF_FORCEASCII;
2593 cb = sizeof(pktp->data) - (inp - pktp->data);
2594 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2595 #ifdef DEBUG_UNICODE
2598 cb = sizeof(pktp->data);
2600 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2601 flags | SMB_STRF_SRCNULTERM);
2604 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2605 size_t cb, char ** chainpp, int flags)
2608 if (!WANTS_UNICODE(pktp))
2609 flags |= SMB_STRF_FORCEASCII;
2612 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2615 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2616 size_t cch, char ** chainpp, int flags)
2621 if (!WANTS_UNICODE(pktp))
2622 flags |= SMB_STRF_FORCEASCII;
2624 cb = cch * sizeof(wchar_t);
2627 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2631 smb_ParseStringBuf(const unsigned char * bufbase,
2632 cm_space_t ** stringspp,
2633 unsigned char *inp, size_t *pcb_max,
2634 char **chainpp, int flags)
2637 if (!(flags & SMB_STRF_FORCEASCII)) {
2639 cm_space_t * spacep;
2642 if (bufbase && ((inp - bufbase) % 2) != 0) {
2643 inp++; /* unicode strings are always word aligned */
2647 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2649 cch_src = *pcb_max / sizeof(wchar_t);
2653 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2660 spacep = cm_GetSpace();
2661 spacep->nextp = *stringspp;
2662 *stringspp = spacep;
2666 *chainpp = inp + sizeof(wchar_t);
2669 *(spacep->wdata) = 0;
2670 return spacep->wdata;
2673 StringCchCopyNW(spacep->wdata,
2674 lengthof(spacep->wdata),
2675 (const clientchar_t *) inp, cch_src);
2678 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2680 return spacep->wdata;
2684 cm_space_t * spacep;
2687 /* Not using Unicode */
2689 *chainpp = inp + strlen(inp) + 1;
2692 spacep = cm_GetSpace();
2693 spacep->nextp = *stringspp;
2694 *stringspp = spacep;
2696 cchdest = lengthof(spacep->wdata);
2697 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2698 spacep->wdata, cchdest);
2700 return spacep->wdata;
2706 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2708 size_t * plen, int flags)
2714 /* we are only calculating the required size */
2721 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2723 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2724 if (!(flags & SMB_STRF_IGNORENUL))
2725 *plen += sizeof(wchar_t);
2727 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2737 cch_str = cm_ClientStrLen(str);
2738 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2741 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2749 /* if outp != NULL ... */
2751 /* Number of bytes left in the buffer.
2753 If outp lies inside the packet data buffer, we assume that the
2754 buffer is the packet data buffer. Otherwise we assume that the
2755 buffer is sizeof(packet->data).
2758 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2759 align = (int)((outp - pktp->data) % 2);
2760 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2762 align = (int)(((size_t) outp) % 2);
2763 buffersize = (int)sizeof(pktp->data);
2768 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2774 if (*str == _C('\0')) {
2776 if (buffersize < sizeof(wchar_t))
2779 *((wchar_t *) outp) = L'\0';
2780 if (plen && !(flags & SMB_STRF_IGNORENUL))
2781 *plen += sizeof(wchar_t);
2782 return outp + sizeof(wchar_t);
2785 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2787 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2788 osi_LogSaveClientString(smb_logp, str),
2794 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2796 return outp + sizeof(wchar_t) * nchars;
2804 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2807 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2809 return outp + cch_dest;
2813 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2819 tlen = inp[0] + (inp[1]<<8);
2820 inp += 2; /* skip length field */
2823 *chainpp = inp + tlen;
2832 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2836 if (*inp++ != 0x1) return NULL;
2837 tlen = inp[0] + (inp[1]<<8);
2838 inp += 2; /* skip length field */
2841 *chainpp = inp + tlen;
2844 if (lengthp) *lengthp = tlen;
2849 /* format a packet as a response */
2850 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2855 outp = (smb_t *) op;
2857 /* zero the basic structure through the smb_wct field, and zero the data
2858 * size field, assuming that wct stays zero; otherwise, you have to
2859 * explicitly set the data size field, too.
2861 inSmbp = (smb_t *) inp;
2862 memset(outp, 0, sizeof(smb_t)+2);
2868 outp->com = inSmbp->com;
2869 outp->tid = inSmbp->tid;
2870 outp->pid = inSmbp->pid;
2871 outp->uid = inSmbp->uid;
2872 outp->mid = inSmbp->mid;
2873 outp->res[0] = inSmbp->res[0];
2874 outp->res[1] = inSmbp->res[1];
2875 op->inCom = inSmbp->com;
2877 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2878 #ifdef SEND_CANONICAL_PATHNAMES
2879 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2881 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2883 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2884 outp->flg2 |= SMB_FLAGS2_UNICODE;
2887 /* copy fields in generic packet area */
2888 op->wctp = &outp->wct;
2891 /* send a (probably response) packet; vcp tells us to whom to send it.
2892 * we compute the length by looking at wct and bcc fields.
2894 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2904 ncbp = smb_GetNCB();
2908 memset((char *)ncbp, 0, sizeof(NCB));
2910 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2911 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2912 extra += tp[0] + (tp[1]<<8);
2913 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2914 extra += 3; /* wct and length fields */
2916 ncbp->ncb_length = extra; /* bytes to send */
2917 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2918 ncbp->ncb_lana_num = vcp->lana;
2919 ncbp->ncb_command = NCBSEND; /* op means send data */
2920 ncbp->ncb_buffer = (char *) inp;/* packet */
2921 code = Netbios(ncbp);
2924 const char * s = ncb_error_string(code);
2925 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2926 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2928 lock_ObtainMutex(&vcp->mx);
2929 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2930 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2932 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2933 lock_ReleaseMutex(&vcp->mx);
2934 lock_ObtainWrite(&smb_globalLock);
2935 dead_sessions[vcp->session] = TRUE;
2936 lock_ReleaseWrite(&smb_globalLock);
2937 smb_CleanupDeadVC(vcp);
2939 lock_ReleaseMutex(&vcp->mx);
2947 void smb_MapNTError(long code, unsigned long *NTStatusp)
2949 unsigned long NTStatus;
2951 /* map CM_ERROR_* errors to NT 32-bit status codes */
2952 /* NT Status codes are listed in ntstatus.h not winerror.h */
2956 else if (code == CM_ERROR_NOSUCHCELL) {
2957 NTStatus = 0xC000000FL; /* No such file */
2959 else if (code == CM_ERROR_NOSUCHVOLUME) {
2960 NTStatus = 0xC000000FL; /* No such file */
2962 else if (code == CM_ERROR_TIMEDOUT) {
2964 NTStatus = 0xC00000CFL; /* Sharing Paused */
2966 NTStatus = 0x00000102L; /* Timeout */
2969 else if (code == CM_ERROR_RETRY) {
2970 NTStatus = 0xC000022DL; /* Retry */
2972 else if (code == CM_ERROR_NOACCESS) {
2973 NTStatus = 0xC0000022L; /* Access denied */
2975 else if (code == CM_ERROR_READONLY) {
2976 NTStatus = 0xC00000A2L; /* Write protected */
2978 else if (code == CM_ERROR_NOSUCHFILE ||
2979 code == CM_ERROR_BPLUS_NOMATCH) {
2980 NTStatus = 0xC000000FL; /* No such file */
2982 else if (code == CM_ERROR_NOSUCHPATH) {
2983 NTStatus = 0xC000003AL; /* Object path not found */
2985 else if (code == CM_ERROR_TOOBIG) {
2986 NTStatus = 0xC000007BL; /* Invalid image format */
2988 else if (code == CM_ERROR_INVAL) {
2989 NTStatus = 0xC000000DL; /* Invalid parameter */
2991 else if (code == CM_ERROR_BADFD) {
2992 NTStatus = 0xC0000008L; /* Invalid handle */
2994 else if (code == CM_ERROR_BADFDOP) {
2995 NTStatus = 0xC0000022L; /* Access denied */
2997 else if (code == CM_ERROR_EXISTS) {
2998 NTStatus = 0xC0000035L; /* Object name collision */
3000 else if (code == CM_ERROR_NOTEMPTY) {
3001 NTStatus = 0xC0000101L; /* Directory not empty */
3003 else if (code == CM_ERROR_CROSSDEVLINK) {
3004 NTStatus = 0xC00000D4L; /* Not same device */
3006 else if (code == CM_ERROR_NOTDIR) {
3007 NTStatus = 0xC0000103L; /* Not a directory */
3009 else if (code == CM_ERROR_ISDIR) {
3010 NTStatus = 0xC00000BAL; /* File is a directory */
3012 else if (code == CM_ERROR_BADOP) {
3014 /* I have no idea where this comes from */
3015 NTStatus = 0xC09820FFL; /* SMB no support */
3017 NTStatus = 0xC00000BBL; /* Not supported */
3018 #endif /* COMMENT */
3020 else if (code == CM_ERROR_BADSHARENAME) {
3021 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3023 else if (code == CM_ERROR_NOIPC) {
3025 NTStatus = 0xC0000022L; /* Access Denied */
3027 NTStatus = 0xC000013DL; /* Remote Resources */
3030 else if (code == CM_ERROR_CLOCKSKEW) {
3031 NTStatus = 0xC0000133L; /* Time difference at DC */
3033 else if (code == CM_ERROR_BADTID) {
3034 NTStatus = 0xC0982005L; /* SMB bad TID */
3036 else if (code == CM_ERROR_USESTD) {
3037 NTStatus = 0xC09820FBL; /* SMB use standard */
3039 else if (code == CM_ERROR_QUOTA) {
3040 NTStatus = 0xC0000044L; /* Quota exceeded */
3042 else if (code == CM_ERROR_SPACE) {
3043 NTStatus = 0xC000007FL; /* Disk full */
3045 else if (code == CM_ERROR_ATSYS) {
3046 NTStatus = 0xC0000033L; /* Object name invalid */
3048 else if (code == CM_ERROR_BADNTFILENAME) {
3049 NTStatus = 0xC0000033L; /* Object name invalid */
3051 else if (code == CM_ERROR_WOULDBLOCK) {
3052 NTStatus = 0xC00000D8L; /* Can't wait */
3054 else if (code == CM_ERROR_SHARING_VIOLATION) {
3055 NTStatus = 0xC0000043L; /* Sharing violation */
3057 else if (code == CM_ERROR_LOCK_CONFLICT) {
3058 NTStatus = 0xC0000054L; /* Lock conflict */
3060 else if (code == CM_ERROR_PARTIALWRITE) {
3061 NTStatus = 0xC000007FL; /* Disk full */
3063 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3064 NTStatus = 0xC0000023L; /* Buffer too small */
3066 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3067 NTStatus = 0xC0000035L; /* Object name collision */
3069 else if (code == CM_ERROR_BADPASSWORD) {
3070 NTStatus = 0xC000006DL; /* unknown username or bad password */
3072 else if (code == CM_ERROR_BADLOGONTYPE) {
3073 NTStatus = 0xC000015BL; /* logon type not granted */
3075 else if (code == CM_ERROR_GSSCONTINUE) {
3076 NTStatus = 0xC0000016L; /* more processing required */
3078 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3080 NTStatus = 0xC0000280L; /* reparse point not resolved */
3082 NTStatus = 0xC0000022L; /* Access Denied */
3085 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3086 NTStatus = 0xC0000257L; /* Path Not Covered */
3088 else if (code == CM_ERROR_ALLBUSY) {
3089 NTStatus = 0xC000022DL; /* Retry */
3091 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3092 NTStatus = 0xC000003AL; /* Path not found */
3094 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3095 NTStatus = 0xC0000322L; /* No Kerberos key */
3097 else if (code == CM_ERROR_BAD_LEVEL) {
3098 NTStatus = 0xC0000148L; /* Invalid Level */
3100 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3101 NTStatus = 0xC000007EL; /* Range Not Locked */
3103 else if (code == CM_ERROR_NOSUCHDEVICE) {
3104 NTStatus = 0xC000000EL; /* No Such Device */
3106 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3107 NTStatus = 0xC0000055L; /* Lock Not Granted */
3109 else if (code == ENOMEM) {
3110 NTStatus = 0xC0000017L; /* Out of Memory */
3112 else if (code == CM_ERROR_RPC_MOREDATA) {
3113 NTStatus = 0x80000005L; /* Buffer overflow */
3116 NTStatus = 0xC0982001L; /* SMB non-specific error */
3119 *NTStatusp = NTStatus;
3120 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3124 * NTSTATUS <-> Win32 Error Translation
3125 * http://support.microsoft.com/kb/113996
3127 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3129 unsigned long Win32E;
3131 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3135 else if (code == CM_ERROR_NOSUCHCELL) {
3136 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3138 else if (code == CM_ERROR_NOSUCHVOLUME) {
3139 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3141 else if (code == CM_ERROR_TIMEDOUT) {
3143 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3145 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3148 else if (code == CM_ERROR_RETRY) {
3149 Win32E = ERROR_RETRY; /* Retry */
3151 else if (code == CM_ERROR_NOACCESS) {
3152 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3154 else if (code == CM_ERROR_READONLY) {
3155 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3157 else if (code == CM_ERROR_NOSUCHFILE ||
3158 code == CM_ERROR_BPLUS_NOMATCH) {
3159 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3161 else if (code == CM_ERROR_NOSUCHPATH) {
3162 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3164 else if (code == CM_ERROR_TOOBIG) {
3165 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3167 else if (code == CM_ERROR_INVAL) {
3168 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3170 else if (code == CM_ERROR_BADFD) {
3171 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3173 else if (code == CM_ERROR_BADFDOP) {
3174 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3176 else if (code == CM_ERROR_EXISTS) {
3177 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3179 else if (code == CM_ERROR_NOTEMPTY) {
3180 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3182 else if (code == CM_ERROR_CROSSDEVLINK) {
3183 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3185 else if (code == CM_ERROR_NOTDIR) {
3186 Win32E = ERROR_DIRECTORY; /* Not a directory */
3188 else if (code == CM_ERROR_ISDIR) {
3189 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3191 else if (code == CM_ERROR_BADOP) {
3192 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3194 else if (code == CM_ERROR_BADSHARENAME) {
3195 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3197 else if (code == CM_ERROR_NOIPC) {
3199 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3201 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3204 else if (code == CM_ERROR_CLOCKSKEW) {
3205 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3207 else if (code == CM_ERROR_BADTID) {
3208 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3210 else if (code == CM_ERROR_USESTD) {
3211 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3213 else if (code == CM_ERROR_QUOTA) {
3214 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3216 else if (code == CM_ERROR_SPACE) {
3217 Win32E = ERROR_DISK_FULL; /* Disk full */
3219 else if (code == CM_ERROR_ATSYS) {
3220 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3222 else if (code == CM_ERROR_BADNTFILENAME) {
3223 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3225 else if (code == CM_ERROR_WOULDBLOCK) {
3226 Win32E = WAIT_TIMEOUT; /* Can't wait */
3228 else if (code == CM_ERROR_SHARING_VIOLATION) {
3229 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3231 else if (code == CM_ERROR_LOCK_CONFLICT) {
3232 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3234 else if (code == CM_ERROR_PARTIALWRITE) {
3235 Win32E = ERROR_DISK_FULL; /* Disk full */
3237 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3238 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3240 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3241 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3243 else if (code == CM_ERROR_BADPASSWORD) {
3244 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3246 else if (code == CM_ERROR_BADLOGONTYPE) {
3247 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3249 else if (code == CM_ERROR_GSSCONTINUE) {
3250 Win32E = ERROR_MORE_DATA; /* more processing required */
3252 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3254 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3256 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3259 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3260 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3262 else if (code == CM_ERROR_ALLBUSY) {
3263 Win32E = ERROR_RETRY; /* Retry */
3265 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3266 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3268 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3269 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3271 else if (code == CM_ERROR_BAD_LEVEL) {
3272 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3274 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3275 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3277 else if (code == CM_ERROR_NOSUCHDEVICE) {
3278 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3280 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3281 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3283 else if (code == ENOMEM) {
3284 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3286 else if (code == CM_ERROR_RPC_MOREDATA) {
3287 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3290 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3294 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3297 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3298 unsigned char *classp)
3300 unsigned char class;
3301 unsigned short error;
3303 /* map CM_ERROR_* errors to SMB errors */
3304 if (code == CM_ERROR_NOSUCHCELL) {
3306 error = 3; /* bad path */
3308 else if (code == CM_ERROR_NOSUCHVOLUME) {
3310 error = 3; /* bad path */
3312 else if (code == CM_ERROR_TIMEDOUT) {
3314 error = 81; /* server is paused */
3316 else if (code == CM_ERROR_RETRY) {
3317 class = 2; /* shouldn't happen */
3320 else if (code == CM_ERROR_NOACCESS) {
3322 error = 4; /* bad access */
3324 else if (code == CM_ERROR_READONLY) {
3326 error = 19; /* read only */
3328 else if (code == CM_ERROR_NOSUCHFILE ||
3329 code == CM_ERROR_BPLUS_NOMATCH) {
3331 error = 2; /* ENOENT! */
3333 else if (code == CM_ERROR_NOSUCHPATH) {
3335 error = 3; /* Bad path */
3337 else if (code == CM_ERROR_TOOBIG) {
3339 error = 11; /* bad format */
3341 else if (code == CM_ERROR_INVAL) {
3342 class = 2; /* server non-specific error code */
3345 else if (code == CM_ERROR_BADFD) {
3347 error = 6; /* invalid file handle */
3349 else if (code == CM_ERROR_BADFDOP) {
3350 class = 1; /* invalid op on FD */
3353 else if (code == CM_ERROR_EXISTS) {
3355 error = 80; /* file already exists */
3357 else if (code == CM_ERROR_NOTEMPTY) {
3359 error = 5; /* delete directory not empty */
3361 else if (code == CM_ERROR_CROSSDEVLINK) {
3363 error = 17; /* EXDEV */
3365 else if (code == CM_ERROR_NOTDIR) {
3366 class = 1; /* bad path */
3369 else if (code == CM_ERROR_ISDIR) {
3370 class = 1; /* access denied; DOS doesn't have a good match */
3373 else if (code == CM_ERROR_BADOP) {
3377 else if (code == CM_ERROR_BADSHARENAME) {
3381 else if (code == CM_ERROR_NOIPC) {
3383 error = 4; /* bad access */
3385 else if (code == CM_ERROR_CLOCKSKEW) {
3386 class = 1; /* invalid function */
3389 else if (code == CM_ERROR_BADTID) {
3393 else if (code == CM_ERROR_USESTD) {
3397 else if (code == CM_ERROR_REMOTECONN) {
3401 else if (code == CM_ERROR_QUOTA) {
3402 if (vcp->flags & SMB_VCFLAG_USEV3) {
3404 error = 39; /* disk full */
3408 error = 5; /* access denied */
3411 else if (code == CM_ERROR_SPACE) {
3412 if (vcp->flags & SMB_VCFLAG_USEV3) {
3414 error = 39; /* disk full */
3418 error = 5; /* access denied */
3421 else if (code == CM_ERROR_PARTIALWRITE) {
3423 error = 39; /* disk full */
3425 else if (code == CM_ERROR_ATSYS) {
3427 error = 2; /* ENOENT */
3429 else if (code == CM_ERROR_WOULDBLOCK) {
3431 error = 33; /* lock conflict */
3433 else if (code == CM_ERROR_LOCK_CONFLICT) {
3435 error = 33; /* lock conflict */
3437 else if (code == CM_ERROR_SHARING_VIOLATION) {
3439 error = 33; /* lock conflict */
3441 else if (code == CM_ERROR_NOFILES) {
3443 error = 18; /* no files in search */
3445 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3447 error = 183; /* Samba uses this */
3449 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3450 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3452 error = 2; /* bad password */
3454 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3456 error = 3; /* bad path */
3465 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3468 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3470 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3471 return CM_ERROR_BADOP;
3475 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3477 unsigned short EchoCount, i;
3478 char *data, *outdata;
3481 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3483 for (i=1; i<=EchoCount; i++) {
3484 data = smb_GetSMBData(inp, &dataSize);
3485 smb_SetSMBParm(outp, 0, i);
3486 smb_SetSMBDataLength(outp, dataSize);
3487 outdata = smb_GetSMBData(outp, NULL);
3488 memcpy(outdata, data, dataSize);
3489 smb_SendPacket(vcp, outp);
3495 /* SMB_COM_READ_RAW */
3496 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3499 long count, minCount, finalCount;
3503 smb_t *smbp = (smb_t*) inp;
3505 cm_user_t *userp = NULL;
3508 char *rawBuf = NULL;
3513 fd = smb_GetSMBParm(inp, 0);
3514 count = smb_GetSMBParm(inp, 3);
3515 minCount = smb_GetSMBParm(inp, 4);
3516 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3518 if (*inp->wctp == 10) {
3519 /* we were sent a request with 64-bit file offsets */
3520 #ifdef AFS_LARGEFILES
3521 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3523 if (LargeIntegerLessThanZero(offset)) {
3524 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3528 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3529 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3532 offset.HighPart = 0;
3536 /* we were sent a request with 32-bit file offsets */
3537 offset.HighPart = 0;
3540 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3541 fd, offset.HighPart, offset.LowPart, count);
3543 fidp = smb_FindFID(vcp, fd, 0);
3547 lock_ObtainMutex(&fidp->mx);
3549 lock_ReleaseMutex(&fidp->mx);
3550 smb_ReleaseFID(fidp);
3551 return CM_ERROR_BADFD;
3554 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3555 lock_ReleaseMutex(&fidp->mx);
3556 smb_CloseFID(vcp, fidp, NULL, 0);
3557 code = CM_ERROR_NOSUCHFILE;
3563 LARGE_INTEGER LOffset, LLength;
3566 key = cm_GenerateKey(vcp->vcID, pid, fd);
3568 LOffset.HighPart = offset.HighPart;
3569 LOffset.LowPart = offset.LowPart;
3570 LLength.HighPart = 0;
3571 LLength.LowPart = count;
3573 lock_ObtainWrite(&fidp->scp->rw);
3574 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3575 lock_ReleaseWrite(&fidp->scp->rw);
3578 lock_ReleaseMutex(&fidp->mx);
3582 lock_ObtainMutex(&smb_RawBufLock);
3584 /* Get a raw buf, from head of list */
3585 rawBuf = smb_RawBufs;
3586 smb_RawBufs = *(char **)smb_RawBufs;
3588 lock_ReleaseMutex(&smb_RawBufLock);
3590 lock_ReleaseMutex(&fidp->mx);
3594 if (fidp->flags & SMB_FID_IOCTL)
3596 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3598 /* Give back raw buffer */
3599 lock_ObtainMutex(&smb_RawBufLock);
3600 *((char **) rawBuf) = smb_RawBufs;
3602 smb_RawBufs = rawBuf;
3603 lock_ReleaseMutex(&smb_RawBufLock);
3606 lock_ReleaseMutex(&fidp->mx);
3607 smb_ReleaseFID(fidp);
3610 lock_ReleaseMutex(&fidp->mx);
3612 userp = smb_GetUserFromVCP(vcp, inp);
3614 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3620 cm_ReleaseUser(userp);
3623 smb_ReleaseFID(fidp);
3627 memset((char *)ncbp, 0, sizeof(NCB));
3629 ncbp->ncb_length = (unsigned short) finalCount;
3630 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3631 ncbp->ncb_lana_num = vcp->lana;
3632 ncbp->ncb_command = NCBSEND;
3633 ncbp->ncb_buffer = rawBuf;
3635 code = Netbios(ncbp);
3637 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3640 /* Give back raw buffer */
3641 lock_ObtainMutex(&smb_RawBufLock);
3642 *((char **) rawBuf) = smb_RawBufs;
3644 smb_RawBufs = rawBuf;
3645 lock_ReleaseMutex(&smb_RawBufLock);
3651 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3653 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3658 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3660 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3665 /* SMB_COM_NEGOTIATE */
3666 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3673 int VistaProtoIndex;
3674 int protoIndex; /* index we're using */
3679 char protocol_array[10][1024]; /* protocol signature of the client */
3680 int caps; /* capabilities */
3683 TIME_ZONE_INFORMATION tzi;
3685 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3688 namep = smb_GetSMBData(inp, &dbytes);
3691 coreProtoIndex = -1; /* not found */
3694 VistaProtoIndex = -1;
3695 while(namex < dbytes) {
3696 osi_Log1(smb_logp, "Protocol %s",
3697 osi_LogSaveString(smb_logp, namep+1));
3698 strcpy(protocol_array[tcounter], namep+1);
3700 /* namep points at the first protocol, or really, a 0x02
3701 * byte preceding the null-terminated ASCII name.
3703 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3704 coreProtoIndex = tcounter;
3706 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3707 v3ProtoIndex = tcounter;
3709 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3710 NTProtoIndex = tcounter;
3712 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3713 VistaProtoIndex = tcounter;
3716 /* compute size of protocol entry */
3717 entryLength = (int)strlen(namep+1);
3718 entryLength += 2; /* 0x02 bytes and null termination */
3720 /* advance over this protocol entry */
3721 namex += entryLength;
3722 namep += entryLength;
3723 tcounter++; /* which proto entry we're looking at */
3726 lock_ObtainMutex(&vcp->mx);
3728 if (VistaProtoIndex != -1) {
3729 protoIndex = VistaProtoIndex;
3730 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3733 if (NTProtoIndex != -1) {
3734 protoIndex = NTProtoIndex;
3735 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3737 else if (v3ProtoIndex != -1) {
3738 protoIndex = v3ProtoIndex;
3739 vcp->flags |= SMB_VCFLAG_USEV3;
3741 else if (coreProtoIndex != -1) {
3742 protoIndex = coreProtoIndex;
3743 vcp->flags |= SMB_VCFLAG_USECORE;
3745 else protoIndex = -1;
3746 lock_ReleaseMutex(&vcp->mx);
3748 if (protoIndex == -1)
3749 return CM_ERROR_INVAL;
3750 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3751 smb_SetSMBParm(outp, 0, protoIndex);
3752 if (smb_authType != SMB_AUTH_NONE) {
3753 smb_SetSMBParmByte(outp, 1,
3754 NEGOTIATE_SECURITY_USER_LEVEL |
3755 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3757 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3759 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3760 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3761 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3762 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3763 /* The session key is not a well documented field however most clients
3764 * will echo back the session key to the server. Currently we are using
3765 * the same value for all sessions. We should generate a random value
3766 * and store it into the vcp
3768 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3769 smb_SetSMBParm(outp, 8, 1);
3771 * Tried changing the capabilities to support for W2K - defect 117695
3772 * Maybe something else needs to be changed here?
3776 smb_SetSMBParmLong(outp, 9, 0x43fd);
3778 smb_SetSMBParmLong(outp, 9, 0x251);
3781 * 32-bit error codes *
3787 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3789 NTNEGOTIATE_CAPABILITY_DFS |
3791 #ifdef AFS_LARGEFILES
3792 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3794 NTNEGOTIATE_CAPABILITY_NTFIND |
3795 NTNEGOTIATE_CAPABILITY_RAWMODE |
3796 NTNEGOTIATE_CAPABILITY_NTSMB;
3798 if ( smb_authType == SMB_AUTH_EXTENDED )
3799 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3802 if ( smb_UseUnicode ) {
3803 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3807 smb_SetSMBParmLong(outp, 9, caps);
3809 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3810 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3811 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3813 GetTimeZoneInformation(&tzi);
3814 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3816 if (smb_authType == SMB_AUTH_NTLM) {
3817 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3818 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3819 /* paste in encryption key */
3820 datap = smb_GetSMBData(outp, NULL);
3821 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3822 /* and the faux domain name */
3823 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3824 datap + MSV1_0_CHALLENGE_LENGTH,
3825 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3826 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3830 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3832 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3834 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3836 datap = smb_GetSMBData(outp, NULL);
3837 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3840 datap += sizeof(smb_ServerGUID);
3841 memcpy(datap, secBlob, secBlobLength);
3845 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3846 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3849 else if (v3ProtoIndex != -1) {
3850 smb_SetSMBParm(outp, 0, protoIndex);
3852 /* NOTE: Extended authentication cannot be negotiated with v3
3853 * therefore we fail over to NTLM
3855 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3856 smb_SetSMBParm(outp, 1,
3857 NEGOTIATE_SECURITY_USER_LEVEL |
3858 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3860 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3862 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3863 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3864 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3865 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3866 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3867 smb_SetSMBParm(outp, 7, 1);
3869 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3870 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3871 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3873 GetTimeZoneInformation(&tzi);
3874 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3876 /* NOTE: Extended authentication cannot be negotiated with v3
3877 * therefore we fail over to NTLM
3879 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3880 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3881 smb_SetSMBParm(outp, 12, 0); /* resvd */
3882 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3883 datap = smb_GetSMBData(outp, NULL);
3884 /* paste in a new encryption key */
3885 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3886 /* and the faux domain name */
3887 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3888 datap + MSV1_0_CHALLENGE_LENGTH,
3889 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3891 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3892 smb_SetSMBParm(outp, 12, 0); /* resvd */
3893 smb_SetSMBDataLength(outp, 0);
3896 else if (coreProtoIndex != -1) { /* not really supported anymore */
3897 smb_SetSMBParm(outp, 0, protoIndex);
3898 smb_SetSMBDataLength(outp, 0);
3903 void smb_CheckVCs(void)
3905 smb_vc_t * vcp, *nextp;
3906 smb_packet_t * outp = smb_GetPacket();
3909 lock_ObtainWrite(&smb_rctLock);
3910 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3912 if (vcp->magic != SMB_VC_MAGIC)
3913 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3914 __FILE__, __LINE__);
3916 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3918 smb_HoldVCNoLock(vcp);
3921 * obtain a reference to 'nextp' now because we drop the
3922 * smb_rctLock later and the list contents could change
3923 * or 'vcp' could be destroyed when released.
3927 smb_HoldVCNoLock(nextp);
3929 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3930 smb_ReleaseVCNoLock(vcp);
3934 smb_FormatResponsePacket(vcp, NULL, outp);
3935 smbp = (smb_t *)outp;
3936 outp->inCom = smbp->com = 0x2b /* Echo */;
3944 smb_SetSMBParm(outp, 0, 0);
3945 smb_SetSMBDataLength(outp, 0);
3946 lock_ReleaseWrite(&smb_rctLock);
3948 smb_SendPacket(vcp, outp);
3950 lock_ObtainWrite(&smb_rctLock);
3951 smb_ReleaseVCNoLock(vcp);
3953 lock_ReleaseWrite(&smb_rctLock);
3954 smb_FreePacket(outp);
3957 void smb_Daemon(void *parmp)
3959 afs_uint32 count = 0;
3960 smb_username_t **unpp;
3963 while(smbShutdownFlag == 0) {
3967 if (smbShutdownFlag == 1)
3970 if ((count % 72) == 0) { /* every five minutes */
3972 time_t old_localZero = smb_localZero;
3974 /* Initialize smb_localZero */
3975 myTime.tm_isdst = -1; /* compute whether on DST or not */
3976 myTime.tm_year = 70;
3982 smb_localZero = mktime(&myTime);
3984 #ifdef AFS_FREELANCE
3985 if ( smb_localZero != old_localZero )
3986 cm_noteLocalMountPointChange();
3992 /* GC smb_username_t objects that will no longer be used */
3994 lock_ObtainWrite(&smb_rctLock);
3995 for ( unpp=&usernamesp; *unpp; ) {
3997 smb_username_t *unp;
3999 lock_ObtainMutex(&(*unpp)->mx);
4000 if ( (*unpp)->refCount > 0 ||
4001 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4002 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4004 else if (!smb_LogoffTokenTransfer ||
4005 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4007 lock_ReleaseMutex(&(*unpp)->mx);
4015 lock_FinalizeMutex(&unp->mx);
4021 cm_ReleaseUser(userp);
4023 unpp = &(*unpp)->nextp;
4026 lock_ReleaseWrite(&smb_rctLock);
4028 /* XXX GC dir search entries */
4032 void smb_WaitingLocksDaemon()
4034 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4035 smb_waitingLock_t *wl, *wlNext;
4038 smb_packet_t *inp, *outp;
4042 while (smbShutdownFlag == 0) {
4043 lock_ObtainWrite(&smb_globalLock);
4044 nwlRequest = smb_allWaitingLocks;
4045 if (nwlRequest == NULL) {
4046 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4051 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4058 lock_ObtainWrite(&smb_globalLock);
4060 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4062 wlRequest = nwlRequest;
4063 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4064 lock_ReleaseWrite(&smb_globalLock);
4068 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4069 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4072 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4073 code = CM_ERROR_LOCK_NOT_GRANTED;
4077 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4079 /* wl->state is either _DONE or _WAITING. _ERROR
4080 would no longer be on the queue. */
4081 code = cm_RetryLock( wl->lockp,
4082 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4085 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4086 } else if (code != CM_ERROR_WOULDBLOCK) {
4087 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4092 if (code == CM_ERROR_WOULDBLOCK) {
4095 if (wlRequest->msTimeout != 0xffffffff
4096 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4108 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4111 scp = wlRequest->scp;
4112 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4116 lock_ObtainWrite(&scp->rw);
4118 for (wl = wlRequest->locks; wl; wl = wlNext) {
4119 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4121 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4122 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4123 wl->LLength, wl->key, 0, NULL, &req);
4125 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4130 lock_ReleaseWrite(&scp->rw);
4134 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4137 for (wl = wlRequest->locks; wl; wl = wlNext) {
4138 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4139 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4144 vcp = wlRequest->vcp;
4145 inp = wlRequest->inp;
4146 outp = wlRequest->outp;
4147 ncbp = smb_GetNCB();
4148 ncbp->ncb_length = inp->ncb_length;
4149 inp->spacep = cm_GetSpace();
4151 /* Remove waitingLock from list */
4152 lock_ObtainWrite(&smb_globalLock);
4153 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4155 lock_ReleaseWrite(&smb_globalLock);
4157 /* Resume packet processing */
4159 smb_SetSMBDataLength(outp, 0);
4160 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4161 outp->resumeCode = code;
4163 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4166 cm_FreeSpace(inp->spacep);
4167 smb_FreePacket(inp);
4168 smb_FreePacket(outp);
4170 cm_ReleaseSCache(wlRequest->scp);
4173 } while (nwlRequest && smbShutdownFlag == 0);
4178 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4180 osi_Log0(smb_logp, "SMB receive get disk attributes");
4182 smb_SetSMBParm(outp, 0, 32000);
4183 smb_SetSMBParm(outp, 1, 64);
4184 smb_SetSMBParm(outp, 2, 1024);
4185 smb_SetSMBParm(outp, 3, 30000);
4186 smb_SetSMBParm(outp, 4, 0);
4187 smb_SetSMBDataLength(outp, 0);
4191 /* SMB_COM_TREE_CONNECT */
4192 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4196 unsigned short newTid;
4197 clientchar_t shareName[AFSPATHMAX];
4198 clientchar_t *sharePath;
4201 clientchar_t *pathp;
4204 osi_Log0(smb_logp, "SMB receive tree connect");
4206 /* parse input parameters */
4209 tbp = smb_GetSMBData(inp, NULL);
4210 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4212 return CM_ERROR_BADSMB;
4214 tp = cm_ClientStrRChr(pathp, '\\');
4216 return CM_ERROR_BADSMB;
4217 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4219 lock_ObtainMutex(&vcp->mx);
4220 newTid = vcp->tidCounter++;
4221 lock_ReleaseMutex(&vcp->mx);
4223 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4224 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4226 return CM_ERROR_BADSMB;
4227 userp = smb_GetUserFromUID(uidp);
4228 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4229 smb_ReleaseUID(uidp);
4231 smb_ReleaseTID(tidp, FALSE);
4232 return CM_ERROR_BADSHARENAME;
4234 lock_ObtainMutex(&tidp->mx);
4235 tidp->userp = userp;
4236 tidp->pathname = sharePath;
4237 lock_ReleaseMutex(&tidp->mx);
4238 smb_ReleaseTID(tidp, FALSE);
4240 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4241 smb_SetSMBParm(rsp, 1, newTid);
4242 smb_SetSMBDataLength(rsp, 0);
4244 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4248 /* set maskp to the mask part of the incoming path.
4249 * Mask is 11 bytes long (8.3 with the dot elided).
4250 * Returns true if succeeds with a valid name, otherwise it does
4251 * its best, but returns false.
4253 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4261 /* starts off valid */
4264 /* mask starts out all blanks */
4265 memset(maskp, ' ', 11);
4268 /* find last backslash, or use whole thing if there is none */
4269 tp = cm_ClientStrRChr(pathp, '\\');
4273 tp++; /* skip slash */
4277 /* names starting with a dot are illegal */
4285 if (tc == '.' || tc == '"')
4293 /* if we get here, tp point after the dot */
4294 up = maskp+8; /* ext goes here */
4301 if (tc == '.' || tc == '"')
4304 /* copy extension if not too long */
4314 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4316 clientchar_t umask[11];
4324 /* XXX redo this, calling cm_MatchMask with a converted mask */
4326 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4330 /* otherwise, we have a valid 8.3 name; see if we have a match,
4331 * treating '?' as a wildcard in maskp (but not in the file name).
4333 tp1 = umask; /* real name, in mask format */
4334 tp2 = maskp; /* mask, in mask format */
4335 for(i=0; i<11; i++) {
4336 tc1 = *tp1++; /* clientchar_t from real name */
4337 tc2 = *tp2++; /* clientchar_t from mask */
4338 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4339 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4342 if (tc2 == '?' && tc1 != ' ')
4349 /* we got a match */
4353 clientchar_t *smb_FindMask(clientchar_t *pathp)
4357 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4360 return tp+1; /* skip the slash */
4362 return pathp; /* no slash, return the entire path */
4365 /* SMB_COM_SEARCH for a volume label
4367 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4368 dispatch function.) */
4369 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4371 clientchar_t *pathp;
4373 clientchar_t mask[12];
4374 unsigned char *statBlockp;
4375 unsigned char initStatBlock[21];
4378 osi_Log0(smb_logp, "SMB receive search volume");
4380 /* pull pathname and stat block out of request */
4381 tp = smb_GetSMBData(inp, NULL);
4382 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4383 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4385 return CM_ERROR_BADSMB;
4386 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4387 osi_assertx(statBlockp != NULL, "null statBlock");
4389 statBlockp = initStatBlock;
4393 /* for returning to caller */
4394 smb_Get8Dot3MaskFromPath(mask, pathp);
4396 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4397 tp = smb_GetSMBData(outp, NULL);
4399 *tp++ = 43; /* bytes in a dir entry */
4400 *tp++ = 0; /* high byte in counter */
4402 /* now marshall the dir entry, starting with the search status */
4403 *tp++ = statBlockp[0]; /* Reserved */
4404 memcpy(tp, mask, 11); tp += 11; /* FileName */
4406 /* now pass back server use info, with 1st byte non-zero */
4408 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4410 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4412 *tp++ = 0x8; /* attribute: volume */
4422 /* 4 byte file size */
4428 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4431 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4432 memset(tp, ' ', 13);
4435 /* set the length of the data part of the packet to 43 + 3, for the dir
4436 * entry plus the 5 and the length fields.
4438 smb_SetSMBDataLength(outp, 46);
4443 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4444 clientchar_t * tidPathp, clientchar_t * relPathp,
4445 cm_user_t *userp, cm_req_t *reqp)
4453 smb_dirListPatch_t *patchp;
4454 smb_dirListPatch_t *npatchp;
4455 clientchar_t path[AFSPATHMAX];
4457 afs_int32 mustFake = 0;
4459 code = cm_FindACLCache(dscp, userp, &rights);
4461 lock_ObtainWrite(&dscp->rw);
4462 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4463 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4464 lock_ReleaseWrite(&dscp->rw);
4465 if (code == CM_ERROR_NOACCESS) {
4473 if (!mustFake) { /* Bulk Stat */
4475 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4477 memset(bsp, 0, sizeof(cm_bulkStat_t));
4479 for (patchp = *dirPatchespp, count=0;
4481 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4482 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4486 if (lock_TryWrite(&tscp->rw)) {
4487 /* we have an entry that we can look at */
4488 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4489 /* we have a callback on it. Don't bother
4490 * fetching this stat entry, since we're happy
4491 * with the info we have.
4493 lock_ReleaseWrite(&tscp->rw);
4494 cm_ReleaseSCache(tscp);
4497 lock_ReleaseWrite(&tscp->rw);
4499 cm_ReleaseSCache(tscp);
4503 bsp->fids[i].Volume = patchp->fid.volume;
4504 bsp->fids[i].Vnode = patchp->fid.vnode;
4505 bsp->fids[i].Unique = patchp->fid.unique;
4507 if (bsp->counter == AFSCBMAX) {
4508 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4509 memset(bsp, 0, sizeof(cm_bulkStat_t));
4513 if (bsp->counter > 0)
4514 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4519 for (patchp = *dirPatchespp; patchp; patchp =
4520 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4522 dptr = patchp->dptr;
4524 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4525 relPathp ? relPathp : _C(""), patchp->dep->name);
4526 reqp->relPathp = path;
4527 reqp->tidPathp = tidPathp;
4529 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4530 reqp->relPathp = reqp->tidPathp = NULL;
4533 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4534 *dptr++ = SMB_ATTR_HIDDEN;
4537 lock_ObtainWrite(&scp->rw);
4538 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4539 lock_ReleaseWrite(&scp->rw);
4541 /* set the attribute */
4542 switch (scp->fileType) {
4543 case CM_SCACHETYPE_DIRECTORY:
4544 case CM_SCACHETYPE_MOUNTPOINT:
4545 case CM_SCACHETYPE_INVALID:
4546 attr = SMB_ATTR_DIRECTORY;
4548 case CM_SCACHETYPE_SYMLINK:
4549 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4550 attr = SMB_ATTR_DIRECTORY;
4552 attr = SMB_ATTR_NORMAL;
4555 /* if we get here we either have a normal file
4556 * or we have a file for which we have never
4557 * received status info. In this case, we can
4558 * check the even/odd value of the entry's vnode.
4559 * odd means it is to be treated as a directory
4560 * and even means it is to be treated as a file.
4562 if (mustFake && (scp->fid.vnode & 0x1))
4563 attr = SMB_ATTR_DIRECTORY;
4565 attr = SMB_ATTR_NORMAL;
4569 /* 1969-12-31 23:59:58 +00*/
4570 dosTime = 0xEBBFBF7D;
4573 shortTemp = (unsigned short) (dosTime & 0xffff);
4574 *((u_short *)dptr) = shortTemp;
4577 /* and copy out date */
4578 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4579 *((u_short *)dptr) = shortTemp;
4582 /* copy out file length */
4583 *((u_long *)dptr) = 0;
4586 lock_ConvertWToR(&scp->rw);
4587 attr = smb_Attributes(scp);
4588 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4589 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4590 attr |= SMB_ATTR_HIDDEN;
4594 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4597 shortTemp = (unsigned short) (dosTime & 0xffff);
4598 *((u_short *)dptr) = shortTemp;
4601 /* and copy out date */
4602 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4603 *((u_short *)dptr) = shortTemp;
4606 /* copy out file length */
4607 *((u_long *)dptr) = scp->length.LowPart;
4609 lock_ReleaseRead(&scp->rw);
4611 cm_ReleaseSCache(scp);
4614 /* now free the patches */
4615 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4616 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4620 /* and mark the list as empty */
4621 *dirPatchespp = NULL;
4627 /* SMB_COM_SEARCH */
4628 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4634 clientchar_t *pathp;
4635 cm_dirEntry_t *dep = 0;
4637 smb_dirListPatch_t *dirListPatchesp;
4638 smb_dirListPatch_t *curPatchp;
4642 osi_hyper_t dirLength;
4643 osi_hyper_t bufferOffset;
4644 osi_hyper_t curOffset;
4646 unsigned char *inCookiep;
4647 smb_dirSearch_t *dsp;
4651 unsigned long clientCookie;
4652 cm_pageHeader_t *pageHeaderp;
4653 cm_user_t *userp = NULL;
4655 clientchar_t mask[12];
4657 long nextEntryCookie;
4658 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4659 char resByte; /* reserved byte from the cookie */
4660 char *op; /* output data ptr */
4661 char *origOp; /* original value of op */
4662 cm_space_t *spacep; /* for pathname buffer */
4666 clientchar_t *tidPathp = 0;
4673 maxCount = smb_GetSMBParm(inp, 0);
4675 dirListPatchesp = NULL;
4677 caseFold = CM_FLAG_CASEFOLD;
4679 tp = smb_GetSMBData(inp, NULL);
4680 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4681 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4683 return CM_ERROR_BADSMB;
4685 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4687 return CM_ERROR_BADSMB;
4689 /* We can handle long names */
4690 if (vcp->flags & SMB_VCFLAG_USENT)
4691 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4693 /* make sure we got a whole search status */
4694 if (dataLength < 21) {
4695 nextCookie = 0; /* start at the beginning of the dir */
4698 attribute = smb_GetSMBParm(inp, 1);
4700 /* handle volume info in another function */
4701 if (attribute & 0x8)
4702 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4704 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4705 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4707 if (*pathp == 0) { /* null pathp, treat as root dir */
4708 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4709 return CM_ERROR_NOFILES;
4713 dsp = smb_NewDirSearch(0);
4714 dsp->attribute = attribute;
4715 smb_Get8Dot3MaskFromPath(mask, pathp);
4716 memcpy(dsp->mask, mask, 12);
4718 /* track if this is likely to match a lot of entries */
4719 if (smb_Is8Dot3StarMask(mask))
4724 /* pull the next cookie value out of the search status block */
4725 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4726 + (inCookiep[16]<<24);
4727 dsp = smb_FindDirSearch(inCookiep[12]);
4729 /* can't find dir search status; fatal error */
4730 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4731 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4732 return CM_ERROR_BADFD;
4734 attribute = dsp->attribute;
4735 resByte = inCookiep[0];
4737 /* copy out client cookie, in host byte order. Don't bother
4738 * interpreting it, since we're just passing it through, anyway.
4740 memcpy(&clientCookie, &inCookiep[17], 4);
4742 memcpy(mask, dsp->mask, 12);
4744 /* assume we're doing a star match if it has continued for more
4750 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4751 nextCookie, dsp->cookie, attribute);
4753 userp = smb_GetUserFromVCP(vcp, inp);
4755 /* try to get the vnode for the path name next */
4756 lock_ObtainMutex(&dsp->mx);
4759 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4763 spacep = inp->spacep;
4764 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4765 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4767 lock_ReleaseMutex(&dsp->mx);
4768 cm_ReleaseUser(userp);
4769 smb_DeleteDirSearch(dsp);
4770 smb_ReleaseDirSearch(dsp);
4771 return CM_ERROR_NOFILES;
4773 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4774 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4776 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4777 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4780 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4783 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4784 cm_ReleaseSCache(scp);
4785 lock_ReleaseMutex(&dsp->mx);
4786 cm_ReleaseUser(userp);
4787 smb_DeleteDirSearch(dsp);
4788 smb_ReleaseDirSearch(dsp);
4789 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4790 return CM_ERROR_PATH_NOT_COVERED;
4792 return CM_ERROR_NOSUCHPATH;
4794 #endif /* DFS_SUPPORT */
4797 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4798 /* we need one hold for the entry we just stored into,
4799 * and one for our own processing. When we're done with this
4800 * function, we'll drop the one for our own processing.
4801 * We held it once from the namei call, and so we do another hold
4805 lock_ObtainWrite(&scp->rw);
4806 dsp->flags |= SMB_DIRSEARCH_BULKST;
4807 lock_ReleaseWrite(&scp->rw);
4810 lock_ReleaseMutex(&dsp->mx);
4812 cm_ReleaseUser(userp);
4813 smb_DeleteDirSearch(dsp);
4814 smb_ReleaseDirSearch(dsp);
4818 /* reserves space for parameter; we'll adjust it again later to the
4819 * real count of the # of entries we returned once we've actually
4820 * assembled the directory listing.
4822 smb_SetSMBParm(outp, 0, 0);
4824 /* get the directory size */
4825 lock_ObtainWrite(&scp->rw);
4826 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4827 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4829 lock_ReleaseWrite(&scp->rw);
4830 cm_ReleaseSCache(scp);
4831 cm_ReleaseUser(userp);
4832 smb_DeleteDirSearch(dsp);
4833 smb_ReleaseDirSearch(dsp);
4837 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4839 dirLength = scp->length;
4841 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4842 curOffset.HighPart = 0;
4843 curOffset.LowPart = nextCookie;
4844 origOp = op = smb_GetSMBData(outp, NULL);
4845 /* and write out the basic header */
4846 *op++ = 5; /* variable block */
4847 op += 2; /* skip vbl block length; we'll fill it in later */
4851 clientchar_t *actualName = NULL;
4852 int free_actualName = 0;
4853 clientchar_t shortName[13];
4854 clientchar_t *shortNameEnd;
4856 /* make sure that curOffset.LowPart doesn't point to the first
4857 * 32 bytes in the 2nd through last dir page, and that it doesn't
4858 * point at the first 13 32-byte chunks in the first dir page,
4859 * since those are dir and page headers, and don't contain useful
4862 temp = curOffset.LowPart & (2048-1);
4863 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4864 /* we're in the first page */
4865 if (temp < 13*32) temp = 13*32;
4868 /* we're in a later dir page */
4869 if (temp < 32) temp = 32;
4872 /* make sure the low order 5 bits are zero */
4875 /* now put temp bits back ito curOffset.LowPart */
4876 curOffset.LowPart &= ~(2048-1);
4877 curOffset.LowPart |= temp;
4879 /* check if we've returned all the names that will fit in the
4882 if (returnedNames >= maxCount) {
4883 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4884 returnedNames, maxCount);
4888 /* check if we've passed the dir's EOF */
4889 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4891 /* see if we can use the bufferp we have now; compute in which page
4892 * the current offset would be, and check whether that's the offset
4893 * of the buffer we have. If not, get the buffer.
4895 thyper.HighPart = curOffset.HighPart;
4896 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4897 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4900 buf_Release(bufferp);
4903 lock_ReleaseWrite(&scp->rw);
4904 code = buf_Get(scp, &thyper, &req, &bufferp);
4905 lock_ObtainMutex(&dsp->mx);
4907 /* now, if we're doing a star match, do bulk fetching of all of
4908 * the status info for files in the dir.
4911 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4913 lock_ObtainWrite(&scp->rw);
4914 lock_ReleaseMutex(&dsp->mx);
4916 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4920 bufferOffset = thyper;
4922 /* now get the data in the cache */
4924 code = cm_SyncOp(scp, bufferp, userp, &req,
4926 CM_SCACHESYNC_NEEDCALLBACK |
4927 CM_SCACHESYNC_READ);
4929 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4933 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4935 if (cm_HaveBuffer(scp, bufferp, 0)) {
4936 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4940 /* otherwise, load the buffer and try again */
4941 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4943 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4944 scp, bufferp, code);
4949 buf_Release(bufferp);
4953 } /* if (wrong buffer) ... */
4955 /* now we have the buffer containing the entry we're interested in; copy
4956 * it out if it represents a non-deleted entry.
4958 entryInDir = curOffset.LowPart & (2048-1);
4959 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4961 /* page header will help tell us which entries are free. Page header
4962 * can change more often than once per buffer, since AFS 3 dir page size
4963 * may be less than (but not more than a buffer package buffer.
4965 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4966 temp &= ~(2048 - 1); /* turn off intra-page bits */
4967 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4969 /* now determine which entry we're looking at in the page. If it is
4970 * free (there's a free bitmap at the start of the dir), we should
4971 * skip these 32 bytes.
4973 slotInPage = (entryInDir & 0x7e0) >> 5;
4974 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4975 /* this entry is free */
4976 numDirChunks = 1; /* only skip this guy */
4980 tp = bufferp->datap + entryInBuffer;
4981 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4983 /* while we're here, compute the next entry's location, too,
4984 * since we'll need it when writing out the cookie into the dir
4987 * XXXX Probably should do more sanity checking.
4989 numDirChunks = cm_NameEntries(dep->name, NULL);
4991 /* compute the offset of the cookie representing the next entry */
4992 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4994 /* Compute 8.3 name if necessary */
4995 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4996 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4999 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5000 actualName = shortName;
5001 free_actualName = 0;
5003 free_actualName = 1;
5006 if (actualName == NULL) {
5007 /* Couldn't convert the name for some reason */
5008 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5009 osi_LogSaveString(smb_logp, dep->name));
5013 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5014 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5015 osi_LogSaveClientString(smb_logp, actualName));
5017 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5018 /* this is one of the entries to use: it is not deleted
5019 * and it matches the star pattern we're looking for.
5022 /* Eliminate entries that don't match requested
5025 /* no hidden files */
5026 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5027 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5031 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5033 /* We have already done the cm_TryBulkStat above */
5034 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5035 fileType = cm_FindFileType(&fid);
5036 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5037 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5039 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5040 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5041 fileType == CM_SCACHETYPE_DFSLINK ||
5042 fileType == CM_SCACHETYPE_INVALID)
5043 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5048 memcpy(op, mask, 11); op += 11;
5049 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5050 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5051 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5052 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5053 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5054 memcpy(op, &clientCookie, 4); op += 4;
5056 /* now we emit the attribute. This is sort of tricky,
5057 * since we need to really stat the file to find out
5058 * what type of entry we've got. Right now, we're
5059 * copying out data from a buffer, while holding the
5060 * scp locked, so it isn't really convenient to stat
5061 * something now. We'll put in a place holder now,
5062 * and make a second pass before returning this to get
5063 * the real attributes. So, we just skip the data for
5064 * now, and adjust it later. We allocate a patch
5065 * record to make it easy to find this point later.
5066 * The replay will happen at a time when it is safe to
5067 * unlock the directory.
5069 curPatchp = malloc(sizeof(*curPatchp));
5070 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5071 curPatchp->dptr = op;
5072 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5074 /* do hidden attribute here since name won't be around when applying
5078 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5079 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5081 curPatchp->flags = 0;
5083 op += 9; /* skip attr, time, date and size */
5085 /* zero out name area. The spec says to pad with
5086 * spaces, but Samba doesn't, and neither do we.
5090 /* finally, we get to copy out the name; we know that
5091 * it fits in 8.3 or the pattern wouldn't match, but it
5092 * never hurts to be sure.
5094 cm_ClientStringToUtf8(actualName, -1, op, 13);
5095 if (smb_StoreAnsiFilenames)
5097 /* This is a UCHAR field, which is ASCII even if Unicode
5100 /* Uppercase if requested by client */
5101 if (!KNOWS_LONG_NAMES(inp))
5106 /* now, adjust the # of entries copied */
5108 } /* if we're including this name */
5111 if (free_actualName && actualName) {
5116 /* and adjust curOffset to be where the new cookie is */
5117 thyper.HighPart = 0;
5118 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5119 curOffset = LargeIntegerAdd(thyper, curOffset);
5120 } /* while copying data for dir listing */
5122 /* release the mutex */
5123 lock_ReleaseWrite(&scp->rw);
5125 buf_Release(bufferp);
5129 /* apply and free last set of patches; if not doing a star match, this
5130 * will be empty, but better safe (and freeing everything) than sorry.
5132 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5134 /* special return code for unsuccessful search */
5135 if (code == 0 && dataLength < 21 && returnedNames == 0)
5136 code = CM_ERROR_NOFILES;
5138 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5139 returnedNames, code);
5142 smb_DeleteDirSearch(dsp);
5143 smb_ReleaseDirSearch(dsp);
5144 cm_ReleaseSCache(scp);
5145 cm_ReleaseUser(userp);
5149 /* finalize the output buffer */
5150 smb_SetSMBParm(outp, 0, returnedNames);
5151 temp = (long) (op - origOp);
5152 smb_SetSMBDataLength(outp, temp);
5154 /* the data area is a variable block, which has a 5 (already there)
5155 * followed by the length of the # of data bytes. We now know this to
5156 * be "temp," although that includes the 3 bytes of vbl block header.
5157 * Deduct for them and fill in the length field.
5159 temp -= 3; /* deduct vbl block info */
5160 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5161 origOp[1] = (unsigned char)(temp & 0xff);
5162 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5163 if (returnedNames == 0)
5164 smb_DeleteDirSearch(dsp);
5165 smb_ReleaseDirSearch(dsp);
5166 cm_ReleaseSCache(scp);
5167 cm_ReleaseUser(userp);
5172 /* verify that this is a valid path to a directory. I don't know why they
5173 * don't use the get file attributes call.
5175 * SMB_COM_CHECK_DIRECTORY
5177 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5179 clientchar_t *pathp;
5181 cm_scache_t *rootScp;
5182 cm_scache_t *newScp;
5186 clientchar_t *tidPathp;
5192 pdata = smb_GetSMBData(inp, NULL);
5193 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5195 return CM_ERROR_BADSMB;
5196 osi_Log1(smb_logp, "SMB receive check path %S",
5197 osi_LogSaveClientString(smb_logp, pathp));
5199 rootScp = cm_data.rootSCachep;
5201 userp = smb_GetUserFromVCP(vcp, inp);
5203 caseFold = CM_FLAG_CASEFOLD;
5205 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5207 cm_ReleaseUser(userp);
5208 return CM_ERROR_NOSUCHPATH;
5210 code = cm_NameI(rootScp, pathp,
5211 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5212 userp, tidPathp, &req, &newScp);
5215 cm_ReleaseUser(userp);
5220 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5221 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5222 cm_ReleaseSCache(newScp);
5223 cm_ReleaseUser(userp);
5224 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5225 return CM_ERROR_PATH_NOT_COVERED;
5227 return CM_ERROR_NOSUCHPATH;
5229 #endif /* DFS_SUPPORT */
5231 /* now lock the vnode with a callback; returns with newScp locked */
5232 lock_ObtainWrite(&newScp->rw);
5233 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5234 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5236 if (code != CM_ERROR_NOACCESS) {
5237 lock_ReleaseWrite(&newScp->rw);
5238 cm_ReleaseSCache(newScp);
5239 cm_ReleaseUser(userp);
5243 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5246 attrs = smb_Attributes(newScp);
5248 if (!(attrs & SMB_ATTR_DIRECTORY))
5249 code = CM_ERROR_NOTDIR;
5251 lock_ReleaseWrite(&newScp->rw);
5253 cm_ReleaseSCache(newScp);
5254 cm_ReleaseUser(userp);
5258 /* SMB_COM_SET_INFORMATION */
5259 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5261 clientchar_t *pathp;
5263 cm_scache_t *rootScp;
5264 unsigned short attribute;
5266 cm_scache_t *newScp;
5270 clientchar_t *tidPathp;
5276 /* decode basic attributes we're passed */
5277 attribute = smb_GetSMBParm(inp, 0);
5278 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5280 datap = smb_GetSMBData(inp, NULL);
5281 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5283 return CM_ERROR_BADSMB;
5285 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5286 dosTime, attribute);
5288 rootScp = cm_data.rootSCachep;
5290 userp = smb_GetUserFromVCP(vcp, inp);
5292 caseFold = CM_FLAG_CASEFOLD;
5294 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5296 cm_ReleaseUser(userp);
5297 return CM_ERROR_NOSUCHFILE;
5299 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5300 tidPathp, &req, &newScp);
5303 cm_ReleaseUser(userp);
5308 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5309 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5310 cm_ReleaseSCache(newScp);
5311 cm_ReleaseUser(userp);
5312 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5313 return CM_ERROR_PATH_NOT_COVERED;
5315 return CM_ERROR_NOSUCHPATH;
5317 #endif /* DFS_SUPPORT */
5319 /* now lock the vnode with a callback; returns with newScp locked; we
5320 * need the current status to determine what the new status is, in some
5323 lock_ObtainWrite(&newScp->rw);
5324 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5325 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5327 lock_ReleaseWrite(&newScp->rw);
5328 cm_ReleaseSCache(newScp);
5329 cm_ReleaseUser(userp);
5333 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5335 /* Check for RO volume */
5336 if (newScp->flags & CM_SCACHEFLAG_RO) {
5337 lock_ReleaseWrite(&newScp->rw);
5338 cm_ReleaseSCache(newScp);
5339 cm_ReleaseUser(userp);
5340 return CM_ERROR_READONLY;
5343 /* prepare for setattr call */
5346 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5347 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5349 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5350 /* we're told to make a writable file read-only */
5351 attr.unixModeBits = newScp->unixModeBits & ~0222;
5352 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5354 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5355 /* we're told to make a read-only file writable */
5356 attr.unixModeBits = newScp->unixModeBits | 0222;
5357 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5359 lock_ReleaseWrite(&newScp->rw);
5361 /* now call setattr */
5363 code = cm_SetAttr(newScp, &attr, userp, &req);
5367 cm_ReleaseSCache(newScp);
5368 cm_ReleaseUser(userp);
5374 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5376 clientchar_t *pathp;
5378 cm_scache_t *rootScp;
5379 cm_scache_t *newScp, *dscp;
5384 clientchar_t *tidPathp;
5386 clientchar_t *lastComp;
5392 datap = smb_GetSMBData(inp, NULL);
5393 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5395 return CM_ERROR_BADSMB;
5397 if (*pathp == 0) /* null path */
5400 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5401 osi_LogSaveClientString(smb_logp, pathp));
5403 rootScp = cm_data.rootSCachep;
5405 userp = smb_GetUserFromVCP(vcp, inp);
5407 /* we shouldn't need this for V3 requests, but we seem to */
5408 caseFold = CM_FLAG_CASEFOLD;
5410 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5412 cm_ReleaseUser(userp);
5413 return CM_ERROR_NOSUCHFILE;
5417 * XXX Strange hack XXX
5419 * As of Patch 5 (16 July 97), we are having the following problem:
5420 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5421 * requests to look up "desktop.ini" in all the subdirectories.
5422 * This can cause zillions of timeouts looking up non-existent cells
5423 * and volumes, especially in the top-level directory.
5425 * We have not found any way to avoid this or work around it except
5426 * to explicitly ignore the requests for mount points that haven't
5427 * yet been evaluated and for directories that haven't yet been
5430 * We should modify this hack to provide a fake desktop.ini file
5431 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5433 spacep = inp->spacep;
5434 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5435 #ifndef SPECIAL_FOLDERS
5436 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5437 code = cm_NameI(rootScp, spacep->wdata,
5438 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5439 userp, tidPathp, &req, &dscp);
5442 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5443 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5445 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5446 return CM_ERROR_PATH_NOT_COVERED;
5448 return CM_ERROR_NOSUCHPATH;
5450 #endif /* DFS_SUPPORT */
5451 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5452 code = CM_ERROR_NOSUCHFILE;
5453 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5454 cm_buf_t *bp = buf_Find(dscp, &hzero);
5459 code = CM_ERROR_NOSUCHFILE;
5461 cm_ReleaseSCache(dscp);
5463 cm_ReleaseUser(userp);
5468 #endif /* SPECIAL_FOLDERS */
5470 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5471 tidPathp, &req, &newScp);
5473 cm_ReleaseUser(userp);
5478 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5479 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5480 cm_ReleaseSCache(newScp);
5481 cm_ReleaseUser(userp);
5482 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5483 return CM_ERROR_PATH_NOT_COVERED;
5485 return CM_ERROR_NOSUCHPATH;
5487 #endif /* DFS_SUPPORT */
5489 /* now lock the vnode with a callback; returns with newScp locked */
5490 lock_ObtainWrite(&newScp->rw);
5491 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5492 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5494 lock_ReleaseWrite(&newScp->rw);
5495 cm_ReleaseSCache(newScp);
5496 cm_ReleaseUser(userp);
5500 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5502 attrs = smb_Attributes(newScp);
5504 smb_SetSMBParm(outp, 0, attrs);
5506 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5507 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5508 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5509 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5510 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5511 smb_SetSMBParm(outp, 5, 0);
5512 smb_SetSMBParm(outp, 6, 0);
5513 smb_SetSMBParm(outp, 7, 0);
5514 smb_SetSMBParm(outp, 8, 0);
5515 smb_SetSMBParm(outp, 9, 0);
5516 smb_SetSMBDataLength(outp, 0);
5517 lock_ReleaseWrite(&newScp->rw);
5519 cm_ReleaseSCache(newScp);
5520 cm_ReleaseUser(userp);
5525 /* SMB_COM_TREE_DISCONNECT */
5526 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5530 osi_Log0(smb_logp, "SMB receive tree disconnect");
5532 /* find the tree and free it */
5533 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5535 lock_ObtainWrite(&smb_rctLock);
5537 smb_ReleaseTID(tidp, TRUE);
5538 lock_ReleaseWrite(&smb_rctLock);
5545 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5548 clientchar_t *pathp;
5549 clientchar_t *lastNamep;
5558 clientchar_t *tidPathp;
5564 datap = smb_GetSMBData(inp, NULL);
5565 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5567 return CM_ERROR_BADSMB;
5569 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5571 #ifdef DEBUG_VERBOSE
5575 hexpath = osi_HexifyString( pathp );
5576 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5581 if (!cm_IsValidClientString(pathp)) {
5583 clientchar_t * hexp;
5585 hexp = cm_GetRawCharsAlloc(pathp, -1);
5586 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5587 osi_LogSaveClientString(smb_logp, hexp));
5591 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5593 return CM_ERROR_BADNTFILENAME;
5596 share = smb_GetSMBParm(inp, 0);
5597 attribute = smb_GetSMBParm(inp, 1);
5599 spacep = inp->spacep;
5600 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5601 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5602 /* special case magic file name for receiving IOCTL requests
5603 * (since IOCTL calls themselves aren't getting through).
5605 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5606 smb_SetupIoctlFid(fidp, spacep);
5607 smb_SetSMBParm(outp, 0, fidp->fid);
5608 smb_SetSMBParm(outp, 1, 0); /* attrs */
5609 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5610 smb_SetSMBParm(outp, 3, 0);
5611 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5612 smb_SetSMBParm(outp, 5, 0x7fff);
5613 /* pass the open mode back */
5614 smb_SetSMBParm(outp, 6, (share & 0xf));
5615 smb_SetSMBDataLength(outp, 0);
5616 smb_ReleaseFID(fidp);
5620 userp = smb_GetUserFromVCP(vcp, inp);
5622 caseFold = CM_FLAG_CASEFOLD;
5624 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5626 cm_ReleaseUser(userp);
5627 return CM_ERROR_NOSUCHPATH;
5629 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5630 tidPathp, &req, &scp);
5633 cm_ReleaseUser(userp);
5638 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5639 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5640 cm_ReleaseSCache(scp);
5641 cm_ReleaseUser(userp);
5642 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5643 return CM_ERROR_PATH_NOT_COVERED;
5645 return CM_ERROR_NOSUCHPATH;
5647 #endif /* DFS_SUPPORT */
5649 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5651 cm_ReleaseSCache(scp);
5652 cm_ReleaseUser(userp);
5656 /* don't need callback to check file type, since file types never
5657 * change, and namei and cm_Lookup all stat the object at least once on
5658 * a successful return.
5660 if (scp->fileType != CM_SCACHETYPE_FILE) {
5661 cm_ReleaseSCache(scp);
5662 cm_ReleaseUser(userp);
5663 return CM_ERROR_ISDIR;
5666 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5667 osi_assertx(fidp, "null smb_fid_t");
5669 lock_ObtainMutex(&fidp->mx);
5670 if ((share & 0xf) == 0)
5671 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5672 else if ((share & 0xf) == 1)
5673 fidp->flags |= SMB_FID_OPENWRITE;
5675 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5679 fidp->userp = userp;
5681 /* and a pointer to the vnode */
5683 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5684 lock_ObtainWrite(&scp->rw);
5685 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5687 smb_SetSMBParm(outp, 0, fidp->fid);
5688 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5689 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5690 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5691 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5692 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5693 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5694 /* pass the open mode back; XXXX add access checks */
5695 smb_SetSMBParm(outp, 6, (share & 0xf));
5696 smb_SetSMBDataLength(outp, 0);
5697 lock_ReleaseMutex(&fidp->mx);
5698 lock_ReleaseRead(&scp->rw);
5701 cm_Open(scp, 0, userp);
5703 /* send and free packet */
5704 smb_ReleaseFID(fidp);
5705 cm_ReleaseUser(userp);
5706 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5710 typedef struct smb_unlinkRock {
5715 clientchar_t *maskp; /* pointer to the star pattern */
5718 cm_dirEntryList_t * matches;
5721 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5724 smb_unlinkRock_t *rockp;
5727 normchar_t matchName[MAX_PATH];
5731 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5732 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5733 caseFold |= CM_FLAG_8DOT3;
5735 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5736 /* Can't convert name */
5737 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5738 osi_LogSaveString(smb_logp, dep->name));
5742 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5744 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5745 !cm_Is8Dot3(matchName)) {
5746 cm_Gen8Dot3Name(dep, matchName, NULL);
5747 /* 8.3 matches are always case insensitive */
5748 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5751 osi_Log1(smb_logp, "Found match %S",
5752 osi_LogSaveClientString(smb_logp, matchName));
5754 cm_DirEntryListAdd(dep->name, &rockp->matches);
5758 /* If we made a case sensitive exact match, we might as well quit now. */
5759 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5760 code = CM_ERROR_STOPNOW;
5769 /* SMB_COM_DELETE */
5770 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5774 clientchar_t *pathp;
5778 clientchar_t *lastNamep;
5779 smb_unlinkRock_t rock;
5783 clientchar_t *tidPathp;
5787 memset(&rock, 0, sizeof(rock));
5789 attribute = smb_GetSMBParm(inp, 0);
5791 tp = smb_GetSMBData(inp, NULL);
5792 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5794 return CM_ERROR_BADSMB;
5796 osi_Log1(smb_logp, "SMB receive unlink %S",
5797 osi_LogSaveClientString(smb_logp, pathp));
5799 spacep = inp->spacep;
5800 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5802 userp = smb_GetUserFromVCP(vcp, inp);
5804 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5806 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5808 cm_ReleaseUser(userp);
5809 return CM_ERROR_NOSUCHPATH;
5811 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5814 cm_ReleaseUser(userp);
5819 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5820 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5821 cm_ReleaseSCache(dscp);
5822 cm_ReleaseUser(userp);
5823 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5824 return CM_ERROR_PATH_NOT_COVERED;
5826 return CM_ERROR_NOSUCHPATH;
5828 #endif /* DFS_SUPPORT */
5830 /* otherwise, scp points to the parent directory. */
5837 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5839 code = CM_ERROR_NOSUCHFILE;
5842 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5845 thyper.HighPart = 0;
5850 rock.matches = NULL;
5852 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5853 * match. If that fails, we do a case insensitve match.
5855 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5856 !smb_IsStarMask(rock.maskp)) {
5857 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5860 thyper.HighPart = 0;
5861 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5866 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5868 if (code == CM_ERROR_STOPNOW)
5871 if (code == 0 && rock.matches) {
5872 cm_dirEntryList_t * entry;
5874 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5875 normchar_t normalizedName[MAX_PATH];
5877 /* Note: entry->name is a non-normalized name */
5879 osi_Log1(smb_logp, "Unlinking %s",
5880 osi_LogSaveString(smb_logp, entry->name));
5882 /* We assume this works because entry->name was
5883 successfully converted in smb_UnlinkProc() once. */
5884 cm_FsStringToNormString(entry->name, -1,
5885 normalizedName, lengthof(normalizedName));
5887 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5889 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5890 smb_NotifyChange(FILE_ACTION_REMOVED,
5891 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5892 dscp, normalizedName, NULL, TRUE);
5896 cm_DirEntryListFree(&rock.matches);
5900 cm_ReleaseUser(userp);
5903 cm_ReleaseSCache(dscp);
5908 if (code == 0 && !rock.any)
5909 code = CM_ERROR_NOSUCHFILE;
5913 typedef struct smb_renameRock {
5914 cm_scache_t *odscp; /* old dir */
5915 cm_scache_t *ndscp; /* new dir */
5916 cm_user_t *userp; /* user */
5917 cm_req_t *reqp; /* request struct */
5918 smb_vc_t *vcp; /* virtual circuit */
5919 normchar_t *maskp; /* pointer to star pattern of old file name */
5920 int flags; /* tilde, casefold, etc */
5921 clientchar_t *newNamep; /* ptr to the new file's name */
5922 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5923 clientchar_t clOldName[MAX_PATH]; /* client name */
5927 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5930 smb_renameRock_t *rockp;
5933 normchar_t matchName[MAX_PATH];
5935 rockp = (smb_renameRock_t *) vrockp;
5937 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5938 /* Can't convert string */
5939 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
5940 osi_LogSaveString(smb_logp, dep->name));
5944 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5945 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5946 caseFold |= CM_FLAG_8DOT3;
5948 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5950 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5951 !cm_Is8Dot3(matchName)) {
5952 cm_Gen8Dot3Name(dep, matchName, NULL);
5953 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5958 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5959 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5961 code = CM_ERROR_STOPNOW;
5971 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5974 cm_space_t *spacep = NULL;
5975 smb_renameRock_t rock;
5976 cm_scache_t *oldDscp = NULL;
5977 cm_scache_t *newDscp = NULL;
5978 cm_scache_t *tmpscp= NULL;
5979 cm_scache_t *tmpscp2 = NULL;
5980 clientchar_t *oldLastNamep;
5981 clientchar_t *newLastNamep;
5985 clientchar_t *tidPathp;
5989 userp = smb_GetUserFromVCP(vcp, inp);
5990 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5992 cm_ReleaseUser(userp);
5993 return CM_ERROR_NOSUCHPATH;
5997 memset(&rock, 0, sizeof(rock));
5999 spacep = inp->spacep;
6000 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6002 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6003 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6004 userp, tidPathp, &req, &oldDscp);
6006 cm_ReleaseUser(userp);
6011 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6012 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6013 cm_ReleaseSCache(oldDscp);
6014 cm_ReleaseUser(userp);
6015 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6016 return CM_ERROR_PATH_NOT_COVERED;
6018 return CM_ERROR_NOSUCHPATH;
6020 #endif /* DFS_SUPPORT */
6022 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6023 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6024 userp, tidPathp, &req, &newDscp);
6027 cm_ReleaseSCache(oldDscp);
6028 cm_ReleaseUser(userp);
6033 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6034 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6035 cm_ReleaseSCache(oldDscp);
6036 cm_ReleaseSCache(newDscp);
6037 cm_ReleaseUser(userp);
6038 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6039 return CM_ERROR_PATH_NOT_COVERED;
6041 return CM_ERROR_NOSUCHPATH;
6043 #endif /* DFS_SUPPORT */
6046 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6047 * next, get the component names, and lower case them.
6050 /* handle the old name first */
6052 oldLastNamep = oldPathp;
6056 /* and handle the new name, too */
6058 newLastNamep = newPathp;
6062 /* TODO: The old name could be a wildcard. The new name must not be */
6064 /* Check if the file already exists; if so return error */
6065 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6066 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6067 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6069 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6070 osi_LogSaveClientString(smb_logp, newLastNamep));
6072 /* Check if the old and the new names differ only in case. If so return
6073 * success, else return CM_ERROR_EXISTS
6075 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6077 /* This would be a success only if the old file is *as same as* the new file */
6078 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6080 if (tmpscp == tmpscp2)
6083 code = CM_ERROR_EXISTS;
6084 cm_ReleaseSCache(tmpscp2);
6087 code = CM_ERROR_NOSUCHFILE;
6090 /* file exist, do not rename, also fixes move */
6091 osi_Log0(smb_logp, "Can't rename. Target already exists");
6092 code = CM_ERROR_EXISTS;
6097 /* do the vnode call */
6098 rock.odscp = oldDscp;
6099 rock.ndscp = newDscp;
6103 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6105 code = CM_ERROR_NOSUCHFILE;
6108 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6109 rock.newNamep = newLastNamep;
6110 rock.fsOldName[0] = '\0';
6111 rock.clOldName[0] = '\0';
6114 /* Now search the directory for the pattern, and do the appropriate rename when found */
6115 thyper.LowPart = 0; /* search dir from here */
6116 thyper.HighPart = 0;
6118 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6119 if (code == 0 && !rock.any) {
6121 thyper.HighPart = 0;
6122 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6123 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6125 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6127 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6128 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6129 rock.ndscp, rock.newNamep, rock.userp,
6131 /* if the call worked, stop doing the search now, since we
6132 * really only want to rename one file.
6135 osi_Log0(smb_logp, "cm_Rename failure");
6136 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6137 } else if (code == 0) {
6138 code = CM_ERROR_NOSUCHFILE;
6141 /* Handle Change Notification */
6143 * Being lazy, not distinguishing between files and dirs in this
6144 * filter, since we'd have to do a lookup.
6147 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6148 if (oldDscp == newDscp) {
6149 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6150 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6151 filter, oldDscp, rock.clOldName,
6152 newLastNamep, TRUE);
6154 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6155 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6156 filter, oldDscp, rock.clOldName,
6158 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6159 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6160 filter, newDscp, newLastNamep,
6167 cm_ReleaseSCache(tmpscp);
6169 cm_ReleaseUser(userp);
6171 cm_ReleaseSCache(oldDscp);
6173 cm_ReleaseSCache(newDscp);
6181 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6184 cm_space_t *spacep = NULL;
6185 cm_scache_t *oldDscp = NULL;
6186 cm_scache_t *newDscp = NULL;
6187 cm_scache_t *tmpscp= NULL;
6188 cm_scache_t *tmpscp2 = NULL;
6189 cm_scache_t *sscp = NULL;
6190 clientchar_t *oldLastNamep;
6191 clientchar_t *newLastNamep;
6194 clientchar_t *tidPathp;
6198 userp = smb_GetUserFromVCP(vcp, inp);
6200 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6202 cm_ReleaseUser(userp);
6203 return CM_ERROR_NOSUCHPATH;
6208 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6210 spacep = inp->spacep;
6211 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6213 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6214 userp, tidPathp, &req, &oldDscp);
6216 cm_ReleaseUser(userp);
6221 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6222 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6223 cm_ReleaseSCache(oldDscp);
6224 cm_ReleaseUser(userp);
6225 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6226 return CM_ERROR_PATH_NOT_COVERED;
6228 return CM_ERROR_NOSUCHPATH;
6230 #endif /* DFS_SUPPORT */
6232 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6233 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6234 userp, tidPathp, &req, &newDscp);
6236 cm_ReleaseSCache(oldDscp);
6237 cm_ReleaseUser(userp);
6242 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6243 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6244 cm_ReleaseSCache(newDscp);
6245 cm_ReleaseSCache(oldDscp);
6246 cm_ReleaseUser(userp);
6247 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6248 return CM_ERROR_PATH_NOT_COVERED;
6250 return CM_ERROR_NOSUCHPATH;
6252 #endif /* DFS_SUPPORT */
6254 /* Now, although we did two lookups for the two directories (because the same
6255 * directory can be referenced through different paths), we only allow hard links
6256 * within the same directory. */
6257 if (oldDscp != newDscp) {
6258 cm_ReleaseSCache(oldDscp);
6259 cm_ReleaseSCache(newDscp);
6260 cm_ReleaseUser(userp);
6261 return CM_ERROR_CROSSDEVLINK;
6264 /* handle the old name first */
6266 oldLastNamep = oldPathp;
6270 /* and handle the new name, too */
6272 newLastNamep = newPathp;
6276 /* now lookup the old name */
6277 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6278 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6280 cm_ReleaseSCache(oldDscp);
6281 cm_ReleaseSCache(newDscp);
6282 cm_ReleaseUser(userp);
6286 /* Check if the file already exists; if so return error */
6287 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6288 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6289 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6291 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6292 osi_LogSaveClientString(smb_logp, newLastNamep));
6294 /* if the existing link is to the same file, then we return success */
6296 if(sscp == tmpscp) {
6299 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6300 code = CM_ERROR_EXISTS;
6305 cm_ReleaseSCache(tmpscp);
6306 cm_ReleaseSCache(sscp);
6307 cm_ReleaseSCache(newDscp);
6308 cm_ReleaseSCache(oldDscp);
6309 cm_ReleaseUser(userp);
6313 /* now create the hardlink */
6314 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6315 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6316 osi_Log1(smb_logp," Link returns 0x%x", code);
6318 /* Handle Change Notification */
6320 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6321 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6322 smb_NotifyChange(FILE_ACTION_ADDED,
6323 filter, newDscp, newLastNamep,
6328 cm_ReleaseSCache(tmpscp);
6329 cm_ReleaseUser(userp);
6330 cm_ReleaseSCache(sscp);
6331 cm_ReleaseSCache(oldDscp);
6332 cm_ReleaseSCache(newDscp);
6336 /* SMB_COM_RENAME */
6338 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6340 clientchar_t *oldPathp;
6341 clientchar_t *newPathp;
6345 tp = smb_GetSMBData(inp, NULL);
6346 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6348 return CM_ERROR_BADSMB;
6349 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6351 return CM_ERROR_BADSMB;
6353 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6354 osi_LogSaveClientString(smb_logp, oldPathp),
6355 osi_LogSaveClientString(smb_logp, newPathp));
6357 if (!cm_IsValidClientString(newPathp)) {
6359 clientchar_t * hexp;
6361 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6362 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6363 osi_LogSaveClientString(smb_logp, hexp));
6367 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6369 return CM_ERROR_BADNTFILENAME;
6372 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6374 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6380 typedef struct smb_rmdirRock {
6384 normchar_t *maskp; /* pointer to the star pattern */
6387 cm_dirEntryList_t * matches;
6390 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6393 smb_rmdirRock_t *rockp;
6395 normchar_t matchName[MAX_PATH];
6397 rockp = (smb_rmdirRock_t *) vrockp;
6399 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6400 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6401 osi_LogSaveString(smb_logp, dep->name));
6405 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6406 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6408 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6410 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6411 !cm_Is8Dot3(matchName)) {
6412 cm_Gen8Dot3Name(dep, matchName, NULL);
6413 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6418 cm_DirEntryListAdd(dep->name, &rockp->matches);
6425 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6428 clientchar_t *pathp;
6432 clientchar_t *lastNamep;
6433 smb_rmdirRock_t rock;
6437 clientchar_t *tidPathp;
6441 memset(&rock, 0, sizeof(rock));
6443 tp = smb_GetSMBData(inp, NULL);
6444 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6446 return CM_ERROR_BADSMB;
6448 spacep = inp->spacep;
6449 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6451 userp = smb_GetUserFromVCP(vcp, inp);
6453 caseFold = CM_FLAG_CASEFOLD;
6455 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6457 cm_ReleaseUser(userp);
6458 return CM_ERROR_NOSUCHPATH;
6460 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6461 userp, tidPathp, &req, &dscp);
6464 cm_ReleaseUser(userp);
6469 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6470 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6471 cm_ReleaseSCache(dscp);
6472 cm_ReleaseUser(userp);
6473 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6474 return CM_ERROR_PATH_NOT_COVERED;
6476 return CM_ERROR_NOSUCHPATH;
6478 #endif /* DFS_SUPPORT */
6480 /* otherwise, scp points to the parent directory. */
6487 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6489 code = CM_ERROR_NOSUCHFILE;
6492 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6495 thyper.HighPart = 0;
6499 rock.matches = NULL;
6501 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6502 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6503 if (code == 0 && !rock.any) {
6505 thyper.HighPart = 0;
6506 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6507 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6510 if (code == 0 && rock.matches) {
6511 cm_dirEntryList_t * entry;
6513 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6514 clientchar_t clientName[MAX_PATH];
6516 /* We assume this will succeed because smb_RmdirProc()
6517 successfully converted entry->name once above. */
6518 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6520 osi_Log1(smb_logp, "Removing directory %s",
6521 osi_LogSaveString(smb_logp, entry->name));
6523 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6525 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6526 smb_NotifyChange(FILE_ACTION_REMOVED,
6527 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6528 dscp, clientName, NULL, TRUE);
6534 cm_DirEntryListFree(&rock.matches);
6537 cm_ReleaseUser(userp);
6540 cm_ReleaseSCache(dscp);
6542 if (code == 0 && !rock.any)
6543 code = CM_ERROR_NOSUCHFILE;
6552 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6562 fid = smb_GetSMBParm(inp, 0);
6564 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6566 fid = smb_ChainFID(fid, inp);
6567 fidp = smb_FindFID(vcp, fid, 0);
6569 return CM_ERROR_BADFD;
6571 userp = smb_GetUserFromVCP(vcp, inp);
6573 lock_ObtainMutex(&fidp->mx);
6574 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6575 cm_ReleaseUser(userp);
6576 lock_ReleaseMutex(&fidp->mx);
6577 smb_ReleaseFID(fidp);
6578 return CM_ERROR_BADFD;
6581 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6582 lock_ReleaseMutex(&fidp->mx);
6583 cm_ReleaseUser(userp);
6584 smb_CloseFID(vcp, fidp, NULL, 0);
6585 smb_ReleaseFID(fidp);
6586 return CM_ERROR_NOSUCHFILE;
6589 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6590 cm_scache_t * scp = fidp->scp;
6592 lock_ReleaseMutex(&fidp->mx);
6593 code = cm_FSync(scp, userp, &req);
6594 cm_ReleaseSCache(scp);
6596 lock_ReleaseMutex(&fidp->mx);
6600 cm_ReleaseUser(userp);
6601 smb_ReleaseFID(fidp);
6605 struct smb_FullNameRock {
6608 clientchar_t *fullName;
6609 fschar_t *originalName;
6612 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6615 normchar_t matchName[MAX_PATH];
6616 struct smb_FullNameRock *vrockp;
6618 vrockp = (struct smb_FullNameRock *)rockp;
6620 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6621 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6622 osi_LogSaveString(smb_logp, dep->name));
6626 if (!cm_Is8Dot3(matchName)) {
6627 clientchar_t shortName[13];
6629 cm_Gen8Dot3Name(dep, shortName, NULL);
6631 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6632 vrockp->fullName = cm_ClientStrDup(matchName);
6633 vrockp->originalName = cm_FsStrDup(dep->name);
6634 return CM_ERROR_STOPNOW;
6637 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6638 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6639 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6640 vrockp->fullName = cm_ClientStrDup(matchName);
6641 vrockp->originalName = cm_FsStrDup(dep->name);
6642 return CM_ERROR_STOPNOW;
6647 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6648 clientchar_t **newPathp, fschar_t ** originalPathp,
6649 cm_user_t *userp, cm_req_t *reqp)
6651 struct smb_FullNameRock rock;
6654 memset(&rock, 0, sizeof(rock));
6658 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6659 if (code == CM_ERROR_STOPNOW) {
6660 *newPathp = rock.fullName;
6661 *originalPathp = rock.originalName;
6663 *newPathp = cm_ClientStrDup(pathp);
6664 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6668 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6669 afs_uint32 dosTime) {
6672 cm_scache_t *dscp = NULL;
6673 clientchar_t *pathp = NULL;
6674 cm_scache_t * scp = NULL;
6675 cm_scache_t *delscp = NULL;
6676 int nullcreator = 0;
6678 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6679 fidp, fidp->fid, scp, vcp);
6682 lock_ObtainMutex(&fidp->mx);
6683 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6685 lock_ReleaseMutex(&fidp->mx);
6686 osi_Log0(smb_logp, " No user specified. Not closing fid");
6687 return CM_ERROR_BADFD;
6690 userp = fidp->userp; /* no hold required since fidp is held
6691 throughout the function */
6692 lock_ReleaseMutex(&fidp->mx);
6697 lock_ObtainWrite(&smb_rctLock);
6698 if (fidp->deleteOk) {
6699 osi_Log0(smb_logp, " Fid already closed.");
6700 lock_ReleaseWrite(&smb_rctLock);
6701 return CM_ERROR_BADFD;
6704 lock_ReleaseWrite(&smb_rctLock);
6706 lock_ObtainMutex(&fidp->mx);
6707 if (fidp->NTopen_dscp) {
6708 dscp = fidp->NTopen_dscp;
6709 cm_HoldSCache(dscp);
6712 if (fidp->NTopen_pathp)
6713 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6720 /* Don't jump the gun on an async raw write */
6721 while (fidp->raw_writers) {
6722 lock_ReleaseMutex(&fidp->mx);
6723 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6724 lock_ObtainMutex(&fidp->mx);
6727 /* watch for ioctl closes, and read-only opens */
6729 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6730 == SMB_FID_OPENWRITE) {
6731 if (dosTime != 0 && dosTime != -1) {
6732 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6733 /* This fixes defect 10958 */
6734 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6735 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6737 if (smb_AsyncStore != 2) {
6738 lock_ReleaseMutex(&fidp->mx);
6739 code = cm_FSync(scp, userp, &req);
6740 lock_ObtainMutex(&fidp->mx);
6746 /* unlock any pending locks */
6747 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6748 scp->fileType == CM_SCACHETYPE_FILE) {
6752 lock_ReleaseMutex(&fidp->mx);
6754 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6756 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6757 lock_ObtainWrite(&scp->rw);
6759 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6760 CM_SCACHESYNC_NEEDCALLBACK
6761 | CM_SCACHESYNC_GETSTATUS
6762 | CM_SCACHESYNC_LOCK);
6766 "smb CoreClose SyncOp failure code 0x%x", tcode);
6767 goto post_syncopdone;
6770 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6772 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6776 lock_ReleaseWrite(&scp->rw);
6777 lock_ObtainMutex(&fidp->mx);
6780 if (fidp->flags & SMB_FID_DELONCLOSE) {
6781 clientchar_t *fullPathp = NULL;
6782 fschar_t *originalNamep = NULL;
6784 lock_ReleaseMutex(&fidp->mx);
6786 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6791 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6792 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6793 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6795 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6796 smb_NotifyChange(FILE_ACTION_REMOVED,
6797 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6798 dscp, fullPathp, NULL, TRUE);
6801 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6803 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6804 smb_NotifyChange(FILE_ACTION_REMOVED,
6805 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6806 dscp, fullPathp, NULL, TRUE);
6813 free(originalNamep);
6815 lock_ObtainMutex(&fidp->mx);
6816 fidp->flags &= ~SMB_FID_DELONCLOSE;
6819 /* if this was a newly created file, then clear the creator
6820 * in the stat cache entry. */
6821 if (fidp->flags & SMB_FID_CREATED) {
6823 fidp->flags &= ~SMB_FID_CREATED;
6826 if (fidp->flags & SMB_FID_NTOPEN) {
6827 cm_ReleaseSCache(fidp->NTopen_dscp);
6828 fidp->NTopen_dscp = NULL;
6829 free(fidp->NTopen_pathp);
6830 fidp->NTopen_pathp = NULL;
6831 fidp->flags &= ~SMB_FID_NTOPEN;
6833 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6834 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6837 if (fidp->NTopen_wholepathp) {
6838 free(fidp->NTopen_wholepathp);
6839 fidp->NTopen_wholepathp = NULL;
6843 cm_ReleaseSCache(fidp->scp);
6846 lock_ReleaseMutex(&fidp->mx);
6849 cm_ReleaseSCache(dscp);
6852 cm_ReleaseSCache(delscp);
6856 lock_ObtainWrite(&scp->rw);
6857 if (nullcreator && scp->creator == userp)
6858 scp->creator = NULL;
6859 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6860 lock_ReleaseWrite(&scp->rw);
6861 cm_ReleaseSCache(scp);
6871 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6879 fid = smb_GetSMBParm(inp, 0);
6880 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6882 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6884 fid = smb_ChainFID(fid, inp);
6885 fidp = smb_FindFID(vcp, fid, 0);
6887 return CM_ERROR_BADFD;
6890 userp = smb_GetUserFromVCP(vcp, inp);
6892 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6894 smb_ReleaseFID(fidp);
6895 cm_ReleaseUser(userp);
6900 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6902 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6903 cm_user_t *userp, long *readp)
6909 osi_hyper_t fileLength;
6911 osi_hyper_t lastByte;
6912 osi_hyper_t bufferOffset;
6916 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6919 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6920 fidp->fid, offsetp->LowPart, count);
6924 lock_ObtainMutex(&fidp->mx);
6925 /* make sure we have a readable FD */
6926 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6927 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6928 fidp->fid, fidp->flags);
6929 lock_ReleaseMutex(&fidp->mx);
6930 code = CM_ERROR_BADFDOP;
6935 lock_ReleaseMutex(&fidp->mx);
6936 code = CM_ERROR_BADFD;
6947 lock_ObtainWrite(&scp->rw);
6949 if (offset.HighPart == 0) {
6950 chunk = offset.LowPart >> cm_logChunkSize;
6951 if (chunk != fidp->curr_chunk) {
6952 fidp->prev_chunk = fidp->curr_chunk;
6953 fidp->curr_chunk = chunk;
6955 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6958 lock_ReleaseMutex(&fidp->mx);
6960 /* start by looking up the file's end */
6961 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6962 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6966 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6968 /* now we have the entry locked, look up the length */
6969 fileLength = scp->length;
6971 /* adjust count down so that it won't go past EOF */
6972 thyper.LowPart = count;
6973 thyper.HighPart = 0;
6974 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6976 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6977 /* we'd read past EOF, so just stop at fileLength bytes.
6978 * Start by computing how many bytes remain in the file.
6980 thyper = LargeIntegerSubtract(fileLength, offset);
6982 /* if we are past EOF, read 0 bytes */
6983 if (LargeIntegerLessThanZero(thyper))
6986 count = thyper.LowPart;
6991 /* now, copy the data one buffer at a time,
6992 * until we've filled the request packet
6995 /* if we've copied all the data requested, we're done */
6996 if (count <= 0) break;
6998 /* otherwise, load up a buffer of data */
6999 thyper.HighPart = offset.HighPart;
7000 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7001 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7004 buf_Release(bufferp);
7007 lock_ReleaseWrite(&scp->rw);
7009 code = buf_Get(scp, &thyper, &req, &bufferp);
7011 lock_ObtainWrite(&scp->rw);
7012 if (code) goto done;
7013 bufferOffset = thyper;
7015 /* now get the data in the cache */
7017 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7018 CM_SCACHESYNC_NEEDCALLBACK |
7019 CM_SCACHESYNC_READ);
7023 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7025 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7027 /* otherwise, load the buffer and try again */
7028 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7032 buf_Release(bufferp);
7036 } /* if (wrong buffer) ... */
7038 /* now we have the right buffer loaded. Copy out the
7039 * data from here to the user's buffer.
7041 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7043 /* and figure out how many bytes we want from this buffer */
7044 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7045 if (nbytes > count) nbytes = count; /* don't go past EOF */
7047 /* now copy the data */
7048 memcpy(op, bufferp->datap + bufIndex, nbytes);
7050 /* adjust counters, pointers, etc. */
7053 thyper.LowPart = nbytes;
7054 thyper.HighPart = 0;
7055 offset = LargeIntegerAdd(thyper, offset);
7059 lock_ReleaseWrite(&scp->rw);
7061 buf_Release(bufferp);
7063 if (code == 0 && sequential)
7064 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7066 cm_ReleaseSCache(scp);
7069 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7070 fidp->fid, code, *readp);
7075 * smb_WriteData -- common code for Write and Raw Write
7077 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7078 cm_user_t *userp, long *writtenp)
7080 osi_hyper_t offset = *offsetp;
7083 cm_scache_t *scp = NULL;
7084 osi_hyper_t fileLength; /* file's length at start of write */
7085 osi_hyper_t minLength; /* don't read past this */
7086 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7087 cm_buf_t *bufferp = NULL;
7088 osi_hyper_t thyper; /* hyper tmp variable */
7089 osi_hyper_t bufferOffset;
7090 afs_uint32 bufIndex; /* index in buffer where our data is */
7091 int doWriteBack = 0;
7092 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7096 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7097 fidp->fid, offsetp->LowPart, count);
7101 lock_ObtainMutex(&fidp->mx);
7102 /* make sure we have a writable FD */
7103 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7104 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7105 fidp->fid, fidp->flags);
7106 lock_ReleaseMutex(&fidp->mx);
7107 code = CM_ERROR_BADFDOP;
7115 lock_ReleaseMutex(&fidp->mx);
7117 lock_ObtainWrite(&scp->rw);
7118 /* start by looking up the file's end */
7119 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7120 CM_SCACHESYNC_NEEDCALLBACK
7121 | CM_SCACHESYNC_SETSTATUS
7122 | CM_SCACHESYNC_GETSTATUS);
7126 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7128 /* now we have the entry locked, look up the length */
7129 fileLength = scp->length;
7130 minLength = fileLength;
7131 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7132 minLength = scp->serverLength;
7134 /* adjust file length if we extend past EOF */
7135 thyper.LowPart = count;
7136 thyper.HighPart = 0;
7137 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7138 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7139 /* we'd write past EOF, so extend the file */
7140 scp->mask |= CM_SCACHEMASK_LENGTH;
7141 scp->length = thyper;
7142 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7144 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7146 /* now, if the new position (thyper) and the old (offset) are in
7147 * different storeback windows, remember to store back the previous
7148 * storeback window when we're done with the write.
7150 * the purpose of this logic is to slow down the CIFS client
7151 * in order to avoid the client disconnecting during the CLOSE
7152 * operation if there are too many dirty buffers left to write
7153 * than can be accomplished during 45 seconds. This used to be
7154 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7155 * so that we can read larger amounts of data at a time.
7157 if (smb_AsyncStore == 1 &&
7158 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7159 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7160 /* they're different */
7162 writeBackOffset.HighPart = offset.HighPart;
7163 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7168 /* now, copy the data one buffer at a time, until we've filled the
7171 /* if we've copied all the data requested, we're done */
7175 /* handle over quota or out of space */
7176 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7177 *writtenp = written;
7178 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7182 /* otherwise, load up a buffer of data */
7183 thyper.HighPart = offset.HighPart;
7184 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7185 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7188 lock_ReleaseMutex(&bufferp->mx);
7189 buf_Release(bufferp);
7192 lock_ReleaseWrite(&scp->rw);
7194 code = buf_Get(scp, &thyper, &req, &bufferp);
7196 lock_ObtainMutex(&bufferp->mx);
7197 lock_ObtainWrite(&scp->rw);
7198 if (code) goto done;
7200 bufferOffset = thyper;
7202 /* now get the data in the cache */
7204 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7205 CM_SCACHESYNC_NEEDCALLBACK
7206 | CM_SCACHESYNC_WRITE
7207 | CM_SCACHESYNC_BUFLOCKED);
7211 cm_SyncOpDone(scp, bufferp,
7212 CM_SCACHESYNC_NEEDCALLBACK
7213 | CM_SCACHESYNC_WRITE
7214 | CM_SCACHESYNC_BUFLOCKED);
7216 /* If we're overwriting the entire buffer, or
7217 * if we're writing at or past EOF, mark the
7218 * buffer as current so we don't call
7219 * cm_GetBuffer. This skips the fetch from the
7220 * server in those cases where we're going to
7221 * obliterate all the data in the buffer anyway,
7222 * or in those cases where there is no useful
7223 * data at the server to start with.
7225 * Use minLength instead of scp->length, since
7226 * the latter has already been updated by this
7229 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7230 || LargeIntegerEqualTo(offset, bufferp->offset)
7231 && (count >= cm_data.buf_blockSize
7232 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7233 ConvertLongToLargeInteger(count)),
7235 if (count < cm_data.buf_blockSize
7236 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7237 memset(bufferp->datap, 0,
7238 cm_data.buf_blockSize);
7239 bufferp->dataVersion = scp->dataVersion;
7242 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7244 /* otherwise, load the buffer and try again */
7245 lock_ReleaseMutex(&bufferp->mx);
7246 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7248 lock_ReleaseWrite(&scp->rw);
7249 lock_ObtainMutex(&bufferp->mx);
7250 lock_ObtainWrite(&scp->rw);
7254 lock_ReleaseMutex(&bufferp->mx);
7255 buf_Release(bufferp);
7259 } /* if (wrong buffer) ... */
7261 /* now we have the right buffer loaded. Copy out the
7262 * data from here to the user's buffer.
7264 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7266 /* and figure out how many bytes we want from this buffer */
7267 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7269 nbytes = count; /* don't go past end of request */
7271 /* now copy the data */
7272 memcpy(bufferp->datap + bufIndex, op, nbytes);
7273 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7275 /* adjust counters, pointers, etc. */
7279 thyper.LowPart = nbytes;
7280 thyper.HighPart = 0;
7281 offset = LargeIntegerAdd(thyper, offset);
7285 lock_ReleaseWrite(&scp->rw);
7288 lock_ReleaseMutex(&bufferp->mx);
7289 buf_Release(bufferp);
7292 lock_ObtainMutex(&fidp->mx);
7293 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7294 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7296 lock_ReleaseMutex(&fidp->mx);
7297 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7298 fidp->NTopen_dscp, fidp->NTopen_pathp,
7301 lock_ReleaseMutex(&fidp->mx);
7305 if (smb_AsyncStore > 0) {
7309 lock_ObtainWrite(&scp->rw);
7310 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7312 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7313 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7315 lock_ReleaseWrite(&scp->rw);
7316 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7317 writeBackOffset.HighPart,
7318 smb_AsyncStoreSize, 0, userp);
7319 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7322 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7326 cm_ReleaseSCache(scp);
7329 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7330 fidp->fid, code, *writtenp);
7335 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7338 unsigned short count;
7340 unsigned short hint;
7341 long written = 0, total_written = 0;
7344 smb_t* smbp = (smb_t*) inp;
7348 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7350 int inDataBlockCount;
7352 fd = smb_GetSMBParm(inp, 0);
7353 count = smb_GetSMBParm(inp, 1);
7354 offset.HighPart = 0; /* too bad */
7355 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7356 hint = smb_GetSMBParm(inp, 4);
7358 op = smb_GetSMBData(inp, NULL);
7359 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7361 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7362 fd, offset.LowPart, count);
7364 fd = smb_ChainFID(fd, inp);
7365 fidp = smb_FindFID(vcp, fd, 0);
7367 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7368 return CM_ERROR_BADFD;
7371 lock_ObtainMutex(&fidp->mx);
7372 if (fidp->flags & SMB_FID_IOCTL) {
7373 lock_ReleaseMutex(&fidp->mx);
7374 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7375 smb_ReleaseFID(fidp);
7376 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7380 if (fidp->flags & SMB_FID_RPC) {
7381 lock_ReleaseMutex(&fidp->mx);
7382 code = smb_RPCWrite(fidp, vcp, inp, outp);
7383 smb_ReleaseFID(fidp);
7384 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7389 lock_ReleaseMutex(&fidp->mx);
7390 smb_ReleaseFID(fidp);
7391 return CM_ERROR_BADFD;
7394 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7395 lock_ReleaseMutex(&fidp->mx);
7396 smb_CloseFID(vcp, fidp, NULL, 0);
7397 smb_ReleaseFID(fidp);
7398 return CM_ERROR_NOSUCHFILE;
7403 lock_ReleaseMutex(&fidp->mx);
7404 userp = smb_GetUserFromVCP(vcp, inp);
7408 LARGE_INTEGER LOffset;
7409 LARGE_INTEGER LLength;
7412 key = cm_GenerateKey(vcp->vcID, pid, fd);
7414 LOffset.HighPart = offset.HighPart;
7415 LOffset.LowPart = offset.LowPart;
7416 LLength.HighPart = 0;
7417 LLength.LowPart = count;
7419 lock_ObtainWrite(&scp->rw);
7420 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7421 lock_ReleaseWrite(&scp->rw);
7424 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7429 /* special case: 0 bytes transferred means truncate to this position */
7433 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7437 truncAttr.mask = CM_ATTRMASK_LENGTH;
7438 truncAttr.length.LowPart = offset.LowPart;
7439 truncAttr.length.HighPart = 0;
7440 lock_ObtainMutex(&fidp->mx);
7441 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7442 fidp->flags |= SMB_FID_LENGTHSETDONE;
7443 lock_ReleaseMutex(&fidp->mx);
7444 smb_SetSMBParm(outp, 0, 0 /* count */);
7445 smb_SetSMBDataLength(outp, 0);
7450 * Work around bug in NT client
7452 * When copying a file, the NT client should first copy the data,
7453 * then copy the last write time. But sometimes the NT client does
7454 * these in the wrong order, so the data copies would inadvertently
7455 * cause the last write time to be overwritten. We try to detect this,
7456 * and don't set client mod time if we think that would go against the
7459 lock_ObtainMutex(&fidp->mx);
7460 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7461 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7462 fidp->scp->clientModTime = time(NULL);
7464 lock_ReleaseMutex(&fidp->mx);
7467 while ( code == 0 && count > 0 ) {
7468 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7469 if (code == 0 && written == 0)
7470 code = CM_ERROR_PARTIALWRITE;
7472 offset = LargeIntegerAdd(offset,
7473 ConvertLongToLargeInteger(written));
7474 count -= (unsigned short)written;
7475 total_written += written;
7479 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7480 total_written, code);
7482 /* set the packet data length to 3 bytes for the data block header,
7483 * plus the size of the data.
7485 smb_SetSMBParm(outp, 0, total_written);
7486 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7487 smb_SetSMBParm(outp, 3, hint);
7488 smb_SetSMBDataLength(outp, 0);
7491 smb_ReleaseFID(fidp);
7492 cm_ReleaseUser(userp);
7493 cm_ReleaseSCache(scp);
7498 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7499 NCB *ncbp, raw_write_cont_t *rwcp)
7508 fd = smb_GetSMBParm(inp, 0);
7509 fidp = smb_FindFID(vcp, fd, 0);
7511 lock_ObtainMutex(&fidp->mx);
7513 lock_ReleaseMutex(&fidp->mx);
7514 smb_ReleaseFID(fidp);
7518 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7519 lock_ReleaseMutex(&fidp->mx);
7520 smb_CloseFID(vcp, fidp, NULL, 0);
7521 smb_ReleaseFID(fidp);
7524 lock_ReleaseMutex(&fidp->mx);
7526 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7527 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7529 userp = smb_GetUserFromVCP(vcp, inp);
7532 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7534 if (rwcp->writeMode & 0x1) { /* synchronous */
7537 smb_FormatResponsePacket(vcp, inp, outp);
7538 op = (smb_t *) outp;
7539 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7540 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7541 smb_SetSMBDataLength(outp, 0);
7542 smb_SendPacket(vcp, outp);
7543 smb_FreePacket(outp);
7545 else { /* asynchronous */
7546 lock_ObtainMutex(&fidp->mx);
7547 fidp->raw_writers--;
7548 if (fidp->raw_writers == 0)
7549 thrd_SetEvent(fidp->raw_write_event);
7550 lock_ReleaseMutex(&fidp->mx);
7553 /* Give back raw buffer */
7554 lock_ObtainMutex(&smb_RawBufLock);
7555 *((char **)rawBuf) = smb_RawBufs;
7556 smb_RawBufs = rawBuf;
7557 lock_ReleaseMutex(&smb_RawBufLock);
7559 smb_ReleaseFID(fidp);
7560 cm_ReleaseUser(userp);
7563 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7568 /* SMB_COM_WRITE_RAW */
7569 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7572 long count, written = 0, total_written = 0;
7576 smb_t *smbp = (smb_t*) inp;
7581 unsigned short writeMode;
7583 fd = smb_GetSMBParm(inp, 0);
7584 totalCount = smb_GetSMBParm(inp, 1);
7585 count = smb_GetSMBParm(inp, 10);
7586 writeMode = smb_GetSMBParm(inp, 7);
7588 op = (char *) inp->data;
7589 op += smb_GetSMBParm(inp, 11);
7591 offset.HighPart = 0;
7592 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7594 if (*inp->wctp == 14) {
7595 /* we received a 64-bit file offset */
7596 #ifdef AFS_LARGEFILES
7597 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7599 if (LargeIntegerLessThanZero(offset)) {
7601 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7602 offset.HighPart, offset.LowPart);
7603 return CM_ERROR_BADSMB;
7606 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7608 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7609 return CM_ERROR_BADSMB;
7612 offset.HighPart = 0;
7615 offset.HighPart = 0; /* 32-bit file offset */
7619 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7620 fd, offset.HighPart, offset.LowPart, count);
7622 " WriteRaw WriteMode 0x%x",
7625 fd = smb_ChainFID(fd, inp);
7626 fidp = smb_FindFID(vcp, fd, 0);
7628 return CM_ERROR_BADFD;
7630 lock_ObtainMutex(&fidp->mx);
7632 lock_ReleaseMutex(&fidp->mx);
7633 smb_ReleaseFID(fidp);
7634 return CM_ERROR_BADFD;
7637 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7638 lock_ReleaseMutex(&fidp->mx);
7639 smb_CloseFID(vcp, fidp, NULL, 0);
7640 smb_ReleaseFID(fidp);
7641 return CM_ERROR_NOSUCHFILE;
7646 lock_ReleaseMutex(&fidp->mx);
7651 LARGE_INTEGER LOffset;
7652 LARGE_INTEGER LLength;
7655 key = cm_GenerateKey(vcp->vcID, pid, fd);
7657 LOffset.HighPart = offset.HighPart;
7658 LOffset.LowPart = offset.LowPart;
7659 LLength.HighPart = 0;
7660 LLength.LowPart = count;
7662 lock_ObtainWrite(&scp->rw);
7663 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7664 lock_ReleaseWrite(&scp->rw);
7667 cm_ReleaseSCache(scp);
7668 smb_ReleaseFID(fidp);
7673 userp = smb_GetUserFromVCP(vcp, inp);
7676 * Work around bug in NT client
7678 * When copying a file, the NT client should first copy the data,
7679 * then copy the last write time. But sometimes the NT client does
7680 * these in the wrong order, so the data copies would inadvertently
7681 * cause the last write time to be overwritten. We try to detect this,
7682 * and don't set client mod time if we think that would go against the
7685 lock_ObtainMutex(&fidp->mx);
7686 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7687 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7688 fidp->scp->clientModTime = time(NULL);
7690 lock_ReleaseMutex(&fidp->mx);
7693 while ( code == 0 && count > 0 ) {
7694 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7695 if (code == 0 && written == 0)
7696 code = CM_ERROR_PARTIALWRITE;
7698 offset = LargeIntegerAdd(offset,
7699 ConvertLongToLargeInteger(written));
7702 total_written += written;
7706 /* Get a raw buffer */
7709 lock_ObtainMutex(&smb_RawBufLock);
7711 /* Get a raw buf, from head of list */
7712 rawBuf = smb_RawBufs;
7713 smb_RawBufs = *(char **)smb_RawBufs;
7716 code = CM_ERROR_USESTD;
7718 lock_ReleaseMutex(&smb_RawBufLock);
7721 /* Don't allow a premature Close */
7722 if (code == 0 && (writeMode & 1) == 0) {
7723 lock_ObtainMutex(&fidp->mx);
7724 fidp->raw_writers++;
7725 thrd_ResetEvent(fidp->raw_write_event);
7726 lock_ReleaseMutex(&fidp->mx);
7729 smb_ReleaseFID(fidp);
7730 cm_ReleaseUser(userp);
7731 cm_ReleaseSCache(scp);
7734 smb_SetSMBParm(outp, 0, total_written);
7735 smb_SetSMBDataLength(outp, 0);
7736 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7741 offset = LargeIntegerAdd(offset,
7742 ConvertLongToLargeInteger(count));
7746 rwcp->offset.HighPart = offset.HighPart;
7747 rwcp->offset.LowPart = offset.LowPart;
7748 rwcp->count = totalCount - count;
7749 rwcp->writeMode = writeMode;
7750 rwcp->alreadyWritten = total_written;
7752 /* set the packet data length to 3 bytes for the data block header,
7753 * plus the size of the data.
7755 smb_SetSMBParm(outp, 0, 0xffff);
7756 smb_SetSMBDataLength(outp, 0);
7762 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7765 long count, finalCount;
7769 smb_t *smbp = (smb_t*) inp;
7775 fd = smb_GetSMBParm(inp, 0);
7776 count = smb_GetSMBParm(inp, 1);
7777 offset.HighPart = 0; /* too bad */
7778 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7780 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7781 fd, offset.LowPart, count);
7783 fd = smb_ChainFID(fd, inp);
7784 fidp = smb_FindFID(vcp, fd, 0);
7786 return CM_ERROR_BADFD;
7788 lock_ObtainMutex(&fidp->mx);
7789 if (fidp->flags & SMB_FID_IOCTL) {
7790 lock_ReleaseMutex(&fidp->mx);
7791 code = smb_IoctlRead(fidp, vcp, inp, outp);
7792 smb_ReleaseFID(fidp);
7796 if (fidp->flags & SMB_FID_RPC) {
7797 lock_ReleaseMutex(&fidp->mx);
7798 code = smb_RPCRead(fidp, vcp, inp, outp);
7799 smb_ReleaseFID(fidp);
7804 lock_ReleaseMutex(&fidp->mx);
7805 smb_ReleaseFID(fidp);
7806 return CM_ERROR_BADFD;
7809 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7810 lock_ReleaseMutex(&fidp->mx);
7811 smb_CloseFID(vcp, fidp, NULL, 0);
7812 smb_ReleaseFID(fidp);
7813 return CM_ERROR_NOSUCHFILE;
7818 lock_ReleaseMutex(&fidp->mx);
7821 LARGE_INTEGER LOffset, LLength;
7825 key = cm_GenerateKey(vcp->vcID, pid, fd);
7827 LOffset.HighPart = 0;
7828 LOffset.LowPart = offset.LowPart;
7829 LLength.HighPart = 0;
7830 LLength.LowPart = count;
7832 lock_ObtainWrite(&scp->rw);
7833 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7834 lock_ReleaseWrite(&scp->rw);
7837 cm_ReleaseSCache(scp);
7838 smb_ReleaseFID(fidp);
7842 userp = smb_GetUserFromVCP(vcp, inp);
7844 /* remember this for final results */
7845 smb_SetSMBParm(outp, 0, count);
7846 smb_SetSMBParm(outp, 1, 0);
7847 smb_SetSMBParm(outp, 2, 0);
7848 smb_SetSMBParm(outp, 3, 0);
7849 smb_SetSMBParm(outp, 4, 0);
7851 /* set the packet data length to 3 bytes for the data block header,
7852 * plus the size of the data.
7854 smb_SetSMBDataLength(outp, count+3);
7856 /* get op ptr after putting in the parms, since otherwise we don't
7857 * know where the data really is.
7859 op = smb_GetSMBData(outp, NULL);
7861 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7862 *op++ = 1; /* data block marker */
7863 *op++ = (unsigned char) (count & 0xff);
7864 *op++ = (unsigned char) ((count >> 8) & 0xff);
7866 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7868 /* fix some things up */
7869 smb_SetSMBParm(outp, 0, finalCount);
7870 smb_SetSMBDataLength(outp, finalCount+3);
7872 smb_ReleaseFID(fidp);
7874 cm_ReleaseUser(userp);
7875 cm_ReleaseSCache(scp);
7879 /* SMB_COM_CREATE_DIRECTORY */
7880 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7882 clientchar_t *pathp;
7887 cm_scache_t *dscp; /* dir we're dealing with */
7888 cm_scache_t *scp; /* file we're creating */
7890 int initialModeBits;
7891 clientchar_t *lastNamep;
7893 clientchar_t *tidPathp;
7900 /* compute initial mode bits based on read-only flag in attributes */
7901 initialModeBits = 0777;
7903 tp = smb_GetSMBData(inp, NULL);
7904 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7906 return CM_ERROR_BADSMB;
7908 spacep = inp->spacep;
7909 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7911 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7912 return CM_ERROR_EXISTS;
7914 userp = smb_GetUserFromVCP(vcp, inp);
7916 caseFold = CM_FLAG_CASEFOLD;
7918 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7920 cm_ReleaseUser(userp);
7921 return CM_ERROR_NOSUCHPATH;
7924 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7925 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7926 userp, tidPathp, &req, &dscp);
7929 cm_ReleaseUser(userp);
7934 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7935 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7936 cm_ReleaseSCache(dscp);
7937 cm_ReleaseUser(userp);
7938 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7939 return CM_ERROR_PATH_NOT_COVERED;
7941 return CM_ERROR_NOSUCHPATH;
7943 #endif /* DFS_SUPPORT */
7945 /* otherwise, scp points to the parent directory. Do a lookup, and
7946 * fail if we find it. Otherwise, we do the create.
7952 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7953 if (scp) cm_ReleaseSCache(scp);
7954 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7955 if (code == 0) code = CM_ERROR_EXISTS;
7956 cm_ReleaseSCache(dscp);
7957 cm_ReleaseUser(userp);
7961 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7962 setAttr.clientModTime = time(NULL);
7963 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7964 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7965 smb_NotifyChange(FILE_ACTION_ADDED,
7966 FILE_NOTIFY_CHANGE_DIR_NAME,
7967 dscp, lastNamep, NULL, TRUE);
7969 /* we don't need this any longer */
7970 cm_ReleaseSCache(dscp);
7973 /* something went wrong creating or truncating the file */
7974 cm_ReleaseUser(userp);
7978 /* otherwise we succeeded */
7979 smb_SetSMBDataLength(outp, 0);
7980 cm_ReleaseUser(userp);
7985 BOOL smb_IsLegalFilename(clientchar_t *filename)
7988 * Find the longest substring of filename that does not contain
7989 * any of the chars in illegalChars. If that substring is less
7990 * than the length of the whole string, then one or more of the
7991 * illegal chars is in filename.
7993 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7999 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8000 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8002 clientchar_t *pathp;
8008 cm_scache_t *dscp; /* dir we're dealing with */
8009 cm_scache_t *scp; /* file we're creating */
8011 int initialModeBits;
8014 clientchar_t *lastNamep;
8017 clientchar_t *tidPathp;
8019 int created = 0; /* the file was new */
8024 excl = (inp->inCom == 0x03)? 0 : 1;
8026 attributes = smb_GetSMBParm(inp, 0);
8027 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8029 /* compute initial mode bits based on read-only flag in attributes */
8030 initialModeBits = 0666;
8031 if (attributes & SMB_ATTR_READONLY)
8032 initialModeBits &= ~0222;
8034 tp = smb_GetSMBData(inp, NULL);
8035 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8037 return CM_ERROR_BADSMB;
8039 if (!cm_IsValidClientString(pathp)) {
8041 clientchar_t * hexp;
8043 hexp = cm_GetRawCharsAlloc(pathp, -1);
8044 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8045 osi_LogSaveClientString(smb_logp, hexp));
8049 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8051 return CM_ERROR_BADNTFILENAME;
8054 spacep = inp->spacep;
8055 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8057 userp = smb_GetUserFromVCP(vcp, inp);
8059 caseFold = CM_FLAG_CASEFOLD;
8061 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8063 cm_ReleaseUser(userp);
8064 return CM_ERROR_NOSUCHPATH;
8066 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8067 userp, tidPathp, &req, &dscp);
8070 cm_ReleaseUser(userp);
8075 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8076 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8077 cm_ReleaseSCache(dscp);
8078 cm_ReleaseUser(userp);
8079 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8080 return CM_ERROR_PATH_NOT_COVERED;
8082 return CM_ERROR_NOSUCHPATH;
8084 #endif /* DFS_SUPPORT */
8086 /* otherwise, scp points to the parent directory. Do a lookup, and
8087 * truncate the file if we find it, otherwise we create the file.
8094 if (!smb_IsLegalFilename(lastNamep))
8095 return CM_ERROR_BADNTFILENAME;
8097 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8098 #ifdef DEBUG_VERBOSE
8101 hexp = osi_HexifyString( lastNamep );
8102 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8107 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8108 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8109 cm_ReleaseSCache(dscp);
8110 cm_ReleaseUser(userp);
8114 /* if we get here, if code is 0, the file exists and is represented by
8115 * scp. Otherwise, we have to create it.
8119 /* oops, file shouldn't be there */
8120 cm_ReleaseSCache(dscp);
8121 cm_ReleaseSCache(scp);
8122 cm_ReleaseUser(userp);
8123 return CM_ERROR_EXISTS;
8126 setAttr.mask = CM_ATTRMASK_LENGTH;
8127 setAttr.length.LowPart = 0;
8128 setAttr.length.HighPart = 0;
8129 code = cm_SetAttr(scp, &setAttr, userp, &req);
8132 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8133 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8134 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8138 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8139 smb_NotifyChange(FILE_ACTION_ADDED,
8140 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8141 dscp, lastNamep, NULL, TRUE);
8142 } else if (!excl && code == CM_ERROR_EXISTS) {
8143 /* not an exclusive create, and someone else tried
8144 * creating it already, then we open it anyway. We
8145 * don't bother retrying after this, since if this next
8146 * fails, that means that the file was deleted after
8147 * we started this call.
8149 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8152 setAttr.mask = CM_ATTRMASK_LENGTH;
8153 setAttr.length.LowPart = 0;
8154 setAttr.length.HighPart = 0;
8155 code = cm_SetAttr(scp, &setAttr, userp, &req);
8160 /* we don't need this any longer */
8161 cm_ReleaseSCache(dscp);
8164 /* something went wrong creating or truncating the file */
8165 if (scp) cm_ReleaseSCache(scp);
8166 cm_ReleaseUser(userp);
8170 /* make sure we only open files */
8171 if (scp->fileType != CM_SCACHETYPE_FILE) {
8172 cm_ReleaseSCache(scp);
8173 cm_ReleaseUser(userp);
8174 return CM_ERROR_ISDIR;
8177 /* now all we have to do is open the file itself */
8178 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8179 osi_assertx(fidp, "null smb_fid_t");
8183 lock_ObtainMutex(&fidp->mx);
8184 /* always create it open for read/write */
8185 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8187 /* remember that the file was newly created */
8189 fidp->flags |= SMB_FID_CREATED;
8191 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8193 /* save a pointer to the vnode */
8195 lock_ObtainWrite(&scp->rw);
8196 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8197 lock_ReleaseWrite(&scp->rw);
8200 fidp->userp = userp;
8201 lock_ReleaseMutex(&fidp->mx);
8203 smb_SetSMBParm(outp, 0, fidp->fid);
8204 smb_SetSMBDataLength(outp, 0);
8206 cm_Open(scp, 0, userp);
8208 smb_ReleaseFID(fidp);
8209 cm_ReleaseUser(userp);
8210 /* leave scp held since we put it in fidp->scp */
8215 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8218 osi_hyper_t new_offset;
8229 fd = smb_GetSMBParm(inp, 0);
8230 whence = smb_GetSMBParm(inp, 1);
8231 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8233 /* try to find the file descriptor */
8234 fd = smb_ChainFID(fd, inp);
8235 fidp = smb_FindFID(vcp, fd, 0);
8237 return CM_ERROR_BADFD;
8239 lock_ObtainMutex(&fidp->mx);
8240 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8241 lock_ReleaseMutex(&fidp->mx);
8242 smb_ReleaseFID(fidp);
8243 return CM_ERROR_BADFD;
8246 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8247 lock_ReleaseMutex(&fidp->mx);
8248 smb_CloseFID(vcp, fidp, NULL, 0);
8249 smb_ReleaseFID(fidp);
8250 return CM_ERROR_NOSUCHFILE;
8253 lock_ReleaseMutex(&fidp->mx);
8255 userp = smb_GetUserFromVCP(vcp, inp);
8257 lock_ObtainMutex(&fidp->mx);
8260 lock_ReleaseMutex(&fidp->mx);
8261 lock_ObtainWrite(&scp->rw);
8262 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8263 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8265 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8267 /* offset from current offset */
8268 new_offset = LargeIntegerAdd(fidp->offset,
8269 ConvertLongToLargeInteger(offset));
8271 else if (whence == 2) {
8272 /* offset from current EOF */
8273 new_offset = LargeIntegerAdd(scp->length,
8274 ConvertLongToLargeInteger(offset));
8276 new_offset = ConvertLongToLargeInteger(offset);
8279 fidp->offset = new_offset;
8280 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8281 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8282 smb_SetSMBDataLength(outp, 0);
8284 lock_ReleaseWrite(&scp->rw);
8285 smb_ReleaseFID(fidp);
8286 cm_ReleaseSCache(scp);
8287 cm_ReleaseUser(userp);
8291 /* dispatch all of the requests received in a packet. Due to chaining, this may
8292 * be more than one request.
8294 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8295 NCB *ncbp, raw_write_cont_t *rwcp)
8299 unsigned long code = 0;
8300 unsigned char *outWctp;
8301 int nparms; /* # of bytes of parameters */
8303 int nbytes; /* bytes of data, excluding count */
8306 unsigned short errCode;
8307 unsigned long NTStatus;
8309 unsigned char errClass;
8310 unsigned int oldGen;
8311 DWORD oldTime, newTime;
8313 /* get easy pointer to the data */
8314 smbp = (smb_t *) inp->data;
8316 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8317 /* setup the basic parms for the initial request in the packet */
8318 inp->inCom = smbp->com;
8319 inp->wctp = &smbp->wct;
8321 inp->ncb_length = ncbp->ncb_length;
8326 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8327 /* log it and discard it */
8328 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8329 __FILE__, __LINE__, ncbp->ncb_length);
8330 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8334 /* We are an ongoing op */
8335 thrd_Increment(&ongoingOps);
8337 /* set up response packet for receiving output */
8338 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8339 smb_FormatResponsePacket(vcp, inp, outp);
8340 outWctp = outp->wctp;
8342 /* Remember session generation number and time */
8343 oldGen = sessionGen;
8344 oldTime = GetTickCount();
8346 while (inp->inCom != 0xff) {
8347 dp = &smb_dispatchTable[inp->inCom];
8349 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8350 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8351 code = outp->resumeCode;
8355 /* process each request in the packet; inCom, wctp and inCount
8356 * are already set up.
8358 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8361 /* now do the dispatch */
8362 /* start by formatting the response record a little, as a default */
8363 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8365 outWctp[1] = 0xff; /* no operation */
8366 outWctp[2] = 0; /* padding */
8371 /* not a chained request, this is a more reasonable default */
8372 outWctp[0] = 0; /* wct of zero */
8373 outWctp[1] = 0; /* and bcc (word) of zero */
8377 /* once set, stays set. Doesn't matter, since we never chain
8378 * "no response" calls.
8380 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8384 /* we have a recognized operation */
8385 char * opName = myCrt_Dispatch(inp->inCom);
8388 smbp = (smb_t *) inp;
8390 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8391 opName, smbp->mid, vcp,vcp->lana,vcp->lsn);
8392 if (inp->inCom == 0x1d) {
8394 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8396 code = (*(dp->procp)) (vcp, inp, outp);
8398 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8399 code, smbp->mid, vcp,vcp->lana,vcp->lsn);
8401 newTime = GetTickCount();
8402 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8403 opName, smbp->mid, newTime - oldTime);
8406 if ( code == CM_ERROR_BADSMB ||
8407 code == CM_ERROR_BADOP )
8409 #endif /* LOG_PACKET */
8411 /* ReceiveV3Tran2A handles its own logging */
8412 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8415 clientchar_t *treepath = NULL; /* do not free */
8416 clientchar_t *pathname = NULL;
8417 cm_fid_t afid = {0,0,0,0,0};
8419 uidp = smb_FindUID(vcp, smbp->uid, 0);
8420 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8421 fidp = smb_FindFID(vcp, inp->fid, 0);
8424 lock_ObtainMutex(&fidp->mx);
8425 if (fidp->NTopen_pathp)
8426 pathname = fidp->NTopen_pathp;
8428 afid = fidp->scp->fid;
8430 if (inp->stringsp->wdata)
8431 pathname = inp->stringsp->wdata;
8434 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)",
8435 opName, newTime - oldTime,
8436 smbp->uid, uidp ? uidp->unp->name : NULL,
8437 smbp->pid, smbp->mid, smbp->tid,
8440 afid.cell, afid.volume, afid.vnode, afid.unique);
8443 lock_ReleaseMutex(&fidp->mx);
8446 smb_ReleaseUID(uidp);
8448 smb_ReleaseFID(fidp);
8451 if (oldGen != sessionGen) {
8452 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8453 newTime - oldTime, ncbp->ncb_length);
8454 osi_Log3(smb_logp, "Request %s straddled session startup, "
8455 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8458 FreeSMBStrings(inp);
8460 /* bad opcode, fail the request, after displaying it */
8461 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8464 #endif /* LOG_PACKET */
8467 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8468 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8469 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8470 if (code == IDCANCEL)
8473 code = CM_ERROR_BADOP;
8476 /* catastrophic failure: log as much as possible */
8477 if (code == CM_ERROR_BADSMB) {
8478 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8482 #endif /* LOG_PACKET */
8483 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8486 code = CM_ERROR_INVAL;
8489 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8490 thrd_Decrement(&ongoingOps);
8495 /* now, if we failed, turn the current response into an empty
8496 * one, and fill in the response packet's error code.
8499 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8500 smb_MapNTError(code, &NTStatus);
8501 outWctp = outp->wctp;
8502 smbp = (smb_t *) &outp->data;
8503 if (code != CM_ERROR_PARTIALWRITE
8504 && code != CM_ERROR_BUFFERTOOSMALL
8505 && code != CM_ERROR_GSSCONTINUE) {
8506 /* nuke wct and bcc. For a partial
8507 * write or an in-process authentication handshake,
8508 * assume they're OK.
8514 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8515 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8516 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8517 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8518 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8522 smb_MapCoreError(code, vcp, &errCode, &errClass);
8523 outWctp = outp->wctp;
8524 smbp = (smb_t *) &outp->data;
8525 if (code != CM_ERROR_PARTIALWRITE) {
8526 /* nuke wct and bcc. For a partial
8527 * write, assume they're OK.
8533 smbp->errLow = (unsigned char) (errCode & 0xff);
8534 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8535 smbp->rcls = errClass;
8538 } /* error occurred */
8540 /* if we're here, we've finished one request. Look to see if
8541 * this is a chained opcode. If it is, setup things to process
8542 * the chained request, and setup the output buffer to hold the
8543 * chained response. Start by finding the next input record.
8545 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8546 break; /* not a chained req */
8547 tp = inp->wctp; /* points to start of last request */
8548 /* in a chained request, the first two
8549 * parm fields are required, and are
8550 * AndXCommand/AndXReserved and
8552 if (tp[0] < 2) break;
8553 if (tp[1] == 0xff) break; /* no more chained opcodes */
8555 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8558 /* and now append the next output request to the end of this
8559 * last request. Begin by finding out where the last response
8560 * ends, since that's where we'll put our new response.
8562 outWctp = outp->wctp; /* ptr to out parameters */
8563 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8564 nparms = outWctp[0] << 1;
8565 tp = outWctp + nparms + 1; /* now points to bcc field */
8566 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8567 tp += 2 /* for the count itself */ + nbytes;
8568 /* tp now points to the new output record; go back and patch the
8569 * second parameter (off2) to point to the new record.
8571 temp = (unsigned int)(tp - outp->data);
8572 outWctp[3] = (unsigned char) (temp & 0xff);
8573 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8574 outWctp[2] = 0; /* padding */
8575 outWctp[1] = inp->inCom; /* next opcode */
8577 /* finally, setup for the next iteration */
8580 } /* while loop over all requests in the packet */
8582 /* now send the output packet, and return */
8584 smb_SendPacket(vcp, outp);
8585 thrd_Decrement(&ongoingOps);
8590 /* Wait for Netbios() calls to return, and make the results available to server
8591 * threads. Note that server threads can't wait on the NCBevents array
8592 * themselves, because NCB events are manual-reset, and the servers would race
8593 * each other to reset them.
8595 void smb_ClientWaiter(void *parmp)
8600 while (smbShutdownFlag == 0) {
8601 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8603 if (code == WAIT_OBJECT_0)
8606 /* error checking */
8607 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8609 int abandonIdx = code - WAIT_ABANDONED_0;
8610 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8613 if (code == WAIT_IO_COMPLETION)
8615 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8619 if (code == WAIT_TIMEOUT)
8621 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8624 if (code == WAIT_FAILED)
8626 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8629 idx = code - WAIT_OBJECT_0;
8631 /* check idx range! */
8632 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8634 /* this is fatal - log as much as possible */
8635 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8636 osi_assertx(0, "invalid index");
8639 thrd_ResetEvent(NCBevents[idx]);
8640 thrd_SetEvent(NCBreturns[0][idx]);
8645 * Try to have one NCBRECV request waiting for every live session. Not more
8646 * than one, because if there is more than one, it's hard to handle Write Raw.
8648 void smb_ServerWaiter(void *parmp)
8651 int idx_session, idx_NCB;
8654 while (smbShutdownFlag == 0) {
8656 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8658 if (code == WAIT_OBJECT_0)
8661 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8663 int abandonIdx = code - WAIT_ABANDONED_0;
8664 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8667 if (code == WAIT_IO_COMPLETION)
8669 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8673 if (code == WAIT_TIMEOUT)
8675 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8678 if (code == WAIT_FAILED)
8680 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8683 idx_session = code - WAIT_OBJECT_0;
8685 /* check idx range! */
8686 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8688 /* this is fatal - log as much as possible */
8689 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8690 osi_assertx(0, "invalid index");
8695 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8697 if (code == WAIT_OBJECT_0) {
8698 if (smbShutdownFlag == 1)
8704 /* error checking */
8705 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8707 int abandonIdx = code - WAIT_ABANDONED_0;
8708 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8711 if (code == WAIT_IO_COMPLETION)
8713 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8717 if (code == WAIT_TIMEOUT)
8719 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8722 if (code == WAIT_FAILED)
8724 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8727 idx_NCB = code - WAIT_OBJECT_0;
8729 /* check idx range! */
8730 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8732 /* this is fatal - log as much as possible */
8733 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8734 osi_assertx(0, "invalid index");
8737 /* Link them together */
8738 NCBsessions[idx_NCB] = idx_session;
8741 ncbp = NCBs[idx_NCB];
8742 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8743 ncbp->ncb_command = NCBRECV | ASYNCH;
8744 ncbp->ncb_lana_num = lanas[idx_session];
8745 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8746 ncbp->ncb_event = NCBevents[idx_NCB];
8747 ncbp->ncb_length = SMB_PACKETSIZE;
8753 * The top level loop for handling SMB request messages. Each server thread
8754 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8755 * NCB and buffer for the incoming request are loaned to us.
8757 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8758 * to immediately send a request for the rest of the data. This must come
8759 * before any other traffic for that session, so we delay setting the session
8760 * event until that data has come in.
8762 void smb_Server(VOID *parmp)
8764 INT_PTR myIdx = (INT_PTR) parmp;
8768 smb_packet_t *outbufp;
8770 int idx_NCB, idx_session;
8772 smb_vc_t *vcp = NULL;
8774 extern void rx_StartClientThread(void);
8776 rx_StartClientThread();
8778 outncbp = smb_GetNCB();
8779 outbufp = smb_GetPacket();
8780 outbufp->ncbp = outncbp;
8788 cm_ResetServerPriority();
8790 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8793 /* terminate silently if shutdown flag is set */
8794 if (code == WAIT_OBJECT_0) {
8795 if (smbShutdownFlag == 1) {
8796 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8802 /* error checking */
8803 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8805 int abandonIdx = code - WAIT_ABANDONED_0;
8806 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8809 if (code == WAIT_IO_COMPLETION)
8811 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8815 if (code == WAIT_TIMEOUT)
8817 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8820 if (code == WAIT_FAILED)
8822 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8825 idx_NCB = code - WAIT_OBJECT_0;
8827 /* check idx range! */
8828 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8830 /* this is fatal - log as much as possible */
8831 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8832 osi_assertx(0, "invalid index");
8835 ncbp = NCBs[idx_NCB];
8836 idx_session = NCBsessions[idx_NCB];
8837 rc = ncbp->ncb_retcode;
8839 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8840 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8844 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8848 /* Can this happen? Or is it just my UNIX paranoia? */
8849 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8854 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8857 /* Client closed session */
8858 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8860 lock_ObtainMutex(&vcp->mx);
8861 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8862 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8864 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8865 lock_ReleaseMutex(&vcp->mx);
8866 lock_ObtainWrite(&smb_globalLock);
8867 dead_sessions[vcp->session] = TRUE;
8868 lock_ReleaseWrite(&smb_globalLock);
8870 lock_ReleaseMutex(&vcp->mx);
8872 smb_CleanupDeadVC(vcp);
8879 /* Treat as transient error */
8880 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8883 "dispatch smb recv failed, message incomplete, ncb_length %d",
8886 "SMB message incomplete, "
8887 "length %d", ncbp->ncb_length);
8890 * We used to discard the packet.
8891 * Instead, try handling it normally.
8895 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8899 /* A weird error code. Log it, sleep, and continue. */
8900 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8902 lock_ObtainMutex(&vcp->mx);
8903 if (vcp->errorCount++ > 3) {
8904 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8905 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8906 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8908 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8909 lock_ReleaseMutex(&vcp->mx);
8910 lock_ObtainWrite(&smb_globalLock);
8911 dead_sessions[vcp->session] = TRUE;
8912 lock_ReleaseWrite(&smb_globalLock);
8914 lock_ReleaseMutex(&vcp->mx);
8916 smb_CleanupDeadVC(vcp);
8922 lock_ReleaseMutex(&vcp->mx);
8926 thrd_SetEvent(SessionEvents[idx_session]);
8932 /* Success, so now dispatch on all the data in the packet */
8934 smb_concurrentCalls++;
8935 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8936 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8939 * If at this point vcp is NULL (implies that packet was invalid)
8940 * then we are in big trouble. This means either :
8941 * a) we have the wrong NCB.
8942 * b) Netbios screwed up the call.
8943 * c) The VC was already marked dead before we were able to
8945 * Obviously this implies that
8946 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8947 * lanas[idx_session] != ncbp->ncb_lana_num )
8948 * Either way, we can't do anything with this packet.
8949 * Log, sleep and resume.
8952 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8956 ncbp->ncb_lana_num);
8958 /* Also log in the trace log. */
8959 osi_Log4(smb_logp, "Server: VCP does not exist!"
8960 "LSNs[idx_session]=[%d],"
8961 "lanas[idx_session]=[%d],"
8962 "ncbp->ncb_lsn=[%d],"
8963 "ncbp->ncb_lana_num=[%d]",
8967 ncbp->ncb_lana_num);
8969 /* thrd_Sleep(1000); Don't bother sleeping */
8970 thrd_SetEvent(SessionEvents[idx_session]);
8971 smb_concurrentCalls--;
8975 cm_SetRequestStartTime();
8977 vcp->errorCount = 0;
8978 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8979 smbp = (smb_t *)bufp->data;
8986 if (smbp->com == 0x1d) {
8987 /* Special handling for Write Raw */
8988 raw_write_cont_t rwc;
8990 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8991 if (rwc.code == 0) {
8992 EVENT_HANDLE rwevent;
8993 char eventName[MAX_PATH];
8995 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
8996 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8997 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8998 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9000 ncbp->ncb_command = NCBRECV | ASYNCH;
9001 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9002 ncbp->ncb_lana_num = vcp->lana;
9003 ncbp->ncb_buffer = rwc.buf;
9004 ncbp->ncb_length = 65535;
9005 ncbp->ncb_event = rwevent;
9007 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9008 thrd_CloseHandle(rwevent);
9010 thrd_SetEvent(SessionEvents[idx_session]);
9012 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9014 else if (smbp->com == 0xa0) {
9016 * Serialize the handling for NT Transact
9019 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9020 thrd_SetEvent(SessionEvents[idx_session]);
9022 thrd_SetEvent(SessionEvents[idx_session]);
9023 /* TODO: what else needs to be serialized? */
9024 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9028 __except( smb_ServerExceptionFilter() ) {
9032 smb_concurrentCalls--;
9035 thrd_SetEvent(NCBavails[idx_NCB]);
9040 smb_FreePacket(outbufp);
9042 smb_FreeNCB(outncbp);
9046 * Exception filter for the server threads. If an exception occurs in the
9047 * dispatch routines, which is where exceptions are most common, then do a
9048 * force trace and give control to upstream exception handlers. Useful for
9051 DWORD smb_ServerExceptionFilter(void) {
9052 /* While this is not the best time to do a trace, if it succeeds, then
9053 * we have a trace (assuming tracing was enabled). Otherwise, this should
9054 * throw a second exception.
9056 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9057 afsd_ForceTrace(TRUE);
9058 buf_ForceTrace(TRUE);
9059 return EXCEPTION_CONTINUE_SEARCH;
9063 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9064 * If the number of server threads is M, and the number of live sessions is
9065 * N, then the number of NCB's in use at any time either waiting for, or
9066 * holding, received messages is M + N, so that is how many NCB's get created.
9068 void InitNCBslot(int idx)
9070 struct smb_packet *bufp;
9071 EVENT_HANDLE retHandle;
9073 char eventName[MAX_PATH];
9075 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9077 NCBs[idx] = smb_GetNCB();
9078 sprintf(eventName,"NCBavails[%d]", idx);
9079 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9080 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9081 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9082 sprintf(eventName,"NCBevents[%d]", idx);
9083 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9084 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9085 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9086 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9087 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9088 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9089 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9090 for (i=0; i<smb_NumServerThreads; i++)
9091 NCBreturns[i][idx] = retHandle;
9092 bufp = smb_GetPacket();
9093 bufp->spacep = cm_GetSpace();
9097 /* listen for new connections */
9098 void smb_Listener(void *parmp)
9104 afs_uint32 session, thread;
9105 smb_vc_t *vcp = NULL;
9107 char rname[NCBNAMSZ+1];
9108 char cname[MAX_COMPUTERNAME_LENGTH+1];
9109 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9110 INT_PTR lana = (INT_PTR) parmp;
9111 char eventName[MAX_PATH];
9112 int bridgeCount = 0;
9113 int nowildCount = 0;
9115 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9116 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9117 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9118 thrd_ResetEvent(ListenerShutdown[lana]);
9120 ncbp = smb_GetNCB();
9122 /* retrieve computer name */
9123 GetComputerName(cname, &cnamelen);
9126 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9127 memset(ncbp, 0, sizeof(NCB));
9130 ncbp->ncb_command = NCBLISTEN;
9131 ncbp->ncb_rto = 0; /* No receive timeout */
9132 ncbp->ncb_sto = 0; /* No send timeout */
9134 /* pad out with spaces instead of null termination */
9135 len = (long)strlen(smb_localNamep);
9136 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9137 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9139 strcpy(ncbp->ncb_callname, "*");
9140 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9142 ncbp->ncb_lana_num = (UCHAR)lana;
9144 code = Netbios(ncbp);
9146 if (code == NRC_NAMERR) {
9147 /* An smb shutdown or Vista resume must have taken place */
9149 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9150 ncbp->ncb_lana_num);
9151 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9153 if (lock_TryMutex(&smb_StartedLock)) {
9154 lana_list.lana[i] = LANA_INVALID;
9155 lock_ReleaseMutex(&smb_StartedLock);
9158 } else if (code == NRC_BRIDGE || code != 0) {
9159 int lanaRemaining = 0;
9161 if (code == NRC_BRIDGE) {
9162 if (++bridgeCount <= 5) {
9163 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9166 } else if (code == NRC_NOWILD) {
9167 if (++nowildCount <= 5) {
9168 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9170 if (bridgeCount > 0) {
9171 memset(ncbp, 0, sizeof(*ncbp));
9172 ncbp->ncb_command = NCBADDNAME;
9173 ncbp->ncb_lana_num = (UCHAR)lana;
9174 /* pad out with spaces instead of null termination */
9175 len = (long)strlen(smb_localNamep);
9176 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9177 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9178 code = Netbios(ncbp);
9184 while (!lock_TryMutex(&smb_StartedLock)) {
9185 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9191 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9192 ncbp->ncb_lana_num, ncb_error_string(code));
9193 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9194 ncbp->ncb_lana_num, ncb_error_string(code));
9196 for (i = 0; i < lana_list.length; i++) {
9197 if (lana_list.lana[i] == lana) {
9198 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9199 lana_list.lana[i] = LANA_INVALID;
9201 if (lana_list.lana[i] != LANA_INVALID)
9205 if (lanaRemaining == 0) {
9206 cm_VolStatus_Network_Stopped(cm_NetbiosName
9211 smb_ListenerState = SMB_LISTENER_STOPPED;
9212 smb_LANadapter = LANA_INVALID;
9213 lana_list.length = 0;
9215 lock_ReleaseMutex(&smb_StartedLock);
9219 else if (code != 0) {
9220 char tbuffer[AFSPATHMAX];
9222 /* terminate silently if shutdown flag is set */
9223 while (!lock_TryMutex(&smb_StartedLock)) {
9224 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9230 "NCBLISTEN lana=%d failed with code %d [%s]",
9231 ncbp->ncb_lana_num, code, ncb_error_string(code));
9233 "Client exiting due to network failure. Please restart client.\n");
9236 "Client exiting due to network failure. Please restart client.\n"
9237 "NCBLISTEN lana=%d failed with code %d [%s]",
9238 ncbp->ncb_lana_num, code, ncb_error_string(code));
9240 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9241 MB_OK|MB_SERVICE_NOTIFICATION);
9242 osi_panic(tbuffer, __FILE__, __LINE__);
9244 lock_ReleaseMutex(&smb_StartedLock);
9249 /* a successful packet received. clear bridge error count */
9253 /* check for remote conns */
9254 /* first get remote name and insert null terminator */
9255 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9256 for (i=NCBNAMSZ; i>0; i--) {
9257 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9263 /* compare with local name */
9265 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9266 flags |= SMB_VCFLAG_REMOTECONN;
9269 lock_ObtainMutex(&smb_ListenerLock);
9271 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9272 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9274 /* now ncbp->ncb_lsn is the connection ID */
9275 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9276 if (vcp->session == 0) {
9277 /* New generation */
9278 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9281 /* Log session startup */
9283 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9284 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9285 #endif /* NOTSERVICE */
9286 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9287 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9289 if (reportSessionStartups) {
9290 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9293 lock_ObtainMutex(&vcp->mx);
9294 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9295 vcp->flags |= flags;
9296 lock_ReleaseMutex(&vcp->mx);
9298 /* Allocate slot in session arrays */
9299 /* Re-use dead session if possible, otherwise add one more */
9300 /* But don't look at session[0], it is reserved */
9301 lock_ObtainWrite(&smb_globalLock);
9302 for (session = 1; session < numSessions; session++) {
9303 if (dead_sessions[session]) {
9304 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9305 dead_sessions[session] = FALSE;
9309 lock_ReleaseWrite(&smb_globalLock);
9311 /* We are re-using an existing VC because the lsn and lana
9313 session = vcp->session;
9315 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9317 /* Log session startup */
9319 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9320 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9321 #endif /* NOTSERVICE */
9322 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9323 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9325 if (reportSessionStartups) {
9326 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9330 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9331 unsigned long code = CM_ERROR_ALLBUSY;
9332 smb_packet_t * outp = smb_GetPacket();
9333 unsigned char *outWctp;
9336 smb_FormatResponsePacket(vcp, NULL, outp);
9339 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9340 unsigned long NTStatus;
9341 smb_MapNTError(code, &NTStatus);
9342 outWctp = outp->wctp;
9343 smbp = (smb_t *) &outp->data;
9347 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9348 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9349 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9350 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9351 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9353 unsigned short errCode;
9354 unsigned char errClass;
9355 smb_MapCoreError(code, vcp, &errCode, &errClass);
9356 outWctp = outp->wctp;
9357 smbp = (smb_t *) &outp->data;
9361 smbp->errLow = (unsigned char) (errCode & 0xff);
9362 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9363 smbp->rcls = errClass;
9366 smb_SendPacket(vcp, outp);
9367 smb_FreePacket(outp);
9369 lock_ObtainMutex(&vcp->mx);
9370 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9371 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9373 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9374 lock_ReleaseMutex(&vcp->mx);
9375 lock_ObtainWrite(&smb_globalLock);
9376 dead_sessions[vcp->session] = TRUE;
9377 lock_ReleaseWrite(&smb_globalLock);
9378 smb_CleanupDeadVC(vcp);
9380 lock_ReleaseMutex(&vcp->mx);
9383 /* assert that we do not exceed the maximum number of sessions or NCBs.
9384 * we should probably want to wait for a session to be freed in case
9387 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9388 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9390 lock_ObtainMutex(&vcp->mx);
9391 vcp->session = session;
9392 lock_ReleaseMutex(&vcp->mx);
9393 lock_ObtainWrite(&smb_globalLock);
9394 LSNs[session] = ncbp->ncb_lsn;
9395 lanas[session] = ncbp->ncb_lana_num;
9396 lock_ReleaseWrite(&smb_globalLock);
9398 if (session == numSessions) {
9399 /* Add new NCB for new session */
9400 char eventName[MAX_PATH];
9402 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9404 InitNCBslot(numNCBs);
9405 lock_ObtainWrite(&smb_globalLock);
9407 lock_ReleaseWrite(&smb_globalLock);
9408 thrd_SetEvent(NCBavails[0]);
9409 thrd_SetEvent(NCBevents[0]);
9410 for (thread = 0; thread < smb_NumServerThreads; thread++)
9411 thrd_SetEvent(NCBreturns[thread][0]);
9412 /* Also add new session event */
9413 sprintf(eventName, "SessionEvents[%d]", session);
9414 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9415 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9416 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9417 lock_ObtainWrite(&smb_globalLock);
9419 lock_ReleaseWrite(&smb_globalLock);
9420 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9421 thrd_SetEvent(SessionEvents[0]);
9423 thrd_SetEvent(SessionEvents[session]);
9429 lock_ReleaseMutex(&smb_ListenerLock);
9430 } /* dispatch while loop */
9434 thrd_SetEvent(ListenerShutdown[lana]);
9439 configureBackConnectionHostNames(void)
9441 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9442 * there is a restriction on the use of SMB authentication on loopback connections.
9443 * There are two work arounds available:
9445 * (1) We can disable the check for matching host names. This does not
9447 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9448 * "DisableLoopbackCheck"=dword:00000001
9450 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9451 * does require a reboot:
9452 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9453 * "BackConnectionHostNames"=multi-sz
9455 * The algorithm will be:
9456 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9457 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9458 * (2b1) and check to see if DisableLoopbackCheck is set.
9459 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9460 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9461 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9462 * check for the UnsetDisableLoopbackCheck value.
9463 * If set, set the DisableLoopbackCheck flag to 0x0
9464 * and delete the UnsetDisableLoopbackCheck value
9466 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9467 * force Windows to use the loopback authentication mechanism for the specified
9470 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9471 * service session that set it.
9477 DWORD dwSize, dwAllocSize;
9479 PBYTE pHostNames = NULL, pName = NULL;
9480 BOOL bNameFound = FALSE;
9481 static BOOL bLoopbackCheckDisabled = FALSE;
9483 /* BackConnectionHostNames and DisableLoopbackCheck */
9484 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9485 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9488 &hkMSV10) == ERROR_SUCCESS )
9490 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9491 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9492 (dwType == REG_MULTI_SZ))
9494 dwAllocSize += 1 /* in case the source string is not nul terminated */
9495 + (DWORD)strlen(cm_NetbiosName) + 2;
9496 pHostNames = malloc(dwAllocSize);
9497 dwSize = dwAllocSize;
9498 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9499 pHostNames, &dwSize) == ERROR_SUCCESS)
9501 for (pName = pHostNames;
9502 (pName - pHostNames < (int) dwSize) && *pName ;
9503 pName += strlen(pName) + 1)
9505 if ( !stricmp(pName, cm_NetbiosName) ) {
9513 if ( !bNameFound ) {
9514 size_t size = strlen(cm_NetbiosName) + 2;
9515 if ( !pHostNames ) {
9516 pHostNames = malloc(size);
9519 StringCbCopyA(pName, size, cm_NetbiosName);
9521 *pName = '\0'; /* add a second nul terminator */
9523 dwType = REG_MULTI_SZ;
9524 dwSize = (DWORD)(pName - pHostNames + 1);
9525 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9527 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9528 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9531 &hkLsa) == ERROR_SUCCESS )
9533 dwSize = sizeof(DWORD);
9534 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9537 dwSize = sizeof(DWORD);
9539 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9541 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9542 AFSREG_CLT_OPENAFS_SUBKEY,
9545 REG_OPTION_NON_VOLATILE,
9549 NULL) == ERROR_SUCCESS) {
9552 dwSize = sizeof(DWORD);
9554 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9555 bLoopbackCheckDisabled = TRUE;
9556 RegCloseKey(hkClient);
9561 } else if (!bLoopbackCheckDisabled) {
9562 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9563 AFSREG_CLT_OPENAFS_SUBKEY,
9566 REG_OPTION_NON_VOLATILE,
9570 NULL) == ERROR_SUCCESS) {
9572 dwSize = sizeof(DWORD);
9573 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9575 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9576 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9579 &hkLsa) == ERROR_SUCCESS )
9581 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9585 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9586 RegCloseKey(hkClient);
9595 RegCloseKey(hkMSV10);
9601 configureExtendedSMBSessionTimeouts(void)
9604 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9605 * new functionality:
9607 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9608 * "ReconnectableServers" REG_MULTI_SZ
9609 * "ExtendedSessTimeout" REG_DWORD (seconds)
9610 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
9612 * These values can be used to prevent the smb redirector from timing out
9613 * smb connection to the afs smb server prematurely.
9617 DWORD dwSize, dwAllocSize;
9619 PBYTE pHostNames = NULL, pName = NULL;
9620 BOOL bNameFound = FALSE;
9622 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9623 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9626 &hkLanMan) == ERROR_SUCCESS )
9628 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
9629 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9630 (dwType == REG_MULTI_SZ))
9632 dwAllocSize += 1 /* in case the source string is not nul terminated */
9633 + (DWORD)strlen(cm_NetbiosName) + 2;
9634 pHostNames = malloc(dwAllocSize);
9635 dwSize = dwAllocSize;
9636 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
9637 pHostNames, &dwSize) == ERROR_SUCCESS)
9639 for (pName = pHostNames;
9640 (pName - pHostNames < (int) dwSize) && *pName ;
9641 pName += strlen(pName) + 1)
9643 if ( !stricmp(pName, cm_NetbiosName) ) {
9651 if ( !bNameFound ) {
9652 size_t size = strlen(cm_NetbiosName) + 2;
9653 if ( !pHostNames ) {
9654 pHostNames = malloc(size);
9657 StringCbCopyA(pName, size, cm_NetbiosName);
9659 *pName = '\0'; /* add a second nul terminator */
9661 dwType = REG_MULTI_SZ;
9662 dwSize = (DWORD)(pName - pHostNames + 1);
9663 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9671 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
9672 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9673 (dwType == REG_MULTI_SZ))
9675 dwAllocSize += 1 /* in case the source string is not nul terminated */
9676 + (DWORD)strlen(cm_NetbiosName) + 2;
9677 pHostNames = malloc(dwAllocSize);
9678 dwSize = dwAllocSize;
9679 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
9680 pHostNames, &dwSize) == ERROR_SUCCESS)
9682 for (pName = pHostNames;
9683 (pName - pHostNames < (int) dwSize) && *pName ;
9684 pName += strlen(pName) + 1)
9686 if ( !stricmp(pName, cm_NetbiosName) ) {
9694 if ( !bNameFound ) {
9695 size_t size = strlen(cm_NetbiosName) + 2;
9696 if ( !pHostNames ) {
9697 pHostNames = malloc(size);
9700 StringCbCopyA(pName, size, cm_NetbiosName);
9702 *pName = '\0'; /* add a second nul terminator */
9704 dwType = REG_MULTI_SZ;
9705 dwSize = (DWORD)(pName - pHostNames + 1);
9706 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9714 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
9715 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9716 (dwType != REG_DWORD))
9719 dwSize = sizeof(dwValue);
9720 dwValue = 300; /* 5 minutes */
9721 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9723 RegCloseKey(hkLanMan);
9728 smb_LanAdapterChangeThread(void *param)
9731 * Give the IPAddrDaemon thread a chance
9732 * to block before we trigger.
9735 smb_LanAdapterChange(0);
9738 void smb_SetLanAdapterChangeDetected(void)
9743 lock_ObtainMutex(&smb_StartedLock);
9745 if (!powerStateSuspended) {
9746 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9747 NULL, 0, &lpid, "smb_LanAdapterChange");
9748 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9749 thrd_CloseHandle(phandle);
9752 smb_LanAdapterChangeDetected = 1;
9753 lock_ReleaseMutex(&smb_StartedLock);
9756 void smb_LanAdapterChange(int locked) {
9757 lana_number_t lanaNum;
9759 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9761 LANA_ENUM temp_list;
9766 afsi_log("smb_LanAdapterChange");
9769 lock_ObtainMutex(&smb_StartedLock);
9771 smb_LanAdapterChangeDetected = 0;
9773 if (!powerStateSuspended &&
9774 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9775 LANA_NETBIOS_NAME_FULL)) &&
9776 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9777 if ( isGateway != bGateway ) {
9778 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9779 smb_LANadapter, lanaNum, isGateway, bGateway);
9781 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9782 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9783 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9786 NCB *ncbp = smb_GetNCB();
9787 ncbp->ncb_command = NCBENUM;
9788 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9789 ncbp->ncb_length = sizeof(temp_list);
9790 code = Netbios(ncbp);
9792 if (temp_list.length != lana_list.length) {
9793 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9794 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9797 for (i=0; i<lana_list.length; i++) {
9798 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9799 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9800 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9812 smb_StopListeners(1);
9813 smb_RestartListeners(1);
9816 lock_ReleaseMutex(&smb_StartedLock);
9819 /* initialize Netbios */
9820 int smb_NetbiosInit(int locked)
9823 int i, lana, code, l;
9825 int delname_tried=0;
9828 lana_number_t lanaNum;
9831 lock_ObtainMutex(&smb_StartedLock);
9833 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9834 smb_ListenerState != SMB_LISTENER_STOPPED) {
9837 lock_ReleaseMutex(&smb_StartedLock);
9840 /* setup the NCB system */
9841 ncbp = smb_GetNCB();
9843 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9844 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9845 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9847 if (smb_LANadapter != LANA_INVALID)
9848 afsi_log("LAN adapter number %d", smb_LANadapter);
9850 afsi_log("LAN adapter number not determined");
9853 afsi_log("Set for gateway service");
9855 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9857 /* something went horribly wrong. We can't proceed without a netbios name */
9859 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9860 osi_panic(buf, __FILE__, __LINE__);
9863 /* remember the name */
9864 len = (int)strlen(cm_NetbiosName);
9866 free(smb_localNamep);
9867 smb_localNamep = malloc(len+1);
9868 strcpy(smb_localNamep, cm_NetbiosName);
9869 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9871 /* Also copy the value to the client character encoded string */
9872 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9874 if (smb_LANadapter == LANA_INVALID) {
9875 ncbp->ncb_command = NCBENUM;
9876 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9877 ncbp->ncb_length = sizeof(lana_list);
9878 code = Netbios(ncbp);
9880 afsi_log("Netbios NCBENUM error code %d", code);
9881 osi_panic(s, __FILE__, __LINE__);
9885 lana_list.length = 1;
9886 lana_list.lana[0] = smb_LANadapter;
9889 for (i = 0; i < lana_list.length; i++) {
9890 /* reset the adaptor: in Win32, this is required for every process, and
9891 * acts as an init call, not as a real hardware reset.
9893 ncbp->ncb_command = NCBRESET;
9894 ncbp->ncb_callname[0] = 100;
9895 ncbp->ncb_callname[2] = 100;
9896 ncbp->ncb_lana_num = lana_list.lana[i];
9897 code = Netbios(ncbp);
9899 code = ncbp->ncb_retcode;
9901 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9902 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9904 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9908 /* and declare our name so we can receive connections */
9909 memset(ncbp, 0, sizeof(*ncbp));
9910 len=lstrlen(smb_localNamep);
9911 memset(smb_sharename,' ',NCBNAMSZ);
9912 memcpy(smb_sharename,smb_localNamep,len);
9913 afsi_log("lana_list.length %d", lana_list.length);
9915 /* Keep the name so we can unregister it later */
9916 for (l = 0; l < lana_list.length; l++) {
9917 lana = lana_list.lana[l];
9919 ncbp->ncb_command = NCBADDNAME;
9920 ncbp->ncb_lana_num = lana;
9921 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9922 code = Netbios(ncbp);
9924 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9925 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9927 char name[NCBNAMSZ+1];
9929 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9930 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9934 code = ncbp->ncb_retcode;
9937 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9940 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9941 if (code == NRC_BRIDGE) { /* invalid LANA num */
9942 lana_list.lana[l] = LANA_INVALID;
9945 else if (code == NRC_DUPNAME) {
9946 afsi_log("Name already exists; try to delete it");
9947 memset(ncbp, 0, sizeof(*ncbp));
9948 ncbp->ncb_command = NCBDELNAME;
9949 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9950 ncbp->ncb_lana_num = lana;
9951 code = Netbios(ncbp);
9953 code = ncbp->ncb_retcode;
9955 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9957 if (code != 0 || delname_tried) {
9958 lana_list.lana[l] = LANA_INVALID;
9960 else if (code == 0) {
9961 if (!delname_tried) {
9969 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9970 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9974 smb_LANadapter = lana;
9975 lana_found = 1; /* at least one worked */
9979 osi_assertx(lana_list.length >= 0, "empty lana list");
9981 afsi_log("No valid LANA numbers found!");
9982 lana_list.length = 0;
9983 smb_LANadapter = LANA_INVALID;
9984 smb_ListenerState = SMB_LISTENER_STOPPED;
9985 cm_VolStatus_Network_Stopped(cm_NetbiosName
9992 /* we're done with the NCB now */
9995 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9996 if (lana_list.length > 0)
9997 osi_assert(smb_LANadapter != LANA_INVALID);
10000 lock_ReleaseMutex(&smb_StartedLock);
10002 return (lana_list.length > 0 ? 1 : 0);
10005 void smb_StartListeners(int locked)
10012 lock_ObtainMutex(&smb_StartedLock);
10014 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10016 lock_ReleaseMutex(&smb_StartedLock);
10020 afsi_log("smb_StartListeners");
10021 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10022 configureBackConnectionHostNames();
10024 /* Configure Extended SMB Session Timeouts */
10025 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10026 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10027 configureExtendedSMBSessionTimeouts();
10030 smb_ListenerState = SMB_LISTENER_STARTED;
10031 cm_VolStatus_Network_Started(cm_NetbiosName
10037 for (i = 0; i < lana_list.length; i++) {
10038 if (lana_list.lana[i] == LANA_INVALID)
10040 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10041 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10042 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10043 thrd_CloseHandle(phandle);
10046 lock_ReleaseMutex(&smb_StartedLock);
10049 void smb_RestartListeners(int locked)
10052 lock_ObtainMutex(&smb_StartedLock);
10054 if (powerStateSuspended)
10055 afsi_log("smb_RestartListeners called while suspended");
10057 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10058 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10059 if (smb_NetbiosInit(1))
10060 smb_StartListeners(1);
10061 } else if (smb_LanAdapterChangeDetected) {
10062 smb_LanAdapterChange(1);
10066 lock_ReleaseMutex(&smb_StartedLock);
10069 void smb_StopListener(NCB *ncbp, int lana, int wait)
10073 memset(ncbp, 0, sizeof(*ncbp));
10074 ncbp->ncb_command = NCBDELNAME;
10075 ncbp->ncb_lana_num = lana;
10076 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10077 code = Netbios(ncbp);
10079 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10080 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10082 /* and then reset the LANA; this will cause the listener threads to exit */
10083 ncbp->ncb_command = NCBRESET;
10084 ncbp->ncb_callname[0] = 100;
10085 ncbp->ncb_callname[2] = 100;
10086 ncbp->ncb_lana_num = lana;
10087 code = Netbios(ncbp);
10089 code = ncbp->ncb_retcode;
10091 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10093 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10097 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10100 void smb_StopListeners(int locked)
10106 lock_ObtainMutex(&smb_StartedLock);
10108 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10110 lock_ReleaseMutex(&smb_StartedLock);
10114 afsi_log("smb_StopListeners");
10115 smb_ListenerState = SMB_LISTENER_STOPPED;
10116 cm_VolStatus_Network_Stopped(cm_NetbiosName
10122 ncbp = smb_GetNCB();
10124 /* Unregister the SMB name */
10125 for (l = 0; l < lana_list.length; l++) {
10126 lana = lana_list.lana[l];
10128 if (lana != LANA_INVALID) {
10129 smb_StopListener(ncbp, lana, TRUE);
10131 /* mark the adapter invalid */
10132 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10136 /* force a re-evaluation of the network adapters */
10137 lana_list.length = 0;
10138 smb_LANadapter = LANA_INVALID;
10141 lock_ReleaseMutex(&smb_StartedLock);
10144 void smb_Init(osi_log_t *logp, int useV3,
10154 EVENT_HANDLE retHandle;
10155 char eventName[MAX_PATH];
10156 int startListeners = 0;
10158 smb_MBfunc = aMBfunc;
10162 /* Initialize smb_localZero */
10163 myTime.tm_isdst = -1; /* compute whether on DST or not */
10164 myTime.tm_year = 70;
10166 myTime.tm_mday = 1;
10167 myTime.tm_hour = 0;
10170 smb_localZero = mktime(&myTime);
10172 #ifdef AFS_FREELANCE_CLIENT
10173 /* Make sure the root.afs volume has the correct time */
10174 cm_noteLocalMountPointChange();
10177 /* initialize the remote debugging log */
10180 /* and the global lock */
10181 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10182 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10184 /* Raw I/O data structures */
10185 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10187 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10188 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10190 /* 4 Raw I/O buffers */
10191 smb_RawBufs = calloc(65536,1);
10192 *((char **)smb_RawBufs) = NULL;
10193 for (i=0; i<3; i++) {
10194 char *rawBuf = calloc(65536,1);
10195 *((char **)rawBuf) = smb_RawBufs;
10196 smb_RawBufs = rawBuf;
10199 /* global free lists */
10200 smb_ncbFreeListp = NULL;
10201 smb_packetFreeListp = NULL;
10203 lock_ObtainMutex(&smb_StartedLock);
10204 startListeners = smb_NetbiosInit(1);
10206 /* Initialize listener and server structures */
10208 memset(dead_sessions, 0, sizeof(dead_sessions));
10209 sprintf(eventName, "SessionEvents[0]");
10210 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10211 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10212 afsi_log("Event Object Already Exists: %s", eventName);
10214 smb_NumServerThreads = nThreads;
10215 sprintf(eventName, "NCBavails[0]");
10216 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10217 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10218 afsi_log("Event Object Already Exists: %s", eventName);
10219 sprintf(eventName, "NCBevents[0]");
10220 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10221 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10222 afsi_log("Event Object Already Exists: %s", eventName);
10223 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10224 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10225 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10226 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10227 afsi_log("Event Object Already Exists: %s", eventName);
10228 for (i = 0; i < smb_NumServerThreads; i++) {
10229 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10230 NCBreturns[i][0] = retHandle;
10233 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10234 for (i = 0; i < smb_NumServerThreads; i++) {
10235 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10236 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10237 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10238 afsi_log("Event Object Already Exists: %s", eventName);
10239 InitNCBslot((int)(i+1));
10241 numNCBs = smb_NumServerThreads + 1;
10243 /* Initialize dispatch table */
10244 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10245 /* Prepare the table for unknown operations */
10246 for(i=0; i<= SMB_NOPCODES; i++) {
10247 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10249 /* Fill in the ones we do know */
10250 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10251 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10252 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10253 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10254 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10255 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10256 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10257 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10258 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10259 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10260 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10261 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10262 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10263 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10264 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10265 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10266 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10267 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10268 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10269 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10270 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10271 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10272 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10273 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10274 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10275 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10276 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10277 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10278 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10279 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10280 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10281 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10282 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10283 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10284 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10285 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10286 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10287 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10288 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10289 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10290 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10291 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10292 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10293 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10294 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10295 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10296 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10297 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10298 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10299 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10300 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10301 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10302 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10303 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10304 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10305 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10306 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10307 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10308 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10309 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10310 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10311 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10312 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10313 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10314 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10315 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10316 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10317 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10318 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10319 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10320 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10321 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10322 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10323 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10325 /* setup tran 2 dispatch table */
10326 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10327 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10328 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10329 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10330 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10331 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10332 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10333 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10334 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10335 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10336 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10337 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10338 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10339 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10340 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10341 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10342 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10343 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10345 /* setup the rap dispatch table */
10346 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10347 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10348 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10349 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10350 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10354 /* if we are doing SMB authentication we have register outselves as a logon process */
10355 if (smb_authType != SMB_AUTH_NONE) {
10356 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10357 LSA_STRING afsProcessName;
10358 LSA_OPERATIONAL_MODE dummy; /*junk*/
10360 afsProcessName.Buffer = "OpenAFSClientDaemon";
10361 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10362 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10364 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10366 if (nts == STATUS_SUCCESS) {
10367 LSA_STRING packageName;
10368 /* we are registered. Find out the security package id */
10369 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10370 packageName.Length = (USHORT)strlen(packageName.Buffer);
10371 packageName.MaximumLength = packageName.Length + 1;
10372 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10373 if (nts == STATUS_SUCCESS) {
10375 * This code forces Windows to authenticate against the Logon Cache
10376 * first instead of attempting to authenticate against the Domain
10377 * Controller. When the Windows logon cache is enabled this improves
10378 * performance by removing the network access and works around a bug
10379 * seen at sites which are using a MIT Kerberos principal to login
10380 * to machines joined to a non-root domain in a multi-domain forest.
10381 * MsV1_0SetProcessOption was added in Windows XP.
10383 PVOID pResponse = NULL;
10384 ULONG cbResponse = 0;
10385 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10387 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10388 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10389 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10390 OptionsRequest.DisableOptions = FALSE;
10392 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10395 sizeof(OptionsRequest),
10401 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10402 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10405 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10407 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10408 afsi_log("MsV1_0SetProcessOption success");
10410 /* END - code from Larry */
10412 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10413 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10414 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10416 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10418 /* something went wrong. We report the error and revert back to no authentication
10419 because we can't perform any auth requests without a successful lsa handle
10420 or sec package id. */
10421 afsi_log("Reverting to NO SMB AUTH");
10422 smb_authType = SMB_AUTH_NONE;
10425 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10427 /* something went wrong. We report the error and revert back to no authentication
10428 because we can't perform any auth requests without a successful lsa handle
10429 or sec package id. */
10430 afsi_log("Reverting to NO SMB AUTH");
10431 smb_authType = SMB_AUTH_NONE;
10435 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10436 * time prevents the failure of authentication when logged into Windows with an
10437 * external Kerberos principal mapped to a local account.
10439 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10440 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10441 * then the only option is NTLMSSP anyway; so just fallback.
10446 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10447 if (secBlobLength == 0) {
10448 smb_authType = SMB_AUTH_NTLM;
10449 afsi_log("Reverting to SMB AUTH NTLM");
10458 /* Now get ourselves a domain name. */
10459 /* For now we are using the local computer name as the domain name.
10460 * It is actually the domain for local logins, and we are acting as
10461 * a local SMB server.
10463 bufsize = lengthof(smb_ServerDomainName) - 1;
10464 GetComputerNameW(smb_ServerDomainName, &bufsize);
10465 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10466 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10469 /* Start listeners, waiters, servers, and daemons */
10470 if (startListeners)
10471 smb_StartListeners(1);
10473 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10474 NULL, 0, &lpid, "smb_ClientWaiter");
10475 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10476 thrd_CloseHandle(phandle);
10478 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10479 NULL, 0, &lpid, "smb_ServerWaiter");
10480 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10481 thrd_CloseHandle(phandle);
10483 for (i=0; i<smb_NumServerThreads; i++) {
10484 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10485 (void *) i, 0, &lpid, "smb_Server");
10486 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10487 thrd_CloseHandle(phandle);
10490 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10491 NULL, 0, &lpid, "smb_Daemon");
10492 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10493 thrd_CloseHandle(phandle);
10495 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10496 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10497 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10498 thrd_CloseHandle(phandle);
10500 lock_ReleaseMutex(&smb_StartedLock);
10504 void smb_Shutdown(void)
10511 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10513 /* setup the NCB system */
10514 ncbp = smb_GetNCB();
10516 /* Block new sessions by setting shutdown flag */
10517 smbShutdownFlag = 1;
10519 /* Hang up all sessions */
10520 memset((char *)ncbp, 0, sizeof(NCB));
10521 for (i = 1; i < numSessions; i++)
10523 if (dead_sessions[i])
10526 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10527 ncbp->ncb_command = NCBHANGUP;
10528 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10529 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10530 code = Netbios(ncbp);
10531 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10532 if (code == 0) code = ncbp->ncb_retcode;
10534 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10535 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10539 /* Trigger the shutdown of all SMB threads */
10540 for (i = 0; i < smb_NumServerThreads; i++)
10541 thrd_SetEvent(NCBreturns[i][0]);
10543 thrd_SetEvent(NCBevents[0]);
10544 thrd_SetEvent(SessionEvents[0]);
10545 thrd_SetEvent(NCBavails[0]);
10547 for (i = 0;i < smb_NumServerThreads; i++) {
10548 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10549 if (code == WAIT_OBJECT_0) {
10552 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10553 thrd_SetEvent(NCBreturns[i--][0]);
10557 /* Delete Netbios name */
10558 memset((char *)ncbp, 0, sizeof(NCB));
10559 for (i = 0; i < lana_list.length; i++) {
10560 if (lana_list.lana[i] == LANA_INVALID) continue;
10561 ncbp->ncb_command = NCBDELNAME;
10562 ncbp->ncb_lana_num = lana_list.lana[i];
10563 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10564 code = Netbios(ncbp);
10566 code = ncbp->ncb_retcode;
10568 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10569 ncbp->ncb_lana_num, code);
10574 /* Release the reference counts held by the VCs */
10575 lock_ObtainWrite(&smb_rctLock);
10576 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10581 if (vcp->magic != SMB_VC_MAGIC)
10582 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10583 __FILE__, __LINE__);
10585 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10587 if (fidp->scp != NULL) {
10590 lock_ReleaseWrite(&smb_rctLock);
10591 lock_ObtainMutex(&fidp->mx);
10592 if (fidp->scp != NULL) {
10595 lock_ObtainWrite(&scp->rw);
10596 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10597 lock_ReleaseWrite(&scp->rw);
10598 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10599 cm_ReleaseSCache(scp);
10601 lock_ReleaseMutex(&fidp->mx);
10602 lock_ObtainWrite(&smb_rctLock);
10606 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10608 smb_ReleaseVCNoLock(tidp->vcp);
10610 cm_user_t *userp = tidp->userp;
10611 tidp->userp = NULL;
10612 cm_ReleaseUser(userp);
10616 lock_ReleaseWrite(&smb_rctLock);
10620 /* Get the UNC \\<servername>\<sharename> prefix. */
10621 char *smb_GetSharename()
10626 /* Make sure we have been properly initialized. */
10627 if (smb_localNamep == NULL)
10630 /* Allocate space for \\<servername>\<sharename>, plus the
10633 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10634 name = malloc(len);
10635 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10641 void smb_LogPacket(smb_packet_t *packet)
10645 unsigned length, paramlen, datalen, i, j;
10647 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10649 if (!packet) return;
10651 osi_Log0(smb_logp, "*** SMB packet dump ***");
10653 smbp = (smb_t *) packet->data;
10654 vp = (BYTE *) packet->data;
10656 paramlen = smbp->wct * 2;
10657 datalen = *((WORD *) (smbp->vdata + paramlen));
10658 length = sizeof(*smbp) + paramlen + 1 + datalen;
10660 for (i=0;i < length; i+=16)
10662 memset( buf, ' ', 80 );
10665 itoa( i, buf, 16 );
10667 buf[strlen(buf)] = ' ';
10669 cp = (BYTE*) buf + 7;
10671 for (j=0;j < 16 && (i+j)<length; j++)
10673 *(cp++) = hex[vp[i+j] >> 4];
10674 *(cp++) = hex[vp[i+j] & 0xf];
10684 for (j=0;j < 16 && (i+j)<length;j++)
10686 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10697 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10700 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10702 #endif /* LOG_PACKET */
10705 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10711 smb_username_t *unp;
10712 smb_waitingLockRequest_t *wlrp;
10715 lock_ObtainRead(&smb_rctLock);
10717 sprintf(output, "begin dumping smb_username_t\r\n");
10718 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10719 for (unp = usernamesp; unp; unp=unp->nextp)
10721 cm_ucell_t *ucellp;
10723 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10724 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10725 unp->name ? unp->name : _C("NULL"),
10726 unp->machine ? unp->machine : _C("NULL"));
10727 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10729 sprintf(output, " begin dumping cm_ucell_t\r\n");
10730 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10732 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10733 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",
10734 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10735 ucellp->expirationTime, ucellp->gen,
10737 ucellp->cellp->name);
10738 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10741 sprintf(output, " done dumping cm_ucell_t\r\n");
10742 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10745 sprintf(output, "done dumping smb_username_t\r\n");
10746 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10749 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10750 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10753 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10754 smb_waitingLock_t *lockp;
10756 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10757 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10758 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10760 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10761 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10762 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10763 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10764 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10765 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10767 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10768 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10771 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10772 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10774 sprintf(output, "begin dumping smb_vc_t\r\n");
10775 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10777 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10783 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10784 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10785 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10787 sprintf(output, " begin dumping smb_user_t\r\n");
10788 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10789 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10790 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10791 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10792 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10794 sprintf(output, " done dumping smb_user_t\r\n");
10795 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10797 sprintf(output, " begin dumping smb_tid_t\r\n");
10798 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10799 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10800 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",
10801 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10802 tidp->pathname ? tidp->pathname : _C("NULL"));
10803 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10805 sprintf(output, " done dumping smb_tid_t\r\n");
10806 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10808 sprintf(output, " begin dumping smb_fid_t\r\n");
10809 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10811 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10813 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",
10814 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10815 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10816 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10817 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10820 sprintf(output, " done dumping smb_fid_t\r\n");
10821 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10824 sprintf(output, "done dumping smb_vc_t\r\n");
10825 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10827 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10828 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10830 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10836 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10837 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10838 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10840 sprintf(output, " begin dumping smb_user_t\r\n");
10841 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10842 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10843 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10844 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10845 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10847 sprintf(output, " done dumping smb_user_t\r\n");
10848 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10850 sprintf(output, " begin dumping smb_tid_t\r\n");
10851 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10852 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10853 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",
10854 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10855 tidp->pathname ? tidp->pathname : _C("NULL"));
10856 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10858 sprintf(output, " done dumping smb_tid_t\r\n");
10859 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10861 sprintf(output, " begin dumping smb_fid_t\r\n");
10862 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10864 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10866 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",
10867 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10868 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10869 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10870 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10873 sprintf(output, " done dumping smb_fid_t\r\n");
10874 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10877 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10878 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10881 lock_ReleaseRead(&smb_rctLock);
10885 long smb_IsNetworkStarted(void)
10888 lock_ObtainWrite(&smb_globalLock);
10889 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10890 lock_ReleaseWrite(&smb_globalLock);