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 & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
486 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
488 if ((scp->unixModeBits & 0200) == 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)
1422 if (!(flags & SMB_FLAG_CREATE))
1427 lock_ObtainWrite(&smb_rctLock);
1429 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);
1439 * We dropped the smb_rctLock so the fid value we are using
1440 * may now be used by another thread. Start over with the
1441 * current vcp->fidCounter.
1444 fid = vcp->fidCounter;
1447 if (fid == fidp->fid) {
1449 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1451 if (fid == 0xFFFF) {
1453 "New FID number wraps on vcp 0x%x", vcp);
1463 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1464 char eventName[MAX_PATH];
1468 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1470 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1472 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1473 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1474 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1475 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1476 thrd_CloseHandle(event);
1478 if (fid == 0xFFFF) {
1479 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1485 fidp = malloc(sizeof(*fidp));
1486 memset(fidp, 0, sizeof(*fidp));
1487 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1490 smb_HoldVCNoLock(vcp);
1491 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1493 fidp->curr_chunk = fidp->prev_chunk = -2;
1494 fidp->raw_write_event = event;
1496 vcp->fidCounter = fid+1;
1497 if (vcp->fidCounter == 0xFFFF) {
1498 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1500 vcp->fidCounter = 1;
1505 #ifdef DEBUG_SMB_REFCOUNT
1507 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1508 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1511 lock_ReleaseWrite(&smb_rctLock);
1516 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1517 #ifdef DEBUG_SMB_REFCOUNT
1518 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1520 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1523 smb_fid_t *fidp = NULL, *nextp = NULL;
1529 * If the fidp->scp changes out from under us then
1530 * we must not grab a refCount. It means the *fidp
1531 * was processed by smb_CloseFID() and the *fidp is
1532 * no longer valid for use.
1534 lock_ObtainWrite(&smb_rctLock);
1535 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1536 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1540 if (scp == fidp->scp) {
1541 lock_ReleaseWrite(&smb_rctLock);
1542 lock_ObtainMutex(&fidp->mx);
1543 lock_ObtainWrite(&smb_rctLock);
1544 if (scp == fidp->scp) {
1545 lock_ReleaseMutex(&fidp->mx);
1548 lock_ReleaseMutex(&fidp->mx);
1551 if (fidp->refCount > 1) {
1554 lock_ReleaseWrite(&smb_rctLock);
1555 smb_ReleaseFID(fidp);
1556 lock_ObtainWrite(&smb_rctLock);
1561 if (nextp->refCount > 1) {
1564 lock_ReleaseWrite(&smb_rctLock);
1565 smb_ReleaseFID(nextp);
1566 lock_ObtainWrite(&smb_rctLock);
1570 #ifdef DEBUG_SMB_REFCOUNT
1572 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1573 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1576 lock_ReleaseWrite(&smb_rctLock);
1580 #ifdef DEBUG_SMB_REFCOUNT
1581 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1583 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1586 lock_AssertWrite(&smb_rctLock);
1588 #ifdef DEBUG_SMB_REFCOUNT
1589 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1590 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1596 /* the smb_fid_t->mx and smb_rctLock must not be held */
1597 #ifdef DEBUG_SMB_REFCOUNT
1598 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1600 void smb_ReleaseFID(smb_fid_t *fidp)
1603 cm_scache_t *scp = NULL;
1604 cm_user_t *userp = NULL;
1605 smb_vc_t *vcp = NULL;
1606 smb_ioctl_t *ioctlp;
1608 lock_ObtainMutex(&fidp->mx);
1609 lock_ObtainWrite(&smb_rctLock);
1610 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1611 #ifdef DEBUG_SMB_REFCOUNT
1612 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1613 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1615 if (fidp->refCount == 0) {
1616 if (fidp->deleteOk) {
1619 scp = fidp->scp; /* release after lock is released */
1621 lock_ObtainWrite(&scp->rw);
1622 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1623 lock_ReleaseWrite(&scp->rw);
1624 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1627 userp = fidp->userp;
1631 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1632 thrd_CloseHandle(fidp->raw_write_event);
1634 /* and see if there is ioctl stuff to free */
1635 ioctlp = fidp->ioctlp;
1638 cm_FreeSpace(ioctlp->prefix);
1639 if (ioctlp->ioctl.inAllocp)
1640 free(ioctlp->ioctl.inAllocp);
1641 if (ioctlp->ioctl.outAllocp)
1642 free(ioctlp->ioctl.outAllocp);
1646 smb_CleanupRPCFid(fidp);
1648 lock_ReleaseMutex(&fidp->mx);
1649 lock_FinalizeMutex(&fidp->mx);
1654 smb_ReleaseVCNoLock(vcp);
1658 lock_ReleaseMutex(&fidp->mx);
1660 lock_ReleaseWrite(&smb_rctLock);
1662 /* now release the scache structure */
1664 cm_ReleaseSCache(scp);
1667 cm_ReleaseUser(userp);
1671 * Case-insensitive search for one string in another;
1672 * used to find variable names in submount pathnames.
1674 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1676 clientchar_t *cursor;
1678 for (cursor = str1; *cursor; cursor++)
1679 if (cm_ClientStrCmpI(cursor, str2) == 0)
1686 * Substitute a variable value for its name in a submount pathname. Variable
1687 * name has been identified by smb_stristr() and is in substr. Variable name
1688 * length (plus one) is in substr_size. Variable value is in newstr.
1690 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1691 unsigned int substr_size, clientchar_t *newstr)
1693 clientchar_t temp[1024];
1695 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1696 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1697 cm_ClientStrCat(str1, cchstr1, temp);
1700 clientchar_t VNUserName[] = _C("%USERNAME%");
1701 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1702 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1703 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1705 typedef struct smb_findShare_rock {
1706 clientchar_t * shareName;
1707 clientchar_t * match;
1709 } smb_findShare_rock_t;
1711 #define SMB_FINDSHARE_EXACT_MATCH 1
1712 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1714 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1718 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1719 normchar_t normName[MAX_PATH];
1721 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1722 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1723 osi_LogSaveString(smb_logp, dep->name));
1727 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1728 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1729 matchType = SMB_FINDSHARE_EXACT_MATCH;
1731 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1734 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1735 vrock->matchType = matchType;
1737 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1738 return CM_ERROR_STOPNOW;
1744 /* find a shareName in the table of submounts */
1745 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1746 clientchar_t *shareName,
1747 clientchar_t **pathNamep)
1751 clientchar_t pathName[1024];
1754 clientchar_t *p, *q;
1755 fschar_t *cellname = NULL;
1758 DWORD allSubmount = 1;
1760 /* if allSubmounts == 0, only return the //mountRoot/all share
1761 * if in fact it has been been created in the subMounts table.
1762 * This is to allow sites that want to restrict access to the
1765 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1766 0, KEY_QUERY_VALUE, &parmKey);
1767 if (code == ERROR_SUCCESS) {
1768 cblen = sizeof(allSubmount);
1769 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1770 (BYTE *) &allSubmount, &cblen);
1771 if (code != ERROR_SUCCESS) {
1774 RegCloseKey (parmKey);
1777 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1782 /* In case, the all share is disabled we need to still be able
1783 * to handle ioctl requests
1785 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1786 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1790 if (MSRPC_IsWellKnownService(shareName) ||
1791 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1792 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1798 /* Check for volume references
1800 * They look like <cell>{%,#}<volume>
1802 if (cm_ClientStrChr(shareName, '%') != NULL ||
1803 cm_ClientStrChr(shareName, '#') != NULL) {
1804 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1805 /* make room for '/@vol:' + mountchar + NULL terminator*/
1807 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1808 osi_LogSaveClientString(smb_logp, shareName));
1810 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1811 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1812 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1814 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1816 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1817 cm_ClientStrLwr(*pathNamep);
1818 osi_Log1(smb_logp, " returning pathname [%S]",
1819 osi_LogSaveClientString(smb_logp, *pathNamep));
1827 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1828 0, KEY_QUERY_VALUE, &parmKey);
1829 if (code == ERROR_SUCCESS) {
1830 cblen = sizeof(pathName);
1831 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1832 (BYTE *) pathName, &cblen);
1833 if (code != ERROR_SUCCESS)
1835 RegCloseKey (parmKey);
1839 cchlen = cblen / sizeof(clientchar_t);
1840 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1841 /* We can accept either unix or PC style AFS pathnames. Convert
1842 * Unix-style to PC style here for internal use.
1845 cchlen = lengthof(pathName);
1847 /* within this code block, we maintain, cchlen = writeable
1848 buffer length of p */
1850 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1851 p += cm_mountRootCLen; /* skip mount path */
1852 cchlen -= (DWORD)(p - pathName);
1857 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1863 clientchar_t temp[1024];
1865 if (var = smb_stristr(p, VNUserName)) {
1866 if (uidp && uidp->unp)
1867 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1869 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1871 else if (var = smb_stristr(p, VNLCUserName))
1873 if (uidp && uidp->unp)
1874 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1876 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1877 cm_ClientStrLwr(temp);
1878 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1880 else if (var = smb_stristr(p, VNComputerName))
1882 sizeTemp = lengthof(temp);
1883 GetComputerNameW(temp, &sizeTemp);
1884 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1886 else if (var = smb_stristr(p, VNLCComputerName))
1888 sizeTemp = lengthof(temp);
1889 GetComputerName((LPTSTR)temp, &sizeTemp);
1890 cm_ClientStrLwr(temp);
1891 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1896 *pathNamep = cm_ClientStrDup(p);
1901 /* First lookup shareName in root.afs */
1903 smb_findShare_rock_t vrock;
1905 fschar_t ftemp[1024];
1906 clientchar_t * p = shareName;
1909 /* attempt to locate a partial match in root.afs. This is because
1910 when using the ANSI RAP calls, the share name is limited to 13 chars
1911 and hence is truncated. Of course we prefer exact matches. */
1913 thyper.HighPart = 0;
1916 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1917 if (vrock.shareName == NULL)
1920 vrock.matchType = 0;
1922 cm_HoldSCache(cm_data.rootSCachep);
1923 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1924 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1925 cm_ReleaseSCache(cm_data.rootSCachep);
1927 free(vrock.shareName);
1928 vrock.shareName = NULL;
1930 if (vrock.matchType) {
1931 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1932 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1937 /* if we get here, there was no match for the share in root.afs */
1938 /* so try to create \\<netbiosName>\<cellname> */
1943 /* Get the full name for this cell */
1944 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1945 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
1946 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
1947 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1948 #ifdef AFS_AFSDB_ENV
1949 if (code && cm_dnsEnabled) {
1951 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1953 #endif /* AFS_AFSDB_ENV */
1957 /* construct the path */
1959 clientchar_t temp[1024];
1961 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
1962 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
1963 rw ? _C("/.%S/") : _C("/%S/"), temp);
1964 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1974 /* Client-side offline caching policy types */
1975 #define CSC_POLICY_MANUAL 0
1976 #define CSC_POLICY_DOCUMENTS 1
1977 #define CSC_POLICY_PROGRAMS 2
1978 #define CSC_POLICY_DISABLE 3
1980 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1983 clientchar_t policy[1024];
1986 int retval = CSC_POLICY_MANUAL;
1988 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1989 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1992 REG_OPTION_NON_VOLATILE,
1996 NULL ) != ERROR_SUCCESS)
1997 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1999 len = sizeof(policy);
2000 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2002 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2004 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2006 retval = CSC_POLICY_MANUAL;
2008 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2010 retval = CSC_POLICY_DOCUMENTS;
2012 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2014 retval = CSC_POLICY_PROGRAMS;
2016 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2018 retval = CSC_POLICY_DISABLE;
2021 RegCloseKey(hkCSCPolicy);
2025 /* find a dir search structure by cookie value, and return it held.
2026 * Must be called with smb_globalLock held.
2028 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2030 smb_dirSearch_t *dsp;
2032 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2033 if (dsp->cookie == cookie) {
2034 if (dsp != smb_firstDirSearchp) {
2035 /* move to head of LRU queue, too, if we're not already there */
2036 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2037 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2038 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2039 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2040 if (!smb_lastDirSearchp)
2041 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2049 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2050 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2051 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2057 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2059 lock_ObtainMutex(&dsp->mx);
2060 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2061 dsp->cookie, dsp, dsp->scp);
2062 dsp->flags |= SMB_DIRSEARCH_DELETE;
2063 if (dsp->scp != NULL) {
2064 lock_ObtainWrite(&dsp->scp->rw);
2065 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2066 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2067 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2068 dsp->scp->bulkStatProgress = hzero;
2070 lock_ReleaseWrite(&dsp->scp->rw);
2072 lock_ReleaseMutex(&dsp->mx);
2075 /* Must be called with the smb_globalLock held */
2076 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2078 cm_scache_t *scp = NULL;
2080 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2081 if (dsp->refCount == 0) {
2082 lock_ObtainMutex(&dsp->mx);
2083 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2084 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2085 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2086 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2087 lock_ReleaseMutex(&dsp->mx);
2088 lock_FinalizeMutex(&dsp->mx);
2090 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2091 dsp->cookie, dsp, scp);
2094 lock_ReleaseMutex(&dsp->mx);
2097 /* do this now to avoid spurious locking hierarchy creation */
2099 cm_ReleaseSCache(scp);
2102 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2104 lock_ObtainWrite(&smb_globalLock);
2105 smb_ReleaseDirSearchNoLock(dsp);
2106 lock_ReleaseWrite(&smb_globalLock);
2109 /* find a dir search structure by cookie value, and return it held */
2110 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2112 smb_dirSearch_t *dsp;
2114 lock_ObtainWrite(&smb_globalLock);
2115 dsp = smb_FindDirSearchNoLock(cookie);
2116 lock_ReleaseWrite(&smb_globalLock);
2120 /* GC some dir search entries, in the address space expected by the specific protocol.
2121 * Must be called with smb_globalLock held; release the lock temporarily.
2123 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2124 void smb_GCDirSearches(int isV3)
2126 smb_dirSearch_t *prevp;
2127 smb_dirSearch_t *dsp;
2128 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2132 victimCount = 0; /* how many have we got so far */
2133 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2134 /* we'll move tp from queue, so
2137 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2138 /* if no one is using this guy, and we're either in the new protocol,
2139 * or we're in the old one and this is a small enough ID to be useful
2140 * to the old protocol, GC this guy.
2142 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2143 /* hold and delete */
2144 lock_ObtainMutex(&dsp->mx);
2145 dsp->flags |= SMB_DIRSEARCH_DELETE;
2146 lock_ReleaseMutex(&dsp->mx);
2147 victimsp[victimCount++] = dsp;
2151 /* don't do more than this */
2152 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2156 /* now release them */
2157 for (i = 0; i < victimCount; i++) {
2158 smb_ReleaseDirSearchNoLock(victimsp[i]);
2162 /* function for allocating a dir search entry. We need these to remember enough context
2163 * since we don't get passed the path from call to call during a directory search.
2165 * Returns a held dir search structure, and bumps the reference count on the vnode,
2166 * since it saves a pointer to the vnode.
2168 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2170 smb_dirSearch_t *dsp;
2176 lock_ObtainWrite(&smb_globalLock);
2179 /* what's the biggest ID allowed in this version of the protocol */
2180 /* TODO: do we really want a non v3 dir search request to wrap
2181 smb_dirSearchCounter? */
2182 maxAllowed = isV3 ? 65535 : 255;
2183 if (smb_dirSearchCounter > maxAllowed)
2184 smb_dirSearchCounter = 1;
2186 start = smb_dirSearchCounter;
2189 /* twice so we have enough tries to find guys we GC after one pass;
2190 * 10 extra is just in case I mis-counted.
2192 if (++counter > 2*maxAllowed+10)
2193 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2195 if (smb_dirSearchCounter > maxAllowed) {
2196 smb_dirSearchCounter = 1;
2198 if (smb_dirSearchCounter == start) {
2200 smb_GCDirSearches(isV3);
2203 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2205 /* don't need to watch for refcount zero and deleted, since
2206 * we haven't dropped the global lock.
2209 ++smb_dirSearchCounter;
2213 dsp = malloc(sizeof(*dsp));
2214 memset(dsp, 0, sizeof(*dsp));
2215 dsp->cookie = smb_dirSearchCounter;
2216 ++smb_dirSearchCounter;
2218 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2219 dsp->lastTime = osi_Time();
2220 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2221 if (!smb_lastDirSearchp)
2222 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2224 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2228 lock_ReleaseWrite(&smb_globalLock);
2232 static smb_packet_t *smb_GetPacket(void)
2236 lock_ObtainWrite(&smb_globalLock);
2237 tbp = smb_packetFreeListp;
2239 smb_packetFreeListp = tbp->nextp;
2240 lock_ReleaseWrite(&smb_globalLock);
2242 tbp = calloc(sizeof(*tbp),1);
2243 tbp->magic = SMB_PACKETMAGIC;
2246 tbp->resumeCode = 0;
2252 tbp->ncb_length = 0;
2255 tbp->stringsp = NULL;
2257 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2262 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2265 tbp = smb_GetPacket();
2266 memcpy(tbp, pkt, sizeof(smb_packet_t));
2267 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2268 tbp->stringsp = NULL;
2270 smb_HoldVC(tbp->vcp);
2274 static NCB *smb_GetNCB(void)
2279 lock_ObtainWrite(&smb_globalLock);
2280 tbp = smb_ncbFreeListp;
2282 smb_ncbFreeListp = tbp->nextp;
2283 lock_ReleaseWrite(&smb_globalLock);
2285 tbp = calloc(sizeof(*tbp),1);
2286 tbp->magic = SMB_NCBMAGIC;
2289 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2291 memset(&tbp->ncb, 0, sizeof(NCB));
2296 static void FreeSMBStrings(smb_packet_t * pkt)
2301 for (s = pkt->stringsp; s; s = ns) {
2305 pkt->stringsp = NULL;
2308 void smb_FreePacket(smb_packet_t *tbp)
2310 smb_vc_t * vcp = NULL;
2311 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2313 lock_ObtainWrite(&smb_globalLock);
2314 tbp->nextp = smb_packetFreeListp;
2315 smb_packetFreeListp = tbp;
2316 tbp->magic = SMB_PACKETMAGIC;
2320 tbp->resumeCode = 0;
2326 tbp->ncb_length = 0;
2328 FreeSMBStrings(tbp);
2329 lock_ReleaseWrite(&smb_globalLock);
2335 static void smb_FreeNCB(NCB *bufferp)
2339 tbp = (smb_ncb_t *) bufferp;
2340 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2342 lock_ObtainWrite(&smb_globalLock);
2343 tbp->nextp = smb_ncbFreeListp;
2344 smb_ncbFreeListp = tbp;
2345 lock_ReleaseWrite(&smb_globalLock);
2348 /* get a ptr to the data part of a packet, and its count */
2349 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2353 unsigned char *afterParmsp;
2355 parmBytes = *smbp->wctp << 1;
2356 afterParmsp = smbp->wctp + parmBytes + 1;
2358 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2359 if (nbytesp) *nbytesp = dataBytes;
2361 /* don't forget to skip the data byte count, since it follows
2362 * the parameters; that's where the "2" comes from below.
2364 return (unsigned char *) (afterParmsp + 2);
2367 /* must set all the returned parameters before playing around with the
2368 * data region, since the data region is located past the end of the
2369 * variable number of parameters.
2371 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2373 unsigned char *afterParmsp;
2375 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2377 *afterParmsp++ = dsize & 0xff;
2378 *afterParmsp = (dsize>>8) & 0xff;
2381 /* return the parm'th parameter in the smbp packet */
2382 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2385 unsigned char *parmDatap;
2387 parmCount = *smbp->wctp;
2389 if (parm >= parmCount) {
2392 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2393 parm, parmCount, smbp->ncb_length);
2394 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2395 parm, parmCount, smbp->ncb_length);
2396 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2397 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2398 osi_panic(s, __FILE__, __LINE__);
2400 parmDatap = smbp->wctp + (2*parm) + 1;
2402 return parmDatap[0] + (parmDatap[1] << 8);
2405 /* return the parm'th parameter in the smbp packet */
2406 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2409 unsigned char *parmDatap;
2411 parmCount = *smbp->wctp;
2413 if (parm >= parmCount) {
2416 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2417 parm, parmCount, smbp->ncb_length);
2418 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2419 parm, parmCount, smbp->ncb_length);
2420 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2421 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2422 osi_panic(s, __FILE__, __LINE__);
2424 parmDatap = smbp->wctp + (2*parm) + 1;
2426 return parmDatap[0];
2429 /* return the parm'th parameter in the smbp packet */
2430 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2433 unsigned char *parmDatap;
2435 parmCount = *smbp->wctp;
2437 if (parm + 1 >= parmCount) {
2440 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2441 parm, parmCount, smbp->ncb_length);
2442 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2443 parm, parmCount, smbp->ncb_length);
2444 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2445 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2446 osi_panic(s, __FILE__, __LINE__);
2448 parmDatap = smbp->wctp + (2*parm) + 1;
2450 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2453 /* return the parm'th parameter in the smbp packet */
2454 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2457 unsigned char *parmDatap;
2459 parmCount = *smbp->wctp;
2461 if (parm * 2 + offset >= parmCount * 2) {
2464 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2465 parm, offset, parmCount, smbp->ncb_length);
2466 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2467 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2468 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2469 parm, offset, parmCount, smbp->ncb_length);
2470 osi_panic(s, __FILE__, __LINE__);
2472 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2474 return parmDatap[0] + (parmDatap[1] << 8);
2477 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2479 unsigned char *parmDatap;
2481 /* make sure we have enough slots */
2482 if (*smbp->wctp <= slot)
2483 *smbp->wctp = slot+1;
2485 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2486 *parmDatap++ = parmValue & 0xff;
2487 *parmDatap = (parmValue>>8) & 0xff;
2490 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2492 unsigned char *parmDatap;
2494 /* make sure we have enough slots */
2495 if (*smbp->wctp <= slot)
2496 *smbp->wctp = slot+2;
2498 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2499 *parmDatap++ = parmValue & 0xff;
2500 *parmDatap++ = (parmValue>>8) & 0xff;
2501 *parmDatap++ = (parmValue>>16) & 0xff;
2502 *parmDatap = (parmValue>>24) & 0xff;
2505 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2507 unsigned char *parmDatap;
2510 /* make sure we have enough slots */
2511 if (*smbp->wctp <= slot)
2512 *smbp->wctp = slot+4;
2514 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2516 *parmDatap++ = *parmValuep++;
2519 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2521 unsigned char *parmDatap;
2523 /* make sure we have enough slots */
2524 if (*smbp->wctp <= slot) {
2525 if (smbp->oddByte) {
2527 *smbp->wctp = slot+1;
2532 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2533 *parmDatap++ = parmValue & 0xff;
2538 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2539 clientchar_t *inPathp)
2541 clientchar_t *lastSlashp;
2542 clientchar_t *streamp = NULL;
2543 clientchar_t *typep = NULL;
2545 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2546 if (lastComponentp) {
2547 *lastComponentp = lastSlashp;
2551 * If the name contains a stream name and a type
2552 * and the stream name is the nul-string and the
2553 * type is $DATA, then strip "::$DATA" from the
2554 * last component string that is returned.
2556 * Otherwise, return the full path name and allow
2557 * the file name to be rejected because it contains
2560 typep = cm_ClientStrRChr(lastSlashp, L':');
2561 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2563 streamp = cm_ClientStrRChr(lastSlashp, L':');
2564 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2568 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2569 osi_LogSaveClientString(smb_logp,streamp),
2570 osi_LogSaveClientString(smb_logp,typep));
2574 if (inPathp == lastSlashp)
2576 *outPathp++ = *inPathp++;
2585 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2586 char **chainpp, int flags)
2589 afs_uint32 type = *inp++;
2592 * The first byte specifies the type of the input string.
2593 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2597 /* Length Counted */
2598 case 0x1: /* Data Block */
2599 case 0x5: /* Variable Block */
2600 cb = *inp++ << 16 | *inp++;
2603 /* Null-terminated string */
2604 case 0x4: /* ASCII */
2605 case 0x3: /* Pathname */
2606 case 0x2: /* Dialect */
2607 cb = sizeof(pktp->data) - (inp - pktp->data);
2608 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2609 #ifdef DEBUG_UNICODE
2612 cb = sizeof(pktp->data);
2617 return NULL; /* invalid input */
2621 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2622 flags |= SMB_STRF_FORCEASCII;
2625 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2628 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2629 char ** chainpp, int flags)
2634 if (!WANTS_UNICODE(pktp))
2635 flags |= SMB_STRF_FORCEASCII;
2638 cb = sizeof(pktp->data) - (inp - pktp->data);
2639 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2640 #ifdef DEBUG_UNICODE
2643 cb = sizeof(pktp->data);
2645 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2646 flags | SMB_STRF_SRCNULTERM);
2649 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2650 size_t cb, char ** chainpp, int flags)
2653 if (!WANTS_UNICODE(pktp))
2654 flags |= SMB_STRF_FORCEASCII;
2657 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2660 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2661 size_t cch, char ** chainpp, int flags)
2666 if (!WANTS_UNICODE(pktp))
2667 flags |= SMB_STRF_FORCEASCII;
2669 cb = cch * sizeof(wchar_t);
2672 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2676 smb_ParseStringBuf(const unsigned char * bufbase,
2677 cm_space_t ** stringspp,
2678 unsigned char *inp, size_t *pcb_max,
2679 char **chainpp, int flags)
2682 if (!(flags & SMB_STRF_FORCEASCII)) {
2684 cm_space_t * spacep;
2687 if (bufbase && ((inp - bufbase) % 2) != 0) {
2688 inp++; /* unicode strings are always word aligned */
2692 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2694 cch_src = *pcb_max / sizeof(wchar_t);
2698 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2705 spacep = cm_GetSpace();
2706 spacep->nextp = *stringspp;
2707 *stringspp = spacep;
2711 *chainpp = inp + sizeof(wchar_t);
2714 *(spacep->wdata) = 0;
2715 return spacep->wdata;
2718 StringCchCopyNW(spacep->wdata,
2719 lengthof(spacep->wdata),
2720 (const clientchar_t *) inp, cch_src);
2723 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2725 return spacep->wdata;
2729 cm_space_t * spacep;
2732 /* Not using Unicode */
2734 *chainpp = inp + strlen(inp) + 1;
2737 spacep = cm_GetSpace();
2738 spacep->nextp = *stringspp;
2739 *stringspp = spacep;
2741 cchdest = lengthof(spacep->wdata);
2742 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2743 spacep->wdata, cchdest);
2745 return spacep->wdata;
2751 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2753 size_t * plen, int flags)
2759 /* we are only calculating the required size */
2766 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2768 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2769 if (!(flags & SMB_STRF_IGNORENUL))
2770 *plen += sizeof(wchar_t);
2772 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2782 cch_str = cm_ClientStrLen(str);
2783 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2786 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2794 /* if outp != NULL ... */
2796 /* Number of bytes left in the buffer.
2798 If outp lies inside the packet data buffer, we assume that the
2799 buffer is the packet data buffer. Otherwise we assume that the
2800 buffer is sizeof(packet->data).
2803 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2804 align = (int)((outp - pktp->data) % 2);
2805 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2807 align = (int)(((size_t) outp) % 2);
2808 buffersize = (int)sizeof(pktp->data);
2813 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2819 if (*str == _C('\0')) {
2821 if (buffersize < sizeof(wchar_t))
2824 *((wchar_t *) outp) = L'\0';
2825 if (plen && !(flags & SMB_STRF_IGNORENUL))
2826 *plen += sizeof(wchar_t);
2827 return outp + sizeof(wchar_t);
2830 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2832 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2833 osi_LogSaveClientString(smb_logp, str),
2839 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2841 return outp + sizeof(wchar_t) * nchars;
2849 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2852 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2854 return outp + cch_dest;
2858 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2864 tlen = inp[0] + (inp[1]<<8);
2865 inp += 2; /* skip length field */
2868 *chainpp = inp + tlen;
2877 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2881 if (*inp++ != 0x1) return NULL;
2882 tlen = inp[0] + (inp[1]<<8);
2883 inp += 2; /* skip length field */
2886 *chainpp = inp + tlen;
2889 if (lengthp) *lengthp = tlen;
2894 /* format a packet as a response */
2895 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2900 outp = (smb_t *) op;
2902 /* zero the basic structure through the smb_wct field, and zero the data
2903 * size field, assuming that wct stays zero; otherwise, you have to
2904 * explicitly set the data size field, too.
2906 inSmbp = (smb_t *) inp;
2907 memset(outp, 0, sizeof(smb_t)+2);
2913 outp->com = inSmbp->com;
2914 outp->tid = inSmbp->tid;
2915 outp->pid = inSmbp->pid;
2916 outp->uid = inSmbp->uid;
2917 outp->mid = inSmbp->mid;
2918 outp->res[0] = inSmbp->res[0];
2919 outp->res[1] = inSmbp->res[1];
2920 op->inCom = inSmbp->com;
2922 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2923 #ifdef SEND_CANONICAL_PATHNAMES
2924 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2926 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2928 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2929 outp->flg2 |= SMB_FLAGS2_UNICODE;
2932 /* copy fields in generic packet area */
2933 op->wctp = &outp->wct;
2936 /* send a (probably response) packet; vcp tells us to whom to send it.
2937 * we compute the length by looking at wct and bcc fields.
2939 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2949 ncbp = smb_GetNCB();
2953 memset(ncbp, 0, sizeof(NCB));
2955 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2956 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2957 extra += tp[0] + (tp[1]<<8);
2958 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2959 extra += 3; /* wct and length fields */
2961 ncbp->ncb_length = extra; /* bytes to send */
2962 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2963 ncbp->ncb_lana_num = vcp->lana;
2964 ncbp->ncb_command = NCBSEND; /* op means send data */
2965 ncbp->ncb_buffer = (char *) inp;/* packet */
2966 code = Netbios(ncbp);
2969 const char * s = ncb_error_string(code);
2970 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2971 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2973 lock_ObtainMutex(&vcp->mx);
2974 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2975 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2977 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2978 lock_ReleaseMutex(&vcp->mx);
2979 lock_ObtainWrite(&smb_globalLock);
2980 dead_sessions[vcp->session] = TRUE;
2981 lock_ReleaseWrite(&smb_globalLock);
2982 smb_CleanupDeadVC(vcp);
2984 lock_ReleaseMutex(&vcp->mx);
2992 void smb_MapNTError(long code, unsigned long *NTStatusp)
2994 unsigned long NTStatus;
2996 /* map CM_ERROR_* errors to NT 32-bit status codes */
2997 /* NT Status codes are listed in ntstatus.h not winerror.h */
3001 else if (code == CM_ERROR_NOSUCHCELL) {
3002 NTStatus = 0xC0000034L; /* Name not found */
3004 else if (code == CM_ERROR_NOSUCHVOLUME) {
3005 NTStatus = 0xC0000034L; /* Name not found */
3007 else if (code == CM_ERROR_TIMEDOUT) {
3009 NTStatus = 0xC00000CFL; /* Sharing Paused */
3011 /* Do not send Timeout to the SMB redirector.
3012 * It causes the redirector to drop the connection */
3013 NTStatus = 0x00000102L; /* Timeout */
3014 /* do not send Retry to the SMB redirector.
3015 * It believes the error comes from the transport
3016 * layer not from the SMB server. */
3017 NTStatus = 0xC000022DL; /* Retry */
3019 NTStatus = 0xC00000B5L; /* I/O Timeout */
3022 else if (code == CM_ERROR_RETRY) {
3024 NTStatus = 0xC000022DL; /* Retry */
3026 NTStatus = 0xC00000B5L; /* I/O Timeout */
3029 else if (code == CM_ERROR_NOACCESS) {
3030 NTStatus = 0xC0000022L; /* Access denied */
3032 else if (code == CM_ERROR_READONLY) {
3033 NTStatus = 0xC00000A2L; /* Write protected */
3035 else if (code == CM_ERROR_NOSUCHFILE ||
3036 code == CM_ERROR_BPLUS_NOMATCH) {
3037 NTStatus = 0xC0000034L; /* Name not found */
3039 else if (code == CM_ERROR_NOSUCHPATH) {
3040 NTStatus = 0xC000003AL; /* Object path not found */
3042 else if (code == CM_ERROR_TOOBIG) {
3043 NTStatus = 0xC000007BL; /* Invalid image format */
3045 else if (code == CM_ERROR_INVAL) {
3046 NTStatus = 0xC000000DL; /* Invalid parameter */
3048 else if (code == CM_ERROR_BADFD) {
3049 NTStatus = 0xC0000008L; /* Invalid handle */
3051 else if (code == CM_ERROR_BADFDOP) {
3052 NTStatus = 0xC0000022L; /* Access denied */
3054 else if (code == CM_ERROR_UNKNOWN) {
3055 NTStatus = 0xC0000022L; /* Access denied */
3057 else if (code == CM_ERROR_EXISTS) {
3058 NTStatus = 0xC0000035L; /* Object name collision */
3060 else if (code == CM_ERROR_NOTEMPTY) {
3061 NTStatus = 0xC0000101L; /* Directory not empty */
3063 else if (code == CM_ERROR_CROSSDEVLINK) {
3064 NTStatus = 0xC00000D4L; /* Not same device */
3066 else if (code == CM_ERROR_NOTDIR) {
3067 NTStatus = 0xC0000103L; /* Not a directory */
3069 else if (code == CM_ERROR_ISDIR) {
3070 NTStatus = 0xC00000BAL; /* File is a directory */
3072 else if (code == CM_ERROR_BADOP) {
3074 /* I have no idea where this comes from */
3075 NTStatus = 0xC09820FFL; /* SMB no support */
3077 NTStatus = 0xC00000BBL; /* Not supported */
3078 #endif /* COMMENT */
3080 else if (code == CM_ERROR_BADSHARENAME) {
3081 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3083 else if (code == CM_ERROR_NOIPC) {
3085 NTStatus = 0xC0000022L; /* Access Denied */
3087 NTStatus = 0xC000013DL; /* Remote Resources */
3090 else if (code == CM_ERROR_CLOCKSKEW ||
3091 code == RXKADNOAUTH) {
3092 NTStatus = 0xC0000133L; /* Time difference at DC */
3094 else if (code == CM_ERROR_BADTID) {
3095 NTStatus = 0xC0982005L; /* SMB bad TID */
3097 else if (code == CM_ERROR_USESTD) {
3098 NTStatus = 0xC09820FBL; /* SMB use standard */
3100 else if (code == CM_ERROR_QUOTA) {
3101 NTStatus = 0xC0000044L; /* Quota exceeded */
3103 else if (code == CM_ERROR_SPACE) {
3104 NTStatus = 0xC000007FL; /* Disk full */
3106 else if (code == CM_ERROR_ATSYS) {
3107 NTStatus = 0xC0000033L; /* Object name invalid */
3109 else if (code == CM_ERROR_BADNTFILENAME) {
3110 NTStatus = 0xC0000033L; /* Object name invalid */
3112 else if (code == CM_ERROR_WOULDBLOCK) {
3113 NTStatus = 0xC00000D8L; /* Can't wait */
3115 else if (code == CM_ERROR_SHARING_VIOLATION) {
3116 NTStatus = 0xC0000043L; /* Sharing violation */
3118 else if (code == CM_ERROR_LOCK_CONFLICT) {
3119 NTStatus = 0xC0000054L; /* Lock conflict */
3121 else if (code == CM_ERROR_PARTIALWRITE) {
3122 NTStatus = 0xC000007FL; /* Disk full */
3124 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3125 NTStatus = 0xC0000023L; /* Buffer too small */
3127 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3128 NTStatus = 0xC0000035L; /* Object name collision */
3130 else if (code == CM_ERROR_BADPASSWORD) {
3131 NTStatus = 0xC000006DL; /* unknown username or bad password */
3133 else if (code == CM_ERROR_BADLOGONTYPE) {
3134 NTStatus = 0xC000015BL; /* logon type not granted */
3136 else if (code == CM_ERROR_GSSCONTINUE) {
3137 NTStatus = 0xC0000016L; /* more processing required */
3139 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3141 NTStatus = 0xC0000280L; /* reparse point not resolved */
3143 NTStatus = 0xC0000022L; /* Access Denied */
3146 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3147 NTStatus = 0xC0000257L; /* Path Not Covered */
3149 else if (code == CM_ERROR_ALLBUSY) {
3151 NTStatus = 0xC000022DL; /* Retry */
3153 NTStatus = 0xC00000B5L; /* I/O Timeout */
3156 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3157 NTStatus = 0xC000003AL; /* Path not found */
3159 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3160 NTStatus = 0xC0000322L; /* No Kerberos key */
3162 else if (code == CM_ERROR_BAD_LEVEL) {
3163 NTStatus = 0xC0000148L; /* Invalid Level */
3165 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3166 NTStatus = 0xC000007EL; /* Range Not Locked */
3168 else if (code == CM_ERROR_NOSUCHDEVICE) {
3169 NTStatus = 0xC000000EL; /* No Such Device */
3171 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3172 NTStatus = 0xC0000055L; /* Lock Not Granted */
3174 else if (code == ENOMEM) {
3175 NTStatus = 0xC0000017L; /* Out of Memory */
3177 else if (code == CM_ERROR_RPC_MOREDATA) {
3178 NTStatus = 0x80000005L; /* Buffer overflow */
3181 NTStatus = 0xC0982001L; /* SMB non-specific error */
3184 *NTStatusp = NTStatus;
3185 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3189 * NTSTATUS <-> Win32 Error Translation
3190 * http://support.microsoft.com/kb/113996
3192 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3194 unsigned long Win32E;
3196 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3200 else if (code == CM_ERROR_NOSUCHCELL) {
3201 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3203 else if (code == CM_ERROR_NOSUCHVOLUME) {
3204 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3206 else if (code == CM_ERROR_TIMEDOUT) {
3208 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3210 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3213 else if (code == CM_ERROR_RETRY) {
3214 Win32E = ERROR_RETRY; /* Retry */
3216 else if (code == CM_ERROR_NOACCESS) {
3217 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3219 else if (code == CM_ERROR_READONLY) {
3220 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3222 else if (code == CM_ERROR_NOSUCHFILE ||
3223 code == CM_ERROR_BPLUS_NOMATCH) {
3224 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3226 else if (code == CM_ERROR_NOSUCHPATH) {
3227 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3229 else if (code == CM_ERROR_TOOBIG) {
3230 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3232 else if (code == CM_ERROR_INVAL) {
3233 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3235 else if (code == CM_ERROR_BADFD) {
3236 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3238 else if (code == CM_ERROR_BADFDOP) {
3239 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3241 else if (code == CM_ERROR_UNKNOWN) {
3242 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3244 else if (code == CM_ERROR_EXISTS) {
3245 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3247 else if (code == CM_ERROR_NOTEMPTY) {
3248 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3250 else if (code == CM_ERROR_CROSSDEVLINK) {
3251 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3253 else if (code == CM_ERROR_NOTDIR) {
3254 Win32E = ERROR_DIRECTORY; /* Not a directory */
3256 else if (code == CM_ERROR_ISDIR) {
3257 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3259 else if (code == CM_ERROR_BADOP) {
3260 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3262 else if (code == CM_ERROR_BADSHARENAME) {
3263 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3265 else if (code == CM_ERROR_NOIPC) {
3267 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3269 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3272 else if (code == CM_ERROR_CLOCKSKEW ||
3273 code == RXKADNOAUTH) {
3274 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3276 else if (code == CM_ERROR_BADTID) {
3277 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3279 else if (code == CM_ERROR_USESTD) {
3280 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3282 else if (code == CM_ERROR_QUOTA) {
3283 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3285 else if (code == CM_ERROR_SPACE) {
3286 Win32E = ERROR_DISK_FULL; /* Disk full */
3288 else if (code == CM_ERROR_ATSYS) {
3289 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3291 else if (code == CM_ERROR_BADNTFILENAME) {
3292 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3294 else if (code == CM_ERROR_WOULDBLOCK) {
3295 Win32E = WAIT_TIMEOUT; /* Can't wait */
3297 else if (code == CM_ERROR_SHARING_VIOLATION) {
3298 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3300 else if (code == CM_ERROR_LOCK_CONFLICT) {
3301 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3303 else if (code == CM_ERROR_PARTIALWRITE) {
3304 Win32E = ERROR_DISK_FULL; /* Disk full */
3306 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3307 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3309 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3310 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3312 else if (code == CM_ERROR_BADPASSWORD) {
3313 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3315 else if (code == CM_ERROR_BADLOGONTYPE) {
3316 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3318 else if (code == CM_ERROR_GSSCONTINUE) {
3319 Win32E = ERROR_MORE_DATA; /* more processing required */
3321 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3323 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3325 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3328 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3329 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3331 else if (code == CM_ERROR_ALLBUSY) {
3332 Win32E = ERROR_RETRY; /* Retry */
3334 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3335 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3337 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3338 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3340 else if (code == CM_ERROR_BAD_LEVEL) {
3341 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3343 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3344 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3346 else if (code == CM_ERROR_NOSUCHDEVICE) {
3347 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3349 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3350 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3352 else if (code == ENOMEM) {
3353 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3355 else if (code == CM_ERROR_RPC_MOREDATA) {
3356 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3359 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3363 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3366 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3367 unsigned char *classp)
3369 unsigned char class;
3370 unsigned short error;
3372 /* map CM_ERROR_* errors to SMB errors */
3373 if (code == CM_ERROR_NOSUCHCELL) {
3375 error = 3; /* bad path */
3377 else if (code == CM_ERROR_NOSUCHVOLUME) {
3379 error = 3; /* bad path */
3381 else if (code == CM_ERROR_TIMEDOUT) {
3383 error = 81; /* server is paused */
3385 else if (code == CM_ERROR_RETRY) {
3386 class = 2; /* shouldn't happen */
3389 else if (code == CM_ERROR_NOACCESS) {
3391 error = 4; /* bad access */
3393 else if (code == CM_ERROR_READONLY) {
3395 error = 19; /* read only */
3397 else if (code == CM_ERROR_NOSUCHFILE ||
3398 code == CM_ERROR_BPLUS_NOMATCH) {
3400 error = 2; /* ENOENT! */
3402 else if (code == CM_ERROR_NOSUCHPATH) {
3404 error = 3; /* Bad path */
3406 else if (code == CM_ERROR_TOOBIG) {
3408 error = 11; /* bad format */
3410 else if (code == CM_ERROR_INVAL) {
3411 class = 2; /* server non-specific error code */
3414 else if (code == CM_ERROR_BADFD) {
3416 error = 6; /* invalid file handle */
3418 else if (code == CM_ERROR_BADFDOP) {
3419 class = 1; /* invalid op on FD */
3422 else if (code == CM_ERROR_EXISTS) {
3424 error = 80; /* file already exists */
3426 else if (code == CM_ERROR_NOTEMPTY) {
3428 error = 5; /* delete directory not empty */
3430 else if (code == CM_ERROR_CROSSDEVLINK) {
3432 error = 17; /* EXDEV */
3434 else if (code == CM_ERROR_NOTDIR) {
3435 class = 1; /* bad path */
3438 else if (code == CM_ERROR_ISDIR) {
3439 class = 1; /* access denied; DOS doesn't have a good match */
3442 else if (code == CM_ERROR_BADOP) {
3446 else if (code == CM_ERROR_BADSHARENAME) {
3450 else if (code == CM_ERROR_NOIPC) {
3452 error = 4; /* bad access */
3454 else if (code == CM_ERROR_CLOCKSKEW) {
3455 class = 1; /* invalid function */
3458 else if (code == CM_ERROR_BADTID) {
3462 else if (code == CM_ERROR_USESTD) {
3466 else if (code == CM_ERROR_REMOTECONN) {
3470 else if (code == CM_ERROR_QUOTA) {
3471 if (vcp->flags & SMB_VCFLAG_USEV3) {
3473 error = 39; /* disk full */
3477 error = 5; /* access denied */
3480 else if (code == CM_ERROR_SPACE) {
3481 if (vcp->flags & SMB_VCFLAG_USEV3) {
3483 error = 39; /* disk full */
3487 error = 5; /* access denied */
3490 else if (code == CM_ERROR_PARTIALWRITE) {
3492 error = 39; /* disk full */
3494 else if (code == CM_ERROR_ATSYS) {
3496 error = 2; /* ENOENT */
3498 else if (code == CM_ERROR_WOULDBLOCK) {
3500 error = 33; /* lock conflict */
3502 else if (code == CM_ERROR_LOCK_CONFLICT) {
3504 error = 33; /* lock conflict */
3506 else if (code == CM_ERROR_SHARING_VIOLATION) {
3508 error = 33; /* lock conflict */
3510 else if (code == CM_ERROR_NOFILES) {
3512 error = 18; /* no files in search */
3514 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3516 error = 183; /* Samba uses this */
3518 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3519 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3521 error = 2; /* bad password */
3523 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3525 error = 3; /* bad path */
3534 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3537 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3539 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3540 return CM_ERROR_BADOP;
3544 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3546 unsigned short EchoCount, i;
3547 char *data, *outdata;
3550 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3552 for (i=1; i<=EchoCount; i++) {
3553 data = smb_GetSMBData(inp, &dataSize);
3554 smb_SetSMBParm(outp, 0, i);
3555 smb_SetSMBDataLength(outp, dataSize);
3556 outdata = smb_GetSMBData(outp, NULL);
3557 memcpy(outdata, data, dataSize);
3558 smb_SendPacket(vcp, outp);
3564 /* SMB_COM_READ_RAW */
3565 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3568 long count, minCount, finalCount;
3572 smb_t *smbp = (smb_t*) inp;
3574 cm_user_t *userp = NULL;
3577 char *rawBuf = NULL;
3582 fd = smb_GetSMBParm(inp, 0);
3583 count = smb_GetSMBParm(inp, 3);
3584 minCount = smb_GetSMBParm(inp, 4);
3585 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3587 if (*inp->wctp == 10) {
3588 /* we were sent a request with 64-bit file offsets */
3589 #ifdef AFS_LARGEFILES
3590 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3592 if (LargeIntegerLessThanZero(offset)) {
3593 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3597 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3598 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3601 offset.HighPart = 0;
3605 /* we were sent a request with 32-bit file offsets */
3606 offset.HighPart = 0;
3609 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3610 fd, offset.HighPart, offset.LowPart, count);
3612 fidp = smb_FindFID(vcp, fd, 0);
3614 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3618 lock_ObtainMutex(&fidp->mx);
3620 lock_ReleaseMutex(&fidp->mx);
3621 smb_ReleaseFID(fidp);
3622 return CM_ERROR_BADFD;
3625 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3626 lock_ReleaseMutex(&fidp->mx);
3627 smb_CloseFID(vcp, fidp, NULL, 0);
3628 code = CM_ERROR_NOSUCHFILE;
3634 LARGE_INTEGER LOffset, LLength;
3637 key = cm_GenerateKey(vcp->vcID, pid, fd);
3639 LOffset.HighPart = offset.HighPart;
3640 LOffset.LowPart = offset.LowPart;
3641 LLength.HighPart = 0;
3642 LLength.LowPart = count;
3644 lock_ObtainWrite(&fidp->scp->rw);
3645 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3646 lock_ReleaseWrite(&fidp->scp->rw);
3649 lock_ReleaseMutex(&fidp->mx);
3653 lock_ObtainMutex(&smb_RawBufLock);
3655 /* Get a raw buf, from head of list */
3656 rawBuf = smb_RawBufs;
3657 smb_RawBufs = *(char **)smb_RawBufs;
3659 lock_ReleaseMutex(&smb_RawBufLock);
3661 lock_ReleaseMutex(&fidp->mx);
3665 if (fidp->flags & SMB_FID_IOCTL)
3667 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3669 /* Give back raw buffer */
3670 lock_ObtainMutex(&smb_RawBufLock);
3671 *((char **) rawBuf) = smb_RawBufs;
3673 smb_RawBufs = rawBuf;
3674 lock_ReleaseMutex(&smb_RawBufLock);
3677 lock_ReleaseMutex(&fidp->mx);
3678 smb_ReleaseFID(fidp);
3681 lock_ReleaseMutex(&fidp->mx);
3683 userp = smb_GetUserFromVCP(vcp, inp);
3685 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3691 cm_ReleaseUser(userp);
3694 smb_ReleaseFID(fidp);
3698 memset(ncbp, 0, sizeof(NCB));
3700 ncbp->ncb_length = (unsigned short) finalCount;
3701 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3702 ncbp->ncb_lana_num = vcp->lana;
3703 ncbp->ncb_command = NCBSEND;
3704 ncbp->ncb_buffer = rawBuf;
3706 code = Netbios(ncbp);
3708 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3711 /* Give back raw buffer */
3712 lock_ObtainMutex(&smb_RawBufLock);
3713 *((char **) rawBuf) = smb_RawBufs;
3715 smb_RawBufs = rawBuf;
3716 lock_ReleaseMutex(&smb_RawBufLock);
3722 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3724 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3729 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3731 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3736 /* SMB_COM_NEGOTIATE */
3737 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3744 int VistaProtoIndex;
3745 int protoIndex; /* index we're using */
3750 char protocol_array[10][1024]; /* protocol signature of the client */
3751 int caps; /* capabilities */
3754 TIME_ZONE_INFORMATION tzi;
3756 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3759 namep = smb_GetSMBData(inp, &dbytes);
3762 coreProtoIndex = -1; /* not found */
3765 VistaProtoIndex = -1;
3766 while(namex < dbytes) {
3767 osi_Log1(smb_logp, "Protocol %s",
3768 osi_LogSaveString(smb_logp, namep+1));
3769 strcpy(protocol_array[tcounter], namep+1);
3771 /* namep points at the first protocol, or really, a 0x02
3772 * byte preceding the null-terminated ASCII name.
3774 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3775 coreProtoIndex = tcounter;
3777 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3778 v3ProtoIndex = tcounter;
3780 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3781 NTProtoIndex = tcounter;
3783 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3784 VistaProtoIndex = tcounter;
3787 /* compute size of protocol entry */
3788 entryLength = (int)strlen(namep+1);
3789 entryLength += 2; /* 0x02 bytes and null termination */
3791 /* advance over this protocol entry */
3792 namex += entryLength;
3793 namep += entryLength;
3794 tcounter++; /* which proto entry we're looking at */
3797 lock_ObtainMutex(&vcp->mx);
3799 if (VistaProtoIndex != -1) {
3800 protoIndex = VistaProtoIndex;
3801 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3804 if (NTProtoIndex != -1) {
3805 protoIndex = NTProtoIndex;
3806 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3808 else if (v3ProtoIndex != -1) {
3809 protoIndex = v3ProtoIndex;
3810 vcp->flags |= SMB_VCFLAG_USEV3;
3812 else if (coreProtoIndex != -1) {
3813 protoIndex = coreProtoIndex;
3814 vcp->flags |= SMB_VCFLAG_USECORE;
3816 else protoIndex = -1;
3817 lock_ReleaseMutex(&vcp->mx);
3819 if (protoIndex == -1)
3820 return CM_ERROR_INVAL;
3821 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3822 smb_SetSMBParm(outp, 0, protoIndex);
3823 if (smb_authType != SMB_AUTH_NONE) {
3824 smb_SetSMBParmByte(outp, 1,
3825 NEGOTIATE_SECURITY_USER_LEVEL |
3826 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3828 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3830 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3831 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3832 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3833 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3834 /* The session key is not a well documented field however most clients
3835 * will echo back the session key to the server. Currently we are using
3836 * the same value for all sessions. We should generate a random value
3837 * and store it into the vcp
3839 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3840 smb_SetSMBParm(outp, 8, 1);
3842 * Tried changing the capabilities to support for W2K - defect 117695
3843 * Maybe something else needs to be changed here?
3847 smb_SetSMBParmLong(outp, 9, 0x43fd);
3849 smb_SetSMBParmLong(outp, 9, 0x251);
3852 * 32-bit error codes *
3858 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3860 NTNEGOTIATE_CAPABILITY_DFS |
3862 #ifdef AFS_LARGEFILES
3863 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3865 NTNEGOTIATE_CAPABILITY_NTFIND |
3866 NTNEGOTIATE_CAPABILITY_RAWMODE |
3867 NTNEGOTIATE_CAPABILITY_NTSMB;
3869 if ( smb_authType == SMB_AUTH_EXTENDED )
3870 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3873 if ( smb_UseUnicode ) {
3874 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3878 smb_SetSMBParmLong(outp, 9, caps);
3880 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3881 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3882 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3884 GetTimeZoneInformation(&tzi);
3885 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3887 if (smb_authType == SMB_AUTH_NTLM) {
3888 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3889 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3890 /* paste in encryption key */
3891 datap = smb_GetSMBData(outp, NULL);
3892 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3893 /* and the faux domain name */
3894 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3895 datap + MSV1_0_CHALLENGE_LENGTH,
3896 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3897 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3901 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3903 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3905 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3907 datap = smb_GetSMBData(outp, NULL);
3908 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3911 datap += sizeof(smb_ServerGUID);
3912 memcpy(datap, secBlob, secBlobLength);
3916 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3917 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3920 else if (v3ProtoIndex != -1) {
3921 smb_SetSMBParm(outp, 0, protoIndex);
3923 /* NOTE: Extended authentication cannot be negotiated with v3
3924 * therefore we fail over to NTLM
3926 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3927 smb_SetSMBParm(outp, 1,
3928 NEGOTIATE_SECURITY_USER_LEVEL |
3929 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3931 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3933 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3934 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3935 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3936 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3937 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3938 smb_SetSMBParm(outp, 7, 1);
3940 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3941 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3942 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3944 GetTimeZoneInformation(&tzi);
3945 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3947 /* NOTE: Extended authentication cannot be negotiated with v3
3948 * therefore we fail over to NTLM
3950 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3951 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3952 smb_SetSMBParm(outp, 12, 0); /* resvd */
3953 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3954 datap = smb_GetSMBData(outp, NULL);
3955 /* paste in a new encryption key */
3956 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3957 /* and the faux domain name */
3958 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3959 datap + MSV1_0_CHALLENGE_LENGTH,
3960 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3962 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3963 smb_SetSMBParm(outp, 12, 0); /* resvd */
3964 smb_SetSMBDataLength(outp, 0);
3967 else if (coreProtoIndex != -1) { /* not really supported anymore */
3968 smb_SetSMBParm(outp, 0, protoIndex);
3969 smb_SetSMBDataLength(outp, 0);
3974 void smb_CheckVCs(void)
3976 smb_vc_t * vcp, *nextp;
3977 smb_packet_t * outp = smb_GetPacket();
3980 lock_ObtainWrite(&smb_rctLock);
3981 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3983 if (vcp->magic != SMB_VC_MAGIC)
3984 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3985 __FILE__, __LINE__);
3987 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3989 smb_HoldVCNoLock(vcp);
3992 * obtain a reference to 'nextp' now because we drop the
3993 * smb_rctLock later and the list contents could change
3994 * or 'vcp' could be destroyed when released.
3998 smb_HoldVCNoLock(nextp);
4000 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4001 smb_ReleaseVCNoLock(vcp);
4005 smb_FormatResponsePacket(vcp, NULL, outp);
4006 smbp = (smb_t *)outp;
4007 outp->inCom = smbp->com = 0x2b /* Echo */;
4015 smb_SetSMBParm(outp, 0, 0);
4016 smb_SetSMBDataLength(outp, 0);
4017 lock_ReleaseWrite(&smb_rctLock);
4019 smb_SendPacket(vcp, outp);
4021 lock_ObtainWrite(&smb_rctLock);
4022 smb_ReleaseVCNoLock(vcp);
4024 lock_ReleaseWrite(&smb_rctLock);
4025 smb_FreePacket(outp);
4028 void smb_Daemon(void *parmp)
4030 afs_uint32 count = 0;
4031 smb_username_t **unpp;
4034 while(smbShutdownFlag == 0) {
4038 if (smbShutdownFlag == 1)
4041 if ((count % 72) == 0) { /* every five minutes */
4043 time_t old_localZero = smb_localZero;
4045 /* Initialize smb_localZero */
4046 myTime.tm_isdst = -1; /* compute whether on DST or not */
4047 myTime.tm_year = 70;
4053 smb_localZero = mktime(&myTime);
4055 #ifdef AFS_FREELANCE
4056 if ( smb_localZero != old_localZero )
4057 cm_noteLocalMountPointChange();
4063 /* GC smb_username_t objects that will no longer be used */
4065 lock_ObtainWrite(&smb_rctLock);
4066 for ( unpp=&usernamesp; *unpp; ) {
4068 smb_username_t *unp;
4070 lock_ObtainMutex(&(*unpp)->mx);
4071 if ( (*unpp)->refCount > 0 ||
4072 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4073 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4075 else if (!smb_LogoffTokenTransfer ||
4076 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4078 lock_ReleaseMutex(&(*unpp)->mx);
4086 lock_FinalizeMutex(&unp->mx);
4092 cm_ReleaseUser(userp);
4094 unpp = &(*unpp)->nextp;
4097 lock_ReleaseWrite(&smb_rctLock);
4099 /* XXX GC dir search entries */
4103 void smb_WaitingLocksDaemon()
4105 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4106 smb_waitingLock_t *wl, *wlNext;
4109 smb_packet_t *inp, *outp;
4113 while (smbShutdownFlag == 0) {
4114 lock_ObtainWrite(&smb_globalLock);
4115 nwlRequest = smb_allWaitingLocks;
4116 if (nwlRequest == NULL) {
4117 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4122 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4129 lock_ObtainWrite(&smb_globalLock);
4131 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4133 wlRequest = nwlRequest;
4134 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4135 lock_ReleaseWrite(&smb_globalLock);
4139 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4140 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4143 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4144 code = CM_ERROR_LOCK_NOT_GRANTED;
4148 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4150 /* wl->state is either _DONE or _WAITING. _ERROR
4151 would no longer be on the queue. */
4152 code = cm_RetryLock( wl->lockp,
4153 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4156 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4157 } else if (code != CM_ERROR_WOULDBLOCK) {
4158 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4163 if (code == CM_ERROR_WOULDBLOCK) {
4166 if (wlRequest->msTimeout != 0xffffffff
4167 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4179 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4182 scp = wlRequest->scp;
4183 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4187 lock_ObtainWrite(&scp->rw);
4189 for (wl = wlRequest->locks; wl; wl = wlNext) {
4190 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4192 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4193 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4194 wl->LLength, wl->key, 0, NULL, &req);
4196 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4201 lock_ReleaseWrite(&scp->rw);
4205 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4208 for (wl = wlRequest->locks; wl; wl = wlNext) {
4209 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4210 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4215 vcp = wlRequest->vcp;
4216 inp = wlRequest->inp;
4217 outp = wlRequest->outp;
4218 ncbp = smb_GetNCB();
4219 ncbp->ncb_length = inp->ncb_length;
4220 inp->spacep = cm_GetSpace();
4222 /* Remove waitingLock from list */
4223 lock_ObtainWrite(&smb_globalLock);
4224 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4226 lock_ReleaseWrite(&smb_globalLock);
4228 /* Resume packet processing */
4230 smb_SetSMBDataLength(outp, 0);
4231 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4232 outp->resumeCode = code;
4234 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4237 cm_FreeSpace(inp->spacep);
4238 smb_FreePacket(inp);
4239 smb_FreePacket(outp);
4241 cm_ReleaseSCache(wlRequest->scp);
4244 } while (nwlRequest && smbShutdownFlag == 0);
4249 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4251 osi_Log0(smb_logp, "SMB receive get disk attributes");
4253 smb_SetSMBParm(outp, 0, 32000);
4254 smb_SetSMBParm(outp, 1, 64);
4255 smb_SetSMBParm(outp, 2, 1024);
4256 smb_SetSMBParm(outp, 3, 30000);
4257 smb_SetSMBParm(outp, 4, 0);
4258 smb_SetSMBDataLength(outp, 0);
4262 /* SMB_COM_TREE_CONNECT */
4263 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4267 unsigned short newTid;
4268 clientchar_t shareName[AFSPATHMAX];
4269 clientchar_t *sharePath;
4272 clientchar_t *pathp;
4275 osi_Log0(smb_logp, "SMB receive tree connect");
4277 /* parse input parameters */
4280 tbp = smb_GetSMBData(inp, NULL);
4281 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4283 return CM_ERROR_BADSMB;
4285 tp = cm_ClientStrRChr(pathp, '\\');
4287 return CM_ERROR_BADSMB;
4288 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4290 lock_ObtainMutex(&vcp->mx);
4291 newTid = vcp->tidCounter++;
4292 lock_ReleaseMutex(&vcp->mx);
4294 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4295 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4297 return CM_ERROR_BADSMB;
4298 userp = smb_GetUserFromUID(uidp);
4299 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4300 smb_ReleaseUID(uidp);
4302 smb_ReleaseTID(tidp, FALSE);
4303 return CM_ERROR_BADSHARENAME;
4305 lock_ObtainMutex(&tidp->mx);
4306 tidp->userp = userp;
4307 tidp->pathname = sharePath;
4308 lock_ReleaseMutex(&tidp->mx);
4309 smb_ReleaseTID(tidp, FALSE);
4311 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4312 smb_SetSMBParm(rsp, 1, newTid);
4313 smb_SetSMBDataLength(rsp, 0);
4315 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4319 /* set maskp to the mask part of the incoming path.
4320 * Mask is 11 bytes long (8.3 with the dot elided).
4321 * Returns true if succeeds with a valid name, otherwise it does
4322 * its best, but returns false.
4324 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4332 /* starts off valid */
4335 /* mask starts out all blanks */
4336 memset(maskp, ' ', 11);
4339 /* find last backslash, or use whole thing if there is none */
4340 tp = cm_ClientStrRChr(pathp, '\\');
4344 tp++; /* skip slash */
4348 /* names starting with a dot are illegal */
4356 if (tc == '.' || tc == '"')
4364 /* if we get here, tp point after the dot */
4365 up = maskp+8; /* ext goes here */
4372 if (tc == '.' || tc == '"')
4375 /* copy extension if not too long */
4385 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4387 clientchar_t umask[11];
4395 /* XXX redo this, calling cm_MatchMask with a converted mask */
4397 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4401 /* otherwise, we have a valid 8.3 name; see if we have a match,
4402 * treating '?' as a wildcard in maskp (but not in the file name).
4404 tp1 = umask; /* real name, in mask format */
4405 tp2 = maskp; /* mask, in mask format */
4406 for(i=0; i<11; i++) {
4407 tc1 = *tp1++; /* clientchar_t from real name */
4408 tc2 = *tp2++; /* clientchar_t from mask */
4409 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4410 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4413 if (tc2 == '?' && tc1 != ' ')
4420 /* we got a match */
4424 clientchar_t *smb_FindMask(clientchar_t *pathp)
4428 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4431 return tp+1; /* skip the slash */
4433 return pathp; /* no slash, return the entire path */
4436 /* SMB_COM_SEARCH for a volume label
4438 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4439 dispatch function.) */
4440 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4442 clientchar_t *pathp;
4444 clientchar_t mask[12];
4445 unsigned char *statBlockp;
4446 unsigned char initStatBlock[21];
4449 osi_Log0(smb_logp, "SMB receive search volume");
4451 /* pull pathname and stat block out of request */
4452 tp = smb_GetSMBData(inp, NULL);
4453 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4454 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4456 return CM_ERROR_BADSMB;
4457 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4458 osi_assertx(statBlockp != NULL, "null statBlock");
4460 statBlockp = initStatBlock;
4464 /* for returning to caller */
4465 smb_Get8Dot3MaskFromPath(mask, pathp);
4467 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4468 tp = smb_GetSMBData(outp, NULL);
4470 *tp++ = 43; /* bytes in a dir entry */
4471 *tp++ = 0; /* high byte in counter */
4473 /* now marshall the dir entry, starting with the search status */
4474 *tp++ = statBlockp[0]; /* Reserved */
4475 memcpy(tp, mask, 11); tp += 11; /* FileName */
4477 /* now pass back server use info, with 1st byte non-zero */
4479 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4481 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4483 *tp++ = 0x8; /* attribute: volume */
4493 /* 4 byte file size */
4499 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4502 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4503 memset(tp, ' ', 13);
4506 /* set the length of the data part of the packet to 43 + 3, for the dir
4507 * entry plus the 5 and the length fields.
4509 smb_SetSMBDataLength(outp, 46);
4514 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4515 clientchar_t * tidPathp, clientchar_t * relPathp,
4516 cm_user_t *userp, cm_req_t *reqp)
4524 smb_dirListPatch_t *patchp;
4525 smb_dirListPatch_t *npatchp;
4526 clientchar_t path[AFSPATHMAX];
4528 afs_int32 mustFake = 0;
4530 code = cm_FindACLCache(dscp, userp, &rights);
4532 lock_ObtainWrite(&dscp->rw);
4533 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4534 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4535 lock_ReleaseWrite(&dscp->rw);
4536 if (code == CM_ERROR_NOACCESS) {
4544 if (!mustFake) { /* Bulk Stat */
4546 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4548 memset(bsp, 0, sizeof(cm_bulkStat_t));
4550 for (patchp = *dirPatchespp, count=0;
4552 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4553 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4557 if (lock_TryWrite(&tscp->rw)) {
4558 /* we have an entry that we can look at */
4559 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4560 /* we have a callback on it. Don't bother
4561 * fetching this stat entry, since we're happy
4562 * with the info we have.
4564 lock_ReleaseWrite(&tscp->rw);
4565 cm_ReleaseSCache(tscp);
4568 lock_ReleaseWrite(&tscp->rw);
4570 cm_ReleaseSCache(tscp);
4574 bsp->fids[i].Volume = patchp->fid.volume;
4575 bsp->fids[i].Vnode = patchp->fid.vnode;
4576 bsp->fids[i].Unique = patchp->fid.unique;
4578 if (bsp->counter == AFSCBMAX) {
4579 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4580 memset(bsp, 0, sizeof(cm_bulkStat_t));
4584 if (bsp->counter > 0)
4585 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4590 for (patchp = *dirPatchespp; patchp; patchp =
4591 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4593 dptr = patchp->dptr;
4595 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4596 relPathp ? relPathp : _C(""), patchp->dep->name);
4597 reqp->relPathp = path;
4598 reqp->tidPathp = tidPathp;
4600 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4601 reqp->relPathp = reqp->tidPathp = NULL;
4604 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4605 *dptr++ = SMB_ATTR_HIDDEN;
4608 lock_ObtainWrite(&scp->rw);
4609 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4610 lock_ReleaseWrite(&scp->rw);
4612 /* set the attribute */
4613 switch (scp->fileType) {
4614 case CM_SCACHETYPE_DIRECTORY:
4615 case CM_SCACHETYPE_MOUNTPOINT:
4616 case CM_SCACHETYPE_INVALID:
4617 attr = SMB_ATTR_DIRECTORY;
4619 case CM_SCACHETYPE_SYMLINK:
4620 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4621 attr = SMB_ATTR_DIRECTORY;
4623 attr = SMB_ATTR_NORMAL;
4626 /* if we get here we either have a normal file
4627 * or we have a file for which we have never
4628 * received status info. In this case, we can
4629 * check the even/odd value of the entry's vnode.
4630 * odd means it is to be treated as a directory
4631 * and even means it is to be treated as a file.
4633 if (mustFake && (scp->fid.vnode & 0x1))
4634 attr = SMB_ATTR_DIRECTORY;
4636 attr = SMB_ATTR_NORMAL;
4640 /* 1969-12-31 23:59:58 +00*/
4641 dosTime = 0xEBBFBF7D;
4644 shortTemp = (unsigned short) (dosTime & 0xffff);
4645 *((u_short *)dptr) = shortTemp;
4648 /* and copy out date */
4649 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4650 *((u_short *)dptr) = shortTemp;
4653 /* copy out file length */
4654 *((u_long *)dptr) = 0;
4657 lock_ConvertWToR(&scp->rw);
4658 attr = smb_Attributes(scp);
4659 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4660 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4661 attr |= SMB_ATTR_HIDDEN;
4665 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4668 shortTemp = (unsigned short) (dosTime & 0xffff);
4669 *((u_short *)dptr) = shortTemp;
4672 /* and copy out date */
4673 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4674 *((u_short *)dptr) = shortTemp;
4677 /* copy out file length */
4678 *((u_long *)dptr) = scp->length.LowPart;
4680 lock_ReleaseRead(&scp->rw);
4682 cm_ReleaseSCache(scp);
4685 /* now free the patches */
4686 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4687 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4691 /* and mark the list as empty */
4692 *dirPatchespp = NULL;
4698 /* SMB_COM_SEARCH */
4699 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4705 clientchar_t *pathp;
4706 cm_dirEntry_t *dep = 0;
4708 smb_dirListPatch_t *dirListPatchesp;
4709 smb_dirListPatch_t *curPatchp;
4713 osi_hyper_t dirLength;
4714 osi_hyper_t bufferOffset;
4715 osi_hyper_t curOffset;
4717 unsigned char *inCookiep;
4718 smb_dirSearch_t *dsp;
4722 unsigned long clientCookie;
4723 cm_pageHeader_t *pageHeaderp;
4724 cm_user_t *userp = NULL;
4726 clientchar_t mask[12];
4728 long nextEntryCookie;
4729 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4730 char resByte; /* reserved byte from the cookie */
4731 char *op; /* output data ptr */
4732 char *origOp; /* original value of op */
4733 cm_space_t *spacep; /* for pathname buffer */
4737 clientchar_t *tidPathp = 0;
4744 maxCount = smb_GetSMBParm(inp, 0);
4746 dirListPatchesp = NULL;
4748 caseFold = CM_FLAG_CASEFOLD;
4750 tp = smb_GetSMBData(inp, NULL);
4751 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4752 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4754 return CM_ERROR_BADSMB;
4756 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4758 return CM_ERROR_BADSMB;
4760 /* We can handle long names */
4761 if (vcp->flags & SMB_VCFLAG_USENT)
4762 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4764 /* make sure we got a whole search status */
4765 if (dataLength < 21) {
4766 nextCookie = 0; /* start at the beginning of the dir */
4769 attribute = smb_GetSMBParm(inp, 1);
4771 /* handle volume info in another function */
4772 if (attribute & 0x8)
4773 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4775 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4776 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4778 if (*pathp == 0) { /* null pathp, treat as root dir */
4779 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4780 return CM_ERROR_NOFILES;
4784 dsp = smb_NewDirSearch(0);
4785 dsp->attribute = attribute;
4786 smb_Get8Dot3MaskFromPath(mask, pathp);
4787 memcpy(dsp->mask, mask, 12);
4789 /* track if this is likely to match a lot of entries */
4790 if (smb_Is8Dot3StarMask(mask))
4795 /* pull the next cookie value out of the search status block */
4796 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4797 + (inCookiep[16]<<24);
4798 dsp = smb_FindDirSearch(inCookiep[12]);
4800 /* can't find dir search status; fatal error */
4801 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4802 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4803 return CM_ERROR_BADFD;
4805 attribute = dsp->attribute;
4806 resByte = inCookiep[0];
4808 /* copy out client cookie, in host byte order. Don't bother
4809 * interpreting it, since we're just passing it through, anyway.
4811 memcpy(&clientCookie, &inCookiep[17], 4);
4813 memcpy(mask, dsp->mask, 12);
4815 /* assume we're doing a star match if it has continued for more
4821 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4822 nextCookie, dsp->cookie, attribute);
4824 userp = smb_GetUserFromVCP(vcp, inp);
4826 /* try to get the vnode for the path name next */
4827 lock_ObtainMutex(&dsp->mx);
4830 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4834 spacep = inp->spacep;
4835 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4836 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4838 lock_ReleaseMutex(&dsp->mx);
4839 cm_ReleaseUser(userp);
4840 smb_DeleteDirSearch(dsp);
4841 smb_ReleaseDirSearch(dsp);
4842 return CM_ERROR_NOFILES;
4844 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4845 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4847 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4848 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4851 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4854 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4855 cm_ReleaseSCache(scp);
4856 lock_ReleaseMutex(&dsp->mx);
4857 cm_ReleaseUser(userp);
4858 smb_DeleteDirSearch(dsp);
4859 smb_ReleaseDirSearch(dsp);
4860 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4861 return CM_ERROR_PATH_NOT_COVERED;
4863 return CM_ERROR_NOSUCHPATH;
4865 #endif /* DFS_SUPPORT */
4868 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4869 /* we need one hold for the entry we just stored into,
4870 * and one for our own processing. When we're done with this
4871 * function, we'll drop the one for our own processing.
4872 * We held it once from the namei call, and so we do another hold
4876 lock_ObtainWrite(&scp->rw);
4877 dsp->flags |= SMB_DIRSEARCH_BULKST;
4878 lock_ReleaseWrite(&scp->rw);
4881 lock_ReleaseMutex(&dsp->mx);
4883 cm_ReleaseUser(userp);
4884 smb_DeleteDirSearch(dsp);
4885 smb_ReleaseDirSearch(dsp);
4889 /* reserves space for parameter; we'll adjust it again later to the
4890 * real count of the # of entries we returned once we've actually
4891 * assembled the directory listing.
4893 smb_SetSMBParm(outp, 0, 0);
4895 /* get the directory size */
4896 lock_ObtainWrite(&scp->rw);
4897 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4898 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4900 lock_ReleaseWrite(&scp->rw);
4901 cm_ReleaseSCache(scp);
4902 cm_ReleaseUser(userp);
4903 smb_DeleteDirSearch(dsp);
4904 smb_ReleaseDirSearch(dsp);
4908 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4910 dirLength = scp->length;
4912 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4913 curOffset.HighPart = 0;
4914 curOffset.LowPart = nextCookie;
4915 origOp = op = smb_GetSMBData(outp, NULL);
4916 /* and write out the basic header */
4917 *op++ = 5; /* variable block */
4918 op += 2; /* skip vbl block length; we'll fill it in later */
4922 clientchar_t *actualName = NULL;
4923 int free_actualName = 0;
4924 clientchar_t shortName[13];
4925 clientchar_t *shortNameEnd;
4927 /* make sure that curOffset.LowPart doesn't point to the first
4928 * 32 bytes in the 2nd through last dir page, and that it doesn't
4929 * point at the first 13 32-byte chunks in the first dir page,
4930 * since those are dir and page headers, and don't contain useful
4933 temp = curOffset.LowPart & (2048-1);
4934 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4935 /* we're in the first page */
4936 if (temp < 13*32) temp = 13*32;
4939 /* we're in a later dir page */
4940 if (temp < 32) temp = 32;
4943 /* make sure the low order 5 bits are zero */
4946 /* now put temp bits back ito curOffset.LowPart */
4947 curOffset.LowPart &= ~(2048-1);
4948 curOffset.LowPart |= temp;
4950 /* check if we've returned all the names that will fit in the
4953 if (returnedNames >= maxCount) {
4954 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4955 returnedNames, maxCount);
4959 /* check if we've passed the dir's EOF */
4960 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4962 /* see if we can use the bufferp we have now; compute in which page
4963 * the current offset would be, and check whether that's the offset
4964 * of the buffer we have. If not, get the buffer.
4966 thyper.HighPart = curOffset.HighPart;
4967 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4968 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4971 buf_Release(bufferp);
4974 lock_ReleaseWrite(&scp->rw);
4975 code = buf_Get(scp, &thyper, &req, &bufferp);
4976 lock_ObtainMutex(&dsp->mx);
4978 /* now, if we're doing a star match, do bulk fetching of all of
4979 * the status info for files in the dir.
4982 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4984 lock_ObtainWrite(&scp->rw);
4985 lock_ReleaseMutex(&dsp->mx);
4987 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4991 bufferOffset = thyper;
4993 /* now get the data in the cache */
4995 code = cm_SyncOp(scp, bufferp, userp, &req,
4997 CM_SCACHESYNC_NEEDCALLBACK |
4998 CM_SCACHESYNC_READ);
5000 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5004 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5006 if (cm_HaveBuffer(scp, bufferp, 0)) {
5007 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5011 /* otherwise, load the buffer and try again */
5012 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5014 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5015 scp, bufferp, code);
5020 buf_Release(bufferp);
5024 } /* if (wrong buffer) ... */
5026 /* now we have the buffer containing the entry we're interested in; copy
5027 * it out if it represents a non-deleted entry.
5029 entryInDir = curOffset.LowPart & (2048-1);
5030 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5032 /* page header will help tell us which entries are free. Page header
5033 * can change more often than once per buffer, since AFS 3 dir page size
5034 * may be less than (but not more than a buffer package buffer.
5036 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5037 temp &= ~(2048 - 1); /* turn off intra-page bits */
5038 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5040 /* now determine which entry we're looking at in the page. If it is
5041 * free (there's a free bitmap at the start of the dir), we should
5042 * skip these 32 bytes.
5044 slotInPage = (entryInDir & 0x7e0) >> 5;
5045 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5046 /* this entry is free */
5047 numDirChunks = 1; /* only skip this guy */
5051 tp = bufferp->datap + entryInBuffer;
5052 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5054 /* while we're here, compute the next entry's location, too,
5055 * since we'll need it when writing out the cookie into the dir
5058 * XXXX Probably should do more sanity checking.
5060 numDirChunks = cm_NameEntries(dep->name, NULL);
5062 /* compute the offset of the cookie representing the next entry */
5063 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5065 /* Compute 8.3 name if necessary */
5066 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5067 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5070 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5071 actualName = shortName;
5072 free_actualName = 0;
5074 free_actualName = 1;
5077 if (actualName == NULL) {
5078 /* Couldn't convert the name for some reason */
5079 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5080 osi_LogSaveString(smb_logp, dep->name));
5084 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5085 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5086 osi_LogSaveClientString(smb_logp, actualName));
5088 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5089 /* this is one of the entries to use: it is not deleted
5090 * and it matches the star pattern we're looking for.
5093 /* Eliminate entries that don't match requested
5096 /* no hidden files */
5097 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5098 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5102 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5104 /* We have already done the cm_TryBulkStat above */
5105 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5106 fileType = cm_FindFileType(&fid);
5107 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5108 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5110 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5111 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5112 fileType == CM_SCACHETYPE_DFSLINK ||
5113 fileType == CM_SCACHETYPE_INVALID)
5114 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5119 memcpy(op, mask, 11); op += 11;
5120 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5121 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5122 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5123 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5124 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5125 memcpy(op, &clientCookie, 4); op += 4;
5127 /* now we emit the attribute. This is sort of tricky,
5128 * since we need to really stat the file to find out
5129 * what type of entry we've got. Right now, we're
5130 * copying out data from a buffer, while holding the
5131 * scp locked, so it isn't really convenient to stat
5132 * something now. We'll put in a place holder now,
5133 * and make a second pass before returning this to get
5134 * the real attributes. So, we just skip the data for
5135 * now, and adjust it later. We allocate a patch
5136 * record to make it easy to find this point later.
5137 * The replay will happen at a time when it is safe to
5138 * unlock the directory.
5140 curPatchp = malloc(sizeof(*curPatchp));
5141 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5142 curPatchp->dptr = op;
5143 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5145 /* do hidden attribute here since name won't be around when applying
5149 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5150 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5152 curPatchp->flags = 0;
5154 op += 9; /* skip attr, time, date and size */
5156 /* zero out name area. The spec says to pad with
5157 * spaces, but Samba doesn't, and neither do we.
5161 /* finally, we get to copy out the name; we know that
5162 * it fits in 8.3 or the pattern wouldn't match, but it
5163 * never hurts to be sure.
5165 cm_ClientStringToUtf8(actualName, -1, op, 13);
5166 if (smb_StoreAnsiFilenames)
5168 /* This is a UCHAR field, which is ASCII even if Unicode
5171 /* Uppercase if requested by client */
5172 if (!KNOWS_LONG_NAMES(inp))
5177 /* now, adjust the # of entries copied */
5179 } /* if we're including this name */
5182 if (free_actualName && actualName) {
5187 /* and adjust curOffset to be where the new cookie is */
5188 thyper.HighPart = 0;
5189 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5190 curOffset = LargeIntegerAdd(thyper, curOffset);
5191 } /* while copying data for dir listing */
5193 /* release the mutex */
5194 lock_ReleaseWrite(&scp->rw);
5196 buf_Release(bufferp);
5200 /* apply and free last set of patches; if not doing a star match, this
5201 * will be empty, but better safe (and freeing everything) than sorry.
5203 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5205 /* special return code for unsuccessful search */
5206 if (code == 0 && dataLength < 21 && returnedNames == 0)
5207 code = CM_ERROR_NOFILES;
5209 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5210 returnedNames, code);
5213 smb_DeleteDirSearch(dsp);
5214 smb_ReleaseDirSearch(dsp);
5215 cm_ReleaseSCache(scp);
5216 cm_ReleaseUser(userp);
5220 /* finalize the output buffer */
5221 smb_SetSMBParm(outp, 0, returnedNames);
5222 temp = (long) (op - origOp);
5223 smb_SetSMBDataLength(outp, temp);
5225 /* the data area is a variable block, which has a 5 (already there)
5226 * followed by the length of the # of data bytes. We now know this to
5227 * be "temp," although that includes the 3 bytes of vbl block header.
5228 * Deduct for them and fill in the length field.
5230 temp -= 3; /* deduct vbl block info */
5231 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5232 origOp[1] = (unsigned char)(temp & 0xff);
5233 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5234 if (returnedNames == 0)
5235 smb_DeleteDirSearch(dsp);
5236 smb_ReleaseDirSearch(dsp);
5237 cm_ReleaseSCache(scp);
5238 cm_ReleaseUser(userp);
5243 /* verify that this is a valid path to a directory. I don't know why they
5244 * don't use the get file attributes call.
5246 * SMB_COM_CHECK_DIRECTORY
5248 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5250 clientchar_t *pathp;
5252 cm_scache_t *rootScp;
5253 cm_scache_t *newScp;
5257 clientchar_t *tidPathp;
5263 pdata = smb_GetSMBData(inp, NULL);
5264 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5266 return CM_ERROR_BADSMB;
5267 osi_Log1(smb_logp, "SMB receive check path %S",
5268 osi_LogSaveClientString(smb_logp, pathp));
5270 rootScp = cm_data.rootSCachep;
5272 userp = smb_GetUserFromVCP(vcp, inp);
5274 caseFold = CM_FLAG_CASEFOLD;
5276 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5278 cm_ReleaseUser(userp);
5279 return CM_ERROR_NOSUCHPATH;
5281 code = cm_NameI(rootScp, pathp,
5282 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5283 userp, tidPathp, &req, &newScp);
5286 cm_ReleaseUser(userp);
5291 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5292 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5293 cm_ReleaseSCache(newScp);
5294 cm_ReleaseUser(userp);
5295 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5296 return CM_ERROR_PATH_NOT_COVERED;
5298 return CM_ERROR_NOSUCHPATH;
5300 #endif /* DFS_SUPPORT */
5302 /* now lock the vnode with a callback; returns with newScp locked */
5303 lock_ObtainWrite(&newScp->rw);
5304 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5305 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5307 if (code != CM_ERROR_NOACCESS) {
5308 lock_ReleaseWrite(&newScp->rw);
5309 cm_ReleaseSCache(newScp);
5310 cm_ReleaseUser(userp);
5314 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5317 attrs = smb_Attributes(newScp);
5319 if (!(attrs & SMB_ATTR_DIRECTORY))
5320 code = CM_ERROR_NOTDIR;
5322 lock_ReleaseWrite(&newScp->rw);
5324 cm_ReleaseSCache(newScp);
5325 cm_ReleaseUser(userp);
5329 /* SMB_COM_SET_INFORMATION */
5330 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5332 clientchar_t *pathp;
5334 cm_scache_t *rootScp;
5335 unsigned short attribute;
5337 cm_scache_t *newScp;
5341 clientchar_t *tidPathp;
5347 /* decode basic attributes we're passed */
5348 attribute = smb_GetSMBParm(inp, 0);
5349 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5351 datap = smb_GetSMBData(inp, NULL);
5352 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5354 return CM_ERROR_BADSMB;
5356 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5357 dosTime, attribute);
5359 rootScp = cm_data.rootSCachep;
5361 userp = smb_GetUserFromVCP(vcp, inp);
5363 caseFold = CM_FLAG_CASEFOLD;
5365 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5367 cm_ReleaseUser(userp);
5368 return CM_ERROR_NOSUCHFILE;
5370 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5371 tidPathp, &req, &newScp);
5374 cm_ReleaseUser(userp);
5379 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5380 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5381 cm_ReleaseSCache(newScp);
5382 cm_ReleaseUser(userp);
5383 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5384 return CM_ERROR_PATH_NOT_COVERED;
5386 return CM_ERROR_NOSUCHPATH;
5388 #endif /* DFS_SUPPORT */
5390 /* now lock the vnode with a callback; returns with newScp locked; we
5391 * need the current status to determine what the new status is, in some
5394 lock_ObtainWrite(&newScp->rw);
5395 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5396 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5398 lock_ReleaseWrite(&newScp->rw);
5399 cm_ReleaseSCache(newScp);
5400 cm_ReleaseUser(userp);
5404 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5406 /* Check for RO volume */
5407 if (newScp->flags & CM_SCACHEFLAG_RO) {
5408 lock_ReleaseWrite(&newScp->rw);
5409 cm_ReleaseSCache(newScp);
5410 cm_ReleaseUser(userp);
5411 return CM_ERROR_READONLY;
5414 /* prepare for setattr call */
5417 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5418 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5420 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5421 /* we're told to make a writable file read-only */
5422 attr.unixModeBits = newScp->unixModeBits & ~0222;
5423 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5425 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5426 /* we're told to make a read-only file writable */
5427 attr.unixModeBits = newScp->unixModeBits | 0222;
5428 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5430 lock_ReleaseWrite(&newScp->rw);
5432 /* now call setattr */
5434 code = cm_SetAttr(newScp, &attr, userp, &req);
5438 cm_ReleaseSCache(newScp);
5439 cm_ReleaseUser(userp);
5445 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5447 clientchar_t *pathp;
5449 cm_scache_t *rootScp;
5450 cm_scache_t *newScp, *dscp;
5455 clientchar_t *tidPathp;
5457 clientchar_t *lastComp;
5463 datap = smb_GetSMBData(inp, NULL);
5464 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5466 return CM_ERROR_BADSMB;
5468 if (*pathp == 0) /* null path */
5471 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5472 osi_LogSaveClientString(smb_logp, pathp));
5474 rootScp = cm_data.rootSCachep;
5476 userp = smb_GetUserFromVCP(vcp, inp);
5478 /* we shouldn't need this for V3 requests, but we seem to */
5479 caseFold = CM_FLAG_CASEFOLD;
5481 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5483 cm_ReleaseUser(userp);
5484 return CM_ERROR_NOSUCHFILE;
5488 * XXX Strange hack XXX
5490 * As of Patch 5 (16 July 97), we are having the following problem:
5491 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5492 * requests to look up "desktop.ini" in all the subdirectories.
5493 * This can cause zillions of timeouts looking up non-existent cells
5494 * and volumes, especially in the top-level directory.
5496 * We have not found any way to avoid this or work around it except
5497 * to explicitly ignore the requests for mount points that haven't
5498 * yet been evaluated and for directories that haven't yet been
5501 * We should modify this hack to provide a fake desktop.ini file
5502 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5504 spacep = inp->spacep;
5505 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5506 #ifndef SPECIAL_FOLDERS
5507 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5508 code = cm_NameI(rootScp, spacep->wdata,
5509 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5510 userp, tidPathp, &req, &dscp);
5513 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5514 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5516 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5517 return CM_ERROR_PATH_NOT_COVERED;
5519 return CM_ERROR_NOSUCHPATH;
5521 #endif /* DFS_SUPPORT */
5522 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5523 code = CM_ERROR_NOSUCHFILE;
5524 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5525 cm_buf_t *bp = buf_Find(dscp, &hzero);
5530 code = CM_ERROR_NOSUCHFILE;
5532 cm_ReleaseSCache(dscp);
5534 cm_ReleaseUser(userp);
5539 #endif /* SPECIAL_FOLDERS */
5541 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5542 tidPathp, &req, &newScp);
5544 cm_ReleaseUser(userp);
5549 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5550 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5551 cm_ReleaseSCache(newScp);
5552 cm_ReleaseUser(userp);
5553 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5554 return CM_ERROR_PATH_NOT_COVERED;
5556 return CM_ERROR_NOSUCHPATH;
5558 #endif /* DFS_SUPPORT */
5560 /* now lock the vnode with a callback; returns with newScp locked */
5561 lock_ObtainWrite(&newScp->rw);
5562 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5563 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5565 lock_ReleaseWrite(&newScp->rw);
5566 cm_ReleaseSCache(newScp);
5567 cm_ReleaseUser(userp);
5571 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5573 attrs = smb_Attributes(newScp);
5575 smb_SetSMBParm(outp, 0, attrs);
5577 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5578 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5579 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5580 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5581 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5582 smb_SetSMBParm(outp, 5, 0);
5583 smb_SetSMBParm(outp, 6, 0);
5584 smb_SetSMBParm(outp, 7, 0);
5585 smb_SetSMBParm(outp, 8, 0);
5586 smb_SetSMBParm(outp, 9, 0);
5587 smb_SetSMBDataLength(outp, 0);
5588 lock_ReleaseWrite(&newScp->rw);
5590 cm_ReleaseSCache(newScp);
5591 cm_ReleaseUser(userp);
5596 /* SMB_COM_TREE_DISCONNECT */
5597 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5601 osi_Log0(smb_logp, "SMB receive tree disconnect");
5603 /* find the tree and free it */
5604 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5606 lock_ObtainWrite(&smb_rctLock);
5608 smb_ReleaseTID(tidp, TRUE);
5609 lock_ReleaseWrite(&smb_rctLock);
5616 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5619 clientchar_t *pathp;
5620 clientchar_t *lastNamep;
5629 clientchar_t *tidPathp;
5635 datap = smb_GetSMBData(inp, NULL);
5636 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5638 return CM_ERROR_BADSMB;
5640 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5642 #ifdef DEBUG_VERBOSE
5646 hexpath = osi_HexifyString( pathp );
5647 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5652 share = smb_GetSMBParm(inp, 0);
5653 attribute = smb_GetSMBParm(inp, 1);
5655 spacep = inp->spacep;
5656 /* smb_StripLastComponent will strip "::$DATA" if present */
5657 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5659 if (!cm_IsValidClientString(pathp)) {
5661 clientchar_t * hexp;
5663 hexp = cm_GetRawCharsAlloc(pathp, -1);
5664 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5665 osi_LogSaveClientString(smb_logp, hexp));
5669 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5671 return CM_ERROR_BADNTFILENAME;
5674 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5675 /* special case magic file name for receiving IOCTL requests
5676 * (since IOCTL calls themselves aren't getting through).
5678 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5679 smb_SetupIoctlFid(fidp, spacep);
5680 smb_SetSMBParm(outp, 0, fidp->fid);
5681 smb_SetSMBParm(outp, 1, 0); /* attrs */
5682 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5683 smb_SetSMBParm(outp, 3, 0);
5684 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5685 smb_SetSMBParm(outp, 5, 0x7fff);
5686 /* pass the open mode back */
5687 smb_SetSMBParm(outp, 6, (share & 0xf));
5688 smb_SetSMBDataLength(outp, 0);
5689 smb_ReleaseFID(fidp);
5693 userp = smb_GetUserFromVCP(vcp, inp);
5695 caseFold = CM_FLAG_CASEFOLD;
5697 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5699 cm_ReleaseUser(userp);
5700 return CM_ERROR_NOSUCHPATH;
5702 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5703 tidPathp, &req, &scp);
5706 cm_ReleaseUser(userp);
5711 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5712 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5713 cm_ReleaseSCache(scp);
5714 cm_ReleaseUser(userp);
5715 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5716 return CM_ERROR_PATH_NOT_COVERED;
5718 return CM_ERROR_NOSUCHPATH;
5720 #endif /* DFS_SUPPORT */
5722 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5724 cm_ReleaseSCache(scp);
5725 cm_ReleaseUser(userp);
5729 /* don't need callback to check file type, since file types never
5730 * change, and namei and cm_Lookup all stat the object at least once on
5731 * a successful return.
5733 if (scp->fileType != CM_SCACHETYPE_FILE) {
5734 cm_ReleaseSCache(scp);
5735 cm_ReleaseUser(userp);
5736 return CM_ERROR_ISDIR;
5739 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5740 osi_assertx(fidp, "null smb_fid_t");
5742 lock_ObtainMutex(&fidp->mx);
5743 if ((share & 0xf) == 0)
5744 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5745 else if ((share & 0xf) == 1)
5746 fidp->flags |= SMB_FID_OPENWRITE;
5748 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5752 fidp->userp = userp;
5754 /* and a pointer to the vnode */
5756 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5757 lock_ObtainWrite(&scp->rw);
5758 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5760 smb_SetSMBParm(outp, 0, fidp->fid);
5761 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5762 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5763 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5764 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5765 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5766 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5767 /* pass the open mode back; XXXX add access checks */
5768 smb_SetSMBParm(outp, 6, (share & 0xf));
5769 smb_SetSMBDataLength(outp, 0);
5770 lock_ReleaseMutex(&fidp->mx);
5771 lock_ReleaseRead(&scp->rw);
5774 cm_Open(scp, 0, userp);
5776 /* send and free packet */
5777 smb_ReleaseFID(fidp);
5778 cm_ReleaseUser(userp);
5779 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5783 typedef struct smb_unlinkRock {
5788 clientchar_t *maskp; /* pointer to the star pattern */
5791 cm_dirEntryList_t * matches;
5794 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5797 smb_unlinkRock_t *rockp;
5800 normchar_t matchName[MAX_PATH];
5804 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5805 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5806 caseFold |= CM_FLAG_8DOT3;
5808 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5809 /* Can't convert name */
5810 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5811 osi_LogSaveString(smb_logp, dep->name));
5815 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5817 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5818 !cm_Is8Dot3(matchName)) {
5819 cm_Gen8Dot3Name(dep, matchName, NULL);
5820 /* 8.3 matches are always case insensitive */
5821 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5824 osi_Log1(smb_logp, "Found match %S",
5825 osi_LogSaveClientString(smb_logp, matchName));
5827 cm_DirEntryListAdd(dep->name, &rockp->matches);
5831 /* If we made a case sensitive exact match, we might as well quit now. */
5832 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5833 code = CM_ERROR_STOPNOW;
5842 /* SMB_COM_DELETE */
5843 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5847 clientchar_t *pathp;
5851 clientchar_t *lastNamep;
5852 smb_unlinkRock_t rock;
5856 clientchar_t *tidPathp;
5860 memset(&rock, 0, sizeof(rock));
5862 attribute = smb_GetSMBParm(inp, 0);
5864 tp = smb_GetSMBData(inp, NULL);
5865 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5867 return CM_ERROR_BADSMB;
5869 osi_Log1(smb_logp, "SMB receive unlink %S",
5870 osi_LogSaveClientString(smb_logp, pathp));
5872 spacep = inp->spacep;
5873 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5875 userp = smb_GetUserFromVCP(vcp, inp);
5877 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5879 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5881 cm_ReleaseUser(userp);
5882 return CM_ERROR_NOSUCHPATH;
5884 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5887 cm_ReleaseUser(userp);
5892 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5893 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5894 cm_ReleaseSCache(dscp);
5895 cm_ReleaseUser(userp);
5896 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5897 return CM_ERROR_PATH_NOT_COVERED;
5899 return CM_ERROR_NOSUCHPATH;
5901 #endif /* DFS_SUPPORT */
5903 /* otherwise, scp points to the parent directory. */
5910 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5912 code = CM_ERROR_NOSUCHFILE;
5915 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5918 thyper.HighPart = 0;
5923 rock.matches = NULL;
5925 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5926 * match. If that fails, we do a case insensitve match.
5928 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5929 !smb_IsStarMask(rock.maskp)) {
5930 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5933 thyper.HighPart = 0;
5934 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5939 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5941 if (code == CM_ERROR_STOPNOW)
5944 if (code == 0 && rock.matches) {
5945 cm_dirEntryList_t * entry;
5947 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5948 normchar_t normalizedName[MAX_PATH];
5950 /* Note: entry->name is a non-normalized name */
5952 osi_Log1(smb_logp, "Unlinking %s",
5953 osi_LogSaveString(smb_logp, entry->name));
5955 /* We assume this works because entry->name was
5956 successfully converted in smb_UnlinkProc() once. */
5957 cm_FsStringToNormString(entry->name, -1,
5958 normalizedName, lengthof(normalizedName));
5960 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5962 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5963 smb_NotifyChange(FILE_ACTION_REMOVED,
5964 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5965 dscp, normalizedName, NULL, TRUE);
5969 cm_DirEntryListFree(&rock.matches);
5973 cm_ReleaseUser(userp);
5976 cm_ReleaseSCache(dscp);
5981 if (code == 0 && !rock.any)
5982 code = CM_ERROR_NOSUCHFILE;
5986 typedef struct smb_renameRock {
5987 cm_scache_t *odscp; /* old dir */
5988 cm_scache_t *ndscp; /* new dir */
5989 cm_user_t *userp; /* user */
5990 cm_req_t *reqp; /* request struct */
5991 smb_vc_t *vcp; /* virtual circuit */
5992 normchar_t *maskp; /* pointer to star pattern of old file name */
5993 int flags; /* tilde, casefold, etc */
5994 clientchar_t *newNamep; /* ptr to the new file's name */
5995 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5996 clientchar_t clOldName[MAX_PATH]; /* client name */
6000 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6003 smb_renameRock_t *rockp;
6006 normchar_t matchName[MAX_PATH];
6008 rockp = (smb_renameRock_t *) vrockp;
6010 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6011 /* Can't convert string */
6012 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6013 osi_LogSaveString(smb_logp, dep->name));
6017 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6018 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6019 caseFold |= CM_FLAG_8DOT3;
6021 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6023 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6024 !cm_Is8Dot3(matchName)) {
6025 cm_Gen8Dot3Name(dep, matchName, NULL);
6026 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6031 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6032 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6034 code = CM_ERROR_STOPNOW;
6044 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6047 cm_space_t *spacep = NULL;
6048 smb_renameRock_t rock;
6049 cm_scache_t *oldDscp = NULL;
6050 cm_scache_t *newDscp = NULL;
6051 cm_scache_t *tmpscp= NULL;
6052 cm_scache_t *tmpscp2 = NULL;
6053 clientchar_t *oldLastNamep;
6054 clientchar_t *newLastNamep;
6058 clientchar_t *tidPathp;
6062 userp = smb_GetUserFromVCP(vcp, inp);
6063 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6065 cm_ReleaseUser(userp);
6066 return CM_ERROR_NOSUCHPATH;
6070 memset(&rock, 0, sizeof(rock));
6072 spacep = inp->spacep;
6073 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6075 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6076 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6077 userp, tidPathp, &req, &oldDscp);
6079 cm_ReleaseUser(userp);
6084 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6085 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6086 cm_ReleaseSCache(oldDscp);
6087 cm_ReleaseUser(userp);
6088 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6089 return CM_ERROR_PATH_NOT_COVERED;
6091 return CM_ERROR_NOSUCHPATH;
6093 #endif /* DFS_SUPPORT */
6095 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6096 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6097 userp, tidPathp, &req, &newDscp);
6100 cm_ReleaseSCache(oldDscp);
6101 cm_ReleaseUser(userp);
6106 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6107 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6108 cm_ReleaseSCache(oldDscp);
6109 cm_ReleaseSCache(newDscp);
6110 cm_ReleaseUser(userp);
6111 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6112 return CM_ERROR_PATH_NOT_COVERED;
6114 return CM_ERROR_NOSUCHPATH;
6116 #endif /* DFS_SUPPORT */
6119 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6120 * next, get the component names, and lower case them.
6123 /* handle the old name first */
6125 oldLastNamep = oldPathp;
6129 /* and handle the new name, too */
6131 newLastNamep = newPathp;
6135 /* TODO: The old name could be a wildcard. The new name must not be */
6137 /* Check if the file already exists; if so return error */
6138 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6139 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6140 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6142 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6143 osi_LogSaveClientString(smb_logp, newLastNamep));
6145 /* Check if the old and the new names differ only in case. If so return
6146 * success, else return CM_ERROR_EXISTS
6148 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6150 /* This would be a success only if the old file is *as same as* the new file */
6151 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6153 if (tmpscp == tmpscp2)
6156 code = CM_ERROR_EXISTS;
6157 cm_ReleaseSCache(tmpscp2);
6160 code = CM_ERROR_NOSUCHFILE;
6163 /* file exist, do not rename, also fixes move */
6164 osi_Log0(smb_logp, "Can't rename. Target already exists");
6165 code = CM_ERROR_EXISTS;
6170 /* do the vnode call */
6171 rock.odscp = oldDscp;
6172 rock.ndscp = newDscp;
6176 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6178 code = CM_ERROR_NOSUCHFILE;
6181 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6182 rock.newNamep = newLastNamep;
6183 rock.fsOldName[0] = '\0';
6184 rock.clOldName[0] = '\0';
6187 /* Now search the directory for the pattern, and do the appropriate rename when found */
6188 thyper.LowPart = 0; /* search dir from here */
6189 thyper.HighPart = 0;
6191 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6192 if (code == 0 && !rock.any) {
6194 thyper.HighPart = 0;
6195 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6196 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6198 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6200 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6201 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6202 rock.ndscp, rock.newNamep, rock.userp,
6204 /* if the call worked, stop doing the search now, since we
6205 * really only want to rename one file.
6208 osi_Log0(smb_logp, "cm_Rename failure");
6209 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6210 } else if (code == 0) {
6211 code = CM_ERROR_NOSUCHFILE;
6214 /* Handle Change Notification */
6216 * Being lazy, not distinguishing between files and dirs in this
6217 * filter, since we'd have to do a lookup.
6220 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6221 if (oldDscp == newDscp) {
6222 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6223 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6224 filter, oldDscp, rock.clOldName,
6225 newLastNamep, TRUE);
6227 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6228 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6229 filter, oldDscp, rock.clOldName,
6231 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6232 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6233 filter, newDscp, newLastNamep,
6240 cm_ReleaseSCache(tmpscp);
6242 cm_ReleaseUser(userp);
6244 cm_ReleaseSCache(oldDscp);
6246 cm_ReleaseSCache(newDscp);
6254 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6257 cm_space_t *spacep = NULL;
6258 cm_scache_t *oldDscp = NULL;
6259 cm_scache_t *newDscp = NULL;
6260 cm_scache_t *tmpscp= NULL;
6261 cm_scache_t *tmpscp2 = NULL;
6262 cm_scache_t *sscp = NULL;
6263 clientchar_t *oldLastNamep;
6264 clientchar_t *newLastNamep;
6267 clientchar_t *tidPathp;
6271 userp = smb_GetUserFromVCP(vcp, inp);
6273 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6275 cm_ReleaseUser(userp);
6276 return CM_ERROR_NOSUCHPATH;
6281 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6283 spacep = inp->spacep;
6284 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6286 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6287 userp, tidPathp, &req, &oldDscp);
6289 cm_ReleaseUser(userp);
6294 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6295 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6296 cm_ReleaseSCache(oldDscp);
6297 cm_ReleaseUser(userp);
6298 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6299 return CM_ERROR_PATH_NOT_COVERED;
6301 return CM_ERROR_NOSUCHPATH;
6303 #endif /* DFS_SUPPORT */
6305 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6306 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6307 userp, tidPathp, &req, &newDscp);
6309 cm_ReleaseSCache(oldDscp);
6310 cm_ReleaseUser(userp);
6315 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6316 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6317 cm_ReleaseSCache(newDscp);
6318 cm_ReleaseSCache(oldDscp);
6319 cm_ReleaseUser(userp);
6320 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6321 return CM_ERROR_PATH_NOT_COVERED;
6323 return CM_ERROR_NOSUCHPATH;
6325 #endif /* DFS_SUPPORT */
6327 /* Now, although we did two lookups for the two directories (because the same
6328 * directory can be referenced through different paths), we only allow hard links
6329 * within the same directory. */
6330 if (oldDscp != newDscp) {
6331 cm_ReleaseSCache(oldDscp);
6332 cm_ReleaseSCache(newDscp);
6333 cm_ReleaseUser(userp);
6334 return CM_ERROR_CROSSDEVLINK;
6337 /* handle the old name first */
6339 oldLastNamep = oldPathp;
6343 /* and handle the new name, too */
6345 newLastNamep = newPathp;
6349 /* now lookup the old name */
6350 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6351 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6353 cm_ReleaseSCache(oldDscp);
6354 cm_ReleaseSCache(newDscp);
6355 cm_ReleaseUser(userp);
6359 /* Check if the file already exists; if so return error */
6360 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6361 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6362 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6364 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6365 osi_LogSaveClientString(smb_logp, newLastNamep));
6367 /* if the existing link is to the same file, then we return success */
6369 if(sscp == tmpscp) {
6372 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6373 code = CM_ERROR_EXISTS;
6378 cm_ReleaseSCache(tmpscp);
6379 cm_ReleaseSCache(sscp);
6380 cm_ReleaseSCache(newDscp);
6381 cm_ReleaseSCache(oldDscp);
6382 cm_ReleaseUser(userp);
6386 /* now create the hardlink */
6387 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6388 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6389 osi_Log1(smb_logp," Link returns 0x%x", code);
6391 /* Handle Change Notification */
6393 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6394 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6395 smb_NotifyChange(FILE_ACTION_ADDED,
6396 filter, newDscp, newLastNamep,
6401 cm_ReleaseSCache(tmpscp);
6402 cm_ReleaseUser(userp);
6403 cm_ReleaseSCache(sscp);
6404 cm_ReleaseSCache(oldDscp);
6405 cm_ReleaseSCache(newDscp);
6409 /* SMB_COM_RENAME */
6411 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6413 clientchar_t *oldPathp;
6414 clientchar_t *newPathp;
6418 tp = smb_GetSMBData(inp, NULL);
6419 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6421 return CM_ERROR_BADSMB;
6422 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6424 return CM_ERROR_BADSMB;
6426 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6427 osi_LogSaveClientString(smb_logp, oldPathp),
6428 osi_LogSaveClientString(smb_logp, newPathp));
6430 if (!cm_IsValidClientString(newPathp)) {
6432 clientchar_t * hexp;
6434 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6435 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6436 osi_LogSaveClientString(smb_logp, hexp));
6440 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6442 return CM_ERROR_BADNTFILENAME;
6445 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6447 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6453 typedef struct smb_rmdirRock {
6457 normchar_t *maskp; /* pointer to the star pattern */
6460 cm_dirEntryList_t * matches;
6463 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6466 smb_rmdirRock_t *rockp;
6468 normchar_t matchName[MAX_PATH];
6470 rockp = (smb_rmdirRock_t *) vrockp;
6472 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6473 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6474 osi_LogSaveString(smb_logp, dep->name));
6478 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6479 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6481 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6483 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6484 !cm_Is8Dot3(matchName)) {
6485 cm_Gen8Dot3Name(dep, matchName, NULL);
6486 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6491 cm_DirEntryListAdd(dep->name, &rockp->matches);
6498 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6501 clientchar_t *pathp;
6505 clientchar_t *lastNamep;
6506 smb_rmdirRock_t rock;
6510 clientchar_t *tidPathp;
6514 memset(&rock, 0, sizeof(rock));
6516 tp = smb_GetSMBData(inp, NULL);
6517 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6519 return CM_ERROR_BADSMB;
6521 spacep = inp->spacep;
6522 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6524 userp = smb_GetUserFromVCP(vcp, inp);
6526 caseFold = CM_FLAG_CASEFOLD;
6528 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6530 cm_ReleaseUser(userp);
6531 return CM_ERROR_NOSUCHPATH;
6533 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6534 userp, tidPathp, &req, &dscp);
6537 cm_ReleaseUser(userp);
6542 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6543 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6544 cm_ReleaseSCache(dscp);
6545 cm_ReleaseUser(userp);
6546 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6547 return CM_ERROR_PATH_NOT_COVERED;
6549 return CM_ERROR_NOSUCHPATH;
6551 #endif /* DFS_SUPPORT */
6553 /* otherwise, scp points to the parent directory. */
6560 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6562 code = CM_ERROR_NOSUCHFILE;
6565 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6568 thyper.HighPart = 0;
6572 rock.matches = NULL;
6574 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6575 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6576 if (code == 0 && !rock.any) {
6578 thyper.HighPart = 0;
6579 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6580 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6583 if (code == 0 && rock.matches) {
6584 cm_dirEntryList_t * entry;
6586 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6587 clientchar_t clientName[MAX_PATH];
6589 /* We assume this will succeed because smb_RmdirProc()
6590 successfully converted entry->name once above. */
6591 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6593 osi_Log1(smb_logp, "Removing directory %s",
6594 osi_LogSaveString(smb_logp, entry->name));
6596 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6598 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6599 smb_NotifyChange(FILE_ACTION_REMOVED,
6600 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6601 dscp, clientName, NULL, TRUE);
6607 cm_DirEntryListFree(&rock.matches);
6610 cm_ReleaseUser(userp);
6613 cm_ReleaseSCache(dscp);
6615 if (code == 0 && !rock.any)
6616 code = CM_ERROR_NOSUCHFILE;
6625 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6635 fid = smb_GetSMBParm(inp, 0);
6637 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6639 fid = smb_ChainFID(fid, inp);
6640 fidp = smb_FindFID(vcp, fid, 0);
6642 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6644 return CM_ERROR_BADFD;
6646 userp = smb_GetUserFromVCP(vcp, inp);
6648 lock_ObtainMutex(&fidp->mx);
6649 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6650 cm_ReleaseUser(userp);
6651 lock_ReleaseMutex(&fidp->mx);
6652 smb_ReleaseFID(fidp);
6653 return CM_ERROR_BADFD;
6656 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6657 lock_ReleaseMutex(&fidp->mx);
6658 cm_ReleaseUser(userp);
6659 smb_CloseFID(vcp, fidp, NULL, 0);
6660 smb_ReleaseFID(fidp);
6661 return CM_ERROR_NOSUCHFILE;
6664 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6665 cm_scache_t * scp = fidp->scp;
6667 lock_ReleaseMutex(&fidp->mx);
6668 code = cm_FSync(scp, userp, &req);
6669 cm_ReleaseSCache(scp);
6671 lock_ReleaseMutex(&fidp->mx);
6675 cm_ReleaseUser(userp);
6676 smb_ReleaseFID(fidp);
6680 struct smb_FullNameRock {
6683 clientchar_t *fullName;
6684 fschar_t *originalName;
6687 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6690 normchar_t matchName[MAX_PATH];
6691 struct smb_FullNameRock *vrockp;
6693 vrockp = (struct smb_FullNameRock *)rockp;
6695 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6696 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6697 osi_LogSaveString(smb_logp, dep->name));
6701 if (!cm_Is8Dot3(matchName)) {
6702 clientchar_t shortName[13];
6704 cm_Gen8Dot3Name(dep, shortName, NULL);
6706 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6707 vrockp->fullName = cm_ClientStrDup(matchName);
6708 vrockp->originalName = cm_FsStrDup(dep->name);
6709 return CM_ERROR_STOPNOW;
6712 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6713 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6714 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6715 vrockp->fullName = cm_ClientStrDup(matchName);
6716 vrockp->originalName = cm_FsStrDup(dep->name);
6717 return CM_ERROR_STOPNOW;
6722 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6723 clientchar_t **newPathp, fschar_t ** originalPathp,
6724 cm_user_t *userp, cm_req_t *reqp)
6726 struct smb_FullNameRock rock;
6729 memset(&rock, 0, sizeof(rock));
6733 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6734 if (code == CM_ERROR_STOPNOW) {
6735 *newPathp = rock.fullName;
6736 *originalPathp = rock.originalName;
6738 *newPathp = cm_ClientStrDup(pathp);
6739 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6743 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6744 afs_uint32 dosTime) {
6747 cm_scache_t *dscp = NULL;
6748 clientchar_t *pathp = NULL;
6749 cm_scache_t * scp = NULL;
6750 cm_scache_t *delscp = NULL;
6751 int nullcreator = 0;
6753 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6754 fidp, fidp->fid, scp, vcp);
6757 lock_ObtainMutex(&fidp->mx);
6758 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6760 lock_ReleaseMutex(&fidp->mx);
6761 osi_Log0(smb_logp, " No user specified. Not closing fid");
6762 return CM_ERROR_BADFD;
6765 userp = fidp->userp; /* no hold required since fidp is held
6766 throughout the function */
6767 lock_ReleaseMutex(&fidp->mx);
6772 lock_ObtainWrite(&smb_rctLock);
6773 if (fidp->deleteOk) {
6774 osi_Log0(smb_logp, " Fid already closed.");
6775 lock_ReleaseWrite(&smb_rctLock);
6776 return CM_ERROR_BADFD;
6779 lock_ReleaseWrite(&smb_rctLock);
6781 lock_ObtainMutex(&fidp->mx);
6782 if (fidp->NTopen_dscp) {
6783 dscp = fidp->NTopen_dscp;
6784 cm_HoldSCache(dscp);
6787 if (fidp->NTopen_pathp)
6788 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6795 /* Don't jump the gun on an async raw write */
6796 while (fidp->raw_writers) {
6797 lock_ReleaseMutex(&fidp->mx);
6798 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6799 lock_ObtainMutex(&fidp->mx);
6802 /* watch for ioctl closes, and read-only opens */
6804 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6805 == SMB_FID_OPENWRITE) {
6806 if (dosTime != 0 && dosTime != -1) {
6807 lock_ObtainWrite(&fidp->scp->rw);
6808 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6809 /* This fixes defect 10958 */
6810 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6811 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6812 lock_ReleaseWrite(&fidp->scp->rw);
6814 if (smb_AsyncStore != 2) {
6815 lock_ReleaseMutex(&fidp->mx);
6816 code = cm_FSync(scp, userp, &req);
6817 lock_ObtainMutex(&fidp->mx);
6823 /* unlock any pending locks */
6824 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6825 scp->fileType == CM_SCACHETYPE_FILE) {
6829 lock_ReleaseMutex(&fidp->mx);
6831 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6833 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6834 lock_ObtainWrite(&scp->rw);
6836 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6837 CM_SCACHESYNC_NEEDCALLBACK
6838 | CM_SCACHESYNC_GETSTATUS
6839 | CM_SCACHESYNC_LOCK);
6843 "smb CoreClose SyncOp failure code 0x%x", tcode);
6844 goto post_syncopdone;
6847 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6849 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6853 lock_ReleaseWrite(&scp->rw);
6854 lock_ObtainMutex(&fidp->mx);
6857 if (fidp->flags & SMB_FID_DELONCLOSE) {
6858 clientchar_t *fullPathp = NULL;
6859 fschar_t *originalNamep = NULL;
6861 lock_ReleaseMutex(&fidp->mx);
6863 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6868 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6869 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6870 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6872 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6873 smb_NotifyChange(FILE_ACTION_REMOVED,
6874 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6875 dscp, fullPathp, NULL, TRUE);
6878 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6880 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6881 smb_NotifyChange(FILE_ACTION_REMOVED,
6882 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6883 dscp, fullPathp, NULL, TRUE);
6890 free(originalNamep);
6892 lock_ObtainMutex(&fidp->mx);
6893 fidp->flags &= ~SMB_FID_DELONCLOSE;
6896 /* if this was a newly created file, then clear the creator
6897 * in the stat cache entry. */
6898 if (fidp->flags & SMB_FID_CREATED) {
6900 fidp->flags &= ~SMB_FID_CREATED;
6903 if (fidp->flags & SMB_FID_NTOPEN) {
6904 cm_ReleaseSCache(fidp->NTopen_dscp);
6905 fidp->NTopen_dscp = NULL;
6906 free(fidp->NTopen_pathp);
6907 fidp->NTopen_pathp = NULL;
6908 fidp->flags &= ~SMB_FID_NTOPEN;
6910 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6911 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6914 if (fidp->NTopen_wholepathp) {
6915 free(fidp->NTopen_wholepathp);
6916 fidp->NTopen_wholepathp = NULL;
6920 cm_ReleaseSCache(fidp->scp);
6923 lock_ReleaseMutex(&fidp->mx);
6926 cm_ReleaseSCache(dscp);
6929 cm_ReleaseSCache(delscp);
6933 lock_ObtainWrite(&scp->rw);
6934 if (nullcreator && scp->creator == userp)
6935 scp->creator = NULL;
6936 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6937 lock_ReleaseWrite(&scp->rw);
6938 cm_ReleaseSCache(scp);
6948 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6956 fid = smb_GetSMBParm(inp, 0);
6957 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6959 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6961 fid = smb_ChainFID(fid, inp);
6962 fidp = smb_FindFID(vcp, fid, 0);
6964 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
6966 return CM_ERROR_BADFD;
6969 userp = smb_GetUserFromVCP(vcp, inp);
6971 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6973 smb_ReleaseFID(fidp);
6974 cm_ReleaseUser(userp);
6979 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6981 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6982 cm_user_t *userp, long *readp)
6988 osi_hyper_t fileLength;
6990 osi_hyper_t lastByte;
6991 osi_hyper_t bufferOffset;
6995 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6998 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6999 fidp->fid, offsetp->LowPart, count);
7003 lock_ObtainMutex(&fidp->mx);
7004 /* make sure we have a readable FD */
7005 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7006 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7007 fidp->fid, fidp->flags);
7008 lock_ReleaseMutex(&fidp->mx);
7009 code = CM_ERROR_BADFDOP;
7014 lock_ReleaseMutex(&fidp->mx);
7015 code = CM_ERROR_BADFD;
7026 lock_ObtainWrite(&scp->rw);
7028 if (offset.HighPart == 0) {
7029 chunk = offset.LowPart >> cm_logChunkSize;
7030 if (chunk != fidp->curr_chunk) {
7031 fidp->prev_chunk = fidp->curr_chunk;
7032 fidp->curr_chunk = chunk;
7034 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7037 lock_ReleaseMutex(&fidp->mx);
7039 /* start by looking up the file's end */
7040 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7041 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7045 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7047 /* now we have the entry locked, look up the length */
7048 fileLength = scp->length;
7050 /* adjust count down so that it won't go past EOF */
7051 thyper.LowPart = count;
7052 thyper.HighPart = 0;
7053 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7055 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7056 /* we'd read past EOF, so just stop at fileLength bytes.
7057 * Start by computing how many bytes remain in the file.
7059 thyper = LargeIntegerSubtract(fileLength, offset);
7061 /* if we are past EOF, read 0 bytes */
7062 if (LargeIntegerLessThanZero(thyper))
7065 count = thyper.LowPart;
7070 /* now, copy the data one buffer at a time,
7071 * until we've filled the request packet
7074 /* if we've copied all the data requested, we're done */
7075 if (count <= 0) break;
7077 /* otherwise, load up a buffer of data */
7078 thyper.HighPart = offset.HighPart;
7079 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7080 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7083 buf_Release(bufferp);
7086 lock_ReleaseWrite(&scp->rw);
7088 code = buf_Get(scp, &thyper, &req, &bufferp);
7090 lock_ObtainWrite(&scp->rw);
7091 if (code) goto done;
7092 bufferOffset = thyper;
7094 /* now get the data in the cache */
7096 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7097 CM_SCACHESYNC_NEEDCALLBACK |
7098 CM_SCACHESYNC_READ);
7102 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7104 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7106 /* otherwise, load the buffer and try again */
7107 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7111 buf_Release(bufferp);
7115 } /* if (wrong buffer) ... */
7117 /* now we have the right buffer loaded. Copy out the
7118 * data from here to the user's buffer.
7120 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7122 /* and figure out how many bytes we want from this buffer */
7123 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7124 if (nbytes > count) nbytes = count; /* don't go past EOF */
7126 /* now copy the data */
7127 memcpy(op, bufferp->datap + bufIndex, nbytes);
7129 /* adjust counters, pointers, etc. */
7132 thyper.LowPart = nbytes;
7133 thyper.HighPart = 0;
7134 offset = LargeIntegerAdd(thyper, offset);
7138 lock_ReleaseWrite(&scp->rw);
7140 buf_Release(bufferp);
7142 if (code == 0 && sequential)
7143 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7145 cm_ReleaseSCache(scp);
7148 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7149 fidp->fid, code, *readp);
7154 * smb_WriteData -- common code for Write and Raw Write
7156 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7157 cm_user_t *userp, long *writtenp)
7159 osi_hyper_t offset = *offsetp;
7162 cm_scache_t *scp = NULL;
7163 osi_hyper_t fileLength; /* file's length at start of write */
7164 osi_hyper_t minLength; /* don't read past this */
7165 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7166 cm_buf_t *bufferp = NULL;
7167 osi_hyper_t thyper; /* hyper tmp variable */
7168 osi_hyper_t bufferOffset;
7169 afs_uint32 bufIndex; /* index in buffer where our data is */
7170 int doWriteBack = 0;
7171 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7175 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7176 fidp->fid, offsetp->LowPart, count);
7180 lock_ObtainMutex(&fidp->mx);
7181 /* make sure we have a writable FD */
7182 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7183 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7184 fidp->fid, fidp->flags);
7185 lock_ReleaseMutex(&fidp->mx);
7186 code = CM_ERROR_BADFDOP;
7194 lock_ReleaseMutex(&fidp->mx);
7196 lock_ObtainWrite(&scp->rw);
7197 /* start by looking up the file's end */
7198 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7199 CM_SCACHESYNC_NEEDCALLBACK
7200 | CM_SCACHESYNC_SETSTATUS
7201 | CM_SCACHESYNC_GETSTATUS);
7205 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7207 /* now we have the entry locked, look up the length */
7208 fileLength = scp->length;
7209 minLength = fileLength;
7210 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7211 minLength = scp->serverLength;
7213 /* adjust file length if we extend past EOF */
7214 thyper.LowPart = count;
7215 thyper.HighPart = 0;
7216 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7217 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7218 /* we'd write past EOF, so extend the file */
7219 scp->mask |= CM_SCACHEMASK_LENGTH;
7220 scp->length = thyper;
7221 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7223 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7225 /* now, if the new position (thyper) and the old (offset) are in
7226 * different storeback windows, remember to store back the previous
7227 * storeback window when we're done with the write.
7229 * the purpose of this logic is to slow down the CIFS client
7230 * in order to avoid the client disconnecting during the CLOSE
7231 * operation if there are too many dirty buffers left to write
7232 * than can be accomplished during 45 seconds. This used to be
7233 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7234 * so that we can read larger amounts of data at a time.
7236 if (smb_AsyncStore == 1 &&
7237 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7238 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7239 /* they're different */
7241 writeBackOffset.HighPart = offset.HighPart;
7242 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7247 /* now, copy the data one buffer at a time, until we've filled the
7250 /* if we've copied all the data requested, we're done */
7254 /* handle over quota or out of space */
7255 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7256 *writtenp = written;
7257 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7261 /* otherwise, load up a buffer of data */
7262 thyper.HighPart = offset.HighPart;
7263 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7264 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7267 lock_ReleaseMutex(&bufferp->mx);
7268 buf_Release(bufferp);
7271 lock_ReleaseWrite(&scp->rw);
7273 code = buf_Get(scp, &thyper, &req, &bufferp);
7275 lock_ObtainMutex(&bufferp->mx);
7276 lock_ObtainWrite(&scp->rw);
7277 if (code) goto done;
7279 bufferOffset = thyper;
7281 /* now get the data in the cache */
7283 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7284 CM_SCACHESYNC_NEEDCALLBACK
7285 | CM_SCACHESYNC_WRITE
7286 | CM_SCACHESYNC_BUFLOCKED);
7290 cm_SyncOpDone(scp, bufferp,
7291 CM_SCACHESYNC_NEEDCALLBACK
7292 | CM_SCACHESYNC_WRITE
7293 | CM_SCACHESYNC_BUFLOCKED);
7295 /* If we're overwriting the entire buffer, or
7296 * if we're writing at or past EOF, mark the
7297 * buffer as current so we don't call
7298 * cm_GetBuffer. This skips the fetch from the
7299 * server in those cases where we're going to
7300 * obliterate all the data in the buffer anyway,
7301 * or in those cases where there is no useful
7302 * data at the server to start with.
7304 * Use minLength instead of scp->length, since
7305 * the latter has already been updated by this
7308 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7309 || LargeIntegerEqualTo(offset, bufferp->offset)
7310 && (count >= cm_data.buf_blockSize
7311 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7312 ConvertLongToLargeInteger(count)),
7314 if (count < cm_data.buf_blockSize
7315 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7316 memset(bufferp->datap, 0,
7317 cm_data.buf_blockSize);
7318 bufferp->dataVersion = scp->dataVersion;
7321 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7323 /* otherwise, load the buffer and try again */
7324 lock_ReleaseMutex(&bufferp->mx);
7325 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7327 lock_ReleaseWrite(&scp->rw);
7328 lock_ObtainMutex(&bufferp->mx);
7329 lock_ObtainWrite(&scp->rw);
7333 lock_ReleaseMutex(&bufferp->mx);
7334 buf_Release(bufferp);
7338 } /* if (wrong buffer) ... */
7340 /* now we have the right buffer loaded. Copy out the
7341 * data from here to the user's buffer.
7343 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7345 /* and figure out how many bytes we want from this buffer */
7346 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7348 nbytes = count; /* don't go past end of request */
7350 /* now copy the data */
7351 memcpy(bufferp->datap + bufIndex, op, nbytes);
7352 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7354 /* adjust counters, pointers, etc. */
7358 thyper.LowPart = nbytes;
7359 thyper.HighPart = 0;
7360 offset = LargeIntegerAdd(thyper, offset);
7364 lock_ReleaseWrite(&scp->rw);
7367 lock_ReleaseMutex(&bufferp->mx);
7368 buf_Release(bufferp);
7371 lock_ObtainMutex(&fidp->mx);
7372 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7373 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7375 lock_ReleaseMutex(&fidp->mx);
7376 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7377 fidp->NTopen_dscp, fidp->NTopen_pathp,
7380 lock_ReleaseMutex(&fidp->mx);
7384 if (smb_AsyncStore > 0) {
7388 lock_ObtainWrite(&scp->rw);
7389 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7391 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7392 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7394 lock_ReleaseWrite(&scp->rw);
7395 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7396 writeBackOffset.HighPart,
7397 smb_AsyncStoreSize, 0, userp);
7398 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7401 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7405 cm_ReleaseSCache(scp);
7408 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7409 fidp->fid, code, *writtenp);
7414 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7417 unsigned short count;
7419 unsigned short hint;
7420 long written = 0, total_written = 0;
7423 smb_t* smbp = (smb_t*) inp;
7427 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7429 int inDataBlockCount;
7431 fd = smb_GetSMBParm(inp, 0);
7432 count = smb_GetSMBParm(inp, 1);
7433 offset.HighPart = 0; /* too bad */
7434 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7435 hint = smb_GetSMBParm(inp, 4);
7437 op = smb_GetSMBData(inp, NULL);
7438 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7440 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7441 fd, offset.LowPart, count);
7443 fd = smb_ChainFID(fd, inp);
7444 fidp = smb_FindFID(vcp, fd, 0);
7446 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7448 return CM_ERROR_BADFD;
7451 lock_ObtainMutex(&fidp->mx);
7452 if (fidp->flags & SMB_FID_IOCTL) {
7453 lock_ReleaseMutex(&fidp->mx);
7454 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7455 smb_ReleaseFID(fidp);
7456 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7460 if (fidp->flags & SMB_FID_RPC) {
7461 lock_ReleaseMutex(&fidp->mx);
7462 code = smb_RPCWrite(fidp, vcp, inp, outp);
7463 smb_ReleaseFID(fidp);
7464 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7469 lock_ReleaseMutex(&fidp->mx);
7470 smb_ReleaseFID(fidp);
7471 return CM_ERROR_BADFD;
7474 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7475 lock_ReleaseMutex(&fidp->mx);
7476 smb_CloseFID(vcp, fidp, NULL, 0);
7477 smb_ReleaseFID(fidp);
7478 return CM_ERROR_NOSUCHFILE;
7483 lock_ReleaseMutex(&fidp->mx);
7484 userp = smb_GetUserFromVCP(vcp, inp);
7488 LARGE_INTEGER LOffset;
7489 LARGE_INTEGER LLength;
7492 key = cm_GenerateKey(vcp->vcID, pid, fd);
7494 LOffset.HighPart = offset.HighPart;
7495 LOffset.LowPart = offset.LowPart;
7496 LLength.HighPart = 0;
7497 LLength.LowPart = count;
7499 lock_ObtainWrite(&scp->rw);
7500 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7501 lock_ReleaseWrite(&scp->rw);
7504 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7509 /* special case: 0 bytes transferred means truncate to this position */
7513 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7517 truncAttr.mask = CM_ATTRMASK_LENGTH;
7518 truncAttr.length.LowPart = offset.LowPart;
7519 truncAttr.length.HighPart = 0;
7520 lock_ObtainMutex(&fidp->mx);
7521 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7522 fidp->flags |= SMB_FID_LENGTHSETDONE;
7523 lock_ReleaseMutex(&fidp->mx);
7524 smb_SetSMBParm(outp, 0, 0 /* count */);
7525 smb_SetSMBDataLength(outp, 0);
7530 * Work around bug in NT client
7532 * When copying a file, the NT client should first copy the data,
7533 * then copy the last write time. But sometimes the NT client does
7534 * these in the wrong order, so the data copies would inadvertently
7535 * cause the last write time to be overwritten. We try to detect this,
7536 * and don't set client mod time if we think that would go against the
7539 lock_ObtainMutex(&fidp->mx);
7540 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7541 lock_ObtainWrite(&fidp->scp->rw);
7542 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7543 fidp->scp->clientModTime = time(NULL);
7544 lock_ReleaseWrite(&fidp->scp->rw);
7546 lock_ReleaseMutex(&fidp->mx);
7549 while ( code == 0 && count > 0 ) {
7550 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7551 if (code == 0 && written == 0)
7552 code = CM_ERROR_PARTIALWRITE;
7554 offset = LargeIntegerAdd(offset,
7555 ConvertLongToLargeInteger(written));
7556 count -= (unsigned short)written;
7557 total_written += written;
7561 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7562 total_written, code);
7564 /* set the packet data length to 3 bytes for the data block header,
7565 * plus the size of the data.
7567 smb_SetSMBParm(outp, 0, total_written);
7568 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7569 smb_SetSMBParm(outp, 3, hint);
7570 smb_SetSMBDataLength(outp, 0);
7573 smb_ReleaseFID(fidp);
7574 cm_ReleaseUser(userp);
7575 cm_ReleaseSCache(scp);
7580 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7581 NCB *ncbp, raw_write_cont_t *rwcp)
7590 fd = smb_GetSMBParm(inp, 0);
7591 fidp = smb_FindFID(vcp, fd, 0);
7593 lock_ObtainMutex(&fidp->mx);
7595 lock_ReleaseMutex(&fidp->mx);
7596 smb_ReleaseFID(fidp);
7600 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7601 lock_ReleaseMutex(&fidp->mx);
7602 smb_CloseFID(vcp, fidp, NULL, 0);
7603 smb_ReleaseFID(fidp);
7606 lock_ReleaseMutex(&fidp->mx);
7608 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7609 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7611 userp = smb_GetUserFromVCP(vcp, inp);
7614 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7616 if (rwcp->writeMode & 0x1) { /* synchronous */
7619 smb_FormatResponsePacket(vcp, inp, outp);
7620 op = (smb_t *) outp;
7621 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7622 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7623 smb_SetSMBDataLength(outp, 0);
7624 smb_SendPacket(vcp, outp);
7625 smb_FreePacket(outp);
7627 else { /* asynchronous */
7628 lock_ObtainMutex(&fidp->mx);
7629 fidp->raw_writers--;
7630 if (fidp->raw_writers == 0)
7631 thrd_SetEvent(fidp->raw_write_event);
7632 lock_ReleaseMutex(&fidp->mx);
7635 /* Give back raw buffer */
7636 lock_ObtainMutex(&smb_RawBufLock);
7637 *((char **)rawBuf) = smb_RawBufs;
7638 smb_RawBufs = rawBuf;
7639 lock_ReleaseMutex(&smb_RawBufLock);
7641 smb_ReleaseFID(fidp);
7642 cm_ReleaseUser(userp);
7645 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7650 /* SMB_COM_WRITE_RAW */
7651 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7654 long count, written = 0, total_written = 0;
7658 smb_t *smbp = (smb_t*) inp;
7663 unsigned short writeMode;
7665 fd = smb_GetSMBParm(inp, 0);
7666 totalCount = smb_GetSMBParm(inp, 1);
7667 count = smb_GetSMBParm(inp, 10);
7668 writeMode = smb_GetSMBParm(inp, 7);
7670 op = (char *) inp->data;
7671 op += smb_GetSMBParm(inp, 11);
7673 offset.HighPart = 0;
7674 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7676 if (*inp->wctp == 14) {
7677 /* we received a 64-bit file offset */
7678 #ifdef AFS_LARGEFILES
7679 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7681 if (LargeIntegerLessThanZero(offset)) {
7683 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7684 offset.HighPart, offset.LowPart);
7685 return CM_ERROR_BADSMB;
7688 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7690 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7691 return CM_ERROR_BADSMB;
7694 offset.HighPart = 0;
7697 offset.HighPart = 0; /* 32-bit file offset */
7701 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7702 fd, offset.HighPart, offset.LowPart, count);
7704 " WriteRaw WriteMode 0x%x",
7707 fd = smb_ChainFID(fd, inp);
7708 fidp = smb_FindFID(vcp, fd, 0);
7710 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7712 return CM_ERROR_BADFD;
7714 lock_ObtainMutex(&fidp->mx);
7716 lock_ReleaseMutex(&fidp->mx);
7717 smb_ReleaseFID(fidp);
7718 return CM_ERROR_BADFD;
7721 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7722 lock_ReleaseMutex(&fidp->mx);
7723 smb_CloseFID(vcp, fidp, NULL, 0);
7724 smb_ReleaseFID(fidp);
7725 return CM_ERROR_NOSUCHFILE;
7730 lock_ReleaseMutex(&fidp->mx);
7735 LARGE_INTEGER LOffset;
7736 LARGE_INTEGER LLength;
7739 key = cm_GenerateKey(vcp->vcID, pid, fd);
7741 LOffset.HighPart = offset.HighPart;
7742 LOffset.LowPart = offset.LowPart;
7743 LLength.HighPart = 0;
7744 LLength.LowPart = count;
7746 lock_ObtainWrite(&scp->rw);
7747 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7748 lock_ReleaseWrite(&scp->rw);
7751 cm_ReleaseSCache(scp);
7752 smb_ReleaseFID(fidp);
7757 userp = smb_GetUserFromVCP(vcp, inp);
7760 * Work around bug in NT client
7762 * When copying a file, the NT client should first copy the data,
7763 * then copy the last write time. But sometimes the NT client does
7764 * these in the wrong order, so the data copies would inadvertently
7765 * cause the last write time to be overwritten. We try to detect this,
7766 * and don't set client mod time if we think that would go against the
7769 lock_ObtainMutex(&fidp->mx);
7770 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7771 lock_ObtainWrite(&fidp->scp->rw);
7772 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7773 fidp->scp->clientModTime = time(NULL);
7774 lock_ReleaseWrite(&fidp->scp->rw);
7776 lock_ReleaseMutex(&fidp->mx);
7779 while ( code == 0 && count > 0 ) {
7780 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7781 if (code == 0 && written == 0)
7782 code = CM_ERROR_PARTIALWRITE;
7784 offset = LargeIntegerAdd(offset,
7785 ConvertLongToLargeInteger(written));
7788 total_written += written;
7792 /* Get a raw buffer */
7795 lock_ObtainMutex(&smb_RawBufLock);
7797 /* Get a raw buf, from head of list */
7798 rawBuf = smb_RawBufs;
7799 smb_RawBufs = *(char **)smb_RawBufs;
7802 code = CM_ERROR_USESTD;
7804 lock_ReleaseMutex(&smb_RawBufLock);
7807 /* Don't allow a premature Close */
7808 if (code == 0 && (writeMode & 1) == 0) {
7809 lock_ObtainMutex(&fidp->mx);
7810 fidp->raw_writers++;
7811 thrd_ResetEvent(fidp->raw_write_event);
7812 lock_ReleaseMutex(&fidp->mx);
7815 smb_ReleaseFID(fidp);
7816 cm_ReleaseUser(userp);
7817 cm_ReleaseSCache(scp);
7820 smb_SetSMBParm(outp, 0, total_written);
7821 smb_SetSMBDataLength(outp, 0);
7822 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7827 offset = LargeIntegerAdd(offset,
7828 ConvertLongToLargeInteger(count));
7832 rwcp->offset.HighPart = offset.HighPart;
7833 rwcp->offset.LowPart = offset.LowPart;
7834 rwcp->count = totalCount - count;
7835 rwcp->writeMode = writeMode;
7836 rwcp->alreadyWritten = total_written;
7838 /* set the packet data length to 3 bytes for the data block header,
7839 * plus the size of the data.
7841 smb_SetSMBParm(outp, 0, 0xffff);
7842 smb_SetSMBDataLength(outp, 0);
7848 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7851 long count, finalCount;
7855 smb_t *smbp = (smb_t*) inp;
7861 fd = smb_GetSMBParm(inp, 0);
7862 count = smb_GetSMBParm(inp, 1);
7863 offset.HighPart = 0; /* too bad */
7864 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7866 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7867 fd, offset.LowPart, count);
7869 fd = smb_ChainFID(fd, inp);
7870 fidp = smb_FindFID(vcp, fd, 0);
7872 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7874 return CM_ERROR_BADFD;
7876 lock_ObtainMutex(&fidp->mx);
7877 if (fidp->flags & SMB_FID_IOCTL) {
7878 lock_ReleaseMutex(&fidp->mx);
7879 code = smb_IoctlRead(fidp, vcp, inp, outp);
7880 smb_ReleaseFID(fidp);
7884 if (fidp->flags & SMB_FID_RPC) {
7885 lock_ReleaseMutex(&fidp->mx);
7886 code = smb_RPCRead(fidp, vcp, inp, outp);
7887 smb_ReleaseFID(fidp);
7892 lock_ReleaseMutex(&fidp->mx);
7893 smb_ReleaseFID(fidp);
7894 return CM_ERROR_BADFD;
7897 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7898 lock_ReleaseMutex(&fidp->mx);
7899 smb_CloseFID(vcp, fidp, NULL, 0);
7900 smb_ReleaseFID(fidp);
7901 return CM_ERROR_NOSUCHFILE;
7906 lock_ReleaseMutex(&fidp->mx);
7909 LARGE_INTEGER LOffset, LLength;
7913 key = cm_GenerateKey(vcp->vcID, pid, fd);
7915 LOffset.HighPart = 0;
7916 LOffset.LowPart = offset.LowPart;
7917 LLength.HighPart = 0;
7918 LLength.LowPart = count;
7920 lock_ObtainWrite(&scp->rw);
7921 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7922 lock_ReleaseWrite(&scp->rw);
7925 cm_ReleaseSCache(scp);
7926 smb_ReleaseFID(fidp);
7930 userp = smb_GetUserFromVCP(vcp, inp);
7932 /* remember this for final results */
7933 smb_SetSMBParm(outp, 0, count);
7934 smb_SetSMBParm(outp, 1, 0);
7935 smb_SetSMBParm(outp, 2, 0);
7936 smb_SetSMBParm(outp, 3, 0);
7937 smb_SetSMBParm(outp, 4, 0);
7939 /* set the packet data length to 3 bytes for the data block header,
7940 * plus the size of the data.
7942 smb_SetSMBDataLength(outp, count+3);
7944 /* get op ptr after putting in the parms, since otherwise we don't
7945 * know where the data really is.
7947 op = smb_GetSMBData(outp, NULL);
7949 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7950 *op++ = 1; /* data block marker */
7951 *op++ = (unsigned char) (count & 0xff);
7952 *op++ = (unsigned char) ((count >> 8) & 0xff);
7954 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7956 /* fix some things up */
7957 smb_SetSMBParm(outp, 0, finalCount);
7958 smb_SetSMBDataLength(outp, finalCount+3);
7960 smb_ReleaseFID(fidp);
7962 cm_ReleaseUser(userp);
7963 cm_ReleaseSCache(scp);
7967 /* SMB_COM_CREATE_DIRECTORY */
7968 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7970 clientchar_t *pathp;
7975 cm_scache_t *dscp; /* dir we're dealing with */
7976 cm_scache_t *scp; /* file we're creating */
7978 int initialModeBits;
7979 clientchar_t *lastNamep;
7981 clientchar_t *tidPathp;
7988 /* compute initial mode bits based on read-only flag in attributes */
7989 initialModeBits = 0777;
7991 tp = smb_GetSMBData(inp, NULL);
7992 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7994 return CM_ERROR_BADSMB;
7996 spacep = inp->spacep;
7997 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7999 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8000 return CM_ERROR_EXISTS;
8002 userp = smb_GetUserFromVCP(vcp, inp);
8004 caseFold = CM_FLAG_CASEFOLD;
8006 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8008 cm_ReleaseUser(userp);
8009 return CM_ERROR_NOSUCHPATH;
8012 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
8013 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8014 userp, tidPathp, &req, &dscp);
8017 cm_ReleaseUser(userp);
8022 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8023 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8024 cm_ReleaseSCache(dscp);
8025 cm_ReleaseUser(userp);
8026 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8027 return CM_ERROR_PATH_NOT_COVERED;
8029 return CM_ERROR_NOSUCHPATH;
8031 #endif /* DFS_SUPPORT */
8033 /* otherwise, scp points to the parent directory. Do a lookup, and
8034 * fail if we find it. Otherwise, we do the create.
8040 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8041 if (scp) cm_ReleaseSCache(scp);
8042 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8043 if (code == 0) code = CM_ERROR_EXISTS;
8044 cm_ReleaseSCache(dscp);
8045 cm_ReleaseUser(userp);
8049 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8050 setAttr.clientModTime = time(NULL);
8051 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8052 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8053 smb_NotifyChange(FILE_ACTION_ADDED,
8054 FILE_NOTIFY_CHANGE_DIR_NAME,
8055 dscp, lastNamep, NULL, TRUE);
8057 /* we don't need this any longer */
8058 cm_ReleaseSCache(dscp);
8061 /* something went wrong creating or truncating the file */
8062 cm_ReleaseUser(userp);
8066 /* otherwise we succeeded */
8067 smb_SetSMBDataLength(outp, 0);
8068 cm_ReleaseUser(userp);
8073 BOOL smb_IsLegalFilename(clientchar_t *filename)
8076 * Find the longest substring of filename that does not contain
8077 * any of the chars in illegalChars. If that substring is less
8078 * than the length of the whole string, then one or more of the
8079 * illegal chars is in filename.
8081 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8087 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8088 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8090 clientchar_t *pathp;
8096 cm_scache_t *dscp; /* dir we're dealing with */
8097 cm_scache_t *scp; /* file we're creating */
8099 int initialModeBits;
8102 clientchar_t *lastNamep;
8105 clientchar_t *tidPathp;
8107 int created = 0; /* the file was new */
8112 excl = (inp->inCom == 0x03)? 0 : 1;
8114 attributes = smb_GetSMBParm(inp, 0);
8115 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8117 /* compute initial mode bits based on read-only flag in attributes */
8118 initialModeBits = 0666;
8119 if (attributes & SMB_ATTR_READONLY)
8120 initialModeBits &= ~0222;
8122 tp = smb_GetSMBData(inp, NULL);
8123 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8125 return CM_ERROR_BADSMB;
8127 spacep = inp->spacep;
8128 /* smb_StripLastComponent will strip "::$DATA" if present */
8129 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8131 if (!cm_IsValidClientString(pathp)) {
8133 clientchar_t * hexp;
8135 hexp = cm_GetRawCharsAlloc(pathp, -1);
8136 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8137 osi_LogSaveClientString(smb_logp, hexp));
8141 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8143 return CM_ERROR_BADNTFILENAME;
8146 userp = smb_GetUserFromVCP(vcp, inp);
8148 caseFold = CM_FLAG_CASEFOLD;
8150 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8152 cm_ReleaseUser(userp);
8153 return CM_ERROR_NOSUCHPATH;
8155 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8156 userp, tidPathp, &req, &dscp);
8159 cm_ReleaseUser(userp);
8164 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8165 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8166 cm_ReleaseSCache(dscp);
8167 cm_ReleaseUser(userp);
8168 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8169 return CM_ERROR_PATH_NOT_COVERED;
8171 return CM_ERROR_NOSUCHPATH;
8173 #endif /* DFS_SUPPORT */
8175 /* otherwise, scp points to the parent directory. Do a lookup, and
8176 * truncate the file if we find it, otherwise we create the file.
8183 if (!smb_IsLegalFilename(lastNamep))
8184 return CM_ERROR_BADNTFILENAME;
8186 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8187 #ifdef DEBUG_VERBOSE
8190 hexp = osi_HexifyString( lastNamep );
8191 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8196 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8197 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8198 cm_ReleaseSCache(dscp);
8199 cm_ReleaseUser(userp);
8203 /* if we get here, if code is 0, the file exists and is represented by
8204 * scp. Otherwise, we have to create it.
8208 /* oops, file shouldn't be there */
8209 cm_ReleaseSCache(dscp);
8210 cm_ReleaseSCache(scp);
8211 cm_ReleaseUser(userp);
8212 return CM_ERROR_EXISTS;
8215 setAttr.mask = CM_ATTRMASK_LENGTH;
8216 setAttr.length.LowPart = 0;
8217 setAttr.length.HighPart = 0;
8218 code = cm_SetAttr(scp, &setAttr, userp, &req);
8221 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8222 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8223 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8227 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8228 smb_NotifyChange(FILE_ACTION_ADDED,
8229 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8230 dscp, lastNamep, NULL, TRUE);
8231 } else if (!excl && code == CM_ERROR_EXISTS) {
8232 /* not an exclusive create, and someone else tried
8233 * creating it already, then we open it anyway. We
8234 * don't bother retrying after this, since if this next
8235 * fails, that means that the file was deleted after
8236 * we started this call.
8238 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8241 setAttr.mask = CM_ATTRMASK_LENGTH;
8242 setAttr.length.LowPart = 0;
8243 setAttr.length.HighPart = 0;
8244 code = cm_SetAttr(scp, &setAttr, userp, &req);
8249 /* we don't need this any longer */
8250 cm_ReleaseSCache(dscp);
8253 /* something went wrong creating or truncating the file */
8254 if (scp) cm_ReleaseSCache(scp);
8255 cm_ReleaseUser(userp);
8259 /* make sure we only open files */
8260 if (scp->fileType != CM_SCACHETYPE_FILE) {
8261 cm_ReleaseSCache(scp);
8262 cm_ReleaseUser(userp);
8263 return CM_ERROR_ISDIR;
8266 /* now all we have to do is open the file itself */
8267 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8268 osi_assertx(fidp, "null smb_fid_t");
8272 lock_ObtainMutex(&fidp->mx);
8273 /* always create it open for read/write */
8274 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8276 /* remember that the file was newly created */
8278 fidp->flags |= SMB_FID_CREATED;
8280 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8282 /* save a pointer to the vnode */
8284 lock_ObtainWrite(&scp->rw);
8285 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8286 lock_ReleaseWrite(&scp->rw);
8289 fidp->userp = userp;
8290 lock_ReleaseMutex(&fidp->mx);
8292 smb_SetSMBParm(outp, 0, fidp->fid);
8293 smb_SetSMBDataLength(outp, 0);
8295 cm_Open(scp, 0, userp);
8297 smb_ReleaseFID(fidp);
8298 cm_ReleaseUser(userp);
8299 /* leave scp held since we put it in fidp->scp */
8304 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8307 osi_hyper_t new_offset;
8318 fd = smb_GetSMBParm(inp, 0);
8319 whence = smb_GetSMBParm(inp, 1);
8320 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8322 /* try to find the file descriptor */
8323 fd = smb_ChainFID(fd, inp);
8324 fidp = smb_FindFID(vcp, fd, 0);
8326 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8328 return CM_ERROR_BADFD;
8330 lock_ObtainMutex(&fidp->mx);
8331 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8332 lock_ReleaseMutex(&fidp->mx);
8333 smb_ReleaseFID(fidp);
8334 return CM_ERROR_BADFD;
8337 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8338 lock_ReleaseMutex(&fidp->mx);
8339 smb_CloseFID(vcp, fidp, NULL, 0);
8340 smb_ReleaseFID(fidp);
8341 return CM_ERROR_NOSUCHFILE;
8344 lock_ReleaseMutex(&fidp->mx);
8346 userp = smb_GetUserFromVCP(vcp, inp);
8348 lock_ObtainMutex(&fidp->mx);
8351 lock_ReleaseMutex(&fidp->mx);
8352 lock_ObtainWrite(&scp->rw);
8353 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8354 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8356 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8358 /* offset from current offset */
8359 new_offset = LargeIntegerAdd(fidp->offset,
8360 ConvertLongToLargeInteger(offset));
8362 else if (whence == 2) {
8363 /* offset from current EOF */
8364 new_offset = LargeIntegerAdd(scp->length,
8365 ConvertLongToLargeInteger(offset));
8367 new_offset = ConvertLongToLargeInteger(offset);
8370 fidp->offset = new_offset;
8371 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8372 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8373 smb_SetSMBDataLength(outp, 0);
8375 lock_ReleaseWrite(&scp->rw);
8376 smb_ReleaseFID(fidp);
8377 cm_ReleaseSCache(scp);
8378 cm_ReleaseUser(userp);
8382 /* dispatch all of the requests received in a packet. Due to chaining, this may
8383 * be more than one request.
8385 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8386 NCB *ncbp, raw_write_cont_t *rwcp)
8390 unsigned long code = 0;
8391 unsigned char *outWctp;
8392 int nparms; /* # of bytes of parameters */
8394 int nbytes; /* bytes of data, excluding count */
8397 unsigned short errCode;
8398 unsigned long NTStatus;
8400 unsigned char errClass;
8401 unsigned int oldGen;
8402 DWORD oldTime, newTime;
8404 /* get easy pointer to the data */
8405 smbp = (smb_t *) inp->data;
8407 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8408 /* setup the basic parms for the initial request in the packet */
8409 inp->inCom = smbp->com;
8410 inp->wctp = &smbp->wct;
8412 inp->ncb_length = ncbp->ncb_length;
8417 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8418 /* log it and discard it */
8419 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8420 __FILE__, __LINE__, ncbp->ncb_length);
8421 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8425 /* We are an ongoing op */
8426 thrd_Increment(&ongoingOps);
8428 /* set up response packet for receiving output */
8429 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8430 smb_FormatResponsePacket(vcp, inp, outp);
8431 outWctp = outp->wctp;
8433 /* Remember session generation number and time */
8434 oldGen = sessionGen;
8435 oldTime = GetTickCount();
8437 while (inp->inCom != 0xff) {
8438 dp = &smb_dispatchTable[inp->inCom];
8440 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8441 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8442 code = outp->resumeCode;
8446 /* process each request in the packet; inCom, wctp and inCount
8447 * are already set up.
8449 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8452 /* now do the dispatch */
8453 /* start by formatting the response record a little, as a default */
8454 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8456 outWctp[1] = 0xff; /* no operation */
8457 outWctp[2] = 0; /* padding */
8462 /* not a chained request, this is a more reasonable default */
8463 outWctp[0] = 0; /* wct of zero */
8464 outWctp[1] = 0; /* and bcc (word) of zero */
8468 /* once set, stays set. Doesn't matter, since we never chain
8469 * "no response" calls.
8471 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8475 /* we have a recognized operation */
8476 char * opName = myCrt_Dispatch(inp->inCom);
8479 smbp = (smb_t *) inp;
8481 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8482 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8483 if (inp->inCom == 0x1d) {
8485 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8487 code = (*(dp->procp)) (vcp, inp, outp);
8489 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8490 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8492 newTime = GetTickCount();
8493 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8494 opName, smbp->mid, newTime - oldTime);
8497 if ( code == CM_ERROR_BADSMB ||
8498 code == CM_ERROR_BADOP )
8500 #endif /* LOG_PACKET */
8502 /* ReceiveV3Tran2A handles its own logging */
8503 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8506 clientchar_t *treepath = NULL; /* do not free */
8507 clientchar_t *pathname = NULL;
8508 cm_fid_t afid = {0,0,0,0,0};
8510 uidp = smb_FindUID(vcp, smbp->uid, 0);
8511 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8512 fidp = smb_FindFID(vcp, inp->fid, 0);
8515 lock_ObtainMutex(&fidp->mx);
8516 if (fidp->NTopen_pathp)
8517 pathname = fidp->NTopen_pathp;
8519 afid = fidp->scp->fid;
8521 if (inp->stringsp->wdata)
8522 pathname = inp->stringsp->wdata;
8525 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)",
8526 opName, newTime - oldTime,
8527 smbp->uid, uidp ? uidp->unp->name : NULL,
8528 smbp->pid, smbp->mid, smbp->tid,
8531 afid.cell, afid.volume, afid.vnode, afid.unique);
8534 lock_ReleaseMutex(&fidp->mx);
8537 smb_ReleaseUID(uidp);
8539 smb_ReleaseFID(fidp);
8542 if (oldGen != sessionGen) {
8543 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8544 newTime - oldTime, ncbp->ncb_length);
8545 osi_Log3(smb_logp, "Request %s straddled session startup, "
8546 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8549 FreeSMBStrings(inp);
8551 /* bad opcode, fail the request, after displaying it */
8552 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8555 #endif /* LOG_PACKET */
8558 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8559 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8560 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8561 if (code == IDCANCEL)
8564 code = CM_ERROR_BADOP;
8567 /* catastrophic failure: log as much as possible */
8568 if (code == CM_ERROR_BADSMB) {
8569 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8573 #endif /* LOG_PACKET */
8574 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8577 code = CM_ERROR_INVAL;
8580 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8581 thrd_Decrement(&ongoingOps);
8586 /* now, if we failed, turn the current response into an empty
8587 * one, and fill in the response packet's error code.
8590 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8591 smb_MapNTError(code, &NTStatus);
8592 outWctp = outp->wctp;
8593 smbp = (smb_t *) &outp->data;
8594 if (code != CM_ERROR_PARTIALWRITE
8595 && code != CM_ERROR_BUFFERTOOSMALL
8596 && code != CM_ERROR_GSSCONTINUE) {
8597 /* nuke wct and bcc. For a partial
8598 * write or an in-process authentication handshake,
8599 * assume they're OK.
8605 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8606 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8607 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8608 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8609 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8613 smb_MapCoreError(code, vcp, &errCode, &errClass);
8614 outWctp = outp->wctp;
8615 smbp = (smb_t *) &outp->data;
8616 if (code != CM_ERROR_PARTIALWRITE) {
8617 /* nuke wct and bcc. For a partial
8618 * write, assume they're OK.
8624 smbp->errLow = (unsigned char) (errCode & 0xff);
8625 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8626 smbp->rcls = errClass;
8629 } /* error occurred */
8631 /* if we're here, we've finished one request. Look to see if
8632 * this is a chained opcode. If it is, setup things to process
8633 * the chained request, and setup the output buffer to hold the
8634 * chained response. Start by finding the next input record.
8636 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8637 break; /* not a chained req */
8638 tp = inp->wctp; /* points to start of last request */
8639 /* in a chained request, the first two
8640 * parm fields are required, and are
8641 * AndXCommand/AndXReserved and
8643 if (tp[0] < 2) break;
8644 if (tp[1] == 0xff) break; /* no more chained opcodes */
8646 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8649 /* and now append the next output request to the end of this
8650 * last request. Begin by finding out where the last response
8651 * ends, since that's where we'll put our new response.
8653 outWctp = outp->wctp; /* ptr to out parameters */
8654 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8655 nparms = outWctp[0] << 1;
8656 tp = outWctp + nparms + 1; /* now points to bcc field */
8657 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8658 tp += 2 /* for the count itself */ + nbytes;
8659 /* tp now points to the new output record; go back and patch the
8660 * second parameter (off2) to point to the new record.
8662 temp = (unsigned int)(tp - outp->data);
8663 outWctp[3] = (unsigned char) (temp & 0xff);
8664 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8665 outWctp[2] = 0; /* padding */
8666 outWctp[1] = inp->inCom; /* next opcode */
8668 /* finally, setup for the next iteration */
8671 } /* while loop over all requests in the packet */
8673 /* now send the output packet, and return */
8675 smb_SendPacket(vcp, outp);
8676 thrd_Decrement(&ongoingOps);
8681 /* Wait for Netbios() calls to return, and make the results available to server
8682 * threads. Note that server threads can't wait on the NCBevents array
8683 * themselves, because NCB events are manual-reset, and the servers would race
8684 * each other to reset them.
8686 void smb_ClientWaiter(void *parmp)
8691 while (smbShutdownFlag == 0) {
8692 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8694 if (code == WAIT_OBJECT_0)
8697 /* error checking */
8698 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8700 int abandonIdx = code - WAIT_ABANDONED_0;
8701 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8704 if (code == WAIT_IO_COMPLETION)
8706 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8710 if (code == WAIT_TIMEOUT)
8712 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8715 if (code == WAIT_FAILED)
8717 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8720 idx = code - WAIT_OBJECT_0;
8722 /* check idx range! */
8723 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8725 /* this is fatal - log as much as possible */
8726 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8727 osi_assertx(0, "invalid index");
8730 thrd_ResetEvent(NCBevents[idx]);
8731 thrd_SetEvent(NCBreturns[0][idx]);
8736 * Try to have one NCBRECV request waiting for every live session. Not more
8737 * than one, because if there is more than one, it's hard to handle Write Raw.
8739 void smb_ServerWaiter(void *parmp)
8742 int idx_session, idx_NCB;
8745 while (smbShutdownFlag == 0) {
8747 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8749 if (code == WAIT_OBJECT_0)
8752 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8754 int abandonIdx = code - WAIT_ABANDONED_0;
8755 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8758 if (code == WAIT_IO_COMPLETION)
8760 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8764 if (code == WAIT_TIMEOUT)
8766 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8769 if (code == WAIT_FAILED)
8771 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8774 idx_session = code - WAIT_OBJECT_0;
8776 /* check idx range! */
8777 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8779 /* this is fatal - log as much as possible */
8780 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8781 osi_assertx(0, "invalid index");
8786 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8788 if (code == WAIT_OBJECT_0) {
8789 if (smbShutdownFlag == 1)
8795 /* error checking */
8796 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8798 int abandonIdx = code - WAIT_ABANDONED_0;
8799 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8802 if (code == WAIT_IO_COMPLETION)
8804 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8808 if (code == WAIT_TIMEOUT)
8810 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8813 if (code == WAIT_FAILED)
8815 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8818 idx_NCB = code - WAIT_OBJECT_0;
8820 /* check idx range! */
8821 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8823 /* this is fatal - log as much as possible */
8824 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8825 osi_assertx(0, "invalid index");
8828 /* Link them together */
8829 NCBsessions[idx_NCB] = idx_session;
8832 ncbp = NCBs[idx_NCB];
8833 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8834 ncbp->ncb_command = NCBRECV | ASYNCH;
8835 ncbp->ncb_lana_num = lanas[idx_session];
8836 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8837 ncbp->ncb_event = NCBevents[idx_NCB];
8838 ncbp->ncb_length = SMB_PACKETSIZE;
8844 * The top level loop for handling SMB request messages. Each server thread
8845 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8846 * NCB and buffer for the incoming request are loaned to us.
8848 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8849 * to immediately send a request for the rest of the data. This must come
8850 * before any other traffic for that session, so we delay setting the session
8851 * event until that data has come in.
8853 void smb_Server(VOID *parmp)
8855 INT_PTR myIdx = (INT_PTR) parmp;
8859 smb_packet_t *outbufp;
8861 int idx_NCB, idx_session;
8863 smb_vc_t *vcp = NULL;
8865 extern void rx_StartClientThread(void);
8867 rx_StartClientThread();
8869 outncbp = smb_GetNCB();
8870 outbufp = smb_GetPacket();
8871 outbufp->ncbp = outncbp;
8879 cm_ResetServerPriority();
8881 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8884 /* terminate silently if shutdown flag is set */
8885 if (code == WAIT_OBJECT_0) {
8886 if (smbShutdownFlag == 1) {
8887 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8893 /* error checking */
8894 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8896 int abandonIdx = code - WAIT_ABANDONED_0;
8897 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8900 if (code == WAIT_IO_COMPLETION)
8902 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8906 if (code == WAIT_TIMEOUT)
8908 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8911 if (code == WAIT_FAILED)
8913 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8916 idx_NCB = code - WAIT_OBJECT_0;
8918 /* check idx range! */
8919 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8921 /* this is fatal - log as much as possible */
8922 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8923 osi_assertx(0, "invalid index");
8926 ncbp = NCBs[idx_NCB];
8927 idx_session = NCBsessions[idx_NCB];
8928 rc = ncbp->ncb_retcode;
8930 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8931 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8935 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8939 /* Can this happen? Or is it just my UNIX paranoia? */
8940 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8945 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8948 /* Client closed session */
8949 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8951 lock_ObtainMutex(&vcp->mx);
8952 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8953 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8955 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8956 lock_ReleaseMutex(&vcp->mx);
8957 lock_ObtainWrite(&smb_globalLock);
8958 dead_sessions[vcp->session] = TRUE;
8959 lock_ReleaseWrite(&smb_globalLock);
8961 lock_ReleaseMutex(&vcp->mx);
8963 smb_CleanupDeadVC(vcp);
8970 /* Treat as transient error */
8971 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8974 "dispatch smb recv failed, message incomplete, ncb_length %d",
8977 "SMB message incomplete, "
8978 "length %d", ncbp->ncb_length);
8981 * We used to discard the packet.
8982 * Instead, try handling it normally.
8986 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8990 /* A weird error code. Log it, sleep, and continue. */
8991 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8993 lock_ObtainMutex(&vcp->mx);
8994 if (vcp->errorCount++ > 3) {
8995 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8996 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8997 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8999 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9000 lock_ReleaseMutex(&vcp->mx);
9001 lock_ObtainWrite(&smb_globalLock);
9002 dead_sessions[vcp->session] = TRUE;
9003 lock_ReleaseWrite(&smb_globalLock);
9005 lock_ReleaseMutex(&vcp->mx);
9007 smb_CleanupDeadVC(vcp);
9013 lock_ReleaseMutex(&vcp->mx);
9017 thrd_SetEvent(SessionEvents[idx_session]);
9023 /* Success, so now dispatch on all the data in the packet */
9025 smb_concurrentCalls++;
9026 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9027 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9030 * If at this point vcp is NULL (implies that packet was invalid)
9031 * then we are in big trouble. This means either :
9032 * a) we have the wrong NCB.
9033 * b) Netbios screwed up the call.
9034 * c) The VC was already marked dead before we were able to
9036 * Obviously this implies that
9037 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9038 * lanas[idx_session] != ncbp->ncb_lana_num )
9039 * Either way, we can't do anything with this packet.
9040 * Log, sleep and resume.
9043 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9047 ncbp->ncb_lana_num);
9049 /* Also log in the trace log. */
9050 osi_Log4(smb_logp, "Server: VCP does not exist!"
9051 "LSNs[idx_session]=[%d],"
9052 "lanas[idx_session]=[%d],"
9053 "ncbp->ncb_lsn=[%d],"
9054 "ncbp->ncb_lana_num=[%d]",
9058 ncbp->ncb_lana_num);
9060 /* thrd_Sleep(1000); Don't bother sleeping */
9061 thrd_SetEvent(SessionEvents[idx_session]);
9062 smb_concurrentCalls--;
9066 cm_SetRequestStartTime();
9068 vcp->errorCount = 0;
9069 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9070 smbp = (smb_t *)bufp->data;
9077 if (smbp->com == 0x1d) {
9078 /* Special handling for Write Raw */
9079 raw_write_cont_t rwc;
9081 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9082 if (rwc.code == 0) {
9083 EVENT_HANDLE rwevent;
9084 char eventName[MAX_PATH];
9086 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9087 rwevent = 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));
9091 ncbp->ncb_command = NCBRECV | ASYNCH;
9092 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9093 ncbp->ncb_lana_num = vcp->lana;
9094 ncbp->ncb_buffer = rwc.buf;
9095 ncbp->ncb_length = 65535;
9096 ncbp->ncb_event = rwevent;
9098 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9099 thrd_CloseHandle(rwevent);
9101 thrd_SetEvent(SessionEvents[idx_session]);
9103 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9105 else if (smbp->com == 0xa0) {
9107 * Serialize the handling for NT Transact
9110 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9111 thrd_SetEvent(SessionEvents[idx_session]);
9113 thrd_SetEvent(SessionEvents[idx_session]);
9114 /* TODO: what else needs to be serialized? */
9115 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9119 __except( smb_ServerExceptionFilter() ) {
9123 smb_concurrentCalls--;
9126 thrd_SetEvent(NCBavails[idx_NCB]);
9131 smb_FreePacket(outbufp);
9133 smb_FreeNCB(outncbp);
9137 * Exception filter for the server threads. If an exception occurs in the
9138 * dispatch routines, which is where exceptions are most common, then do a
9139 * force trace and give control to upstream exception handlers. Useful for
9142 DWORD smb_ServerExceptionFilter(void) {
9143 /* While this is not the best time to do a trace, if it succeeds, then
9144 * we have a trace (assuming tracing was enabled). Otherwise, this should
9145 * throw a second exception.
9147 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9148 afsd_ForceTrace(TRUE);
9149 buf_ForceTrace(TRUE);
9150 return EXCEPTION_CONTINUE_SEARCH;
9154 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9155 * If the number of server threads is M, and the number of live sessions is
9156 * N, then the number of NCB's in use at any time either waiting for, or
9157 * holding, received messages is M + N, so that is how many NCB's get created.
9159 void InitNCBslot(int idx)
9161 struct smb_packet *bufp;
9162 EVENT_HANDLE retHandle;
9164 char eventName[MAX_PATH];
9166 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9168 NCBs[idx] = smb_GetNCB();
9169 sprintf(eventName,"NCBavails[%d]", idx);
9170 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9171 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9172 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9173 sprintf(eventName,"NCBevents[%d]", idx);
9174 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9175 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9176 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9177 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9178 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9179 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9180 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9181 for (i=0; i<smb_NumServerThreads; i++)
9182 NCBreturns[i][idx] = retHandle;
9183 bufp = smb_GetPacket();
9184 bufp->spacep = cm_GetSpace();
9188 /* listen for new connections */
9189 void smb_Listener(void *parmp)
9195 afs_uint32 session, thread;
9196 smb_vc_t *vcp = NULL;
9198 char rname[NCBNAMSZ+1];
9199 char cname[MAX_COMPUTERNAME_LENGTH+1];
9200 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9201 INT_PTR lana = (INT_PTR) parmp;
9202 char eventName[MAX_PATH];
9203 int bridgeCount = 0;
9204 int nowildCount = 0;
9206 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9207 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9208 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9209 thrd_ResetEvent(ListenerShutdown[lana]);
9211 ncbp = smb_GetNCB();
9213 /* retrieve computer name */
9214 GetComputerName(cname, &cnamelen);
9217 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9218 memset(ncbp, 0, sizeof(NCB));
9221 ncbp->ncb_command = NCBLISTEN;
9222 ncbp->ncb_rto = 0; /* No receive timeout */
9223 ncbp->ncb_sto = 0; /* No send timeout */
9225 /* pad out with spaces instead of null termination */
9226 len = (long)strlen(smb_localNamep);
9227 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9228 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9230 strcpy(ncbp->ncb_callname, "*");
9231 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9233 ncbp->ncb_lana_num = (UCHAR)lana;
9235 code = Netbios(ncbp);
9237 if (code == NRC_NAMERR) {
9238 /* An smb shutdown or Vista resume must have taken place */
9240 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9241 ncbp->ncb_lana_num);
9242 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9244 if (lock_TryMutex(&smb_StartedLock)) {
9245 lana_list.lana[i] = LANA_INVALID;
9246 lock_ReleaseMutex(&smb_StartedLock);
9249 } else if (code == NRC_BRIDGE || code != 0) {
9250 int lanaRemaining = 0;
9252 if (code == NRC_BRIDGE) {
9253 if (++bridgeCount <= 5) {
9254 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9257 } else if (code == NRC_NOWILD) {
9258 if (++nowildCount <= 5) {
9259 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9261 if (bridgeCount > 0) {
9262 memset(ncbp, 0, sizeof(*ncbp));
9263 ncbp->ncb_command = NCBADDNAME;
9264 ncbp->ncb_lana_num = (UCHAR)lana;
9265 /* pad out with spaces instead of null termination */
9266 len = (long)strlen(smb_localNamep);
9267 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9268 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9269 code = Netbios(ncbp);
9275 while (!lock_TryMutex(&smb_StartedLock)) {
9276 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9282 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9283 ncbp->ncb_lana_num, ncb_error_string(code));
9284 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9285 ncbp->ncb_lana_num, ncb_error_string(code));
9287 for (i = 0; i < lana_list.length; i++) {
9288 if (lana_list.lana[i] == lana) {
9289 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9290 lana_list.lana[i] = LANA_INVALID;
9292 if (lana_list.lana[i] != LANA_INVALID)
9296 if (lanaRemaining == 0) {
9297 cm_VolStatus_Network_Stopped(cm_NetbiosName
9302 smb_ListenerState = SMB_LISTENER_STOPPED;
9303 smb_LANadapter = LANA_INVALID;
9304 lana_list.length = 0;
9306 lock_ReleaseMutex(&smb_StartedLock);
9310 else if (code != 0) {
9311 char tbuffer[AFSPATHMAX];
9313 /* terminate silently if shutdown flag is set */
9314 while (!lock_TryMutex(&smb_StartedLock)) {
9315 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9321 "NCBLISTEN lana=%d failed with code %d [%s]",
9322 ncbp->ncb_lana_num, code, ncb_error_string(code));
9324 "Client exiting due to network failure. Please restart client.\n");
9327 "Client exiting due to network failure. Please restart client.\n"
9328 "NCBLISTEN lana=%d failed with code %d [%s]",
9329 ncbp->ncb_lana_num, code, ncb_error_string(code));
9331 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9332 MB_OK|MB_SERVICE_NOTIFICATION);
9333 osi_panic(tbuffer, __FILE__, __LINE__);
9335 lock_ReleaseMutex(&smb_StartedLock);
9340 /* a successful packet received. clear bridge error count */
9344 /* check for remote conns */
9345 /* first get remote name and insert null terminator */
9346 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9347 for (i=NCBNAMSZ; i>0; i--) {
9348 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9354 /* compare with local name */
9356 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9357 flags |= SMB_VCFLAG_REMOTECONN;
9360 lock_ObtainMutex(&smb_ListenerLock);
9362 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9363 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9365 /* now ncbp->ncb_lsn is the connection ID */
9366 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9367 if (vcp->session == 0) {
9368 /* New generation */
9369 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9372 /* Log session startup */
9374 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9375 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9376 #endif /* NOTSERVICE */
9377 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9378 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9380 if (reportSessionStartups) {
9381 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9384 lock_ObtainMutex(&vcp->mx);
9385 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9386 vcp->flags |= flags;
9387 lock_ReleaseMutex(&vcp->mx);
9389 /* Allocate slot in session arrays */
9390 /* Re-use dead session if possible, otherwise add one more */
9391 /* But don't look at session[0], it is reserved */
9392 lock_ObtainWrite(&smb_globalLock);
9393 for (session = 1; session < numSessions; session++) {
9394 if (dead_sessions[session]) {
9395 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9396 dead_sessions[session] = FALSE;
9400 lock_ReleaseWrite(&smb_globalLock);
9402 /* We are re-using an existing VC because the lsn and lana
9404 session = vcp->session;
9406 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9408 /* Log session startup */
9410 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9411 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9412 #endif /* NOTSERVICE */
9413 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9414 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9416 if (reportSessionStartups) {
9417 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9421 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9422 unsigned long code = CM_ERROR_ALLBUSY;
9423 smb_packet_t * outp = smb_GetPacket();
9424 unsigned char *outWctp;
9427 smb_FormatResponsePacket(vcp, NULL, outp);
9430 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9431 unsigned long NTStatus;
9432 smb_MapNTError(code, &NTStatus);
9433 outWctp = outp->wctp;
9434 smbp = (smb_t *) &outp->data;
9438 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9439 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9440 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9441 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9442 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9444 unsigned short errCode;
9445 unsigned char errClass;
9446 smb_MapCoreError(code, vcp, &errCode, &errClass);
9447 outWctp = outp->wctp;
9448 smbp = (smb_t *) &outp->data;
9452 smbp->errLow = (unsigned char) (errCode & 0xff);
9453 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9454 smbp->rcls = errClass;
9457 smb_SendPacket(vcp, outp);
9458 smb_FreePacket(outp);
9460 lock_ObtainMutex(&vcp->mx);
9461 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9462 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9464 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9465 lock_ReleaseMutex(&vcp->mx);
9466 lock_ObtainWrite(&smb_globalLock);
9467 dead_sessions[vcp->session] = TRUE;
9468 lock_ReleaseWrite(&smb_globalLock);
9469 smb_CleanupDeadVC(vcp);
9471 lock_ReleaseMutex(&vcp->mx);
9474 /* assert that we do not exceed the maximum number of sessions or NCBs.
9475 * we should probably want to wait for a session to be freed in case
9478 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9479 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9481 lock_ObtainMutex(&vcp->mx);
9482 vcp->session = session;
9483 lock_ReleaseMutex(&vcp->mx);
9484 lock_ObtainWrite(&smb_globalLock);
9485 LSNs[session] = ncbp->ncb_lsn;
9486 lanas[session] = ncbp->ncb_lana_num;
9487 lock_ReleaseWrite(&smb_globalLock);
9489 if (session == numSessions) {
9490 /* Add new NCB for new session */
9491 char eventName[MAX_PATH];
9493 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9495 InitNCBslot(numNCBs);
9496 lock_ObtainWrite(&smb_globalLock);
9498 lock_ReleaseWrite(&smb_globalLock);
9499 thrd_SetEvent(NCBavails[0]);
9500 thrd_SetEvent(NCBevents[0]);
9501 for (thread = 0; thread < smb_NumServerThreads; thread++)
9502 thrd_SetEvent(NCBreturns[thread][0]);
9503 /* Also add new session event */
9504 sprintf(eventName, "SessionEvents[%d]", session);
9505 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9506 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9507 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9508 lock_ObtainWrite(&smb_globalLock);
9510 lock_ReleaseWrite(&smb_globalLock);
9511 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9512 thrd_SetEvent(SessionEvents[0]);
9514 thrd_SetEvent(SessionEvents[session]);
9520 lock_ReleaseMutex(&smb_ListenerLock);
9521 } /* dispatch while loop */
9525 thrd_SetEvent(ListenerShutdown[lana]);
9530 configureBackConnectionHostNames(void)
9532 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9533 * there is a restriction on the use of SMB authentication on loopback connections.
9534 * There are two work arounds available:
9536 * (1) We can disable the check for matching host names. This does not
9538 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9539 * "DisableLoopbackCheck"=dword:00000001
9541 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9542 * does require a reboot:
9543 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9544 * "BackConnectionHostNames"=multi-sz
9546 * The algorithm will be:
9547 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9548 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9549 * (2b1) and check to see if DisableLoopbackCheck is set.
9550 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9551 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9552 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9553 * check for the UnsetDisableLoopbackCheck value.
9554 * If set, set the DisableLoopbackCheck flag to 0x0
9555 * and delete the UnsetDisableLoopbackCheck value
9557 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9558 * force Windows to use the loopback authentication mechanism for the specified
9561 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9562 * service session that set it.
9568 DWORD dwSize, dwAllocSize;
9570 PBYTE pHostNames = NULL, pName = NULL;
9571 BOOL bNameFound = FALSE;
9572 static BOOL bLoopbackCheckDisabled = FALSE;
9574 /* BackConnectionHostNames and DisableLoopbackCheck */
9575 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9576 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9579 &hkMSV10) == ERROR_SUCCESS )
9581 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9582 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9583 (dwType == REG_MULTI_SZ))
9585 dwAllocSize += 1 /* in case the source string is not nul terminated */
9586 + (DWORD)strlen(cm_NetbiosName) + 2;
9587 pHostNames = malloc(dwAllocSize);
9588 dwSize = dwAllocSize;
9589 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9590 pHostNames, &dwSize) == ERROR_SUCCESS)
9592 for (pName = pHostNames;
9593 (pName - pHostNames < (int) dwSize) && *pName ;
9594 pName += strlen(pName) + 1)
9596 if ( !stricmp(pName, cm_NetbiosName) ) {
9604 if ( !bNameFound ) {
9605 size_t size = strlen(cm_NetbiosName) + 2;
9606 if ( !pHostNames ) {
9607 pHostNames = malloc(size);
9610 StringCbCopyA(pName, size, cm_NetbiosName);
9612 *pName = '\0'; /* add a second nul terminator */
9614 dwType = REG_MULTI_SZ;
9615 dwSize = (DWORD)(pName - pHostNames + 1);
9616 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9618 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9619 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9622 &hkLsa) == ERROR_SUCCESS )
9624 dwSize = sizeof(DWORD);
9625 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9628 dwSize = sizeof(DWORD);
9630 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9632 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9633 AFSREG_CLT_OPENAFS_SUBKEY,
9636 REG_OPTION_NON_VOLATILE,
9640 NULL) == ERROR_SUCCESS) {
9643 dwSize = sizeof(DWORD);
9645 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9646 bLoopbackCheckDisabled = TRUE;
9647 RegCloseKey(hkClient);
9652 } else if (!bLoopbackCheckDisabled) {
9653 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9654 AFSREG_CLT_OPENAFS_SUBKEY,
9657 REG_OPTION_NON_VOLATILE,
9661 NULL) == ERROR_SUCCESS) {
9663 dwSize = sizeof(DWORD);
9664 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9666 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9667 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9670 &hkLsa) == ERROR_SUCCESS )
9672 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9676 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9677 RegCloseKey(hkClient);
9686 RegCloseKey(hkMSV10);
9692 configureExtendedSMBSessionTimeouts(void)
9695 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9696 * new functionality:
9698 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9699 * "ReconnectableServers" REG_MULTI_SZ
9700 * "ExtendedSessTimeout" REG_DWORD (seconds)
9701 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
9703 * These values can be used to prevent the smb redirector from timing out
9704 * smb connection to the afs smb server prematurely.
9708 DWORD dwSize, dwAllocSize;
9710 PBYTE pHostNames = NULL, pName = NULL;
9711 BOOL bNameFound = FALSE;
9713 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9714 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9717 &hkLanMan) == ERROR_SUCCESS )
9719 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
9720 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9721 (dwType == REG_MULTI_SZ))
9723 dwAllocSize += 1 /* in case the source string is not nul terminated */
9724 + (DWORD)strlen(cm_NetbiosName) + 2;
9725 pHostNames = malloc(dwAllocSize);
9726 dwSize = dwAllocSize;
9727 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
9728 pHostNames, &dwSize) == ERROR_SUCCESS)
9730 for (pName = pHostNames;
9731 (pName - pHostNames < (int) dwSize) && *pName ;
9732 pName += strlen(pName) + 1)
9734 if ( !stricmp(pName, cm_NetbiosName) ) {
9742 if ( !bNameFound ) {
9743 size_t size = strlen(cm_NetbiosName) + 2;
9744 if ( !pHostNames ) {
9745 pHostNames = malloc(size);
9748 StringCbCopyA(pName, size, cm_NetbiosName);
9750 *pName = '\0'; /* add a second nul terminator */
9752 dwType = REG_MULTI_SZ;
9753 dwSize = (DWORD)(pName - pHostNames + 1);
9754 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9762 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
9763 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9764 (dwType == REG_MULTI_SZ))
9766 dwAllocSize += 1 /* in case the source string is not nul terminated */
9767 + (DWORD)strlen(cm_NetbiosName) + 2;
9768 pHostNames = malloc(dwAllocSize);
9769 dwSize = dwAllocSize;
9770 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
9771 pHostNames, &dwSize) == ERROR_SUCCESS)
9773 for (pName = pHostNames;
9774 (pName - pHostNames < (int) dwSize) && *pName ;
9775 pName += strlen(pName) + 1)
9777 if ( !stricmp(pName, cm_NetbiosName) ) {
9785 if ( !bNameFound ) {
9786 size_t size = strlen(cm_NetbiosName) + 2;
9787 if ( !pHostNames ) {
9788 pHostNames = malloc(size);
9791 StringCbCopyA(pName, size, cm_NetbiosName);
9793 *pName = '\0'; /* add a second nul terminator */
9795 dwType = REG_MULTI_SZ;
9796 dwSize = (DWORD)(pName - pHostNames + 1);
9797 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9805 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
9806 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9807 (dwType != REG_DWORD))
9810 dwSize = sizeof(dwValue);
9811 dwValue = 300; /* 5 minutes */
9812 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9814 RegCloseKey(hkLanMan);
9819 smb_LanAdapterChangeThread(void *param)
9822 * Give the IPAddrDaemon thread a chance
9823 * to block before we trigger.
9826 smb_LanAdapterChange(0);
9829 void smb_SetLanAdapterChangeDetected(void)
9834 lock_ObtainMutex(&smb_StartedLock);
9836 if (!powerStateSuspended) {
9837 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9838 NULL, 0, &lpid, "smb_LanAdapterChange");
9839 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9840 thrd_CloseHandle(phandle);
9843 smb_LanAdapterChangeDetected = 1;
9844 lock_ReleaseMutex(&smb_StartedLock);
9847 void smb_LanAdapterChange(int locked) {
9848 lana_number_t lanaNum;
9850 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9852 LANA_ENUM temp_list;
9857 afsi_log("smb_LanAdapterChange");
9860 lock_ObtainMutex(&smb_StartedLock);
9862 smb_LanAdapterChangeDetected = 0;
9864 if (!powerStateSuspended &&
9865 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9866 LANA_NETBIOS_NAME_FULL)) &&
9867 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9868 if ( isGateway != bGateway ) {
9869 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9870 smb_LANadapter, lanaNum, isGateway, bGateway);
9872 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9873 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9874 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9877 NCB *ncbp = smb_GetNCB();
9878 ncbp->ncb_command = NCBENUM;
9879 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9880 ncbp->ncb_length = sizeof(temp_list);
9881 code = Netbios(ncbp);
9883 if (temp_list.length != lana_list.length) {
9884 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9885 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9888 for (i=0; i<lana_list.length; i++) {
9889 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9890 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9891 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9903 smb_StopListeners(1);
9904 smb_RestartListeners(1);
9907 lock_ReleaseMutex(&smb_StartedLock);
9910 /* initialize Netbios */
9911 int smb_NetbiosInit(int locked)
9914 int i, lana, code, l;
9916 int delname_tried=0;
9919 lana_number_t lanaNum;
9922 lock_ObtainMutex(&smb_StartedLock);
9924 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9925 smb_ListenerState != SMB_LISTENER_STOPPED) {
9928 lock_ReleaseMutex(&smb_StartedLock);
9931 /* setup the NCB system */
9932 ncbp = smb_GetNCB();
9934 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9935 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9936 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9938 if (smb_LANadapter != LANA_INVALID)
9939 afsi_log("LAN adapter number %d", smb_LANadapter);
9941 afsi_log("LAN adapter number not determined");
9944 afsi_log("Set for gateway service");
9946 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9948 /* something went horribly wrong. We can't proceed without a netbios name */
9950 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9951 osi_panic(buf, __FILE__, __LINE__);
9954 /* remember the name */
9955 len = (int)strlen(cm_NetbiosName);
9957 free(smb_localNamep);
9958 smb_localNamep = malloc(len+1);
9959 strcpy(smb_localNamep, cm_NetbiosName);
9960 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9962 /* Also copy the value to the client character encoded string */
9963 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9965 if (smb_LANadapter == LANA_INVALID) {
9966 ncbp->ncb_command = NCBENUM;
9967 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9968 ncbp->ncb_length = sizeof(lana_list);
9969 code = Netbios(ncbp);
9971 afsi_log("Netbios NCBENUM error code %d", code);
9972 osi_panic(s, __FILE__, __LINE__);
9976 lana_list.length = 1;
9977 lana_list.lana[0] = smb_LANadapter;
9980 for (i = 0; i < lana_list.length; i++) {
9981 /* reset the adaptor: in Win32, this is required for every process, and
9982 * acts as an init call, not as a real hardware reset.
9984 ncbp->ncb_command = NCBRESET;
9985 ncbp->ncb_callname[0] = 100;
9986 ncbp->ncb_callname[2] = 100;
9987 ncbp->ncb_lana_num = lana_list.lana[i];
9988 code = Netbios(ncbp);
9990 code = ncbp->ncb_retcode;
9992 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9993 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9995 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9999 /* and declare our name so we can receive connections */
10000 memset(ncbp, 0, sizeof(*ncbp));
10001 len=lstrlen(smb_localNamep);
10002 memset(smb_sharename,' ',NCBNAMSZ);
10003 memcpy(smb_sharename,smb_localNamep,len);
10004 afsi_log("lana_list.length %d", lana_list.length);
10006 /* Keep the name so we can unregister it later */
10007 for (l = 0; l < lana_list.length; l++) {
10008 lana = lana_list.lana[l];
10010 ncbp->ncb_command = NCBADDNAME;
10011 ncbp->ncb_lana_num = lana;
10012 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10013 code = Netbios(ncbp);
10015 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10016 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10018 char name[NCBNAMSZ+1];
10020 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10021 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10025 code = ncbp->ncb_retcode;
10028 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10031 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10032 if (code == NRC_BRIDGE) { /* invalid LANA num */
10033 lana_list.lana[l] = LANA_INVALID;
10036 else if (code == NRC_DUPNAME) {
10037 afsi_log("Name already exists; try to delete it");
10038 memset(ncbp, 0, sizeof(*ncbp));
10039 ncbp->ncb_command = NCBDELNAME;
10040 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10041 ncbp->ncb_lana_num = lana;
10042 code = Netbios(ncbp);
10044 code = ncbp->ncb_retcode;
10046 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10048 if (code != 0 || delname_tried) {
10049 lana_list.lana[l] = LANA_INVALID;
10051 else if (code == 0) {
10052 if (!delname_tried) {
10060 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10061 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10065 smb_LANadapter = lana;
10066 lana_found = 1; /* at least one worked */
10070 osi_assertx(lana_list.length >= 0, "empty lana list");
10072 afsi_log("No valid LANA numbers found!");
10073 lana_list.length = 0;
10074 smb_LANadapter = LANA_INVALID;
10075 smb_ListenerState = SMB_LISTENER_STOPPED;
10076 cm_VolStatus_Network_Stopped(cm_NetbiosName
10083 /* we're done with the NCB now */
10086 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10087 if (lana_list.length > 0)
10088 osi_assert(smb_LANadapter != LANA_INVALID);
10091 lock_ReleaseMutex(&smb_StartedLock);
10093 return (lana_list.length > 0 ? 1 : 0);
10096 void smb_StartListeners(int locked)
10103 lock_ObtainMutex(&smb_StartedLock);
10105 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10107 lock_ReleaseMutex(&smb_StartedLock);
10111 afsi_log("smb_StartListeners");
10112 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10113 configureBackConnectionHostNames();
10115 /* Configure Extended SMB Session Timeouts */
10116 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10117 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10118 configureExtendedSMBSessionTimeouts();
10121 smb_ListenerState = SMB_LISTENER_STARTED;
10122 cm_VolStatus_Network_Started(cm_NetbiosName
10128 for (i = 0; i < lana_list.length; i++) {
10129 if (lana_list.lana[i] == LANA_INVALID)
10131 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10132 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10133 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10134 thrd_CloseHandle(phandle);
10137 lock_ReleaseMutex(&smb_StartedLock);
10140 void smb_RestartListeners(int locked)
10143 lock_ObtainMutex(&smb_StartedLock);
10145 if (powerStateSuspended)
10146 afsi_log("smb_RestartListeners called while suspended");
10148 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10149 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10150 if (smb_NetbiosInit(1))
10151 smb_StartListeners(1);
10152 } else if (smb_LanAdapterChangeDetected) {
10153 smb_LanAdapterChange(1);
10157 lock_ReleaseMutex(&smb_StartedLock);
10160 void smb_StopListener(NCB *ncbp, int lana, int wait)
10164 memset(ncbp, 0, sizeof(*ncbp));
10165 ncbp->ncb_command = NCBDELNAME;
10166 ncbp->ncb_lana_num = lana;
10167 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10168 code = Netbios(ncbp);
10170 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10171 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10173 /* and then reset the LANA; this will cause the listener threads to exit */
10174 ncbp->ncb_command = NCBRESET;
10175 ncbp->ncb_callname[0] = 100;
10176 ncbp->ncb_callname[2] = 100;
10177 ncbp->ncb_lana_num = lana;
10178 code = Netbios(ncbp);
10180 code = ncbp->ncb_retcode;
10182 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10184 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10188 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10191 void smb_StopListeners(int locked)
10197 lock_ObtainMutex(&smb_StartedLock);
10199 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10201 lock_ReleaseMutex(&smb_StartedLock);
10205 afsi_log("smb_StopListeners");
10206 smb_ListenerState = SMB_LISTENER_STOPPED;
10207 cm_VolStatus_Network_Stopped(cm_NetbiosName
10213 ncbp = smb_GetNCB();
10215 /* Unregister the SMB name */
10216 for (l = 0; l < lana_list.length; l++) {
10217 lana = lana_list.lana[l];
10219 if (lana != LANA_INVALID) {
10220 smb_StopListener(ncbp, lana, TRUE);
10222 /* mark the adapter invalid */
10223 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10227 /* force a re-evaluation of the network adapters */
10228 lana_list.length = 0;
10229 smb_LANadapter = LANA_INVALID;
10232 lock_ReleaseMutex(&smb_StartedLock);
10235 void smb_Init(osi_log_t *logp, int useV3,
10245 EVENT_HANDLE retHandle;
10246 char eventName[MAX_PATH];
10247 int startListeners = 0;
10249 smb_MBfunc = aMBfunc;
10253 /* Initialize smb_localZero */
10254 myTime.tm_isdst = -1; /* compute whether on DST or not */
10255 myTime.tm_year = 70;
10257 myTime.tm_mday = 1;
10258 myTime.tm_hour = 0;
10261 smb_localZero = mktime(&myTime);
10263 #ifdef AFS_FREELANCE_CLIENT
10264 /* Make sure the root.afs volume has the correct time */
10265 cm_noteLocalMountPointChange();
10268 /* initialize the remote debugging log */
10271 /* and the global lock */
10272 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10273 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10275 /* Raw I/O data structures */
10276 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10278 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10279 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10281 /* 4 Raw I/O buffers */
10282 smb_RawBufs = calloc(65536,1);
10283 *((char **)smb_RawBufs) = NULL;
10284 for (i=0; i<3; i++) {
10285 char *rawBuf = calloc(65536,1);
10286 *((char **)rawBuf) = smb_RawBufs;
10287 smb_RawBufs = rawBuf;
10290 /* global free lists */
10291 smb_ncbFreeListp = NULL;
10292 smb_packetFreeListp = NULL;
10294 lock_ObtainMutex(&smb_StartedLock);
10295 startListeners = smb_NetbiosInit(1);
10297 /* Initialize listener and server structures */
10299 memset(dead_sessions, 0, sizeof(dead_sessions));
10300 sprintf(eventName, "SessionEvents[0]");
10301 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10302 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10303 afsi_log("Event Object Already Exists: %s", eventName);
10305 smb_NumServerThreads = nThreads;
10306 sprintf(eventName, "NCBavails[0]");
10307 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10308 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10309 afsi_log("Event Object Already Exists: %s", eventName);
10310 sprintf(eventName, "NCBevents[0]");
10311 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10312 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10313 afsi_log("Event Object Already Exists: %s", eventName);
10314 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10315 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10316 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10317 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10318 afsi_log("Event Object Already Exists: %s", eventName);
10319 for (i = 0; i < smb_NumServerThreads; i++) {
10320 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10321 NCBreturns[i][0] = retHandle;
10324 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10325 for (i = 0; i < smb_NumServerThreads; i++) {
10326 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10327 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10328 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10329 afsi_log("Event Object Already Exists: %s", eventName);
10330 InitNCBslot((int)(i+1));
10332 numNCBs = smb_NumServerThreads + 1;
10334 /* Initialize dispatch table */
10335 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10336 /* Prepare the table for unknown operations */
10337 for(i=0; i<= SMB_NOPCODES; i++) {
10338 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10340 /* Fill in the ones we do know */
10341 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10342 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10343 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10344 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10345 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10346 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10347 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10348 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10349 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10350 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10351 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10352 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10353 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10354 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10355 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10356 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10357 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10358 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10359 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10360 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10361 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10362 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10363 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10364 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10365 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10366 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10367 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10368 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10369 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10370 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10371 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10372 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10373 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10374 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10375 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10376 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10377 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10378 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10379 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10380 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10381 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10382 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10383 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10384 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10385 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10386 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10387 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10388 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10389 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10390 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10391 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10392 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10393 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10394 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10395 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10396 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10397 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10398 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10399 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10400 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10401 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10402 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10403 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10404 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10405 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10406 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10407 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10408 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10409 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10410 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10411 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10412 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10413 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10414 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10416 /* setup tran 2 dispatch table */
10417 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10418 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10419 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10420 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10421 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10422 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10423 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10424 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10425 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10426 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10427 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10428 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10429 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10430 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10431 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10432 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10433 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10434 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10436 /* setup the rap dispatch table */
10437 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10438 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10439 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10440 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10441 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10445 /* if we are doing SMB authentication we have register outselves as a logon process */
10446 if (smb_authType != SMB_AUTH_NONE) {
10447 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10448 LSA_STRING afsProcessName;
10449 LSA_OPERATIONAL_MODE dummy; /*junk*/
10451 afsProcessName.Buffer = "OpenAFSClientDaemon";
10452 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10453 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10455 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10457 if (nts == STATUS_SUCCESS) {
10458 LSA_STRING packageName;
10459 /* we are registered. Find out the security package id */
10460 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10461 packageName.Length = (USHORT)strlen(packageName.Buffer);
10462 packageName.MaximumLength = packageName.Length + 1;
10463 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10464 if (nts == STATUS_SUCCESS) {
10466 * This code forces Windows to authenticate against the Logon Cache
10467 * first instead of attempting to authenticate against the Domain
10468 * Controller. When the Windows logon cache is enabled this improves
10469 * performance by removing the network access and works around a bug
10470 * seen at sites which are using a MIT Kerberos principal to login
10471 * to machines joined to a non-root domain in a multi-domain forest.
10472 * MsV1_0SetProcessOption was added in Windows XP.
10474 PVOID pResponse = NULL;
10475 ULONG cbResponse = 0;
10476 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10478 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10479 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10480 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10481 OptionsRequest.DisableOptions = FALSE;
10483 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10486 sizeof(OptionsRequest),
10492 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10493 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10496 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10498 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10499 afsi_log("MsV1_0SetProcessOption success");
10501 /* END - code from Larry */
10503 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10504 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10505 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10507 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10509 /* something went wrong. We report the error and revert back to no authentication
10510 because we can't perform any auth requests without a successful lsa handle
10511 or sec package id. */
10512 afsi_log("Reverting to NO SMB AUTH");
10513 smb_authType = SMB_AUTH_NONE;
10516 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10518 /* something went wrong. We report the error and revert back to no authentication
10519 because we can't perform any auth requests without a successful lsa handle
10520 or sec package id. */
10521 afsi_log("Reverting to NO SMB AUTH");
10522 smb_authType = SMB_AUTH_NONE;
10526 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10527 * time prevents the failure of authentication when logged into Windows with an
10528 * external Kerberos principal mapped to a local account.
10530 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10531 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10532 * then the only option is NTLMSSP anyway; so just fallback.
10537 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10538 if (secBlobLength == 0) {
10539 smb_authType = SMB_AUTH_NTLM;
10540 afsi_log("Reverting to SMB AUTH NTLM");
10549 /* Now get ourselves a domain name. */
10550 /* For now we are using the local computer name as the domain name.
10551 * It is actually the domain for local logins, and we are acting as
10552 * a local SMB server.
10554 bufsize = lengthof(smb_ServerDomainName) - 1;
10555 GetComputerNameW(smb_ServerDomainName, &bufsize);
10556 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10557 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10560 /* Start listeners, waiters, servers, and daemons */
10561 if (startListeners)
10562 smb_StartListeners(1);
10564 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10565 NULL, 0, &lpid, "smb_ClientWaiter");
10566 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10567 thrd_CloseHandle(phandle);
10569 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10570 NULL, 0, &lpid, "smb_ServerWaiter");
10571 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10572 thrd_CloseHandle(phandle);
10574 for (i=0; i<smb_NumServerThreads; i++) {
10575 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10576 (void *) i, 0, &lpid, "smb_Server");
10577 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10578 thrd_CloseHandle(phandle);
10581 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10582 NULL, 0, &lpid, "smb_Daemon");
10583 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10584 thrd_CloseHandle(phandle);
10586 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10587 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10588 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10589 thrd_CloseHandle(phandle);
10591 lock_ReleaseMutex(&smb_StartedLock);
10595 void smb_Shutdown(void)
10602 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10604 /* setup the NCB system */
10605 ncbp = smb_GetNCB();
10607 /* Block new sessions by setting shutdown flag */
10608 smbShutdownFlag = 1;
10610 /* Hang up all sessions */
10611 memset(ncbp, 0, sizeof(NCB));
10612 for (i = 1; i < numSessions; i++)
10614 if (dead_sessions[i])
10617 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10618 ncbp->ncb_command = NCBHANGUP;
10619 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10620 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10621 code = Netbios(ncbp);
10622 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10623 if (code == 0) code = ncbp->ncb_retcode;
10625 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10626 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10630 /* Trigger the shutdown of all SMB threads */
10631 for (i = 0; i < smb_NumServerThreads; i++)
10632 thrd_SetEvent(NCBreturns[i][0]);
10634 thrd_SetEvent(NCBevents[0]);
10635 thrd_SetEvent(SessionEvents[0]);
10636 thrd_SetEvent(NCBavails[0]);
10638 for (i = 0;i < smb_NumServerThreads; i++) {
10639 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10640 if (code == WAIT_OBJECT_0) {
10643 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10644 thrd_SetEvent(NCBreturns[i--][0]);
10648 /* Delete Netbios name */
10649 memset(ncbp, 0, sizeof(NCB));
10650 for (i = 0; i < lana_list.length; i++) {
10651 if (lana_list.lana[i] == LANA_INVALID) continue;
10652 ncbp->ncb_command = NCBDELNAME;
10653 ncbp->ncb_lana_num = lana_list.lana[i];
10654 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10655 code = Netbios(ncbp);
10657 code = ncbp->ncb_retcode;
10659 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10660 ncbp->ncb_lana_num, code);
10665 /* Release the reference counts held by the VCs */
10666 lock_ObtainWrite(&smb_rctLock);
10667 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10672 if (vcp->magic != SMB_VC_MAGIC)
10673 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10674 __FILE__, __LINE__);
10676 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10678 if (fidp->scp != NULL) {
10681 lock_ReleaseWrite(&smb_rctLock);
10682 lock_ObtainMutex(&fidp->mx);
10683 if (fidp->scp != NULL) {
10686 lock_ObtainWrite(&scp->rw);
10687 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10688 lock_ReleaseWrite(&scp->rw);
10689 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10690 cm_ReleaseSCache(scp);
10692 lock_ReleaseMutex(&fidp->mx);
10693 lock_ObtainWrite(&smb_rctLock);
10697 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10699 smb_ReleaseVCNoLock(tidp->vcp);
10701 cm_user_t *userp = tidp->userp;
10702 tidp->userp = NULL;
10703 cm_ReleaseUser(userp);
10707 lock_ReleaseWrite(&smb_rctLock);
10711 /* Get the UNC \\<servername>\<sharename> prefix. */
10712 char *smb_GetSharename()
10717 /* Make sure we have been properly initialized. */
10718 if (smb_localNamep == NULL)
10721 /* Allocate space for \\<servername>\<sharename>, plus the
10724 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10725 name = malloc(len);
10726 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10732 void smb_LogPacket(smb_packet_t *packet)
10736 unsigned length, paramlen, datalen, i, j;
10738 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10740 if (!packet) return;
10742 osi_Log0(smb_logp, "*** SMB packet dump ***");
10744 smbp = (smb_t *) packet->data;
10745 vp = (BYTE *) packet->data;
10747 paramlen = smbp->wct * 2;
10748 datalen = *((WORD *) (smbp->vdata + paramlen));
10749 length = sizeof(*smbp) + paramlen + 1 + datalen;
10751 for (i=0;i < length; i+=16)
10753 memset( buf, ' ', 80 );
10756 itoa( i, buf, 16 );
10758 buf[strlen(buf)] = ' ';
10760 cp = (BYTE*) buf + 7;
10762 for (j=0;j < 16 && (i+j)<length; j++)
10764 *(cp++) = hex[vp[i+j] >> 4];
10765 *(cp++) = hex[vp[i+j] & 0xf];
10775 for (j=0;j < 16 && (i+j)<length;j++)
10777 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10788 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10791 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10793 #endif /* LOG_PACKET */
10796 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10802 smb_username_t *unp;
10803 smb_waitingLockRequest_t *wlrp;
10806 lock_ObtainRead(&smb_rctLock);
10808 sprintf(output, "begin dumping smb_username_t\r\n");
10809 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10810 for (unp = usernamesp; unp; unp=unp->nextp)
10812 cm_ucell_t *ucellp;
10814 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10815 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10816 unp->name ? unp->name : _C("NULL"),
10817 unp->machine ? unp->machine : _C("NULL"));
10818 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10820 sprintf(output, " begin dumping cm_ucell_t\r\n");
10821 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10823 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10824 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",
10825 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10826 ucellp->expirationTime, ucellp->gen,
10828 ucellp->cellp->name);
10829 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10832 sprintf(output, " done dumping cm_ucell_t\r\n");
10833 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10836 sprintf(output, "done dumping smb_username_t\r\n");
10837 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10840 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10841 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10844 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10845 smb_waitingLock_t *lockp;
10847 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10848 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10849 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10851 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10852 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10853 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10854 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10855 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10856 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10858 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10859 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10862 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10863 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10865 sprintf(output, "begin dumping smb_vc_t\r\n");
10866 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10868 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10874 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10875 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10876 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10878 sprintf(output, " begin dumping smb_user_t\r\n");
10879 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10880 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10881 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10882 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10883 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10885 sprintf(output, " done dumping smb_user_t\r\n");
10886 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10888 sprintf(output, " begin dumping smb_tid_t\r\n");
10889 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10890 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10891 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",
10892 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10893 tidp->pathname ? tidp->pathname : _C("NULL"));
10894 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10896 sprintf(output, " done dumping smb_tid_t\r\n");
10897 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10899 sprintf(output, " begin dumping smb_fid_t\r\n");
10900 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10902 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10904 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",
10905 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10906 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10907 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10908 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10911 sprintf(output, " done dumping smb_fid_t\r\n");
10912 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10915 sprintf(output, "done dumping smb_vc_t\r\n");
10916 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10918 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10919 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10921 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10927 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10928 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10929 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10931 sprintf(output, " begin dumping smb_user_t\r\n");
10932 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10933 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10934 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10935 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10936 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10938 sprintf(output, " done dumping smb_user_t\r\n");
10939 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10941 sprintf(output, " begin dumping smb_tid_t\r\n");
10942 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10943 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10944 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",
10945 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10946 tidp->pathname ? tidp->pathname : _C("NULL"));
10947 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10949 sprintf(output, " done dumping smb_tid_t\r\n");
10950 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10952 sprintf(output, " begin dumping smb_fid_t\r\n");
10953 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10955 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10957 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",
10958 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10959 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10960 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10961 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10964 sprintf(output, " done dumping smb_fid_t\r\n");
10965 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10968 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10969 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10972 lock_ReleaseRead(&smb_rctLock);
10976 long smb_IsNetworkStarted(void)
10979 lock_ObtainWrite(&smb_globalLock);
10980 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10981 lock_ReleaseWrite(&smb_globalLock);