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 if (code && cm_dnsEnabled) {
1950 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1955 /* construct the path */
1957 clientchar_t temp[1024];
1959 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
1960 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
1961 rw ? _C("/.%S/") : _C("/%S/"), temp);
1962 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1972 /* Client-side offline caching policy types */
1973 #define CSC_POLICY_MANUAL 0
1974 #define CSC_POLICY_DOCUMENTS 1
1975 #define CSC_POLICY_PROGRAMS 2
1976 #define CSC_POLICY_DISABLE 3
1978 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1981 clientchar_t policy[1024];
1984 int retval = CSC_POLICY_MANUAL;
1986 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1987 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1990 REG_OPTION_NON_VOLATILE,
1994 NULL ) != ERROR_SUCCESS)
1995 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1997 len = sizeof(policy);
1998 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2000 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2002 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2004 retval = CSC_POLICY_MANUAL;
2006 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2008 retval = CSC_POLICY_DOCUMENTS;
2010 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2012 retval = CSC_POLICY_PROGRAMS;
2014 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2016 retval = CSC_POLICY_DISABLE;
2019 RegCloseKey(hkCSCPolicy);
2023 /* find a dir search structure by cookie value, and return it held.
2024 * Must be called with smb_globalLock held.
2026 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2028 smb_dirSearch_t *dsp;
2030 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2031 if (dsp->cookie == cookie) {
2032 if (dsp != smb_firstDirSearchp) {
2033 /* move to head of LRU queue, too, if we're not already there */
2034 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2035 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2036 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2037 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2038 if (!smb_lastDirSearchp)
2039 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2047 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2048 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2049 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2055 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2057 lock_ObtainMutex(&dsp->mx);
2058 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2059 dsp->cookie, dsp, dsp->scp);
2060 dsp->flags |= SMB_DIRSEARCH_DELETE;
2061 if (dsp->scp != NULL) {
2062 lock_ObtainWrite(&dsp->scp->rw);
2063 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2064 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2065 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2066 dsp->scp->bulkStatProgress = hzero;
2068 lock_ReleaseWrite(&dsp->scp->rw);
2070 lock_ReleaseMutex(&dsp->mx);
2073 /* Must be called with the smb_globalLock held */
2074 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2076 cm_scache_t *scp = NULL;
2078 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2079 if (dsp->refCount == 0) {
2080 lock_ObtainMutex(&dsp->mx);
2081 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2082 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2083 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2084 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2085 lock_ReleaseMutex(&dsp->mx);
2086 lock_FinalizeMutex(&dsp->mx);
2088 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2089 dsp->cookie, dsp, scp);
2092 lock_ReleaseMutex(&dsp->mx);
2095 /* do this now to avoid spurious locking hierarchy creation */
2097 cm_ReleaseSCache(scp);
2100 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2102 lock_ObtainWrite(&smb_globalLock);
2103 smb_ReleaseDirSearchNoLock(dsp);
2104 lock_ReleaseWrite(&smb_globalLock);
2107 /* find a dir search structure by cookie value, and return it held */
2108 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2110 smb_dirSearch_t *dsp;
2112 lock_ObtainWrite(&smb_globalLock);
2113 dsp = smb_FindDirSearchNoLock(cookie);
2114 lock_ReleaseWrite(&smb_globalLock);
2118 /* GC some dir search entries, in the address space expected by the specific protocol.
2119 * Must be called with smb_globalLock held; release the lock temporarily.
2121 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2122 void smb_GCDirSearches(int isV3)
2124 smb_dirSearch_t *prevp;
2125 smb_dirSearch_t *dsp;
2126 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2130 victimCount = 0; /* how many have we got so far */
2131 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2132 /* we'll move tp from queue, so
2135 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2136 /* if no one is using this guy, and we're either in the new protocol,
2137 * or we're in the old one and this is a small enough ID to be useful
2138 * to the old protocol, GC this guy.
2140 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2141 /* hold and delete */
2142 lock_ObtainMutex(&dsp->mx);
2143 dsp->flags |= SMB_DIRSEARCH_DELETE;
2144 lock_ReleaseMutex(&dsp->mx);
2145 victimsp[victimCount++] = dsp;
2149 /* don't do more than this */
2150 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2154 /* now release them */
2155 for (i = 0; i < victimCount; i++) {
2156 smb_ReleaseDirSearchNoLock(victimsp[i]);
2160 /* function for allocating a dir search entry. We need these to remember enough context
2161 * since we don't get passed the path from call to call during a directory search.
2163 * Returns a held dir search structure, and bumps the reference count on the vnode,
2164 * since it saves a pointer to the vnode.
2166 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2168 smb_dirSearch_t *dsp;
2174 lock_ObtainWrite(&smb_globalLock);
2177 /* what's the biggest ID allowed in this version of the protocol */
2178 /* TODO: do we really want a non v3 dir search request to wrap
2179 smb_dirSearchCounter? */
2180 maxAllowed = isV3 ? 65535 : 255;
2181 if (smb_dirSearchCounter > maxAllowed)
2182 smb_dirSearchCounter = 1;
2184 start = smb_dirSearchCounter;
2187 /* twice so we have enough tries to find guys we GC after one pass;
2188 * 10 extra is just in case I mis-counted.
2190 if (++counter > 2*maxAllowed+10)
2191 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2193 if (smb_dirSearchCounter > maxAllowed) {
2194 smb_dirSearchCounter = 1;
2196 if (smb_dirSearchCounter == start) {
2198 smb_GCDirSearches(isV3);
2201 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2203 /* don't need to watch for refcount zero and deleted, since
2204 * we haven't dropped the global lock.
2207 ++smb_dirSearchCounter;
2211 dsp = malloc(sizeof(*dsp));
2212 memset(dsp, 0, sizeof(*dsp));
2213 dsp->cookie = smb_dirSearchCounter;
2214 ++smb_dirSearchCounter;
2216 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2217 dsp->lastTime = osi_Time();
2218 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2219 if (!smb_lastDirSearchp)
2220 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2222 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2226 lock_ReleaseWrite(&smb_globalLock);
2230 static smb_packet_t *smb_GetPacket(void)
2234 lock_ObtainWrite(&smb_globalLock);
2235 tbp = smb_packetFreeListp;
2237 smb_packetFreeListp = tbp->nextp;
2238 lock_ReleaseWrite(&smb_globalLock);
2240 tbp = calloc(sizeof(*tbp),1);
2241 tbp->magic = SMB_PACKETMAGIC;
2244 tbp->resumeCode = 0;
2250 tbp->ncb_length = 0;
2253 tbp->stringsp = NULL;
2255 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2260 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2263 tbp = smb_GetPacket();
2264 memcpy(tbp, pkt, sizeof(smb_packet_t));
2265 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2266 tbp->stringsp = NULL;
2268 smb_HoldVC(tbp->vcp);
2272 static NCB *smb_GetNCB(void)
2277 lock_ObtainWrite(&smb_globalLock);
2278 tbp = smb_ncbFreeListp;
2280 smb_ncbFreeListp = tbp->nextp;
2281 lock_ReleaseWrite(&smb_globalLock);
2283 tbp = calloc(sizeof(*tbp),1);
2284 tbp->magic = SMB_NCBMAGIC;
2287 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2289 memset(&tbp->ncb, 0, sizeof(NCB));
2294 static void FreeSMBStrings(smb_packet_t * pkt)
2299 for (s = pkt->stringsp; s; s = ns) {
2303 pkt->stringsp = NULL;
2306 void smb_FreePacket(smb_packet_t *tbp)
2308 smb_vc_t * vcp = NULL;
2309 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2311 lock_ObtainWrite(&smb_globalLock);
2312 tbp->nextp = smb_packetFreeListp;
2313 smb_packetFreeListp = tbp;
2314 tbp->magic = SMB_PACKETMAGIC;
2318 tbp->resumeCode = 0;
2324 tbp->ncb_length = 0;
2326 FreeSMBStrings(tbp);
2327 lock_ReleaseWrite(&smb_globalLock);
2333 static void smb_FreeNCB(NCB *bufferp)
2337 tbp = (smb_ncb_t *) bufferp;
2338 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2340 lock_ObtainWrite(&smb_globalLock);
2341 tbp->nextp = smb_ncbFreeListp;
2342 smb_ncbFreeListp = tbp;
2343 lock_ReleaseWrite(&smb_globalLock);
2346 /* get a ptr to the data part of a packet, and its count */
2347 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2351 unsigned char *afterParmsp;
2353 parmBytes = *smbp->wctp << 1;
2354 afterParmsp = smbp->wctp + parmBytes + 1;
2356 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2357 if (nbytesp) *nbytesp = dataBytes;
2359 /* don't forget to skip the data byte count, since it follows
2360 * the parameters; that's where the "2" comes from below.
2362 return (unsigned char *) (afterParmsp + 2);
2365 /* must set all the returned parameters before playing around with the
2366 * data region, since the data region is located past the end of the
2367 * variable number of parameters.
2369 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2371 unsigned char *afterParmsp;
2373 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2375 *afterParmsp++ = dsize & 0xff;
2376 *afterParmsp = (dsize>>8) & 0xff;
2379 /* return the parm'th parameter in the smbp packet */
2380 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2383 unsigned char *parmDatap;
2385 parmCount = *smbp->wctp;
2387 if (parm >= parmCount) {
2390 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2391 parm, parmCount, smbp->ncb_length);
2392 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2393 parm, parmCount, smbp->ncb_length);
2394 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2395 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2396 osi_panic(s, __FILE__, __LINE__);
2398 parmDatap = smbp->wctp + (2*parm) + 1;
2400 return parmDatap[0] + (parmDatap[1] << 8);
2403 /* return the parm'th parameter in the smbp packet */
2404 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2407 unsigned char *parmDatap;
2409 parmCount = *smbp->wctp;
2411 if (parm >= parmCount) {
2414 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2415 parm, parmCount, smbp->ncb_length);
2416 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2417 parm, parmCount, smbp->ncb_length);
2418 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2419 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2420 osi_panic(s, __FILE__, __LINE__);
2422 parmDatap = smbp->wctp + (2*parm) + 1;
2424 return parmDatap[0];
2427 /* return the parm'th parameter in the smbp packet */
2428 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2431 unsigned char *parmDatap;
2433 parmCount = *smbp->wctp;
2435 if (parm + 1 >= parmCount) {
2438 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2439 parm, parmCount, smbp->ncb_length);
2440 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2441 parm, parmCount, smbp->ncb_length);
2442 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2443 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2444 osi_panic(s, __FILE__, __LINE__);
2446 parmDatap = smbp->wctp + (2*parm) + 1;
2448 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2451 /* return the parm'th parameter in the smbp packet */
2452 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2455 unsigned char *parmDatap;
2457 parmCount = *smbp->wctp;
2459 if (parm * 2 + offset >= parmCount * 2) {
2462 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2463 parm, offset, parmCount, smbp->ncb_length);
2464 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2465 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2466 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2467 parm, offset, parmCount, smbp->ncb_length);
2468 osi_panic(s, __FILE__, __LINE__);
2470 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2472 return parmDatap[0] + (parmDatap[1] << 8);
2475 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2477 unsigned char *parmDatap;
2479 /* make sure we have enough slots */
2480 if (*smbp->wctp <= slot)
2481 *smbp->wctp = slot+1;
2483 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2484 *parmDatap++ = parmValue & 0xff;
2485 *parmDatap = (parmValue>>8) & 0xff;
2488 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2490 unsigned char *parmDatap;
2492 /* make sure we have enough slots */
2493 if (*smbp->wctp <= slot)
2494 *smbp->wctp = slot+2;
2496 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2497 *parmDatap++ = parmValue & 0xff;
2498 *parmDatap++ = (parmValue>>8) & 0xff;
2499 *parmDatap++ = (parmValue>>16) & 0xff;
2500 *parmDatap = (parmValue>>24) & 0xff;
2503 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2505 unsigned char *parmDatap;
2508 /* make sure we have enough slots */
2509 if (*smbp->wctp <= slot)
2510 *smbp->wctp = slot+4;
2512 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2514 *parmDatap++ = *parmValuep++;
2517 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2519 unsigned char *parmDatap;
2521 /* make sure we have enough slots */
2522 if (*smbp->wctp <= slot) {
2523 if (smbp->oddByte) {
2525 *smbp->wctp = slot+1;
2530 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2531 *parmDatap++ = parmValue & 0xff;
2536 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2537 clientchar_t *inPathp)
2539 clientchar_t *lastSlashp;
2540 clientchar_t *streamp = NULL;
2541 clientchar_t *typep = NULL;
2543 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2544 if (lastComponentp) {
2545 *lastComponentp = lastSlashp;
2549 * If the name contains a stream name and a type
2550 * and the stream name is the nul-string and the
2551 * type is $DATA, then strip "::$DATA" from the
2552 * last component string that is returned.
2554 * Otherwise, return the full path name and allow
2555 * the file name to be rejected because it contains
2558 typep = cm_ClientStrRChr(lastSlashp, L':');
2559 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2561 streamp = cm_ClientStrRChr(lastSlashp, L':');
2562 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2566 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2567 osi_LogSaveClientString(smb_logp,streamp),
2568 osi_LogSaveClientString(smb_logp,typep));
2572 if (inPathp == lastSlashp)
2574 *outPathp++ = *inPathp++;
2583 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2584 char **chainpp, int flags)
2587 afs_uint32 type = *inp++;
2590 * The first byte specifies the type of the input string.
2591 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2595 /* Length Counted */
2596 case 0x1: /* Data Block */
2597 case 0x5: /* Variable Block */
2598 cb = *inp++ << 16 | *inp++;
2601 /* Null-terminated string */
2602 case 0x4: /* ASCII */
2603 case 0x3: /* Pathname */
2604 case 0x2: /* Dialect */
2605 cb = sizeof(pktp->data) - (inp - pktp->data);
2606 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2607 #ifdef DEBUG_UNICODE
2610 cb = sizeof(pktp->data);
2615 return NULL; /* invalid input */
2619 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2620 flags |= SMB_STRF_FORCEASCII;
2623 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2626 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2627 char ** chainpp, int flags)
2632 if (!WANTS_UNICODE(pktp))
2633 flags |= SMB_STRF_FORCEASCII;
2636 cb = sizeof(pktp->data) - (inp - pktp->data);
2637 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2638 #ifdef DEBUG_UNICODE
2641 cb = sizeof(pktp->data);
2643 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2644 flags | SMB_STRF_SRCNULTERM);
2647 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2648 size_t cb, char ** chainpp, int flags)
2651 if (!WANTS_UNICODE(pktp))
2652 flags |= SMB_STRF_FORCEASCII;
2655 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2658 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2659 size_t cch, char ** chainpp, int flags)
2664 if (!WANTS_UNICODE(pktp))
2665 flags |= SMB_STRF_FORCEASCII;
2667 cb = cch * sizeof(wchar_t);
2670 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2674 smb_ParseStringBuf(const unsigned char * bufbase,
2675 cm_space_t ** stringspp,
2676 unsigned char *inp, size_t *pcb_max,
2677 char **chainpp, int flags)
2680 if (!(flags & SMB_STRF_FORCEASCII)) {
2682 cm_space_t * spacep;
2685 if (bufbase && ((inp - bufbase) % 2) != 0) {
2686 inp++; /* unicode strings are always word aligned */
2690 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2692 cch_src = *pcb_max / sizeof(wchar_t);
2696 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2703 spacep = cm_GetSpace();
2704 spacep->nextp = *stringspp;
2705 *stringspp = spacep;
2709 *chainpp = inp + sizeof(wchar_t);
2712 *(spacep->wdata) = 0;
2713 return spacep->wdata;
2716 StringCchCopyNW(spacep->wdata,
2717 lengthof(spacep->wdata),
2718 (const clientchar_t *) inp, cch_src);
2721 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2723 return spacep->wdata;
2727 cm_space_t * spacep;
2730 /* Not using Unicode */
2732 *chainpp = inp + strlen(inp) + 1;
2735 spacep = cm_GetSpace();
2736 spacep->nextp = *stringspp;
2737 *stringspp = spacep;
2739 cchdest = lengthof(spacep->wdata);
2740 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2741 spacep->wdata, cchdest);
2743 return spacep->wdata;
2749 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2751 size_t * plen, int flags)
2757 /* we are only calculating the required size */
2764 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2766 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2767 if (!(flags & SMB_STRF_IGNORENUL))
2768 *plen += sizeof(wchar_t);
2770 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2780 cch_str = cm_ClientStrLen(str);
2781 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2784 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2792 /* if outp != NULL ... */
2794 /* Number of bytes left in the buffer.
2796 If outp lies inside the packet data buffer, we assume that the
2797 buffer is the packet data buffer. Otherwise we assume that the
2798 buffer is sizeof(packet->data).
2801 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2802 align = (int)((outp - pktp->data) % 2);
2803 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2805 align = (int)(((size_t) outp) % 2);
2806 buffersize = (int)sizeof(pktp->data);
2811 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2817 if (*str == _C('\0')) {
2819 if (buffersize < sizeof(wchar_t))
2822 *((wchar_t *) outp) = L'\0';
2823 if (plen && !(flags & SMB_STRF_IGNORENUL))
2824 *plen += sizeof(wchar_t);
2825 return outp + sizeof(wchar_t);
2828 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2830 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2831 osi_LogSaveClientString(smb_logp, str),
2837 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2839 return outp + sizeof(wchar_t) * nchars;
2847 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2850 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2852 return outp + cch_dest;
2856 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2862 tlen = inp[0] + (inp[1]<<8);
2863 inp += 2; /* skip length field */
2866 *chainpp = inp + tlen;
2875 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2879 if (*inp++ != 0x1) return NULL;
2880 tlen = inp[0] + (inp[1]<<8);
2881 inp += 2; /* skip length field */
2884 *chainpp = inp + tlen;
2887 if (lengthp) *lengthp = tlen;
2892 /* format a packet as a response */
2893 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2898 outp = (smb_t *) op;
2900 /* zero the basic structure through the smb_wct field, and zero the data
2901 * size field, assuming that wct stays zero; otherwise, you have to
2902 * explicitly set the data size field, too.
2904 inSmbp = (smb_t *) inp;
2905 memset(outp, 0, sizeof(smb_t)+2);
2911 outp->com = inSmbp->com;
2912 outp->tid = inSmbp->tid;
2913 outp->pid = inSmbp->pid;
2914 outp->uid = inSmbp->uid;
2915 outp->mid = inSmbp->mid;
2916 outp->res[0] = inSmbp->res[0];
2917 outp->res[1] = inSmbp->res[1];
2918 op->inCom = inSmbp->com;
2920 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2921 #ifdef SEND_CANONICAL_PATHNAMES
2922 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2924 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2926 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2927 outp->flg2 |= SMB_FLAGS2_UNICODE;
2930 /* copy fields in generic packet area */
2931 op->wctp = &outp->wct;
2934 /* send a (probably response) packet; vcp tells us to whom to send it.
2935 * we compute the length by looking at wct and bcc fields.
2937 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2947 ncbp = smb_GetNCB();
2951 memset(ncbp, 0, sizeof(NCB));
2953 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2954 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2955 extra += tp[0] + (tp[1]<<8);
2956 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2957 extra += 3; /* wct and length fields */
2959 ncbp->ncb_length = extra; /* bytes to send */
2960 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2961 ncbp->ncb_lana_num = vcp->lana;
2962 ncbp->ncb_command = NCBSEND; /* op means send data */
2963 ncbp->ncb_buffer = (char *) inp;/* packet */
2964 code = Netbios(ncbp);
2967 const char * s = ncb_error_string(code);
2968 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2969 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2971 lock_ObtainMutex(&vcp->mx);
2972 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2973 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2975 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2976 lock_ReleaseMutex(&vcp->mx);
2977 lock_ObtainWrite(&smb_globalLock);
2978 dead_sessions[vcp->session] = TRUE;
2979 lock_ReleaseWrite(&smb_globalLock);
2980 smb_CleanupDeadVC(vcp);
2982 lock_ReleaseMutex(&vcp->mx);
2990 void smb_MapNTError(long code, unsigned long *NTStatusp)
2992 unsigned long NTStatus;
2994 /* map CM_ERROR_* errors to NT 32-bit status codes */
2995 /* NT Status codes are listed in ntstatus.h not winerror.h */
2999 else if (code == CM_ERROR_NOSUCHCELL) {
3000 NTStatus = 0xC0000034L; /* Name not found */
3002 else if (code == CM_ERROR_NOSUCHVOLUME) {
3003 NTStatus = 0xC0000034L; /* Name not found */
3005 else if (code == CM_ERROR_TIMEDOUT) {
3007 NTStatus = 0xC00000CFL; /* Sharing Paused */
3009 /* Do not send Timeout to the SMB redirector.
3010 * It causes the redirector to drop the connection */
3011 NTStatus = 0x00000102L; /* Timeout */
3012 /* do not send Retry to the SMB redirector.
3013 * It believes the error comes from the transport
3014 * layer not from the SMB server. */
3015 NTStatus = 0xC000022DL; /* Retry */
3017 NTStatus = 0xC00000B5L; /* I/O Timeout */
3020 else if (code == CM_ERROR_RETRY) {
3022 NTStatus = 0xC000022DL; /* Retry */
3024 NTStatus = 0xC00000B5L; /* I/O Timeout */
3027 else if (code == CM_ERROR_NOACCESS) {
3028 NTStatus = 0xC0000022L; /* Access denied */
3030 else if (code == CM_ERROR_READONLY) {
3031 NTStatus = 0xC00000A2L; /* Write protected */
3033 else if (code == CM_ERROR_NOSUCHFILE ||
3034 code == CM_ERROR_BPLUS_NOMATCH) {
3035 NTStatus = 0xC0000034L; /* Name not found */
3037 else if (code == CM_ERROR_NOSUCHPATH) {
3038 NTStatus = 0xC000003AL; /* Object path not found */
3040 else if (code == CM_ERROR_TOOBIG) {
3041 NTStatus = 0xC000007BL; /* Invalid image format */
3043 else if (code == CM_ERROR_INVAL) {
3044 NTStatus = 0xC000000DL; /* Invalid parameter */
3046 else if (code == CM_ERROR_BADFD) {
3047 NTStatus = 0xC0000008L; /* Invalid handle */
3049 else if (code == CM_ERROR_BADFDOP) {
3050 NTStatus = 0xC0000022L; /* Access denied */
3052 else if (code == CM_ERROR_UNKNOWN) {
3053 NTStatus = 0xC0000022L; /* Access denied */
3055 else if (code == CM_ERROR_EXISTS) {
3056 NTStatus = 0xC0000035L; /* Object name collision */
3058 else if (code == CM_ERROR_NOTEMPTY) {
3059 NTStatus = 0xC0000101L; /* Directory not empty */
3061 else if (code == CM_ERROR_CROSSDEVLINK) {
3062 NTStatus = 0xC00000D4L; /* Not same device */
3064 else if (code == CM_ERROR_NOTDIR) {
3065 NTStatus = 0xC0000103L; /* Not a directory */
3067 else if (code == CM_ERROR_ISDIR) {
3068 NTStatus = 0xC00000BAL; /* File is a directory */
3070 else if (code == CM_ERROR_BADOP) {
3072 /* I have no idea where this comes from */
3073 NTStatus = 0xC09820FFL; /* SMB no support */
3075 NTStatus = 0xC00000BBL; /* Not supported */
3076 #endif /* COMMENT */
3078 else if (code == CM_ERROR_BADSHARENAME) {
3079 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3081 else if (code == CM_ERROR_NOIPC) {
3083 NTStatus = 0xC0000022L; /* Access Denied */
3085 NTStatus = 0xC000013DL; /* Remote Resources */
3088 else if (code == CM_ERROR_CLOCKSKEW ||
3089 code == RXKADNOAUTH) {
3090 NTStatus = 0xC0000133L; /* Time difference at DC */
3092 else if (code == CM_ERROR_BADTID) {
3093 NTStatus = 0xC0982005L; /* SMB bad TID */
3095 else if (code == CM_ERROR_USESTD) {
3096 NTStatus = 0xC09820FBL; /* SMB use standard */
3098 else if (code == CM_ERROR_QUOTA) {
3099 NTStatus = 0xC0000044L; /* Quota exceeded */
3101 else if (code == CM_ERROR_SPACE) {
3102 NTStatus = 0xC000007FL; /* Disk full */
3104 else if (code == CM_ERROR_ATSYS) {
3105 NTStatus = 0xC0000033L; /* Object name invalid */
3107 else if (code == CM_ERROR_BADNTFILENAME) {
3108 NTStatus = 0xC0000033L; /* Object name invalid */
3110 else if (code == CM_ERROR_WOULDBLOCK) {
3111 NTStatus = 0xC00000D8L; /* Can't wait */
3113 else if (code == CM_ERROR_SHARING_VIOLATION) {
3114 NTStatus = 0xC0000043L; /* Sharing violation */
3116 else if (code == CM_ERROR_LOCK_CONFLICT) {
3117 NTStatus = 0xC0000054L; /* Lock conflict */
3119 else if (code == CM_ERROR_PARTIALWRITE) {
3120 NTStatus = 0xC000007FL; /* Disk full */
3122 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3123 NTStatus = 0xC0000023L; /* Buffer too small */
3125 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3126 NTStatus = 0xC0000035L; /* Object name collision */
3128 else if (code == CM_ERROR_BADPASSWORD) {
3129 NTStatus = 0xC000006DL; /* unknown username or bad password */
3131 else if (code == CM_ERROR_BADLOGONTYPE) {
3132 NTStatus = 0xC000015BL; /* logon type not granted */
3134 else if (code == CM_ERROR_GSSCONTINUE) {
3135 NTStatus = 0xC0000016L; /* more processing required */
3137 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3139 NTStatus = 0xC0000280L; /* reparse point not resolved */
3141 NTStatus = 0xC0000022L; /* Access Denied */
3144 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3145 NTStatus = 0xC0000257L; /* Path Not Covered */
3147 else if (code == CM_ERROR_ALLBUSY) {
3149 NTStatus = 0xC000022DL; /* Retry */
3151 NTStatus = 0xC00000B5L; /* I/O Timeout */
3154 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3155 NTStatus = 0xC000003AL; /* Path not found */
3157 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3158 NTStatus = 0xC0000322L; /* No Kerberos key */
3160 else if (code == CM_ERROR_BAD_LEVEL) {
3161 NTStatus = 0xC0000148L; /* Invalid Level */
3163 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3164 NTStatus = 0xC000007EL; /* Range Not Locked */
3166 else if (code == CM_ERROR_NOSUCHDEVICE) {
3167 NTStatus = 0xC000000EL; /* No Such Device */
3169 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3170 NTStatus = 0xC0000055L; /* Lock Not Granted */
3172 else if (code == ENOMEM) {
3173 NTStatus = 0xC0000017L; /* Out of Memory */
3175 else if (code == CM_ERROR_RPC_MOREDATA) {
3176 NTStatus = 0x80000005L; /* Buffer overflow */
3179 NTStatus = 0xC0982001L; /* SMB non-specific error */
3182 *NTStatusp = NTStatus;
3183 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3187 * NTSTATUS <-> Win32 Error Translation
3188 * http://support.microsoft.com/kb/113996
3190 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3192 unsigned long Win32E;
3194 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3198 else if (code == CM_ERROR_NOSUCHCELL) {
3199 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3201 else if (code == CM_ERROR_NOSUCHVOLUME) {
3202 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3204 else if (code == CM_ERROR_TIMEDOUT) {
3206 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3208 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3211 else if (code == CM_ERROR_RETRY) {
3212 Win32E = ERROR_RETRY; /* Retry */
3214 else if (code == CM_ERROR_NOACCESS) {
3215 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3217 else if (code == CM_ERROR_READONLY) {
3218 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3220 else if (code == CM_ERROR_NOSUCHFILE ||
3221 code == CM_ERROR_BPLUS_NOMATCH) {
3222 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3224 else if (code == CM_ERROR_NOSUCHPATH) {
3225 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3227 else if (code == CM_ERROR_TOOBIG) {
3228 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3230 else if (code == CM_ERROR_INVAL) {
3231 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3233 else if (code == CM_ERROR_BADFD) {
3234 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3236 else if (code == CM_ERROR_BADFDOP) {
3237 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3239 else if (code == CM_ERROR_UNKNOWN) {
3240 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3242 else if (code == CM_ERROR_EXISTS) {
3243 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3245 else if (code == CM_ERROR_NOTEMPTY) {
3246 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3248 else if (code == CM_ERROR_CROSSDEVLINK) {
3249 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3251 else if (code == CM_ERROR_NOTDIR) {
3252 Win32E = ERROR_DIRECTORY; /* Not a directory */
3254 else if (code == CM_ERROR_ISDIR) {
3255 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3257 else if (code == CM_ERROR_BADOP) {
3258 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3260 else if (code == CM_ERROR_BADSHARENAME) {
3261 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3263 else if (code == CM_ERROR_NOIPC) {
3265 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3267 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3270 else if (code == CM_ERROR_CLOCKSKEW ||
3271 code == RXKADNOAUTH) {
3272 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3274 else if (code == CM_ERROR_BADTID) {
3275 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3277 else if (code == CM_ERROR_USESTD) {
3278 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3280 else if (code == CM_ERROR_QUOTA) {
3281 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3283 else if (code == CM_ERROR_SPACE) {
3284 Win32E = ERROR_DISK_FULL; /* Disk full */
3286 else if (code == CM_ERROR_ATSYS) {
3287 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3289 else if (code == CM_ERROR_BADNTFILENAME) {
3290 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3292 else if (code == CM_ERROR_WOULDBLOCK) {
3293 Win32E = WAIT_TIMEOUT; /* Can't wait */
3295 else if (code == CM_ERROR_SHARING_VIOLATION) {
3296 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3298 else if (code == CM_ERROR_LOCK_CONFLICT) {
3299 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3301 else if (code == CM_ERROR_PARTIALWRITE) {
3302 Win32E = ERROR_DISK_FULL; /* Disk full */
3304 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3305 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3307 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3308 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3310 else if (code == CM_ERROR_BADPASSWORD) {
3311 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3313 else if (code == CM_ERROR_BADLOGONTYPE) {
3314 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3316 else if (code == CM_ERROR_GSSCONTINUE) {
3317 Win32E = ERROR_MORE_DATA; /* more processing required */
3319 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3321 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3323 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3326 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3327 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3329 else if (code == CM_ERROR_ALLBUSY) {
3330 Win32E = ERROR_RETRY; /* Retry */
3332 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3333 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3335 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3336 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3338 else if (code == CM_ERROR_BAD_LEVEL) {
3339 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3341 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3342 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3344 else if (code == CM_ERROR_NOSUCHDEVICE) {
3345 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3347 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3348 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3350 else if (code == ENOMEM) {
3351 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3353 else if (code == CM_ERROR_RPC_MOREDATA) {
3354 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3357 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3361 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3364 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3365 unsigned char *classp)
3367 unsigned char class;
3368 unsigned short error;
3370 /* map CM_ERROR_* errors to SMB errors */
3371 if (code == CM_ERROR_NOSUCHCELL) {
3373 error = 3; /* bad path */
3375 else if (code == CM_ERROR_NOSUCHVOLUME) {
3377 error = 3; /* bad path */
3379 else if (code == CM_ERROR_TIMEDOUT) {
3381 error = 81; /* server is paused */
3383 else if (code == CM_ERROR_RETRY) {
3384 class = 2; /* shouldn't happen */
3387 else if (code == CM_ERROR_NOACCESS) {
3389 error = 4; /* bad access */
3391 else if (code == CM_ERROR_READONLY) {
3393 error = 19; /* read only */
3395 else if (code == CM_ERROR_NOSUCHFILE ||
3396 code == CM_ERROR_BPLUS_NOMATCH) {
3398 error = 2; /* ENOENT! */
3400 else if (code == CM_ERROR_NOSUCHPATH) {
3402 error = 3; /* Bad path */
3404 else if (code == CM_ERROR_TOOBIG) {
3406 error = 11; /* bad format */
3408 else if (code == CM_ERROR_INVAL) {
3409 class = 2; /* server non-specific error code */
3412 else if (code == CM_ERROR_BADFD) {
3414 error = 6; /* invalid file handle */
3416 else if (code == CM_ERROR_BADFDOP) {
3417 class = 1; /* invalid op on FD */
3420 else if (code == CM_ERROR_EXISTS) {
3422 error = 80; /* file already exists */
3424 else if (code == CM_ERROR_NOTEMPTY) {
3426 error = 5; /* delete directory not empty */
3428 else if (code == CM_ERROR_CROSSDEVLINK) {
3430 error = 17; /* EXDEV */
3432 else if (code == CM_ERROR_NOTDIR) {
3433 class = 1; /* bad path */
3436 else if (code == CM_ERROR_ISDIR) {
3437 class = 1; /* access denied; DOS doesn't have a good match */
3440 else if (code == CM_ERROR_BADOP) {
3444 else if (code == CM_ERROR_BADSHARENAME) {
3448 else if (code == CM_ERROR_NOIPC) {
3450 error = 4; /* bad access */
3452 else if (code == CM_ERROR_CLOCKSKEW) {
3453 class = 1; /* invalid function */
3456 else if (code == CM_ERROR_BADTID) {
3460 else if (code == CM_ERROR_USESTD) {
3464 else if (code == CM_ERROR_REMOTECONN) {
3468 else if (code == CM_ERROR_QUOTA) {
3469 if (vcp->flags & SMB_VCFLAG_USEV3) {
3471 error = 39; /* disk full */
3475 error = 5; /* access denied */
3478 else if (code == CM_ERROR_SPACE) {
3479 if (vcp->flags & SMB_VCFLAG_USEV3) {
3481 error = 39; /* disk full */
3485 error = 5; /* access denied */
3488 else if (code == CM_ERROR_PARTIALWRITE) {
3490 error = 39; /* disk full */
3492 else if (code == CM_ERROR_ATSYS) {
3494 error = 2; /* ENOENT */
3496 else if (code == CM_ERROR_WOULDBLOCK) {
3498 error = 33; /* lock conflict */
3500 else if (code == CM_ERROR_LOCK_CONFLICT) {
3502 error = 33; /* lock conflict */
3504 else if (code == CM_ERROR_SHARING_VIOLATION) {
3506 error = 33; /* lock conflict */
3508 else if (code == CM_ERROR_NOFILES) {
3510 error = 18; /* no files in search */
3512 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3514 error = 183; /* Samba uses this */
3516 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3517 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3519 error = 2; /* bad password */
3521 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3523 error = 3; /* bad path */
3532 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3535 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3537 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3538 return CM_ERROR_BADOP;
3542 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3544 unsigned short EchoCount, i;
3545 char *data, *outdata;
3548 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3550 for (i=1; i<=EchoCount; i++) {
3551 data = smb_GetSMBData(inp, &dataSize);
3552 smb_SetSMBParm(outp, 0, i);
3553 smb_SetSMBDataLength(outp, dataSize);
3554 outdata = smb_GetSMBData(outp, NULL);
3555 memcpy(outdata, data, dataSize);
3556 smb_SendPacket(vcp, outp);
3562 /* SMB_COM_READ_RAW */
3563 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3566 long count, minCount, finalCount;
3570 smb_t *smbp = (smb_t*) inp;
3572 cm_user_t *userp = NULL;
3575 char *rawBuf = NULL;
3580 fd = smb_GetSMBParm(inp, 0);
3581 count = smb_GetSMBParm(inp, 3);
3582 minCount = smb_GetSMBParm(inp, 4);
3583 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3585 if (*inp->wctp == 10) {
3586 /* we were sent a request with 64-bit file offsets */
3587 #ifdef AFS_LARGEFILES
3588 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3590 if (LargeIntegerLessThanZero(offset)) {
3591 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3595 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3596 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3599 offset.HighPart = 0;
3603 /* we were sent a request with 32-bit file offsets */
3604 offset.HighPart = 0;
3607 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3608 fd, offset.HighPart, offset.LowPart, count);
3610 fidp = smb_FindFID(vcp, fd, 0);
3612 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3616 lock_ObtainMutex(&fidp->mx);
3618 lock_ReleaseMutex(&fidp->mx);
3619 smb_ReleaseFID(fidp);
3620 return CM_ERROR_BADFD;
3623 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3624 lock_ReleaseMutex(&fidp->mx);
3625 smb_CloseFID(vcp, fidp, NULL, 0);
3626 code = CM_ERROR_NOSUCHFILE;
3632 LARGE_INTEGER LOffset, LLength;
3635 key = cm_GenerateKey(vcp->vcID, pid, fd);
3637 LOffset.HighPart = offset.HighPart;
3638 LOffset.LowPart = offset.LowPart;
3639 LLength.HighPart = 0;
3640 LLength.LowPart = count;
3642 lock_ObtainWrite(&fidp->scp->rw);
3643 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3644 lock_ReleaseWrite(&fidp->scp->rw);
3647 lock_ReleaseMutex(&fidp->mx);
3651 lock_ObtainMutex(&smb_RawBufLock);
3653 /* Get a raw buf, from head of list */
3654 rawBuf = smb_RawBufs;
3655 smb_RawBufs = *(char **)smb_RawBufs;
3657 lock_ReleaseMutex(&smb_RawBufLock);
3659 lock_ReleaseMutex(&fidp->mx);
3663 if (fidp->flags & SMB_FID_IOCTL)
3665 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3667 /* Give back raw buffer */
3668 lock_ObtainMutex(&smb_RawBufLock);
3669 *((char **) rawBuf) = smb_RawBufs;
3671 smb_RawBufs = rawBuf;
3672 lock_ReleaseMutex(&smb_RawBufLock);
3675 lock_ReleaseMutex(&fidp->mx);
3676 smb_ReleaseFID(fidp);
3679 lock_ReleaseMutex(&fidp->mx);
3681 userp = smb_GetUserFromVCP(vcp, inp);
3683 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3689 cm_ReleaseUser(userp);
3692 smb_ReleaseFID(fidp);
3696 memset(ncbp, 0, sizeof(NCB));
3698 ncbp->ncb_length = (unsigned short) finalCount;
3699 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3700 ncbp->ncb_lana_num = vcp->lana;
3701 ncbp->ncb_command = NCBSEND;
3702 ncbp->ncb_buffer = rawBuf;
3704 code = Netbios(ncbp);
3706 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3709 /* Give back raw buffer */
3710 lock_ObtainMutex(&smb_RawBufLock);
3711 *((char **) rawBuf) = smb_RawBufs;
3713 smb_RawBufs = rawBuf;
3714 lock_ReleaseMutex(&smb_RawBufLock);
3720 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3722 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3727 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3729 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3734 /* SMB_COM_NEGOTIATE */
3735 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3742 int VistaProtoIndex;
3743 int protoIndex; /* index we're using */
3748 char protocol_array[10][1024]; /* protocol signature of the client */
3749 int caps; /* capabilities */
3752 TIME_ZONE_INFORMATION tzi;
3754 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3757 namep = smb_GetSMBData(inp, &dbytes);
3760 coreProtoIndex = -1; /* not found */
3763 VistaProtoIndex = -1;
3764 while(namex < dbytes) {
3765 osi_Log1(smb_logp, "Protocol %s",
3766 osi_LogSaveString(smb_logp, namep+1));
3767 strcpy(protocol_array[tcounter], namep+1);
3769 /* namep points at the first protocol, or really, a 0x02
3770 * byte preceding the null-terminated ASCII name.
3772 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3773 coreProtoIndex = tcounter;
3775 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3776 v3ProtoIndex = tcounter;
3778 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3779 NTProtoIndex = tcounter;
3781 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3782 VistaProtoIndex = tcounter;
3785 /* compute size of protocol entry */
3786 entryLength = (int)strlen(namep+1);
3787 entryLength += 2; /* 0x02 bytes and null termination */
3789 /* advance over this protocol entry */
3790 namex += entryLength;
3791 namep += entryLength;
3792 tcounter++; /* which proto entry we're looking at */
3795 lock_ObtainMutex(&vcp->mx);
3797 if (VistaProtoIndex != -1) {
3798 protoIndex = VistaProtoIndex;
3799 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3802 if (NTProtoIndex != -1) {
3803 protoIndex = NTProtoIndex;
3804 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3806 else if (v3ProtoIndex != -1) {
3807 protoIndex = v3ProtoIndex;
3808 vcp->flags |= SMB_VCFLAG_USEV3;
3810 else if (coreProtoIndex != -1) {
3811 protoIndex = coreProtoIndex;
3812 vcp->flags |= SMB_VCFLAG_USECORE;
3814 else protoIndex = -1;
3815 lock_ReleaseMutex(&vcp->mx);
3817 if (protoIndex == -1)
3818 return CM_ERROR_INVAL;
3819 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3820 smb_SetSMBParm(outp, 0, protoIndex);
3821 if (smb_authType != SMB_AUTH_NONE) {
3822 smb_SetSMBParmByte(outp, 1,
3823 NEGOTIATE_SECURITY_USER_LEVEL |
3824 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3826 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3828 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3829 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3830 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3831 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3832 /* The session key is not a well documented field however most clients
3833 * will echo back the session key to the server. Currently we are using
3834 * the same value for all sessions. We should generate a random value
3835 * and store it into the vcp
3837 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3838 smb_SetSMBParm(outp, 8, 1);
3840 * Tried changing the capabilities to support for W2K - defect 117695
3841 * Maybe something else needs to be changed here?
3845 smb_SetSMBParmLong(outp, 9, 0x43fd);
3847 smb_SetSMBParmLong(outp, 9, 0x251);
3850 * 32-bit error codes *
3856 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3858 NTNEGOTIATE_CAPABILITY_DFS |
3860 #ifdef AFS_LARGEFILES
3861 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3863 NTNEGOTIATE_CAPABILITY_NTFIND |
3864 NTNEGOTIATE_CAPABILITY_RAWMODE |
3865 NTNEGOTIATE_CAPABILITY_NTSMB;
3867 if ( smb_authType == SMB_AUTH_EXTENDED )
3868 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3871 if ( smb_UseUnicode ) {
3872 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3876 smb_SetSMBParmLong(outp, 9, caps);
3878 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3879 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3880 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3882 GetTimeZoneInformation(&tzi);
3883 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3885 if (smb_authType == SMB_AUTH_NTLM) {
3886 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3887 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3888 /* paste in encryption key */
3889 datap = smb_GetSMBData(outp, NULL);
3890 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3891 /* and the faux domain name */
3892 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3893 datap + MSV1_0_CHALLENGE_LENGTH,
3894 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3895 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3899 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3901 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3903 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3905 datap = smb_GetSMBData(outp, NULL);
3906 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3909 datap += sizeof(smb_ServerGUID);
3910 memcpy(datap, secBlob, secBlobLength);
3914 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3915 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3918 else if (v3ProtoIndex != -1) {
3919 smb_SetSMBParm(outp, 0, protoIndex);
3921 /* NOTE: Extended authentication cannot be negotiated with v3
3922 * therefore we fail over to NTLM
3924 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3925 smb_SetSMBParm(outp, 1,
3926 NEGOTIATE_SECURITY_USER_LEVEL |
3927 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3929 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3931 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3932 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3933 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3934 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3935 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3936 smb_SetSMBParm(outp, 7, 1);
3938 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3939 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3940 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3942 GetTimeZoneInformation(&tzi);
3943 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3945 /* NOTE: Extended authentication cannot be negotiated with v3
3946 * therefore we fail over to NTLM
3948 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3949 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3950 smb_SetSMBParm(outp, 12, 0); /* resvd */
3951 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3952 datap = smb_GetSMBData(outp, NULL);
3953 /* paste in a new encryption key */
3954 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3955 /* and the faux domain name */
3956 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3957 datap + MSV1_0_CHALLENGE_LENGTH,
3958 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3960 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3961 smb_SetSMBParm(outp, 12, 0); /* resvd */
3962 smb_SetSMBDataLength(outp, 0);
3965 else if (coreProtoIndex != -1) { /* not really supported anymore */
3966 smb_SetSMBParm(outp, 0, protoIndex);
3967 smb_SetSMBDataLength(outp, 0);
3972 void smb_CheckVCs(void)
3974 smb_vc_t * vcp, *nextp;
3975 smb_packet_t * outp = smb_GetPacket();
3978 lock_ObtainWrite(&smb_rctLock);
3979 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3981 if (vcp->magic != SMB_VC_MAGIC)
3982 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3983 __FILE__, __LINE__);
3985 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3987 smb_HoldVCNoLock(vcp);
3990 * obtain a reference to 'nextp' now because we drop the
3991 * smb_rctLock later and the list contents could change
3992 * or 'vcp' could be destroyed when released.
3996 smb_HoldVCNoLock(nextp);
3998 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3999 smb_ReleaseVCNoLock(vcp);
4003 smb_FormatResponsePacket(vcp, NULL, outp);
4004 smbp = (smb_t *)outp;
4005 outp->inCom = smbp->com = 0x2b /* Echo */;
4013 smb_SetSMBParm(outp, 0, 0);
4014 smb_SetSMBDataLength(outp, 0);
4015 lock_ReleaseWrite(&smb_rctLock);
4017 smb_SendPacket(vcp, outp);
4019 lock_ObtainWrite(&smb_rctLock);
4020 smb_ReleaseVCNoLock(vcp);
4022 lock_ReleaseWrite(&smb_rctLock);
4023 smb_FreePacket(outp);
4026 void smb_Daemon(void *parmp)
4028 afs_uint32 count = 0;
4029 smb_username_t **unpp;
4032 while(smbShutdownFlag == 0) {
4036 if (smbShutdownFlag == 1)
4039 if ((count % 72) == 0) { /* every five minutes */
4041 time_t old_localZero = smb_localZero;
4043 /* Initialize smb_localZero */
4044 myTime.tm_isdst = -1; /* compute whether on DST or not */
4045 myTime.tm_year = 70;
4051 smb_localZero = mktime(&myTime);
4053 #ifdef AFS_FREELANCE
4054 if ( smb_localZero != old_localZero )
4055 cm_noteLocalMountPointChange();
4061 /* GC smb_username_t objects that will no longer be used */
4063 lock_ObtainWrite(&smb_rctLock);
4064 for ( unpp=&usernamesp; *unpp; ) {
4066 smb_username_t *unp;
4068 lock_ObtainMutex(&(*unpp)->mx);
4069 if ( (*unpp)->refCount > 0 ||
4070 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4071 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4073 else if (!smb_LogoffTokenTransfer ||
4074 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4076 lock_ReleaseMutex(&(*unpp)->mx);
4084 lock_FinalizeMutex(&unp->mx);
4090 cm_ReleaseUser(userp);
4092 unpp = &(*unpp)->nextp;
4095 lock_ReleaseWrite(&smb_rctLock);
4097 /* XXX GC dir search entries */
4101 void smb_WaitingLocksDaemon()
4103 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4104 smb_waitingLock_t *wl, *wlNext;
4107 smb_packet_t *inp, *outp;
4111 while (smbShutdownFlag == 0) {
4112 lock_ObtainWrite(&smb_globalLock);
4113 nwlRequest = smb_allWaitingLocks;
4114 if (nwlRequest == NULL) {
4115 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4120 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4127 lock_ObtainWrite(&smb_globalLock);
4129 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4131 wlRequest = nwlRequest;
4132 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4133 lock_ReleaseWrite(&smb_globalLock);
4137 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4138 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4141 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4142 code = CM_ERROR_LOCK_NOT_GRANTED;
4146 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4148 /* wl->state is either _DONE or _WAITING. _ERROR
4149 would no longer be on the queue. */
4150 code = cm_RetryLock( wl->lockp,
4151 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4154 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4155 } else if (code != CM_ERROR_WOULDBLOCK) {
4156 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4161 if (code == CM_ERROR_WOULDBLOCK) {
4164 if (wlRequest->msTimeout != 0xffffffff
4165 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4177 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4180 scp = wlRequest->scp;
4181 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4185 lock_ObtainWrite(&scp->rw);
4187 for (wl = wlRequest->locks; wl; wl = wlNext) {
4188 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4190 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4191 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4192 wl->LLength, wl->key, 0, NULL, &req);
4194 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4199 lock_ReleaseWrite(&scp->rw);
4203 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4206 for (wl = wlRequest->locks; wl; wl = wlNext) {
4207 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4208 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4213 vcp = wlRequest->vcp;
4214 inp = wlRequest->inp;
4215 outp = wlRequest->outp;
4216 ncbp = smb_GetNCB();
4217 ncbp->ncb_length = inp->ncb_length;
4218 inp->spacep = cm_GetSpace();
4220 /* Remove waitingLock from list */
4221 lock_ObtainWrite(&smb_globalLock);
4222 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4224 lock_ReleaseWrite(&smb_globalLock);
4226 /* Resume packet processing */
4228 smb_SetSMBDataLength(outp, 0);
4229 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4230 outp->resumeCode = code;
4232 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4235 cm_FreeSpace(inp->spacep);
4236 smb_FreePacket(inp);
4237 smb_FreePacket(outp);
4239 cm_ReleaseSCache(wlRequest->scp);
4242 } while (nwlRequest && smbShutdownFlag == 0);
4247 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4249 osi_Log0(smb_logp, "SMB receive get disk attributes");
4251 smb_SetSMBParm(outp, 0, 32000);
4252 smb_SetSMBParm(outp, 1, 64);
4253 smb_SetSMBParm(outp, 2, 1024);
4254 smb_SetSMBParm(outp, 3, 30000);
4255 smb_SetSMBParm(outp, 4, 0);
4256 smb_SetSMBDataLength(outp, 0);
4260 /* SMB_COM_TREE_CONNECT */
4261 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4265 unsigned short newTid;
4266 clientchar_t shareName[AFSPATHMAX];
4267 clientchar_t *sharePath;
4270 clientchar_t *pathp;
4273 osi_Log0(smb_logp, "SMB receive tree connect");
4275 /* parse input parameters */
4278 tbp = smb_GetSMBData(inp, NULL);
4279 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4281 return CM_ERROR_BADSMB;
4283 tp = cm_ClientStrRChr(pathp, '\\');
4285 return CM_ERROR_BADSMB;
4286 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4288 lock_ObtainMutex(&vcp->mx);
4289 newTid = vcp->tidCounter++;
4290 lock_ReleaseMutex(&vcp->mx);
4292 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4293 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4295 return CM_ERROR_BADSMB;
4296 userp = smb_GetUserFromUID(uidp);
4297 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4298 smb_ReleaseUID(uidp);
4300 smb_ReleaseTID(tidp, FALSE);
4301 return CM_ERROR_BADSHARENAME;
4303 lock_ObtainMutex(&tidp->mx);
4304 tidp->userp = userp;
4305 tidp->pathname = sharePath;
4306 lock_ReleaseMutex(&tidp->mx);
4307 smb_ReleaseTID(tidp, FALSE);
4309 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4310 smb_SetSMBParm(rsp, 1, newTid);
4311 smb_SetSMBDataLength(rsp, 0);
4313 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4317 /* set maskp to the mask part of the incoming path.
4318 * Mask is 11 bytes long (8.3 with the dot elided).
4319 * Returns true if succeeds with a valid name, otherwise it does
4320 * its best, but returns false.
4322 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4330 /* starts off valid */
4333 /* mask starts out all blanks */
4334 memset(maskp, ' ', 11);
4337 /* find last backslash, or use whole thing if there is none */
4338 tp = cm_ClientStrRChr(pathp, '\\');
4342 tp++; /* skip slash */
4346 /* names starting with a dot are illegal */
4354 if (tc == '.' || tc == '"')
4362 /* if we get here, tp point after the dot */
4363 up = maskp+8; /* ext goes here */
4370 if (tc == '.' || tc == '"')
4373 /* copy extension if not too long */
4383 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4385 clientchar_t umask[11];
4393 /* XXX redo this, calling cm_MatchMask with a converted mask */
4395 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4399 /* otherwise, we have a valid 8.3 name; see if we have a match,
4400 * treating '?' as a wildcard in maskp (but not in the file name).
4402 tp1 = umask; /* real name, in mask format */
4403 tp2 = maskp; /* mask, in mask format */
4404 for(i=0; i<11; i++) {
4405 tc1 = *tp1++; /* clientchar_t from real name */
4406 tc2 = *tp2++; /* clientchar_t from mask */
4407 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4408 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4411 if (tc2 == '?' && tc1 != ' ')
4418 /* we got a match */
4422 clientchar_t *smb_FindMask(clientchar_t *pathp)
4426 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4429 return tp+1; /* skip the slash */
4431 return pathp; /* no slash, return the entire path */
4434 /* SMB_COM_SEARCH for a volume label
4436 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4437 dispatch function.) */
4438 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4440 clientchar_t *pathp;
4442 clientchar_t mask[12];
4443 unsigned char *statBlockp;
4444 unsigned char initStatBlock[21];
4447 osi_Log0(smb_logp, "SMB receive search volume");
4449 /* pull pathname and stat block out of request */
4450 tp = smb_GetSMBData(inp, NULL);
4451 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4452 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4454 return CM_ERROR_BADSMB;
4455 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4456 osi_assertx(statBlockp != NULL, "null statBlock");
4458 statBlockp = initStatBlock;
4462 /* for returning to caller */
4463 smb_Get8Dot3MaskFromPath(mask, pathp);
4465 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4466 tp = smb_GetSMBData(outp, NULL);
4468 *tp++ = 43; /* bytes in a dir entry */
4469 *tp++ = 0; /* high byte in counter */
4471 /* now marshall the dir entry, starting with the search status */
4472 *tp++ = statBlockp[0]; /* Reserved */
4473 memcpy(tp, mask, 11); tp += 11; /* FileName */
4475 /* now pass back server use info, with 1st byte non-zero */
4477 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4479 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4481 *tp++ = 0x8; /* attribute: volume */
4491 /* 4 byte file size */
4497 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4500 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4501 memset(tp, ' ', 13);
4504 /* set the length of the data part of the packet to 43 + 3, for the dir
4505 * entry plus the 5 and the length fields.
4507 smb_SetSMBDataLength(outp, 46);
4512 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4513 clientchar_t * tidPathp, clientchar_t * relPathp,
4514 cm_user_t *userp, cm_req_t *reqp)
4522 smb_dirListPatch_t *patchp;
4523 smb_dirListPatch_t *npatchp;
4524 clientchar_t path[AFSPATHMAX];
4526 afs_int32 mustFake = 0;
4528 code = cm_FindACLCache(dscp, userp, &rights);
4530 lock_ObtainWrite(&dscp->rw);
4531 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4532 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4533 lock_ReleaseWrite(&dscp->rw);
4534 if (code == CM_ERROR_NOACCESS) {
4542 if (!mustFake) { /* Bulk Stat */
4544 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4546 memset(bsp, 0, sizeof(cm_bulkStat_t));
4548 for (patchp = *dirPatchespp, count=0;
4550 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4551 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4555 if (lock_TryWrite(&tscp->rw)) {
4556 /* we have an entry that we can look at */
4557 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4558 /* we have a callback on it. Don't bother
4559 * fetching this stat entry, since we're happy
4560 * with the info we have.
4562 lock_ReleaseWrite(&tscp->rw);
4563 cm_ReleaseSCache(tscp);
4566 lock_ReleaseWrite(&tscp->rw);
4568 cm_ReleaseSCache(tscp);
4572 bsp->fids[i].Volume = patchp->fid.volume;
4573 bsp->fids[i].Vnode = patchp->fid.vnode;
4574 bsp->fids[i].Unique = patchp->fid.unique;
4576 if (bsp->counter == AFSCBMAX) {
4577 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4578 memset(bsp, 0, sizeof(cm_bulkStat_t));
4582 if (bsp->counter > 0)
4583 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4588 for (patchp = *dirPatchespp; patchp; patchp =
4589 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4591 dptr = patchp->dptr;
4593 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4594 relPathp ? relPathp : _C(""), patchp->dep->name);
4595 reqp->relPathp = path;
4596 reqp->tidPathp = tidPathp;
4598 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4599 reqp->relPathp = reqp->tidPathp = NULL;
4602 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4603 *dptr++ = SMB_ATTR_HIDDEN;
4606 lock_ObtainWrite(&scp->rw);
4607 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4608 lock_ReleaseWrite(&scp->rw);
4610 /* set the attribute */
4611 switch (scp->fileType) {
4612 case CM_SCACHETYPE_DIRECTORY:
4613 case CM_SCACHETYPE_MOUNTPOINT:
4614 case CM_SCACHETYPE_INVALID:
4615 attr = SMB_ATTR_DIRECTORY;
4617 case CM_SCACHETYPE_SYMLINK:
4618 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4619 attr = SMB_ATTR_DIRECTORY;
4621 attr = SMB_ATTR_NORMAL;
4624 /* if we get here we either have a normal file
4625 * or we have a file for which we have never
4626 * received status info. In this case, we can
4627 * check the even/odd value of the entry's vnode.
4628 * odd means it is to be treated as a directory
4629 * and even means it is to be treated as a file.
4631 if (mustFake && (scp->fid.vnode & 0x1))
4632 attr = SMB_ATTR_DIRECTORY;
4634 attr = SMB_ATTR_NORMAL;
4638 /* 1969-12-31 23:59:58 +00*/
4639 dosTime = 0xEBBFBF7D;
4642 shortTemp = (unsigned short) (dosTime & 0xffff);
4643 *((u_short *)dptr) = shortTemp;
4646 /* and copy out date */
4647 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4648 *((u_short *)dptr) = shortTemp;
4651 /* copy out file length */
4652 *((u_long *)dptr) = 0;
4655 lock_ConvertWToR(&scp->rw);
4656 attr = smb_Attributes(scp);
4657 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4658 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4659 attr |= SMB_ATTR_HIDDEN;
4663 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4666 shortTemp = (unsigned short) (dosTime & 0xffff);
4667 *((u_short *)dptr) = shortTemp;
4670 /* and copy out date */
4671 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4672 *((u_short *)dptr) = shortTemp;
4675 /* copy out file length */
4676 *((u_long *)dptr) = scp->length.LowPart;
4678 lock_ReleaseRead(&scp->rw);
4680 cm_ReleaseSCache(scp);
4683 /* now free the patches */
4684 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4685 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4689 /* and mark the list as empty */
4690 *dirPatchespp = NULL;
4696 /* SMB_COM_SEARCH */
4697 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4703 clientchar_t *pathp;
4704 cm_dirEntry_t *dep = 0;
4706 smb_dirListPatch_t *dirListPatchesp;
4707 smb_dirListPatch_t *curPatchp;
4711 osi_hyper_t dirLength;
4712 osi_hyper_t bufferOffset;
4713 osi_hyper_t curOffset;
4715 unsigned char *inCookiep;
4716 smb_dirSearch_t *dsp;
4720 unsigned long clientCookie;
4721 cm_pageHeader_t *pageHeaderp;
4722 cm_user_t *userp = NULL;
4724 clientchar_t mask[12];
4726 long nextEntryCookie;
4727 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4728 char resByte; /* reserved byte from the cookie */
4729 char *op; /* output data ptr */
4730 char *origOp; /* original value of op */
4731 cm_space_t *spacep; /* for pathname buffer */
4735 clientchar_t *tidPathp = 0;
4742 maxCount = smb_GetSMBParm(inp, 0);
4744 dirListPatchesp = NULL;
4746 caseFold = CM_FLAG_CASEFOLD;
4748 tp = smb_GetSMBData(inp, NULL);
4749 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4750 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4752 return CM_ERROR_BADSMB;
4754 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4756 return CM_ERROR_BADSMB;
4758 /* We can handle long names */
4759 if (vcp->flags & SMB_VCFLAG_USENT)
4760 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4762 /* make sure we got a whole search status */
4763 if (dataLength < 21) {
4764 nextCookie = 0; /* start at the beginning of the dir */
4767 attribute = smb_GetSMBParm(inp, 1);
4769 /* handle volume info in another function */
4770 if (attribute & 0x8)
4771 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4773 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4774 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4776 if (*pathp == 0) { /* null pathp, treat as root dir */
4777 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4778 return CM_ERROR_NOFILES;
4782 dsp = smb_NewDirSearch(0);
4783 dsp->attribute = attribute;
4784 smb_Get8Dot3MaskFromPath(mask, pathp);
4785 memcpy(dsp->mask, mask, 12);
4787 /* track if this is likely to match a lot of entries */
4788 if (smb_Is8Dot3StarMask(mask))
4793 /* pull the next cookie value out of the search status block */
4794 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4795 + (inCookiep[16]<<24);
4796 dsp = smb_FindDirSearch(inCookiep[12]);
4798 /* can't find dir search status; fatal error */
4799 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4800 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4801 return CM_ERROR_BADFD;
4803 attribute = dsp->attribute;
4804 resByte = inCookiep[0];
4806 /* copy out client cookie, in host byte order. Don't bother
4807 * interpreting it, since we're just passing it through, anyway.
4809 memcpy(&clientCookie, &inCookiep[17], 4);
4811 memcpy(mask, dsp->mask, 12);
4813 /* assume we're doing a star match if it has continued for more
4819 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4820 nextCookie, dsp->cookie, attribute);
4822 userp = smb_GetUserFromVCP(vcp, inp);
4824 /* try to get the vnode for the path name next */
4825 lock_ObtainMutex(&dsp->mx);
4828 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4832 spacep = inp->spacep;
4833 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4834 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4836 lock_ReleaseMutex(&dsp->mx);
4837 cm_ReleaseUser(userp);
4838 smb_DeleteDirSearch(dsp);
4839 smb_ReleaseDirSearch(dsp);
4840 return CM_ERROR_NOFILES;
4842 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4843 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4845 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4846 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4849 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4852 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4853 cm_ReleaseSCache(scp);
4854 lock_ReleaseMutex(&dsp->mx);
4855 cm_ReleaseUser(userp);
4856 smb_DeleteDirSearch(dsp);
4857 smb_ReleaseDirSearch(dsp);
4858 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4859 return CM_ERROR_PATH_NOT_COVERED;
4861 return CM_ERROR_NOSUCHPATH;
4863 #endif /* DFS_SUPPORT */
4866 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4867 /* we need one hold for the entry we just stored into,
4868 * and one for our own processing. When we're done with this
4869 * function, we'll drop the one for our own processing.
4870 * We held it once from the namei call, and so we do another hold
4874 lock_ObtainWrite(&scp->rw);
4875 dsp->flags |= SMB_DIRSEARCH_BULKST;
4876 lock_ReleaseWrite(&scp->rw);
4879 lock_ReleaseMutex(&dsp->mx);
4881 cm_ReleaseUser(userp);
4882 smb_DeleteDirSearch(dsp);
4883 smb_ReleaseDirSearch(dsp);
4887 /* reserves space for parameter; we'll adjust it again later to the
4888 * real count of the # of entries we returned once we've actually
4889 * assembled the directory listing.
4891 smb_SetSMBParm(outp, 0, 0);
4893 /* get the directory size */
4894 lock_ObtainWrite(&scp->rw);
4895 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4896 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4898 lock_ReleaseWrite(&scp->rw);
4899 cm_ReleaseSCache(scp);
4900 cm_ReleaseUser(userp);
4901 smb_DeleteDirSearch(dsp);
4902 smb_ReleaseDirSearch(dsp);
4906 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4908 dirLength = scp->length;
4910 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4911 curOffset.HighPart = 0;
4912 curOffset.LowPart = nextCookie;
4913 origOp = op = smb_GetSMBData(outp, NULL);
4914 /* and write out the basic header */
4915 *op++ = 5; /* variable block */
4916 op += 2; /* skip vbl block length; we'll fill it in later */
4920 clientchar_t *actualName = NULL;
4921 int free_actualName = 0;
4922 clientchar_t shortName[13];
4923 clientchar_t *shortNameEnd;
4925 /* make sure that curOffset.LowPart doesn't point to the first
4926 * 32 bytes in the 2nd through last dir page, and that it doesn't
4927 * point at the first 13 32-byte chunks in the first dir page,
4928 * since those are dir and page headers, and don't contain useful
4931 temp = curOffset.LowPart & (2048-1);
4932 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4933 /* we're in the first page */
4934 if (temp < 13*32) temp = 13*32;
4937 /* we're in a later dir page */
4938 if (temp < 32) temp = 32;
4941 /* make sure the low order 5 bits are zero */
4944 /* now put temp bits back ito curOffset.LowPart */
4945 curOffset.LowPart &= ~(2048-1);
4946 curOffset.LowPart |= temp;
4948 /* check if we've returned all the names that will fit in the
4951 if (returnedNames >= maxCount) {
4952 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4953 returnedNames, maxCount);
4957 /* check if we've passed the dir's EOF */
4958 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4960 /* see if we can use the bufferp we have now; compute in which page
4961 * the current offset would be, and check whether that's the offset
4962 * of the buffer we have. If not, get the buffer.
4964 thyper.HighPart = curOffset.HighPart;
4965 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4966 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4969 buf_Release(bufferp);
4972 lock_ReleaseWrite(&scp->rw);
4973 code = buf_Get(scp, &thyper, &req, &bufferp);
4974 lock_ObtainMutex(&dsp->mx);
4976 /* now, if we're doing a star match, do bulk fetching of all of
4977 * the status info for files in the dir.
4980 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4982 lock_ObtainWrite(&scp->rw);
4983 lock_ReleaseMutex(&dsp->mx);
4985 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4989 bufferOffset = thyper;
4991 /* now get the data in the cache */
4993 code = cm_SyncOp(scp, bufferp, userp, &req,
4995 CM_SCACHESYNC_NEEDCALLBACK |
4996 CM_SCACHESYNC_READ);
4998 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5002 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5004 if (cm_HaveBuffer(scp, bufferp, 0)) {
5005 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5009 /* otherwise, load the buffer and try again */
5010 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5012 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5013 scp, bufferp, code);
5018 buf_Release(bufferp);
5022 } /* if (wrong buffer) ... */
5024 /* now we have the buffer containing the entry we're interested in; copy
5025 * it out if it represents a non-deleted entry.
5027 entryInDir = curOffset.LowPart & (2048-1);
5028 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5030 /* page header will help tell us which entries are free. Page header
5031 * can change more often than once per buffer, since AFS 3 dir page size
5032 * may be less than (but not more than a buffer package buffer.
5034 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5035 temp &= ~(2048 - 1); /* turn off intra-page bits */
5036 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5038 /* now determine which entry we're looking at in the page. If it is
5039 * free (there's a free bitmap at the start of the dir), we should
5040 * skip these 32 bytes.
5042 slotInPage = (entryInDir & 0x7e0) >> 5;
5043 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5044 /* this entry is free */
5045 numDirChunks = 1; /* only skip this guy */
5049 tp = bufferp->datap + entryInBuffer;
5050 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5052 /* while we're here, compute the next entry's location, too,
5053 * since we'll need it when writing out the cookie into the dir
5056 * XXXX Probably should do more sanity checking.
5058 numDirChunks = cm_NameEntries(dep->name, NULL);
5060 /* compute the offset of the cookie representing the next entry */
5061 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5063 /* Compute 8.3 name if necessary */
5064 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5065 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5068 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5069 actualName = shortName;
5070 free_actualName = 0;
5072 free_actualName = 1;
5075 if (actualName == NULL) {
5076 /* Couldn't convert the name for some reason */
5077 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5078 osi_LogSaveString(smb_logp, dep->name));
5082 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5083 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5084 osi_LogSaveClientString(smb_logp, actualName));
5086 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5087 /* this is one of the entries to use: it is not deleted
5088 * and it matches the star pattern we're looking for.
5091 /* Eliminate entries that don't match requested
5094 /* no hidden files */
5095 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5096 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5100 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5102 /* We have already done the cm_TryBulkStat above */
5103 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5104 fileType = cm_FindFileType(&fid);
5105 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5106 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5108 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5109 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5110 fileType == CM_SCACHETYPE_DFSLINK ||
5111 fileType == CM_SCACHETYPE_INVALID)
5112 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5117 memcpy(op, mask, 11); op += 11;
5118 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5119 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5120 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5121 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5122 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5123 memcpy(op, &clientCookie, 4); op += 4;
5125 /* now we emit the attribute. This is sort of tricky,
5126 * since we need to really stat the file to find out
5127 * what type of entry we've got. Right now, we're
5128 * copying out data from a buffer, while holding the
5129 * scp locked, so it isn't really convenient to stat
5130 * something now. We'll put in a place holder now,
5131 * and make a second pass before returning this to get
5132 * the real attributes. So, we just skip the data for
5133 * now, and adjust it later. We allocate a patch
5134 * record to make it easy to find this point later.
5135 * The replay will happen at a time when it is safe to
5136 * unlock the directory.
5138 curPatchp = malloc(sizeof(*curPatchp));
5139 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5140 curPatchp->dptr = op;
5141 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5143 /* do hidden attribute here since name won't be around when applying
5147 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5148 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5150 curPatchp->flags = 0;
5152 op += 9; /* skip attr, time, date and size */
5154 /* zero out name area. The spec says to pad with
5155 * spaces, but Samba doesn't, and neither do we.
5159 /* finally, we get to copy out the name; we know that
5160 * it fits in 8.3 or the pattern wouldn't match, but it
5161 * never hurts to be sure.
5163 cm_ClientStringToUtf8(actualName, -1, op, 13);
5164 if (smb_StoreAnsiFilenames)
5166 /* This is a UCHAR field, which is ASCII even if Unicode
5169 /* Uppercase if requested by client */
5170 if (!KNOWS_LONG_NAMES(inp))
5175 /* now, adjust the # of entries copied */
5177 } /* if we're including this name */
5180 if (free_actualName && actualName) {
5185 /* and adjust curOffset to be where the new cookie is */
5186 thyper.HighPart = 0;
5187 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5188 curOffset = LargeIntegerAdd(thyper, curOffset);
5189 } /* while copying data for dir listing */
5191 /* release the mutex */
5192 lock_ReleaseWrite(&scp->rw);
5194 buf_Release(bufferp);
5198 /* apply and free last set of patches; if not doing a star match, this
5199 * will be empty, but better safe (and freeing everything) than sorry.
5201 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5203 /* special return code for unsuccessful search */
5204 if (code == 0 && dataLength < 21 && returnedNames == 0)
5205 code = CM_ERROR_NOFILES;
5207 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5208 returnedNames, code);
5211 smb_DeleteDirSearch(dsp);
5212 smb_ReleaseDirSearch(dsp);
5213 cm_ReleaseSCache(scp);
5214 cm_ReleaseUser(userp);
5218 /* finalize the output buffer */
5219 smb_SetSMBParm(outp, 0, returnedNames);
5220 temp = (long) (op - origOp);
5221 smb_SetSMBDataLength(outp, temp);
5223 /* the data area is a variable block, which has a 5 (already there)
5224 * followed by the length of the # of data bytes. We now know this to
5225 * be "temp," although that includes the 3 bytes of vbl block header.
5226 * Deduct for them and fill in the length field.
5228 temp -= 3; /* deduct vbl block info */
5229 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5230 origOp[1] = (unsigned char)(temp & 0xff);
5231 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5232 if (returnedNames == 0)
5233 smb_DeleteDirSearch(dsp);
5234 smb_ReleaseDirSearch(dsp);
5235 cm_ReleaseSCache(scp);
5236 cm_ReleaseUser(userp);
5241 /* verify that this is a valid path to a directory. I don't know why they
5242 * don't use the get file attributes call.
5244 * SMB_COM_CHECK_DIRECTORY
5246 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5248 clientchar_t *pathp;
5250 cm_scache_t *rootScp;
5251 cm_scache_t *newScp;
5255 clientchar_t *tidPathp;
5261 pdata = smb_GetSMBData(inp, NULL);
5262 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5264 return CM_ERROR_BADSMB;
5265 osi_Log1(smb_logp, "SMB receive check path %S",
5266 osi_LogSaveClientString(smb_logp, pathp));
5268 rootScp = cm_data.rootSCachep;
5270 userp = smb_GetUserFromVCP(vcp, inp);
5272 caseFold = CM_FLAG_CASEFOLD;
5274 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5276 cm_ReleaseUser(userp);
5277 return CM_ERROR_NOSUCHPATH;
5279 code = cm_NameI(rootScp, pathp,
5280 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5281 userp, tidPathp, &req, &newScp);
5284 cm_ReleaseUser(userp);
5289 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5290 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5291 cm_ReleaseSCache(newScp);
5292 cm_ReleaseUser(userp);
5293 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5294 return CM_ERROR_PATH_NOT_COVERED;
5296 return CM_ERROR_NOSUCHPATH;
5298 #endif /* DFS_SUPPORT */
5300 /* now lock the vnode with a callback; returns with newScp locked */
5301 lock_ObtainWrite(&newScp->rw);
5302 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5303 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5305 if (code != CM_ERROR_NOACCESS) {
5306 lock_ReleaseWrite(&newScp->rw);
5307 cm_ReleaseSCache(newScp);
5308 cm_ReleaseUser(userp);
5312 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5315 attrs = smb_Attributes(newScp);
5317 if (!(attrs & SMB_ATTR_DIRECTORY))
5318 code = CM_ERROR_NOTDIR;
5320 lock_ReleaseWrite(&newScp->rw);
5322 cm_ReleaseSCache(newScp);
5323 cm_ReleaseUser(userp);
5327 /* SMB_COM_SET_INFORMATION */
5328 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5330 clientchar_t *pathp;
5332 cm_scache_t *rootScp;
5333 unsigned short attribute;
5335 cm_scache_t *newScp;
5339 clientchar_t *tidPathp;
5345 /* decode basic attributes we're passed */
5346 attribute = smb_GetSMBParm(inp, 0);
5347 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5349 datap = smb_GetSMBData(inp, NULL);
5350 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5352 return CM_ERROR_BADSMB;
5354 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5355 dosTime, attribute);
5357 rootScp = cm_data.rootSCachep;
5359 userp = smb_GetUserFromVCP(vcp, inp);
5361 caseFold = CM_FLAG_CASEFOLD;
5363 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5365 cm_ReleaseUser(userp);
5366 return CM_ERROR_NOSUCHFILE;
5368 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5369 tidPathp, &req, &newScp);
5372 cm_ReleaseUser(userp);
5377 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5378 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5379 cm_ReleaseSCache(newScp);
5380 cm_ReleaseUser(userp);
5381 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5382 return CM_ERROR_PATH_NOT_COVERED;
5384 return CM_ERROR_NOSUCHPATH;
5386 #endif /* DFS_SUPPORT */
5388 /* now lock the vnode with a callback; returns with newScp locked; we
5389 * need the current status to determine what the new status is, in some
5392 lock_ObtainWrite(&newScp->rw);
5393 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5394 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5396 lock_ReleaseWrite(&newScp->rw);
5397 cm_ReleaseSCache(newScp);
5398 cm_ReleaseUser(userp);
5402 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5404 /* Check for RO volume */
5405 if (newScp->flags & CM_SCACHEFLAG_RO) {
5406 lock_ReleaseWrite(&newScp->rw);
5407 cm_ReleaseSCache(newScp);
5408 cm_ReleaseUser(userp);
5409 return CM_ERROR_READONLY;
5412 /* prepare for setattr call */
5415 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5416 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5418 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5419 /* we're told to make a writable file read-only */
5420 attr.unixModeBits = newScp->unixModeBits & ~0222;
5421 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5423 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5424 /* we're told to make a read-only file writable */
5425 attr.unixModeBits = newScp->unixModeBits | 0222;
5426 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5428 lock_ReleaseWrite(&newScp->rw);
5430 /* now call setattr */
5432 code = cm_SetAttr(newScp, &attr, userp, &req);
5436 cm_ReleaseSCache(newScp);
5437 cm_ReleaseUser(userp);
5443 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5445 clientchar_t *pathp;
5447 cm_scache_t *rootScp;
5448 cm_scache_t *newScp, *dscp;
5453 clientchar_t *tidPathp;
5455 clientchar_t *lastComp;
5461 datap = smb_GetSMBData(inp, NULL);
5462 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5464 return CM_ERROR_BADSMB;
5466 if (*pathp == 0) /* null path */
5469 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5470 osi_LogSaveClientString(smb_logp, pathp));
5472 rootScp = cm_data.rootSCachep;
5474 userp = smb_GetUserFromVCP(vcp, inp);
5476 /* we shouldn't need this for V3 requests, but we seem to */
5477 caseFold = CM_FLAG_CASEFOLD;
5479 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5481 cm_ReleaseUser(userp);
5482 return CM_ERROR_NOSUCHFILE;
5486 * XXX Strange hack XXX
5488 * As of Patch 5 (16 July 97), we are having the following problem:
5489 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5490 * requests to look up "desktop.ini" in all the subdirectories.
5491 * This can cause zillions of timeouts looking up non-existent cells
5492 * and volumes, especially in the top-level directory.
5494 * We have not found any way to avoid this or work around it except
5495 * to explicitly ignore the requests for mount points that haven't
5496 * yet been evaluated and for directories that haven't yet been
5499 * We should modify this hack to provide a fake desktop.ini file
5500 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5502 spacep = inp->spacep;
5503 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5504 #ifndef SPECIAL_FOLDERS
5505 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5506 code = cm_NameI(rootScp, spacep->wdata,
5507 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5508 userp, tidPathp, &req, &dscp);
5511 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5512 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5514 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5515 return CM_ERROR_PATH_NOT_COVERED;
5517 return CM_ERROR_NOSUCHPATH;
5519 #endif /* DFS_SUPPORT */
5520 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5521 code = CM_ERROR_NOSUCHFILE;
5522 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5523 cm_buf_t *bp = buf_Find(dscp, &hzero);
5528 code = CM_ERROR_NOSUCHFILE;
5530 cm_ReleaseSCache(dscp);
5532 cm_ReleaseUser(userp);
5537 #endif /* SPECIAL_FOLDERS */
5539 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5540 tidPathp, &req, &newScp);
5542 cm_ReleaseUser(userp);
5547 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5548 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5549 cm_ReleaseSCache(newScp);
5550 cm_ReleaseUser(userp);
5551 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5552 return CM_ERROR_PATH_NOT_COVERED;
5554 return CM_ERROR_NOSUCHPATH;
5556 #endif /* DFS_SUPPORT */
5558 /* now lock the vnode with a callback; returns with newScp locked */
5559 lock_ObtainWrite(&newScp->rw);
5560 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5561 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5563 lock_ReleaseWrite(&newScp->rw);
5564 cm_ReleaseSCache(newScp);
5565 cm_ReleaseUser(userp);
5569 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5571 attrs = smb_Attributes(newScp);
5573 smb_SetSMBParm(outp, 0, attrs);
5575 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5576 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5577 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5578 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5579 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5580 smb_SetSMBParm(outp, 5, 0);
5581 smb_SetSMBParm(outp, 6, 0);
5582 smb_SetSMBParm(outp, 7, 0);
5583 smb_SetSMBParm(outp, 8, 0);
5584 smb_SetSMBParm(outp, 9, 0);
5585 smb_SetSMBDataLength(outp, 0);
5586 lock_ReleaseWrite(&newScp->rw);
5588 cm_ReleaseSCache(newScp);
5589 cm_ReleaseUser(userp);
5594 /* SMB_COM_TREE_DISCONNECT */
5595 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5599 osi_Log0(smb_logp, "SMB receive tree disconnect");
5601 /* find the tree and free it */
5602 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5604 lock_ObtainWrite(&smb_rctLock);
5606 smb_ReleaseTID(tidp, TRUE);
5607 lock_ReleaseWrite(&smb_rctLock);
5614 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5617 clientchar_t *pathp;
5618 clientchar_t *lastNamep;
5627 clientchar_t *tidPathp;
5633 datap = smb_GetSMBData(inp, NULL);
5634 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5636 return CM_ERROR_BADSMB;
5638 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5640 #ifdef DEBUG_VERBOSE
5644 hexpath = osi_HexifyString( pathp );
5645 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5650 share = smb_GetSMBParm(inp, 0);
5651 attribute = smb_GetSMBParm(inp, 1);
5653 spacep = inp->spacep;
5654 /* smb_StripLastComponent will strip "::$DATA" if present */
5655 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5657 if (!cm_IsValidClientString(pathp)) {
5659 clientchar_t * hexp;
5661 hexp = cm_GetRawCharsAlloc(pathp, -1);
5662 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5663 osi_LogSaveClientString(smb_logp, hexp));
5667 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5669 return CM_ERROR_BADNTFILENAME;
5672 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5673 /* special case magic file name for receiving IOCTL requests
5674 * (since IOCTL calls themselves aren't getting through).
5676 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5677 smb_SetupIoctlFid(fidp, spacep);
5678 smb_SetSMBParm(outp, 0, fidp->fid);
5679 smb_SetSMBParm(outp, 1, 0); /* attrs */
5680 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5681 smb_SetSMBParm(outp, 3, 0);
5682 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5683 smb_SetSMBParm(outp, 5, 0x7fff);
5684 /* pass the open mode back */
5685 smb_SetSMBParm(outp, 6, (share & 0xf));
5686 smb_SetSMBDataLength(outp, 0);
5687 smb_ReleaseFID(fidp);
5691 userp = smb_GetUserFromVCP(vcp, inp);
5693 caseFold = CM_FLAG_CASEFOLD;
5695 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5697 cm_ReleaseUser(userp);
5698 return CM_ERROR_NOSUCHPATH;
5700 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5701 tidPathp, &req, &scp);
5704 cm_ReleaseUser(userp);
5709 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5710 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5711 cm_ReleaseSCache(scp);
5712 cm_ReleaseUser(userp);
5713 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5714 return CM_ERROR_PATH_NOT_COVERED;
5716 return CM_ERROR_NOSUCHPATH;
5718 #endif /* DFS_SUPPORT */
5720 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5722 cm_ReleaseSCache(scp);
5723 cm_ReleaseUser(userp);
5727 /* don't need callback to check file type, since file types never
5728 * change, and namei and cm_Lookup all stat the object at least once on
5729 * a successful return.
5731 if (scp->fileType != CM_SCACHETYPE_FILE) {
5732 cm_ReleaseSCache(scp);
5733 cm_ReleaseUser(userp);
5734 return CM_ERROR_ISDIR;
5737 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5738 osi_assertx(fidp, "null smb_fid_t");
5740 lock_ObtainMutex(&fidp->mx);
5741 if ((share & 0xf) == 0)
5742 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5743 else if ((share & 0xf) == 1)
5744 fidp->flags |= SMB_FID_OPENWRITE;
5746 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5750 fidp->userp = userp;
5752 /* and a pointer to the vnode */
5754 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5755 lock_ObtainWrite(&scp->rw);
5756 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5758 smb_SetSMBParm(outp, 0, fidp->fid);
5759 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5760 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5761 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5762 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5763 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5764 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5765 /* pass the open mode back; XXXX add access checks */
5766 smb_SetSMBParm(outp, 6, (share & 0xf));
5767 smb_SetSMBDataLength(outp, 0);
5768 lock_ReleaseMutex(&fidp->mx);
5769 lock_ReleaseRead(&scp->rw);
5772 cm_Open(scp, 0, userp);
5774 /* send and free packet */
5775 smb_ReleaseFID(fidp);
5776 cm_ReleaseUser(userp);
5777 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5781 typedef struct smb_unlinkRock {
5786 clientchar_t *maskp; /* pointer to the star pattern */
5789 cm_dirEntryList_t * matches;
5792 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5795 smb_unlinkRock_t *rockp;
5798 normchar_t matchName[MAX_PATH];
5802 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5803 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5804 caseFold |= CM_FLAG_8DOT3;
5806 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5807 /* Can't convert name */
5808 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5809 osi_LogSaveString(smb_logp, dep->name));
5813 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5815 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5816 !cm_Is8Dot3(matchName)) {
5817 cm_Gen8Dot3Name(dep, matchName, NULL);
5818 /* 8.3 matches are always case insensitive */
5819 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5822 osi_Log1(smb_logp, "Found match %S",
5823 osi_LogSaveClientString(smb_logp, matchName));
5825 cm_DirEntryListAdd(dep->name, &rockp->matches);
5829 /* If we made a case sensitive exact match, we might as well quit now. */
5830 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5831 code = CM_ERROR_STOPNOW;
5840 /* SMB_COM_DELETE */
5841 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5845 clientchar_t *pathp;
5849 clientchar_t *lastNamep;
5850 smb_unlinkRock_t rock;
5854 clientchar_t *tidPathp;
5858 memset(&rock, 0, sizeof(rock));
5860 attribute = smb_GetSMBParm(inp, 0);
5862 tp = smb_GetSMBData(inp, NULL);
5863 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5865 return CM_ERROR_BADSMB;
5867 osi_Log1(smb_logp, "SMB receive unlink %S",
5868 osi_LogSaveClientString(smb_logp, pathp));
5870 spacep = inp->spacep;
5871 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5873 userp = smb_GetUserFromVCP(vcp, inp);
5875 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5877 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5879 cm_ReleaseUser(userp);
5880 return CM_ERROR_NOSUCHPATH;
5882 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5885 cm_ReleaseUser(userp);
5890 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5891 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5892 cm_ReleaseSCache(dscp);
5893 cm_ReleaseUser(userp);
5894 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5895 return CM_ERROR_PATH_NOT_COVERED;
5897 return CM_ERROR_NOSUCHPATH;
5899 #endif /* DFS_SUPPORT */
5901 /* otherwise, scp points to the parent directory. */
5908 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5910 code = CM_ERROR_NOSUCHFILE;
5913 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5916 thyper.HighPart = 0;
5921 rock.matches = NULL;
5923 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5924 * match. If that fails, we do a case insensitve match.
5926 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5927 !smb_IsStarMask(rock.maskp)) {
5928 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5931 thyper.HighPart = 0;
5932 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5937 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5939 if (code == CM_ERROR_STOPNOW)
5942 if (code == 0 && rock.matches) {
5943 cm_dirEntryList_t * entry;
5945 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5946 normchar_t normalizedName[MAX_PATH];
5948 /* Note: entry->name is a non-normalized name */
5950 osi_Log1(smb_logp, "Unlinking %s",
5951 osi_LogSaveString(smb_logp, entry->name));
5953 /* We assume this works because entry->name was
5954 successfully converted in smb_UnlinkProc() once. */
5955 cm_FsStringToNormString(entry->name, -1,
5956 normalizedName, lengthof(normalizedName));
5958 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5960 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5961 smb_NotifyChange(FILE_ACTION_REMOVED,
5962 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5963 dscp, normalizedName, NULL, TRUE);
5967 cm_DirEntryListFree(&rock.matches);
5971 cm_ReleaseUser(userp);
5974 cm_ReleaseSCache(dscp);
5979 if (code == 0 && !rock.any)
5980 code = CM_ERROR_NOSUCHFILE;
5984 typedef struct smb_renameRock {
5985 cm_scache_t *odscp; /* old dir */
5986 cm_scache_t *ndscp; /* new dir */
5987 cm_user_t *userp; /* user */
5988 cm_req_t *reqp; /* request struct */
5989 smb_vc_t *vcp; /* virtual circuit */
5990 normchar_t *maskp; /* pointer to star pattern of old file name */
5991 int flags; /* tilde, casefold, etc */
5992 clientchar_t *newNamep; /* ptr to the new file's name */
5993 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5994 clientchar_t clOldName[MAX_PATH]; /* client name */
5998 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6001 smb_renameRock_t *rockp;
6004 normchar_t matchName[MAX_PATH];
6006 rockp = (smb_renameRock_t *) vrockp;
6008 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6009 /* Can't convert string */
6010 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6011 osi_LogSaveString(smb_logp, dep->name));
6015 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6016 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6017 caseFold |= CM_FLAG_8DOT3;
6019 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6021 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6022 !cm_Is8Dot3(matchName)) {
6023 cm_Gen8Dot3Name(dep, matchName, NULL);
6024 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6029 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6030 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6032 code = CM_ERROR_STOPNOW;
6042 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6045 cm_space_t *spacep = NULL;
6046 smb_renameRock_t rock;
6047 cm_scache_t *oldDscp = NULL;
6048 cm_scache_t *newDscp = NULL;
6049 cm_scache_t *tmpscp= NULL;
6050 cm_scache_t *tmpscp2 = NULL;
6051 clientchar_t *oldLastNamep;
6052 clientchar_t *newLastNamep;
6056 clientchar_t *tidPathp;
6060 userp = smb_GetUserFromVCP(vcp, inp);
6061 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6063 cm_ReleaseUser(userp);
6064 return CM_ERROR_NOSUCHPATH;
6068 memset(&rock, 0, sizeof(rock));
6070 spacep = inp->spacep;
6071 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6073 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6074 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6075 userp, tidPathp, &req, &oldDscp);
6077 cm_ReleaseUser(userp);
6082 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6083 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6084 cm_ReleaseSCache(oldDscp);
6085 cm_ReleaseUser(userp);
6086 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6087 return CM_ERROR_PATH_NOT_COVERED;
6089 return CM_ERROR_NOSUCHPATH;
6091 #endif /* DFS_SUPPORT */
6093 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6094 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6095 userp, tidPathp, &req, &newDscp);
6098 cm_ReleaseSCache(oldDscp);
6099 cm_ReleaseUser(userp);
6104 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6105 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6106 cm_ReleaseSCache(oldDscp);
6107 cm_ReleaseSCache(newDscp);
6108 cm_ReleaseUser(userp);
6109 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6110 return CM_ERROR_PATH_NOT_COVERED;
6112 return CM_ERROR_NOSUCHPATH;
6114 #endif /* DFS_SUPPORT */
6117 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6118 * next, get the component names, and lower case them.
6121 /* handle the old name first */
6123 oldLastNamep = oldPathp;
6127 /* and handle the new name, too */
6129 newLastNamep = newPathp;
6133 /* TODO: The old name could be a wildcard. The new name must not be */
6135 /* Check if the file already exists; if so return error */
6136 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6137 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6138 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6140 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6141 osi_LogSaveClientString(smb_logp, newLastNamep));
6143 /* Check if the old and the new names differ only in case. If so return
6144 * success, else return CM_ERROR_EXISTS
6146 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6148 /* This would be a success only if the old file is *as same as* the new file */
6149 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6151 if (tmpscp == tmpscp2)
6154 code = CM_ERROR_EXISTS;
6155 cm_ReleaseSCache(tmpscp2);
6158 code = CM_ERROR_NOSUCHFILE;
6161 /* file exist, do not rename, also fixes move */
6162 osi_Log0(smb_logp, "Can't rename. Target already exists");
6163 code = CM_ERROR_EXISTS;
6168 /* do the vnode call */
6169 rock.odscp = oldDscp;
6170 rock.ndscp = newDscp;
6174 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6176 code = CM_ERROR_NOSUCHFILE;
6179 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6180 rock.newNamep = newLastNamep;
6181 rock.fsOldName[0] = '\0';
6182 rock.clOldName[0] = '\0';
6185 /* Now search the directory for the pattern, and do the appropriate rename when found */
6186 thyper.LowPart = 0; /* search dir from here */
6187 thyper.HighPart = 0;
6189 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6190 if (code == 0 && !rock.any) {
6192 thyper.HighPart = 0;
6193 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6194 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6196 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6198 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6199 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6200 rock.ndscp, rock.newNamep, rock.userp,
6202 /* if the call worked, stop doing the search now, since we
6203 * really only want to rename one file.
6206 osi_Log0(smb_logp, "cm_Rename failure");
6207 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6208 } else if (code == 0) {
6209 code = CM_ERROR_NOSUCHFILE;
6212 /* Handle Change Notification */
6214 * Being lazy, not distinguishing between files and dirs in this
6215 * filter, since we'd have to do a lookup.
6218 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6219 if (oldDscp == newDscp) {
6220 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6221 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6222 filter, oldDscp, rock.clOldName,
6223 newLastNamep, TRUE);
6225 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6226 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6227 filter, oldDscp, rock.clOldName,
6229 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6230 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6231 filter, newDscp, newLastNamep,
6238 cm_ReleaseSCache(tmpscp);
6240 cm_ReleaseUser(userp);
6242 cm_ReleaseSCache(oldDscp);
6244 cm_ReleaseSCache(newDscp);
6252 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6255 cm_space_t *spacep = NULL;
6256 cm_scache_t *oldDscp = NULL;
6257 cm_scache_t *newDscp = NULL;
6258 cm_scache_t *tmpscp= NULL;
6259 cm_scache_t *tmpscp2 = NULL;
6260 cm_scache_t *sscp = NULL;
6261 clientchar_t *oldLastNamep;
6262 clientchar_t *newLastNamep;
6265 clientchar_t *tidPathp;
6269 userp = smb_GetUserFromVCP(vcp, inp);
6271 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6273 cm_ReleaseUser(userp);
6274 return CM_ERROR_NOSUCHPATH;
6279 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6281 spacep = inp->spacep;
6282 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6284 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6285 userp, tidPathp, &req, &oldDscp);
6287 cm_ReleaseUser(userp);
6292 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6293 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6294 cm_ReleaseSCache(oldDscp);
6295 cm_ReleaseUser(userp);
6296 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6297 return CM_ERROR_PATH_NOT_COVERED;
6299 return CM_ERROR_NOSUCHPATH;
6301 #endif /* DFS_SUPPORT */
6303 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6304 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6305 userp, tidPathp, &req, &newDscp);
6307 cm_ReleaseSCache(oldDscp);
6308 cm_ReleaseUser(userp);
6313 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6314 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6315 cm_ReleaseSCache(newDscp);
6316 cm_ReleaseSCache(oldDscp);
6317 cm_ReleaseUser(userp);
6318 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6319 return CM_ERROR_PATH_NOT_COVERED;
6321 return CM_ERROR_NOSUCHPATH;
6323 #endif /* DFS_SUPPORT */
6325 /* Now, although we did two lookups for the two directories (because the same
6326 * directory can be referenced through different paths), we only allow hard links
6327 * within the same directory. */
6328 if (oldDscp != newDscp) {
6329 cm_ReleaseSCache(oldDscp);
6330 cm_ReleaseSCache(newDscp);
6331 cm_ReleaseUser(userp);
6332 return CM_ERROR_CROSSDEVLINK;
6335 /* handle the old name first */
6337 oldLastNamep = oldPathp;
6341 /* and handle the new name, too */
6343 newLastNamep = newPathp;
6347 /* now lookup the old name */
6348 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6349 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6351 cm_ReleaseSCache(oldDscp);
6352 cm_ReleaseSCache(newDscp);
6353 cm_ReleaseUser(userp);
6357 /* Check if the file already exists; if so return error */
6358 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6359 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6360 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6362 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6363 osi_LogSaveClientString(smb_logp, newLastNamep));
6365 /* if the existing link is to the same file, then we return success */
6367 if(sscp == tmpscp) {
6370 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6371 code = CM_ERROR_EXISTS;
6376 cm_ReleaseSCache(tmpscp);
6377 cm_ReleaseSCache(sscp);
6378 cm_ReleaseSCache(newDscp);
6379 cm_ReleaseSCache(oldDscp);
6380 cm_ReleaseUser(userp);
6384 /* now create the hardlink */
6385 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6386 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6387 osi_Log1(smb_logp," Link returns 0x%x", code);
6389 /* Handle Change Notification */
6391 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6392 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6393 smb_NotifyChange(FILE_ACTION_ADDED,
6394 filter, newDscp, newLastNamep,
6399 cm_ReleaseSCache(tmpscp);
6400 cm_ReleaseUser(userp);
6401 cm_ReleaseSCache(sscp);
6402 cm_ReleaseSCache(oldDscp);
6403 cm_ReleaseSCache(newDscp);
6407 /* SMB_COM_RENAME */
6409 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6411 clientchar_t *oldPathp;
6412 clientchar_t *newPathp;
6416 tp = smb_GetSMBData(inp, NULL);
6417 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6419 return CM_ERROR_BADSMB;
6420 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6422 return CM_ERROR_BADSMB;
6424 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6425 osi_LogSaveClientString(smb_logp, oldPathp),
6426 osi_LogSaveClientString(smb_logp, newPathp));
6428 if (!cm_IsValidClientString(newPathp)) {
6430 clientchar_t * hexp;
6432 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6433 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6434 osi_LogSaveClientString(smb_logp, hexp));
6438 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6440 return CM_ERROR_BADNTFILENAME;
6443 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6445 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6451 typedef struct smb_rmdirRock {
6455 normchar_t *maskp; /* pointer to the star pattern */
6458 cm_dirEntryList_t * matches;
6461 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6464 smb_rmdirRock_t *rockp;
6466 normchar_t matchName[MAX_PATH];
6468 rockp = (smb_rmdirRock_t *) vrockp;
6470 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6471 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6472 osi_LogSaveString(smb_logp, dep->name));
6476 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6477 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6479 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6481 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6482 !cm_Is8Dot3(matchName)) {
6483 cm_Gen8Dot3Name(dep, matchName, NULL);
6484 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6489 cm_DirEntryListAdd(dep->name, &rockp->matches);
6496 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6499 clientchar_t *pathp;
6503 clientchar_t *lastNamep;
6504 smb_rmdirRock_t rock;
6508 clientchar_t *tidPathp;
6512 memset(&rock, 0, sizeof(rock));
6514 tp = smb_GetSMBData(inp, NULL);
6515 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6517 return CM_ERROR_BADSMB;
6519 spacep = inp->spacep;
6520 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6522 userp = smb_GetUserFromVCP(vcp, inp);
6524 caseFold = CM_FLAG_CASEFOLD;
6526 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6528 cm_ReleaseUser(userp);
6529 return CM_ERROR_NOSUCHPATH;
6531 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6532 userp, tidPathp, &req, &dscp);
6535 cm_ReleaseUser(userp);
6540 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6541 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6542 cm_ReleaseSCache(dscp);
6543 cm_ReleaseUser(userp);
6544 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6545 return CM_ERROR_PATH_NOT_COVERED;
6547 return CM_ERROR_NOSUCHPATH;
6549 #endif /* DFS_SUPPORT */
6551 /* otherwise, scp points to the parent directory. */
6558 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6560 code = CM_ERROR_NOSUCHFILE;
6563 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6566 thyper.HighPart = 0;
6570 rock.matches = NULL;
6572 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6573 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6574 if (code == 0 && !rock.any) {
6576 thyper.HighPart = 0;
6577 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6578 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6581 if (code == 0 && rock.matches) {
6582 cm_dirEntryList_t * entry;
6584 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6585 clientchar_t clientName[MAX_PATH];
6587 /* We assume this will succeed because smb_RmdirProc()
6588 successfully converted entry->name once above. */
6589 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6591 osi_Log1(smb_logp, "Removing directory %s",
6592 osi_LogSaveString(smb_logp, entry->name));
6594 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6596 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6597 smb_NotifyChange(FILE_ACTION_REMOVED,
6598 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6599 dscp, clientName, NULL, TRUE);
6605 cm_DirEntryListFree(&rock.matches);
6608 cm_ReleaseUser(userp);
6611 cm_ReleaseSCache(dscp);
6613 if (code == 0 && !rock.any)
6614 code = CM_ERROR_NOSUCHFILE;
6623 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6633 fid = smb_GetSMBParm(inp, 0);
6635 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6637 fid = smb_ChainFID(fid, inp);
6638 fidp = smb_FindFID(vcp, fid, 0);
6640 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6642 return CM_ERROR_BADFD;
6644 userp = smb_GetUserFromVCP(vcp, inp);
6646 lock_ObtainMutex(&fidp->mx);
6647 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6648 cm_ReleaseUser(userp);
6649 lock_ReleaseMutex(&fidp->mx);
6650 smb_ReleaseFID(fidp);
6651 return CM_ERROR_BADFD;
6654 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6655 lock_ReleaseMutex(&fidp->mx);
6656 cm_ReleaseUser(userp);
6657 smb_CloseFID(vcp, fidp, NULL, 0);
6658 smb_ReleaseFID(fidp);
6659 return CM_ERROR_NOSUCHFILE;
6662 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6663 cm_scache_t * scp = fidp->scp;
6665 lock_ReleaseMutex(&fidp->mx);
6666 code = cm_FSync(scp, userp, &req);
6667 cm_ReleaseSCache(scp);
6669 lock_ReleaseMutex(&fidp->mx);
6673 cm_ReleaseUser(userp);
6674 smb_ReleaseFID(fidp);
6678 struct smb_FullNameRock {
6681 clientchar_t *fullName;
6682 fschar_t *originalName;
6685 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6688 normchar_t matchName[MAX_PATH];
6689 struct smb_FullNameRock *vrockp;
6691 vrockp = (struct smb_FullNameRock *)rockp;
6693 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6694 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6695 osi_LogSaveString(smb_logp, dep->name));
6699 if (!cm_Is8Dot3(matchName)) {
6700 clientchar_t shortName[13];
6702 cm_Gen8Dot3Name(dep, shortName, NULL);
6704 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6705 vrockp->fullName = cm_ClientStrDup(matchName);
6706 vrockp->originalName = cm_FsStrDup(dep->name);
6707 return CM_ERROR_STOPNOW;
6710 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6711 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6712 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6713 vrockp->fullName = cm_ClientStrDup(matchName);
6714 vrockp->originalName = cm_FsStrDup(dep->name);
6715 return CM_ERROR_STOPNOW;
6720 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6721 clientchar_t **newPathp, fschar_t ** originalPathp,
6722 cm_user_t *userp, cm_req_t *reqp)
6724 struct smb_FullNameRock rock;
6727 memset(&rock, 0, sizeof(rock));
6731 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6732 if (code == CM_ERROR_STOPNOW) {
6733 *newPathp = rock.fullName;
6734 *originalPathp = rock.originalName;
6736 *newPathp = cm_ClientStrDup(pathp);
6737 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6741 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6742 afs_uint32 dosTime) {
6745 cm_scache_t *dscp = NULL;
6746 clientchar_t *pathp = NULL;
6747 cm_scache_t * scp = NULL;
6748 cm_scache_t *delscp = NULL;
6749 int nullcreator = 0;
6751 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6752 fidp, fidp->fid, scp, vcp);
6755 lock_ObtainMutex(&fidp->mx);
6756 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6758 lock_ReleaseMutex(&fidp->mx);
6759 osi_Log0(smb_logp, " No user specified. Not closing fid");
6760 return CM_ERROR_BADFD;
6763 userp = fidp->userp; /* no hold required since fidp is held
6764 throughout the function */
6765 lock_ReleaseMutex(&fidp->mx);
6770 lock_ObtainWrite(&smb_rctLock);
6771 if (fidp->deleteOk) {
6772 osi_Log0(smb_logp, " Fid already closed.");
6773 lock_ReleaseWrite(&smb_rctLock);
6774 return CM_ERROR_BADFD;
6777 lock_ReleaseWrite(&smb_rctLock);
6779 lock_ObtainMutex(&fidp->mx);
6780 if (fidp->NTopen_dscp) {
6781 dscp = fidp->NTopen_dscp;
6782 cm_HoldSCache(dscp);
6785 if (fidp->NTopen_pathp)
6786 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6793 /* Don't jump the gun on an async raw write */
6794 while (fidp->raw_writers) {
6795 lock_ReleaseMutex(&fidp->mx);
6796 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6797 lock_ObtainMutex(&fidp->mx);
6800 /* watch for ioctl closes, and read-only opens */
6802 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6803 == SMB_FID_OPENWRITE) {
6804 if (dosTime != 0 && dosTime != -1) {
6805 lock_ObtainWrite(&fidp->scp->rw);
6806 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6807 /* This fixes defect 10958 */
6808 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6809 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6810 lock_ReleaseWrite(&fidp->scp->rw);
6812 if (smb_AsyncStore != 2) {
6813 lock_ReleaseMutex(&fidp->mx);
6814 code = cm_FSync(scp, userp, &req);
6815 lock_ObtainMutex(&fidp->mx);
6821 /* unlock any pending locks */
6822 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6823 scp->fileType == CM_SCACHETYPE_FILE) {
6827 lock_ReleaseMutex(&fidp->mx);
6829 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6831 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6832 lock_ObtainWrite(&scp->rw);
6834 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6835 CM_SCACHESYNC_NEEDCALLBACK
6836 | CM_SCACHESYNC_GETSTATUS
6837 | CM_SCACHESYNC_LOCK);
6841 "smb CoreClose SyncOp failure code 0x%x", tcode);
6842 goto post_syncopdone;
6845 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6847 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6851 lock_ReleaseWrite(&scp->rw);
6852 lock_ObtainMutex(&fidp->mx);
6855 if (fidp->flags & SMB_FID_DELONCLOSE) {
6856 clientchar_t *fullPathp = NULL;
6857 fschar_t *originalNamep = NULL;
6859 lock_ReleaseMutex(&fidp->mx);
6861 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6866 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6867 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6868 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6870 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6871 smb_NotifyChange(FILE_ACTION_REMOVED,
6872 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6873 dscp, fullPathp, NULL, TRUE);
6876 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6878 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6879 smb_NotifyChange(FILE_ACTION_REMOVED,
6880 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6881 dscp, fullPathp, NULL, TRUE);
6888 free(originalNamep);
6890 lock_ObtainMutex(&fidp->mx);
6891 fidp->flags &= ~SMB_FID_DELONCLOSE;
6894 /* if this was a newly created file, then clear the creator
6895 * in the stat cache entry. */
6896 if (fidp->flags & SMB_FID_CREATED) {
6898 fidp->flags &= ~SMB_FID_CREATED;
6901 if (fidp->flags & SMB_FID_NTOPEN) {
6902 cm_ReleaseSCache(fidp->NTopen_dscp);
6903 fidp->NTopen_dscp = NULL;
6904 free(fidp->NTopen_pathp);
6905 fidp->NTopen_pathp = NULL;
6906 fidp->flags &= ~SMB_FID_NTOPEN;
6908 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6909 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6912 if (fidp->NTopen_wholepathp) {
6913 free(fidp->NTopen_wholepathp);
6914 fidp->NTopen_wholepathp = NULL;
6918 cm_ReleaseSCache(fidp->scp);
6921 lock_ReleaseMutex(&fidp->mx);
6924 cm_ReleaseSCache(dscp);
6927 cm_ReleaseSCache(delscp);
6931 lock_ObtainWrite(&scp->rw);
6932 if (nullcreator && scp->creator == userp)
6933 scp->creator = NULL;
6934 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6935 lock_ReleaseWrite(&scp->rw);
6936 cm_ReleaseSCache(scp);
6946 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6954 fid = smb_GetSMBParm(inp, 0);
6955 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6957 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6959 fid = smb_ChainFID(fid, inp);
6960 fidp = smb_FindFID(vcp, fid, 0);
6962 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
6964 return CM_ERROR_BADFD;
6967 userp = smb_GetUserFromVCP(vcp, inp);
6969 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6971 smb_ReleaseFID(fidp);
6972 cm_ReleaseUser(userp);
6977 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6979 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6980 cm_user_t *userp, long *readp)
6986 osi_hyper_t fileLength;
6988 osi_hyper_t lastByte;
6989 osi_hyper_t bufferOffset;
6993 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6996 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6997 fidp->fid, offsetp->LowPart, count);
7001 lock_ObtainMutex(&fidp->mx);
7002 /* make sure we have a readable FD */
7003 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7004 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7005 fidp->fid, fidp->flags);
7006 lock_ReleaseMutex(&fidp->mx);
7007 code = CM_ERROR_BADFDOP;
7012 lock_ReleaseMutex(&fidp->mx);
7013 code = CM_ERROR_BADFD;
7024 lock_ObtainWrite(&scp->rw);
7026 if (offset.HighPart == 0) {
7027 chunk = offset.LowPart >> cm_logChunkSize;
7028 if (chunk != fidp->curr_chunk) {
7029 fidp->prev_chunk = fidp->curr_chunk;
7030 fidp->curr_chunk = chunk;
7032 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7035 lock_ReleaseMutex(&fidp->mx);
7037 /* start by looking up the file's end */
7038 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7039 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7043 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7045 /* now we have the entry locked, look up the length */
7046 fileLength = scp->length;
7048 /* adjust count down so that it won't go past EOF */
7049 thyper.LowPart = count;
7050 thyper.HighPart = 0;
7051 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7053 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7054 /* we'd read past EOF, so just stop at fileLength bytes.
7055 * Start by computing how many bytes remain in the file.
7057 thyper = LargeIntegerSubtract(fileLength, offset);
7059 /* if we are past EOF, read 0 bytes */
7060 if (LargeIntegerLessThanZero(thyper))
7063 count = thyper.LowPart;
7068 /* now, copy the data one buffer at a time,
7069 * until we've filled the request packet
7072 /* if we've copied all the data requested, we're done */
7073 if (count <= 0) break;
7075 /* otherwise, load up a buffer of data */
7076 thyper.HighPart = offset.HighPart;
7077 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7078 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7081 buf_Release(bufferp);
7084 lock_ReleaseWrite(&scp->rw);
7086 code = buf_Get(scp, &thyper, &req, &bufferp);
7088 lock_ObtainWrite(&scp->rw);
7089 if (code) goto done;
7090 bufferOffset = thyper;
7092 /* now get the data in the cache */
7094 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7095 CM_SCACHESYNC_NEEDCALLBACK |
7096 CM_SCACHESYNC_READ);
7100 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7102 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7104 /* otherwise, load the buffer and try again */
7105 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7109 buf_Release(bufferp);
7113 } /* if (wrong buffer) ... */
7115 /* now we have the right buffer loaded. Copy out the
7116 * data from here to the user's buffer.
7118 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7120 /* and figure out how many bytes we want from this buffer */
7121 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7122 if (nbytes > count) nbytes = count; /* don't go past EOF */
7124 /* now copy the data */
7125 memcpy(op, bufferp->datap + bufIndex, nbytes);
7127 /* adjust counters, pointers, etc. */
7130 thyper.LowPart = nbytes;
7131 thyper.HighPart = 0;
7132 offset = LargeIntegerAdd(thyper, offset);
7136 lock_ReleaseWrite(&scp->rw);
7138 buf_Release(bufferp);
7140 if (code == 0 && sequential)
7141 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7143 cm_ReleaseSCache(scp);
7146 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7147 fidp->fid, code, *readp);
7152 * smb_WriteData -- common code for Write and Raw Write
7154 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7155 cm_user_t *userp, long *writtenp)
7157 osi_hyper_t offset = *offsetp;
7160 cm_scache_t *scp = NULL;
7161 osi_hyper_t fileLength; /* file's length at start of write */
7162 osi_hyper_t minLength; /* don't read past this */
7163 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7164 cm_buf_t *bufferp = NULL;
7165 osi_hyper_t thyper; /* hyper tmp variable */
7166 osi_hyper_t bufferOffset;
7167 afs_uint32 bufIndex; /* index in buffer where our data is */
7168 int doWriteBack = 0;
7169 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7172 int needSyncOpDone = 0;
7174 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7175 fidp->fid, offsetp->LowPart, count);
7179 lock_ObtainMutex(&fidp->mx);
7180 /* make sure we have a writable FD */
7181 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7182 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7183 fidp->fid, fidp->flags);
7184 lock_ReleaseMutex(&fidp->mx);
7185 code = CM_ERROR_BADFDOP;
7193 lock_ReleaseMutex(&fidp->mx);
7195 lock_ObtainWrite(&scp->rw);
7196 /* start by looking up the file's end */
7197 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7198 CM_SCACHESYNC_NEEDCALLBACK
7199 | CM_SCACHESYNC_SETSTATUS
7200 | CM_SCACHESYNC_GETSTATUS);
7204 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7206 /* now we have the entry locked, look up the length */
7207 fileLength = scp->length;
7208 minLength = fileLength;
7209 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7210 minLength = scp->serverLength;
7212 /* adjust file length if we extend past EOF */
7213 thyper.LowPart = count;
7214 thyper.HighPart = 0;
7215 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7216 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7217 /* we'd write past EOF, so extend the file */
7218 scp->mask |= CM_SCACHEMASK_LENGTH;
7219 scp->length = thyper;
7220 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7222 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7224 /* now, if the new position (thyper) and the old (offset) are in
7225 * different storeback windows, remember to store back the previous
7226 * storeback window when we're done with the write.
7228 * the purpose of this logic is to slow down the CIFS client
7229 * in order to avoid the client disconnecting during the CLOSE
7230 * operation if there are too many dirty buffers left to write
7231 * than can be accomplished during 45 seconds. This used to be
7232 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7233 * so that we can read larger amounts of data at a time.
7235 if (smb_AsyncStore == 1 &&
7236 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7237 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7238 /* they're different */
7240 writeBackOffset.HighPart = offset.HighPart;
7241 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7246 /* now, copy the data one buffer at a time, until we've filled the
7248 while (count != 0) {
7250 /* handle over quota or out of space */
7251 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7252 *writtenp = written;
7253 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7257 /* otherwise, load up a buffer of data */
7258 thyper.HighPart = offset.HighPart;
7259 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7260 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7263 if (needSyncOpDone) {
7264 cm_SyncOpDone(scp, bufferp,
7265 CM_SCACHESYNC_NEEDCALLBACK
7266 | CM_SCACHESYNC_WRITE
7267 | CM_SCACHESYNC_BUFLOCKED);
7270 lock_ReleaseMutex(&bufferp->mx);
7271 buf_Release(bufferp);
7274 lock_ReleaseWrite(&scp->rw);
7276 code = buf_Get(scp, &thyper, &req, &bufferp);
7278 lock_ObtainMutex(&bufferp->mx);
7279 lock_ObtainWrite(&scp->rw);
7280 if (code) goto done;
7282 bufferOffset = thyper;
7284 /* now get the data in the cache */
7286 if (!needSyncOpDone) {
7287 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7288 CM_SCACHESYNC_NEEDCALLBACK
7289 | CM_SCACHESYNC_WRITE
7290 | CM_SCACHESYNC_BUFLOCKED);
7297 /* If we're overwriting the entire buffer, or
7298 * if we're writing at or past EOF, mark the
7299 * buffer as current so we don't call
7300 * cm_GetBuffer. This skips the fetch from the
7301 * server in those cases where we're going to
7302 * obliterate all the data in the buffer anyway,
7303 * or in those cases where there is no useful
7304 * data at the server to start with.
7306 * Use minLength instead of scp->length, since
7307 * the latter has already been updated by this
7310 * The scp lock has been dropped multiple times
7311 * so the minLength must be refreshed before it
7315 minLength = scp->length;
7316 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7317 minLength = scp->serverLength;
7319 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7320 || LargeIntegerEqualTo(offset, bufferp->offset)
7321 && (count >= cm_data.buf_blockSize
7322 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7323 ConvertLongToLargeInteger(count)),
7325 if (count < cm_data.buf_blockSize
7326 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7327 memset(bufferp->datap, 0,
7328 cm_data.buf_blockSize);
7329 bufferp->dataVersion = scp->dataVersion;
7332 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7334 /* otherwise, load the buffer and try again */
7335 cm_SyncOpDone(scp, bufferp,
7336 CM_SCACHESYNC_NEEDCALLBACK
7337 | CM_SCACHESYNC_WRITE
7338 | CM_SCACHESYNC_BUFLOCKED);
7341 lock_ReleaseMutex(&bufferp->mx);
7342 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7344 lock_ReleaseWrite(&scp->rw);
7345 lock_ObtainMutex(&bufferp->mx);
7346 lock_ObtainWrite(&scp->rw);
7350 } /* if (wrong buffer) ... */
7352 /* now we have the right buffer loaded. Copy out the
7353 * data from here to the user's buffer.
7355 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7357 /* and figure out how many bytes we want from this buffer */
7358 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7360 nbytes = count; /* don't go past end of request */
7362 /* now copy the data */
7363 memcpy(bufferp->datap + bufIndex, op, nbytes);
7364 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7366 /* adjust counters, pointers, etc. */
7370 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7371 } /* while count != 0 */
7374 if (bufferp && needSyncOpDone) {
7375 cm_SyncOpDone(scp, bufferp,
7376 CM_SCACHESYNC_NEEDCALLBACK
7377 | CM_SCACHESYNC_WRITE
7378 | CM_SCACHESYNC_BUFLOCKED);
7381 lock_ReleaseWrite(&scp->rw);
7384 lock_ReleaseMutex(&bufferp->mx);
7385 buf_Release(bufferp);
7388 lock_ObtainMutex(&fidp->mx);
7389 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7390 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7392 lock_ReleaseMutex(&fidp->mx);
7393 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7394 fidp->NTopen_dscp, fidp->NTopen_pathp,
7397 lock_ReleaseMutex(&fidp->mx);
7401 if (smb_AsyncStore > 0) {
7405 lock_ObtainWrite(&scp->rw);
7406 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7408 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7409 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7411 lock_ReleaseWrite(&scp->rw);
7412 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7413 writeBackOffset.HighPart,
7414 smb_AsyncStoreSize, 0, userp);
7415 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7418 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7422 cm_ReleaseSCache(scp);
7425 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7426 fidp->fid, code, *writtenp);
7431 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7434 unsigned short count;
7436 unsigned short hint;
7437 long written = 0, total_written = 0;
7440 smb_t* smbp = (smb_t*) inp;
7444 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7446 int inDataBlockCount;
7448 fd = smb_GetSMBParm(inp, 0);
7449 count = smb_GetSMBParm(inp, 1);
7450 offset.HighPart = 0; /* too bad */
7451 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7452 hint = smb_GetSMBParm(inp, 4);
7454 op = smb_GetSMBData(inp, NULL);
7455 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7457 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7458 fd, offset.LowPart, count);
7460 fd = smb_ChainFID(fd, inp);
7461 fidp = smb_FindFID(vcp, fd, 0);
7463 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7465 return CM_ERROR_BADFD;
7468 lock_ObtainMutex(&fidp->mx);
7469 if (fidp->flags & SMB_FID_IOCTL) {
7470 lock_ReleaseMutex(&fidp->mx);
7471 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7472 smb_ReleaseFID(fidp);
7473 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7477 if (fidp->flags & SMB_FID_RPC) {
7478 lock_ReleaseMutex(&fidp->mx);
7479 code = smb_RPCWrite(fidp, vcp, inp, outp);
7480 smb_ReleaseFID(fidp);
7481 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7486 lock_ReleaseMutex(&fidp->mx);
7487 smb_ReleaseFID(fidp);
7488 return CM_ERROR_BADFD;
7491 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7492 lock_ReleaseMutex(&fidp->mx);
7493 smb_CloseFID(vcp, fidp, NULL, 0);
7494 smb_ReleaseFID(fidp);
7495 return CM_ERROR_NOSUCHFILE;
7500 lock_ReleaseMutex(&fidp->mx);
7501 userp = smb_GetUserFromVCP(vcp, inp);
7505 LARGE_INTEGER LOffset;
7506 LARGE_INTEGER LLength;
7509 key = cm_GenerateKey(vcp->vcID, pid, fd);
7511 LOffset.HighPart = offset.HighPart;
7512 LOffset.LowPart = offset.LowPart;
7513 LLength.HighPart = 0;
7514 LLength.LowPart = count;
7516 lock_ObtainWrite(&scp->rw);
7517 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7518 lock_ReleaseWrite(&scp->rw);
7521 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7526 /* special case: 0 bytes transferred means truncate to this position */
7530 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7534 truncAttr.mask = CM_ATTRMASK_LENGTH;
7535 truncAttr.length.LowPart = offset.LowPart;
7536 truncAttr.length.HighPart = 0;
7537 lock_ObtainMutex(&fidp->mx);
7538 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7539 fidp->flags |= SMB_FID_LENGTHSETDONE;
7540 lock_ReleaseMutex(&fidp->mx);
7541 smb_SetSMBParm(outp, 0, 0 /* count */);
7542 smb_SetSMBDataLength(outp, 0);
7547 * Work around bug in NT client
7549 * When copying a file, the NT client should first copy the data,
7550 * then copy the last write time. But sometimes the NT client does
7551 * these in the wrong order, so the data copies would inadvertently
7552 * cause the last write time to be overwritten. We try to detect this,
7553 * and don't set client mod time if we think that would go against the
7556 lock_ObtainMutex(&fidp->mx);
7557 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7558 lock_ObtainWrite(&fidp->scp->rw);
7559 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7560 fidp->scp->clientModTime = time(NULL);
7561 lock_ReleaseWrite(&fidp->scp->rw);
7563 lock_ReleaseMutex(&fidp->mx);
7566 while ( code == 0 && count > 0 ) {
7567 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7568 if (code == 0 && written == 0)
7569 code = CM_ERROR_PARTIALWRITE;
7571 offset = LargeIntegerAdd(offset,
7572 ConvertLongToLargeInteger(written));
7573 count -= (unsigned short)written;
7574 total_written += written;
7578 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7579 total_written, code);
7581 /* set the packet data length to 3 bytes for the data block header,
7582 * plus the size of the data.
7584 smb_SetSMBParm(outp, 0, total_written);
7585 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7586 smb_SetSMBParm(outp, 3, hint);
7587 smb_SetSMBDataLength(outp, 0);
7590 smb_ReleaseFID(fidp);
7591 cm_ReleaseUser(userp);
7592 cm_ReleaseSCache(scp);
7597 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7598 NCB *ncbp, raw_write_cont_t *rwcp)
7607 fd = smb_GetSMBParm(inp, 0);
7608 fidp = smb_FindFID(vcp, fd, 0);
7610 lock_ObtainMutex(&fidp->mx);
7612 lock_ReleaseMutex(&fidp->mx);
7613 smb_ReleaseFID(fidp);
7617 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7618 lock_ReleaseMutex(&fidp->mx);
7619 smb_CloseFID(vcp, fidp, NULL, 0);
7620 smb_ReleaseFID(fidp);
7623 lock_ReleaseMutex(&fidp->mx);
7625 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7626 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7628 userp = smb_GetUserFromVCP(vcp, inp);
7631 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7633 if (rwcp->writeMode & 0x1) { /* synchronous */
7636 smb_FormatResponsePacket(vcp, inp, outp);
7637 op = (smb_t *) outp;
7638 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7639 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7640 smb_SetSMBDataLength(outp, 0);
7641 smb_SendPacket(vcp, outp);
7642 smb_FreePacket(outp);
7644 else { /* asynchronous */
7645 lock_ObtainMutex(&fidp->mx);
7646 fidp->raw_writers--;
7647 if (fidp->raw_writers == 0)
7648 thrd_SetEvent(fidp->raw_write_event);
7649 lock_ReleaseMutex(&fidp->mx);
7652 /* Give back raw buffer */
7653 lock_ObtainMutex(&smb_RawBufLock);
7654 *((char **)rawBuf) = smb_RawBufs;
7655 smb_RawBufs = rawBuf;
7656 lock_ReleaseMutex(&smb_RawBufLock);
7658 smb_ReleaseFID(fidp);
7659 cm_ReleaseUser(userp);
7662 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7667 /* SMB_COM_WRITE_RAW */
7668 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7671 long count, written = 0, total_written = 0;
7675 smb_t *smbp = (smb_t*) inp;
7680 unsigned short writeMode;
7682 fd = smb_GetSMBParm(inp, 0);
7683 totalCount = smb_GetSMBParm(inp, 1);
7684 count = smb_GetSMBParm(inp, 10);
7685 writeMode = smb_GetSMBParm(inp, 7);
7687 op = (char *) inp->data;
7688 op += smb_GetSMBParm(inp, 11);
7690 offset.HighPart = 0;
7691 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7693 if (*inp->wctp == 14) {
7694 /* we received a 64-bit file offset */
7695 #ifdef AFS_LARGEFILES
7696 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7698 if (LargeIntegerLessThanZero(offset)) {
7700 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7701 offset.HighPart, offset.LowPart);
7702 return CM_ERROR_BADSMB;
7705 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7707 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7708 return CM_ERROR_BADSMB;
7711 offset.HighPart = 0;
7714 offset.HighPart = 0; /* 32-bit file offset */
7718 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7719 fd, offset.HighPart, offset.LowPart, count);
7721 " WriteRaw WriteMode 0x%x",
7724 fd = smb_ChainFID(fd, inp);
7725 fidp = smb_FindFID(vcp, fd, 0);
7727 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7729 return CM_ERROR_BADFD;
7731 lock_ObtainMutex(&fidp->mx);
7733 lock_ReleaseMutex(&fidp->mx);
7734 smb_ReleaseFID(fidp);
7735 return CM_ERROR_BADFD;
7738 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7739 lock_ReleaseMutex(&fidp->mx);
7740 smb_CloseFID(vcp, fidp, NULL, 0);
7741 smb_ReleaseFID(fidp);
7742 return CM_ERROR_NOSUCHFILE;
7747 lock_ReleaseMutex(&fidp->mx);
7752 LARGE_INTEGER LOffset;
7753 LARGE_INTEGER LLength;
7756 key = cm_GenerateKey(vcp->vcID, pid, fd);
7758 LOffset.HighPart = offset.HighPart;
7759 LOffset.LowPart = offset.LowPart;
7760 LLength.HighPart = 0;
7761 LLength.LowPart = count;
7763 lock_ObtainWrite(&scp->rw);
7764 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7765 lock_ReleaseWrite(&scp->rw);
7768 cm_ReleaseSCache(scp);
7769 smb_ReleaseFID(fidp);
7774 userp = smb_GetUserFromVCP(vcp, inp);
7777 * Work around bug in NT client
7779 * When copying a file, the NT client should first copy the data,
7780 * then copy the last write time. But sometimes the NT client does
7781 * these in the wrong order, so the data copies would inadvertently
7782 * cause the last write time to be overwritten. We try to detect this,
7783 * and don't set client mod time if we think that would go against the
7786 lock_ObtainMutex(&fidp->mx);
7787 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7788 lock_ObtainWrite(&fidp->scp->rw);
7789 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7790 fidp->scp->clientModTime = time(NULL);
7791 lock_ReleaseWrite(&fidp->scp->rw);
7793 lock_ReleaseMutex(&fidp->mx);
7796 while ( code == 0 && count > 0 ) {
7797 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7798 if (code == 0 && written == 0)
7799 code = CM_ERROR_PARTIALWRITE;
7801 offset = LargeIntegerAdd(offset,
7802 ConvertLongToLargeInteger(written));
7805 total_written += written;
7809 /* Get a raw buffer */
7812 lock_ObtainMutex(&smb_RawBufLock);
7814 /* Get a raw buf, from head of list */
7815 rawBuf = smb_RawBufs;
7816 smb_RawBufs = *(char **)smb_RawBufs;
7819 code = CM_ERROR_USESTD;
7821 lock_ReleaseMutex(&smb_RawBufLock);
7824 /* Don't allow a premature Close */
7825 if (code == 0 && (writeMode & 1) == 0) {
7826 lock_ObtainMutex(&fidp->mx);
7827 fidp->raw_writers++;
7828 thrd_ResetEvent(fidp->raw_write_event);
7829 lock_ReleaseMutex(&fidp->mx);
7832 smb_ReleaseFID(fidp);
7833 cm_ReleaseUser(userp);
7834 cm_ReleaseSCache(scp);
7837 smb_SetSMBParm(outp, 0, total_written);
7838 smb_SetSMBDataLength(outp, 0);
7839 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7844 offset = LargeIntegerAdd(offset,
7845 ConvertLongToLargeInteger(count));
7849 rwcp->offset.HighPart = offset.HighPart;
7850 rwcp->offset.LowPart = offset.LowPart;
7851 rwcp->count = totalCount - count;
7852 rwcp->writeMode = writeMode;
7853 rwcp->alreadyWritten = total_written;
7855 /* set the packet data length to 3 bytes for the data block header,
7856 * plus the size of the data.
7858 smb_SetSMBParm(outp, 0, 0xffff);
7859 smb_SetSMBDataLength(outp, 0);
7865 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7868 long count, finalCount;
7872 smb_t *smbp = (smb_t*) inp;
7878 fd = smb_GetSMBParm(inp, 0);
7879 count = smb_GetSMBParm(inp, 1);
7880 offset.HighPart = 0; /* too bad */
7881 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7883 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7884 fd, offset.LowPart, count);
7886 fd = smb_ChainFID(fd, inp);
7887 fidp = smb_FindFID(vcp, fd, 0);
7889 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7891 return CM_ERROR_BADFD;
7893 lock_ObtainMutex(&fidp->mx);
7894 if (fidp->flags & SMB_FID_IOCTL) {
7895 lock_ReleaseMutex(&fidp->mx);
7896 code = smb_IoctlRead(fidp, vcp, inp, outp);
7897 smb_ReleaseFID(fidp);
7901 if (fidp->flags & SMB_FID_RPC) {
7902 lock_ReleaseMutex(&fidp->mx);
7903 code = smb_RPCRead(fidp, vcp, inp, outp);
7904 smb_ReleaseFID(fidp);
7909 lock_ReleaseMutex(&fidp->mx);
7910 smb_ReleaseFID(fidp);
7911 return CM_ERROR_BADFD;
7914 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7915 lock_ReleaseMutex(&fidp->mx);
7916 smb_CloseFID(vcp, fidp, NULL, 0);
7917 smb_ReleaseFID(fidp);
7918 return CM_ERROR_NOSUCHFILE;
7923 lock_ReleaseMutex(&fidp->mx);
7926 LARGE_INTEGER LOffset, LLength;
7930 key = cm_GenerateKey(vcp->vcID, pid, fd);
7932 LOffset.HighPart = 0;
7933 LOffset.LowPart = offset.LowPart;
7934 LLength.HighPart = 0;
7935 LLength.LowPart = count;
7937 lock_ObtainWrite(&scp->rw);
7938 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7939 lock_ReleaseWrite(&scp->rw);
7942 cm_ReleaseSCache(scp);
7943 smb_ReleaseFID(fidp);
7947 userp = smb_GetUserFromVCP(vcp, inp);
7949 /* remember this for final results */
7950 smb_SetSMBParm(outp, 0, count);
7951 smb_SetSMBParm(outp, 1, 0);
7952 smb_SetSMBParm(outp, 2, 0);
7953 smb_SetSMBParm(outp, 3, 0);
7954 smb_SetSMBParm(outp, 4, 0);
7956 /* set the packet data length to 3 bytes for the data block header,
7957 * plus the size of the data.
7959 smb_SetSMBDataLength(outp, count+3);
7961 /* get op ptr after putting in the parms, since otherwise we don't
7962 * know where the data really is.
7964 op = smb_GetSMBData(outp, NULL);
7966 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7967 *op++ = 1; /* data block marker */
7968 *op++ = (unsigned char) (count & 0xff);
7969 *op++ = (unsigned char) ((count >> 8) & 0xff);
7971 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7973 /* fix some things up */
7974 smb_SetSMBParm(outp, 0, finalCount);
7975 smb_SetSMBDataLength(outp, finalCount+3);
7977 smb_ReleaseFID(fidp);
7979 cm_ReleaseUser(userp);
7980 cm_ReleaseSCache(scp);
7984 /* SMB_COM_CREATE_DIRECTORY */
7985 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7987 clientchar_t *pathp;
7992 cm_scache_t *dscp; /* dir we're dealing with */
7993 cm_scache_t *scp; /* file we're creating */
7995 int initialModeBits;
7996 clientchar_t *lastNamep;
7998 clientchar_t *tidPathp;
8005 /* compute initial mode bits based on read-only flag in attributes */
8006 initialModeBits = 0777;
8008 tp = smb_GetSMBData(inp, NULL);
8009 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8011 return CM_ERROR_BADSMB;
8013 spacep = inp->spacep;
8014 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8016 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8017 return CM_ERROR_EXISTS;
8019 userp = smb_GetUserFromVCP(vcp, inp);
8021 caseFold = CM_FLAG_CASEFOLD;
8023 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8025 cm_ReleaseUser(userp);
8026 return CM_ERROR_NOSUCHPATH;
8029 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
8030 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8031 userp, tidPathp, &req, &dscp);
8034 cm_ReleaseUser(userp);
8039 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8040 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8041 cm_ReleaseSCache(dscp);
8042 cm_ReleaseUser(userp);
8043 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8044 return CM_ERROR_PATH_NOT_COVERED;
8046 return CM_ERROR_NOSUCHPATH;
8048 #endif /* DFS_SUPPORT */
8050 /* otherwise, scp points to the parent directory. Do a lookup, and
8051 * fail if we find it. Otherwise, we do the create.
8057 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8058 if (scp) cm_ReleaseSCache(scp);
8059 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8060 if (code == 0) code = CM_ERROR_EXISTS;
8061 cm_ReleaseSCache(dscp);
8062 cm_ReleaseUser(userp);
8066 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8067 setAttr.clientModTime = time(NULL);
8068 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8069 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8070 smb_NotifyChange(FILE_ACTION_ADDED,
8071 FILE_NOTIFY_CHANGE_DIR_NAME,
8072 dscp, lastNamep, NULL, TRUE);
8074 /* we don't need this any longer */
8075 cm_ReleaseSCache(dscp);
8078 /* something went wrong creating or truncating the file */
8079 cm_ReleaseUser(userp);
8083 /* otherwise we succeeded */
8084 smb_SetSMBDataLength(outp, 0);
8085 cm_ReleaseUser(userp);
8090 BOOL smb_IsLegalFilename(clientchar_t *filename)
8093 * Find the longest substring of filename that does not contain
8094 * any of the chars in illegalChars. If that substring is less
8095 * than the length of the whole string, then one or more of the
8096 * illegal chars is in filename.
8098 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8104 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8105 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8107 clientchar_t *pathp;
8113 cm_scache_t *dscp; /* dir we're dealing with */
8114 cm_scache_t *scp; /* file we're creating */
8116 int initialModeBits;
8119 clientchar_t *lastNamep;
8122 clientchar_t *tidPathp;
8124 int created = 0; /* the file was new */
8129 excl = (inp->inCom == 0x03)? 0 : 1;
8131 attributes = smb_GetSMBParm(inp, 0);
8132 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8134 /* compute initial mode bits based on read-only flag in attributes */
8135 initialModeBits = 0666;
8136 if (attributes & SMB_ATTR_READONLY)
8137 initialModeBits &= ~0222;
8139 tp = smb_GetSMBData(inp, NULL);
8140 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8142 return CM_ERROR_BADSMB;
8144 spacep = inp->spacep;
8145 /* smb_StripLastComponent will strip "::$DATA" if present */
8146 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8148 if (!cm_IsValidClientString(pathp)) {
8150 clientchar_t * hexp;
8152 hexp = cm_GetRawCharsAlloc(pathp, -1);
8153 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8154 osi_LogSaveClientString(smb_logp, hexp));
8158 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8160 return CM_ERROR_BADNTFILENAME;
8163 userp = smb_GetUserFromVCP(vcp, inp);
8165 caseFold = CM_FLAG_CASEFOLD;
8167 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8169 cm_ReleaseUser(userp);
8170 return CM_ERROR_NOSUCHPATH;
8172 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8173 userp, tidPathp, &req, &dscp);
8176 cm_ReleaseUser(userp);
8181 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8182 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8183 cm_ReleaseSCache(dscp);
8184 cm_ReleaseUser(userp);
8185 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8186 return CM_ERROR_PATH_NOT_COVERED;
8188 return CM_ERROR_NOSUCHPATH;
8190 #endif /* DFS_SUPPORT */
8192 /* otherwise, scp points to the parent directory. Do a lookup, and
8193 * truncate the file if we find it, otherwise we create the file.
8200 if (!smb_IsLegalFilename(lastNamep))
8201 return CM_ERROR_BADNTFILENAME;
8203 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8204 #ifdef DEBUG_VERBOSE
8207 hexp = osi_HexifyString( lastNamep );
8208 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8213 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8214 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8215 cm_ReleaseSCache(dscp);
8216 cm_ReleaseUser(userp);
8220 /* if we get here, if code is 0, the file exists and is represented by
8221 * scp. Otherwise, we have to create it.
8225 /* oops, file shouldn't be there */
8226 cm_ReleaseSCache(dscp);
8227 cm_ReleaseSCache(scp);
8228 cm_ReleaseUser(userp);
8229 return CM_ERROR_EXISTS;
8232 setAttr.mask = CM_ATTRMASK_LENGTH;
8233 setAttr.length.LowPart = 0;
8234 setAttr.length.HighPart = 0;
8235 code = cm_SetAttr(scp, &setAttr, userp, &req);
8238 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8239 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8240 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8244 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8245 smb_NotifyChange(FILE_ACTION_ADDED,
8246 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8247 dscp, lastNamep, NULL, TRUE);
8248 } else if (!excl && code == CM_ERROR_EXISTS) {
8249 /* not an exclusive create, and someone else tried
8250 * creating it already, then we open it anyway. We
8251 * don't bother retrying after this, since if this next
8252 * fails, that means that the file was deleted after
8253 * we started this call.
8255 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8258 setAttr.mask = CM_ATTRMASK_LENGTH;
8259 setAttr.length.LowPart = 0;
8260 setAttr.length.HighPart = 0;
8261 code = cm_SetAttr(scp, &setAttr, userp, &req);
8266 /* we don't need this any longer */
8267 cm_ReleaseSCache(dscp);
8270 /* something went wrong creating or truncating the file */
8271 if (scp) cm_ReleaseSCache(scp);
8272 cm_ReleaseUser(userp);
8276 /* make sure we only open files */
8277 if (scp->fileType != CM_SCACHETYPE_FILE) {
8278 cm_ReleaseSCache(scp);
8279 cm_ReleaseUser(userp);
8280 return CM_ERROR_ISDIR;
8283 /* now all we have to do is open the file itself */
8284 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8285 osi_assertx(fidp, "null smb_fid_t");
8289 lock_ObtainMutex(&fidp->mx);
8290 /* always create it open for read/write */
8291 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8293 /* remember that the file was newly created */
8295 fidp->flags |= SMB_FID_CREATED;
8297 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8299 /* save a pointer to the vnode */
8301 lock_ObtainWrite(&scp->rw);
8302 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8303 lock_ReleaseWrite(&scp->rw);
8306 fidp->userp = userp;
8307 lock_ReleaseMutex(&fidp->mx);
8309 smb_SetSMBParm(outp, 0, fidp->fid);
8310 smb_SetSMBDataLength(outp, 0);
8312 cm_Open(scp, 0, userp);
8314 smb_ReleaseFID(fidp);
8315 cm_ReleaseUser(userp);
8316 /* leave scp held since we put it in fidp->scp */
8321 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8324 osi_hyper_t new_offset;
8335 fd = smb_GetSMBParm(inp, 0);
8336 whence = smb_GetSMBParm(inp, 1);
8337 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8339 /* try to find the file descriptor */
8340 fd = smb_ChainFID(fd, inp);
8341 fidp = smb_FindFID(vcp, fd, 0);
8343 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8345 return CM_ERROR_BADFD;
8347 lock_ObtainMutex(&fidp->mx);
8348 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8349 lock_ReleaseMutex(&fidp->mx);
8350 smb_ReleaseFID(fidp);
8351 return CM_ERROR_BADFD;
8354 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8355 lock_ReleaseMutex(&fidp->mx);
8356 smb_CloseFID(vcp, fidp, NULL, 0);
8357 smb_ReleaseFID(fidp);
8358 return CM_ERROR_NOSUCHFILE;
8361 lock_ReleaseMutex(&fidp->mx);
8363 userp = smb_GetUserFromVCP(vcp, inp);
8365 lock_ObtainMutex(&fidp->mx);
8368 lock_ReleaseMutex(&fidp->mx);
8369 lock_ObtainWrite(&scp->rw);
8370 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8371 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8373 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8375 /* offset from current offset */
8376 new_offset = LargeIntegerAdd(fidp->offset,
8377 ConvertLongToLargeInteger(offset));
8379 else if (whence == 2) {
8380 /* offset from current EOF */
8381 new_offset = LargeIntegerAdd(scp->length,
8382 ConvertLongToLargeInteger(offset));
8384 new_offset = ConvertLongToLargeInteger(offset);
8387 fidp->offset = new_offset;
8388 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8389 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8390 smb_SetSMBDataLength(outp, 0);
8392 lock_ReleaseWrite(&scp->rw);
8393 smb_ReleaseFID(fidp);
8394 cm_ReleaseSCache(scp);
8395 cm_ReleaseUser(userp);
8399 /* dispatch all of the requests received in a packet. Due to chaining, this may
8400 * be more than one request.
8402 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8403 NCB *ncbp, raw_write_cont_t *rwcp)
8407 unsigned long code = 0;
8408 unsigned char *outWctp;
8409 int nparms; /* # of bytes of parameters */
8411 int nbytes; /* bytes of data, excluding count */
8414 unsigned short errCode;
8415 unsigned long NTStatus;
8417 unsigned char errClass;
8418 unsigned int oldGen;
8419 DWORD oldTime, newTime;
8421 /* get easy pointer to the data */
8422 smbp = (smb_t *) inp->data;
8424 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8425 /* setup the basic parms for the initial request in the packet */
8426 inp->inCom = smbp->com;
8427 inp->wctp = &smbp->wct;
8429 inp->ncb_length = ncbp->ncb_length;
8434 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8435 /* log it and discard it */
8436 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8437 __FILE__, __LINE__, ncbp->ncb_length);
8438 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8442 /* We are an ongoing op */
8443 thrd_Increment(&ongoingOps);
8445 /* set up response packet for receiving output */
8446 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8447 smb_FormatResponsePacket(vcp, inp, outp);
8448 outWctp = outp->wctp;
8450 /* Remember session generation number and time */
8451 oldGen = sessionGen;
8452 oldTime = GetTickCount();
8454 while (inp->inCom != 0xff) {
8455 dp = &smb_dispatchTable[inp->inCom];
8457 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8458 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8459 code = outp->resumeCode;
8463 /* process each request in the packet; inCom, wctp and inCount
8464 * are already set up.
8466 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8469 /* now do the dispatch */
8470 /* start by formatting the response record a little, as a default */
8471 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8473 outWctp[1] = 0xff; /* no operation */
8474 outWctp[2] = 0; /* padding */
8479 /* not a chained request, this is a more reasonable default */
8480 outWctp[0] = 0; /* wct of zero */
8481 outWctp[1] = 0; /* and bcc (word) of zero */
8485 /* once set, stays set. Doesn't matter, since we never chain
8486 * "no response" calls.
8488 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8492 /* we have a recognized operation */
8493 char * opName = myCrt_Dispatch(inp->inCom);
8496 smbp = (smb_t *) inp;
8498 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8499 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8500 if (inp->inCom == 0x1d) {
8502 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8504 code = (*(dp->procp)) (vcp, inp, outp);
8506 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8507 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8509 newTime = GetTickCount();
8510 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8511 opName, smbp->mid, newTime - oldTime);
8514 if ( code == CM_ERROR_BADSMB ||
8515 code == CM_ERROR_BADOP )
8517 #endif /* LOG_PACKET */
8519 /* ReceiveV3Tran2A handles its own logging */
8520 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8523 clientchar_t *treepath = NULL; /* do not free */
8524 clientchar_t *pathname = NULL;
8525 cm_fid_t afid = {0,0,0,0,0};
8527 uidp = smb_FindUID(vcp, smbp->uid, 0);
8528 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8529 fidp = smb_FindFID(vcp, inp->fid, 0);
8532 lock_ObtainMutex(&fidp->mx);
8533 if (fidp->NTopen_pathp)
8534 pathname = fidp->NTopen_pathp;
8536 afid = fidp->scp->fid;
8538 if (inp->stringsp->wdata)
8539 pathname = inp->stringsp->wdata;
8542 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)",
8543 opName, newTime - oldTime,
8544 smbp->uid, uidp ? uidp->unp->name : NULL,
8545 smbp->pid, smbp->mid, smbp->tid,
8548 afid.cell, afid.volume, afid.vnode, afid.unique);
8551 lock_ReleaseMutex(&fidp->mx);
8554 smb_ReleaseUID(uidp);
8556 smb_ReleaseFID(fidp);
8559 if (oldGen != sessionGen) {
8560 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8561 newTime - oldTime, ncbp->ncb_length);
8562 osi_Log3(smb_logp, "Request %s straddled session startup, "
8563 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8566 FreeSMBStrings(inp);
8568 /* bad opcode, fail the request, after displaying it */
8569 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8572 #endif /* LOG_PACKET */
8575 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8576 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8577 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8578 if (code == IDCANCEL)
8581 code = CM_ERROR_BADOP;
8584 /* catastrophic failure: log as much as possible */
8585 if (code == CM_ERROR_BADSMB) {
8586 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8590 #endif /* LOG_PACKET */
8591 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8594 code = CM_ERROR_INVAL;
8597 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8598 thrd_Decrement(&ongoingOps);
8603 /* now, if we failed, turn the current response into an empty
8604 * one, and fill in the response packet's error code.
8607 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8608 smb_MapNTError(code, &NTStatus);
8609 outWctp = outp->wctp;
8610 smbp = (smb_t *) &outp->data;
8611 if (code != CM_ERROR_PARTIALWRITE
8612 && code != CM_ERROR_BUFFERTOOSMALL
8613 && code != CM_ERROR_GSSCONTINUE) {
8614 /* nuke wct and bcc. For a partial
8615 * write or an in-process authentication handshake,
8616 * assume they're OK.
8622 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8623 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8624 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8625 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8626 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8630 smb_MapCoreError(code, vcp, &errCode, &errClass);
8631 outWctp = outp->wctp;
8632 smbp = (smb_t *) &outp->data;
8633 if (code != CM_ERROR_PARTIALWRITE) {
8634 /* nuke wct and bcc. For a partial
8635 * write, assume they're OK.
8641 smbp->errLow = (unsigned char) (errCode & 0xff);
8642 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8643 smbp->rcls = errClass;
8646 } /* error occurred */
8648 /* if we're here, we've finished one request. Look to see if
8649 * this is a chained opcode. If it is, setup things to process
8650 * the chained request, and setup the output buffer to hold the
8651 * chained response. Start by finding the next input record.
8653 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8654 break; /* not a chained req */
8655 tp = inp->wctp; /* points to start of last request */
8656 /* in a chained request, the first two
8657 * parm fields are required, and are
8658 * AndXCommand/AndXReserved and
8660 if (tp[0] < 2) break;
8661 if (tp[1] == 0xff) break; /* no more chained opcodes */
8663 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8666 /* and now append the next output request to the end of this
8667 * last request. Begin by finding out where the last response
8668 * ends, since that's where we'll put our new response.
8670 outWctp = outp->wctp; /* ptr to out parameters */
8671 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8672 nparms = outWctp[0] << 1;
8673 tp = outWctp + nparms + 1; /* now points to bcc field */
8674 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8675 tp += 2 /* for the count itself */ + nbytes;
8676 /* tp now points to the new output record; go back and patch the
8677 * second parameter (off2) to point to the new record.
8679 temp = (unsigned int)(tp - outp->data);
8680 outWctp[3] = (unsigned char) (temp & 0xff);
8681 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8682 outWctp[2] = 0; /* padding */
8683 outWctp[1] = inp->inCom; /* next opcode */
8685 /* finally, setup for the next iteration */
8688 } /* while loop over all requests in the packet */
8690 /* now send the output packet, and return */
8692 smb_SendPacket(vcp, outp);
8693 thrd_Decrement(&ongoingOps);
8698 /* Wait for Netbios() calls to return, and make the results available to server
8699 * threads. Note that server threads can't wait on the NCBevents array
8700 * themselves, because NCB events are manual-reset, and the servers would race
8701 * each other to reset them.
8703 void smb_ClientWaiter(void *parmp)
8708 while (smbShutdownFlag == 0) {
8709 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8711 if (code == WAIT_OBJECT_0)
8714 /* error checking */
8715 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8717 int abandonIdx = code - WAIT_ABANDONED_0;
8718 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8721 if (code == WAIT_IO_COMPLETION)
8723 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8727 if (code == WAIT_TIMEOUT)
8729 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8732 if (code == WAIT_FAILED)
8734 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8737 idx = code - WAIT_OBJECT_0;
8739 /* check idx range! */
8740 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8742 /* this is fatal - log as much as possible */
8743 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8744 osi_assertx(0, "invalid index");
8747 thrd_ResetEvent(NCBevents[idx]);
8748 thrd_SetEvent(NCBreturns[0][idx]);
8753 * Try to have one NCBRECV request waiting for every live session. Not more
8754 * than one, because if there is more than one, it's hard to handle Write Raw.
8756 void smb_ServerWaiter(void *parmp)
8759 int idx_session, idx_NCB;
8762 while (smbShutdownFlag == 0) {
8764 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8766 if (code == WAIT_OBJECT_0)
8769 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8771 int abandonIdx = code - WAIT_ABANDONED_0;
8772 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8775 if (code == WAIT_IO_COMPLETION)
8777 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8781 if (code == WAIT_TIMEOUT)
8783 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8786 if (code == WAIT_FAILED)
8788 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8791 idx_session = code - WAIT_OBJECT_0;
8793 /* check idx range! */
8794 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8796 /* this is fatal - log as much as possible */
8797 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8798 osi_assertx(0, "invalid index");
8803 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8805 if (code == WAIT_OBJECT_0) {
8806 if (smbShutdownFlag == 1)
8812 /* error checking */
8813 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8815 int abandonIdx = code - WAIT_ABANDONED_0;
8816 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8819 if (code == WAIT_IO_COMPLETION)
8821 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8825 if (code == WAIT_TIMEOUT)
8827 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8830 if (code == WAIT_FAILED)
8832 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8835 idx_NCB = code - WAIT_OBJECT_0;
8837 /* check idx range! */
8838 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8840 /* this is fatal - log as much as possible */
8841 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8842 osi_assertx(0, "invalid index");
8845 /* Link them together */
8846 NCBsessions[idx_NCB] = idx_session;
8849 ncbp = NCBs[idx_NCB];
8850 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8851 ncbp->ncb_command = NCBRECV | ASYNCH;
8852 ncbp->ncb_lana_num = lanas[idx_session];
8853 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8854 ncbp->ncb_event = NCBevents[idx_NCB];
8855 ncbp->ncb_length = SMB_PACKETSIZE;
8861 * The top level loop for handling SMB request messages. Each server thread
8862 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8863 * NCB and buffer for the incoming request are loaned to us.
8865 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8866 * to immediately send a request for the rest of the data. This must come
8867 * before any other traffic for that session, so we delay setting the session
8868 * event until that data has come in.
8870 void smb_Server(VOID *parmp)
8872 INT_PTR myIdx = (INT_PTR) parmp;
8876 smb_packet_t *outbufp;
8878 int idx_NCB, idx_session;
8880 smb_vc_t *vcp = NULL;
8882 extern void rx_StartClientThread(void);
8884 rx_StartClientThread();
8886 outncbp = smb_GetNCB();
8887 outbufp = smb_GetPacket();
8888 outbufp->ncbp = outncbp;
8896 cm_ResetServerPriority();
8898 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8901 /* terminate silently if shutdown flag is set */
8902 if (code == WAIT_OBJECT_0) {
8903 if (smbShutdownFlag == 1) {
8904 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8910 /* error checking */
8911 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8913 int abandonIdx = code - WAIT_ABANDONED_0;
8914 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8917 if (code == WAIT_IO_COMPLETION)
8919 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8923 if (code == WAIT_TIMEOUT)
8925 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8928 if (code == WAIT_FAILED)
8930 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8933 idx_NCB = code - WAIT_OBJECT_0;
8935 /* check idx range! */
8936 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8938 /* this is fatal - log as much as possible */
8939 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8940 osi_assertx(0, "invalid index");
8943 ncbp = NCBs[idx_NCB];
8944 idx_session = NCBsessions[idx_NCB];
8945 rc = ncbp->ncb_retcode;
8947 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8948 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8952 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8956 /* Can this happen? Or is it just my UNIX paranoia? */
8957 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8962 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8965 /* Client closed session */
8966 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8968 lock_ObtainMutex(&vcp->mx);
8969 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8970 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8972 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8973 lock_ReleaseMutex(&vcp->mx);
8974 lock_ObtainWrite(&smb_globalLock);
8975 dead_sessions[vcp->session] = TRUE;
8976 lock_ReleaseWrite(&smb_globalLock);
8978 lock_ReleaseMutex(&vcp->mx);
8980 smb_CleanupDeadVC(vcp);
8987 /* Treat as transient error */
8988 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8991 "dispatch smb recv failed, message incomplete, ncb_length %d",
8994 "SMB message incomplete, "
8995 "length %d", ncbp->ncb_length);
8998 * We used to discard the packet.
8999 * Instead, try handling it normally.
9003 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9007 /* A weird error code. Log it, sleep, and continue. */
9008 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9010 lock_ObtainMutex(&vcp->mx);
9011 if (vcp->errorCount++ > 3) {
9012 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9013 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9014 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9016 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9017 lock_ReleaseMutex(&vcp->mx);
9018 lock_ObtainWrite(&smb_globalLock);
9019 dead_sessions[vcp->session] = TRUE;
9020 lock_ReleaseWrite(&smb_globalLock);
9022 lock_ReleaseMutex(&vcp->mx);
9024 smb_CleanupDeadVC(vcp);
9030 lock_ReleaseMutex(&vcp->mx);
9034 thrd_SetEvent(SessionEvents[idx_session]);
9040 /* Success, so now dispatch on all the data in the packet */
9042 smb_concurrentCalls++;
9043 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9044 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9047 * If at this point vcp is NULL (implies that packet was invalid)
9048 * then we are in big trouble. This means either :
9049 * a) we have the wrong NCB.
9050 * b) Netbios screwed up the call.
9051 * c) The VC was already marked dead before we were able to
9053 * Obviously this implies that
9054 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9055 * lanas[idx_session] != ncbp->ncb_lana_num )
9056 * Either way, we can't do anything with this packet.
9057 * Log, sleep and resume.
9060 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9064 ncbp->ncb_lana_num);
9066 /* Also log in the trace log. */
9067 osi_Log4(smb_logp, "Server: VCP does not exist!"
9068 "LSNs[idx_session]=[%d],"
9069 "lanas[idx_session]=[%d],"
9070 "ncbp->ncb_lsn=[%d],"
9071 "ncbp->ncb_lana_num=[%d]",
9075 ncbp->ncb_lana_num);
9077 /* thrd_Sleep(1000); Don't bother sleeping */
9078 thrd_SetEvent(SessionEvents[idx_session]);
9079 smb_concurrentCalls--;
9083 cm_SetRequestStartTime();
9085 vcp->errorCount = 0;
9086 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9087 smbp = (smb_t *)bufp->data;
9094 if (smbp->com == 0x1d) {
9095 /* Special handling for Write Raw */
9096 raw_write_cont_t rwc;
9098 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9099 if (rwc.code == 0) {
9100 EVENT_HANDLE rwevent;
9101 char eventName[MAX_PATH];
9103 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9104 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9105 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9106 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9108 ncbp->ncb_command = NCBRECV | ASYNCH;
9109 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9110 ncbp->ncb_lana_num = vcp->lana;
9111 ncbp->ncb_buffer = rwc.buf;
9112 ncbp->ncb_length = 65535;
9113 ncbp->ncb_event = rwevent;
9115 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9116 thrd_CloseHandle(rwevent);
9118 thrd_SetEvent(SessionEvents[idx_session]);
9120 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9122 else if (smbp->com == 0xa0) {
9124 * Serialize the handling for NT Transact
9127 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9128 thrd_SetEvent(SessionEvents[idx_session]);
9130 thrd_SetEvent(SessionEvents[idx_session]);
9131 /* TODO: what else needs to be serialized? */
9132 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9136 __except( smb_ServerExceptionFilter() ) {
9140 smb_concurrentCalls--;
9143 thrd_SetEvent(NCBavails[idx_NCB]);
9148 smb_FreePacket(outbufp);
9150 smb_FreeNCB(outncbp);
9154 * Exception filter for the server threads. If an exception occurs in the
9155 * dispatch routines, which is where exceptions are most common, then do a
9156 * force trace and give control to upstream exception handlers. Useful for
9159 DWORD smb_ServerExceptionFilter(void) {
9160 /* While this is not the best time to do a trace, if it succeeds, then
9161 * we have a trace (assuming tracing was enabled). Otherwise, this should
9162 * throw a second exception.
9164 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9165 afsd_ForceTrace(TRUE);
9166 buf_ForceTrace(TRUE);
9167 return EXCEPTION_CONTINUE_SEARCH;
9171 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9172 * If the number of server threads is M, and the number of live sessions is
9173 * N, then the number of NCB's in use at any time either waiting for, or
9174 * holding, received messages is M + N, so that is how many NCB's get created.
9176 void InitNCBslot(int idx)
9178 struct smb_packet *bufp;
9179 EVENT_HANDLE retHandle;
9181 char eventName[MAX_PATH];
9183 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9185 NCBs[idx] = smb_GetNCB();
9186 sprintf(eventName,"NCBavails[%d]", idx);
9187 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9188 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9189 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9190 sprintf(eventName,"NCBevents[%d]", idx);
9191 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9192 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9193 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9194 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9195 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9196 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9197 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9198 for (i=0; i<smb_NumServerThreads; i++)
9199 NCBreturns[i][idx] = retHandle;
9200 bufp = smb_GetPacket();
9201 bufp->spacep = cm_GetSpace();
9205 /* listen for new connections */
9206 void smb_Listener(void *parmp)
9212 afs_uint32 session, thread;
9213 smb_vc_t *vcp = NULL;
9215 char rname[NCBNAMSZ+1];
9216 char cname[MAX_COMPUTERNAME_LENGTH+1];
9217 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9218 INT_PTR lana = (INT_PTR) parmp;
9219 char eventName[MAX_PATH];
9220 int bridgeCount = 0;
9221 int nowildCount = 0;
9223 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9224 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9225 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9226 thrd_ResetEvent(ListenerShutdown[lana]);
9228 ncbp = smb_GetNCB();
9230 /* retrieve computer name */
9231 GetComputerName(cname, &cnamelen);
9234 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9235 memset(ncbp, 0, sizeof(NCB));
9238 ncbp->ncb_command = NCBLISTEN;
9239 ncbp->ncb_rto = 0; /* No receive timeout */
9240 ncbp->ncb_sto = 0; /* No send timeout */
9242 /* pad out with spaces instead of null termination */
9243 len = (long)strlen(smb_localNamep);
9244 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9245 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9247 strcpy(ncbp->ncb_callname, "*");
9248 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9250 ncbp->ncb_lana_num = (UCHAR)lana;
9252 code = Netbios(ncbp);
9254 if (code == NRC_NAMERR) {
9255 /* An smb shutdown or Vista resume must have taken place */
9257 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9258 ncbp->ncb_lana_num);
9259 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9261 if (lock_TryMutex(&smb_StartedLock)) {
9262 lana_list.lana[i] = LANA_INVALID;
9263 lock_ReleaseMutex(&smb_StartedLock);
9266 } else if (code == NRC_BRIDGE || code != 0) {
9267 int lanaRemaining = 0;
9269 if (code == NRC_BRIDGE) {
9270 if (++bridgeCount <= 5) {
9271 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9274 } else if (code == NRC_NOWILD) {
9275 if (++nowildCount <= 5) {
9276 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9278 if (bridgeCount > 0) {
9279 memset(ncbp, 0, sizeof(*ncbp));
9280 ncbp->ncb_command = NCBADDNAME;
9281 ncbp->ncb_lana_num = (UCHAR)lana;
9282 /* pad out with spaces instead of null termination */
9283 len = (long)strlen(smb_localNamep);
9284 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9285 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9286 code = Netbios(ncbp);
9292 while (!lock_TryMutex(&smb_StartedLock)) {
9293 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9299 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9300 ncbp->ncb_lana_num, ncb_error_string(code));
9301 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9302 ncbp->ncb_lana_num, ncb_error_string(code));
9304 for (i = 0; i < lana_list.length; i++) {
9305 if (lana_list.lana[i] == lana) {
9306 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9307 lana_list.lana[i] = LANA_INVALID;
9309 if (lana_list.lana[i] != LANA_INVALID)
9313 if (lanaRemaining == 0) {
9314 cm_VolStatus_Network_Stopped(cm_NetbiosName
9319 smb_ListenerState = SMB_LISTENER_STOPPED;
9320 smb_LANadapter = LANA_INVALID;
9321 lana_list.length = 0;
9323 lock_ReleaseMutex(&smb_StartedLock);
9327 else if (code != 0) {
9328 char tbuffer[AFSPATHMAX];
9330 /* terminate silently if shutdown flag is set */
9331 while (!lock_TryMutex(&smb_StartedLock)) {
9332 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9338 "NCBLISTEN lana=%d failed with code %d [%s]",
9339 ncbp->ncb_lana_num, code, ncb_error_string(code));
9341 "Client exiting due to network failure. Please restart client.\n");
9344 "Client exiting due to network failure. Please restart client.\n"
9345 "NCBLISTEN lana=%d failed with code %d [%s]",
9346 ncbp->ncb_lana_num, code, ncb_error_string(code));
9348 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9349 MB_OK|MB_SERVICE_NOTIFICATION);
9350 osi_panic(tbuffer, __FILE__, __LINE__);
9352 lock_ReleaseMutex(&smb_StartedLock);
9357 /* a successful packet received. clear bridge error count */
9361 /* check for remote conns */
9362 /* first get remote name and insert null terminator */
9363 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9364 for (i=NCBNAMSZ; i>0; i--) {
9365 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9371 /* compare with local name */
9373 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9374 flags |= SMB_VCFLAG_REMOTECONN;
9377 lock_ObtainMutex(&smb_ListenerLock);
9379 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9380 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9382 /* now ncbp->ncb_lsn is the connection ID */
9383 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9384 if (vcp->session == 0) {
9385 /* New generation */
9386 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9389 /* Log session startup */
9391 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9392 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9393 #endif /* NOTSERVICE */
9394 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9395 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9397 if (reportSessionStartups) {
9398 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9401 lock_ObtainMutex(&vcp->mx);
9402 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9403 vcp->flags |= flags;
9404 lock_ReleaseMutex(&vcp->mx);
9406 /* Allocate slot in session arrays */
9407 /* Re-use dead session if possible, otherwise add one more */
9408 /* But don't look at session[0], it is reserved */
9409 lock_ObtainWrite(&smb_globalLock);
9410 for (session = 1; session < numSessions; session++) {
9411 if (dead_sessions[session]) {
9412 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9413 dead_sessions[session] = FALSE;
9417 lock_ReleaseWrite(&smb_globalLock);
9419 /* We are re-using an existing VC because the lsn and lana
9421 session = vcp->session;
9423 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9425 /* Log session startup */
9427 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9428 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9429 #endif /* NOTSERVICE */
9430 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9431 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9433 if (reportSessionStartups) {
9434 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9438 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9439 unsigned long code = CM_ERROR_ALLBUSY;
9440 smb_packet_t * outp = smb_GetPacket();
9441 unsigned char *outWctp;
9444 smb_FormatResponsePacket(vcp, NULL, outp);
9447 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9448 unsigned long NTStatus;
9449 smb_MapNTError(code, &NTStatus);
9450 outWctp = outp->wctp;
9451 smbp = (smb_t *) &outp->data;
9455 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9456 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9457 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9458 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9459 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9461 unsigned short errCode;
9462 unsigned char errClass;
9463 smb_MapCoreError(code, vcp, &errCode, &errClass);
9464 outWctp = outp->wctp;
9465 smbp = (smb_t *) &outp->data;
9469 smbp->errLow = (unsigned char) (errCode & 0xff);
9470 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9471 smbp->rcls = errClass;
9474 smb_SendPacket(vcp, outp);
9475 smb_FreePacket(outp);
9477 lock_ObtainMutex(&vcp->mx);
9478 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9479 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9481 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9482 lock_ReleaseMutex(&vcp->mx);
9483 lock_ObtainWrite(&smb_globalLock);
9484 dead_sessions[vcp->session] = TRUE;
9485 lock_ReleaseWrite(&smb_globalLock);
9486 smb_CleanupDeadVC(vcp);
9488 lock_ReleaseMutex(&vcp->mx);
9491 /* assert that we do not exceed the maximum number of sessions or NCBs.
9492 * we should probably want to wait for a session to be freed in case
9495 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9496 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9498 lock_ObtainMutex(&vcp->mx);
9499 vcp->session = session;
9500 lock_ReleaseMutex(&vcp->mx);
9501 lock_ObtainWrite(&smb_globalLock);
9502 LSNs[session] = ncbp->ncb_lsn;
9503 lanas[session] = ncbp->ncb_lana_num;
9504 lock_ReleaseWrite(&smb_globalLock);
9506 if (session == numSessions) {
9507 /* Add new NCB for new session */
9508 char eventName[MAX_PATH];
9510 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9512 InitNCBslot(numNCBs);
9513 lock_ObtainWrite(&smb_globalLock);
9515 lock_ReleaseWrite(&smb_globalLock);
9516 thrd_SetEvent(NCBavails[0]);
9517 thrd_SetEvent(NCBevents[0]);
9518 for (thread = 0; thread < smb_NumServerThreads; thread++)
9519 thrd_SetEvent(NCBreturns[thread][0]);
9520 /* Also add new session event */
9521 sprintf(eventName, "SessionEvents[%d]", session);
9522 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9523 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9524 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9525 lock_ObtainWrite(&smb_globalLock);
9527 lock_ReleaseWrite(&smb_globalLock);
9528 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9529 thrd_SetEvent(SessionEvents[0]);
9531 thrd_SetEvent(SessionEvents[session]);
9537 lock_ReleaseMutex(&smb_ListenerLock);
9538 } /* dispatch while loop */
9542 thrd_SetEvent(ListenerShutdown[lana]);
9547 configureBackConnectionHostNames(void)
9549 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9550 * there is a restriction on the use of SMB authentication on loopback connections.
9551 * There are two work arounds available:
9553 * (1) We can disable the check for matching host names. This does not
9555 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9556 * "DisableLoopbackCheck"=dword:00000001
9558 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9559 * does require a reboot:
9560 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9561 * "BackConnectionHostNames"=multi-sz
9563 * The algorithm will be:
9564 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9565 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9566 * (2b1) and check to see if DisableLoopbackCheck is set.
9567 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9568 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9569 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9570 * check for the UnsetDisableLoopbackCheck value.
9571 * If set, set the DisableLoopbackCheck flag to 0x0
9572 * and delete the UnsetDisableLoopbackCheck value
9574 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9575 * force Windows to use the loopback authentication mechanism for the specified
9578 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9579 * service session that set it.
9585 DWORD dwSize, dwAllocSize;
9587 PBYTE pHostNames = NULL, pName = NULL;
9588 BOOL bNameFound = FALSE;
9589 static BOOL bLoopbackCheckDisabled = FALSE;
9591 /* BackConnectionHostNames and DisableLoopbackCheck */
9592 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9593 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9596 &hkMSV10) == ERROR_SUCCESS )
9598 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9599 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9600 (dwType == REG_MULTI_SZ))
9602 dwAllocSize += 1 /* in case the source string is not nul terminated */
9603 + (DWORD)strlen(cm_NetbiosName) + 2;
9604 pHostNames = malloc(dwAllocSize);
9605 dwSize = dwAllocSize;
9606 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9607 pHostNames, &dwSize) == ERROR_SUCCESS)
9609 for (pName = pHostNames;
9610 (pName - pHostNames < (int) dwSize) && *pName ;
9611 pName += strlen(pName) + 1)
9613 if ( !stricmp(pName, cm_NetbiosName) ) {
9621 if ( !bNameFound ) {
9622 size_t size = strlen(cm_NetbiosName) + 2;
9623 if ( !pHostNames ) {
9624 pHostNames = malloc(size);
9627 StringCbCopyA(pName, size, cm_NetbiosName);
9629 *pName = '\0'; /* add a second nul terminator */
9631 dwType = REG_MULTI_SZ;
9632 dwSize = (DWORD)(pName - pHostNames + 1);
9633 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9635 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9636 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9639 &hkLsa) == ERROR_SUCCESS )
9641 dwSize = sizeof(DWORD);
9642 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9645 dwSize = sizeof(DWORD);
9647 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9649 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9650 AFSREG_CLT_OPENAFS_SUBKEY,
9653 REG_OPTION_NON_VOLATILE,
9657 NULL) == ERROR_SUCCESS) {
9660 dwSize = sizeof(DWORD);
9662 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9663 bLoopbackCheckDisabled = TRUE;
9664 RegCloseKey(hkClient);
9669 } else if (!bLoopbackCheckDisabled) {
9670 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9671 AFSREG_CLT_OPENAFS_SUBKEY,
9674 REG_OPTION_NON_VOLATILE,
9678 NULL) == ERROR_SUCCESS) {
9680 dwSize = sizeof(DWORD);
9681 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9683 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9684 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9687 &hkLsa) == ERROR_SUCCESS )
9689 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9693 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9694 RegCloseKey(hkClient);
9703 RegCloseKey(hkMSV10);
9709 configureExtendedSMBSessionTimeouts(void)
9712 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9713 * new functionality:
9715 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9716 * "ReconnectableServers" REG_MULTI_SZ
9717 * "ExtendedSessTimeout" REG_DWORD (seconds)
9718 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
9720 * These values can be used to prevent the smb redirector from timing out
9721 * smb connection to the afs smb server prematurely.
9725 DWORD dwSize, dwAllocSize;
9727 PBYTE pHostNames = NULL, pName = NULL;
9728 BOOL bNameFound = FALSE;
9730 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9731 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9734 &hkLanMan) == ERROR_SUCCESS )
9736 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
9737 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9738 (dwType == REG_MULTI_SZ))
9740 dwAllocSize += 1 /* in case the source string is not nul terminated */
9741 + (DWORD)strlen(cm_NetbiosName) + 2;
9742 pHostNames = malloc(dwAllocSize);
9743 dwSize = dwAllocSize;
9744 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
9745 pHostNames, &dwSize) == ERROR_SUCCESS)
9747 for (pName = pHostNames;
9748 (pName - pHostNames < (int) dwSize) && *pName ;
9749 pName += strlen(pName) + 1)
9751 if ( !stricmp(pName, cm_NetbiosName) ) {
9759 if ( !bNameFound ) {
9760 size_t size = strlen(cm_NetbiosName) + 2;
9761 if ( !pHostNames ) {
9762 pHostNames = malloc(size);
9765 StringCbCopyA(pName, size, cm_NetbiosName);
9767 *pName = '\0'; /* add a second nul terminator */
9769 dwType = REG_MULTI_SZ;
9770 dwSize = (DWORD)(pName - pHostNames + 1);
9771 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9779 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
9780 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9781 (dwType == REG_MULTI_SZ))
9783 dwAllocSize += 1 /* in case the source string is not nul terminated */
9784 + (DWORD)strlen(cm_NetbiosName) + 2;
9785 pHostNames = malloc(dwAllocSize);
9786 dwSize = dwAllocSize;
9787 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
9788 pHostNames, &dwSize) == ERROR_SUCCESS)
9790 for (pName = pHostNames;
9791 (pName - pHostNames < (int) dwSize) && *pName ;
9792 pName += strlen(pName) + 1)
9794 if ( !stricmp(pName, cm_NetbiosName) ) {
9802 if ( !bNameFound ) {
9803 size_t size = strlen(cm_NetbiosName) + 2;
9804 if ( !pHostNames ) {
9805 pHostNames = malloc(size);
9808 StringCbCopyA(pName, size, cm_NetbiosName);
9810 *pName = '\0'; /* add a second nul terminator */
9812 dwType = REG_MULTI_SZ;
9813 dwSize = (DWORD)(pName - pHostNames + 1);
9814 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9822 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
9823 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9824 (dwType != REG_DWORD))
9827 dwSize = sizeof(dwValue);
9828 dwValue = 300; /* 5 minutes */
9829 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9831 RegCloseKey(hkLanMan);
9836 smb_LanAdapterChangeThread(void *param)
9839 * Give the IPAddrDaemon thread a chance
9840 * to block before we trigger.
9843 smb_LanAdapterChange(0);
9846 void smb_SetLanAdapterChangeDetected(void)
9851 lock_ObtainMutex(&smb_StartedLock);
9853 if (!powerStateSuspended) {
9854 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9855 NULL, 0, &lpid, "smb_LanAdapterChange");
9856 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9857 thrd_CloseHandle(phandle);
9860 smb_LanAdapterChangeDetected = 1;
9861 lock_ReleaseMutex(&smb_StartedLock);
9864 void smb_LanAdapterChange(int locked) {
9865 lana_number_t lanaNum;
9867 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9869 LANA_ENUM temp_list;
9874 afsi_log("smb_LanAdapterChange");
9877 lock_ObtainMutex(&smb_StartedLock);
9879 smb_LanAdapterChangeDetected = 0;
9881 if (!powerStateSuspended &&
9882 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9883 LANA_NETBIOS_NAME_FULL)) &&
9884 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9885 if ( isGateway != bGateway ) {
9886 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9887 smb_LANadapter, lanaNum, isGateway, bGateway);
9889 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9890 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9891 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9894 NCB *ncbp = smb_GetNCB();
9895 ncbp->ncb_command = NCBENUM;
9896 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9897 ncbp->ncb_length = sizeof(temp_list);
9898 code = Netbios(ncbp);
9900 if (temp_list.length != lana_list.length) {
9901 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9902 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9905 for (i=0; i<lana_list.length; i++) {
9906 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9907 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9908 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9920 smb_StopListeners(1);
9921 smb_RestartListeners(1);
9924 lock_ReleaseMutex(&smb_StartedLock);
9927 /* initialize Netbios */
9928 int smb_NetbiosInit(int locked)
9931 int i, lana, code, l;
9933 int delname_tried=0;
9936 lana_number_t lanaNum;
9939 lock_ObtainMutex(&smb_StartedLock);
9941 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9942 smb_ListenerState != SMB_LISTENER_STOPPED) {
9945 lock_ReleaseMutex(&smb_StartedLock);
9948 /* setup the NCB system */
9949 ncbp = smb_GetNCB();
9951 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9952 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9953 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9955 if (smb_LANadapter != LANA_INVALID)
9956 afsi_log("LAN adapter number %d", smb_LANadapter);
9958 afsi_log("LAN adapter number not determined");
9961 afsi_log("Set for gateway service");
9963 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9965 /* something went horribly wrong. We can't proceed without a netbios name */
9967 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9968 osi_panic(buf, __FILE__, __LINE__);
9971 /* remember the name */
9972 len = (int)strlen(cm_NetbiosName);
9974 free(smb_localNamep);
9975 smb_localNamep = malloc(len+1);
9976 strcpy(smb_localNamep, cm_NetbiosName);
9977 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9979 /* Also copy the value to the client character encoded string */
9980 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9982 if (smb_LANadapter == LANA_INVALID) {
9983 ncbp->ncb_command = NCBENUM;
9984 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9985 ncbp->ncb_length = sizeof(lana_list);
9986 code = Netbios(ncbp);
9988 afsi_log("Netbios NCBENUM error code %d", code);
9989 osi_panic(s, __FILE__, __LINE__);
9993 lana_list.length = 1;
9994 lana_list.lana[0] = smb_LANadapter;
9997 for (i = 0; i < lana_list.length; i++) {
9998 /* reset the adaptor: in Win32, this is required for every process, and
9999 * acts as an init call, not as a real hardware reset.
10001 ncbp->ncb_command = NCBRESET;
10002 ncbp->ncb_callname[0] = 100;
10003 ncbp->ncb_callname[2] = 100;
10004 ncbp->ncb_lana_num = lana_list.lana[i];
10005 code = Netbios(ncbp);
10007 code = ncbp->ncb_retcode;
10009 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10010 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10012 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10016 /* and declare our name so we can receive connections */
10017 memset(ncbp, 0, sizeof(*ncbp));
10018 len=lstrlen(smb_localNamep);
10019 memset(smb_sharename,' ',NCBNAMSZ);
10020 memcpy(smb_sharename,smb_localNamep,len);
10021 afsi_log("lana_list.length %d", lana_list.length);
10023 /* Keep the name so we can unregister it later */
10024 for (l = 0; l < lana_list.length; l++) {
10025 lana = lana_list.lana[l];
10027 ncbp->ncb_command = NCBADDNAME;
10028 ncbp->ncb_lana_num = lana;
10029 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10030 code = Netbios(ncbp);
10032 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10033 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10035 char name[NCBNAMSZ+1];
10037 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10038 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10042 code = ncbp->ncb_retcode;
10045 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10048 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10049 if (code == NRC_BRIDGE) { /* invalid LANA num */
10050 lana_list.lana[l] = LANA_INVALID;
10053 else if (code == NRC_DUPNAME) {
10054 afsi_log("Name already exists; try to delete it");
10055 memset(ncbp, 0, sizeof(*ncbp));
10056 ncbp->ncb_command = NCBDELNAME;
10057 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10058 ncbp->ncb_lana_num = lana;
10059 code = Netbios(ncbp);
10061 code = ncbp->ncb_retcode;
10063 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10065 if (code != 0 || delname_tried) {
10066 lana_list.lana[l] = LANA_INVALID;
10068 else if (code == 0) {
10069 if (!delname_tried) {
10077 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10078 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10082 smb_LANadapter = lana;
10083 lana_found = 1; /* at least one worked */
10087 osi_assertx(lana_list.length >= 0, "empty lana list");
10089 afsi_log("No valid LANA numbers found!");
10090 lana_list.length = 0;
10091 smb_LANadapter = LANA_INVALID;
10092 smb_ListenerState = SMB_LISTENER_STOPPED;
10093 cm_VolStatus_Network_Stopped(cm_NetbiosName
10100 /* we're done with the NCB now */
10103 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10104 if (lana_list.length > 0)
10105 osi_assert(smb_LANadapter != LANA_INVALID);
10108 lock_ReleaseMutex(&smb_StartedLock);
10110 return (lana_list.length > 0 ? 1 : 0);
10113 void smb_StartListeners(int locked)
10120 lock_ObtainMutex(&smb_StartedLock);
10122 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10124 lock_ReleaseMutex(&smb_StartedLock);
10128 afsi_log("smb_StartListeners");
10129 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10130 configureBackConnectionHostNames();
10132 /* Configure Extended SMB Session Timeouts */
10133 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10134 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10135 configureExtendedSMBSessionTimeouts();
10138 smb_ListenerState = SMB_LISTENER_STARTED;
10139 cm_VolStatus_Network_Started(cm_NetbiosName
10145 for (i = 0; i < lana_list.length; i++) {
10146 if (lana_list.lana[i] == LANA_INVALID)
10148 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10149 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10150 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10151 thrd_CloseHandle(phandle);
10154 lock_ReleaseMutex(&smb_StartedLock);
10157 void smb_RestartListeners(int locked)
10160 lock_ObtainMutex(&smb_StartedLock);
10162 if (powerStateSuspended)
10163 afsi_log("smb_RestartListeners called while suspended");
10165 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10166 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10167 if (smb_NetbiosInit(1))
10168 smb_StartListeners(1);
10169 } else if (smb_LanAdapterChangeDetected) {
10170 smb_LanAdapterChange(1);
10174 lock_ReleaseMutex(&smb_StartedLock);
10177 void smb_StopListener(NCB *ncbp, int lana, int wait)
10181 memset(ncbp, 0, sizeof(*ncbp));
10182 ncbp->ncb_command = NCBDELNAME;
10183 ncbp->ncb_lana_num = lana;
10184 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10185 code = Netbios(ncbp);
10187 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10188 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10190 /* and then reset the LANA; this will cause the listener threads to exit */
10191 ncbp->ncb_command = NCBRESET;
10192 ncbp->ncb_callname[0] = 100;
10193 ncbp->ncb_callname[2] = 100;
10194 ncbp->ncb_lana_num = lana;
10195 code = Netbios(ncbp);
10197 code = ncbp->ncb_retcode;
10199 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10201 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10205 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10208 void smb_StopListeners(int locked)
10214 lock_ObtainMutex(&smb_StartedLock);
10216 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10218 lock_ReleaseMutex(&smb_StartedLock);
10222 afsi_log("smb_StopListeners");
10223 smb_ListenerState = SMB_LISTENER_STOPPED;
10224 cm_VolStatus_Network_Stopped(cm_NetbiosName
10230 ncbp = smb_GetNCB();
10232 /* Unregister the SMB name */
10233 for (l = 0; l < lana_list.length; l++) {
10234 lana = lana_list.lana[l];
10236 if (lana != LANA_INVALID) {
10237 smb_StopListener(ncbp, lana, TRUE);
10239 /* mark the adapter invalid */
10240 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10244 /* force a re-evaluation of the network adapters */
10245 lana_list.length = 0;
10246 smb_LANadapter = LANA_INVALID;
10249 lock_ReleaseMutex(&smb_StartedLock);
10252 void smb_Init(osi_log_t *logp, int useV3,
10262 EVENT_HANDLE retHandle;
10263 char eventName[MAX_PATH];
10264 int startListeners = 0;
10266 smb_MBfunc = aMBfunc;
10270 /* Initialize smb_localZero */
10271 myTime.tm_isdst = -1; /* compute whether on DST or not */
10272 myTime.tm_year = 70;
10274 myTime.tm_mday = 1;
10275 myTime.tm_hour = 0;
10278 smb_localZero = mktime(&myTime);
10280 #ifdef AFS_FREELANCE_CLIENT
10281 /* Make sure the root.afs volume has the correct time */
10282 cm_noteLocalMountPointChange();
10285 /* initialize the remote debugging log */
10288 /* and the global lock */
10289 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10290 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10292 /* Raw I/O data structures */
10293 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10295 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10296 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10298 /* 4 Raw I/O buffers */
10299 smb_RawBufs = calloc(65536,1);
10300 *((char **)smb_RawBufs) = NULL;
10301 for (i=0; i<3; i++) {
10302 char *rawBuf = calloc(65536,1);
10303 *((char **)rawBuf) = smb_RawBufs;
10304 smb_RawBufs = rawBuf;
10307 /* global free lists */
10308 smb_ncbFreeListp = NULL;
10309 smb_packetFreeListp = NULL;
10311 lock_ObtainMutex(&smb_StartedLock);
10312 startListeners = smb_NetbiosInit(1);
10314 /* Initialize listener and server structures */
10316 memset(dead_sessions, 0, sizeof(dead_sessions));
10317 sprintf(eventName, "SessionEvents[0]");
10318 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10319 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10320 afsi_log("Event Object Already Exists: %s", eventName);
10322 smb_NumServerThreads = nThreads;
10323 sprintf(eventName, "NCBavails[0]");
10324 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10325 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10326 afsi_log("Event Object Already Exists: %s", eventName);
10327 sprintf(eventName, "NCBevents[0]");
10328 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10329 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10330 afsi_log("Event Object Already Exists: %s", eventName);
10331 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10332 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10333 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10334 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10335 afsi_log("Event Object Already Exists: %s", eventName);
10336 for (i = 0; i < smb_NumServerThreads; i++) {
10337 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10338 NCBreturns[i][0] = retHandle;
10341 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10342 for (i = 0; i < smb_NumServerThreads; i++) {
10343 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10344 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10345 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10346 afsi_log("Event Object Already Exists: %s", eventName);
10347 InitNCBslot((int)(i+1));
10349 numNCBs = smb_NumServerThreads + 1;
10351 /* Initialize dispatch table */
10352 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10353 /* Prepare the table for unknown operations */
10354 for(i=0; i<= SMB_NOPCODES; i++) {
10355 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10357 /* Fill in the ones we do know */
10358 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10359 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10360 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10361 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10362 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10363 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10364 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10365 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10366 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10367 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10368 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10369 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10370 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10371 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10372 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10373 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10374 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10375 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10376 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10377 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10378 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10379 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10380 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10381 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10382 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10383 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10384 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10385 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10386 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10387 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10388 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10389 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10390 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10391 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10392 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10393 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10394 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10395 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10396 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10397 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10398 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10399 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10400 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10401 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10402 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10403 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10404 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10405 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10406 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10407 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10408 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10409 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10410 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10411 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10412 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10413 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10414 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10415 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10416 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10417 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10418 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10419 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10420 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10421 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10422 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10423 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10424 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10425 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10426 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10427 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10428 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10429 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10430 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10431 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10433 /* setup tran 2 dispatch table */
10434 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10435 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10436 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10437 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10438 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10439 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10440 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10441 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10442 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10443 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10444 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10445 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10446 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10447 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10448 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10449 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10450 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10451 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10453 /* setup the rap dispatch table */
10454 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10455 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10456 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10457 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10458 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10462 /* if we are doing SMB authentication we have register outselves as a logon process */
10463 if (smb_authType != SMB_AUTH_NONE) {
10464 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10465 LSA_STRING afsProcessName;
10466 LSA_OPERATIONAL_MODE dummy; /*junk*/
10468 afsProcessName.Buffer = "OpenAFSClientDaemon";
10469 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10470 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10472 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10474 if (nts == STATUS_SUCCESS) {
10475 LSA_STRING packageName;
10476 /* we are registered. Find out the security package id */
10477 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10478 packageName.Length = (USHORT)strlen(packageName.Buffer);
10479 packageName.MaximumLength = packageName.Length + 1;
10480 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10481 if (nts == STATUS_SUCCESS) {
10483 * This code forces Windows to authenticate against the Logon Cache
10484 * first instead of attempting to authenticate against the Domain
10485 * Controller. When the Windows logon cache is enabled this improves
10486 * performance by removing the network access and works around a bug
10487 * seen at sites which are using a MIT Kerberos principal to login
10488 * to machines joined to a non-root domain in a multi-domain forest.
10489 * MsV1_0SetProcessOption was added in Windows XP.
10491 PVOID pResponse = NULL;
10492 ULONG cbResponse = 0;
10493 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10495 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10496 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10497 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10498 OptionsRequest.DisableOptions = FALSE;
10500 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10503 sizeof(OptionsRequest),
10509 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10510 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10513 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10515 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10516 afsi_log("MsV1_0SetProcessOption success");
10518 /* END - code from Larry */
10520 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10521 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10522 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10524 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10526 /* something went wrong. We report the error and revert back to no authentication
10527 because we can't perform any auth requests without a successful lsa handle
10528 or sec package id. */
10529 afsi_log("Reverting to NO SMB AUTH");
10530 smb_authType = SMB_AUTH_NONE;
10533 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10535 /* something went wrong. We report the error and revert back to no authentication
10536 because we can't perform any auth requests without a successful lsa handle
10537 or sec package id. */
10538 afsi_log("Reverting to NO SMB AUTH");
10539 smb_authType = SMB_AUTH_NONE;
10543 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10544 * time prevents the failure of authentication when logged into Windows with an
10545 * external Kerberos principal mapped to a local account.
10547 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10548 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10549 * then the only option is NTLMSSP anyway; so just fallback.
10554 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10555 if (secBlobLength == 0) {
10556 smb_authType = SMB_AUTH_NTLM;
10557 afsi_log("Reverting to SMB AUTH NTLM");
10566 /* Now get ourselves a domain name. */
10567 /* For now we are using the local computer name as the domain name.
10568 * It is actually the domain for local logins, and we are acting as
10569 * a local SMB server.
10571 bufsize = lengthof(smb_ServerDomainName) - 1;
10572 GetComputerNameW(smb_ServerDomainName, &bufsize);
10573 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10574 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10577 /* Start listeners, waiters, servers, and daemons */
10578 if (startListeners)
10579 smb_StartListeners(1);
10581 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10582 NULL, 0, &lpid, "smb_ClientWaiter");
10583 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10584 thrd_CloseHandle(phandle);
10586 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10587 NULL, 0, &lpid, "smb_ServerWaiter");
10588 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10589 thrd_CloseHandle(phandle);
10591 for (i=0; i<smb_NumServerThreads; i++) {
10592 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10593 (void *) i, 0, &lpid, "smb_Server");
10594 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10595 thrd_CloseHandle(phandle);
10598 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10599 NULL, 0, &lpid, "smb_Daemon");
10600 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10601 thrd_CloseHandle(phandle);
10603 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10604 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10605 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10606 thrd_CloseHandle(phandle);
10608 lock_ReleaseMutex(&smb_StartedLock);
10612 void smb_Shutdown(void)
10619 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10621 /* setup the NCB system */
10622 ncbp = smb_GetNCB();
10624 /* Block new sessions by setting shutdown flag */
10625 smbShutdownFlag = 1;
10627 /* Hang up all sessions */
10628 memset(ncbp, 0, sizeof(NCB));
10629 for (i = 1; i < numSessions; i++)
10631 if (dead_sessions[i])
10634 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10635 ncbp->ncb_command = NCBHANGUP;
10636 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10637 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10638 code = Netbios(ncbp);
10639 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10640 if (code == 0) code = ncbp->ncb_retcode;
10642 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10643 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10647 /* Trigger the shutdown of all SMB threads */
10648 for (i = 0; i < smb_NumServerThreads; i++)
10649 thrd_SetEvent(NCBreturns[i][0]);
10651 thrd_SetEvent(NCBevents[0]);
10652 thrd_SetEvent(SessionEvents[0]);
10653 thrd_SetEvent(NCBavails[0]);
10655 for (i = 0;i < smb_NumServerThreads; i++) {
10656 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10657 if (code == WAIT_OBJECT_0) {
10660 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10661 thrd_SetEvent(NCBreturns[i--][0]);
10665 /* Delete Netbios name */
10666 memset(ncbp, 0, sizeof(NCB));
10667 for (i = 0; i < lana_list.length; i++) {
10668 if (lana_list.lana[i] == LANA_INVALID) continue;
10669 ncbp->ncb_command = NCBDELNAME;
10670 ncbp->ncb_lana_num = lana_list.lana[i];
10671 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10672 code = Netbios(ncbp);
10674 code = ncbp->ncb_retcode;
10676 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10677 ncbp->ncb_lana_num, code);
10682 /* Release the reference counts held by the VCs */
10683 lock_ObtainWrite(&smb_rctLock);
10684 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10689 if (vcp->magic != SMB_VC_MAGIC)
10690 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10691 __FILE__, __LINE__);
10693 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10695 if (fidp->scp != NULL) {
10698 lock_ReleaseWrite(&smb_rctLock);
10699 lock_ObtainMutex(&fidp->mx);
10700 if (fidp->scp != NULL) {
10703 lock_ObtainWrite(&scp->rw);
10704 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10705 lock_ReleaseWrite(&scp->rw);
10706 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10707 cm_ReleaseSCache(scp);
10709 lock_ReleaseMutex(&fidp->mx);
10710 lock_ObtainWrite(&smb_rctLock);
10714 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10716 smb_ReleaseVCNoLock(tidp->vcp);
10718 cm_user_t *userp = tidp->userp;
10719 tidp->userp = NULL;
10720 cm_ReleaseUser(userp);
10724 lock_ReleaseWrite(&smb_rctLock);
10728 /* Get the UNC \\<servername>\<sharename> prefix. */
10729 char *smb_GetSharename()
10734 /* Make sure we have been properly initialized. */
10735 if (smb_localNamep == NULL)
10738 /* Allocate space for \\<servername>\<sharename>, plus the
10741 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10742 name = malloc(len);
10743 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10749 void smb_LogPacket(smb_packet_t *packet)
10753 unsigned length, paramlen, datalen, i, j;
10755 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10757 if (!packet) return;
10759 osi_Log0(smb_logp, "*** SMB packet dump ***");
10761 smbp = (smb_t *) packet->data;
10762 vp = (BYTE *) packet->data;
10764 paramlen = smbp->wct * 2;
10765 datalen = *((WORD *) (smbp->vdata + paramlen));
10766 length = sizeof(*smbp) + paramlen + 1 + datalen;
10768 for (i=0;i < length; i+=16)
10770 memset( buf, ' ', 80 );
10773 itoa( i, buf, 16 );
10775 buf[strlen(buf)] = ' ';
10777 cp = (BYTE*) buf + 7;
10779 for (j=0;j < 16 && (i+j)<length; j++)
10781 *(cp++) = hex[vp[i+j] >> 4];
10782 *(cp++) = hex[vp[i+j] & 0xf];
10792 for (j=0;j < 16 && (i+j)<length;j++)
10794 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10805 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10808 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10810 #endif /* LOG_PACKET */
10813 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10819 smb_username_t *unp;
10820 smb_waitingLockRequest_t *wlrp;
10823 lock_ObtainRead(&smb_rctLock);
10825 sprintf(output, "begin dumping smb_username_t\r\n");
10826 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10827 for (unp = usernamesp; unp; unp=unp->nextp)
10829 cm_ucell_t *ucellp;
10831 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10832 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10833 unp->name ? unp->name : _C("NULL"),
10834 unp->machine ? unp->machine : _C("NULL"));
10835 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10837 sprintf(output, " begin dumping cm_ucell_t\r\n");
10838 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10840 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10841 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",
10842 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10843 ucellp->expirationTime, ucellp->gen,
10845 ucellp->cellp->name);
10846 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10849 sprintf(output, " done dumping cm_ucell_t\r\n");
10850 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10853 sprintf(output, "done dumping smb_username_t\r\n");
10854 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10857 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10858 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10861 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10862 smb_waitingLock_t *lockp;
10864 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10865 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10866 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10868 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10869 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10870 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10871 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10872 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10873 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10875 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10876 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10879 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10880 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10882 sprintf(output, "begin dumping smb_vc_t\r\n");
10883 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10885 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10891 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10892 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10893 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10895 sprintf(output, " begin dumping smb_user_t\r\n");
10896 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10897 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10898 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10899 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10900 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10902 sprintf(output, " done dumping smb_user_t\r\n");
10903 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10905 sprintf(output, " begin dumping smb_tid_t\r\n");
10906 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10907 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10908 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",
10909 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10910 tidp->pathname ? tidp->pathname : _C("NULL"));
10911 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10913 sprintf(output, " done dumping smb_tid_t\r\n");
10914 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10916 sprintf(output, " begin dumping smb_fid_t\r\n");
10917 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10919 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10921 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",
10922 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10923 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10924 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10925 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10928 sprintf(output, " done dumping smb_fid_t\r\n");
10929 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10932 sprintf(output, "done dumping smb_vc_t\r\n");
10933 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10935 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10936 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10938 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10944 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10945 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10946 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10948 sprintf(output, " begin dumping smb_user_t\r\n");
10949 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10950 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10951 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10952 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10953 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10955 sprintf(output, " done dumping smb_user_t\r\n");
10956 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10958 sprintf(output, " begin dumping smb_tid_t\r\n");
10959 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10960 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10961 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",
10962 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10963 tidp->pathname ? tidp->pathname : _C("NULL"));
10964 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10966 sprintf(output, " done dumping smb_tid_t\r\n");
10967 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10969 sprintf(output, " begin dumping smb_fid_t\r\n");
10970 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10972 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10974 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",
10975 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10976 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10977 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10978 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10981 sprintf(output, " done dumping smb_fid_t\r\n");
10982 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10985 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10986 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10989 lock_ReleaseRead(&smb_rctLock);
10993 long smb_IsNetworkStarted(void)
10996 lock_ObtainWrite(&smb_globalLock);
10997 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10998 lock_ReleaseWrite(&smb_globalLock);