2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
33 #include "lanahelper.h"
35 #define STRSAFE_NO_DEPRECATE
38 /* These characters are illegal in Windows filenames */
39 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
41 static int smbShutdownFlag = 0;
42 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
44 int smb_LogoffTokenTransfer;
45 time_t smb_LogoffTransferTimeout;
47 int smb_StoreAnsiFilenames = 0;
49 DWORD last_msg_time = 0;
53 unsigned int sessionGen = 0;
55 extern void afsi_log(char *pattern, ...);
56 extern HANDLE afsi_file;
57 extern int powerStateSuspended;
59 osi_hyper_t hzero = {0, 0};
60 osi_hyper_t hones = {0xFFFFFFFF, -1};
63 osi_rwlock_t smb_globalLock;
64 osi_rwlock_t smb_rctLock;
65 osi_mutex_t smb_ListenerLock;
66 osi_mutex_t smb_StartedLock;
68 unsigned char smb_LANadapter = LANA_INVALID;
69 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
70 int smb_LanAdapterChangeDetected = 0;
71 afs_uint32 smb_AsyncStore = 1;
72 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
74 BOOL isGateway = FALSE;
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
85 afs_uint32 smb_NumServerThreads;
87 afs_uint32 numNCBs, numSessions, numVCs;
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
92 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
94 ULONG smb_lsaSecPackage;
95 LSA_STRING smb_lsaLogonOrigin;
97 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
99 EVENT_HANDLE **NCBreturns;
100 EVENT_HANDLE **NCBShutdown;
101 EVENT_HANDLE *smb_ServerShutdown;
102 EVENT_HANDLE ListenerShutdown[256];
103 DWORD NCBsessions[NCB_MAX];
105 struct smb_packet *bufs[NCB_MAX];
107 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
108 EVENT_HANDLE SessionEvents[SESSION_MAX];
109 unsigned short LSNs[SESSION_MAX];
110 int lanas[SESSION_MAX];
111 BOOL dead_sessions[SESSION_MAX];
114 osi_mutex_t smb_RawBufLock;
117 #define SMB_MASKFLAG_TILDE 1
118 #define SMB_MASKFLAG_CASEFOLD 2
120 #define RAWTIMEOUT INFINITE
123 typedef struct raw_write_cont {
132 /* dir search stuff */
133 long smb_dirSearchCounter = 1;
134 smb_dirSearch_t *smb_firstDirSearchp;
135 smb_dirSearch_t *smb_lastDirSearchp;
137 /* hide dot files? */
138 int smb_hideDotFiles;
140 /* Negotiate Unicode support? */
143 /* global state about V3 protocols */
144 int smb_useV3; /* try to negotiate V3 */
146 static int showErrors = 0;
147 /* MessageBox or something like it */
148 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
152 * Time in Unix format of midnight, 1/1/1970 local time.
153 * When added to dosUTime, gives Unix (AFS) time.
155 time_t smb_localZero = 0;
157 char *smb_localNamep = NULL;
159 smb_vc_t *smb_allVCsp;
160 smb_vc_t *smb_deadVCsp;
162 smb_username_t *usernamesp = NULL;
164 smb_waitingLockRequest_t *smb_allWaitingLocks;
167 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
168 NCB *ncbp, raw_write_cont_t *rwcp);
169 int smb_NetbiosInit(int);
172 void smb_LogPacket(smb_packet_t *packet);
173 #endif /* LOG_PACKET */
175 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
176 int smb_ServerDomainNameLength = 0;
177 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
178 int smb_ServerOSLength = lengthof(smb_ServerOS);
179 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
180 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
182 /* Faux server GUID. This is never checked. */
183 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
185 void smb_InitReq(cm_req_t *reqp)
188 reqp->flags |= CM_REQ_SOURCE_SMB;
191 const char * ncb_error_string(int code)
195 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
196 case 0x03: s = "NRC_ILLCMD illegal command"; break;
197 case 0x05: s = "NRC_CMDTMO command timed out"; break;
198 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
199 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
200 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
201 case 0x09: s = "NRC_NORES no resource available"; break;
202 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
203 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
204 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
205 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
206 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
207 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
208 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
209 case 0x13: s = "NRC_ILLNN illegal name number"; break;
210 case 0x14: s = "NRC_NOCALL no callname"; break;
211 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
212 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
213 case 0x17: s = "NRC_NAMERR name deleted"; break;
214 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
215 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
216 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
217 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
218 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
219 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
220 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
221 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
222 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
223 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
224 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
225 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
226 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
227 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
228 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
229 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
230 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
231 case 0x40: s = "NRC_SYSTEM system error"; break;
232 default: s = "unknown error";
238 char * myCrt_Dispatch(int i)
243 return "(00)ReceiveCoreMakeDir";
245 return "(01)ReceiveCoreRemoveDir";
247 return "(02)ReceiveCoreOpen";
249 return "(03)ReceiveCoreCreate";
251 return "(04)ReceiveCoreClose";
253 return "(05)ReceiveCoreFlush";
255 return "(06)ReceiveCoreUnlink";
257 return "(07)ReceiveCoreRename";
259 return "(08)ReceiveCoreGetFileAttributes";
261 return "(09)ReceiveCoreSetFileAttributes";
263 return "(0a)ReceiveCoreRead";
265 return "(0b)ReceiveCoreWrite";
267 return "(0c)ReceiveCoreLockRecord";
269 return "(0d)ReceiveCoreUnlockRecord";
271 return "(0e)SendCoreBadOp";
273 return "(0f)ReceiveCoreCreate";
275 return "(10)ReceiveCoreCheckPath";
277 return "(11)SendCoreBadOp";
279 return "(12)ReceiveCoreSeek";
281 return "(1a)ReceiveCoreReadRaw";
283 return "(1d)ReceiveCoreWriteRawDummy";
285 return "(22)ReceiveV3SetAttributes";
287 return "(23)ReceiveV3GetAttributes";
289 return "(24)ReceiveV3LockingX";
291 return "(25)ReceiveV3Trans";
293 return "(26)ReceiveV3Trans[aux]";
295 return "(29)SendCoreBadOp";
297 return "(2b)ReceiveCoreEcho";
299 return "(2d)ReceiveV3OpenX";
301 return "(2e)ReceiveV3ReadX";
303 return "(2f)ReceiveV3WriteX";
305 return "(32)ReceiveV3Tran2A";
307 return "(33)ReceiveV3Tran2A[aux]";
309 return "(34)ReceiveV3FindClose";
311 return "(35)ReceiveV3FindNotifyClose";
313 return "(70)ReceiveCoreTreeConnect";
315 return "(71)ReceiveCoreTreeDisconnect";
317 return "(72)ReceiveNegotiate";
319 return "(73)ReceiveV3SessionSetupX";
321 return "(74)ReceiveV3UserLogoffX";
323 return "(75)ReceiveV3TreeConnectX";
325 return "(80)ReceiveCoreGetDiskAttributes";
327 return "(81)ReceiveCoreSearchDir";
331 return "(83)FindUnique";
333 return "(84)FindClose";
335 return "(A0)ReceiveNTTransact";
337 return "(A2)ReceiveNTCreateX";
339 return "(A4)ReceiveNTCancel";
341 return "(A5)ReceiveNTRename";
343 return "(C0)OpenPrintFile";
345 return "(C1)WritePrintFile";
347 return "(C2)ClosePrintFile";
349 return "(C3)GetPrintQueue";
351 return "(D8)ReadBulk";
353 return "(D9)WriteBulk";
355 return "(DA)WriteBulkData";
357 return "unknown SMB op";
361 char * myCrt_2Dispatch(int i)
366 return "unknown SMB op-2";
368 return "S(00)CreateFile_ReceiveTran2Open";
370 return "S(01)FindFirst_ReceiveTran2SearchDir";
372 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
374 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
376 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
378 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
380 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
382 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
384 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
386 return "S(09)_ReceiveTran2FSCTL";
388 return "S(0a)_ReceiveTran2IOCTL";
390 return "S(0b)_ReceiveTran2FindNotifyFirst";
392 return "S(0c)_ReceiveTran2FindNotifyNext";
394 return "S(0d)_ReceiveTran2CreateDirectory";
396 return "S(0e)_ReceiveTran2SessionSetup";
398 return "S(0f)_QueryFileSystemInformationFid";
400 return "S(10)_ReceiveTran2GetDfsReferral";
402 return "S(11)_ReceiveTran2ReportDfsInconsistency";
406 char * myCrt_RapDispatch(int i)
411 return "unknown RAP OP";
413 return "RAP(0)NetShareEnum";
415 return "RAP(1)NetShareGetInfo";
417 return "RAP(13)NetServerGetInfo";
419 return "RAP(63)NetWkStaGetInfo";
423 char * myCrt_NmpipeDispatch(int i)
426 case SMB_TRANS_SET_NMPIPE_STATE:
427 return "SET NMPIPE STATE";
429 case SMB_TRANS_RAW_READ_NMPIPE:
430 return "RAW READ NMPIPE";
432 case SMB_TRANS_QUERY_NMPIPE_STATE:
433 return "QUERY NMPIPE STATE";
435 case SMB_TRANS_QUERY_NMPIPE_INFO:
436 return "QUERY NMPIPE INFO";
438 case SMB_TRANS_PEEK_NMPIPE:
439 return "PEEK NMPIPE";
441 case SMB_TRANS_TRANSACT_NMPIPE:
442 return "TRANSACT NMPIPE";
444 case SMB_TRANS_RAW_WRITE_NMPIPE:
445 return "WRITE NMPIPE";
447 case SMB_TRANS_READ_NMPIPE:
448 return "READ NMPIPE";
450 case SMB_TRANS_WRITE_NMPIPE:
451 return "WRITE NMPIPE";
453 case SMB_TRANS_WAIT_NMPIPE:
454 return "WAIT NMPIPE";
456 case SMB_TRANS_CALL_NMPIPE:
457 return "CALL NMPIPE";
462 /* scache must be locked */
463 unsigned int smb_Attributes(cm_scache_t *scp)
467 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
468 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
469 scp->fileType == CM_SCACHETYPE_INVALID)
471 attrs = SMB_ATTR_DIRECTORY;
472 #ifdef SPECIAL_FOLDERS
473 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
474 #endif /* SPECIAL_FOLDERS */
475 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
476 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
481 * We used to mark a file RO if it was in an RO volume, but that
482 * turns out to be impolitic in NT. See defect 10007.
485 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
486 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
488 if ((scp->unixModeBits & 0200) == 0)
489 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
495 /* Check if the named file/dir is a dotfile/dotdir */
496 /* String pointed to by lastComp can have leading slashes, but otherwise should have
497 no other patch components */
498 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
502 /* skip over slashes */
503 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
508 /* nulls, curdir and parent dir doesn't count */
514 if(*(s+1) == _C('.') && !*(s + 2))
521 static int ExtractBits(WORD bits, short start, short len)
528 num = bits << (16 - end);
529 num = num >> ((16 - end) + start);
534 void ShowUnixTime(char *FuncName, time_t unixTime)
539 cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
541 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
542 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
544 int day, month, year, sec, min, hour;
547 day = ExtractBits(wDate, 0, 5);
548 month = ExtractBits(wDate, 5, 4);
549 year = ExtractBits(wDate, 9, 7) + 1980;
551 sec = ExtractBits(wTime, 0, 5);
552 min = ExtractBits(wTime, 5, 6);
553 hour = ExtractBits(wTime, 11, 5);
555 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
556 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
560 /* Determine if we are observing daylight savings time */
561 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
563 TIME_ZONE_INFORMATION timeZoneInformation;
564 SYSTEMTIME utc, local, localDST;
566 /* Get the time zone info. NT uses this to calc if we are in DST. */
567 GetTimeZoneInformation(&timeZoneInformation);
569 /* Return the daylight bias */
570 *pDstBias = timeZoneInformation.DaylightBias;
572 /* Return the bias */
573 *pBias = timeZoneInformation.Bias;
575 /* Now determine if DST is being observed */
577 /* Get the UTC (GMT) time */
580 /* Convert UTC time to local time using the time zone info. If we are
581 observing DST, the calculated local time will include this.
583 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
585 /* Set the daylight bias to 0. The daylight bias is the amount of change
586 * in time that we use for daylight savings time. By setting this to 0
587 * we cause there to be no change in time during daylight savings time.
589 timeZoneInformation.DaylightBias = 0;
591 /* Convert the utc time to local time again, but this time without any
592 adjustment for daylight savings time.
594 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
596 /* If the two times are different, then it means that the localDST that
597 we calculated includes the daylight bias, and therefore we are
598 observing daylight savings time.
600 *pDST = localDST.wHour != local.wHour;
604 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
606 BOOL dst; /* Will be TRUE if observing DST */
607 LONG dstBias; /* Offset from local time if observing DST */
608 LONG bias; /* Offset from GMT for local time */
611 * This function will adjust the last write time to compensate
612 * for two bugs in the smb client:
614 * 1) During Daylight Savings Time, the LastWriteTime is ahead
615 * in time by the DaylightBias (ignoring the sign - the
616 * DaylightBias is always stored as a negative number). If
617 * the DaylightBias is -60, then the LastWriteTime will be
618 * ahead by 60 minutes.
620 * 2) If the local time zone is a positive offset from GMT, then
621 * the LastWriteTime will be the correct local time plus the
622 * Bias (ignoring the sign - a positive offset from GMT is
623 * always stored as a negative Bias). If the Bias is -120,
624 * then the LastWriteTime will be ahead by 120 minutes.
626 * These bugs can occur at the same time.
629 GetTimeZoneInfo(&dst, &dstBias, &bias);
631 /* First adjust for DST */
633 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
635 /* Now adjust for a positive offset from GMT (a negative bias). */
637 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
640 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
642 time_t diff_t = unixTime - smb_localZero;
643 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
644 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
646 *dosUTimep = (afs_uint32)diff_t;
649 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
651 *unixTimep = dosTime + smb_localZero;
654 void smb_MarkAllVCsDead(smb_vc_t * exclude)
657 smb_vc_t **vcp_to_cleanup = NULL;
658 int n_to_cleanup = 0;
661 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
663 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
664 lock_ObtainWrite(&smb_rctLock);
665 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
667 if (vcp->magic != SMB_VC_MAGIC)
668 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
674 lock_ObtainMutex(&vcp->mx);
675 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
676 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
677 lock_ReleaseMutex(&vcp->mx);
678 dead_sessions[vcp->session] = TRUE;
680 lock_ReleaseMutex(&vcp->mx);
685 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
687 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
691 vcp_to_cleanup[i++] = vcp;
692 smb_HoldVCNoLock(vcp);
695 osi_assert(i == n_to_cleanup);
697 lock_ReleaseWrite(&smb_rctLock);
698 lock_ReleaseWrite(&smb_globalLock);
700 for (i=0; i < n_to_cleanup; i++) {
701 smb_CleanupDeadVC(vcp_to_cleanup[i]);
702 smb_ReleaseVC(vcp_to_cleanup[i]);
703 vcp_to_cleanup[i] = 0;
706 free(vcp_to_cleanup);
709 #ifdef DEBUG_SMB_REFCOUNT
710 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
712 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
717 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
718 lock_ObtainWrite(&smb_rctLock);
719 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
720 if (vcp->magic != SMB_VC_MAGIC)
721 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
724 lock_ObtainMutex(&vcp->mx);
725 if (lsn == vcp->lsn && lana == vcp->lana &&
726 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
727 lock_ReleaseMutex(&vcp->mx);
728 smb_HoldVCNoLock(vcp);
731 lock_ReleaseMutex(&vcp->mx);
733 if (!vcp && (flags & SMB_FLAG_CREATE)) {
734 vcp = malloc(sizeof(*vcp));
735 memset(vcp, 0, sizeof(*vcp));
736 vcp->vcID = ++numVCs;
737 vcp->magic = SMB_VC_MAGIC;
738 vcp->refCount = 2; /* smb_allVCsp and caller */
741 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
742 vcp->nextp = smb_allVCsp;
744 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
749 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
750 /* We must obtain a challenge for extended auth
751 * in case the client negotiates smb v3
753 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
754 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
755 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
756 ULONG lsaRespSize = 0;
758 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
760 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
767 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
768 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
769 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
770 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
771 nts, ntsEx, lsaRespSize);
773 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
775 if (ntsEx == STATUS_SUCCESS) {
776 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
779 * This will cause the subsequent authentication to fail but
780 * that is better than us dereferencing a NULL pointer and
783 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
786 LsaFreeReturnBuffer(lsaResp);
789 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
791 if (numVCs >= CM_SESSION_RESERVED) {
793 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
796 #ifdef DEBUG_SMB_REFCOUNT
798 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
799 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
802 lock_ReleaseWrite(&smb_rctLock);
803 lock_ReleaseWrite(&smb_globalLock);
807 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
812 for(i=0; i<11; i++) {
814 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
820 static int smb_IsStarMask(clientchar_t *maskp)
826 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
832 #ifdef DEBUG_SMB_REFCOUNT
833 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
834 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
836 void smb_ReleaseVCInternal(smb_vc_t *vcp)
842 lock_AssertWrite(&smb_rctLock);
845 if (vcp->refCount == 0) {
846 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
847 #ifdef DEBUG_SMB_REFCOUNT
848 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
849 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
851 /* remove VCP from smb_deadVCsp */
852 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
858 lock_FinalizeMutex(&vcp->mx);
859 memset(vcp,0,sizeof(smb_vc_t));
862 #ifdef DEBUG_SMB_REFCOUNT
863 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
865 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
869 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
870 avcp?"":"not ",vcp, vcp->refCount);
872 /* This is a wrong. However, I suspect that there is an undercount
873 * and I don't want to release 1.4.1 in a state that will allow
874 * smb_vc_t objects to be deallocated while still in the
875 * smb_allVCsp list. The list is supposed to keep a reference
876 * to the smb_vc_t. Put it back.
880 #ifdef DEBUG_SMB_REFCOUNT
881 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
882 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
886 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
887 /* The reference count is non-zero but the VC is dead.
888 * This implies that some FIDs, TIDs, etc on the VC have yet to
889 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
890 * add a reference that will be dropped by
891 * smb_CleanupDeadVC() and try to cleanup the VC again.
892 * Eventually the refCount will drop to zero when all of the
893 * active threads working with the VC end their task.
895 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
896 vcp->refCount++; /* put the refCount back */
897 lock_ReleaseWrite(&smb_rctLock);
898 smb_CleanupDeadVC(vcp);
899 #ifdef DEBUG_SMB_REFCOUNT
900 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
901 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
903 lock_ObtainWrite(&smb_rctLock);
906 #ifdef DEBUG_SMB_REFCOUNT
907 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
908 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
913 #ifdef DEBUG_SMB_REFCOUNT
914 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
916 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
919 lock_AssertWrite(&smb_rctLock);
920 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
921 smb_ReleaseVCInternal(vcp);
924 #ifdef DEBUG_SMB_REFCOUNT
925 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
927 void smb_ReleaseVC(smb_vc_t *vcp)
930 lock_ObtainWrite(&smb_rctLock);
931 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
932 smb_ReleaseVCInternal(vcp);
933 lock_ReleaseWrite(&smb_rctLock);
936 #ifdef DEBUG_SMB_REFCOUNT
937 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
939 void smb_HoldVCNoLock(smb_vc_t *vcp)
942 lock_AssertWrite(&smb_rctLock);
944 #ifdef DEBUG_SMB_REFCOUNT
945 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
946 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
948 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
952 #ifdef DEBUG_SMB_REFCOUNT
953 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
955 void smb_HoldVC(smb_vc_t *vcp)
958 lock_ObtainWrite(&smb_rctLock);
960 #ifdef DEBUG_SMB_REFCOUNT
961 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
962 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
964 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
966 lock_ReleaseWrite(&smb_rctLock);
969 void smb_CleanupDeadVC(smb_vc_t *vcp)
977 smb_user_t *uidpIter;
978 smb_user_t *uidpNext;
980 afs_uint32 refCount = 0;
982 lock_ObtainMutex(&vcp->mx);
983 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
984 lock_ReleaseMutex(&vcp->mx);
985 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
988 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
989 lock_ReleaseMutex(&vcp->mx);
990 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
992 lock_ObtainWrite(&smb_rctLock);
993 /* remove VCP from smb_allVCsp */
994 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
995 if ((*vcpp)->magic != SMB_VC_MAGIC)
996 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1000 vcp->nextp = smb_deadVCsp;
1002 /* Hold onto the reference until we are done with this function */
1007 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1008 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1010 if (fidpIter->deleteOk)
1013 fid = fidpIter->fid;
1014 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1016 smb_HoldFIDNoLock(fidpIter);
1017 lock_ReleaseWrite(&smb_rctLock);
1019 smb_CloseFID(vcp, fidpIter, NULL, 0);
1020 smb_ReleaseFID(fidpIter);
1022 lock_ObtainWrite(&smb_rctLock);
1023 fidpNext = vcp->fidsp;
1026 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1027 tidpNext = tidpIter->nextp;
1028 if (tidpIter->deleteOk)
1030 tidpIter->deleteOk = 1;
1032 tid = tidpIter->tid;
1033 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1035 smb_HoldTIDNoLock(tidpIter);
1036 smb_ReleaseTID(tidpIter, TRUE);
1037 tidpNext = vcp->tidsp;
1040 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1041 uidpNext = uidpIter->nextp;
1042 if (uidpIter->deleteOk)
1044 uidpIter->deleteOk = 1;
1046 /* do not add an additional reference count for the smb_user_t
1047 * as the smb_vc_t already is holding a reference */
1048 lock_ReleaseWrite(&smb_rctLock);
1050 smb_ReleaseUID(uidpIter);
1052 lock_ObtainWrite(&smb_rctLock);
1053 uidpNext = vcp->usersp;
1056 /* The vcp is now on the deadVCsp list. We intentionally drop the
1057 * reference so that the refcount can reach 0 and we can delete it
1059 * If the refCount == 1 going into the ReleaseVCNoLock call
1060 * the object will be freed and it won't be safe to clear
1063 refCount = vcp->refCount;
1064 smb_ReleaseVCNoLock(vcp);
1066 lock_ObtainMutex(&vcp->mx);
1067 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1068 lock_ReleaseMutex(&vcp->mx);
1071 lock_ReleaseWrite(&smb_rctLock);
1072 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1075 #ifdef DEBUG_SMB_REFCOUNT
1076 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1078 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1083 lock_ObtainWrite(&smb_rctLock);
1085 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1086 if (tidp->refCount == 0 && tidp->deleteOk) {
1088 smb_ReleaseTID(tidp, TRUE);
1092 if (tid == tidp->tid) {
1097 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1098 tidp = malloc(sizeof(*tidp));
1099 memset(tidp, 0, sizeof(*tidp));
1100 tidp->nextp = vcp->tidsp;
1103 smb_HoldVCNoLock(vcp);
1105 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1108 #ifdef DEBUG_SMB_REFCOUNT
1110 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1111 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1114 lock_ReleaseWrite(&smb_rctLock);
1118 #ifdef DEBUG_SMB_REFCOUNT
1119 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1121 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1124 lock_AssertWrite(&smb_rctLock);
1126 #ifdef DEBUG_SMB_REFCOUNT
1127 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1128 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1132 #ifdef DEBUG_SMB_REFCOUNT
1133 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1135 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1140 cm_user_t *userp = NULL;
1141 smb_vc_t *vcp = NULL;
1144 lock_ObtainWrite(&smb_rctLock);
1146 lock_AssertWrite(&smb_rctLock);
1148 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1149 #ifdef DEBUG_SMB_REFCOUNT
1150 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1151 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1153 if (tidp->refCount == 0) {
1154 if (tidp->deleteOk) {
1155 ltpp = &tidp->vcp->tidsp;
1156 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1160 osi_assertx(tp != NULL, "null smb_tid_t");
1162 lock_FinalizeMutex(&tidp->mx);
1163 userp = tidp->userp; /* remember to drop ref later */
1171 smb_ReleaseVCNoLock(vcp);
1173 lock_ReleaseWrite(&smb_rctLock);
1175 cm_ReleaseUser(userp);
1178 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1180 smb_user_t *uidp = NULL;
1182 lock_ObtainWrite(&smb_rctLock);
1183 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1184 if (uid == uidp->userID) {
1186 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1188 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1192 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1193 uidp = malloc(sizeof(*uidp));
1194 memset(uidp, 0, sizeof(*uidp));
1195 uidp->nextp = vcp->usersp;
1196 uidp->refCount = 2; /* one for the vcp and one for the caller */
1198 smb_HoldVCNoLock(vcp);
1200 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1202 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1204 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1206 lock_ReleaseWrite(&smb_rctLock);
1210 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1213 smb_username_t *unp= NULL;
1215 lock_ObtainWrite(&smb_rctLock);
1216 for(unp = usernamesp; unp; unp = unp->nextp) {
1217 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1218 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1223 if (!unp && (flags & SMB_FLAG_CREATE)) {
1224 unp = malloc(sizeof(*unp));
1225 memset(unp, 0, sizeof(*unp));
1227 unp->nextp = usernamesp;
1228 unp->name = cm_ClientStrDup(usern);
1229 unp->machine = cm_ClientStrDup(machine);
1231 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1232 if (flags & SMB_FLAG_AFSLOGON)
1233 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1236 lock_ReleaseWrite(&smb_rctLock);
1240 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1242 smb_user_t *uidp= NULL;
1244 lock_ObtainWrite(&smb_rctLock);
1245 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1248 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1250 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1251 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1256 lock_ReleaseWrite(&smb_rctLock);
1260 void smb_ReleaseUsername(smb_username_t *unp)
1263 smb_username_t **lupp;
1264 cm_user_t *userp = NULL;
1265 time_t now = osi_Time();
1267 lock_ObtainWrite(&smb_rctLock);
1268 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1269 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1270 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1272 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1276 osi_assertx(up != NULL, "null smb_username_t");
1278 up->nextp = NULL; /* do not remove this */
1279 lock_FinalizeMutex(&unp->mx);
1285 lock_ReleaseWrite(&smb_rctLock);
1287 cm_ReleaseUser(userp);
1290 void smb_HoldUIDNoLock(smb_user_t *uidp)
1292 lock_AssertWrite(&smb_rctLock);
1296 void smb_ReleaseUID(smb_user_t *uidp)
1300 smb_username_t *unp = NULL;
1302 lock_ObtainWrite(&smb_rctLock);
1303 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1304 if (uidp->refCount == 0) {
1305 lupp = &uidp->vcp->usersp;
1306 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1310 osi_assertx(up != NULL, "null smb_user_t");
1312 lock_FinalizeMutex(&uidp->mx);
1314 smb_ReleaseVCNoLock(uidp->vcp);
1318 lock_ReleaseWrite(&smb_rctLock);
1322 cm_ReleaseUserVCRef(unp->userp);
1323 smb_ReleaseUsername(unp);
1327 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1329 cm_user_t *up = NULL;
1334 lock_ObtainMutex(&uidp->mx);
1336 up = uidp->unp->userp;
1339 lock_ReleaseMutex(&uidp->mx);
1345 /* retrieve a held reference to a user structure corresponding to an incoming
1347 * corresponding release function is cm_ReleaseUser.
1349 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1352 cm_user_t *up = NULL;
1355 smbp = (smb_t *) inp;
1356 uidp = smb_FindUID(vcp, smbp->uid, 0);
1360 up = smb_GetUserFromUID(uidp);
1362 smb_ReleaseUID(uidp);
1367 * Return a pointer to a pathname extracted from a TID structure. The
1368 * TID structure is not held; assume it won't go away.
1370 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1375 tidp = smb_FindTID(vcp, tid, 0);
1379 if (tidp->flags & SMB_TIDFLAG_IPC) {
1380 code = CM_ERROR_TIDIPC;
1381 /* tidp->pathname would be NULL, but that's fine */
1383 *treepath = tidp->pathname;
1384 smb_ReleaseTID(tidp, FALSE);
1389 /* check to see if we have a chained fid, that is, a fid that comes from an
1390 * OpenAndX message that ran earlier in this packet. In this case, the fid
1391 * field in a read, for example, request, isn't set, since the value is
1392 * supposed to be inherited from the openAndX call.
1394 int smb_ChainFID(int fid, smb_packet_t *inp)
1396 if (inp->fid == 0 || inp->inCount == 0)
1402 /* are we a priv'd user? What does this mean on NT? */
1403 int smb_SUser(cm_user_t *userp)
1408 /* find a file ID. If we pass in 0 we select an unused File ID.
1409 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1410 * smb_fid_t data structure if desired File ID cannot be found.
1412 #ifdef DEBUG_SMB_REFCOUNT
1413 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1415 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1422 if (!(flags & SMB_FLAG_CREATE))
1427 lock_ObtainWrite(&smb_rctLock);
1429 fid = vcp->fidCounter;
1432 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1433 if (fidp->refCount == 0 && fidp->deleteOk) {
1435 lock_ReleaseWrite(&smb_rctLock);
1436 smb_ReleaseFID(fidp);
1437 lock_ObtainWrite(&smb_rctLock);
1439 * We dropped the smb_rctLock so the fid value we are using
1440 * may now be used by another thread. Start over with the
1441 * current vcp->fidCounter.
1444 fid = vcp->fidCounter;
1447 if (fid == fidp->fid) {
1449 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1451 if (fid == 0xFFFF) {
1453 "New FID number wraps on vcp 0x%x", vcp);
1463 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1464 char eventName[MAX_PATH];
1468 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1470 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1472 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1473 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1474 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1475 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1476 thrd_CloseHandle(event);
1478 if (fid == 0xFFFF) {
1479 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1485 fidp = malloc(sizeof(*fidp));
1486 memset(fidp, 0, sizeof(*fidp));
1487 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1490 smb_HoldVCNoLock(vcp);
1491 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1493 fidp->curr_chunk = fidp->prev_chunk = -2;
1494 fidp->raw_write_event = event;
1496 vcp->fidCounter = fid+1;
1497 if (vcp->fidCounter == 0xFFFF) {
1498 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1500 vcp->fidCounter = 1;
1505 #ifdef DEBUG_SMB_REFCOUNT
1507 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1508 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1511 lock_ReleaseWrite(&smb_rctLock);
1516 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1517 #ifdef DEBUG_SMB_REFCOUNT
1518 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1520 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1523 smb_fid_t *fidp = NULL, *nextp = NULL;
1529 * If the fidp->scp changes out from under us then
1530 * we must not grab a refCount. It means the *fidp
1531 * was processed by smb_CloseFID() and the *fidp is
1532 * no longer valid for use.
1534 lock_ObtainWrite(&smb_rctLock);
1535 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1536 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1540 if (scp == fidp->scp) {
1541 lock_ReleaseWrite(&smb_rctLock);
1542 lock_ObtainMutex(&fidp->mx);
1543 lock_ObtainWrite(&smb_rctLock);
1544 if (scp == fidp->scp) {
1545 lock_ReleaseMutex(&fidp->mx);
1548 lock_ReleaseMutex(&fidp->mx);
1551 if (fidp->refCount > 1) {
1554 lock_ReleaseWrite(&smb_rctLock);
1555 smb_ReleaseFID(fidp);
1556 lock_ObtainWrite(&smb_rctLock);
1561 if (nextp->refCount > 1) {
1564 lock_ReleaseWrite(&smb_rctLock);
1565 smb_ReleaseFID(nextp);
1566 lock_ObtainWrite(&smb_rctLock);
1570 #ifdef DEBUG_SMB_REFCOUNT
1572 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1573 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1576 lock_ReleaseWrite(&smb_rctLock);
1580 #ifdef DEBUG_SMB_REFCOUNT
1581 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1583 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1586 lock_AssertWrite(&smb_rctLock);
1588 #ifdef DEBUG_SMB_REFCOUNT
1589 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1590 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1596 /* the smb_fid_t->mx and smb_rctLock must not be held */
1597 #ifdef DEBUG_SMB_REFCOUNT
1598 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1600 void smb_ReleaseFID(smb_fid_t *fidp)
1603 cm_scache_t *scp = NULL;
1604 cm_user_t *userp = NULL;
1605 smb_vc_t *vcp = NULL;
1606 smb_ioctl_t *ioctlp;
1608 lock_ObtainMutex(&fidp->mx);
1609 lock_ObtainWrite(&smb_rctLock);
1610 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1611 #ifdef DEBUG_SMB_REFCOUNT
1612 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1613 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1615 if (fidp->refCount == 0) {
1616 if (fidp->deleteOk) {
1619 scp = fidp->scp; /* release after lock is released */
1621 lock_ObtainWrite(&scp->rw);
1622 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1623 lock_ReleaseWrite(&scp->rw);
1624 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1627 userp = fidp->userp;
1631 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1632 thrd_CloseHandle(fidp->raw_write_event);
1634 /* and see if there is ioctl stuff to free */
1635 ioctlp = fidp->ioctlp;
1638 cm_FreeSpace(ioctlp->prefix);
1639 if (ioctlp->ioctl.inAllocp)
1640 free(ioctlp->ioctl.inAllocp);
1641 if (ioctlp->ioctl.outAllocp)
1642 free(ioctlp->ioctl.outAllocp);
1646 smb_CleanupRPCFid(fidp);
1648 lock_ReleaseMutex(&fidp->mx);
1649 lock_FinalizeMutex(&fidp->mx);
1654 smb_ReleaseVCNoLock(vcp);
1658 lock_ReleaseMutex(&fidp->mx);
1660 lock_ReleaseWrite(&smb_rctLock);
1662 /* now release the scache structure */
1664 cm_ReleaseSCache(scp);
1667 cm_ReleaseUser(userp);
1671 * Case-insensitive search for one string in another;
1672 * used to find variable names in submount pathnames.
1674 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1676 clientchar_t *cursor;
1678 for (cursor = str1; *cursor; cursor++)
1679 if (cm_ClientStrCmpI(cursor, str2) == 0)
1686 * Substitute a variable value for its name in a submount pathname. Variable
1687 * name has been identified by smb_stristr() and is in substr. Variable name
1688 * length (plus one) is in substr_size. Variable value is in newstr.
1690 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1691 unsigned int substr_size, clientchar_t *newstr)
1693 clientchar_t temp[1024];
1695 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1696 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1697 cm_ClientStrCat(str1, cchstr1, temp);
1700 clientchar_t VNUserName[] = _C("%USERNAME%");
1701 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1702 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1703 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1705 typedef struct smb_findShare_rock {
1706 clientchar_t * shareName;
1707 clientchar_t * match;
1709 } smb_findShare_rock_t;
1711 #define SMB_FINDSHARE_EXACT_MATCH 1
1712 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1714 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1718 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1719 normchar_t normName[MAX_PATH];
1721 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1722 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1723 osi_LogSaveString(smb_logp, dep->name));
1727 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1728 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1729 matchType = SMB_FINDSHARE_EXACT_MATCH;
1731 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1734 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1735 vrock->matchType = matchType;
1737 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1738 return CM_ERROR_STOPNOW;
1744 /* find a shareName in the table of submounts */
1745 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1746 clientchar_t *shareName,
1747 clientchar_t **pathNamep)
1751 clientchar_t pathName[1024];
1754 clientchar_t *p, *q;
1755 fschar_t *cellname = NULL;
1758 DWORD allSubmount = 1;
1760 /* if allSubmounts == 0, only return the //mountRoot/all share
1761 * if in fact it has been been created in the subMounts table.
1762 * This is to allow sites that want to restrict access to the
1765 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1766 0, KEY_QUERY_VALUE, &parmKey);
1767 if (code == ERROR_SUCCESS) {
1768 cblen = sizeof(allSubmount);
1769 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1770 (BYTE *) &allSubmount, &cblen);
1771 if (code != ERROR_SUCCESS) {
1774 RegCloseKey (parmKey);
1777 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1782 /* In case, the all share is disabled we need to still be able
1783 * to handle ioctl requests
1785 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1786 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1790 if (MSRPC_IsWellKnownService(shareName) ||
1791 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1792 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1798 /* Check for volume references
1800 * They look like <cell>{%,#}<volume>
1802 if (cm_ClientStrChr(shareName, '%') != NULL ||
1803 cm_ClientStrChr(shareName, '#') != NULL) {
1804 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1805 /* make room for '/@vol:' + mountchar + NULL terminator*/
1807 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1808 osi_LogSaveClientString(smb_logp, shareName));
1810 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1811 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1812 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1814 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1816 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1817 cm_ClientStrLwr(*pathNamep);
1818 osi_Log1(smb_logp, " returning pathname [%S]",
1819 osi_LogSaveClientString(smb_logp, *pathNamep));
1827 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1828 0, KEY_QUERY_VALUE, &parmKey);
1829 if (code == ERROR_SUCCESS) {
1830 cblen = sizeof(pathName);
1831 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1832 (BYTE *) pathName, &cblen);
1833 if (code != ERROR_SUCCESS)
1835 RegCloseKey (parmKey);
1839 cchlen = cblen / sizeof(clientchar_t);
1840 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1841 /* We can accept either unix or PC style AFS pathnames. Convert
1842 * Unix-style to PC style here for internal use.
1845 cchlen = lengthof(pathName);
1847 /* within this code block, we maintain, cchlen = writeable
1848 buffer length of p */
1850 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1851 p += cm_mountRootCLen; /* skip mount path */
1852 cchlen -= (DWORD)(p - pathName);
1857 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1863 clientchar_t temp[1024];
1865 if (var = smb_stristr(p, VNUserName)) {
1866 if (uidp && uidp->unp)
1867 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1869 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1871 else if (var = smb_stristr(p, VNLCUserName))
1873 if (uidp && uidp->unp)
1874 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1876 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1877 cm_ClientStrLwr(temp);
1878 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1880 else if (var = smb_stristr(p, VNComputerName))
1882 sizeTemp = lengthof(temp);
1883 GetComputerNameW(temp, &sizeTemp);
1884 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1886 else if (var = smb_stristr(p, VNLCComputerName))
1888 sizeTemp = lengthof(temp);
1889 GetComputerName((LPTSTR)temp, &sizeTemp);
1890 cm_ClientStrLwr(temp);
1891 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1896 *pathNamep = cm_ClientStrDup(p);
1901 /* First lookup shareName in root.afs */
1903 smb_findShare_rock_t vrock;
1905 fschar_t ftemp[1024];
1906 clientchar_t * p = shareName;
1909 /* attempt to locate a partial match in root.afs. This is because
1910 when using the ANSI RAP calls, the share name is limited to 13 chars
1911 and hence is truncated. Of course we prefer exact matches. */
1913 thyper.HighPart = 0;
1916 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1917 if (vrock.shareName == NULL)
1920 vrock.matchType = 0;
1922 cm_HoldSCache(cm_data.rootSCachep);
1923 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1924 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1925 cm_ReleaseSCache(cm_data.rootSCachep);
1927 free(vrock.shareName);
1928 vrock.shareName = NULL;
1930 if (vrock.matchType) {
1931 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1932 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1937 /* if we get here, there was no match for the share in root.afs */
1938 /* so try to create \\<netbiosName>\<cellname> */
1943 /* Get the full name for this cell */
1944 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1945 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
1946 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
1947 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1948 #ifdef AFS_AFSDB_ENV
1949 if (code && cm_dnsEnabled) {
1951 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1953 #endif /* AFS_AFSDB_ENV */
1957 /* construct the path */
1959 clientchar_t temp[1024];
1961 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
1962 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
1963 rw ? _C("/.%S/") : _C("/%S/"), temp);
1964 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1974 /* Client-side offline caching policy types */
1975 #define CSC_POLICY_MANUAL 0
1976 #define CSC_POLICY_DOCUMENTS 1
1977 #define CSC_POLICY_PROGRAMS 2
1978 #define CSC_POLICY_DISABLE 3
1980 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1983 clientchar_t policy[1024];
1986 int retval = CSC_POLICY_MANUAL;
1988 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1989 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1992 REG_OPTION_NON_VOLATILE,
1996 NULL ) != ERROR_SUCCESS)
1997 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1999 len = sizeof(policy);
2000 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2002 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2004 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2006 retval = CSC_POLICY_MANUAL;
2008 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2010 retval = CSC_POLICY_DOCUMENTS;
2012 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2014 retval = CSC_POLICY_PROGRAMS;
2016 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2018 retval = CSC_POLICY_DISABLE;
2021 RegCloseKey(hkCSCPolicy);
2025 /* find a dir search structure by cookie value, and return it held.
2026 * Must be called with smb_globalLock held.
2028 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2030 smb_dirSearch_t *dsp;
2032 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2033 if (dsp->cookie == cookie) {
2034 if (dsp != smb_firstDirSearchp) {
2035 /* move to head of LRU queue, too, if we're not already there */
2036 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2037 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2038 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2039 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2040 if (!smb_lastDirSearchp)
2041 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2049 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2050 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2051 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2057 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2059 lock_ObtainMutex(&dsp->mx);
2060 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2061 dsp->cookie, dsp, dsp->scp);
2062 dsp->flags |= SMB_DIRSEARCH_DELETE;
2063 if (dsp->scp != NULL) {
2064 lock_ObtainWrite(&dsp->scp->rw);
2065 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2066 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2067 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2068 dsp->scp->bulkStatProgress = hzero;
2070 lock_ReleaseWrite(&dsp->scp->rw);
2072 lock_ReleaseMutex(&dsp->mx);
2075 /* Must be called with the smb_globalLock held */
2076 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2078 cm_scache_t *scp = NULL;
2080 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2081 if (dsp->refCount == 0) {
2082 lock_ObtainMutex(&dsp->mx);
2083 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2084 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2085 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2086 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2087 lock_ReleaseMutex(&dsp->mx);
2088 lock_FinalizeMutex(&dsp->mx);
2090 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2091 dsp->cookie, dsp, scp);
2094 lock_ReleaseMutex(&dsp->mx);
2097 /* do this now to avoid spurious locking hierarchy creation */
2099 cm_ReleaseSCache(scp);
2102 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2104 lock_ObtainWrite(&smb_globalLock);
2105 smb_ReleaseDirSearchNoLock(dsp);
2106 lock_ReleaseWrite(&smb_globalLock);
2109 /* find a dir search structure by cookie value, and return it held */
2110 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2112 smb_dirSearch_t *dsp;
2114 lock_ObtainWrite(&smb_globalLock);
2115 dsp = smb_FindDirSearchNoLock(cookie);
2116 lock_ReleaseWrite(&smb_globalLock);
2120 /* GC some dir search entries, in the address space expected by the specific protocol.
2121 * Must be called with smb_globalLock held; release the lock temporarily.
2123 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2124 void smb_GCDirSearches(int isV3)
2126 smb_dirSearch_t *prevp;
2127 smb_dirSearch_t *dsp;
2128 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2132 victimCount = 0; /* how many have we got so far */
2133 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2134 /* we'll move tp from queue, so
2137 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2138 /* if no one is using this guy, and we're either in the new protocol,
2139 * or we're in the old one and this is a small enough ID to be useful
2140 * to the old protocol, GC this guy.
2142 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2143 /* hold and delete */
2144 lock_ObtainMutex(&dsp->mx);
2145 dsp->flags |= SMB_DIRSEARCH_DELETE;
2146 lock_ReleaseMutex(&dsp->mx);
2147 victimsp[victimCount++] = dsp;
2151 /* don't do more than this */
2152 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2156 /* now release them */
2157 for (i = 0; i < victimCount; i++) {
2158 smb_ReleaseDirSearchNoLock(victimsp[i]);
2162 /* function for allocating a dir search entry. We need these to remember enough context
2163 * since we don't get passed the path from call to call during a directory search.
2165 * Returns a held dir search structure, and bumps the reference count on the vnode,
2166 * since it saves a pointer to the vnode.
2168 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2170 smb_dirSearch_t *dsp;
2176 lock_ObtainWrite(&smb_globalLock);
2179 /* what's the biggest ID allowed in this version of the protocol */
2180 /* TODO: do we really want a non v3 dir search request to wrap
2181 smb_dirSearchCounter? */
2182 maxAllowed = isV3 ? 65535 : 255;
2183 if (smb_dirSearchCounter > maxAllowed)
2184 smb_dirSearchCounter = 1;
2186 start = smb_dirSearchCounter;
2189 /* twice so we have enough tries to find guys we GC after one pass;
2190 * 10 extra is just in case I mis-counted.
2192 if (++counter > 2*maxAllowed+10)
2193 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2195 if (smb_dirSearchCounter > maxAllowed) {
2196 smb_dirSearchCounter = 1;
2198 if (smb_dirSearchCounter == start) {
2200 smb_GCDirSearches(isV3);
2203 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2205 /* don't need to watch for refcount zero and deleted, since
2206 * we haven't dropped the global lock.
2209 ++smb_dirSearchCounter;
2213 dsp = malloc(sizeof(*dsp));
2214 memset(dsp, 0, sizeof(*dsp));
2215 dsp->cookie = smb_dirSearchCounter;
2216 ++smb_dirSearchCounter;
2218 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2219 dsp->lastTime = osi_Time();
2220 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2221 if (!smb_lastDirSearchp)
2222 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2224 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2228 lock_ReleaseWrite(&smb_globalLock);
2232 static smb_packet_t *smb_GetPacket(void)
2236 lock_ObtainWrite(&smb_globalLock);
2237 tbp = smb_packetFreeListp;
2239 smb_packetFreeListp = tbp->nextp;
2240 lock_ReleaseWrite(&smb_globalLock);
2242 tbp = calloc(sizeof(*tbp),1);
2243 tbp->magic = SMB_PACKETMAGIC;
2246 tbp->resumeCode = 0;
2252 tbp->ncb_length = 0;
2255 tbp->stringsp = NULL;
2257 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2262 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2265 tbp = smb_GetPacket();
2266 memcpy(tbp, pkt, sizeof(smb_packet_t));
2267 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2268 tbp->stringsp = NULL;
2270 smb_HoldVC(tbp->vcp);
2274 static NCB *smb_GetNCB(void)
2279 lock_ObtainWrite(&smb_globalLock);
2280 tbp = smb_ncbFreeListp;
2282 smb_ncbFreeListp = tbp->nextp;
2283 lock_ReleaseWrite(&smb_globalLock);
2285 tbp = calloc(sizeof(*tbp),1);
2286 tbp->magic = SMB_NCBMAGIC;
2289 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2291 memset(&tbp->ncb, 0, sizeof(NCB));
2296 static void FreeSMBStrings(smb_packet_t * pkt)
2301 for (s = pkt->stringsp; s; s = ns) {
2305 pkt->stringsp = NULL;
2308 void smb_FreePacket(smb_packet_t *tbp)
2310 smb_vc_t * vcp = NULL;
2311 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2313 lock_ObtainWrite(&smb_globalLock);
2314 tbp->nextp = smb_packetFreeListp;
2315 smb_packetFreeListp = tbp;
2316 tbp->magic = SMB_PACKETMAGIC;
2320 tbp->resumeCode = 0;
2326 tbp->ncb_length = 0;
2328 FreeSMBStrings(tbp);
2329 lock_ReleaseWrite(&smb_globalLock);
2335 static void smb_FreeNCB(NCB *bufferp)
2339 tbp = (smb_ncb_t *) bufferp;
2340 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2342 lock_ObtainWrite(&smb_globalLock);
2343 tbp->nextp = smb_ncbFreeListp;
2344 smb_ncbFreeListp = tbp;
2345 lock_ReleaseWrite(&smb_globalLock);
2348 /* get a ptr to the data part of a packet, and its count */
2349 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2353 unsigned char *afterParmsp;
2355 parmBytes = *smbp->wctp << 1;
2356 afterParmsp = smbp->wctp + parmBytes + 1;
2358 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2359 if (nbytesp) *nbytesp = dataBytes;
2361 /* don't forget to skip the data byte count, since it follows
2362 * the parameters; that's where the "2" comes from below.
2364 return (unsigned char *) (afterParmsp + 2);
2367 /* must set all the returned parameters before playing around with the
2368 * data region, since the data region is located past the end of the
2369 * variable number of parameters.
2371 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2373 unsigned char *afterParmsp;
2375 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2377 *afterParmsp++ = dsize & 0xff;
2378 *afterParmsp = (dsize>>8) & 0xff;
2381 /* return the parm'th parameter in the smbp packet */
2382 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2385 unsigned char *parmDatap;
2387 parmCount = *smbp->wctp;
2389 if (parm >= parmCount) {
2392 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2393 parm, parmCount, smbp->ncb_length);
2394 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2395 parm, parmCount, smbp->ncb_length);
2396 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2397 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2398 osi_panic(s, __FILE__, __LINE__);
2400 parmDatap = smbp->wctp + (2*parm) + 1;
2402 return parmDatap[0] + (parmDatap[1] << 8);
2405 /* return the parm'th parameter in the smbp packet */
2406 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2409 unsigned char *parmDatap;
2411 parmCount = *smbp->wctp;
2413 if (parm >= parmCount) {
2416 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2417 parm, parmCount, smbp->ncb_length);
2418 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2419 parm, parmCount, smbp->ncb_length);
2420 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2421 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2422 osi_panic(s, __FILE__, __LINE__);
2424 parmDatap = smbp->wctp + (2*parm) + 1;
2426 return parmDatap[0];
2429 /* return the parm'th parameter in the smbp packet */
2430 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2433 unsigned char *parmDatap;
2435 parmCount = *smbp->wctp;
2437 if (parm + 1 >= parmCount) {
2440 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2441 parm, parmCount, smbp->ncb_length);
2442 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2443 parm, parmCount, smbp->ncb_length);
2444 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2445 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2446 osi_panic(s, __FILE__, __LINE__);
2448 parmDatap = smbp->wctp + (2*parm) + 1;
2450 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2453 /* return the parm'th parameter in the smbp packet */
2454 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2457 unsigned char *parmDatap;
2459 parmCount = *smbp->wctp;
2461 if (parm * 2 + offset >= parmCount * 2) {
2464 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2465 parm, offset, parmCount, smbp->ncb_length);
2466 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2467 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2468 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2469 parm, offset, parmCount, smbp->ncb_length);
2470 osi_panic(s, __FILE__, __LINE__);
2472 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2474 return parmDatap[0] + (parmDatap[1] << 8);
2477 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2479 unsigned char *parmDatap;
2481 /* make sure we have enough slots */
2482 if (*smbp->wctp <= slot)
2483 *smbp->wctp = slot+1;
2485 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2486 *parmDatap++ = parmValue & 0xff;
2487 *parmDatap = (parmValue>>8) & 0xff;
2490 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2492 unsigned char *parmDatap;
2494 /* make sure we have enough slots */
2495 if (*smbp->wctp <= slot)
2496 *smbp->wctp = slot+2;
2498 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2499 *parmDatap++ = parmValue & 0xff;
2500 *parmDatap++ = (parmValue>>8) & 0xff;
2501 *parmDatap++ = (parmValue>>16) & 0xff;
2502 *parmDatap = (parmValue>>24) & 0xff;
2505 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2507 unsigned char *parmDatap;
2510 /* make sure we have enough slots */
2511 if (*smbp->wctp <= slot)
2512 *smbp->wctp = slot+4;
2514 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2516 *parmDatap++ = *parmValuep++;
2519 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2521 unsigned char *parmDatap;
2523 /* make sure we have enough slots */
2524 if (*smbp->wctp <= slot) {
2525 if (smbp->oddByte) {
2527 *smbp->wctp = slot+1;
2532 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2533 *parmDatap++ = parmValue & 0xff;
2538 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2539 clientchar_t *inPathp)
2541 clientchar_t *lastSlashp;
2542 clientchar_t *streamp = NULL;
2543 clientchar_t *typep = NULL;
2545 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2546 if (lastComponentp) {
2547 *lastComponentp = lastSlashp;
2551 * If the name contains a stream name and a type
2552 * and the stream name is the nul-string and the
2553 * type is $DATA, then strip "::$DATA" from the
2554 * last component string that is returned.
2556 * Otherwise, return the full path name and allow
2557 * the file name to be rejected because it contains
2560 typep = cm_ClientStrRChr(lastSlashp, L':');
2561 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2563 streamp = cm_ClientStrRChr(lastSlashp, L':');
2564 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2568 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2569 osi_LogSaveClientString(smb_logp,streamp),
2570 osi_LogSaveClientString(smb_logp,typep));
2574 if (inPathp == lastSlashp)
2576 *outPathp++ = *inPathp++;
2585 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2586 char **chainpp, int flags)
2589 afs_uint32 type = *inp++;
2592 * The first byte specifies the type of the input string.
2593 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2597 /* Length Counted */
2598 case 0x1: /* Data Block */
2599 case 0x5: /* Variable Block */
2600 cb = *inp++ << 16 | *inp++;
2603 /* Null-terminated string */
2604 case 0x4: /* ASCII */
2605 case 0x3: /* Pathname */
2606 case 0x2: /* Dialect */
2607 cb = sizeof(pktp->data) - (inp - pktp->data);
2608 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2609 #ifdef DEBUG_UNICODE
2612 cb = sizeof(pktp->data);
2617 return NULL; /* invalid input */
2621 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2622 flags |= SMB_STRF_FORCEASCII;
2625 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2628 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2629 char ** chainpp, int flags)
2634 if (!WANTS_UNICODE(pktp))
2635 flags |= SMB_STRF_FORCEASCII;
2638 cb = sizeof(pktp->data) - (inp - pktp->data);
2639 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2640 #ifdef DEBUG_UNICODE
2643 cb = sizeof(pktp->data);
2645 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2646 flags | SMB_STRF_SRCNULTERM);
2649 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2650 size_t cb, char ** chainpp, int flags)
2653 if (!WANTS_UNICODE(pktp))
2654 flags |= SMB_STRF_FORCEASCII;
2657 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2660 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2661 size_t cch, char ** chainpp, int flags)
2666 if (!WANTS_UNICODE(pktp))
2667 flags |= SMB_STRF_FORCEASCII;
2669 cb = cch * sizeof(wchar_t);
2672 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2676 smb_ParseStringBuf(const unsigned char * bufbase,
2677 cm_space_t ** stringspp,
2678 unsigned char *inp, size_t *pcb_max,
2679 char **chainpp, int flags)
2682 if (!(flags & SMB_STRF_FORCEASCII)) {
2684 cm_space_t * spacep;
2687 if (bufbase && ((inp - bufbase) % 2) != 0) {
2688 inp++; /* unicode strings are always word aligned */
2692 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2694 cch_src = *pcb_max / sizeof(wchar_t);
2698 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2705 spacep = cm_GetSpace();
2706 spacep->nextp = *stringspp;
2707 *stringspp = spacep;
2711 *chainpp = inp + sizeof(wchar_t);
2714 *(spacep->wdata) = 0;
2715 return spacep->wdata;
2718 StringCchCopyNW(spacep->wdata,
2719 lengthof(spacep->wdata),
2720 (const clientchar_t *) inp, cch_src);
2723 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2725 return spacep->wdata;
2729 cm_space_t * spacep;
2732 /* Not using Unicode */
2734 *chainpp = inp + strlen(inp) + 1;
2737 spacep = cm_GetSpace();
2738 spacep->nextp = *stringspp;
2739 *stringspp = spacep;
2741 cchdest = lengthof(spacep->wdata);
2742 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2743 spacep->wdata, cchdest);
2745 return spacep->wdata;
2751 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2753 size_t * plen, int flags)
2759 /* we are only calculating the required size */
2766 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2768 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2769 if (!(flags & SMB_STRF_IGNORENUL))
2770 *plen += sizeof(wchar_t);
2772 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2782 cch_str = cm_ClientStrLen(str);
2783 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2786 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2794 /* if outp != NULL ... */
2796 /* Number of bytes left in the buffer.
2798 If outp lies inside the packet data buffer, we assume that the
2799 buffer is the packet data buffer. Otherwise we assume that the
2800 buffer is sizeof(packet->data).
2803 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2804 align = (int)((outp - pktp->data) % 2);
2805 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2807 align = (int)(((size_t) outp) % 2);
2808 buffersize = (int)sizeof(pktp->data);
2813 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2819 if (*str == _C('\0')) {
2821 if (buffersize < sizeof(wchar_t))
2824 *((wchar_t *) outp) = L'\0';
2825 if (plen && !(flags & SMB_STRF_IGNORENUL))
2826 *plen += sizeof(wchar_t);
2827 return outp + sizeof(wchar_t);
2830 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2832 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2833 osi_LogSaveClientString(smb_logp, str),
2839 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2841 return outp + sizeof(wchar_t) * nchars;
2849 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2852 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2854 return outp + cch_dest;
2858 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2864 tlen = inp[0] + (inp[1]<<8);
2865 inp += 2; /* skip length field */
2868 *chainpp = inp + tlen;
2877 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2881 if (*inp++ != 0x1) return NULL;
2882 tlen = inp[0] + (inp[1]<<8);
2883 inp += 2; /* skip length field */
2886 *chainpp = inp + tlen;
2889 if (lengthp) *lengthp = tlen;
2894 /* format a packet as a response */
2895 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2900 outp = (smb_t *) op;
2902 /* zero the basic structure through the smb_wct field, and zero the data
2903 * size field, assuming that wct stays zero; otherwise, you have to
2904 * explicitly set the data size field, too.
2906 inSmbp = (smb_t *) inp;
2907 memset(outp, 0, sizeof(smb_t)+2);
2913 outp->com = inSmbp->com;
2914 outp->tid = inSmbp->tid;
2915 outp->pid = inSmbp->pid;
2916 outp->uid = inSmbp->uid;
2917 outp->mid = inSmbp->mid;
2918 outp->res[0] = inSmbp->res[0];
2919 outp->res[1] = inSmbp->res[1];
2920 op->inCom = inSmbp->com;
2922 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2923 #ifdef SEND_CANONICAL_PATHNAMES
2924 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2926 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2928 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2929 outp->flg2 |= SMB_FLAGS2_UNICODE;
2932 /* copy fields in generic packet area */
2933 op->wctp = &outp->wct;
2936 /* send a (probably response) packet; vcp tells us to whom to send it.
2937 * we compute the length by looking at wct and bcc fields.
2939 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2949 ncbp = smb_GetNCB();
2953 memset(ncbp, 0, sizeof(NCB));
2955 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2956 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2957 extra += tp[0] + (tp[1]<<8);
2958 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2959 extra += 3; /* wct and length fields */
2961 ncbp->ncb_length = extra; /* bytes to send */
2962 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2963 ncbp->ncb_lana_num = vcp->lana;
2964 ncbp->ncb_command = NCBSEND; /* op means send data */
2965 ncbp->ncb_buffer = (char *) inp;/* packet */
2966 code = Netbios(ncbp);
2969 const char * s = ncb_error_string(code);
2970 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2971 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2973 lock_ObtainMutex(&vcp->mx);
2974 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2975 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2977 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2978 lock_ReleaseMutex(&vcp->mx);
2979 lock_ObtainWrite(&smb_globalLock);
2980 dead_sessions[vcp->session] = TRUE;
2981 lock_ReleaseWrite(&smb_globalLock);
2982 smb_CleanupDeadVC(vcp);
2984 lock_ReleaseMutex(&vcp->mx);
2992 void smb_MapNTError(long code, unsigned long *NTStatusp)
2994 unsigned long NTStatus;
2996 /* map CM_ERROR_* errors to NT 32-bit status codes */
2997 /* NT Status codes are listed in ntstatus.h not winerror.h */
3001 else if (code == CM_ERROR_NOSUCHCELL) {
3002 NTStatus = 0xC0000034L; /* Name not found */
3004 else if (code == CM_ERROR_NOSUCHVOLUME) {
3005 NTStatus = 0xC0000034L; /* Name not found */
3007 else if (code == CM_ERROR_TIMEDOUT) {
3009 NTStatus = 0xC00000CFL; /* Sharing Paused */
3011 /* Do not send Timeout to the SMB redirector.
3012 * It causes the redirector to drop the connection */
3013 NTStatus = 0x00000102L; /* Timeout */
3014 /* do not send Retry to the SMB redirector.
3015 * It believes the error comes from the transport
3016 * layer not from the SMB server. */
3017 NTStatus = 0xC000022DL; /* Retry */
3019 NTStatus = 0xC00000B5L; /* I/O Timeout */
3022 else if (code == CM_ERROR_RETRY) {
3024 NTStatus = 0xC000022DL; /* Retry */
3026 NTStatus = 0xC00000B5L; /* I/O Timeout */
3029 else if (code == CM_ERROR_NOACCESS) {
3030 NTStatus = 0xC0000022L; /* Access denied */
3032 else if (code == CM_ERROR_READONLY) {
3033 NTStatus = 0xC00000A2L; /* Write protected */
3035 else if (code == CM_ERROR_NOSUCHFILE ||
3036 code == CM_ERROR_BPLUS_NOMATCH) {
3037 NTStatus = 0xC0000034L; /* Name not found */
3039 else if (code == CM_ERROR_NOSUCHPATH) {
3040 NTStatus = 0xC000003AL; /* Object path not found */
3042 else if (code == CM_ERROR_TOOBIG) {
3043 NTStatus = 0xC000007BL; /* Invalid image format */
3045 else if (code == CM_ERROR_INVAL) {
3046 NTStatus = 0xC000000DL; /* Invalid parameter */
3048 else if (code == CM_ERROR_BADFD) {
3049 NTStatus = 0xC0000008L; /* Invalid handle */
3051 else if (code == CM_ERROR_BADFDOP) {
3052 NTStatus = 0xC0000022L; /* Access denied */
3054 else if (code == CM_ERROR_UNKNOWN) {
3055 NTStatus = 0xC0000022L; /* Access denied */
3057 else if (code == CM_ERROR_EXISTS) {
3058 NTStatus = 0xC0000035L; /* Object name collision */
3060 else if (code == CM_ERROR_NOTEMPTY) {
3061 NTStatus = 0xC0000101L; /* Directory not empty */
3063 else if (code == CM_ERROR_CROSSDEVLINK) {
3064 NTStatus = 0xC00000D4L; /* Not same device */
3066 else if (code == CM_ERROR_NOTDIR) {
3067 NTStatus = 0xC0000103L; /* Not a directory */
3069 else if (code == CM_ERROR_ISDIR) {
3070 NTStatus = 0xC00000BAL; /* File is a directory */
3072 else if (code == CM_ERROR_BADOP) {
3074 /* I have no idea where this comes from */
3075 NTStatus = 0xC09820FFL; /* SMB no support */
3077 NTStatus = 0xC00000BBL; /* Not supported */
3078 #endif /* COMMENT */
3080 else if (code == CM_ERROR_BADSHARENAME) {
3081 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3083 else if (code == CM_ERROR_NOIPC) {
3085 NTStatus = 0xC0000022L; /* Access Denied */
3087 NTStatus = 0xC000013DL; /* Remote Resources */
3090 else if (code == CM_ERROR_CLOCKSKEW ||
3091 code == RXKADNOAUTH) {
3092 NTStatus = 0xC0000133L; /* Time difference at DC */
3094 else if (code == CM_ERROR_BADTID) {
3095 NTStatus = 0xC0982005L; /* SMB bad TID */
3097 else if (code == CM_ERROR_USESTD) {
3098 NTStatus = 0xC09820FBL; /* SMB use standard */
3100 else if (code == CM_ERROR_QUOTA) {
3101 NTStatus = 0xC0000044L; /* Quota exceeded */
3103 else if (code == CM_ERROR_SPACE) {
3104 NTStatus = 0xC000007FL; /* Disk full */
3106 else if (code == CM_ERROR_ATSYS) {
3107 NTStatus = 0xC0000033L; /* Object name invalid */
3109 else if (code == CM_ERROR_BADNTFILENAME) {
3110 NTStatus = 0xC0000033L; /* Object name invalid */
3112 else if (code == CM_ERROR_WOULDBLOCK) {
3113 NTStatus = 0xC00000D8L; /* Can't wait */
3115 else if (code == CM_ERROR_SHARING_VIOLATION) {
3116 NTStatus = 0xC0000043L; /* Sharing violation */
3118 else if (code == CM_ERROR_LOCK_CONFLICT) {
3119 NTStatus = 0xC0000054L; /* Lock conflict */
3121 else if (code == CM_ERROR_PARTIALWRITE) {
3122 NTStatus = 0xC000007FL; /* Disk full */
3124 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3125 NTStatus = 0xC0000023L; /* Buffer too small */
3127 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3128 NTStatus = 0xC0000035L; /* Object name collision */
3130 else if (code == CM_ERROR_BADPASSWORD) {
3131 NTStatus = 0xC000006DL; /* unknown username or bad password */
3133 else if (code == CM_ERROR_BADLOGONTYPE) {
3134 NTStatus = 0xC000015BL; /* logon type not granted */
3136 else if (code == CM_ERROR_GSSCONTINUE) {
3137 NTStatus = 0xC0000016L; /* more processing required */
3139 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3141 NTStatus = 0xC0000280L; /* reparse point not resolved */
3143 NTStatus = 0xC0000022L; /* Access Denied */
3146 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3147 NTStatus = 0xC0000257L; /* Path Not Covered */
3149 else if (code == CM_ERROR_ALLBUSY) {
3151 NTStatus = 0xC000022DL; /* Retry */
3153 NTStatus = 0xC00000B5L; /* I/O Timeout */
3156 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3157 NTStatus = 0xC000003AL; /* Path not found */
3159 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3160 NTStatus = 0xC0000322L; /* No Kerberos key */
3162 else if (code == CM_ERROR_BAD_LEVEL) {
3163 NTStatus = 0xC0000148L; /* Invalid Level */
3165 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3166 NTStatus = 0xC000007EL; /* Range Not Locked */
3168 else if (code == CM_ERROR_NOSUCHDEVICE) {
3169 NTStatus = 0xC000000EL; /* No Such Device */
3171 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3172 NTStatus = 0xC0000055L; /* Lock Not Granted */
3174 else if (code == ENOMEM) {
3175 NTStatus = 0xC0000017L; /* Out of Memory */
3177 else if (code == CM_ERROR_RPC_MOREDATA) {
3178 NTStatus = 0x80000005L; /* Buffer overflow */
3181 NTStatus = 0xC0982001L; /* SMB non-specific error */
3184 *NTStatusp = NTStatus;
3185 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3189 * NTSTATUS <-> Win32 Error Translation
3190 * http://support.microsoft.com/kb/113996
3192 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3194 unsigned long Win32E;
3196 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3200 else if (code == CM_ERROR_NOSUCHCELL) {
3201 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3203 else if (code == CM_ERROR_NOSUCHVOLUME) {
3204 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3206 else if (code == CM_ERROR_TIMEDOUT) {
3208 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3210 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3213 else if (code == CM_ERROR_RETRY) {
3214 Win32E = ERROR_RETRY; /* Retry */
3216 else if (code == CM_ERROR_NOACCESS) {
3217 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3219 else if (code == CM_ERROR_READONLY) {
3220 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3222 else if (code == CM_ERROR_NOSUCHFILE ||
3223 code == CM_ERROR_BPLUS_NOMATCH) {
3224 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3226 else if (code == CM_ERROR_NOSUCHPATH) {
3227 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3229 else if (code == CM_ERROR_TOOBIG) {
3230 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3232 else if (code == CM_ERROR_INVAL) {
3233 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3235 else if (code == CM_ERROR_BADFD) {
3236 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3238 else if (code == CM_ERROR_BADFDOP) {
3239 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3241 else if (code == CM_ERROR_UNKNOWN) {
3242 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3244 else if (code == CM_ERROR_EXISTS) {
3245 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3247 else if (code == CM_ERROR_NOTEMPTY) {
3248 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3250 else if (code == CM_ERROR_CROSSDEVLINK) {
3251 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3253 else if (code == CM_ERROR_NOTDIR) {
3254 Win32E = ERROR_DIRECTORY; /* Not a directory */
3256 else if (code == CM_ERROR_ISDIR) {
3257 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3259 else if (code == CM_ERROR_BADOP) {
3260 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3262 else if (code == CM_ERROR_BADSHARENAME) {
3263 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3265 else if (code == CM_ERROR_NOIPC) {
3267 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3269 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3272 else if (code == CM_ERROR_CLOCKSKEW ||
3273 code == RXKADNOAUTH) {
3274 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3276 else if (code == CM_ERROR_BADTID) {
3277 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3279 else if (code == CM_ERROR_USESTD) {
3280 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3282 else if (code == CM_ERROR_QUOTA) {
3283 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3285 else if (code == CM_ERROR_SPACE) {
3286 Win32E = ERROR_DISK_FULL; /* Disk full */
3288 else if (code == CM_ERROR_ATSYS) {
3289 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3291 else if (code == CM_ERROR_BADNTFILENAME) {
3292 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3294 else if (code == CM_ERROR_WOULDBLOCK) {
3295 Win32E = WAIT_TIMEOUT; /* Can't wait */
3297 else if (code == CM_ERROR_SHARING_VIOLATION) {
3298 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3300 else if (code == CM_ERROR_LOCK_CONFLICT) {
3301 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3303 else if (code == CM_ERROR_PARTIALWRITE) {
3304 Win32E = ERROR_DISK_FULL; /* Disk full */
3306 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3307 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3309 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3310 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3312 else if (code == CM_ERROR_BADPASSWORD) {
3313 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3315 else if (code == CM_ERROR_BADLOGONTYPE) {
3316 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3318 else if (code == CM_ERROR_GSSCONTINUE) {
3319 Win32E = ERROR_MORE_DATA; /* more processing required */
3321 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3323 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3325 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3328 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3329 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3331 else if (code == CM_ERROR_ALLBUSY) {
3332 Win32E = ERROR_RETRY; /* Retry */
3334 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3335 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3337 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3338 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3340 else if (code == CM_ERROR_BAD_LEVEL) {
3341 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3343 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3344 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3346 else if (code == CM_ERROR_NOSUCHDEVICE) {
3347 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3349 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3350 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3352 else if (code == ENOMEM) {
3353 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3355 else if (code == CM_ERROR_RPC_MOREDATA) {
3356 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3359 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3363 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3366 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3367 unsigned char *classp)
3369 unsigned char class;
3370 unsigned short error;
3372 /* map CM_ERROR_* errors to SMB errors */
3373 if (code == CM_ERROR_NOSUCHCELL) {
3375 error = 3; /* bad path */
3377 else if (code == CM_ERROR_NOSUCHVOLUME) {
3379 error = 3; /* bad path */
3381 else if (code == CM_ERROR_TIMEDOUT) {
3383 error = 81; /* server is paused */
3385 else if (code == CM_ERROR_RETRY) {
3386 class = 2; /* shouldn't happen */
3389 else if (code == CM_ERROR_NOACCESS) {
3391 error = 4; /* bad access */
3393 else if (code == CM_ERROR_READONLY) {
3395 error = 19; /* read only */
3397 else if (code == CM_ERROR_NOSUCHFILE ||
3398 code == CM_ERROR_BPLUS_NOMATCH) {
3400 error = 2; /* ENOENT! */
3402 else if (code == CM_ERROR_NOSUCHPATH) {
3404 error = 3; /* Bad path */
3406 else if (code == CM_ERROR_TOOBIG) {
3408 error = 11; /* bad format */
3410 else if (code == CM_ERROR_INVAL) {
3411 class = 2; /* server non-specific error code */
3414 else if (code == CM_ERROR_BADFD) {
3416 error = 6; /* invalid file handle */
3418 else if (code == CM_ERROR_BADFDOP) {
3419 class = 1; /* invalid op on FD */
3422 else if (code == CM_ERROR_EXISTS) {
3424 error = 80; /* file already exists */
3426 else if (code == CM_ERROR_NOTEMPTY) {
3428 error = 5; /* delete directory not empty */
3430 else if (code == CM_ERROR_CROSSDEVLINK) {
3432 error = 17; /* EXDEV */
3434 else if (code == CM_ERROR_NOTDIR) {
3435 class = 1; /* bad path */
3438 else if (code == CM_ERROR_ISDIR) {
3439 class = 1; /* access denied; DOS doesn't have a good match */
3442 else if (code == CM_ERROR_BADOP) {
3446 else if (code == CM_ERROR_BADSHARENAME) {
3450 else if (code == CM_ERROR_NOIPC) {
3452 error = 4; /* bad access */
3454 else if (code == CM_ERROR_CLOCKSKEW) {
3455 class = 1; /* invalid function */
3458 else if (code == CM_ERROR_BADTID) {
3462 else if (code == CM_ERROR_USESTD) {
3466 else if (code == CM_ERROR_REMOTECONN) {
3470 else if (code == CM_ERROR_QUOTA) {
3471 if (vcp->flags & SMB_VCFLAG_USEV3) {
3473 error = 39; /* disk full */
3477 error = 5; /* access denied */
3480 else if (code == CM_ERROR_SPACE) {
3481 if (vcp->flags & SMB_VCFLAG_USEV3) {
3483 error = 39; /* disk full */
3487 error = 5; /* access denied */
3490 else if (code == CM_ERROR_PARTIALWRITE) {
3492 error = 39; /* disk full */
3494 else if (code == CM_ERROR_ATSYS) {
3496 error = 2; /* ENOENT */
3498 else if (code == CM_ERROR_WOULDBLOCK) {
3500 error = 33; /* lock conflict */
3502 else if (code == CM_ERROR_LOCK_CONFLICT) {
3504 error = 33; /* lock conflict */
3506 else if (code == CM_ERROR_SHARING_VIOLATION) {
3508 error = 33; /* lock conflict */
3510 else if (code == CM_ERROR_NOFILES) {
3512 error = 18; /* no files in search */
3514 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3516 error = 183; /* Samba uses this */
3518 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3519 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3521 error = 2; /* bad password */
3523 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3525 error = 3; /* bad path */
3534 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3537 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3539 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3540 return CM_ERROR_BADOP;
3544 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3546 unsigned short EchoCount, i;
3547 char *data, *outdata;
3550 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3552 for (i=1; i<=EchoCount; i++) {
3553 data = smb_GetSMBData(inp, &dataSize);
3554 smb_SetSMBParm(outp, 0, i);
3555 smb_SetSMBDataLength(outp, dataSize);
3556 outdata = smb_GetSMBData(outp, NULL);
3557 memcpy(outdata, data, dataSize);
3558 smb_SendPacket(vcp, outp);
3564 /* SMB_COM_READ_RAW */
3565 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3568 long count, minCount, finalCount;
3572 smb_t *smbp = (smb_t*) inp;
3574 cm_user_t *userp = NULL;
3577 char *rawBuf = NULL;
3582 fd = smb_GetSMBParm(inp, 0);
3583 count = smb_GetSMBParm(inp, 3);
3584 minCount = smb_GetSMBParm(inp, 4);
3585 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3587 if (*inp->wctp == 10) {
3588 /* we were sent a request with 64-bit file offsets */
3589 #ifdef AFS_LARGEFILES
3590 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3592 if (LargeIntegerLessThanZero(offset)) {
3593 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3597 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3598 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3601 offset.HighPart = 0;
3605 /* we were sent a request with 32-bit file offsets */
3606 offset.HighPart = 0;
3609 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3610 fd, offset.HighPart, offset.LowPart, count);
3612 fidp = smb_FindFID(vcp, fd, 0);
3614 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3618 lock_ObtainMutex(&fidp->mx);
3620 lock_ReleaseMutex(&fidp->mx);
3621 smb_ReleaseFID(fidp);
3622 return CM_ERROR_BADFD;
3625 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3626 lock_ReleaseMutex(&fidp->mx);
3627 smb_CloseFID(vcp, fidp, NULL, 0);
3628 code = CM_ERROR_NOSUCHFILE;
3634 LARGE_INTEGER LOffset, LLength;
3637 key = cm_GenerateKey(vcp->vcID, pid, fd);
3639 LOffset.HighPart = offset.HighPart;
3640 LOffset.LowPart = offset.LowPart;
3641 LLength.HighPart = 0;
3642 LLength.LowPart = count;
3644 lock_ObtainWrite(&fidp->scp->rw);
3645 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3646 lock_ReleaseWrite(&fidp->scp->rw);
3649 lock_ReleaseMutex(&fidp->mx);
3653 lock_ObtainMutex(&smb_RawBufLock);
3655 /* Get a raw buf, from head of list */
3656 rawBuf = smb_RawBufs;
3657 smb_RawBufs = *(char **)smb_RawBufs;
3659 lock_ReleaseMutex(&smb_RawBufLock);
3661 lock_ReleaseMutex(&fidp->mx);
3665 if (fidp->flags & SMB_FID_IOCTL)
3667 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3669 /* Give back raw buffer */
3670 lock_ObtainMutex(&smb_RawBufLock);
3671 *((char **) rawBuf) = smb_RawBufs;
3673 smb_RawBufs = rawBuf;
3674 lock_ReleaseMutex(&smb_RawBufLock);
3677 lock_ReleaseMutex(&fidp->mx);
3678 smb_ReleaseFID(fidp);
3681 lock_ReleaseMutex(&fidp->mx);
3683 userp = smb_GetUserFromVCP(vcp, inp);
3685 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3691 cm_ReleaseUser(userp);
3694 smb_ReleaseFID(fidp);
3698 memset(ncbp, 0, sizeof(NCB));
3700 ncbp->ncb_length = (unsigned short) finalCount;
3701 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3702 ncbp->ncb_lana_num = vcp->lana;
3703 ncbp->ncb_command = NCBSEND;
3704 ncbp->ncb_buffer = rawBuf;
3706 code = Netbios(ncbp);
3708 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3711 /* Give back raw buffer */
3712 lock_ObtainMutex(&smb_RawBufLock);
3713 *((char **) rawBuf) = smb_RawBufs;
3715 smb_RawBufs = rawBuf;
3716 lock_ReleaseMutex(&smb_RawBufLock);
3722 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3724 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3729 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3731 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3736 /* SMB_COM_NEGOTIATE */
3737 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3744 int VistaProtoIndex;
3745 int protoIndex; /* index we're using */
3750 char protocol_array[10][1024]; /* protocol signature of the client */
3751 int caps; /* capabilities */
3754 TIME_ZONE_INFORMATION tzi;
3756 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3759 namep = smb_GetSMBData(inp, &dbytes);
3762 coreProtoIndex = -1; /* not found */
3765 VistaProtoIndex = -1;
3766 while(namex < dbytes) {
3767 osi_Log1(smb_logp, "Protocol %s",
3768 osi_LogSaveString(smb_logp, namep+1));
3769 strcpy(protocol_array[tcounter], namep+1);
3771 /* namep points at the first protocol, or really, a 0x02
3772 * byte preceding the null-terminated ASCII name.
3774 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3775 coreProtoIndex = tcounter;
3777 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3778 v3ProtoIndex = tcounter;
3780 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3781 NTProtoIndex = tcounter;
3783 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3784 VistaProtoIndex = tcounter;
3787 /* compute size of protocol entry */
3788 entryLength = (int)strlen(namep+1);
3789 entryLength += 2; /* 0x02 bytes and null termination */
3791 /* advance over this protocol entry */
3792 namex += entryLength;
3793 namep += entryLength;
3794 tcounter++; /* which proto entry we're looking at */
3797 lock_ObtainMutex(&vcp->mx);
3799 if (VistaProtoIndex != -1) {
3800 protoIndex = VistaProtoIndex;
3801 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3804 if (NTProtoIndex != -1) {
3805 protoIndex = NTProtoIndex;
3806 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3808 else if (v3ProtoIndex != -1) {
3809 protoIndex = v3ProtoIndex;
3810 vcp->flags |= SMB_VCFLAG_USEV3;
3812 else if (coreProtoIndex != -1) {
3813 protoIndex = coreProtoIndex;
3814 vcp->flags |= SMB_VCFLAG_USECORE;
3816 else protoIndex = -1;
3817 lock_ReleaseMutex(&vcp->mx);
3819 if (protoIndex == -1)
3820 return CM_ERROR_INVAL;
3821 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3822 smb_SetSMBParm(outp, 0, protoIndex);
3823 if (smb_authType != SMB_AUTH_NONE) {
3824 smb_SetSMBParmByte(outp, 1,
3825 NEGOTIATE_SECURITY_USER_LEVEL |
3826 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3828 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3830 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3831 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3832 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3833 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3834 /* The session key is not a well documented field however most clients
3835 * will echo back the session key to the server. Currently we are using
3836 * the same value for all sessions. We should generate a random value
3837 * and store it into the vcp
3839 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3840 smb_SetSMBParm(outp, 8, 1);
3842 * Tried changing the capabilities to support for W2K - defect 117695
3843 * Maybe something else needs to be changed here?
3847 smb_SetSMBParmLong(outp, 9, 0x43fd);
3849 smb_SetSMBParmLong(outp, 9, 0x251);
3852 * 32-bit error codes *
3858 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3860 NTNEGOTIATE_CAPABILITY_DFS |
3862 #ifdef AFS_LARGEFILES
3863 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3865 NTNEGOTIATE_CAPABILITY_NTFIND |
3866 NTNEGOTIATE_CAPABILITY_RAWMODE |
3867 NTNEGOTIATE_CAPABILITY_NTSMB;
3869 if ( smb_authType == SMB_AUTH_EXTENDED )
3870 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3873 if ( smb_UseUnicode ) {
3874 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3878 smb_SetSMBParmLong(outp, 9, caps);
3880 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3881 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3882 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3884 GetTimeZoneInformation(&tzi);
3885 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3887 if (smb_authType == SMB_AUTH_NTLM) {
3888 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3889 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3890 /* paste in encryption key */
3891 datap = smb_GetSMBData(outp, NULL);
3892 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3893 /* and the faux domain name */
3894 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3895 datap + MSV1_0_CHALLENGE_LENGTH,
3896 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3897 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3901 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3903 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3905 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3907 datap = smb_GetSMBData(outp, NULL);
3908 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3911 datap += sizeof(smb_ServerGUID);
3912 memcpy(datap, secBlob, secBlobLength);
3916 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3917 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3920 else if (v3ProtoIndex != -1) {
3921 smb_SetSMBParm(outp, 0, protoIndex);
3923 /* NOTE: Extended authentication cannot be negotiated with v3
3924 * therefore we fail over to NTLM
3926 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3927 smb_SetSMBParm(outp, 1,
3928 NEGOTIATE_SECURITY_USER_LEVEL |
3929 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3931 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3933 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3934 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3935 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3936 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3937 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3938 smb_SetSMBParm(outp, 7, 1);
3940 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3941 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3942 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3944 GetTimeZoneInformation(&tzi);
3945 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3947 /* NOTE: Extended authentication cannot be negotiated with v3
3948 * therefore we fail over to NTLM
3950 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3951 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3952 smb_SetSMBParm(outp, 12, 0); /* resvd */
3953 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3954 datap = smb_GetSMBData(outp, NULL);
3955 /* paste in a new encryption key */
3956 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3957 /* and the faux domain name */
3958 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3959 datap + MSV1_0_CHALLENGE_LENGTH,
3960 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3962 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3963 smb_SetSMBParm(outp, 12, 0); /* resvd */
3964 smb_SetSMBDataLength(outp, 0);
3967 else if (coreProtoIndex != -1) { /* not really supported anymore */
3968 smb_SetSMBParm(outp, 0, protoIndex);
3969 smb_SetSMBDataLength(outp, 0);
3974 void smb_CheckVCs(void)
3976 smb_vc_t * vcp, *nextp;
3977 smb_packet_t * outp = smb_GetPacket();
3980 lock_ObtainWrite(&smb_rctLock);
3981 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3983 if (vcp->magic != SMB_VC_MAGIC)
3984 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3985 __FILE__, __LINE__);
3987 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3989 smb_HoldVCNoLock(vcp);
3992 * obtain a reference to 'nextp' now because we drop the
3993 * smb_rctLock later and the list contents could change
3994 * or 'vcp' could be destroyed when released.
3998 smb_HoldVCNoLock(nextp);
4000 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4001 smb_ReleaseVCNoLock(vcp);
4005 smb_FormatResponsePacket(vcp, NULL, outp);
4006 smbp = (smb_t *)outp;
4007 outp->inCom = smbp->com = 0x2b /* Echo */;
4015 smb_SetSMBParm(outp, 0, 0);
4016 smb_SetSMBDataLength(outp, 0);
4017 lock_ReleaseWrite(&smb_rctLock);
4019 smb_SendPacket(vcp, outp);
4021 lock_ObtainWrite(&smb_rctLock);
4022 smb_ReleaseVCNoLock(vcp);
4024 lock_ReleaseWrite(&smb_rctLock);
4025 smb_FreePacket(outp);
4028 void smb_Daemon(void *parmp)
4030 afs_uint32 count = 0;
4031 smb_username_t **unpp;
4034 while(smbShutdownFlag == 0) {
4038 if (smbShutdownFlag == 1)
4041 if ((count % 72) == 0) { /* every five minutes */
4043 time_t old_localZero = smb_localZero;
4045 /* Initialize smb_localZero */
4046 myTime.tm_isdst = -1; /* compute whether on DST or not */
4047 myTime.tm_year = 70;
4053 smb_localZero = mktime(&myTime);
4055 #ifdef AFS_FREELANCE
4056 if ( smb_localZero != old_localZero )
4057 cm_noteLocalMountPointChange();
4063 /* GC smb_username_t objects that will no longer be used */
4065 lock_ObtainWrite(&smb_rctLock);
4066 for ( unpp=&usernamesp; *unpp; ) {
4068 smb_username_t *unp;
4070 lock_ObtainMutex(&(*unpp)->mx);
4071 if ( (*unpp)->refCount > 0 ||
4072 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4073 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4075 else if (!smb_LogoffTokenTransfer ||
4076 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4078 lock_ReleaseMutex(&(*unpp)->mx);
4086 lock_FinalizeMutex(&unp->mx);
4092 cm_ReleaseUser(userp);
4094 unpp = &(*unpp)->nextp;
4097 lock_ReleaseWrite(&smb_rctLock);
4099 /* XXX GC dir search entries */
4103 void smb_WaitingLocksDaemon()
4105 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4106 smb_waitingLock_t *wl, *wlNext;
4109 smb_packet_t *inp, *outp;
4113 while (smbShutdownFlag == 0) {
4114 lock_ObtainWrite(&smb_globalLock);
4115 nwlRequest = smb_allWaitingLocks;
4116 if (nwlRequest == NULL) {
4117 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4122 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4129 lock_ObtainWrite(&smb_globalLock);
4131 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4133 wlRequest = nwlRequest;
4134 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4135 lock_ReleaseWrite(&smb_globalLock);
4139 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4140 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4143 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4144 code = CM_ERROR_LOCK_NOT_GRANTED;
4148 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4150 /* wl->state is either _DONE or _WAITING. _ERROR
4151 would no longer be on the queue. */
4152 code = cm_RetryLock( wl->lockp,
4153 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4156 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4157 } else if (code != CM_ERROR_WOULDBLOCK) {
4158 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4163 if (code == CM_ERROR_WOULDBLOCK) {
4166 if (wlRequest->msTimeout != 0xffffffff
4167 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4179 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4182 scp = wlRequest->scp;
4183 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4187 lock_ObtainWrite(&scp->rw);
4189 for (wl = wlRequest->locks; wl; wl = wlNext) {
4190 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4192 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4193 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4194 wl->LLength, wl->key, 0, NULL, &req);
4196 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4201 lock_ReleaseWrite(&scp->rw);
4205 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4208 for (wl = wlRequest->locks; wl; wl = wlNext) {
4209 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4210 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4215 vcp = wlRequest->vcp;
4216 inp = wlRequest->inp;
4217 outp = wlRequest->outp;
4218 ncbp = smb_GetNCB();
4219 ncbp->ncb_length = inp->ncb_length;
4220 inp->spacep = cm_GetSpace();
4222 /* Remove waitingLock from list */
4223 lock_ObtainWrite(&smb_globalLock);
4224 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4226 lock_ReleaseWrite(&smb_globalLock);
4228 /* Resume packet processing */
4230 smb_SetSMBDataLength(outp, 0);
4231 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4232 outp->resumeCode = code;
4234 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4237 cm_FreeSpace(inp->spacep);
4238 smb_FreePacket(inp);
4239 smb_FreePacket(outp);
4241 cm_ReleaseSCache(wlRequest->scp);
4244 } while (nwlRequest && smbShutdownFlag == 0);
4249 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4251 osi_Log0(smb_logp, "SMB receive get disk attributes");
4253 smb_SetSMBParm(outp, 0, 32000);
4254 smb_SetSMBParm(outp, 1, 64);
4255 smb_SetSMBParm(outp, 2, 1024);
4256 smb_SetSMBParm(outp, 3, 30000);
4257 smb_SetSMBParm(outp, 4, 0);
4258 smb_SetSMBDataLength(outp, 0);
4262 /* SMB_COM_TREE_CONNECT */
4263 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4267 unsigned short newTid;
4268 clientchar_t shareName[AFSPATHMAX];
4269 clientchar_t *sharePath;
4272 clientchar_t *pathp;
4275 osi_Log0(smb_logp, "SMB receive tree connect");
4277 /* parse input parameters */
4280 tbp = smb_GetSMBData(inp, NULL);
4281 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4283 return CM_ERROR_BADSMB;
4285 tp = cm_ClientStrRChr(pathp, '\\');
4287 return CM_ERROR_BADSMB;
4288 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4290 lock_ObtainMutex(&vcp->mx);
4291 newTid = vcp->tidCounter++;
4292 lock_ReleaseMutex(&vcp->mx);
4294 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4295 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4297 return CM_ERROR_BADSMB;
4298 userp = smb_GetUserFromUID(uidp);
4299 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4300 smb_ReleaseUID(uidp);
4302 smb_ReleaseTID(tidp, FALSE);
4303 return CM_ERROR_BADSHARENAME;
4305 lock_ObtainMutex(&tidp->mx);
4306 tidp->userp = userp;
4307 tidp->pathname = sharePath;
4308 lock_ReleaseMutex(&tidp->mx);
4309 smb_ReleaseTID(tidp, FALSE);
4311 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4312 smb_SetSMBParm(rsp, 1, newTid);
4313 smb_SetSMBDataLength(rsp, 0);
4315 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4319 /* set maskp to the mask part of the incoming path.
4320 * Mask is 11 bytes long (8.3 with the dot elided).
4321 * Returns true if succeeds with a valid name, otherwise it does
4322 * its best, but returns false.
4324 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4332 /* starts off valid */
4335 /* mask starts out all blanks */
4336 memset(maskp, ' ', 11);
4339 /* find last backslash, or use whole thing if there is none */
4340 tp = cm_ClientStrRChr(pathp, '\\');
4344 tp++; /* skip slash */
4348 /* names starting with a dot are illegal */
4356 if (tc == '.' || tc == '"')
4364 /* if we get here, tp point after the dot */
4365 up = maskp+8; /* ext goes here */
4372 if (tc == '.' || tc == '"')
4375 /* copy extension if not too long */
4385 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4387 clientchar_t umask[11];
4395 /* XXX redo this, calling cm_MatchMask with a converted mask */
4397 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4401 /* otherwise, we have a valid 8.3 name; see if we have a match,
4402 * treating '?' as a wildcard in maskp (but not in the file name).
4404 tp1 = umask; /* real name, in mask format */
4405 tp2 = maskp; /* mask, in mask format */
4406 for(i=0; i<11; i++) {
4407 tc1 = *tp1++; /* clientchar_t from real name */
4408 tc2 = *tp2++; /* clientchar_t from mask */
4409 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4410 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4413 if (tc2 == '?' && tc1 != ' ')
4420 /* we got a match */
4424 clientchar_t *smb_FindMask(clientchar_t *pathp)
4428 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4431 return tp+1; /* skip the slash */
4433 return pathp; /* no slash, return the entire path */
4436 /* SMB_COM_SEARCH for a volume label
4438 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4439 dispatch function.) */
4440 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4442 clientchar_t *pathp;
4444 clientchar_t mask[12];
4445 unsigned char *statBlockp;
4446 unsigned char initStatBlock[21];
4449 osi_Log0(smb_logp, "SMB receive search volume");
4451 /* pull pathname and stat block out of request */
4452 tp = smb_GetSMBData(inp, NULL);
4453 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4454 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4456 return CM_ERROR_BADSMB;
4457 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4458 osi_assertx(statBlockp != NULL, "null statBlock");
4460 statBlockp = initStatBlock;
4464 /* for returning to caller */
4465 smb_Get8Dot3MaskFromPath(mask, pathp);
4467 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4468 tp = smb_GetSMBData(outp, NULL);
4470 *tp++ = 43; /* bytes in a dir entry */
4471 *tp++ = 0; /* high byte in counter */
4473 /* now marshall the dir entry, starting with the search status */
4474 *tp++ = statBlockp[0]; /* Reserved */
4475 memcpy(tp, mask, 11); tp += 11; /* FileName */
4477 /* now pass back server use info, with 1st byte non-zero */
4479 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4481 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4483 *tp++ = 0x8; /* attribute: volume */
4493 /* 4 byte file size */
4499 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4502 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4503 memset(tp, ' ', 13);
4506 /* set the length of the data part of the packet to 43 + 3, for the dir
4507 * entry plus the 5 and the length fields.
4509 smb_SetSMBDataLength(outp, 46);
4514 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4515 clientchar_t * tidPathp, clientchar_t * relPathp,
4516 cm_user_t *userp, cm_req_t *reqp)
4524 smb_dirListPatch_t *patchp;
4525 smb_dirListPatch_t *npatchp;
4526 clientchar_t path[AFSPATHMAX];
4528 afs_int32 mustFake = 0;
4530 code = cm_FindACLCache(dscp, userp, &rights);
4532 lock_ObtainWrite(&dscp->rw);
4533 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4534 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4535 lock_ReleaseWrite(&dscp->rw);
4536 if (code == CM_ERROR_NOACCESS) {
4544 if (!mustFake) { /* Bulk Stat */
4546 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4548 memset(bsp, 0, sizeof(cm_bulkStat_t));
4550 for (patchp = *dirPatchespp, count=0;
4552 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4553 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4557 if (lock_TryWrite(&tscp->rw)) {
4558 /* we have an entry that we can look at */
4559 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4560 /* we have a callback on it. Don't bother
4561 * fetching this stat entry, since we're happy
4562 * with the info we have.
4564 lock_ReleaseWrite(&tscp->rw);
4565 cm_ReleaseSCache(tscp);
4568 lock_ReleaseWrite(&tscp->rw);
4570 cm_ReleaseSCache(tscp);
4574 bsp->fids[i].Volume = patchp->fid.volume;
4575 bsp->fids[i].Vnode = patchp->fid.vnode;
4576 bsp->fids[i].Unique = patchp->fid.unique;
4578 if (bsp->counter == AFSCBMAX) {
4579 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4580 memset(bsp, 0, sizeof(cm_bulkStat_t));
4584 if (bsp->counter > 0)
4585 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4590 for (patchp = *dirPatchespp; patchp; patchp =
4591 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4593 dptr = patchp->dptr;
4595 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4596 relPathp ? relPathp : _C(""), patchp->dep->name);
4597 reqp->relPathp = path;
4598 reqp->tidPathp = tidPathp;
4600 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4601 reqp->relPathp = reqp->tidPathp = NULL;
4604 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4605 *dptr++ = SMB_ATTR_HIDDEN;
4608 lock_ObtainWrite(&scp->rw);
4609 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4610 lock_ReleaseWrite(&scp->rw);
4612 /* set the attribute */
4613 switch (scp->fileType) {
4614 case CM_SCACHETYPE_DIRECTORY:
4615 case CM_SCACHETYPE_MOUNTPOINT:
4616 case CM_SCACHETYPE_INVALID:
4617 attr = SMB_ATTR_DIRECTORY;
4619 case CM_SCACHETYPE_SYMLINK:
4620 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4621 attr = SMB_ATTR_DIRECTORY;
4623 attr = SMB_ATTR_NORMAL;
4626 /* if we get here we either have a normal file
4627 * or we have a file for which we have never
4628 * received status info. In this case, we can
4629 * check the even/odd value of the entry's vnode.
4630 * odd means it is to be treated as a directory
4631 * and even means it is to be treated as a file.
4633 if (mustFake && (scp->fid.vnode & 0x1))
4634 attr = SMB_ATTR_DIRECTORY;
4636 attr = SMB_ATTR_NORMAL;
4640 /* 1969-12-31 23:59:58 +00*/
4641 dosTime = 0xEBBFBF7D;
4644 shortTemp = (unsigned short) (dosTime & 0xffff);
4645 *((u_short *)dptr) = shortTemp;
4648 /* and copy out date */
4649 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4650 *((u_short *)dptr) = shortTemp;
4653 /* copy out file length */
4654 *((u_long *)dptr) = 0;
4657 lock_ConvertWToR(&scp->rw);
4658 attr = smb_Attributes(scp);
4659 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4660 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4661 attr |= SMB_ATTR_HIDDEN;
4665 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4668 shortTemp = (unsigned short) (dosTime & 0xffff);
4669 *((u_short *)dptr) = shortTemp;
4672 /* and copy out date */
4673 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4674 *((u_short *)dptr) = shortTemp;
4677 /* copy out file length */
4678 *((u_long *)dptr) = scp->length.LowPart;
4680 lock_ReleaseRead(&scp->rw);
4682 cm_ReleaseSCache(scp);
4685 /* now free the patches */
4686 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4687 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4691 /* and mark the list as empty */
4692 *dirPatchespp = NULL;
4698 /* SMB_COM_SEARCH */
4699 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4705 clientchar_t *pathp;
4706 cm_dirEntry_t *dep = 0;
4708 smb_dirListPatch_t *dirListPatchesp;
4709 smb_dirListPatch_t *curPatchp;
4713 osi_hyper_t dirLength;
4714 osi_hyper_t bufferOffset;
4715 osi_hyper_t curOffset;
4717 unsigned char *inCookiep;
4718 smb_dirSearch_t *dsp;
4722 unsigned long clientCookie;
4723 cm_pageHeader_t *pageHeaderp;
4724 cm_user_t *userp = NULL;
4726 clientchar_t mask[12];
4728 long nextEntryCookie;
4729 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4730 char resByte; /* reserved byte from the cookie */
4731 char *op; /* output data ptr */
4732 char *origOp; /* original value of op */
4733 cm_space_t *spacep; /* for pathname buffer */
4737 clientchar_t *tidPathp = 0;
4744 maxCount = smb_GetSMBParm(inp, 0);
4746 dirListPatchesp = NULL;
4748 caseFold = CM_FLAG_CASEFOLD;
4750 tp = smb_GetSMBData(inp, NULL);
4751 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4752 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4754 return CM_ERROR_BADSMB;
4756 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4758 return CM_ERROR_BADSMB;
4760 /* We can handle long names */
4761 if (vcp->flags & SMB_VCFLAG_USENT)
4762 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4764 /* make sure we got a whole search status */
4765 if (dataLength < 21) {
4766 nextCookie = 0; /* start at the beginning of the dir */
4769 attribute = smb_GetSMBParm(inp, 1);
4771 /* handle volume info in another function */
4772 if (attribute & 0x8)
4773 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4775 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4776 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4778 if (*pathp == 0) { /* null pathp, treat as root dir */
4779 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4780 return CM_ERROR_NOFILES;
4784 dsp = smb_NewDirSearch(0);
4785 dsp->attribute = attribute;
4786 smb_Get8Dot3MaskFromPath(mask, pathp);
4787 memcpy(dsp->mask, mask, 12);
4789 /* track if this is likely to match a lot of entries */
4790 if (smb_Is8Dot3StarMask(mask))
4795 /* pull the next cookie value out of the search status block */
4796 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4797 + (inCookiep[16]<<24);
4798 dsp = smb_FindDirSearch(inCookiep[12]);
4800 /* can't find dir search status; fatal error */
4801 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4802 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4803 return CM_ERROR_BADFD;
4805 attribute = dsp->attribute;
4806 resByte = inCookiep[0];
4808 /* copy out client cookie, in host byte order. Don't bother
4809 * interpreting it, since we're just passing it through, anyway.
4811 memcpy(&clientCookie, &inCookiep[17], 4);
4813 memcpy(mask, dsp->mask, 12);
4815 /* assume we're doing a star match if it has continued for more
4821 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4822 nextCookie, dsp->cookie, attribute);
4824 userp = smb_GetUserFromVCP(vcp, inp);
4826 /* try to get the vnode for the path name next */
4827 lock_ObtainMutex(&dsp->mx);
4830 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4834 spacep = inp->spacep;
4835 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4836 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4838 lock_ReleaseMutex(&dsp->mx);
4839 cm_ReleaseUser(userp);
4840 smb_DeleteDirSearch(dsp);
4841 smb_ReleaseDirSearch(dsp);
4842 return CM_ERROR_NOFILES;
4844 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4845 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4847 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4848 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4851 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4854 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4855 cm_ReleaseSCache(scp);
4856 lock_ReleaseMutex(&dsp->mx);
4857 cm_ReleaseUser(userp);
4858 smb_DeleteDirSearch(dsp);
4859 smb_ReleaseDirSearch(dsp);
4860 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4861 return CM_ERROR_PATH_NOT_COVERED;
4863 return CM_ERROR_NOSUCHPATH;
4865 #endif /* DFS_SUPPORT */
4868 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4869 /* we need one hold for the entry we just stored into,
4870 * and one for our own processing. When we're done with this
4871 * function, we'll drop the one for our own processing.
4872 * We held it once from the namei call, and so we do another hold
4876 lock_ObtainWrite(&scp->rw);
4877 dsp->flags |= SMB_DIRSEARCH_BULKST;
4878 lock_ReleaseWrite(&scp->rw);
4881 lock_ReleaseMutex(&dsp->mx);
4883 cm_ReleaseUser(userp);
4884 smb_DeleteDirSearch(dsp);
4885 smb_ReleaseDirSearch(dsp);
4889 /* reserves space for parameter; we'll adjust it again later to the
4890 * real count of the # of entries we returned once we've actually
4891 * assembled the directory listing.
4893 smb_SetSMBParm(outp, 0, 0);
4895 /* get the directory size */
4896 lock_ObtainWrite(&scp->rw);
4897 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4898 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4900 lock_ReleaseWrite(&scp->rw);
4901 cm_ReleaseSCache(scp);
4902 cm_ReleaseUser(userp);
4903 smb_DeleteDirSearch(dsp);
4904 smb_ReleaseDirSearch(dsp);
4908 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4910 dirLength = scp->length;
4912 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4913 curOffset.HighPart = 0;
4914 curOffset.LowPart = nextCookie;
4915 origOp = op = smb_GetSMBData(outp, NULL);
4916 /* and write out the basic header */
4917 *op++ = 5; /* variable block */
4918 op += 2; /* skip vbl block length; we'll fill it in later */
4922 clientchar_t *actualName = NULL;
4923 int free_actualName = 0;
4924 clientchar_t shortName[13];
4925 clientchar_t *shortNameEnd;
4927 /* make sure that curOffset.LowPart doesn't point to the first
4928 * 32 bytes in the 2nd through last dir page, and that it doesn't
4929 * point at the first 13 32-byte chunks in the first dir page,
4930 * since those are dir and page headers, and don't contain useful
4933 temp = curOffset.LowPart & (2048-1);
4934 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4935 /* we're in the first page */
4936 if (temp < 13*32) temp = 13*32;
4939 /* we're in a later dir page */
4940 if (temp < 32) temp = 32;
4943 /* make sure the low order 5 bits are zero */
4946 /* now put temp bits back ito curOffset.LowPart */
4947 curOffset.LowPart &= ~(2048-1);
4948 curOffset.LowPart |= temp;
4950 /* check if we've returned all the names that will fit in the
4953 if (returnedNames >= maxCount) {
4954 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4955 returnedNames, maxCount);
4959 /* check if we've passed the dir's EOF */
4960 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4962 /* see if we can use the bufferp we have now; compute in which page
4963 * the current offset would be, and check whether that's the offset
4964 * of the buffer we have. If not, get the buffer.
4966 thyper.HighPart = curOffset.HighPart;
4967 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4968 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4971 buf_Release(bufferp);
4974 lock_ReleaseWrite(&scp->rw);
4975 code = buf_Get(scp, &thyper, &req, &bufferp);
4976 lock_ObtainMutex(&dsp->mx);
4978 /* now, if we're doing a star match, do bulk fetching of all of
4979 * the status info for files in the dir.
4982 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4984 lock_ObtainWrite(&scp->rw);
4985 lock_ReleaseMutex(&dsp->mx);
4987 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4991 bufferOffset = thyper;
4993 /* now get the data in the cache */
4995 code = cm_SyncOp(scp, bufferp, userp, &req,
4997 CM_SCACHESYNC_NEEDCALLBACK |
4998 CM_SCACHESYNC_READ);
5000 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5004 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5006 if (cm_HaveBuffer(scp, bufferp, 0)) {
5007 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5011 /* otherwise, load the buffer and try again */
5012 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5014 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5015 scp, bufferp, code);
5020 buf_Release(bufferp);
5024 } /* if (wrong buffer) ... */
5026 /* now we have the buffer containing the entry we're interested in; copy
5027 * it out if it represents a non-deleted entry.
5029 entryInDir = curOffset.LowPart & (2048-1);
5030 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5032 /* page header will help tell us which entries are free. Page header
5033 * can change more often than once per buffer, since AFS 3 dir page size
5034 * may be less than (but not more than a buffer package buffer.
5036 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5037 temp &= ~(2048 - 1); /* turn off intra-page bits */
5038 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5040 /* now determine which entry we're looking at in the page. If it is
5041 * free (there's a free bitmap at the start of the dir), we should
5042 * skip these 32 bytes.
5044 slotInPage = (entryInDir & 0x7e0) >> 5;
5045 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5046 /* this entry is free */
5047 numDirChunks = 1; /* only skip this guy */
5051 tp = bufferp->datap + entryInBuffer;
5052 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5054 /* while we're here, compute the next entry's location, too,
5055 * since we'll need it when writing out the cookie into the dir
5058 * XXXX Probably should do more sanity checking.
5060 numDirChunks = cm_NameEntries(dep->name, NULL);
5062 /* compute the offset of the cookie representing the next entry */
5063 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5065 /* Compute 8.3 name if necessary */
5066 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5067 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5070 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5071 actualName = shortName;
5072 free_actualName = 0;
5074 free_actualName = 1;
5077 if (actualName == NULL) {
5078 /* Couldn't convert the name for some reason */
5079 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5080 osi_LogSaveString(smb_logp, dep->name));
5084 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5085 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5086 osi_LogSaveClientString(smb_logp, actualName));
5088 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5089 /* this is one of the entries to use: it is not deleted
5090 * and it matches the star pattern we're looking for.
5093 /* Eliminate entries that don't match requested
5096 /* no hidden files */
5097 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5098 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5102 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5104 /* We have already done the cm_TryBulkStat above */
5105 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5106 fileType = cm_FindFileType(&fid);
5107 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5108 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5110 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5111 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5112 fileType == CM_SCACHETYPE_DFSLINK ||
5113 fileType == CM_SCACHETYPE_INVALID)
5114 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5119 memcpy(op, mask, 11); op += 11;
5120 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5121 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5122 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5123 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5124 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5125 memcpy(op, &clientCookie, 4); op += 4;
5127 /* now we emit the attribute. This is sort of tricky,
5128 * since we need to really stat the file to find out
5129 * what type of entry we've got. Right now, we're
5130 * copying out data from a buffer, while holding the
5131 * scp locked, so it isn't really convenient to stat
5132 * something now. We'll put in a place holder now,
5133 * and make a second pass before returning this to get
5134 * the real attributes. So, we just skip the data for
5135 * now, and adjust it later. We allocate a patch
5136 * record to make it easy to find this point later.
5137 * The replay will happen at a time when it is safe to
5138 * unlock the directory.
5140 curPatchp = malloc(sizeof(*curPatchp));
5141 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5142 curPatchp->dptr = op;
5143 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5145 /* do hidden attribute here since name won't be around when applying
5149 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5150 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5152 curPatchp->flags = 0;
5154 op += 9; /* skip attr, time, date and size */
5156 /* zero out name area. The spec says to pad with
5157 * spaces, but Samba doesn't, and neither do we.
5161 /* finally, we get to copy out the name; we know that
5162 * it fits in 8.3 or the pattern wouldn't match, but it
5163 * never hurts to be sure.
5165 cm_ClientStringToUtf8(actualName, -1, op, 13);
5166 if (smb_StoreAnsiFilenames)
5168 /* This is a UCHAR field, which is ASCII even if Unicode
5171 /* Uppercase if requested by client */
5172 if (!KNOWS_LONG_NAMES(inp))
5177 /* now, adjust the # of entries copied */
5179 } /* if we're including this name */
5182 if (free_actualName && actualName) {
5187 /* and adjust curOffset to be where the new cookie is */
5188 thyper.HighPart = 0;
5189 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5190 curOffset = LargeIntegerAdd(thyper, curOffset);
5191 } /* while copying data for dir listing */
5193 /* release the mutex */
5194 lock_ReleaseWrite(&scp->rw);
5196 buf_Release(bufferp);
5200 /* apply and free last set of patches; if not doing a star match, this
5201 * will be empty, but better safe (and freeing everything) than sorry.
5203 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5205 /* special return code for unsuccessful search */
5206 if (code == 0 && dataLength < 21 && returnedNames == 0)
5207 code = CM_ERROR_NOFILES;
5209 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5210 returnedNames, code);
5213 smb_DeleteDirSearch(dsp);
5214 smb_ReleaseDirSearch(dsp);
5215 cm_ReleaseSCache(scp);
5216 cm_ReleaseUser(userp);
5220 /* finalize the output buffer */
5221 smb_SetSMBParm(outp, 0, returnedNames);
5222 temp = (long) (op - origOp);
5223 smb_SetSMBDataLength(outp, temp);
5225 /* the data area is a variable block, which has a 5 (already there)
5226 * followed by the length of the # of data bytes. We now know this to
5227 * be "temp," although that includes the 3 bytes of vbl block header.
5228 * Deduct for them and fill in the length field.
5230 temp -= 3; /* deduct vbl block info */
5231 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5232 origOp[1] = (unsigned char)(temp & 0xff);
5233 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5234 if (returnedNames == 0)
5235 smb_DeleteDirSearch(dsp);
5236 smb_ReleaseDirSearch(dsp);
5237 cm_ReleaseSCache(scp);
5238 cm_ReleaseUser(userp);
5243 /* verify that this is a valid path to a directory. I don't know why they
5244 * don't use the get file attributes call.
5246 * SMB_COM_CHECK_DIRECTORY
5248 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5250 clientchar_t *pathp;
5252 cm_scache_t *rootScp;
5253 cm_scache_t *newScp;
5257 clientchar_t *tidPathp;
5263 pdata = smb_GetSMBData(inp, NULL);
5264 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5266 return CM_ERROR_BADSMB;
5267 osi_Log1(smb_logp, "SMB receive check path %S",
5268 osi_LogSaveClientString(smb_logp, pathp));
5270 rootScp = cm_data.rootSCachep;
5272 userp = smb_GetUserFromVCP(vcp, inp);
5274 caseFold = CM_FLAG_CASEFOLD;
5276 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5278 cm_ReleaseUser(userp);
5279 return CM_ERROR_NOSUCHPATH;
5281 code = cm_NameI(rootScp, pathp,
5282 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5283 userp, tidPathp, &req, &newScp);
5286 cm_ReleaseUser(userp);
5291 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5292 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5293 cm_ReleaseSCache(newScp);
5294 cm_ReleaseUser(userp);
5295 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5296 return CM_ERROR_PATH_NOT_COVERED;
5298 return CM_ERROR_NOSUCHPATH;
5300 #endif /* DFS_SUPPORT */
5302 /* now lock the vnode with a callback; returns with newScp locked */
5303 lock_ObtainWrite(&newScp->rw);
5304 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5305 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5307 if (code != CM_ERROR_NOACCESS) {
5308 lock_ReleaseWrite(&newScp->rw);
5309 cm_ReleaseSCache(newScp);
5310 cm_ReleaseUser(userp);
5314 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5317 attrs = smb_Attributes(newScp);
5319 if (!(attrs & SMB_ATTR_DIRECTORY))
5320 code = CM_ERROR_NOTDIR;
5322 lock_ReleaseWrite(&newScp->rw);
5324 cm_ReleaseSCache(newScp);
5325 cm_ReleaseUser(userp);
5329 /* SMB_COM_SET_INFORMATION */
5330 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5332 clientchar_t *pathp;
5334 cm_scache_t *rootScp;
5335 unsigned short attribute;
5337 cm_scache_t *newScp;
5341 clientchar_t *tidPathp;
5347 /* decode basic attributes we're passed */
5348 attribute = smb_GetSMBParm(inp, 0);
5349 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5351 datap = smb_GetSMBData(inp, NULL);
5352 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5354 return CM_ERROR_BADSMB;
5356 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5357 dosTime, attribute);
5359 rootScp = cm_data.rootSCachep;
5361 userp = smb_GetUserFromVCP(vcp, inp);
5363 caseFold = CM_FLAG_CASEFOLD;
5365 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5367 cm_ReleaseUser(userp);
5368 return CM_ERROR_NOSUCHFILE;
5370 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5371 tidPathp, &req, &newScp);
5374 cm_ReleaseUser(userp);
5379 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5380 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5381 cm_ReleaseSCache(newScp);
5382 cm_ReleaseUser(userp);
5383 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5384 return CM_ERROR_PATH_NOT_COVERED;
5386 return CM_ERROR_NOSUCHPATH;
5388 #endif /* DFS_SUPPORT */
5390 /* now lock the vnode with a callback; returns with newScp locked; we
5391 * need the current status to determine what the new status is, in some
5394 lock_ObtainWrite(&newScp->rw);
5395 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5396 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5398 lock_ReleaseWrite(&newScp->rw);
5399 cm_ReleaseSCache(newScp);
5400 cm_ReleaseUser(userp);
5404 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5406 /* Check for RO volume */
5407 if (newScp->flags & CM_SCACHEFLAG_RO) {
5408 lock_ReleaseWrite(&newScp->rw);
5409 cm_ReleaseSCache(newScp);
5410 cm_ReleaseUser(userp);
5411 return CM_ERROR_READONLY;
5414 /* prepare for setattr call */
5417 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5418 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5420 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5421 /* we're told to make a writable file read-only */
5422 attr.unixModeBits = newScp->unixModeBits & ~0222;
5423 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5425 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5426 /* we're told to make a read-only file writable */
5427 attr.unixModeBits = newScp->unixModeBits | 0222;
5428 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5430 lock_ReleaseWrite(&newScp->rw);
5432 /* now call setattr */
5434 code = cm_SetAttr(newScp, &attr, userp, &req);
5438 cm_ReleaseSCache(newScp);
5439 cm_ReleaseUser(userp);
5445 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5447 clientchar_t *pathp;
5449 cm_scache_t *rootScp;
5450 cm_scache_t *newScp, *dscp;
5455 clientchar_t *tidPathp;
5457 clientchar_t *lastComp;
5463 datap = smb_GetSMBData(inp, NULL);
5464 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5466 return CM_ERROR_BADSMB;
5468 if (*pathp == 0) /* null path */
5471 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5472 osi_LogSaveClientString(smb_logp, pathp));
5474 rootScp = cm_data.rootSCachep;
5476 userp = smb_GetUserFromVCP(vcp, inp);
5478 /* we shouldn't need this for V3 requests, but we seem to */
5479 caseFold = CM_FLAG_CASEFOLD;
5481 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5483 cm_ReleaseUser(userp);
5484 return CM_ERROR_NOSUCHFILE;
5488 * XXX Strange hack XXX
5490 * As of Patch 5 (16 July 97), we are having the following problem:
5491 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5492 * requests to look up "desktop.ini" in all the subdirectories.
5493 * This can cause zillions of timeouts looking up non-existent cells
5494 * and volumes, especially in the top-level directory.
5496 * We have not found any way to avoid this or work around it except
5497 * to explicitly ignore the requests for mount points that haven't
5498 * yet been evaluated and for directories that haven't yet been
5501 * We should modify this hack to provide a fake desktop.ini file
5502 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5504 spacep = inp->spacep;
5505 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5506 #ifndef SPECIAL_FOLDERS
5507 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5508 code = cm_NameI(rootScp, spacep->wdata,
5509 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5510 userp, tidPathp, &req, &dscp);
5513 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5514 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5516 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5517 return CM_ERROR_PATH_NOT_COVERED;
5519 return CM_ERROR_NOSUCHPATH;
5521 #endif /* DFS_SUPPORT */
5522 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5523 code = CM_ERROR_NOSUCHFILE;
5524 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5525 cm_buf_t *bp = buf_Find(dscp, &hzero);
5530 code = CM_ERROR_NOSUCHFILE;
5532 cm_ReleaseSCache(dscp);
5534 cm_ReleaseUser(userp);
5539 #endif /* SPECIAL_FOLDERS */
5541 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5542 tidPathp, &req, &newScp);
5544 cm_ReleaseUser(userp);
5549 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5550 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5551 cm_ReleaseSCache(newScp);
5552 cm_ReleaseUser(userp);
5553 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5554 return CM_ERROR_PATH_NOT_COVERED;
5556 return CM_ERROR_NOSUCHPATH;
5558 #endif /* DFS_SUPPORT */
5560 /* now lock the vnode with a callback; returns with newScp locked */
5561 lock_ObtainWrite(&newScp->rw);
5562 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5563 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5565 lock_ReleaseWrite(&newScp->rw);
5566 cm_ReleaseSCache(newScp);
5567 cm_ReleaseUser(userp);
5571 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5573 attrs = smb_Attributes(newScp);
5575 smb_SetSMBParm(outp, 0, attrs);
5577 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5578 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5579 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5580 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5581 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5582 smb_SetSMBParm(outp, 5, 0);
5583 smb_SetSMBParm(outp, 6, 0);
5584 smb_SetSMBParm(outp, 7, 0);
5585 smb_SetSMBParm(outp, 8, 0);
5586 smb_SetSMBParm(outp, 9, 0);
5587 smb_SetSMBDataLength(outp, 0);
5588 lock_ReleaseWrite(&newScp->rw);
5590 cm_ReleaseSCache(newScp);
5591 cm_ReleaseUser(userp);
5596 /* SMB_COM_TREE_DISCONNECT */
5597 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5601 osi_Log0(smb_logp, "SMB receive tree disconnect");
5603 /* find the tree and free it */
5604 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5606 lock_ObtainWrite(&smb_rctLock);
5608 smb_ReleaseTID(tidp, TRUE);
5609 lock_ReleaseWrite(&smb_rctLock);
5616 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5619 clientchar_t *pathp;
5620 clientchar_t *lastNamep;
5629 clientchar_t *tidPathp;
5635 datap = smb_GetSMBData(inp, NULL);
5636 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5638 return CM_ERROR_BADSMB;
5640 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5642 #ifdef DEBUG_VERBOSE
5646 hexpath = osi_HexifyString( pathp );
5647 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5652 share = smb_GetSMBParm(inp, 0);
5653 attribute = smb_GetSMBParm(inp, 1);
5655 spacep = inp->spacep;
5656 /* smb_StripLastComponent will strip "::$DATA" if present */
5657 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5659 if (!cm_IsValidClientString(pathp)) {
5661 clientchar_t * hexp;
5663 hexp = cm_GetRawCharsAlloc(pathp, -1);
5664 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5665 osi_LogSaveClientString(smb_logp, hexp));
5669 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5671 return CM_ERROR_BADNTFILENAME;
5674 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5675 /* special case magic file name for receiving IOCTL requests
5676 * (since IOCTL calls themselves aren't getting through).
5678 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5679 smb_SetupIoctlFid(fidp, spacep);
5680 smb_SetSMBParm(outp, 0, fidp->fid);
5681 smb_SetSMBParm(outp, 1, 0); /* attrs */
5682 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5683 smb_SetSMBParm(outp, 3, 0);
5684 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5685 smb_SetSMBParm(outp, 5, 0x7fff);
5686 /* pass the open mode back */
5687 smb_SetSMBParm(outp, 6, (share & 0xf));
5688 smb_SetSMBDataLength(outp, 0);
5689 smb_ReleaseFID(fidp);
5693 userp = smb_GetUserFromVCP(vcp, inp);
5695 caseFold = CM_FLAG_CASEFOLD;
5697 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5699 cm_ReleaseUser(userp);
5700 return CM_ERROR_NOSUCHPATH;
5702 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5703 tidPathp, &req, &scp);
5706 cm_ReleaseUser(userp);
5711 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5712 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5713 cm_ReleaseSCache(scp);
5714 cm_ReleaseUser(userp);
5715 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5716 return CM_ERROR_PATH_NOT_COVERED;
5718 return CM_ERROR_NOSUCHPATH;
5720 #endif /* DFS_SUPPORT */
5722 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5724 cm_ReleaseSCache(scp);
5725 cm_ReleaseUser(userp);
5729 /* don't need callback to check file type, since file types never
5730 * change, and namei and cm_Lookup all stat the object at least once on
5731 * a successful return.
5733 if (scp->fileType != CM_SCACHETYPE_FILE) {
5734 cm_ReleaseSCache(scp);
5735 cm_ReleaseUser(userp);
5736 return CM_ERROR_ISDIR;
5739 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5740 osi_assertx(fidp, "null smb_fid_t");
5742 lock_ObtainMutex(&fidp->mx);
5743 if ((share & 0xf) == 0)
5744 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5745 else if ((share & 0xf) == 1)
5746 fidp->flags |= SMB_FID_OPENWRITE;
5748 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5752 fidp->userp = userp;
5754 /* and a pointer to the vnode */
5756 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5757 lock_ObtainWrite(&scp->rw);
5758 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5760 smb_SetSMBParm(outp, 0, fidp->fid);
5761 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5762 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5763 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5764 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5765 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5766 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5767 /* pass the open mode back; XXXX add access checks */
5768 smb_SetSMBParm(outp, 6, (share & 0xf));
5769 smb_SetSMBDataLength(outp, 0);
5770 lock_ReleaseMutex(&fidp->mx);
5771 lock_ReleaseRead(&scp->rw);
5774 cm_Open(scp, 0, userp);
5776 /* send and free packet */
5777 smb_ReleaseFID(fidp);
5778 cm_ReleaseUser(userp);
5779 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5783 typedef struct smb_unlinkRock {
5788 clientchar_t *maskp; /* pointer to the star pattern */
5791 cm_dirEntryList_t * matches;
5794 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5797 smb_unlinkRock_t *rockp;
5800 normchar_t matchName[MAX_PATH];
5804 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5805 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5806 caseFold |= CM_FLAG_8DOT3;
5808 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5809 /* Can't convert name */
5810 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5811 osi_LogSaveString(smb_logp, dep->name));
5815 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5817 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5818 !cm_Is8Dot3(matchName)) {
5819 cm_Gen8Dot3Name(dep, matchName, NULL);
5820 /* 8.3 matches are always case insensitive */
5821 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5824 osi_Log1(smb_logp, "Found match %S",
5825 osi_LogSaveClientString(smb_logp, matchName));
5827 cm_DirEntryListAdd(dep->name, &rockp->matches);
5831 /* If we made a case sensitive exact match, we might as well quit now. */
5832 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5833 code = CM_ERROR_STOPNOW;
5842 /* SMB_COM_DELETE */
5843 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5847 clientchar_t *pathp;
5851 clientchar_t *lastNamep;
5852 smb_unlinkRock_t rock;
5856 clientchar_t *tidPathp;
5860 memset(&rock, 0, sizeof(rock));
5862 attribute = smb_GetSMBParm(inp, 0);
5864 tp = smb_GetSMBData(inp, NULL);
5865 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5867 return CM_ERROR_BADSMB;
5869 osi_Log1(smb_logp, "SMB receive unlink %S",
5870 osi_LogSaveClientString(smb_logp, pathp));
5872 spacep = inp->spacep;
5873 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5875 userp = smb_GetUserFromVCP(vcp, inp);
5877 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5879 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5881 cm_ReleaseUser(userp);
5882 return CM_ERROR_NOSUCHPATH;
5884 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5887 cm_ReleaseUser(userp);
5892 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5893 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5894 cm_ReleaseSCache(dscp);
5895 cm_ReleaseUser(userp);
5896 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5897 return CM_ERROR_PATH_NOT_COVERED;
5899 return CM_ERROR_NOSUCHPATH;
5901 #endif /* DFS_SUPPORT */
5903 /* otherwise, scp points to the parent directory. */
5910 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5912 code = CM_ERROR_NOSUCHFILE;
5915 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5918 thyper.HighPart = 0;
5923 rock.matches = NULL;
5925 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5926 * match. If that fails, we do a case insensitve match.
5928 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5929 !smb_IsStarMask(rock.maskp)) {
5930 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5933 thyper.HighPart = 0;
5934 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5939 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5941 if (code == CM_ERROR_STOPNOW)
5944 if (code == 0 && rock.matches) {
5945 cm_dirEntryList_t * entry;
5947 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5948 normchar_t normalizedName[MAX_PATH];
5950 /* Note: entry->name is a non-normalized name */
5952 osi_Log1(smb_logp, "Unlinking %s",
5953 osi_LogSaveString(smb_logp, entry->name));
5955 /* We assume this works because entry->name was
5956 successfully converted in smb_UnlinkProc() once. */
5957 cm_FsStringToNormString(entry->name, -1,
5958 normalizedName, lengthof(normalizedName));
5960 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5962 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5963 smb_NotifyChange(FILE_ACTION_REMOVED,
5964 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5965 dscp, normalizedName, NULL, TRUE);
5969 cm_DirEntryListFree(&rock.matches);
5973 cm_ReleaseUser(userp);
5976 cm_ReleaseSCache(dscp);
5981 if (code == 0 && !rock.any)
5982 code = CM_ERROR_NOSUCHFILE;
5986 typedef struct smb_renameRock {
5987 cm_scache_t *odscp; /* old dir */
5988 cm_scache_t *ndscp; /* new dir */
5989 cm_user_t *userp; /* user */
5990 cm_req_t *reqp; /* request struct */
5991 smb_vc_t *vcp; /* virtual circuit */
5992 normchar_t *maskp; /* pointer to star pattern of old file name */
5993 int flags; /* tilde, casefold, etc */
5994 clientchar_t *newNamep; /* ptr to the new file's name */
5995 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5996 clientchar_t clOldName[MAX_PATH]; /* client name */
6000 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6003 smb_renameRock_t *rockp;
6006 normchar_t matchName[MAX_PATH];
6008 rockp = (smb_renameRock_t *) vrockp;
6010 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6011 /* Can't convert string */
6012 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6013 osi_LogSaveString(smb_logp, dep->name));
6017 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6018 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6019 caseFold |= CM_FLAG_8DOT3;
6021 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6023 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6024 !cm_Is8Dot3(matchName)) {
6025 cm_Gen8Dot3Name(dep, matchName, NULL);
6026 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6031 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6032 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6034 code = CM_ERROR_STOPNOW;
6044 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6047 cm_space_t *spacep = NULL;
6048 smb_renameRock_t rock;
6049 cm_scache_t *oldDscp = NULL;
6050 cm_scache_t *newDscp = NULL;
6051 cm_scache_t *tmpscp= NULL;
6052 cm_scache_t *tmpscp2 = NULL;
6053 clientchar_t *oldLastNamep;
6054 clientchar_t *newLastNamep;
6058 clientchar_t *tidPathp;
6062 userp = smb_GetUserFromVCP(vcp, inp);
6063 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6065 cm_ReleaseUser(userp);
6066 return CM_ERROR_NOSUCHPATH;
6070 memset(&rock, 0, sizeof(rock));
6072 spacep = inp->spacep;
6073 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6075 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6076 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6077 userp, tidPathp, &req, &oldDscp);
6079 cm_ReleaseUser(userp);
6084 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6085 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6086 cm_ReleaseSCache(oldDscp);
6087 cm_ReleaseUser(userp);
6088 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6089 return CM_ERROR_PATH_NOT_COVERED;
6091 return CM_ERROR_NOSUCHPATH;
6093 #endif /* DFS_SUPPORT */
6095 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6096 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6097 userp, tidPathp, &req, &newDscp);
6100 cm_ReleaseSCache(oldDscp);
6101 cm_ReleaseUser(userp);
6106 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6107 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6108 cm_ReleaseSCache(oldDscp);
6109 cm_ReleaseSCache(newDscp);
6110 cm_ReleaseUser(userp);
6111 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6112 return CM_ERROR_PATH_NOT_COVERED;
6114 return CM_ERROR_NOSUCHPATH;
6116 #endif /* DFS_SUPPORT */
6119 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6120 * next, get the component names, and lower case them.
6123 /* handle the old name first */
6125 oldLastNamep = oldPathp;
6129 /* and handle the new name, too */
6131 newLastNamep = newPathp;
6135 /* TODO: The old name could be a wildcard. The new name must not be */
6137 /* Check if the file already exists; if so return error */
6138 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6139 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6140 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6142 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6143 osi_LogSaveClientString(smb_logp, newLastNamep));
6145 /* Check if the old and the new names differ only in case. If so return
6146 * success, else return CM_ERROR_EXISTS
6148 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6150 /* This would be a success only if the old file is *as same as* the new file */
6151 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6153 if (tmpscp == tmpscp2)
6156 code = CM_ERROR_EXISTS;
6157 cm_ReleaseSCache(tmpscp2);
6160 code = CM_ERROR_NOSUCHFILE;
6163 /* file exist, do not rename, also fixes move */
6164 osi_Log0(smb_logp, "Can't rename. Target already exists");
6165 code = CM_ERROR_EXISTS;
6170 /* do the vnode call */
6171 rock.odscp = oldDscp;
6172 rock.ndscp = newDscp;
6176 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6178 code = CM_ERROR_NOSUCHFILE;
6181 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6182 rock.newNamep = newLastNamep;
6183 rock.fsOldName[0] = '\0';
6184 rock.clOldName[0] = '\0';
6187 /* Now search the directory for the pattern, and do the appropriate rename when found */
6188 thyper.LowPart = 0; /* search dir from here */
6189 thyper.HighPart = 0;
6191 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6192 if (code == 0 && !rock.any) {
6194 thyper.HighPart = 0;
6195 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6196 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6198 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6200 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6201 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6202 rock.ndscp, rock.newNamep, rock.userp,
6204 /* if the call worked, stop doing the search now, since we
6205 * really only want to rename one file.
6208 osi_Log0(smb_logp, "cm_Rename failure");
6209 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6210 } else if (code == 0) {
6211 code = CM_ERROR_NOSUCHFILE;
6214 /* Handle Change Notification */
6216 * Being lazy, not distinguishing between files and dirs in this
6217 * filter, since we'd have to do a lookup.
6220 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6221 if (oldDscp == newDscp) {
6222 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6223 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6224 filter, oldDscp, rock.clOldName,
6225 newLastNamep, TRUE);
6227 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6228 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6229 filter, oldDscp, rock.clOldName,
6231 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6232 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6233 filter, newDscp, newLastNamep,
6240 cm_ReleaseSCache(tmpscp);
6242 cm_ReleaseUser(userp);
6244 cm_ReleaseSCache(oldDscp);
6246 cm_ReleaseSCache(newDscp);
6254 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6257 cm_space_t *spacep = NULL;
6258 cm_scache_t *oldDscp = NULL;
6259 cm_scache_t *newDscp = NULL;
6260 cm_scache_t *tmpscp= NULL;
6261 cm_scache_t *tmpscp2 = NULL;
6262 cm_scache_t *sscp = NULL;
6263 clientchar_t *oldLastNamep;
6264 clientchar_t *newLastNamep;
6267 clientchar_t *tidPathp;
6271 userp = smb_GetUserFromVCP(vcp, inp);
6273 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6275 cm_ReleaseUser(userp);
6276 return CM_ERROR_NOSUCHPATH;
6281 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6283 spacep = inp->spacep;
6284 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6286 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6287 userp, tidPathp, &req, &oldDscp);
6289 cm_ReleaseUser(userp);
6294 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6295 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6296 cm_ReleaseSCache(oldDscp);
6297 cm_ReleaseUser(userp);
6298 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6299 return CM_ERROR_PATH_NOT_COVERED;
6301 return CM_ERROR_NOSUCHPATH;
6303 #endif /* DFS_SUPPORT */
6305 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6306 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6307 userp, tidPathp, &req, &newDscp);
6309 cm_ReleaseSCache(oldDscp);
6310 cm_ReleaseUser(userp);
6315 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6316 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6317 cm_ReleaseSCache(newDscp);
6318 cm_ReleaseSCache(oldDscp);
6319 cm_ReleaseUser(userp);
6320 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6321 return CM_ERROR_PATH_NOT_COVERED;
6323 return CM_ERROR_NOSUCHPATH;
6325 #endif /* DFS_SUPPORT */
6327 /* Now, although we did two lookups for the two directories (because the same
6328 * directory can be referenced through different paths), we only allow hard links
6329 * within the same directory. */
6330 if (oldDscp != newDscp) {
6331 cm_ReleaseSCache(oldDscp);
6332 cm_ReleaseSCache(newDscp);
6333 cm_ReleaseUser(userp);
6334 return CM_ERROR_CROSSDEVLINK;
6337 /* handle the old name first */
6339 oldLastNamep = oldPathp;
6343 /* and handle the new name, too */
6345 newLastNamep = newPathp;
6349 /* now lookup the old name */
6350 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6351 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6353 cm_ReleaseSCache(oldDscp);
6354 cm_ReleaseSCache(newDscp);
6355 cm_ReleaseUser(userp);
6359 /* Check if the file already exists; if so return error */
6360 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6361 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6362 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6364 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6365 osi_LogSaveClientString(smb_logp, newLastNamep));
6367 /* if the existing link is to the same file, then we return success */
6369 if(sscp == tmpscp) {
6372 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6373 code = CM_ERROR_EXISTS;
6378 cm_ReleaseSCache(tmpscp);
6379 cm_ReleaseSCache(sscp);
6380 cm_ReleaseSCache(newDscp);
6381 cm_ReleaseSCache(oldDscp);
6382 cm_ReleaseUser(userp);
6386 /* now create the hardlink */
6387 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6388 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6389 osi_Log1(smb_logp," Link returns 0x%x", code);
6391 /* Handle Change Notification */
6393 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6394 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6395 smb_NotifyChange(FILE_ACTION_ADDED,
6396 filter, newDscp, newLastNamep,
6401 cm_ReleaseSCache(tmpscp);
6402 cm_ReleaseUser(userp);
6403 cm_ReleaseSCache(sscp);
6404 cm_ReleaseSCache(oldDscp);
6405 cm_ReleaseSCache(newDscp);
6409 /* SMB_COM_RENAME */
6411 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6413 clientchar_t *oldPathp;
6414 clientchar_t *newPathp;
6418 tp = smb_GetSMBData(inp, NULL);
6419 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6421 return CM_ERROR_BADSMB;
6422 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6424 return CM_ERROR_BADSMB;
6426 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6427 osi_LogSaveClientString(smb_logp, oldPathp),
6428 osi_LogSaveClientString(smb_logp, newPathp));
6430 if (!cm_IsValidClientString(newPathp)) {
6432 clientchar_t * hexp;
6434 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6435 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6436 osi_LogSaveClientString(smb_logp, hexp));
6440 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6442 return CM_ERROR_BADNTFILENAME;
6445 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6447 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6453 typedef struct smb_rmdirRock {
6457 normchar_t *maskp; /* pointer to the star pattern */
6460 cm_dirEntryList_t * matches;
6463 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6466 smb_rmdirRock_t *rockp;
6468 normchar_t matchName[MAX_PATH];
6470 rockp = (smb_rmdirRock_t *) vrockp;
6472 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6473 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6474 osi_LogSaveString(smb_logp, dep->name));
6478 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6479 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6481 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6483 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6484 !cm_Is8Dot3(matchName)) {
6485 cm_Gen8Dot3Name(dep, matchName, NULL);
6486 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6491 cm_DirEntryListAdd(dep->name, &rockp->matches);
6498 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6501 clientchar_t *pathp;
6505 clientchar_t *lastNamep;
6506 smb_rmdirRock_t rock;
6510 clientchar_t *tidPathp;
6514 memset(&rock, 0, sizeof(rock));
6516 tp = smb_GetSMBData(inp, NULL);
6517 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6519 return CM_ERROR_BADSMB;
6521 spacep = inp->spacep;
6522 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6524 userp = smb_GetUserFromVCP(vcp, inp);
6526 caseFold = CM_FLAG_CASEFOLD;
6528 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6530 cm_ReleaseUser(userp);
6531 return CM_ERROR_NOSUCHPATH;
6533 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6534 userp, tidPathp, &req, &dscp);
6537 cm_ReleaseUser(userp);
6542 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6543 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6544 cm_ReleaseSCache(dscp);
6545 cm_ReleaseUser(userp);
6546 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6547 return CM_ERROR_PATH_NOT_COVERED;
6549 return CM_ERROR_NOSUCHPATH;
6551 #endif /* DFS_SUPPORT */
6553 /* otherwise, scp points to the parent directory. */
6560 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6562 code = CM_ERROR_NOSUCHFILE;
6565 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6568 thyper.HighPart = 0;
6572 rock.matches = NULL;
6574 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6575 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6576 if (code == 0 && !rock.any) {
6578 thyper.HighPart = 0;
6579 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6580 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6583 if (code == 0 && rock.matches) {
6584 cm_dirEntryList_t * entry;
6586 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6587 clientchar_t clientName[MAX_PATH];
6589 /* We assume this will succeed because smb_RmdirProc()
6590 successfully converted entry->name once above. */
6591 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6593 osi_Log1(smb_logp, "Removing directory %s",
6594 osi_LogSaveString(smb_logp, entry->name));
6596 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6598 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6599 smb_NotifyChange(FILE_ACTION_REMOVED,
6600 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6601 dscp, clientName, NULL, TRUE);
6607 cm_DirEntryListFree(&rock.matches);
6610 cm_ReleaseUser(userp);
6613 cm_ReleaseSCache(dscp);
6615 if (code == 0 && !rock.any)
6616 code = CM_ERROR_NOSUCHFILE;
6625 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6635 fid = smb_GetSMBParm(inp, 0);
6637 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6639 fid = smb_ChainFID(fid, inp);
6640 fidp = smb_FindFID(vcp, fid, 0);
6642 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6644 return CM_ERROR_BADFD;
6646 userp = smb_GetUserFromVCP(vcp, inp);
6648 lock_ObtainMutex(&fidp->mx);
6649 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6650 cm_ReleaseUser(userp);
6651 lock_ReleaseMutex(&fidp->mx);
6652 smb_ReleaseFID(fidp);
6653 return CM_ERROR_BADFD;
6656 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6657 lock_ReleaseMutex(&fidp->mx);
6658 cm_ReleaseUser(userp);
6659 smb_CloseFID(vcp, fidp, NULL, 0);
6660 smb_ReleaseFID(fidp);
6661 return CM_ERROR_NOSUCHFILE;
6664 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6665 cm_scache_t * scp = fidp->scp;
6667 lock_ReleaseMutex(&fidp->mx);
6668 code = cm_FSync(scp, userp, &req);
6669 cm_ReleaseSCache(scp);
6671 lock_ReleaseMutex(&fidp->mx);
6675 cm_ReleaseUser(userp);
6676 smb_ReleaseFID(fidp);
6680 struct smb_FullNameRock {
6683 clientchar_t *fullName;
6684 fschar_t *originalName;
6687 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6690 normchar_t matchName[MAX_PATH];
6691 struct smb_FullNameRock *vrockp;
6693 vrockp = (struct smb_FullNameRock *)rockp;
6695 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6696 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6697 osi_LogSaveString(smb_logp, dep->name));
6701 if (!cm_Is8Dot3(matchName)) {
6702 clientchar_t shortName[13];
6704 cm_Gen8Dot3Name(dep, shortName, NULL);
6706 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6707 vrockp->fullName = cm_ClientStrDup(matchName);
6708 vrockp->originalName = cm_FsStrDup(dep->name);
6709 return CM_ERROR_STOPNOW;
6712 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6713 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6714 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6715 vrockp->fullName = cm_ClientStrDup(matchName);
6716 vrockp->originalName = cm_FsStrDup(dep->name);
6717 return CM_ERROR_STOPNOW;
6722 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6723 clientchar_t **newPathp, fschar_t ** originalPathp,
6724 cm_user_t *userp, cm_req_t *reqp)
6726 struct smb_FullNameRock rock;
6729 memset(&rock, 0, sizeof(rock));
6733 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6734 if (code == CM_ERROR_STOPNOW) {
6735 *newPathp = rock.fullName;
6736 *originalPathp = rock.originalName;
6738 *newPathp = cm_ClientStrDup(pathp);
6739 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6743 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6744 afs_uint32 dosTime) {
6747 cm_scache_t *dscp = NULL;
6748 clientchar_t *pathp = NULL;
6749 cm_scache_t * scp = NULL;
6750 cm_scache_t *delscp = NULL;
6751 int nullcreator = 0;
6753 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6754 fidp, fidp->fid, scp, vcp);
6757 lock_ObtainMutex(&fidp->mx);
6758 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6760 lock_ReleaseMutex(&fidp->mx);
6761 osi_Log0(smb_logp, " No user specified. Not closing fid");
6762 return CM_ERROR_BADFD;
6765 userp = fidp->userp; /* no hold required since fidp is held
6766 throughout the function */
6767 lock_ReleaseMutex(&fidp->mx);
6772 lock_ObtainWrite(&smb_rctLock);
6773 if (fidp->deleteOk) {
6774 osi_Log0(smb_logp, " Fid already closed.");
6775 lock_ReleaseWrite(&smb_rctLock);
6776 return CM_ERROR_BADFD;
6779 lock_ReleaseWrite(&smb_rctLock);
6781 lock_ObtainMutex(&fidp->mx);
6782 if (fidp->NTopen_dscp) {
6783 dscp = fidp->NTopen_dscp;
6784 cm_HoldSCache(dscp);
6787 if (fidp->NTopen_pathp)
6788 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6795 /* Don't jump the gun on an async raw write */
6796 while (fidp->raw_writers) {
6797 lock_ReleaseMutex(&fidp->mx);
6798 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6799 lock_ObtainMutex(&fidp->mx);
6802 /* watch for ioctl closes, and read-only opens */
6804 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6805 == SMB_FID_OPENWRITE) {
6806 if (dosTime != 0 && dosTime != -1) {
6807 lock_ObtainWrite(&fidp->scp->rw);
6808 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6809 /* This fixes defect 10958 */
6810 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6811 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6812 lock_ReleaseWrite(&fidp->scp->rw);
6814 if (smb_AsyncStore != 2) {
6815 lock_ReleaseMutex(&fidp->mx);
6816 code = cm_FSync(scp, userp, &req);
6817 lock_ObtainMutex(&fidp->mx);
6823 /* unlock any pending locks */
6824 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6825 scp->fileType == CM_SCACHETYPE_FILE) {
6829 lock_ReleaseMutex(&fidp->mx);
6831 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6833 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6834 lock_ObtainWrite(&scp->rw);
6836 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6837 CM_SCACHESYNC_NEEDCALLBACK
6838 | CM_SCACHESYNC_GETSTATUS
6839 | CM_SCACHESYNC_LOCK);
6843 "smb CoreClose SyncOp failure code 0x%x", tcode);
6844 goto post_syncopdone;
6847 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6849 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6853 lock_ReleaseWrite(&scp->rw);
6854 lock_ObtainMutex(&fidp->mx);
6857 if (fidp->flags & SMB_FID_DELONCLOSE) {
6858 clientchar_t *fullPathp = NULL;
6859 fschar_t *originalNamep = NULL;
6861 lock_ReleaseMutex(&fidp->mx);
6863 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6868 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6869 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6870 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6872 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6873 smb_NotifyChange(FILE_ACTION_REMOVED,
6874 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6875 dscp, fullPathp, NULL, TRUE);
6878 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6880 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6881 smb_NotifyChange(FILE_ACTION_REMOVED,
6882 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6883 dscp, fullPathp, NULL, TRUE);
6890 free(originalNamep);
6892 lock_ObtainMutex(&fidp->mx);
6893 fidp->flags &= ~SMB_FID_DELONCLOSE;
6896 /* if this was a newly created file, then clear the creator
6897 * in the stat cache entry. */
6898 if (fidp->flags & SMB_FID_CREATED) {
6900 fidp->flags &= ~SMB_FID_CREATED;
6903 if (fidp->flags & SMB_FID_NTOPEN) {
6904 cm_ReleaseSCache(fidp->NTopen_dscp);
6905 fidp->NTopen_dscp = NULL;
6906 free(fidp->NTopen_pathp);
6907 fidp->NTopen_pathp = NULL;
6908 fidp->flags &= ~SMB_FID_NTOPEN;
6910 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6911 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6914 if (fidp->NTopen_wholepathp) {
6915 free(fidp->NTopen_wholepathp);
6916 fidp->NTopen_wholepathp = NULL;
6920 cm_ReleaseSCache(fidp->scp);
6923 lock_ReleaseMutex(&fidp->mx);
6926 cm_ReleaseSCache(dscp);
6929 cm_ReleaseSCache(delscp);
6933 lock_ObtainWrite(&scp->rw);
6934 if (nullcreator && scp->creator == userp)
6935 scp->creator = NULL;
6936 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6937 lock_ReleaseWrite(&scp->rw);
6938 cm_ReleaseSCache(scp);
6948 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6956 fid = smb_GetSMBParm(inp, 0);
6957 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6959 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6961 fid = smb_ChainFID(fid, inp);
6962 fidp = smb_FindFID(vcp, fid, 0);
6964 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
6966 return CM_ERROR_BADFD;
6969 userp = smb_GetUserFromVCP(vcp, inp);
6971 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6973 smb_ReleaseFID(fidp);
6974 cm_ReleaseUser(userp);
6979 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6981 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6982 cm_user_t *userp, long *readp)
6988 osi_hyper_t fileLength;
6990 osi_hyper_t lastByte;
6991 osi_hyper_t bufferOffset;
6995 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6998 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6999 fidp->fid, offsetp->LowPart, count);
7003 lock_ObtainMutex(&fidp->mx);
7004 /* make sure we have a readable FD */
7005 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7006 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7007 fidp->fid, fidp->flags);
7008 lock_ReleaseMutex(&fidp->mx);
7009 code = CM_ERROR_BADFDOP;
7014 lock_ReleaseMutex(&fidp->mx);
7015 code = CM_ERROR_BADFD;
7026 lock_ObtainWrite(&scp->rw);
7028 if (offset.HighPart == 0) {
7029 chunk = offset.LowPart >> cm_logChunkSize;
7030 if (chunk != fidp->curr_chunk) {
7031 fidp->prev_chunk = fidp->curr_chunk;
7032 fidp->curr_chunk = chunk;
7034 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7037 lock_ReleaseMutex(&fidp->mx);
7039 /* start by looking up the file's end */
7040 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7041 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7045 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7047 /* now we have the entry locked, look up the length */
7048 fileLength = scp->length;
7050 /* adjust count down so that it won't go past EOF */
7051 thyper.LowPart = count;
7052 thyper.HighPart = 0;
7053 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7055 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7056 /* we'd read past EOF, so just stop at fileLength bytes.
7057 * Start by computing how many bytes remain in the file.
7059 thyper = LargeIntegerSubtract(fileLength, offset);
7061 /* if we are past EOF, read 0 bytes */
7062 if (LargeIntegerLessThanZero(thyper))
7065 count = thyper.LowPart;
7070 /* now, copy the data one buffer at a time,
7071 * until we've filled the request packet
7074 /* if we've copied all the data requested, we're done */
7075 if (count <= 0) break;
7077 /* otherwise, load up a buffer of data */
7078 thyper.HighPart = offset.HighPart;
7079 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7080 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7083 buf_Release(bufferp);
7086 lock_ReleaseWrite(&scp->rw);
7088 code = buf_Get(scp, &thyper, &req, &bufferp);
7090 lock_ObtainWrite(&scp->rw);
7091 if (code) goto done;
7092 bufferOffset = thyper;
7094 /* now get the data in the cache */
7096 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7097 CM_SCACHESYNC_NEEDCALLBACK |
7098 CM_SCACHESYNC_READ);
7102 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7104 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7106 /* otherwise, load the buffer and try again */
7107 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7111 buf_Release(bufferp);
7115 } /* if (wrong buffer) ... */
7117 /* now we have the right buffer loaded. Copy out the
7118 * data from here to the user's buffer.
7120 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7122 /* and figure out how many bytes we want from this buffer */
7123 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7124 if (nbytes > count) nbytes = count; /* don't go past EOF */
7126 /* now copy the data */
7127 memcpy(op, bufferp->datap + bufIndex, nbytes);
7129 /* adjust counters, pointers, etc. */
7132 thyper.LowPart = nbytes;
7133 thyper.HighPart = 0;
7134 offset = LargeIntegerAdd(thyper, offset);
7138 lock_ReleaseWrite(&scp->rw);
7140 buf_Release(bufferp);
7142 if (code == 0 && sequential)
7143 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7145 cm_ReleaseSCache(scp);
7148 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7149 fidp->fid, code, *readp);
7154 * smb_WriteData -- common code for Write and Raw Write
7156 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7157 cm_user_t *userp, long *writtenp)
7159 osi_hyper_t offset = *offsetp;
7162 cm_scache_t *scp = NULL;
7163 osi_hyper_t fileLength; /* file's length at start of write */
7164 osi_hyper_t minLength; /* don't read past this */
7165 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7166 cm_buf_t *bufferp = NULL;
7167 osi_hyper_t thyper; /* hyper tmp variable */
7168 osi_hyper_t bufferOffset;
7169 afs_uint32 bufIndex; /* index in buffer where our data is */
7170 int doWriteBack = 0;
7171 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7174 int needSyncOpDone = 0;
7176 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7177 fidp->fid, offsetp->LowPart, count);
7181 lock_ObtainMutex(&fidp->mx);
7182 /* make sure we have a writable FD */
7183 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7184 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7185 fidp->fid, fidp->flags);
7186 lock_ReleaseMutex(&fidp->mx);
7187 code = CM_ERROR_BADFDOP;
7195 lock_ReleaseMutex(&fidp->mx);
7197 lock_ObtainWrite(&scp->rw);
7198 /* start by looking up the file's end */
7199 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7200 CM_SCACHESYNC_NEEDCALLBACK
7201 | CM_SCACHESYNC_SETSTATUS
7202 | CM_SCACHESYNC_GETSTATUS);
7206 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7208 /* now we have the entry locked, look up the length */
7209 fileLength = scp->length;
7210 minLength = fileLength;
7211 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7212 minLength = scp->serverLength;
7214 /* adjust file length if we extend past EOF */
7215 thyper.LowPart = count;
7216 thyper.HighPart = 0;
7217 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7218 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7219 /* we'd write past EOF, so extend the file */
7220 scp->mask |= CM_SCACHEMASK_LENGTH;
7221 scp->length = thyper;
7222 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7224 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7226 /* now, if the new position (thyper) and the old (offset) are in
7227 * different storeback windows, remember to store back the previous
7228 * storeback window when we're done with the write.
7230 * the purpose of this logic is to slow down the CIFS client
7231 * in order to avoid the client disconnecting during the CLOSE
7232 * operation if there are too many dirty buffers left to write
7233 * than can be accomplished during 45 seconds. This used to be
7234 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7235 * so that we can read larger amounts of data at a time.
7237 if (smb_AsyncStore == 1 &&
7238 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7239 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7240 /* they're different */
7242 writeBackOffset.HighPart = offset.HighPart;
7243 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7248 /* now, copy the data one buffer at a time, until we've filled the
7250 while (count != 0) {
7252 /* handle over quota or out of space */
7253 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7254 *writtenp = written;
7255 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7259 /* otherwise, load up a buffer of data */
7260 thyper.HighPart = offset.HighPart;
7261 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7262 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7265 if (needSyncOpDone) {
7266 cm_SyncOpDone(scp, bufferp,
7267 CM_SCACHESYNC_NEEDCALLBACK
7268 | CM_SCACHESYNC_WRITE
7269 | CM_SCACHESYNC_BUFLOCKED);
7272 lock_ReleaseMutex(&bufferp->mx);
7273 buf_Release(bufferp);
7276 lock_ReleaseWrite(&scp->rw);
7278 code = buf_Get(scp, &thyper, &req, &bufferp);
7280 lock_ObtainMutex(&bufferp->mx);
7281 lock_ObtainWrite(&scp->rw);
7282 if (code) goto done;
7284 bufferOffset = thyper;
7286 /* now get the data in the cache */
7288 if (!needSyncOpDone) {
7289 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7290 CM_SCACHESYNC_NEEDCALLBACK
7291 | CM_SCACHESYNC_WRITE
7292 | CM_SCACHESYNC_BUFLOCKED);
7299 /* If we're overwriting the entire buffer, or
7300 * if we're writing at or past EOF, mark the
7301 * buffer as current so we don't call
7302 * cm_GetBuffer. This skips the fetch from the
7303 * server in those cases where we're going to
7304 * obliterate all the data in the buffer anyway,
7305 * or in those cases where there is no useful
7306 * data at the server to start with.
7308 * Use minLength instead of scp->length, since
7309 * the latter has already been updated by this
7312 * The scp lock has been dropped multiple times
7313 * so the minLength must be refreshed before it
7317 minLength = scp->length;
7318 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7319 minLength = scp->serverLength;
7321 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7322 || LargeIntegerEqualTo(offset, bufferp->offset)
7323 && (count >= cm_data.buf_blockSize
7324 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7325 ConvertLongToLargeInteger(count)),
7327 if (count < cm_data.buf_blockSize
7328 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7329 memset(bufferp->datap, 0,
7330 cm_data.buf_blockSize);
7331 bufferp->dataVersion = scp->dataVersion;
7334 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7336 /* otherwise, load the buffer and try again */
7337 cm_SyncOpDone(scp, bufferp,
7338 CM_SCACHESYNC_NEEDCALLBACK
7339 | CM_SCACHESYNC_WRITE
7340 | CM_SCACHESYNC_BUFLOCKED);
7343 lock_ReleaseMutex(&bufferp->mx);
7344 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7346 lock_ReleaseWrite(&scp->rw);
7347 lock_ObtainMutex(&bufferp->mx);
7348 lock_ObtainWrite(&scp->rw);
7352 } /* if (wrong buffer) ... */
7354 /* now we have the right buffer loaded. Copy out the
7355 * data from here to the user's buffer.
7357 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7359 /* and figure out how many bytes we want from this buffer */
7360 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7362 nbytes = count; /* don't go past end of request */
7364 /* now copy the data */
7365 memcpy(bufferp->datap + bufIndex, op, nbytes);
7366 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7368 /* adjust counters, pointers, etc. */
7372 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7373 } /* while count != 0 */
7376 if (bufferp && needSyncOpDone) {
7377 cm_SyncOpDone(scp, bufferp,
7378 CM_SCACHESYNC_NEEDCALLBACK
7379 | CM_SCACHESYNC_WRITE
7380 | CM_SCACHESYNC_BUFLOCKED);
7383 lock_ReleaseWrite(&scp->rw);
7386 lock_ReleaseMutex(&bufferp->mx);
7387 buf_Release(bufferp);
7390 lock_ObtainMutex(&fidp->mx);
7391 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7392 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7394 lock_ReleaseMutex(&fidp->mx);
7395 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7396 fidp->NTopen_dscp, fidp->NTopen_pathp,
7399 lock_ReleaseMutex(&fidp->mx);
7403 if (smb_AsyncStore > 0) {
7407 lock_ObtainWrite(&scp->rw);
7408 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7410 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7411 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7413 lock_ReleaseWrite(&scp->rw);
7414 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7415 writeBackOffset.HighPart,
7416 smb_AsyncStoreSize, 0, userp);
7417 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7420 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7424 cm_ReleaseSCache(scp);
7427 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7428 fidp->fid, code, *writtenp);
7433 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7436 unsigned short count;
7438 unsigned short hint;
7439 long written = 0, total_written = 0;
7442 smb_t* smbp = (smb_t*) inp;
7446 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7448 int inDataBlockCount;
7450 fd = smb_GetSMBParm(inp, 0);
7451 count = smb_GetSMBParm(inp, 1);
7452 offset.HighPart = 0; /* too bad */
7453 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7454 hint = smb_GetSMBParm(inp, 4);
7456 op = smb_GetSMBData(inp, NULL);
7457 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7459 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7460 fd, offset.LowPart, count);
7462 fd = smb_ChainFID(fd, inp);
7463 fidp = smb_FindFID(vcp, fd, 0);
7465 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7467 return CM_ERROR_BADFD;
7470 lock_ObtainMutex(&fidp->mx);
7471 if (fidp->flags & SMB_FID_IOCTL) {
7472 lock_ReleaseMutex(&fidp->mx);
7473 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7474 smb_ReleaseFID(fidp);
7475 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7479 if (fidp->flags & SMB_FID_RPC) {
7480 lock_ReleaseMutex(&fidp->mx);
7481 code = smb_RPCWrite(fidp, vcp, inp, outp);
7482 smb_ReleaseFID(fidp);
7483 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7488 lock_ReleaseMutex(&fidp->mx);
7489 smb_ReleaseFID(fidp);
7490 return CM_ERROR_BADFD;
7493 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7494 lock_ReleaseMutex(&fidp->mx);
7495 smb_CloseFID(vcp, fidp, NULL, 0);
7496 smb_ReleaseFID(fidp);
7497 return CM_ERROR_NOSUCHFILE;
7502 lock_ReleaseMutex(&fidp->mx);
7503 userp = smb_GetUserFromVCP(vcp, inp);
7507 LARGE_INTEGER LOffset;
7508 LARGE_INTEGER LLength;
7511 key = cm_GenerateKey(vcp->vcID, pid, fd);
7513 LOffset.HighPart = offset.HighPart;
7514 LOffset.LowPart = offset.LowPart;
7515 LLength.HighPart = 0;
7516 LLength.LowPart = count;
7518 lock_ObtainWrite(&scp->rw);
7519 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7520 lock_ReleaseWrite(&scp->rw);
7523 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7528 /* special case: 0 bytes transferred means truncate to this position */
7532 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7536 truncAttr.mask = CM_ATTRMASK_LENGTH;
7537 truncAttr.length.LowPart = offset.LowPart;
7538 truncAttr.length.HighPart = 0;
7539 lock_ObtainMutex(&fidp->mx);
7540 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7541 fidp->flags |= SMB_FID_LENGTHSETDONE;
7542 lock_ReleaseMutex(&fidp->mx);
7543 smb_SetSMBParm(outp, 0, 0 /* count */);
7544 smb_SetSMBDataLength(outp, 0);
7549 * Work around bug in NT client
7551 * When copying a file, the NT client should first copy the data,
7552 * then copy the last write time. But sometimes the NT client does
7553 * these in the wrong order, so the data copies would inadvertently
7554 * cause the last write time to be overwritten. We try to detect this,
7555 * and don't set client mod time if we think that would go against the
7558 lock_ObtainMutex(&fidp->mx);
7559 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7560 lock_ObtainWrite(&fidp->scp->rw);
7561 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7562 fidp->scp->clientModTime = time(NULL);
7563 lock_ReleaseWrite(&fidp->scp->rw);
7565 lock_ReleaseMutex(&fidp->mx);
7568 while ( code == 0 && count > 0 ) {
7569 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7570 if (code == 0 && written == 0)
7571 code = CM_ERROR_PARTIALWRITE;
7573 offset = LargeIntegerAdd(offset,
7574 ConvertLongToLargeInteger(written));
7575 count -= (unsigned short)written;
7576 total_written += written;
7580 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7581 total_written, code);
7583 /* set the packet data length to 3 bytes for the data block header,
7584 * plus the size of the data.
7586 smb_SetSMBParm(outp, 0, total_written);
7587 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7588 smb_SetSMBParm(outp, 3, hint);
7589 smb_SetSMBDataLength(outp, 0);
7592 smb_ReleaseFID(fidp);
7593 cm_ReleaseUser(userp);
7594 cm_ReleaseSCache(scp);
7599 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7600 NCB *ncbp, raw_write_cont_t *rwcp)
7609 fd = smb_GetSMBParm(inp, 0);
7610 fidp = smb_FindFID(vcp, fd, 0);
7612 lock_ObtainMutex(&fidp->mx);
7614 lock_ReleaseMutex(&fidp->mx);
7615 smb_ReleaseFID(fidp);
7619 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7620 lock_ReleaseMutex(&fidp->mx);
7621 smb_CloseFID(vcp, fidp, NULL, 0);
7622 smb_ReleaseFID(fidp);
7625 lock_ReleaseMutex(&fidp->mx);
7627 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7628 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7630 userp = smb_GetUserFromVCP(vcp, inp);
7633 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7635 if (rwcp->writeMode & 0x1) { /* synchronous */
7638 smb_FormatResponsePacket(vcp, inp, outp);
7639 op = (smb_t *) outp;
7640 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7641 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7642 smb_SetSMBDataLength(outp, 0);
7643 smb_SendPacket(vcp, outp);
7644 smb_FreePacket(outp);
7646 else { /* asynchronous */
7647 lock_ObtainMutex(&fidp->mx);
7648 fidp->raw_writers--;
7649 if (fidp->raw_writers == 0)
7650 thrd_SetEvent(fidp->raw_write_event);
7651 lock_ReleaseMutex(&fidp->mx);
7654 /* Give back raw buffer */
7655 lock_ObtainMutex(&smb_RawBufLock);
7656 *((char **)rawBuf) = smb_RawBufs;
7657 smb_RawBufs = rawBuf;
7658 lock_ReleaseMutex(&smb_RawBufLock);
7660 smb_ReleaseFID(fidp);
7661 cm_ReleaseUser(userp);
7664 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7669 /* SMB_COM_WRITE_RAW */
7670 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7673 long count, written = 0, total_written = 0;
7677 smb_t *smbp = (smb_t*) inp;
7682 unsigned short writeMode;
7684 fd = smb_GetSMBParm(inp, 0);
7685 totalCount = smb_GetSMBParm(inp, 1);
7686 count = smb_GetSMBParm(inp, 10);
7687 writeMode = smb_GetSMBParm(inp, 7);
7689 op = (char *) inp->data;
7690 op += smb_GetSMBParm(inp, 11);
7692 offset.HighPart = 0;
7693 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7695 if (*inp->wctp == 14) {
7696 /* we received a 64-bit file offset */
7697 #ifdef AFS_LARGEFILES
7698 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7700 if (LargeIntegerLessThanZero(offset)) {
7702 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7703 offset.HighPart, offset.LowPart);
7704 return CM_ERROR_BADSMB;
7707 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7709 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7710 return CM_ERROR_BADSMB;
7713 offset.HighPart = 0;
7716 offset.HighPart = 0; /* 32-bit file offset */
7720 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7721 fd, offset.HighPart, offset.LowPart, count);
7723 " WriteRaw WriteMode 0x%x",
7726 fd = smb_ChainFID(fd, inp);
7727 fidp = smb_FindFID(vcp, fd, 0);
7729 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7731 return CM_ERROR_BADFD;
7733 lock_ObtainMutex(&fidp->mx);
7735 lock_ReleaseMutex(&fidp->mx);
7736 smb_ReleaseFID(fidp);
7737 return CM_ERROR_BADFD;
7740 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7741 lock_ReleaseMutex(&fidp->mx);
7742 smb_CloseFID(vcp, fidp, NULL, 0);
7743 smb_ReleaseFID(fidp);
7744 return CM_ERROR_NOSUCHFILE;
7749 lock_ReleaseMutex(&fidp->mx);
7754 LARGE_INTEGER LOffset;
7755 LARGE_INTEGER LLength;
7758 key = cm_GenerateKey(vcp->vcID, pid, fd);
7760 LOffset.HighPart = offset.HighPart;
7761 LOffset.LowPart = offset.LowPart;
7762 LLength.HighPart = 0;
7763 LLength.LowPart = count;
7765 lock_ObtainWrite(&scp->rw);
7766 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7767 lock_ReleaseWrite(&scp->rw);
7770 cm_ReleaseSCache(scp);
7771 smb_ReleaseFID(fidp);
7776 userp = smb_GetUserFromVCP(vcp, inp);
7779 * Work around bug in NT client
7781 * When copying a file, the NT client should first copy the data,
7782 * then copy the last write time. But sometimes the NT client does
7783 * these in the wrong order, so the data copies would inadvertently
7784 * cause the last write time to be overwritten. We try to detect this,
7785 * and don't set client mod time if we think that would go against the
7788 lock_ObtainMutex(&fidp->mx);
7789 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7790 lock_ObtainWrite(&fidp->scp->rw);
7791 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7792 fidp->scp->clientModTime = time(NULL);
7793 lock_ReleaseWrite(&fidp->scp->rw);
7795 lock_ReleaseMutex(&fidp->mx);
7798 while ( code == 0 && count > 0 ) {
7799 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7800 if (code == 0 && written == 0)
7801 code = CM_ERROR_PARTIALWRITE;
7803 offset = LargeIntegerAdd(offset,
7804 ConvertLongToLargeInteger(written));
7807 total_written += written;
7811 /* Get a raw buffer */
7814 lock_ObtainMutex(&smb_RawBufLock);
7816 /* Get a raw buf, from head of list */
7817 rawBuf = smb_RawBufs;
7818 smb_RawBufs = *(char **)smb_RawBufs;
7821 code = CM_ERROR_USESTD;
7823 lock_ReleaseMutex(&smb_RawBufLock);
7826 /* Don't allow a premature Close */
7827 if (code == 0 && (writeMode & 1) == 0) {
7828 lock_ObtainMutex(&fidp->mx);
7829 fidp->raw_writers++;
7830 thrd_ResetEvent(fidp->raw_write_event);
7831 lock_ReleaseMutex(&fidp->mx);
7834 smb_ReleaseFID(fidp);
7835 cm_ReleaseUser(userp);
7836 cm_ReleaseSCache(scp);
7839 smb_SetSMBParm(outp, 0, total_written);
7840 smb_SetSMBDataLength(outp, 0);
7841 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7846 offset = LargeIntegerAdd(offset,
7847 ConvertLongToLargeInteger(count));
7851 rwcp->offset.HighPart = offset.HighPart;
7852 rwcp->offset.LowPart = offset.LowPart;
7853 rwcp->count = totalCount - count;
7854 rwcp->writeMode = writeMode;
7855 rwcp->alreadyWritten = total_written;
7857 /* set the packet data length to 3 bytes for the data block header,
7858 * plus the size of the data.
7860 smb_SetSMBParm(outp, 0, 0xffff);
7861 smb_SetSMBDataLength(outp, 0);
7867 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7870 long count, finalCount;
7874 smb_t *smbp = (smb_t*) inp;
7880 fd = smb_GetSMBParm(inp, 0);
7881 count = smb_GetSMBParm(inp, 1);
7882 offset.HighPart = 0; /* too bad */
7883 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7885 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7886 fd, offset.LowPart, count);
7888 fd = smb_ChainFID(fd, inp);
7889 fidp = smb_FindFID(vcp, fd, 0);
7891 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7893 return CM_ERROR_BADFD;
7895 lock_ObtainMutex(&fidp->mx);
7896 if (fidp->flags & SMB_FID_IOCTL) {
7897 lock_ReleaseMutex(&fidp->mx);
7898 code = smb_IoctlRead(fidp, vcp, inp, outp);
7899 smb_ReleaseFID(fidp);
7903 if (fidp->flags & SMB_FID_RPC) {
7904 lock_ReleaseMutex(&fidp->mx);
7905 code = smb_RPCRead(fidp, vcp, inp, outp);
7906 smb_ReleaseFID(fidp);
7911 lock_ReleaseMutex(&fidp->mx);
7912 smb_ReleaseFID(fidp);
7913 return CM_ERROR_BADFD;
7916 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7917 lock_ReleaseMutex(&fidp->mx);
7918 smb_CloseFID(vcp, fidp, NULL, 0);
7919 smb_ReleaseFID(fidp);
7920 return CM_ERROR_NOSUCHFILE;
7925 lock_ReleaseMutex(&fidp->mx);
7928 LARGE_INTEGER LOffset, LLength;
7932 key = cm_GenerateKey(vcp->vcID, pid, fd);
7934 LOffset.HighPart = 0;
7935 LOffset.LowPart = offset.LowPart;
7936 LLength.HighPart = 0;
7937 LLength.LowPart = count;
7939 lock_ObtainWrite(&scp->rw);
7940 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7941 lock_ReleaseWrite(&scp->rw);
7944 cm_ReleaseSCache(scp);
7945 smb_ReleaseFID(fidp);
7949 userp = smb_GetUserFromVCP(vcp, inp);
7951 /* remember this for final results */
7952 smb_SetSMBParm(outp, 0, count);
7953 smb_SetSMBParm(outp, 1, 0);
7954 smb_SetSMBParm(outp, 2, 0);
7955 smb_SetSMBParm(outp, 3, 0);
7956 smb_SetSMBParm(outp, 4, 0);
7958 /* set the packet data length to 3 bytes for the data block header,
7959 * plus the size of the data.
7961 smb_SetSMBDataLength(outp, count+3);
7963 /* get op ptr after putting in the parms, since otherwise we don't
7964 * know where the data really is.
7966 op = smb_GetSMBData(outp, NULL);
7968 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7969 *op++ = 1; /* data block marker */
7970 *op++ = (unsigned char) (count & 0xff);
7971 *op++ = (unsigned char) ((count >> 8) & 0xff);
7973 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7975 /* fix some things up */
7976 smb_SetSMBParm(outp, 0, finalCount);
7977 smb_SetSMBDataLength(outp, finalCount+3);
7979 smb_ReleaseFID(fidp);
7981 cm_ReleaseUser(userp);
7982 cm_ReleaseSCache(scp);
7986 /* SMB_COM_CREATE_DIRECTORY */
7987 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7989 clientchar_t *pathp;
7994 cm_scache_t *dscp; /* dir we're dealing with */
7995 cm_scache_t *scp; /* file we're creating */
7997 int initialModeBits;
7998 clientchar_t *lastNamep;
8000 clientchar_t *tidPathp;
8007 /* compute initial mode bits based on read-only flag in attributes */
8008 initialModeBits = 0777;
8010 tp = smb_GetSMBData(inp, NULL);
8011 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8013 return CM_ERROR_BADSMB;
8015 spacep = inp->spacep;
8016 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8018 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8019 return CM_ERROR_EXISTS;
8021 userp = smb_GetUserFromVCP(vcp, inp);
8023 caseFold = CM_FLAG_CASEFOLD;
8025 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8027 cm_ReleaseUser(userp);
8028 return CM_ERROR_NOSUCHPATH;
8031 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
8032 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8033 userp, tidPathp, &req, &dscp);
8036 cm_ReleaseUser(userp);
8041 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8042 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8043 cm_ReleaseSCache(dscp);
8044 cm_ReleaseUser(userp);
8045 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8046 return CM_ERROR_PATH_NOT_COVERED;
8048 return CM_ERROR_NOSUCHPATH;
8050 #endif /* DFS_SUPPORT */
8052 /* otherwise, scp points to the parent directory. Do a lookup, and
8053 * fail if we find it. Otherwise, we do the create.
8059 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8060 if (scp) cm_ReleaseSCache(scp);
8061 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8062 if (code == 0) code = CM_ERROR_EXISTS;
8063 cm_ReleaseSCache(dscp);
8064 cm_ReleaseUser(userp);
8068 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8069 setAttr.clientModTime = time(NULL);
8070 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8071 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8072 smb_NotifyChange(FILE_ACTION_ADDED,
8073 FILE_NOTIFY_CHANGE_DIR_NAME,
8074 dscp, lastNamep, NULL, TRUE);
8076 /* we don't need this any longer */
8077 cm_ReleaseSCache(dscp);
8080 /* something went wrong creating or truncating the file */
8081 cm_ReleaseUser(userp);
8085 /* otherwise we succeeded */
8086 smb_SetSMBDataLength(outp, 0);
8087 cm_ReleaseUser(userp);
8092 BOOL smb_IsLegalFilename(clientchar_t *filename)
8095 * Find the longest substring of filename that does not contain
8096 * any of the chars in illegalChars. If that substring is less
8097 * than the length of the whole string, then one or more of the
8098 * illegal chars is in filename.
8100 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8106 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8107 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8109 clientchar_t *pathp;
8115 cm_scache_t *dscp; /* dir we're dealing with */
8116 cm_scache_t *scp; /* file we're creating */
8118 int initialModeBits;
8121 clientchar_t *lastNamep;
8124 clientchar_t *tidPathp;
8126 int created = 0; /* the file was new */
8131 excl = (inp->inCom == 0x03)? 0 : 1;
8133 attributes = smb_GetSMBParm(inp, 0);
8134 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8136 /* compute initial mode bits based on read-only flag in attributes */
8137 initialModeBits = 0666;
8138 if (attributes & SMB_ATTR_READONLY)
8139 initialModeBits &= ~0222;
8141 tp = smb_GetSMBData(inp, NULL);
8142 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8144 return CM_ERROR_BADSMB;
8146 spacep = inp->spacep;
8147 /* smb_StripLastComponent will strip "::$DATA" if present */
8148 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8150 if (!cm_IsValidClientString(pathp)) {
8152 clientchar_t * hexp;
8154 hexp = cm_GetRawCharsAlloc(pathp, -1);
8155 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8156 osi_LogSaveClientString(smb_logp, hexp));
8160 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8162 return CM_ERROR_BADNTFILENAME;
8165 userp = smb_GetUserFromVCP(vcp, inp);
8167 caseFold = CM_FLAG_CASEFOLD;
8169 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8171 cm_ReleaseUser(userp);
8172 return CM_ERROR_NOSUCHPATH;
8174 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8175 userp, tidPathp, &req, &dscp);
8178 cm_ReleaseUser(userp);
8183 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8184 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8185 cm_ReleaseSCache(dscp);
8186 cm_ReleaseUser(userp);
8187 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8188 return CM_ERROR_PATH_NOT_COVERED;
8190 return CM_ERROR_NOSUCHPATH;
8192 #endif /* DFS_SUPPORT */
8194 /* otherwise, scp points to the parent directory. Do a lookup, and
8195 * truncate the file if we find it, otherwise we create the file.
8202 if (!smb_IsLegalFilename(lastNamep))
8203 return CM_ERROR_BADNTFILENAME;
8205 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8206 #ifdef DEBUG_VERBOSE
8209 hexp = osi_HexifyString( lastNamep );
8210 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8215 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8216 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8217 cm_ReleaseSCache(dscp);
8218 cm_ReleaseUser(userp);
8222 /* if we get here, if code is 0, the file exists and is represented by
8223 * scp. Otherwise, we have to create it.
8227 /* oops, file shouldn't be there */
8228 cm_ReleaseSCache(dscp);
8229 cm_ReleaseSCache(scp);
8230 cm_ReleaseUser(userp);
8231 return CM_ERROR_EXISTS;
8234 setAttr.mask = CM_ATTRMASK_LENGTH;
8235 setAttr.length.LowPart = 0;
8236 setAttr.length.HighPart = 0;
8237 code = cm_SetAttr(scp, &setAttr, userp, &req);
8240 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8241 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8242 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8246 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8247 smb_NotifyChange(FILE_ACTION_ADDED,
8248 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8249 dscp, lastNamep, NULL, TRUE);
8250 } else if (!excl && code == CM_ERROR_EXISTS) {
8251 /* not an exclusive create, and someone else tried
8252 * creating it already, then we open it anyway. We
8253 * don't bother retrying after this, since if this next
8254 * fails, that means that the file was deleted after
8255 * we started this call.
8257 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8260 setAttr.mask = CM_ATTRMASK_LENGTH;
8261 setAttr.length.LowPart = 0;
8262 setAttr.length.HighPart = 0;
8263 code = cm_SetAttr(scp, &setAttr, userp, &req);
8268 /* we don't need this any longer */
8269 cm_ReleaseSCache(dscp);
8272 /* something went wrong creating or truncating the file */
8273 if (scp) cm_ReleaseSCache(scp);
8274 cm_ReleaseUser(userp);
8278 /* make sure we only open files */
8279 if (scp->fileType != CM_SCACHETYPE_FILE) {
8280 cm_ReleaseSCache(scp);
8281 cm_ReleaseUser(userp);
8282 return CM_ERROR_ISDIR;
8285 /* now all we have to do is open the file itself */
8286 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8287 osi_assertx(fidp, "null smb_fid_t");
8291 lock_ObtainMutex(&fidp->mx);
8292 /* always create it open for read/write */
8293 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8295 /* remember that the file was newly created */
8297 fidp->flags |= SMB_FID_CREATED;
8299 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8301 /* save a pointer to the vnode */
8303 lock_ObtainWrite(&scp->rw);
8304 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8305 lock_ReleaseWrite(&scp->rw);
8308 fidp->userp = userp;
8309 lock_ReleaseMutex(&fidp->mx);
8311 smb_SetSMBParm(outp, 0, fidp->fid);
8312 smb_SetSMBDataLength(outp, 0);
8314 cm_Open(scp, 0, userp);
8316 smb_ReleaseFID(fidp);
8317 cm_ReleaseUser(userp);
8318 /* leave scp held since we put it in fidp->scp */
8323 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8326 osi_hyper_t new_offset;
8337 fd = smb_GetSMBParm(inp, 0);
8338 whence = smb_GetSMBParm(inp, 1);
8339 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8341 /* try to find the file descriptor */
8342 fd = smb_ChainFID(fd, inp);
8343 fidp = smb_FindFID(vcp, fd, 0);
8345 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8347 return CM_ERROR_BADFD;
8349 lock_ObtainMutex(&fidp->mx);
8350 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8351 lock_ReleaseMutex(&fidp->mx);
8352 smb_ReleaseFID(fidp);
8353 return CM_ERROR_BADFD;
8356 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8357 lock_ReleaseMutex(&fidp->mx);
8358 smb_CloseFID(vcp, fidp, NULL, 0);
8359 smb_ReleaseFID(fidp);
8360 return CM_ERROR_NOSUCHFILE;
8363 lock_ReleaseMutex(&fidp->mx);
8365 userp = smb_GetUserFromVCP(vcp, inp);
8367 lock_ObtainMutex(&fidp->mx);
8370 lock_ReleaseMutex(&fidp->mx);
8371 lock_ObtainWrite(&scp->rw);
8372 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8373 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8375 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8377 /* offset from current offset */
8378 new_offset = LargeIntegerAdd(fidp->offset,
8379 ConvertLongToLargeInteger(offset));
8381 else if (whence == 2) {
8382 /* offset from current EOF */
8383 new_offset = LargeIntegerAdd(scp->length,
8384 ConvertLongToLargeInteger(offset));
8386 new_offset = ConvertLongToLargeInteger(offset);
8389 fidp->offset = new_offset;
8390 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8391 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8392 smb_SetSMBDataLength(outp, 0);
8394 lock_ReleaseWrite(&scp->rw);
8395 smb_ReleaseFID(fidp);
8396 cm_ReleaseSCache(scp);
8397 cm_ReleaseUser(userp);
8401 /* dispatch all of the requests received in a packet. Due to chaining, this may
8402 * be more than one request.
8404 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8405 NCB *ncbp, raw_write_cont_t *rwcp)
8409 unsigned long code = 0;
8410 unsigned char *outWctp;
8411 int nparms; /* # of bytes of parameters */
8413 int nbytes; /* bytes of data, excluding count */
8416 unsigned short errCode;
8417 unsigned long NTStatus;
8419 unsigned char errClass;
8420 unsigned int oldGen;
8421 DWORD oldTime, newTime;
8423 /* get easy pointer to the data */
8424 smbp = (smb_t *) inp->data;
8426 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8427 /* setup the basic parms for the initial request in the packet */
8428 inp->inCom = smbp->com;
8429 inp->wctp = &smbp->wct;
8431 inp->ncb_length = ncbp->ncb_length;
8436 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8437 /* log it and discard it */
8438 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8439 __FILE__, __LINE__, ncbp->ncb_length);
8440 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8444 /* We are an ongoing op */
8445 thrd_Increment(&ongoingOps);
8447 /* set up response packet for receiving output */
8448 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8449 smb_FormatResponsePacket(vcp, inp, outp);
8450 outWctp = outp->wctp;
8452 /* Remember session generation number and time */
8453 oldGen = sessionGen;
8454 oldTime = GetTickCount();
8456 while (inp->inCom != 0xff) {
8457 dp = &smb_dispatchTable[inp->inCom];
8459 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8460 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8461 code = outp->resumeCode;
8465 /* process each request in the packet; inCom, wctp and inCount
8466 * are already set up.
8468 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8471 /* now do the dispatch */
8472 /* start by formatting the response record a little, as a default */
8473 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8475 outWctp[1] = 0xff; /* no operation */
8476 outWctp[2] = 0; /* padding */
8481 /* not a chained request, this is a more reasonable default */
8482 outWctp[0] = 0; /* wct of zero */
8483 outWctp[1] = 0; /* and bcc (word) of zero */
8487 /* once set, stays set. Doesn't matter, since we never chain
8488 * "no response" calls.
8490 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8494 /* we have a recognized operation */
8495 char * opName = myCrt_Dispatch(inp->inCom);
8498 smbp = (smb_t *) inp;
8500 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8501 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8502 if (inp->inCom == 0x1d) {
8504 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8506 code = (*(dp->procp)) (vcp, inp, outp);
8508 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8509 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8511 newTime = GetTickCount();
8512 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8513 opName, smbp->mid, newTime - oldTime);
8516 if ( code == CM_ERROR_BADSMB ||
8517 code == CM_ERROR_BADOP )
8519 #endif /* LOG_PACKET */
8521 /* ReceiveV3Tran2A handles its own logging */
8522 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8525 clientchar_t *treepath = NULL; /* do not free */
8526 clientchar_t *pathname = NULL;
8527 cm_fid_t afid = {0,0,0,0,0};
8529 uidp = smb_FindUID(vcp, smbp->uid, 0);
8530 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8531 fidp = smb_FindFID(vcp, inp->fid, 0);
8534 lock_ObtainMutex(&fidp->mx);
8535 if (fidp->NTopen_pathp)
8536 pathname = fidp->NTopen_pathp;
8538 afid = fidp->scp->fid;
8540 if (inp->stringsp->wdata)
8541 pathname = inp->stringsp->wdata;
8544 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)",
8545 opName, newTime - oldTime,
8546 smbp->uid, uidp ? uidp->unp->name : NULL,
8547 smbp->pid, smbp->mid, smbp->tid,
8550 afid.cell, afid.volume, afid.vnode, afid.unique);
8553 lock_ReleaseMutex(&fidp->mx);
8556 smb_ReleaseUID(uidp);
8558 smb_ReleaseFID(fidp);
8561 if (oldGen != sessionGen) {
8562 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8563 newTime - oldTime, ncbp->ncb_length);
8564 osi_Log3(smb_logp, "Request %s straddled session startup, "
8565 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8568 FreeSMBStrings(inp);
8570 /* bad opcode, fail the request, after displaying it */
8571 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8574 #endif /* LOG_PACKET */
8577 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8578 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8579 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8580 if (code == IDCANCEL)
8583 code = CM_ERROR_BADOP;
8586 /* catastrophic failure: log as much as possible */
8587 if (code == CM_ERROR_BADSMB) {
8588 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8592 #endif /* LOG_PACKET */
8593 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8596 code = CM_ERROR_INVAL;
8599 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8600 thrd_Decrement(&ongoingOps);
8605 /* now, if we failed, turn the current response into an empty
8606 * one, and fill in the response packet's error code.
8609 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8610 smb_MapNTError(code, &NTStatus);
8611 outWctp = outp->wctp;
8612 smbp = (smb_t *) &outp->data;
8613 if (code != CM_ERROR_PARTIALWRITE
8614 && code != CM_ERROR_BUFFERTOOSMALL
8615 && code != CM_ERROR_GSSCONTINUE) {
8616 /* nuke wct and bcc. For a partial
8617 * write or an in-process authentication handshake,
8618 * assume they're OK.
8624 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8625 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8626 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8627 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8628 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8632 smb_MapCoreError(code, vcp, &errCode, &errClass);
8633 outWctp = outp->wctp;
8634 smbp = (smb_t *) &outp->data;
8635 if (code != CM_ERROR_PARTIALWRITE) {
8636 /* nuke wct and bcc. For a partial
8637 * write, assume they're OK.
8643 smbp->errLow = (unsigned char) (errCode & 0xff);
8644 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8645 smbp->rcls = errClass;
8648 } /* error occurred */
8650 /* if we're here, we've finished one request. Look to see if
8651 * this is a chained opcode. If it is, setup things to process
8652 * the chained request, and setup the output buffer to hold the
8653 * chained response. Start by finding the next input record.
8655 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8656 break; /* not a chained req */
8657 tp = inp->wctp; /* points to start of last request */
8658 /* in a chained request, the first two
8659 * parm fields are required, and are
8660 * AndXCommand/AndXReserved and
8662 if (tp[0] < 2) break;
8663 if (tp[1] == 0xff) break; /* no more chained opcodes */
8665 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8668 /* and now append the next output request to the end of this
8669 * last request. Begin by finding out where the last response
8670 * ends, since that's where we'll put our new response.
8672 outWctp = outp->wctp; /* ptr to out parameters */
8673 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8674 nparms = outWctp[0] << 1;
8675 tp = outWctp + nparms + 1; /* now points to bcc field */
8676 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8677 tp += 2 /* for the count itself */ + nbytes;
8678 /* tp now points to the new output record; go back and patch the
8679 * second parameter (off2) to point to the new record.
8681 temp = (unsigned int)(tp - outp->data);
8682 outWctp[3] = (unsigned char) (temp & 0xff);
8683 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8684 outWctp[2] = 0; /* padding */
8685 outWctp[1] = inp->inCom; /* next opcode */
8687 /* finally, setup for the next iteration */
8690 } /* while loop over all requests in the packet */
8692 /* now send the output packet, and return */
8694 smb_SendPacket(vcp, outp);
8695 thrd_Decrement(&ongoingOps);
8700 /* Wait for Netbios() calls to return, and make the results available to server
8701 * threads. Note that server threads can't wait on the NCBevents array
8702 * themselves, because NCB events are manual-reset, and the servers would race
8703 * each other to reset them.
8705 void smb_ClientWaiter(void *parmp)
8710 while (smbShutdownFlag == 0) {
8711 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8713 if (code == WAIT_OBJECT_0)
8716 /* error checking */
8717 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8719 int abandonIdx = code - WAIT_ABANDONED_0;
8720 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8723 if (code == WAIT_IO_COMPLETION)
8725 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8729 if (code == WAIT_TIMEOUT)
8731 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8734 if (code == WAIT_FAILED)
8736 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8739 idx = code - WAIT_OBJECT_0;
8741 /* check idx range! */
8742 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8744 /* this is fatal - log as much as possible */
8745 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8746 osi_assertx(0, "invalid index");
8749 thrd_ResetEvent(NCBevents[idx]);
8750 thrd_SetEvent(NCBreturns[0][idx]);
8755 * Try to have one NCBRECV request waiting for every live session. Not more
8756 * than one, because if there is more than one, it's hard to handle Write Raw.
8758 void smb_ServerWaiter(void *parmp)
8761 int idx_session, idx_NCB;
8764 while (smbShutdownFlag == 0) {
8766 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8768 if (code == WAIT_OBJECT_0)
8771 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8773 int abandonIdx = code - WAIT_ABANDONED_0;
8774 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8777 if (code == WAIT_IO_COMPLETION)
8779 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8783 if (code == WAIT_TIMEOUT)
8785 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8788 if (code == WAIT_FAILED)
8790 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8793 idx_session = code - WAIT_OBJECT_0;
8795 /* check idx range! */
8796 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8798 /* this is fatal - log as much as possible */
8799 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8800 osi_assertx(0, "invalid index");
8805 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8807 if (code == WAIT_OBJECT_0) {
8808 if (smbShutdownFlag == 1)
8814 /* error checking */
8815 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8817 int abandonIdx = code - WAIT_ABANDONED_0;
8818 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8821 if (code == WAIT_IO_COMPLETION)
8823 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8827 if (code == WAIT_TIMEOUT)
8829 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8832 if (code == WAIT_FAILED)
8834 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8837 idx_NCB = code - WAIT_OBJECT_0;
8839 /* check idx range! */
8840 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8842 /* this is fatal - log as much as possible */
8843 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8844 osi_assertx(0, "invalid index");
8847 /* Link them together */
8848 NCBsessions[idx_NCB] = idx_session;
8851 ncbp = NCBs[idx_NCB];
8852 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8853 ncbp->ncb_command = NCBRECV | ASYNCH;
8854 ncbp->ncb_lana_num = lanas[idx_session];
8855 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8856 ncbp->ncb_event = NCBevents[idx_NCB];
8857 ncbp->ncb_length = SMB_PACKETSIZE;
8863 * The top level loop for handling SMB request messages. Each server thread
8864 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8865 * NCB and buffer for the incoming request are loaned to us.
8867 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8868 * to immediately send a request for the rest of the data. This must come
8869 * before any other traffic for that session, so we delay setting the session
8870 * event until that data has come in.
8872 void smb_Server(VOID *parmp)
8874 INT_PTR myIdx = (INT_PTR) parmp;
8878 smb_packet_t *outbufp;
8880 int idx_NCB, idx_session;
8882 smb_vc_t *vcp = NULL;
8884 extern void rx_StartClientThread(void);
8886 rx_StartClientThread();
8888 outncbp = smb_GetNCB();
8889 outbufp = smb_GetPacket();
8890 outbufp->ncbp = outncbp;
8898 cm_ResetServerPriority();
8900 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8903 /* terminate silently if shutdown flag is set */
8904 if (code == WAIT_OBJECT_0) {
8905 if (smbShutdownFlag == 1) {
8906 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8912 /* error checking */
8913 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8915 int abandonIdx = code - WAIT_ABANDONED_0;
8916 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8919 if (code == WAIT_IO_COMPLETION)
8921 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8925 if (code == WAIT_TIMEOUT)
8927 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8930 if (code == WAIT_FAILED)
8932 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8935 idx_NCB = code - WAIT_OBJECT_0;
8937 /* check idx range! */
8938 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8940 /* this is fatal - log as much as possible */
8941 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8942 osi_assertx(0, "invalid index");
8945 ncbp = NCBs[idx_NCB];
8946 idx_session = NCBsessions[idx_NCB];
8947 rc = ncbp->ncb_retcode;
8949 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8950 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8954 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8958 /* Can this happen? Or is it just my UNIX paranoia? */
8959 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8964 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8967 /* Client closed session */
8968 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8970 lock_ObtainMutex(&vcp->mx);
8971 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8972 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8974 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8975 lock_ReleaseMutex(&vcp->mx);
8976 lock_ObtainWrite(&smb_globalLock);
8977 dead_sessions[vcp->session] = TRUE;
8978 lock_ReleaseWrite(&smb_globalLock);
8980 lock_ReleaseMutex(&vcp->mx);
8982 smb_CleanupDeadVC(vcp);
8989 /* Treat as transient error */
8990 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8993 "dispatch smb recv failed, message incomplete, ncb_length %d",
8996 "SMB message incomplete, "
8997 "length %d", ncbp->ncb_length);
9000 * We used to discard the packet.
9001 * Instead, try handling it normally.
9005 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9009 /* A weird error code. Log it, sleep, and continue. */
9010 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9012 lock_ObtainMutex(&vcp->mx);
9013 if (vcp->errorCount++ > 3) {
9014 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9015 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9016 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9018 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9019 lock_ReleaseMutex(&vcp->mx);
9020 lock_ObtainWrite(&smb_globalLock);
9021 dead_sessions[vcp->session] = TRUE;
9022 lock_ReleaseWrite(&smb_globalLock);
9024 lock_ReleaseMutex(&vcp->mx);
9026 smb_CleanupDeadVC(vcp);
9032 lock_ReleaseMutex(&vcp->mx);
9036 thrd_SetEvent(SessionEvents[idx_session]);
9042 /* Success, so now dispatch on all the data in the packet */
9044 smb_concurrentCalls++;
9045 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9046 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9049 * If at this point vcp is NULL (implies that packet was invalid)
9050 * then we are in big trouble. This means either :
9051 * a) we have the wrong NCB.
9052 * b) Netbios screwed up the call.
9053 * c) The VC was already marked dead before we were able to
9055 * Obviously this implies that
9056 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9057 * lanas[idx_session] != ncbp->ncb_lana_num )
9058 * Either way, we can't do anything with this packet.
9059 * Log, sleep and resume.
9062 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9066 ncbp->ncb_lana_num);
9068 /* Also log in the trace log. */
9069 osi_Log4(smb_logp, "Server: VCP does not exist!"
9070 "LSNs[idx_session]=[%d],"
9071 "lanas[idx_session]=[%d],"
9072 "ncbp->ncb_lsn=[%d],"
9073 "ncbp->ncb_lana_num=[%d]",
9077 ncbp->ncb_lana_num);
9079 /* thrd_Sleep(1000); Don't bother sleeping */
9080 thrd_SetEvent(SessionEvents[idx_session]);
9081 smb_concurrentCalls--;
9085 cm_SetRequestStartTime();
9087 vcp->errorCount = 0;
9088 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9089 smbp = (smb_t *)bufp->data;
9096 if (smbp->com == 0x1d) {
9097 /* Special handling for Write Raw */
9098 raw_write_cont_t rwc;
9100 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9101 if (rwc.code == 0) {
9102 EVENT_HANDLE rwevent;
9103 char eventName[MAX_PATH];
9105 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9106 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9107 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9108 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9110 ncbp->ncb_command = NCBRECV | ASYNCH;
9111 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9112 ncbp->ncb_lana_num = vcp->lana;
9113 ncbp->ncb_buffer = rwc.buf;
9114 ncbp->ncb_length = 65535;
9115 ncbp->ncb_event = rwevent;
9117 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9118 thrd_CloseHandle(rwevent);
9120 thrd_SetEvent(SessionEvents[idx_session]);
9122 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9124 else if (smbp->com == 0xa0) {
9126 * Serialize the handling for NT Transact
9129 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9130 thrd_SetEvent(SessionEvents[idx_session]);
9132 thrd_SetEvent(SessionEvents[idx_session]);
9133 /* TODO: what else needs to be serialized? */
9134 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9138 __except( smb_ServerExceptionFilter() ) {
9142 smb_concurrentCalls--;
9145 thrd_SetEvent(NCBavails[idx_NCB]);
9150 smb_FreePacket(outbufp);
9152 smb_FreeNCB(outncbp);
9156 * Exception filter for the server threads. If an exception occurs in the
9157 * dispatch routines, which is where exceptions are most common, then do a
9158 * force trace and give control to upstream exception handlers. Useful for
9161 DWORD smb_ServerExceptionFilter(void) {
9162 /* While this is not the best time to do a trace, if it succeeds, then
9163 * we have a trace (assuming tracing was enabled). Otherwise, this should
9164 * throw a second exception.
9166 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9167 afsd_ForceTrace(TRUE);
9168 buf_ForceTrace(TRUE);
9169 return EXCEPTION_CONTINUE_SEARCH;
9173 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9174 * If the number of server threads is M, and the number of live sessions is
9175 * N, then the number of NCB's in use at any time either waiting for, or
9176 * holding, received messages is M + N, so that is how many NCB's get created.
9178 void InitNCBslot(int idx)
9180 struct smb_packet *bufp;
9181 EVENT_HANDLE retHandle;
9183 char eventName[MAX_PATH];
9185 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9187 NCBs[idx] = smb_GetNCB();
9188 sprintf(eventName,"NCBavails[%d]", idx);
9189 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9190 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9191 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9192 sprintf(eventName,"NCBevents[%d]", idx);
9193 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9194 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9195 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9196 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9197 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9198 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9199 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9200 for (i=0; i<smb_NumServerThreads; i++)
9201 NCBreturns[i][idx] = retHandle;
9202 bufp = smb_GetPacket();
9203 bufp->spacep = cm_GetSpace();
9207 /* listen for new connections */
9208 void smb_Listener(void *parmp)
9214 afs_uint32 session, thread;
9215 smb_vc_t *vcp = NULL;
9217 char rname[NCBNAMSZ+1];
9218 char cname[MAX_COMPUTERNAME_LENGTH+1];
9219 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9220 INT_PTR lana = (INT_PTR) parmp;
9221 char eventName[MAX_PATH];
9222 int bridgeCount = 0;
9223 int nowildCount = 0;
9225 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9226 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9227 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9228 thrd_ResetEvent(ListenerShutdown[lana]);
9230 ncbp = smb_GetNCB();
9232 /* retrieve computer name */
9233 GetComputerName(cname, &cnamelen);
9236 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9237 memset(ncbp, 0, sizeof(NCB));
9240 ncbp->ncb_command = NCBLISTEN;
9241 ncbp->ncb_rto = 0; /* No receive timeout */
9242 ncbp->ncb_sto = 0; /* No send timeout */
9244 /* pad out with spaces instead of null termination */
9245 len = (long)strlen(smb_localNamep);
9246 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9247 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9249 strcpy(ncbp->ncb_callname, "*");
9250 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9252 ncbp->ncb_lana_num = (UCHAR)lana;
9254 code = Netbios(ncbp);
9256 if (code == NRC_NAMERR) {
9257 /* An smb shutdown or Vista resume must have taken place */
9259 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9260 ncbp->ncb_lana_num);
9261 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9263 if (lock_TryMutex(&smb_StartedLock)) {
9264 lana_list.lana[i] = LANA_INVALID;
9265 lock_ReleaseMutex(&smb_StartedLock);
9268 } else if (code == NRC_BRIDGE || code != 0) {
9269 int lanaRemaining = 0;
9271 if (code == NRC_BRIDGE) {
9272 if (++bridgeCount <= 5) {
9273 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9276 } else if (code == NRC_NOWILD) {
9277 if (++nowildCount <= 5) {
9278 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9280 if (bridgeCount > 0) {
9281 memset(ncbp, 0, sizeof(*ncbp));
9282 ncbp->ncb_command = NCBADDNAME;
9283 ncbp->ncb_lana_num = (UCHAR)lana;
9284 /* pad out with spaces instead of null termination */
9285 len = (long)strlen(smb_localNamep);
9286 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9287 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9288 code = Netbios(ncbp);
9294 while (!lock_TryMutex(&smb_StartedLock)) {
9295 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9301 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9302 ncbp->ncb_lana_num, ncb_error_string(code));
9303 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9304 ncbp->ncb_lana_num, ncb_error_string(code));
9306 for (i = 0; i < lana_list.length; i++) {
9307 if (lana_list.lana[i] == lana) {
9308 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9309 lana_list.lana[i] = LANA_INVALID;
9311 if (lana_list.lana[i] != LANA_INVALID)
9315 if (lanaRemaining == 0) {
9316 cm_VolStatus_Network_Stopped(cm_NetbiosName
9321 smb_ListenerState = SMB_LISTENER_STOPPED;
9322 smb_LANadapter = LANA_INVALID;
9323 lana_list.length = 0;
9325 lock_ReleaseMutex(&smb_StartedLock);
9329 else if (code != 0) {
9330 char tbuffer[AFSPATHMAX];
9332 /* terminate silently if shutdown flag is set */
9333 while (!lock_TryMutex(&smb_StartedLock)) {
9334 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9340 "NCBLISTEN lana=%d failed with code %d [%s]",
9341 ncbp->ncb_lana_num, code, ncb_error_string(code));
9343 "Client exiting due to network failure. Please restart client.\n");
9346 "Client exiting due to network failure. Please restart client.\n"
9347 "NCBLISTEN lana=%d failed with code %d [%s]",
9348 ncbp->ncb_lana_num, code, ncb_error_string(code));
9350 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9351 MB_OK|MB_SERVICE_NOTIFICATION);
9352 osi_panic(tbuffer, __FILE__, __LINE__);
9354 lock_ReleaseMutex(&smb_StartedLock);
9359 /* a successful packet received. clear bridge error count */
9363 /* check for remote conns */
9364 /* first get remote name and insert null terminator */
9365 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9366 for (i=NCBNAMSZ; i>0; i--) {
9367 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9373 /* compare with local name */
9375 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9376 flags |= SMB_VCFLAG_REMOTECONN;
9379 lock_ObtainMutex(&smb_ListenerLock);
9381 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9382 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9384 /* now ncbp->ncb_lsn is the connection ID */
9385 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9386 if (vcp->session == 0) {
9387 /* New generation */
9388 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9391 /* Log session startup */
9393 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9394 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9395 #endif /* NOTSERVICE */
9396 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9397 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9399 if (reportSessionStartups) {
9400 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9403 lock_ObtainMutex(&vcp->mx);
9404 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9405 vcp->flags |= flags;
9406 lock_ReleaseMutex(&vcp->mx);
9408 /* Allocate slot in session arrays */
9409 /* Re-use dead session if possible, otherwise add one more */
9410 /* But don't look at session[0], it is reserved */
9411 lock_ObtainWrite(&smb_globalLock);
9412 for (session = 1; session < numSessions; session++) {
9413 if (dead_sessions[session]) {
9414 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9415 dead_sessions[session] = FALSE;
9419 lock_ReleaseWrite(&smb_globalLock);
9421 /* We are re-using an existing VC because the lsn and lana
9423 session = vcp->session;
9425 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9427 /* Log session startup */
9429 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9430 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9431 #endif /* NOTSERVICE */
9432 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9433 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9435 if (reportSessionStartups) {
9436 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9440 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9441 unsigned long code = CM_ERROR_ALLBUSY;
9442 smb_packet_t * outp = smb_GetPacket();
9443 unsigned char *outWctp;
9446 smb_FormatResponsePacket(vcp, NULL, outp);
9449 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9450 unsigned long NTStatus;
9451 smb_MapNTError(code, &NTStatus);
9452 outWctp = outp->wctp;
9453 smbp = (smb_t *) &outp->data;
9457 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9458 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9459 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9460 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9461 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9463 unsigned short errCode;
9464 unsigned char errClass;
9465 smb_MapCoreError(code, vcp, &errCode, &errClass);
9466 outWctp = outp->wctp;
9467 smbp = (smb_t *) &outp->data;
9471 smbp->errLow = (unsigned char) (errCode & 0xff);
9472 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9473 smbp->rcls = errClass;
9476 smb_SendPacket(vcp, outp);
9477 smb_FreePacket(outp);
9479 lock_ObtainMutex(&vcp->mx);
9480 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9481 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9483 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9484 lock_ReleaseMutex(&vcp->mx);
9485 lock_ObtainWrite(&smb_globalLock);
9486 dead_sessions[vcp->session] = TRUE;
9487 lock_ReleaseWrite(&smb_globalLock);
9488 smb_CleanupDeadVC(vcp);
9490 lock_ReleaseMutex(&vcp->mx);
9493 /* assert that we do not exceed the maximum number of sessions or NCBs.
9494 * we should probably want to wait for a session to be freed in case
9497 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9498 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9500 lock_ObtainMutex(&vcp->mx);
9501 vcp->session = session;
9502 lock_ReleaseMutex(&vcp->mx);
9503 lock_ObtainWrite(&smb_globalLock);
9504 LSNs[session] = ncbp->ncb_lsn;
9505 lanas[session] = ncbp->ncb_lana_num;
9506 lock_ReleaseWrite(&smb_globalLock);
9508 if (session == numSessions) {
9509 /* Add new NCB for new session */
9510 char eventName[MAX_PATH];
9512 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9514 InitNCBslot(numNCBs);
9515 lock_ObtainWrite(&smb_globalLock);
9517 lock_ReleaseWrite(&smb_globalLock);
9518 thrd_SetEvent(NCBavails[0]);
9519 thrd_SetEvent(NCBevents[0]);
9520 for (thread = 0; thread < smb_NumServerThreads; thread++)
9521 thrd_SetEvent(NCBreturns[thread][0]);
9522 /* Also add new session event */
9523 sprintf(eventName, "SessionEvents[%d]", session);
9524 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9525 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9526 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9527 lock_ObtainWrite(&smb_globalLock);
9529 lock_ReleaseWrite(&smb_globalLock);
9530 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9531 thrd_SetEvent(SessionEvents[0]);
9533 thrd_SetEvent(SessionEvents[session]);
9539 lock_ReleaseMutex(&smb_ListenerLock);
9540 } /* dispatch while loop */
9544 thrd_SetEvent(ListenerShutdown[lana]);
9549 configureBackConnectionHostNames(void)
9551 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9552 * there is a restriction on the use of SMB authentication on loopback connections.
9553 * There are two work arounds available:
9555 * (1) We can disable the check for matching host names. This does not
9557 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9558 * "DisableLoopbackCheck"=dword:00000001
9560 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9561 * does require a reboot:
9562 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9563 * "BackConnectionHostNames"=multi-sz
9565 * The algorithm will be:
9566 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9567 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9568 * (2b1) and check to see if DisableLoopbackCheck is set.
9569 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9570 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9571 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9572 * check for the UnsetDisableLoopbackCheck value.
9573 * If set, set the DisableLoopbackCheck flag to 0x0
9574 * and delete the UnsetDisableLoopbackCheck value
9576 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9577 * force Windows to use the loopback authentication mechanism for the specified
9580 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9581 * service session that set it.
9587 DWORD dwSize, dwAllocSize;
9589 PBYTE pHostNames = NULL, pName = NULL;
9590 BOOL bNameFound = FALSE;
9591 static BOOL bLoopbackCheckDisabled = FALSE;
9593 /* BackConnectionHostNames and DisableLoopbackCheck */
9594 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9595 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9598 &hkMSV10) == ERROR_SUCCESS )
9600 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9601 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9602 (dwType == REG_MULTI_SZ))
9604 dwAllocSize += 1 /* in case the source string is not nul terminated */
9605 + (DWORD)strlen(cm_NetbiosName) + 2;
9606 pHostNames = malloc(dwAllocSize);
9607 dwSize = dwAllocSize;
9608 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9609 pHostNames, &dwSize) == ERROR_SUCCESS)
9611 for (pName = pHostNames;
9612 (pName - pHostNames < (int) dwSize) && *pName ;
9613 pName += strlen(pName) + 1)
9615 if ( !stricmp(pName, cm_NetbiosName) ) {
9623 if ( !bNameFound ) {
9624 size_t size = strlen(cm_NetbiosName) + 2;
9625 if ( !pHostNames ) {
9626 pHostNames = malloc(size);
9629 StringCbCopyA(pName, size, cm_NetbiosName);
9631 *pName = '\0'; /* add a second nul terminator */
9633 dwType = REG_MULTI_SZ;
9634 dwSize = (DWORD)(pName - pHostNames + 1);
9635 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9637 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9638 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9641 &hkLsa) == ERROR_SUCCESS )
9643 dwSize = sizeof(DWORD);
9644 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9647 dwSize = sizeof(DWORD);
9649 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9651 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9652 AFSREG_CLT_OPENAFS_SUBKEY,
9655 REG_OPTION_NON_VOLATILE,
9659 NULL) == ERROR_SUCCESS) {
9662 dwSize = sizeof(DWORD);
9664 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9665 bLoopbackCheckDisabled = TRUE;
9666 RegCloseKey(hkClient);
9671 } else if (!bLoopbackCheckDisabled) {
9672 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9673 AFSREG_CLT_OPENAFS_SUBKEY,
9676 REG_OPTION_NON_VOLATILE,
9680 NULL) == ERROR_SUCCESS) {
9682 dwSize = sizeof(DWORD);
9683 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9685 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9686 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9689 &hkLsa) == ERROR_SUCCESS )
9691 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9695 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9696 RegCloseKey(hkClient);
9705 RegCloseKey(hkMSV10);
9711 configureExtendedSMBSessionTimeouts(void)
9714 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9715 * new functionality:
9717 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9718 * "ReconnectableServers" REG_MULTI_SZ
9719 * "ExtendedSessTimeout" REG_DWORD (seconds)
9720 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
9722 * These values can be used to prevent the smb redirector from timing out
9723 * smb connection to the afs smb server prematurely.
9727 DWORD dwSize, dwAllocSize;
9729 PBYTE pHostNames = NULL, pName = NULL;
9730 BOOL bNameFound = FALSE;
9732 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9733 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9736 &hkLanMan) == ERROR_SUCCESS )
9738 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
9739 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9740 (dwType == REG_MULTI_SZ))
9742 dwAllocSize += 1 /* in case the source string is not nul terminated */
9743 + (DWORD)strlen(cm_NetbiosName) + 2;
9744 pHostNames = malloc(dwAllocSize);
9745 dwSize = dwAllocSize;
9746 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
9747 pHostNames, &dwSize) == ERROR_SUCCESS)
9749 for (pName = pHostNames;
9750 (pName - pHostNames < (int) dwSize) && *pName ;
9751 pName += strlen(pName) + 1)
9753 if ( !stricmp(pName, cm_NetbiosName) ) {
9761 if ( !bNameFound ) {
9762 size_t size = strlen(cm_NetbiosName) + 2;
9763 if ( !pHostNames ) {
9764 pHostNames = malloc(size);
9767 StringCbCopyA(pName, size, cm_NetbiosName);
9769 *pName = '\0'; /* add a second nul terminator */
9771 dwType = REG_MULTI_SZ;
9772 dwSize = (DWORD)(pName - pHostNames + 1);
9773 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9781 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
9782 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9783 (dwType == REG_MULTI_SZ))
9785 dwAllocSize += 1 /* in case the source string is not nul terminated */
9786 + (DWORD)strlen(cm_NetbiosName) + 2;
9787 pHostNames = malloc(dwAllocSize);
9788 dwSize = dwAllocSize;
9789 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
9790 pHostNames, &dwSize) == ERROR_SUCCESS)
9792 for (pName = pHostNames;
9793 (pName - pHostNames < (int) dwSize) && *pName ;
9794 pName += strlen(pName) + 1)
9796 if ( !stricmp(pName, cm_NetbiosName) ) {
9804 if ( !bNameFound ) {
9805 size_t size = strlen(cm_NetbiosName) + 2;
9806 if ( !pHostNames ) {
9807 pHostNames = malloc(size);
9810 StringCbCopyA(pName, size, cm_NetbiosName);
9812 *pName = '\0'; /* add a second nul terminator */
9814 dwType = REG_MULTI_SZ;
9815 dwSize = (DWORD)(pName - pHostNames + 1);
9816 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9824 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
9825 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9826 (dwType != REG_DWORD))
9829 dwSize = sizeof(dwValue);
9830 dwValue = 300; /* 5 minutes */
9831 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9833 RegCloseKey(hkLanMan);
9838 smb_LanAdapterChangeThread(void *param)
9841 * Give the IPAddrDaemon thread a chance
9842 * to block before we trigger.
9845 smb_LanAdapterChange(0);
9848 void smb_SetLanAdapterChangeDetected(void)
9853 lock_ObtainMutex(&smb_StartedLock);
9855 if (!powerStateSuspended) {
9856 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9857 NULL, 0, &lpid, "smb_LanAdapterChange");
9858 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9859 thrd_CloseHandle(phandle);
9862 smb_LanAdapterChangeDetected = 1;
9863 lock_ReleaseMutex(&smb_StartedLock);
9866 void smb_LanAdapterChange(int locked) {
9867 lana_number_t lanaNum;
9869 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9871 LANA_ENUM temp_list;
9876 afsi_log("smb_LanAdapterChange");
9879 lock_ObtainMutex(&smb_StartedLock);
9881 smb_LanAdapterChangeDetected = 0;
9883 if (!powerStateSuspended &&
9884 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9885 LANA_NETBIOS_NAME_FULL)) &&
9886 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9887 if ( isGateway != bGateway ) {
9888 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9889 smb_LANadapter, lanaNum, isGateway, bGateway);
9891 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9892 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9893 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9896 NCB *ncbp = smb_GetNCB();
9897 ncbp->ncb_command = NCBENUM;
9898 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9899 ncbp->ncb_length = sizeof(temp_list);
9900 code = Netbios(ncbp);
9902 if (temp_list.length != lana_list.length) {
9903 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9904 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9907 for (i=0; i<lana_list.length; i++) {
9908 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9909 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9910 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9922 smb_StopListeners(1);
9923 smb_RestartListeners(1);
9926 lock_ReleaseMutex(&smb_StartedLock);
9929 /* initialize Netbios */
9930 int smb_NetbiosInit(int locked)
9933 int i, lana, code, l;
9935 int delname_tried=0;
9938 lana_number_t lanaNum;
9941 lock_ObtainMutex(&smb_StartedLock);
9943 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9944 smb_ListenerState != SMB_LISTENER_STOPPED) {
9947 lock_ReleaseMutex(&smb_StartedLock);
9950 /* setup the NCB system */
9951 ncbp = smb_GetNCB();
9953 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9954 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9955 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9957 if (smb_LANadapter != LANA_INVALID)
9958 afsi_log("LAN adapter number %d", smb_LANadapter);
9960 afsi_log("LAN adapter number not determined");
9963 afsi_log("Set for gateway service");
9965 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9967 /* something went horribly wrong. We can't proceed without a netbios name */
9969 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9970 osi_panic(buf, __FILE__, __LINE__);
9973 /* remember the name */
9974 len = (int)strlen(cm_NetbiosName);
9976 free(smb_localNamep);
9977 smb_localNamep = malloc(len+1);
9978 strcpy(smb_localNamep, cm_NetbiosName);
9979 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9981 /* Also copy the value to the client character encoded string */
9982 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9984 if (smb_LANadapter == LANA_INVALID) {
9985 ncbp->ncb_command = NCBENUM;
9986 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9987 ncbp->ncb_length = sizeof(lana_list);
9988 code = Netbios(ncbp);
9990 afsi_log("Netbios NCBENUM error code %d", code);
9991 osi_panic(s, __FILE__, __LINE__);
9995 lana_list.length = 1;
9996 lana_list.lana[0] = smb_LANadapter;
9999 for (i = 0; i < lana_list.length; i++) {
10000 /* reset the adaptor: in Win32, this is required for every process, and
10001 * acts as an init call, not as a real hardware reset.
10003 ncbp->ncb_command = NCBRESET;
10004 ncbp->ncb_callname[0] = 100;
10005 ncbp->ncb_callname[2] = 100;
10006 ncbp->ncb_lana_num = lana_list.lana[i];
10007 code = Netbios(ncbp);
10009 code = ncbp->ncb_retcode;
10011 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10012 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10014 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10018 /* and declare our name so we can receive connections */
10019 memset(ncbp, 0, sizeof(*ncbp));
10020 len=lstrlen(smb_localNamep);
10021 memset(smb_sharename,' ',NCBNAMSZ);
10022 memcpy(smb_sharename,smb_localNamep,len);
10023 afsi_log("lana_list.length %d", lana_list.length);
10025 /* Keep the name so we can unregister it later */
10026 for (l = 0; l < lana_list.length; l++) {
10027 lana = lana_list.lana[l];
10029 ncbp->ncb_command = NCBADDNAME;
10030 ncbp->ncb_lana_num = lana;
10031 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10032 code = Netbios(ncbp);
10034 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10035 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10037 char name[NCBNAMSZ+1];
10039 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10040 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10044 code = ncbp->ncb_retcode;
10047 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10050 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10051 if (code == NRC_BRIDGE) { /* invalid LANA num */
10052 lana_list.lana[l] = LANA_INVALID;
10055 else if (code == NRC_DUPNAME) {
10056 afsi_log("Name already exists; try to delete it");
10057 memset(ncbp, 0, sizeof(*ncbp));
10058 ncbp->ncb_command = NCBDELNAME;
10059 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10060 ncbp->ncb_lana_num = lana;
10061 code = Netbios(ncbp);
10063 code = ncbp->ncb_retcode;
10065 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10067 if (code != 0 || delname_tried) {
10068 lana_list.lana[l] = LANA_INVALID;
10070 else if (code == 0) {
10071 if (!delname_tried) {
10079 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10080 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10084 smb_LANadapter = lana;
10085 lana_found = 1; /* at least one worked */
10089 osi_assertx(lana_list.length >= 0, "empty lana list");
10091 afsi_log("No valid LANA numbers found!");
10092 lana_list.length = 0;
10093 smb_LANadapter = LANA_INVALID;
10094 smb_ListenerState = SMB_LISTENER_STOPPED;
10095 cm_VolStatus_Network_Stopped(cm_NetbiosName
10102 /* we're done with the NCB now */
10105 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10106 if (lana_list.length > 0)
10107 osi_assert(smb_LANadapter != LANA_INVALID);
10110 lock_ReleaseMutex(&smb_StartedLock);
10112 return (lana_list.length > 0 ? 1 : 0);
10115 void smb_StartListeners(int locked)
10122 lock_ObtainMutex(&smb_StartedLock);
10124 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10126 lock_ReleaseMutex(&smb_StartedLock);
10130 afsi_log("smb_StartListeners");
10131 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10132 configureBackConnectionHostNames();
10134 /* Configure Extended SMB Session Timeouts */
10135 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10136 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10137 configureExtendedSMBSessionTimeouts();
10140 smb_ListenerState = SMB_LISTENER_STARTED;
10141 cm_VolStatus_Network_Started(cm_NetbiosName
10147 for (i = 0; i < lana_list.length; i++) {
10148 if (lana_list.lana[i] == LANA_INVALID)
10150 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10151 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10152 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10153 thrd_CloseHandle(phandle);
10156 lock_ReleaseMutex(&smb_StartedLock);
10159 void smb_RestartListeners(int locked)
10162 lock_ObtainMutex(&smb_StartedLock);
10164 if (powerStateSuspended)
10165 afsi_log("smb_RestartListeners called while suspended");
10167 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10168 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10169 if (smb_NetbiosInit(1))
10170 smb_StartListeners(1);
10171 } else if (smb_LanAdapterChangeDetected) {
10172 smb_LanAdapterChange(1);
10176 lock_ReleaseMutex(&smb_StartedLock);
10179 void smb_StopListener(NCB *ncbp, int lana, int wait)
10183 memset(ncbp, 0, sizeof(*ncbp));
10184 ncbp->ncb_command = NCBDELNAME;
10185 ncbp->ncb_lana_num = lana;
10186 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10187 code = Netbios(ncbp);
10189 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10190 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10192 /* and then reset the LANA; this will cause the listener threads to exit */
10193 ncbp->ncb_command = NCBRESET;
10194 ncbp->ncb_callname[0] = 100;
10195 ncbp->ncb_callname[2] = 100;
10196 ncbp->ncb_lana_num = lana;
10197 code = Netbios(ncbp);
10199 code = ncbp->ncb_retcode;
10201 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10203 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10207 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10210 void smb_StopListeners(int locked)
10216 lock_ObtainMutex(&smb_StartedLock);
10218 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10220 lock_ReleaseMutex(&smb_StartedLock);
10224 afsi_log("smb_StopListeners");
10225 smb_ListenerState = SMB_LISTENER_STOPPED;
10226 cm_VolStatus_Network_Stopped(cm_NetbiosName
10232 ncbp = smb_GetNCB();
10234 /* Unregister the SMB name */
10235 for (l = 0; l < lana_list.length; l++) {
10236 lana = lana_list.lana[l];
10238 if (lana != LANA_INVALID) {
10239 smb_StopListener(ncbp, lana, TRUE);
10241 /* mark the adapter invalid */
10242 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10246 /* force a re-evaluation of the network adapters */
10247 lana_list.length = 0;
10248 smb_LANadapter = LANA_INVALID;
10251 lock_ReleaseMutex(&smb_StartedLock);
10254 void smb_Init(osi_log_t *logp, int useV3,
10264 EVENT_HANDLE retHandle;
10265 char eventName[MAX_PATH];
10266 int startListeners = 0;
10268 smb_MBfunc = aMBfunc;
10272 /* Initialize smb_localZero */
10273 myTime.tm_isdst = -1; /* compute whether on DST or not */
10274 myTime.tm_year = 70;
10276 myTime.tm_mday = 1;
10277 myTime.tm_hour = 0;
10280 smb_localZero = mktime(&myTime);
10282 #ifdef AFS_FREELANCE_CLIENT
10283 /* Make sure the root.afs volume has the correct time */
10284 cm_noteLocalMountPointChange();
10287 /* initialize the remote debugging log */
10290 /* and the global lock */
10291 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10292 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10294 /* Raw I/O data structures */
10295 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10297 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10298 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10300 /* 4 Raw I/O buffers */
10301 smb_RawBufs = calloc(65536,1);
10302 *((char **)smb_RawBufs) = NULL;
10303 for (i=0; i<3; i++) {
10304 char *rawBuf = calloc(65536,1);
10305 *((char **)rawBuf) = smb_RawBufs;
10306 smb_RawBufs = rawBuf;
10309 /* global free lists */
10310 smb_ncbFreeListp = NULL;
10311 smb_packetFreeListp = NULL;
10313 lock_ObtainMutex(&smb_StartedLock);
10314 startListeners = smb_NetbiosInit(1);
10316 /* Initialize listener and server structures */
10318 memset(dead_sessions, 0, sizeof(dead_sessions));
10319 sprintf(eventName, "SessionEvents[0]");
10320 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10321 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10322 afsi_log("Event Object Already Exists: %s", eventName);
10324 smb_NumServerThreads = nThreads;
10325 sprintf(eventName, "NCBavails[0]");
10326 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10327 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10328 afsi_log("Event Object Already Exists: %s", eventName);
10329 sprintf(eventName, "NCBevents[0]");
10330 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10331 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10332 afsi_log("Event Object Already Exists: %s", eventName);
10333 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10334 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10335 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10336 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10337 afsi_log("Event Object Already Exists: %s", eventName);
10338 for (i = 0; i < smb_NumServerThreads; i++) {
10339 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10340 NCBreturns[i][0] = retHandle;
10343 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10344 for (i = 0; i < smb_NumServerThreads; i++) {
10345 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10346 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10347 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10348 afsi_log("Event Object Already Exists: %s", eventName);
10349 InitNCBslot((int)(i+1));
10351 numNCBs = smb_NumServerThreads + 1;
10353 /* Initialize dispatch table */
10354 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10355 /* Prepare the table for unknown operations */
10356 for(i=0; i<= SMB_NOPCODES; i++) {
10357 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10359 /* Fill in the ones we do know */
10360 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10361 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10362 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10363 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10364 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10365 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10366 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10367 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10368 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10369 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10370 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10371 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10372 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10373 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10374 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10375 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10376 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10377 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10378 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10379 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10380 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10381 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10382 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10383 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10384 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10385 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10386 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10387 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10388 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10389 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10390 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10391 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10392 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10393 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10394 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10395 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10396 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10397 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10398 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10399 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10400 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10401 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10402 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10403 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10404 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10405 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10406 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10407 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10408 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10409 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10410 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10411 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10412 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10413 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10414 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10415 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10416 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10417 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10418 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10419 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10420 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10421 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10422 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10423 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10424 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10425 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10426 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10427 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10428 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10429 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10430 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10431 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10432 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10433 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10435 /* setup tran 2 dispatch table */
10436 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10437 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10438 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10439 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10440 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10441 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10442 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10443 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10444 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10445 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10446 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10447 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10448 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10449 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10450 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10451 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10452 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10453 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10455 /* setup the rap dispatch table */
10456 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10457 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10458 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10459 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10460 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10464 /* if we are doing SMB authentication we have register outselves as a logon process */
10465 if (smb_authType != SMB_AUTH_NONE) {
10466 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10467 LSA_STRING afsProcessName;
10468 LSA_OPERATIONAL_MODE dummy; /*junk*/
10470 afsProcessName.Buffer = "OpenAFSClientDaemon";
10471 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10472 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10474 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10476 if (nts == STATUS_SUCCESS) {
10477 LSA_STRING packageName;
10478 /* we are registered. Find out the security package id */
10479 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10480 packageName.Length = (USHORT)strlen(packageName.Buffer);
10481 packageName.MaximumLength = packageName.Length + 1;
10482 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10483 if (nts == STATUS_SUCCESS) {
10485 * This code forces Windows to authenticate against the Logon Cache
10486 * first instead of attempting to authenticate against the Domain
10487 * Controller. When the Windows logon cache is enabled this improves
10488 * performance by removing the network access and works around a bug
10489 * seen at sites which are using a MIT Kerberos principal to login
10490 * to machines joined to a non-root domain in a multi-domain forest.
10491 * MsV1_0SetProcessOption was added in Windows XP.
10493 PVOID pResponse = NULL;
10494 ULONG cbResponse = 0;
10495 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10497 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10498 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10499 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10500 OptionsRequest.DisableOptions = FALSE;
10502 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10505 sizeof(OptionsRequest),
10511 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10512 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10515 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10517 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10518 afsi_log("MsV1_0SetProcessOption success");
10520 /* END - code from Larry */
10522 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10523 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10524 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10526 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10528 /* something went wrong. We report the error and revert back to no authentication
10529 because we can't perform any auth requests without a successful lsa handle
10530 or sec package id. */
10531 afsi_log("Reverting to NO SMB AUTH");
10532 smb_authType = SMB_AUTH_NONE;
10535 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10537 /* something went wrong. We report the error and revert back to no authentication
10538 because we can't perform any auth requests without a successful lsa handle
10539 or sec package id. */
10540 afsi_log("Reverting to NO SMB AUTH");
10541 smb_authType = SMB_AUTH_NONE;
10545 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10546 * time prevents the failure of authentication when logged into Windows with an
10547 * external Kerberos principal mapped to a local account.
10549 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10550 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10551 * then the only option is NTLMSSP anyway; so just fallback.
10556 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10557 if (secBlobLength == 0) {
10558 smb_authType = SMB_AUTH_NTLM;
10559 afsi_log("Reverting to SMB AUTH NTLM");
10568 /* Now get ourselves a domain name. */
10569 /* For now we are using the local computer name as the domain name.
10570 * It is actually the domain for local logins, and we are acting as
10571 * a local SMB server.
10573 bufsize = lengthof(smb_ServerDomainName) - 1;
10574 GetComputerNameW(smb_ServerDomainName, &bufsize);
10575 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10576 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10579 /* Start listeners, waiters, servers, and daemons */
10580 if (startListeners)
10581 smb_StartListeners(1);
10583 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10584 NULL, 0, &lpid, "smb_ClientWaiter");
10585 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10586 thrd_CloseHandle(phandle);
10588 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10589 NULL, 0, &lpid, "smb_ServerWaiter");
10590 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10591 thrd_CloseHandle(phandle);
10593 for (i=0; i<smb_NumServerThreads; i++) {
10594 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10595 (void *) i, 0, &lpid, "smb_Server");
10596 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10597 thrd_CloseHandle(phandle);
10600 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10601 NULL, 0, &lpid, "smb_Daemon");
10602 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10603 thrd_CloseHandle(phandle);
10605 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10606 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10607 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10608 thrd_CloseHandle(phandle);
10610 lock_ReleaseMutex(&smb_StartedLock);
10614 void smb_Shutdown(void)
10621 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10623 /* setup the NCB system */
10624 ncbp = smb_GetNCB();
10626 /* Block new sessions by setting shutdown flag */
10627 smbShutdownFlag = 1;
10629 /* Hang up all sessions */
10630 memset(ncbp, 0, sizeof(NCB));
10631 for (i = 1; i < numSessions; i++)
10633 if (dead_sessions[i])
10636 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10637 ncbp->ncb_command = NCBHANGUP;
10638 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10639 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10640 code = Netbios(ncbp);
10641 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10642 if (code == 0) code = ncbp->ncb_retcode;
10644 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10645 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10649 /* Trigger the shutdown of all SMB threads */
10650 for (i = 0; i < smb_NumServerThreads; i++)
10651 thrd_SetEvent(NCBreturns[i][0]);
10653 thrd_SetEvent(NCBevents[0]);
10654 thrd_SetEvent(SessionEvents[0]);
10655 thrd_SetEvent(NCBavails[0]);
10657 for (i = 0;i < smb_NumServerThreads; i++) {
10658 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10659 if (code == WAIT_OBJECT_0) {
10662 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10663 thrd_SetEvent(NCBreturns[i--][0]);
10667 /* Delete Netbios name */
10668 memset(ncbp, 0, sizeof(NCB));
10669 for (i = 0; i < lana_list.length; i++) {
10670 if (lana_list.lana[i] == LANA_INVALID) continue;
10671 ncbp->ncb_command = NCBDELNAME;
10672 ncbp->ncb_lana_num = lana_list.lana[i];
10673 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10674 code = Netbios(ncbp);
10676 code = ncbp->ncb_retcode;
10678 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10679 ncbp->ncb_lana_num, code);
10684 /* Release the reference counts held by the VCs */
10685 lock_ObtainWrite(&smb_rctLock);
10686 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10691 if (vcp->magic != SMB_VC_MAGIC)
10692 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10693 __FILE__, __LINE__);
10695 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10697 if (fidp->scp != NULL) {
10700 lock_ReleaseWrite(&smb_rctLock);
10701 lock_ObtainMutex(&fidp->mx);
10702 if (fidp->scp != NULL) {
10705 lock_ObtainWrite(&scp->rw);
10706 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10707 lock_ReleaseWrite(&scp->rw);
10708 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10709 cm_ReleaseSCache(scp);
10711 lock_ReleaseMutex(&fidp->mx);
10712 lock_ObtainWrite(&smb_rctLock);
10716 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10718 smb_ReleaseVCNoLock(tidp->vcp);
10720 cm_user_t *userp = tidp->userp;
10721 tidp->userp = NULL;
10722 cm_ReleaseUser(userp);
10726 lock_ReleaseWrite(&smb_rctLock);
10730 /* Get the UNC \\<servername>\<sharename> prefix. */
10731 char *smb_GetSharename()
10736 /* Make sure we have been properly initialized. */
10737 if (smb_localNamep == NULL)
10740 /* Allocate space for \\<servername>\<sharename>, plus the
10743 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10744 name = malloc(len);
10745 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10751 void smb_LogPacket(smb_packet_t *packet)
10755 unsigned length, paramlen, datalen, i, j;
10757 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10759 if (!packet) return;
10761 osi_Log0(smb_logp, "*** SMB packet dump ***");
10763 smbp = (smb_t *) packet->data;
10764 vp = (BYTE *) packet->data;
10766 paramlen = smbp->wct * 2;
10767 datalen = *((WORD *) (smbp->vdata + paramlen));
10768 length = sizeof(*smbp) + paramlen + 1 + datalen;
10770 for (i=0;i < length; i+=16)
10772 memset( buf, ' ', 80 );
10775 itoa( i, buf, 16 );
10777 buf[strlen(buf)] = ' ';
10779 cp = (BYTE*) buf + 7;
10781 for (j=0;j < 16 && (i+j)<length; j++)
10783 *(cp++) = hex[vp[i+j] >> 4];
10784 *(cp++) = hex[vp[i+j] & 0xf];
10794 for (j=0;j < 16 && (i+j)<length;j++)
10796 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10807 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10810 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10812 #endif /* LOG_PACKET */
10815 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10821 smb_username_t *unp;
10822 smb_waitingLockRequest_t *wlrp;
10825 lock_ObtainRead(&smb_rctLock);
10827 sprintf(output, "begin dumping smb_username_t\r\n");
10828 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10829 for (unp = usernamesp; unp; unp=unp->nextp)
10831 cm_ucell_t *ucellp;
10833 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10834 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10835 unp->name ? unp->name : _C("NULL"),
10836 unp->machine ? unp->machine : _C("NULL"));
10837 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10839 sprintf(output, " begin dumping cm_ucell_t\r\n");
10840 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10842 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10843 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",
10844 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10845 ucellp->expirationTime, ucellp->gen,
10847 ucellp->cellp->name);
10848 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10851 sprintf(output, " done dumping cm_ucell_t\r\n");
10852 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10855 sprintf(output, "done dumping smb_username_t\r\n");
10856 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10859 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10860 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10863 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10864 smb_waitingLock_t *lockp;
10866 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10867 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10868 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10870 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10871 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10872 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10873 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10874 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10875 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10877 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10878 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10881 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10882 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10884 sprintf(output, "begin dumping smb_vc_t\r\n");
10885 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10887 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10893 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10894 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10895 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10897 sprintf(output, " begin dumping smb_user_t\r\n");
10898 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10899 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10900 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10901 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10902 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10904 sprintf(output, " done dumping smb_user_t\r\n");
10905 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10907 sprintf(output, " begin dumping smb_tid_t\r\n");
10908 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10909 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10910 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",
10911 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10912 tidp->pathname ? tidp->pathname : _C("NULL"));
10913 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10915 sprintf(output, " done dumping smb_tid_t\r\n");
10916 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10918 sprintf(output, " begin dumping smb_fid_t\r\n");
10919 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10921 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10923 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",
10924 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10925 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10926 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10927 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10930 sprintf(output, " done dumping smb_fid_t\r\n");
10931 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10934 sprintf(output, "done dumping smb_vc_t\r\n");
10935 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10937 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10938 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10940 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10946 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10947 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10948 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10950 sprintf(output, " begin dumping smb_user_t\r\n");
10951 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10952 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10953 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10954 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10955 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10957 sprintf(output, " done dumping smb_user_t\r\n");
10958 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10960 sprintf(output, " begin dumping smb_tid_t\r\n");
10961 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10962 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10963 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",
10964 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10965 tidp->pathname ? tidp->pathname : _C("NULL"));
10966 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10968 sprintf(output, " done dumping smb_tid_t\r\n");
10969 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10971 sprintf(output, " begin dumping smb_fid_t\r\n");
10972 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10974 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10976 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",
10977 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10978 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10979 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10980 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10983 sprintf(output, " done dumping smb_fid_t\r\n");
10984 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10987 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10988 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10991 lock_ReleaseRead(&smb_rctLock);
10995 long smb_IsNetworkStarted(void)
10998 lock_ObtainWrite(&smb_globalLock);
10999 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11000 lock_ReleaseWrite(&smb_globalLock);