2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
33 #include "lanahelper.h"
35 #define STRSAFE_NO_DEPRECATE
38 /* These characters are illegal in Windows filenames */
39 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
41 static int smbShutdownFlag = 0;
42 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
44 int smb_LogoffTokenTransfer;
45 time_t smb_LogoffTransferTimeout;
47 int smb_StoreAnsiFilenames = 0;
49 DWORD last_msg_time = 0;
53 unsigned int sessionGen = 0;
55 extern void afsi_log(char *pattern, ...);
56 extern HANDLE afsi_file;
57 extern int powerStateSuspended;
59 osi_hyper_t hzero = {0, 0};
60 osi_hyper_t hones = {0xFFFFFFFF, -1};
63 osi_rwlock_t smb_globalLock;
64 osi_rwlock_t smb_rctLock;
65 osi_mutex_t smb_ListenerLock;
66 osi_mutex_t smb_StartedLock;
68 unsigned char smb_LANadapter = LANA_INVALID;
69 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
70 int smb_LanAdapterChangeDetected = 0;
71 afs_uint32 smb_AsyncStore = 1;
72 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
74 BOOL isGateway = FALSE;
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
85 afs_uint32 smb_NumServerThreads;
87 afs_uint32 numNCBs, numSessions, numVCs;
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
92 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
94 ULONG smb_lsaSecPackage;
95 LSA_STRING smb_lsaLogonOrigin;
97 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
99 EVENT_HANDLE **NCBreturns;
100 EVENT_HANDLE **NCBShutdown;
101 EVENT_HANDLE *smb_ServerShutdown;
102 EVENT_HANDLE ListenerShutdown[256];
103 DWORD NCBsessions[NCB_MAX];
105 struct smb_packet *bufs[NCB_MAX];
107 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
108 EVENT_HANDLE SessionEvents[SESSION_MAX];
109 unsigned short LSNs[SESSION_MAX];
110 int lanas[SESSION_MAX];
111 BOOL dead_sessions[SESSION_MAX];
114 osi_mutex_t smb_RawBufLock;
117 #define SMB_MASKFLAG_TILDE 1
118 #define SMB_MASKFLAG_CASEFOLD 2
120 #define RAWTIMEOUT INFINITE
123 typedef struct raw_write_cont {
132 /* dir search stuff */
133 long smb_dirSearchCounter = 1;
134 smb_dirSearch_t *smb_firstDirSearchp;
135 smb_dirSearch_t *smb_lastDirSearchp;
137 /* hide dot files? */
138 int smb_hideDotFiles;
140 /* Negotiate Unicode support? */
143 /* global state about V3 protocols */
144 int smb_useV3; /* try to negotiate V3 */
146 static int showErrors = 0;
147 /* MessageBox or something like it */
148 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
152 * Time in Unix format of midnight, 1/1/1970 local time.
153 * When added to dosUTime, gives Unix (AFS) time.
155 time_t smb_localZero = 0;
157 char *smb_localNamep = NULL;
159 smb_vc_t *smb_allVCsp;
160 smb_vc_t *smb_deadVCsp;
162 smb_username_t *usernamesp = NULL;
164 smb_waitingLockRequest_t *smb_allWaitingLocks;
167 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
168 NCB *ncbp, raw_write_cont_t *rwcp);
169 int smb_NetbiosInit(int);
172 void smb_LogPacket(smb_packet_t *packet);
173 #endif /* LOG_PACKET */
175 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
176 int smb_ServerDomainNameLength = 0;
177 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
178 int smb_ServerOSLength = lengthof(smb_ServerOS);
179 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
180 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
182 /* Faux server GUID. This is never checked. */
183 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
185 void smb_InitReq(cm_req_t *reqp)
188 reqp->flags |= CM_REQ_SOURCE_SMB;
191 const char * ncb_error_string(int code)
195 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
196 case 0x03: s = "NRC_ILLCMD illegal command"; break;
197 case 0x05: s = "NRC_CMDTMO command timed out"; break;
198 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
199 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
200 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
201 case 0x09: s = "NRC_NORES no resource available"; break;
202 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
203 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
204 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
205 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
206 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
207 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
208 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
209 case 0x13: s = "NRC_ILLNN illegal name number"; break;
210 case 0x14: s = "NRC_NOCALL no callname"; break;
211 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
212 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
213 case 0x17: s = "NRC_NAMERR name deleted"; break;
214 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
215 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
216 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
217 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
218 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
219 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
220 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
221 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
222 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
223 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
224 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
225 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
226 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
227 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
228 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
229 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
230 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
231 case 0x40: s = "NRC_SYSTEM system error"; break;
232 default: s = "unknown error";
238 char * myCrt_Dispatch(int i)
243 return "(00)ReceiveCoreMakeDir";
245 return "(01)ReceiveCoreRemoveDir";
247 return "(02)ReceiveCoreOpen";
249 return "(03)ReceiveCoreCreate";
251 return "(04)ReceiveCoreClose";
253 return "(05)ReceiveCoreFlush";
255 return "(06)ReceiveCoreUnlink";
257 return "(07)ReceiveCoreRename";
259 return "(08)ReceiveCoreGetFileAttributes";
261 return "(09)ReceiveCoreSetFileAttributes";
263 return "(0a)ReceiveCoreRead";
265 return "(0b)ReceiveCoreWrite";
267 return "(0c)ReceiveCoreLockRecord";
269 return "(0d)ReceiveCoreUnlockRecord";
271 return "(0e)SendCoreBadOp";
273 return "(0f)ReceiveCoreCreate";
275 return "(10)ReceiveCoreCheckPath";
277 return "(11)SendCoreBadOp";
279 return "(12)ReceiveCoreSeek";
281 return "(1a)ReceiveCoreReadRaw";
283 return "(1d)ReceiveCoreWriteRawDummy";
285 return "(22)ReceiveV3SetAttributes";
287 return "(23)ReceiveV3GetAttributes";
289 return "(24)ReceiveV3LockingX";
291 return "(25)ReceiveV3Trans";
293 return "(26)ReceiveV3Trans[aux]";
295 return "(29)SendCoreBadOp";
297 return "(2b)ReceiveCoreEcho";
299 return "(2d)ReceiveV3OpenX";
301 return "(2e)ReceiveV3ReadX";
303 return "(2f)ReceiveV3WriteX";
305 return "(32)ReceiveV3Tran2A";
307 return "(33)ReceiveV3Tran2A[aux]";
309 return "(34)ReceiveV3FindClose";
311 return "(35)ReceiveV3FindNotifyClose";
313 return "(70)ReceiveCoreTreeConnect";
315 return "(71)ReceiveCoreTreeDisconnect";
317 return "(72)ReceiveNegotiate";
319 return "(73)ReceiveV3SessionSetupX";
321 return "(74)ReceiveV3UserLogoffX";
323 return "(75)ReceiveV3TreeConnectX";
325 return "(80)ReceiveCoreGetDiskAttributes";
327 return "(81)ReceiveCoreSearchDir";
331 return "(83)FindUnique";
333 return "(84)FindClose";
335 return "(A0)ReceiveNTTransact";
337 return "(A2)ReceiveNTCreateX";
339 return "(A4)ReceiveNTCancel";
341 return "(A5)ReceiveNTRename";
343 return "(C0)OpenPrintFile";
345 return "(C1)WritePrintFile";
347 return "(C2)ClosePrintFile";
349 return "(C3)GetPrintQueue";
351 return "(D8)ReadBulk";
353 return "(D9)WriteBulk";
355 return "(DA)WriteBulkData";
357 return "unknown SMB op";
361 char * myCrt_2Dispatch(int i)
366 return "unknown SMB op-2";
368 return "S(00)CreateFile_ReceiveTran2Open";
370 return "S(01)FindFirst_ReceiveTran2SearchDir";
372 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
374 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
376 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
378 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
380 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
382 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
384 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
386 return "S(09)_ReceiveTran2FSCTL";
388 return "S(0a)_ReceiveTran2IOCTL";
390 return "S(0b)_ReceiveTran2FindNotifyFirst";
392 return "S(0c)_ReceiveTran2FindNotifyNext";
394 return "S(0d)_ReceiveTran2CreateDirectory";
396 return "S(0e)_ReceiveTran2SessionSetup";
398 return "S(0f)_QueryFileSystemInformationFid";
400 return "S(10)_ReceiveTran2GetDfsReferral";
402 return "S(11)_ReceiveTran2ReportDfsInconsistency";
406 char * myCrt_RapDispatch(int i)
411 return "unknown RAP OP";
413 return "RAP(0)NetShareEnum";
415 return "RAP(1)NetShareGetInfo";
417 return "RAP(13)NetServerGetInfo";
419 return "RAP(63)NetWkStaGetInfo";
423 char * myCrt_NmpipeDispatch(int i)
426 case SMB_TRANS_SET_NMPIPE_STATE:
427 return "SET NMPIPE STATE";
429 case SMB_TRANS_RAW_READ_NMPIPE:
430 return "RAW READ NMPIPE";
432 case SMB_TRANS_QUERY_NMPIPE_STATE:
433 return "QUERY NMPIPE STATE";
435 case SMB_TRANS_QUERY_NMPIPE_INFO:
436 return "QUERY NMPIPE INFO";
438 case SMB_TRANS_PEEK_NMPIPE:
439 return "PEEK NMPIPE";
441 case SMB_TRANS_TRANSACT_NMPIPE:
442 return "TRANSACT NMPIPE";
444 case SMB_TRANS_RAW_WRITE_NMPIPE:
445 return "WRITE NMPIPE";
447 case SMB_TRANS_READ_NMPIPE:
448 return "READ NMPIPE";
450 case SMB_TRANS_WRITE_NMPIPE:
451 return "WRITE NMPIPE";
453 case SMB_TRANS_WAIT_NMPIPE:
454 return "WAIT NMPIPE";
456 case SMB_TRANS_CALL_NMPIPE:
457 return "CALL NMPIPE";
462 /* scache must be locked */
463 unsigned int smb_Attributes(cm_scache_t *scp)
467 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
468 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
469 scp->fileType == CM_SCACHETYPE_INVALID)
471 attrs = SMB_ATTR_DIRECTORY;
472 #ifdef SPECIAL_FOLDERS
473 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
474 #endif /* SPECIAL_FOLDERS */
475 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
476 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
481 * We used to mark a file RO if it was in an RO volume, but that
482 * turns out to be impolitic in NT. See defect 10007.
485 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
486 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
488 if ((scp->unixModeBits & 0200) == 0)
489 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
495 /* Check if the named file/dir is a dotfile/dotdir */
496 /* String pointed to by lastComp can have leading slashes, but otherwise should have
497 no other patch components */
498 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
502 /* skip over slashes */
503 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
508 /* nulls, curdir and parent dir doesn't count */
514 if(*(s+1) == _C('.') && !*(s + 2))
521 static int ExtractBits(WORD bits, short start, short len)
528 num = bits << (16 - end);
529 num = num >> ((16 - end) + start);
534 void ShowUnixTime(char *FuncName, time_t unixTime)
539 cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
541 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
542 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
544 int day, month, year, sec, min, hour;
547 day = ExtractBits(wDate, 0, 5);
548 month = ExtractBits(wDate, 5, 4);
549 year = ExtractBits(wDate, 9, 7) + 1980;
551 sec = ExtractBits(wTime, 0, 5);
552 min = ExtractBits(wTime, 5, 6);
553 hour = ExtractBits(wTime, 11, 5);
555 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
556 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
560 /* Determine if we are observing daylight savings time */
561 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
563 TIME_ZONE_INFORMATION timeZoneInformation;
564 SYSTEMTIME utc, local, localDST;
566 /* Get the time zone info. NT uses this to calc if we are in DST. */
567 GetTimeZoneInformation(&timeZoneInformation);
569 /* Return the daylight bias */
570 *pDstBias = timeZoneInformation.DaylightBias;
572 /* Return the bias */
573 *pBias = timeZoneInformation.Bias;
575 /* Now determine if DST is being observed */
577 /* Get the UTC (GMT) time */
580 /* Convert UTC time to local time using the time zone info. If we are
581 observing DST, the calculated local time will include this.
583 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
585 /* Set the daylight bias to 0. The daylight bias is the amount of change
586 * in time that we use for daylight savings time. By setting this to 0
587 * we cause there to be no change in time during daylight savings time.
589 timeZoneInformation.DaylightBias = 0;
591 /* Convert the utc time to local time again, but this time without any
592 adjustment for daylight savings time.
594 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
596 /* If the two times are different, then it means that the localDST that
597 we calculated includes the daylight bias, and therefore we are
598 observing daylight savings time.
600 *pDST = localDST.wHour != local.wHour;
604 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
606 BOOL dst; /* Will be TRUE if observing DST */
607 LONG dstBias; /* Offset from local time if observing DST */
608 LONG bias; /* Offset from GMT for local time */
611 * This function will adjust the last write time to compensate
612 * for two bugs in the smb client:
614 * 1) During Daylight Savings Time, the LastWriteTime is ahead
615 * in time by the DaylightBias (ignoring the sign - the
616 * DaylightBias is always stored as a negative number). If
617 * the DaylightBias is -60, then the LastWriteTime will be
618 * ahead by 60 minutes.
620 * 2) If the local time zone is a positive offset from GMT, then
621 * the LastWriteTime will be the correct local time plus the
622 * Bias (ignoring the sign - a positive offset from GMT is
623 * always stored as a negative Bias). If the Bias is -120,
624 * then the LastWriteTime will be ahead by 120 minutes.
626 * These bugs can occur at the same time.
629 GetTimeZoneInfo(&dst, &dstBias, &bias);
631 /* First adjust for DST */
633 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
635 /* Now adjust for a positive offset from GMT (a negative bias). */
637 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
640 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
642 time_t diff_t = unixTime - smb_localZero;
643 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
644 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
646 *dosUTimep = (afs_uint32)diff_t;
649 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
651 *unixTimep = dosTime + smb_localZero;
654 void smb_MarkAllVCsDead(smb_vc_t * exclude)
657 smb_vc_t **vcp_to_cleanup = NULL;
658 int n_to_cleanup = 0;
661 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
663 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
664 lock_ObtainWrite(&smb_rctLock);
665 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
667 if (vcp->magic != SMB_VC_MAGIC)
668 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
674 lock_ObtainMutex(&vcp->mx);
675 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
676 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
677 lock_ReleaseMutex(&vcp->mx);
678 dead_sessions[vcp->session] = TRUE;
680 lock_ReleaseMutex(&vcp->mx);
685 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
687 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
691 vcp_to_cleanup[i++] = vcp;
692 smb_HoldVCNoLock(vcp);
695 osi_assert(i == n_to_cleanup);
697 lock_ReleaseWrite(&smb_rctLock);
698 lock_ReleaseWrite(&smb_globalLock);
700 for (i=0; i < n_to_cleanup; i++) {
701 smb_CleanupDeadVC(vcp_to_cleanup[i]);
702 smb_ReleaseVC(vcp_to_cleanup[i]);
703 vcp_to_cleanup[i] = 0;
706 free(vcp_to_cleanup);
709 #ifdef DEBUG_SMB_REFCOUNT
710 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
712 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
717 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
718 lock_ObtainWrite(&smb_rctLock);
719 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
720 if (vcp->magic != SMB_VC_MAGIC)
721 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
724 lock_ObtainMutex(&vcp->mx);
725 if (lsn == vcp->lsn && lana == vcp->lana &&
726 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
727 lock_ReleaseMutex(&vcp->mx);
728 smb_HoldVCNoLock(vcp);
731 lock_ReleaseMutex(&vcp->mx);
733 if (!vcp && (flags & SMB_FLAG_CREATE)) {
734 vcp = malloc(sizeof(*vcp));
735 memset(vcp, 0, sizeof(*vcp));
736 vcp->vcID = ++numVCs;
737 vcp->magic = SMB_VC_MAGIC;
738 vcp->refCount = 2; /* smb_allVCsp and caller */
741 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
742 vcp->nextp = smb_allVCsp;
744 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
749 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
750 /* We must obtain a challenge for extended auth
751 * in case the client negotiates smb v3
753 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
754 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
755 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
756 ULONG lsaRespSize = 0;
758 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
760 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
767 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
768 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
769 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
770 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
771 nts, ntsEx, lsaRespSize);
773 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
775 if (ntsEx == STATUS_SUCCESS) {
776 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
779 * This will cause the subsequent authentication to fail but
780 * that is better than us dereferencing a NULL pointer and
783 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
786 LsaFreeReturnBuffer(lsaResp);
789 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
791 if (numVCs >= CM_SESSION_RESERVED) {
793 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
796 #ifdef DEBUG_SMB_REFCOUNT
798 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
799 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
802 lock_ReleaseWrite(&smb_rctLock);
803 lock_ReleaseWrite(&smb_globalLock);
807 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
812 for(i=0; i<11; i++) {
814 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
820 static int smb_IsStarMask(clientchar_t *maskp)
826 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
832 #ifdef DEBUG_SMB_REFCOUNT
833 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
834 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
836 void smb_ReleaseVCInternal(smb_vc_t *vcp)
842 lock_AssertWrite(&smb_rctLock);
845 if (vcp->refCount == 0) {
846 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
847 #ifdef DEBUG_SMB_REFCOUNT
848 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
849 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
851 /* remove VCP from smb_deadVCsp */
852 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
858 lock_FinalizeMutex(&vcp->mx);
859 memset(vcp,0,sizeof(smb_vc_t));
862 #ifdef DEBUG_SMB_REFCOUNT
863 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
865 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
869 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
870 avcp?"":"not ",vcp, vcp->refCount);
872 /* This is a wrong. However, I suspect that there is an undercount
873 * and I don't want to release 1.4.1 in a state that will allow
874 * smb_vc_t objects to be deallocated while still in the
875 * smb_allVCsp list. The list is supposed to keep a reference
876 * to the smb_vc_t. Put it back.
880 #ifdef DEBUG_SMB_REFCOUNT
881 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
882 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
886 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
887 /* The reference count is non-zero but the VC is dead.
888 * This implies that some FIDs, TIDs, etc on the VC have yet to
889 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
890 * add a reference that will be dropped by
891 * smb_CleanupDeadVC() and try to cleanup the VC again.
892 * Eventually the refCount will drop to zero when all of the
893 * active threads working with the VC end their task.
895 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
896 vcp->refCount++; /* put the refCount back */
897 lock_ReleaseWrite(&smb_rctLock);
898 smb_CleanupDeadVC(vcp);
899 #ifdef DEBUG_SMB_REFCOUNT
900 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
901 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
903 lock_ObtainWrite(&smb_rctLock);
906 #ifdef DEBUG_SMB_REFCOUNT
907 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
908 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
913 #ifdef DEBUG_SMB_REFCOUNT
914 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
916 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
919 lock_AssertWrite(&smb_rctLock);
920 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
921 smb_ReleaseVCInternal(vcp);
924 #ifdef DEBUG_SMB_REFCOUNT
925 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
927 void smb_ReleaseVC(smb_vc_t *vcp)
930 lock_ObtainWrite(&smb_rctLock);
931 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
932 smb_ReleaseVCInternal(vcp);
933 lock_ReleaseWrite(&smb_rctLock);
936 #ifdef DEBUG_SMB_REFCOUNT
937 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
939 void smb_HoldVCNoLock(smb_vc_t *vcp)
942 lock_AssertWrite(&smb_rctLock);
944 #ifdef DEBUG_SMB_REFCOUNT
945 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
946 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
948 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
952 #ifdef DEBUG_SMB_REFCOUNT
953 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
955 void smb_HoldVC(smb_vc_t *vcp)
958 lock_ObtainWrite(&smb_rctLock);
960 #ifdef DEBUG_SMB_REFCOUNT
961 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
962 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
964 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
966 lock_ReleaseWrite(&smb_rctLock);
969 void smb_CleanupDeadVC(smb_vc_t *vcp)
977 smb_user_t *uidpIter;
978 smb_user_t *uidpNext;
980 afs_uint32 refCount = 0;
982 lock_ObtainMutex(&vcp->mx);
983 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
984 lock_ReleaseMutex(&vcp->mx);
985 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
988 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
989 lock_ReleaseMutex(&vcp->mx);
990 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
992 lock_ObtainWrite(&smb_rctLock);
993 /* remove VCP from smb_allVCsp */
994 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
995 if ((*vcpp)->magic != SMB_VC_MAGIC)
996 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1000 vcp->nextp = smb_deadVCsp;
1002 /* Hold onto the reference until we are done with this function */
1007 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1008 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1010 if (fidpIter->deleteOk)
1013 fid = fidpIter->fid;
1014 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1016 smb_HoldFIDNoLock(fidpIter);
1017 lock_ReleaseWrite(&smb_rctLock);
1019 smb_CloseFID(vcp, fidpIter, NULL, 0);
1020 smb_ReleaseFID(fidpIter);
1022 lock_ObtainWrite(&smb_rctLock);
1023 fidpNext = vcp->fidsp;
1026 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1027 tidpNext = tidpIter->nextp;
1028 if (tidpIter->deleteOk)
1030 tidpIter->deleteOk = 1;
1032 tid = tidpIter->tid;
1033 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1035 smb_HoldTIDNoLock(tidpIter);
1036 smb_ReleaseTID(tidpIter, TRUE);
1037 tidpNext = vcp->tidsp;
1040 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1041 uidpNext = uidpIter->nextp;
1042 if (uidpIter->deleteOk)
1044 uidpIter->deleteOk = 1;
1046 /* do not add an additional reference count for the smb_user_t
1047 * as the smb_vc_t already is holding a reference */
1048 lock_ReleaseWrite(&smb_rctLock);
1050 smb_ReleaseUID(uidpIter);
1052 lock_ObtainWrite(&smb_rctLock);
1053 uidpNext = vcp->usersp;
1056 /* The vcp is now on the deadVCsp list. We intentionally drop the
1057 * reference so that the refcount can reach 0 and we can delete it
1059 * If the refCount == 1 going into the ReleaseVCNoLock call
1060 * the object will be freed and it won't be safe to clear
1063 refCount = vcp->refCount;
1064 smb_ReleaseVCNoLock(vcp);
1066 lock_ObtainMutex(&vcp->mx);
1067 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1068 lock_ReleaseMutex(&vcp->mx);
1071 lock_ReleaseWrite(&smb_rctLock);
1072 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1075 #ifdef DEBUG_SMB_REFCOUNT
1076 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1078 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1083 lock_ObtainWrite(&smb_rctLock);
1085 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1086 if (tidp->refCount == 0 && tidp->deleteOk) {
1088 smb_ReleaseTID(tidp, TRUE);
1092 if (tid == tidp->tid) {
1097 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1098 tidp = malloc(sizeof(*tidp));
1099 memset(tidp, 0, sizeof(*tidp));
1100 tidp->nextp = vcp->tidsp;
1103 smb_HoldVCNoLock(vcp);
1105 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1108 #ifdef DEBUG_SMB_REFCOUNT
1110 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1111 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1114 lock_ReleaseWrite(&smb_rctLock);
1118 #ifdef DEBUG_SMB_REFCOUNT
1119 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1121 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1124 lock_AssertWrite(&smb_rctLock);
1126 #ifdef DEBUG_SMB_REFCOUNT
1127 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1128 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1132 #ifdef DEBUG_SMB_REFCOUNT
1133 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1135 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1140 cm_user_t *userp = NULL;
1141 smb_vc_t *vcp = NULL;
1144 lock_ObtainWrite(&smb_rctLock);
1146 lock_AssertWrite(&smb_rctLock);
1148 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1149 #ifdef DEBUG_SMB_REFCOUNT
1150 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1151 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1153 if (tidp->refCount == 0) {
1154 if (tidp->deleteOk) {
1155 ltpp = &tidp->vcp->tidsp;
1156 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1160 osi_assertx(tp != NULL, "null smb_tid_t");
1162 lock_FinalizeMutex(&tidp->mx);
1163 userp = tidp->userp; /* remember to drop ref later */
1171 smb_ReleaseVCNoLock(vcp);
1173 lock_ReleaseWrite(&smb_rctLock);
1175 cm_ReleaseUser(userp);
1178 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1180 smb_user_t *uidp = NULL;
1182 lock_ObtainWrite(&smb_rctLock);
1183 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1184 if (uid == uidp->userID) {
1186 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1188 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1192 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1193 uidp = malloc(sizeof(*uidp));
1194 memset(uidp, 0, sizeof(*uidp));
1195 uidp->nextp = vcp->usersp;
1196 uidp->refCount = 2; /* one for the vcp and one for the caller */
1198 smb_HoldVCNoLock(vcp);
1200 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1202 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1204 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1206 lock_ReleaseWrite(&smb_rctLock);
1210 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1213 smb_username_t *unp= NULL;
1215 lock_ObtainWrite(&smb_rctLock);
1216 for(unp = usernamesp; unp; unp = unp->nextp) {
1217 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1218 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1223 if (!unp && (flags & SMB_FLAG_CREATE)) {
1224 unp = malloc(sizeof(*unp));
1225 memset(unp, 0, sizeof(*unp));
1227 unp->nextp = usernamesp;
1228 unp->name = cm_ClientStrDup(usern);
1229 unp->machine = cm_ClientStrDup(machine);
1231 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1232 if (flags & SMB_FLAG_AFSLOGON)
1233 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1236 lock_ReleaseWrite(&smb_rctLock);
1240 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1242 smb_user_t *uidp= NULL;
1244 lock_ObtainWrite(&smb_rctLock);
1245 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1248 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1250 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1251 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1256 lock_ReleaseWrite(&smb_rctLock);
1260 void smb_ReleaseUsername(smb_username_t *unp)
1263 smb_username_t **lupp;
1264 cm_user_t *userp = NULL;
1265 time_t now = osi_Time();
1267 lock_ObtainWrite(&smb_rctLock);
1268 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1269 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1270 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1272 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1276 osi_assertx(up != NULL, "null smb_username_t");
1278 up->nextp = NULL; /* do not remove this */
1279 lock_FinalizeMutex(&unp->mx);
1285 lock_ReleaseWrite(&smb_rctLock);
1287 cm_ReleaseUser(userp);
1290 void smb_HoldUIDNoLock(smb_user_t *uidp)
1292 lock_AssertWrite(&smb_rctLock);
1296 void smb_ReleaseUID(smb_user_t *uidp)
1300 smb_username_t *unp = NULL;
1302 lock_ObtainWrite(&smb_rctLock);
1303 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1304 if (uidp->refCount == 0) {
1305 lupp = &uidp->vcp->usersp;
1306 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1310 osi_assertx(up != NULL, "null smb_user_t");
1312 lock_FinalizeMutex(&uidp->mx);
1314 smb_ReleaseVCNoLock(uidp->vcp);
1318 lock_ReleaseWrite(&smb_rctLock);
1322 cm_ReleaseUserVCRef(unp->userp);
1323 smb_ReleaseUsername(unp);
1327 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1329 cm_user_t *up = NULL;
1334 lock_ObtainMutex(&uidp->mx);
1336 up = uidp->unp->userp;
1339 lock_ReleaseMutex(&uidp->mx);
1345 /* retrieve a held reference to a user structure corresponding to an incoming
1347 * corresponding release function is cm_ReleaseUser.
1349 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1352 cm_user_t *up = NULL;
1355 smbp = (smb_t *) inp;
1356 uidp = smb_FindUID(vcp, smbp->uid, 0);
1360 up = smb_GetUserFromUID(uidp);
1362 smb_ReleaseUID(uidp);
1367 * Return a pointer to a pathname extracted from a TID structure. The
1368 * TID structure is not held; assume it won't go away.
1370 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1375 tidp = smb_FindTID(vcp, tid, 0);
1379 if (tidp->flags & SMB_TIDFLAG_IPC) {
1380 code = CM_ERROR_TIDIPC;
1381 /* tidp->pathname would be NULL, but that's fine */
1383 *treepath = tidp->pathname;
1384 smb_ReleaseTID(tidp, FALSE);
1389 /* check to see if we have a chained fid, that is, a fid that comes from an
1390 * OpenAndX message that ran earlier in this packet. In this case, the fid
1391 * field in a read, for example, request, isn't set, since the value is
1392 * supposed to be inherited from the openAndX call.
1394 int smb_ChainFID(int fid, smb_packet_t *inp)
1396 if (inp->fid == 0 || inp->inCount == 0)
1402 /* are we a priv'd user? What does this mean on NT? */
1403 int smb_SUser(cm_user_t *userp)
1408 /* find a file ID. If we pass in 0 we select an unused File ID.
1409 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1410 * smb_fid_t data structure if desired File ID cannot be found.
1412 #ifdef DEBUG_SMB_REFCOUNT
1413 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1415 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1422 if (!(flags & SMB_FLAG_CREATE))
1427 lock_ObtainWrite(&smb_rctLock);
1429 fid = vcp->fidCounter;
1432 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1433 if (fidp->refCount == 0 && fidp->deleteOk) {
1435 lock_ReleaseWrite(&smb_rctLock);
1436 smb_ReleaseFID(fidp);
1437 lock_ObtainWrite(&smb_rctLock);
1439 * We dropped the smb_rctLock so the fid value we are using
1440 * may now be used by another thread. Start over with the
1441 * current vcp->fidCounter.
1444 fid = vcp->fidCounter;
1447 if (fid == fidp->fid) {
1449 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1451 if (fid == 0xFFFF) {
1453 "New FID number wraps on vcp 0x%x", vcp);
1463 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1464 char eventName[MAX_PATH];
1468 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1470 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1472 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1473 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1474 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1475 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1476 thrd_CloseHandle(event);
1478 if (fid == 0xFFFF) {
1479 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1485 fidp = malloc(sizeof(*fidp));
1486 memset(fidp, 0, sizeof(*fidp));
1487 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1490 smb_HoldVCNoLock(vcp);
1491 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1493 fidp->curr_chunk = fidp->prev_chunk = -2;
1494 fidp->raw_write_event = event;
1496 vcp->fidCounter = fid+1;
1497 if (vcp->fidCounter == 0xFFFF) {
1498 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1500 vcp->fidCounter = 1;
1505 #ifdef DEBUG_SMB_REFCOUNT
1507 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1508 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1511 lock_ReleaseWrite(&smb_rctLock);
1516 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1517 #ifdef DEBUG_SMB_REFCOUNT
1518 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1520 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1523 smb_fid_t *fidp = NULL, *nextp = NULL;
1529 * If the fidp->scp changes out from under us then
1530 * we must not grab a refCount. It means the *fidp
1531 * was processed by smb_CloseFID() and the *fidp is
1532 * no longer valid for use.
1534 lock_ObtainWrite(&smb_rctLock);
1535 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1536 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1540 if (scp == fidp->scp) {
1541 lock_ReleaseWrite(&smb_rctLock);
1542 lock_ObtainMutex(&fidp->mx);
1543 lock_ObtainWrite(&smb_rctLock);
1544 if (scp == fidp->scp) {
1545 lock_ReleaseMutex(&fidp->mx);
1548 lock_ReleaseMutex(&fidp->mx);
1551 if (fidp->refCount > 1) {
1554 lock_ReleaseWrite(&smb_rctLock);
1555 smb_ReleaseFID(fidp);
1556 lock_ObtainWrite(&smb_rctLock);
1561 if (nextp->refCount > 1) {
1564 lock_ReleaseWrite(&smb_rctLock);
1565 smb_ReleaseFID(nextp);
1566 lock_ObtainWrite(&smb_rctLock);
1570 #ifdef DEBUG_SMB_REFCOUNT
1572 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1573 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1576 lock_ReleaseWrite(&smb_rctLock);
1580 #ifdef DEBUG_SMB_REFCOUNT
1581 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1583 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1586 lock_AssertWrite(&smb_rctLock);
1588 #ifdef DEBUG_SMB_REFCOUNT
1589 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1590 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1596 /* the smb_fid_t->mx and smb_rctLock must not be held */
1597 #ifdef DEBUG_SMB_REFCOUNT
1598 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1600 void smb_ReleaseFID(smb_fid_t *fidp)
1603 cm_scache_t *scp = NULL;
1604 cm_user_t *userp = NULL;
1605 smb_vc_t *vcp = NULL;
1606 smb_ioctl_t *ioctlp;
1608 lock_ObtainMutex(&fidp->mx);
1609 lock_ObtainWrite(&smb_rctLock);
1610 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1611 #ifdef DEBUG_SMB_REFCOUNT
1612 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1613 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1615 if (fidp->refCount == 0) {
1616 if (fidp->deleteOk) {
1619 scp = fidp->scp; /* release after lock is released */
1621 lock_ObtainWrite(&scp->rw);
1622 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1623 lock_ReleaseWrite(&scp->rw);
1624 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1627 userp = fidp->userp;
1631 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1632 thrd_CloseHandle(fidp->raw_write_event);
1634 /* and see if there is ioctl stuff to free */
1635 ioctlp = fidp->ioctlp;
1638 cm_FreeSpace(ioctlp->prefix);
1639 if (ioctlp->ioctl.inAllocp)
1640 free(ioctlp->ioctl.inAllocp);
1641 if (ioctlp->ioctl.outAllocp)
1642 free(ioctlp->ioctl.outAllocp);
1646 smb_CleanupRPCFid(fidp);
1648 lock_ReleaseMutex(&fidp->mx);
1649 lock_FinalizeMutex(&fidp->mx);
1654 smb_ReleaseVCNoLock(vcp);
1658 lock_ReleaseMutex(&fidp->mx);
1660 lock_ReleaseWrite(&smb_rctLock);
1662 /* now release the scache structure */
1664 cm_ReleaseSCache(scp);
1667 cm_ReleaseUser(userp);
1671 * Case-insensitive search for one string in another;
1672 * used to find variable names in submount pathnames.
1674 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1676 clientchar_t *cursor;
1678 for (cursor = str1; *cursor; cursor++)
1679 if (cm_ClientStrCmpI(cursor, str2) == 0)
1686 * Substitute a variable value for its name in a submount pathname. Variable
1687 * name has been identified by smb_stristr() and is in substr. Variable name
1688 * length (plus one) is in substr_size. Variable value is in newstr.
1690 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1691 unsigned int substr_size, clientchar_t *newstr)
1693 clientchar_t temp[1024];
1695 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1696 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1697 cm_ClientStrCat(str1, cchstr1, temp);
1700 clientchar_t VNUserName[] = _C("%USERNAME%");
1701 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1702 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1703 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1705 typedef struct smb_findShare_rock {
1706 clientchar_t * shareName;
1707 clientchar_t * match;
1709 } smb_findShare_rock_t;
1711 #define SMB_FINDSHARE_EXACT_MATCH 1
1712 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1714 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1718 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1719 normchar_t normName[MAX_PATH];
1721 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1722 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1723 osi_LogSaveString(smb_logp, dep->name));
1727 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1728 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1729 matchType = SMB_FINDSHARE_EXACT_MATCH;
1731 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1734 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1735 vrock->matchType = matchType;
1737 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1738 return CM_ERROR_STOPNOW;
1744 /* find a shareName in the table of submounts */
1745 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1746 clientchar_t *shareName,
1747 clientchar_t **pathNamep)
1751 clientchar_t pathName[1024];
1754 clientchar_t *p, *q;
1755 fschar_t *cellname = NULL;
1758 DWORD allSubmount = 1;
1760 /* if allSubmounts == 0, only return the //mountRoot/all share
1761 * if in fact it has been been created in the subMounts table.
1762 * This is to allow sites that want to restrict access to the
1765 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1766 0, KEY_QUERY_VALUE, &parmKey);
1767 if (code == ERROR_SUCCESS) {
1768 cblen = sizeof(allSubmount);
1769 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1770 (BYTE *) &allSubmount, &cblen);
1771 if (code != ERROR_SUCCESS) {
1774 RegCloseKey (parmKey);
1777 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1782 /* In case, the all share is disabled we need to still be able
1783 * to handle ioctl requests
1785 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1786 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1790 if (MSRPC_IsWellKnownService(shareName) ||
1791 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1792 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1798 /* Check for volume references
1800 * They look like <cell>{%,#}<volume>
1802 if (cm_ClientStrChr(shareName, '%') != NULL ||
1803 cm_ClientStrChr(shareName, '#') != NULL) {
1804 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1805 /* make room for '/@vol:' + mountchar + NULL terminator*/
1807 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1808 osi_LogSaveClientString(smb_logp, shareName));
1810 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1811 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1812 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1814 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1816 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1817 cm_ClientStrLwr(*pathNamep);
1818 osi_Log1(smb_logp, " returning pathname [%S]",
1819 osi_LogSaveClientString(smb_logp, *pathNamep));
1827 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1828 0, KEY_QUERY_VALUE, &parmKey);
1829 if (code == ERROR_SUCCESS) {
1830 cblen = sizeof(pathName);
1831 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1832 (BYTE *) pathName, &cblen);
1833 if (code != ERROR_SUCCESS)
1835 RegCloseKey (parmKey);
1839 cchlen = cblen / sizeof(clientchar_t);
1840 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1841 /* We can accept either unix or PC style AFS pathnames. Convert
1842 * Unix-style to PC style here for internal use.
1845 cchlen = lengthof(pathName);
1847 /* within this code block, we maintain, cchlen = writeable
1848 buffer length of p */
1850 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1851 p += cm_mountRootCLen; /* skip mount path */
1852 cchlen -= (DWORD)(p - pathName);
1857 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1863 clientchar_t temp[1024];
1865 if (var = smb_stristr(p, VNUserName)) {
1866 if (uidp && uidp->unp)
1867 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1869 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1871 else if (var = smb_stristr(p, VNLCUserName))
1873 if (uidp && uidp->unp)
1874 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1876 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1877 cm_ClientStrLwr(temp);
1878 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1880 else if (var = smb_stristr(p, VNComputerName))
1882 sizeTemp = lengthof(temp);
1883 GetComputerNameW(temp, &sizeTemp);
1884 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1886 else if (var = smb_stristr(p, VNLCComputerName))
1888 sizeTemp = lengthof(temp);
1889 GetComputerName((LPTSTR)temp, &sizeTemp);
1890 cm_ClientStrLwr(temp);
1891 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1896 *pathNamep = cm_ClientStrDup(p);
1901 /* First lookup shareName in root.afs */
1903 smb_findShare_rock_t vrock;
1905 fschar_t ftemp[1024];
1906 clientchar_t * p = shareName;
1909 /* attempt to locate a partial match in root.afs. This is because
1910 when using the ANSI RAP calls, the share name is limited to 13 chars
1911 and hence is truncated. Of course we prefer exact matches. */
1913 thyper.HighPart = 0;
1916 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1917 if (vrock.shareName == NULL)
1920 vrock.matchType = 0;
1922 cm_HoldSCache(cm_data.rootSCachep);
1923 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1924 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1925 cm_ReleaseSCache(cm_data.rootSCachep);
1927 free(vrock.shareName);
1928 vrock.shareName = NULL;
1930 if (vrock.matchType) {
1931 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1932 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1937 /* if we get here, there was no match for the share in root.afs */
1938 /* so try to create \\<netbiosName>\<cellname> */
1943 /* Get the full name for this cell */
1944 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1945 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
1946 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
1947 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1948 if (code && cm_dnsEnabled) {
1950 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1955 /* construct the path */
1957 clientchar_t temp[1024];
1959 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
1960 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
1961 rw ? _C("/.%S/") : _C("/%S/"), temp);
1962 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1972 /* Client-side offline caching policy types */
1973 #define CSC_POLICY_MANUAL 0
1974 #define CSC_POLICY_DOCUMENTS 1
1975 #define CSC_POLICY_PROGRAMS 2
1976 #define CSC_POLICY_DISABLE 3
1978 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1981 clientchar_t policy[1024];
1984 int retval = CSC_POLICY_MANUAL;
1986 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1987 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1990 REG_OPTION_NON_VOLATILE,
1994 NULL ) != ERROR_SUCCESS)
1995 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1997 len = sizeof(policy);
1998 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2000 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2002 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2004 retval = CSC_POLICY_MANUAL;
2006 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2008 retval = CSC_POLICY_DOCUMENTS;
2010 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2012 retval = CSC_POLICY_PROGRAMS;
2014 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2016 retval = CSC_POLICY_DISABLE;
2019 RegCloseKey(hkCSCPolicy);
2023 /* find a dir search structure by cookie value, and return it held.
2024 * Must be called with smb_globalLock held.
2026 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2028 smb_dirSearch_t *dsp;
2030 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2031 if (dsp->cookie == cookie) {
2032 if (dsp != smb_firstDirSearchp) {
2033 /* move to head of LRU queue, too, if we're not already there */
2034 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2035 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2036 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2037 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2038 if (!smb_lastDirSearchp)
2039 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2047 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2048 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2049 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2055 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2057 lock_ObtainMutex(&dsp->mx);
2058 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2059 dsp->cookie, dsp, dsp->scp);
2060 dsp->flags |= SMB_DIRSEARCH_DELETE;
2061 if (dsp->scp != NULL) {
2062 lock_ObtainWrite(&dsp->scp->rw);
2063 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2064 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2065 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2066 dsp->scp->bulkStatProgress = hzero;
2068 lock_ReleaseWrite(&dsp->scp->rw);
2070 lock_ReleaseMutex(&dsp->mx);
2073 /* Must be called with the smb_globalLock held */
2074 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2076 cm_scache_t *scp = NULL;
2078 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2079 if (dsp->refCount == 0) {
2080 lock_ObtainMutex(&dsp->mx);
2081 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2082 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2083 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2084 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2085 lock_ReleaseMutex(&dsp->mx);
2086 lock_FinalizeMutex(&dsp->mx);
2088 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2089 dsp->cookie, dsp, scp);
2092 lock_ReleaseMutex(&dsp->mx);
2095 /* do this now to avoid spurious locking hierarchy creation */
2097 cm_ReleaseSCache(scp);
2100 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2102 lock_ObtainWrite(&smb_globalLock);
2103 smb_ReleaseDirSearchNoLock(dsp);
2104 lock_ReleaseWrite(&smb_globalLock);
2107 /* find a dir search structure by cookie value, and return it held */
2108 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2110 smb_dirSearch_t *dsp;
2112 lock_ObtainWrite(&smb_globalLock);
2113 dsp = smb_FindDirSearchNoLock(cookie);
2114 lock_ReleaseWrite(&smb_globalLock);
2118 /* GC some dir search entries, in the address space expected by the specific protocol.
2119 * Must be called with smb_globalLock held; release the lock temporarily.
2121 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2122 void smb_GCDirSearches(int isV3)
2124 smb_dirSearch_t *prevp;
2125 smb_dirSearch_t *dsp;
2126 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2130 victimCount = 0; /* how many have we got so far */
2131 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2132 /* we'll move tp from queue, so
2135 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2136 /* if no one is using this guy, and we're either in the new protocol,
2137 * or we're in the old one and this is a small enough ID to be useful
2138 * to the old protocol, GC this guy.
2140 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2141 /* hold and delete */
2142 lock_ObtainMutex(&dsp->mx);
2143 dsp->flags |= SMB_DIRSEARCH_DELETE;
2144 lock_ReleaseMutex(&dsp->mx);
2145 victimsp[victimCount++] = dsp;
2149 /* don't do more than this */
2150 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2154 /* now release them */
2155 for (i = 0; i < victimCount; i++) {
2156 smb_ReleaseDirSearchNoLock(victimsp[i]);
2160 /* function for allocating a dir search entry. We need these to remember enough context
2161 * since we don't get passed the path from call to call during a directory search.
2163 * Returns a held dir search structure, and bumps the reference count on the vnode,
2164 * since it saves a pointer to the vnode.
2166 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2168 smb_dirSearch_t *dsp;
2174 lock_ObtainWrite(&smb_globalLock);
2177 /* what's the biggest ID allowed in this version of the protocol */
2178 /* TODO: do we really want a non v3 dir search request to wrap
2179 smb_dirSearchCounter? */
2180 maxAllowed = isV3 ? 65535 : 255;
2181 if (smb_dirSearchCounter > maxAllowed)
2182 smb_dirSearchCounter = 1;
2184 start = smb_dirSearchCounter;
2187 /* twice so we have enough tries to find guys we GC after one pass;
2188 * 10 extra is just in case I mis-counted.
2190 if (++counter > 2*maxAllowed+10)
2191 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2193 if (smb_dirSearchCounter > maxAllowed) {
2194 smb_dirSearchCounter = 1;
2196 if (smb_dirSearchCounter == start) {
2198 smb_GCDirSearches(isV3);
2201 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2203 /* don't need to watch for refcount zero and deleted, since
2204 * we haven't dropped the global lock.
2207 ++smb_dirSearchCounter;
2211 dsp = malloc(sizeof(*dsp));
2212 memset(dsp, 0, sizeof(*dsp));
2213 dsp->cookie = smb_dirSearchCounter;
2214 ++smb_dirSearchCounter;
2216 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2217 dsp->lastTime = osi_Time();
2218 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2219 if (!smb_lastDirSearchp)
2220 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2222 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2226 lock_ReleaseWrite(&smb_globalLock);
2230 static smb_packet_t *smb_GetPacket(void)
2234 lock_ObtainWrite(&smb_globalLock);
2235 tbp = smb_packetFreeListp;
2237 smb_packetFreeListp = tbp->nextp;
2238 lock_ReleaseWrite(&smb_globalLock);
2240 tbp = calloc(sizeof(*tbp),1);
2241 tbp->magic = SMB_PACKETMAGIC;
2244 tbp->resumeCode = 0;
2250 tbp->ncb_length = 0;
2253 tbp->stringsp = NULL;
2255 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2260 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2263 tbp = smb_GetPacket();
2264 memcpy(tbp, pkt, sizeof(smb_packet_t));
2265 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2266 tbp->stringsp = NULL;
2268 smb_HoldVC(tbp->vcp);
2272 static NCB *smb_GetNCB(void)
2277 lock_ObtainWrite(&smb_globalLock);
2278 tbp = smb_ncbFreeListp;
2280 smb_ncbFreeListp = tbp->nextp;
2281 lock_ReleaseWrite(&smb_globalLock);
2283 tbp = calloc(sizeof(*tbp),1);
2284 tbp->magic = SMB_NCBMAGIC;
2287 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2289 memset(&tbp->ncb, 0, sizeof(NCB));
2294 static void FreeSMBStrings(smb_packet_t * pkt)
2299 for (s = pkt->stringsp; s; s = ns) {
2303 pkt->stringsp = NULL;
2306 void smb_FreePacket(smb_packet_t *tbp)
2308 smb_vc_t * vcp = NULL;
2309 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2311 lock_ObtainWrite(&smb_globalLock);
2312 tbp->nextp = smb_packetFreeListp;
2313 smb_packetFreeListp = tbp;
2314 tbp->magic = SMB_PACKETMAGIC;
2318 tbp->resumeCode = 0;
2324 tbp->ncb_length = 0;
2326 FreeSMBStrings(tbp);
2327 lock_ReleaseWrite(&smb_globalLock);
2333 static void smb_FreeNCB(NCB *bufferp)
2337 tbp = (smb_ncb_t *) bufferp;
2338 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2340 lock_ObtainWrite(&smb_globalLock);
2341 tbp->nextp = smb_ncbFreeListp;
2342 smb_ncbFreeListp = tbp;
2343 lock_ReleaseWrite(&smb_globalLock);
2346 /* get a ptr to the data part of a packet, and its count */
2347 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2351 unsigned char *afterParmsp;
2353 parmBytes = *smbp->wctp << 1;
2354 afterParmsp = smbp->wctp + parmBytes + 1;
2356 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2357 if (nbytesp) *nbytesp = dataBytes;
2359 /* don't forget to skip the data byte count, since it follows
2360 * the parameters; that's where the "2" comes from below.
2362 return (unsigned char *) (afterParmsp + 2);
2365 /* must set all the returned parameters before playing around with the
2366 * data region, since the data region is located past the end of the
2367 * variable number of parameters.
2369 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2371 unsigned char *afterParmsp;
2373 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2375 *afterParmsp++ = dsize & 0xff;
2376 *afterParmsp = (dsize>>8) & 0xff;
2379 /* return the parm'th parameter in the smbp packet */
2380 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2383 unsigned char *parmDatap;
2385 parmCount = *smbp->wctp;
2387 if (parm >= parmCount) {
2390 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2391 parm, parmCount, smbp->ncb_length);
2392 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2393 parm, parmCount, smbp->ncb_length);
2394 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2395 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2396 osi_panic(s, __FILE__, __LINE__);
2398 parmDatap = smbp->wctp + (2*parm) + 1;
2400 return parmDatap[0] + (parmDatap[1] << 8);
2403 /* return the parm'th parameter in the smbp packet */
2404 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2407 unsigned char *parmDatap;
2409 parmCount = *smbp->wctp;
2411 if (parm >= parmCount) {
2414 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2415 parm, parmCount, smbp->ncb_length);
2416 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2417 parm, parmCount, smbp->ncb_length);
2418 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2419 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2420 osi_panic(s, __FILE__, __LINE__);
2422 parmDatap = smbp->wctp + (2*parm) + 1;
2424 return parmDatap[0];
2427 /* return the parm'th parameter in the smbp packet */
2428 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2431 unsigned char *parmDatap;
2433 parmCount = *smbp->wctp;
2435 if (parm + 1 >= parmCount) {
2438 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2439 parm, parmCount, smbp->ncb_length);
2440 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2441 parm, parmCount, smbp->ncb_length);
2442 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2443 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2444 osi_panic(s, __FILE__, __LINE__);
2446 parmDatap = smbp->wctp + (2*parm) + 1;
2448 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2451 /* return the parm'th parameter in the smbp packet */
2452 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2455 unsigned char *parmDatap;
2457 parmCount = *smbp->wctp;
2459 if (parm * 2 + offset >= parmCount * 2) {
2462 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2463 parm, offset, parmCount, smbp->ncb_length);
2464 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2465 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2466 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2467 parm, offset, parmCount, smbp->ncb_length);
2468 osi_panic(s, __FILE__, __LINE__);
2470 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2472 return parmDatap[0] + (parmDatap[1] << 8);
2475 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2477 unsigned char *parmDatap;
2479 /* make sure we have enough slots */
2480 if (*smbp->wctp <= slot)
2481 *smbp->wctp = slot+1;
2483 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2484 *parmDatap++ = parmValue & 0xff;
2485 *parmDatap = (parmValue>>8) & 0xff;
2488 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2490 unsigned char *parmDatap;
2492 /* make sure we have enough slots */
2493 if (*smbp->wctp <= slot)
2494 *smbp->wctp = slot+2;
2496 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2497 *parmDatap++ = parmValue & 0xff;
2498 *parmDatap++ = (parmValue>>8) & 0xff;
2499 *parmDatap++ = (parmValue>>16) & 0xff;
2500 *parmDatap = (parmValue>>24) & 0xff;
2503 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2505 unsigned char *parmDatap;
2508 /* make sure we have enough slots */
2509 if (*smbp->wctp <= slot)
2510 *smbp->wctp = slot+4;
2512 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2514 *parmDatap++ = *parmValuep++;
2517 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2519 unsigned char *parmDatap;
2521 /* make sure we have enough slots */
2522 if (*smbp->wctp <= slot) {
2523 if (smbp->oddByte) {
2525 *smbp->wctp = slot+1;
2530 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2531 *parmDatap++ = parmValue & 0xff;
2536 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2537 clientchar_t *inPathp)
2539 clientchar_t *lastSlashp;
2540 clientchar_t *streamp = NULL;
2541 clientchar_t *typep = NULL;
2543 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2544 if (lastComponentp) {
2545 *lastComponentp = lastSlashp;
2549 * If the name contains a stream name and a type
2550 * and the stream name is the nul-string and the
2551 * type is $DATA, then strip "::$DATA" from the
2552 * last component string that is returned.
2554 * Otherwise, return the full path name and allow
2555 * the file name to be rejected because it contains
2558 typep = cm_ClientStrRChr(lastSlashp, L':');
2559 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2561 streamp = cm_ClientStrRChr(lastSlashp, L':');
2562 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2566 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2567 osi_LogSaveClientString(smb_logp,streamp),
2568 osi_LogSaveClientString(smb_logp,typep));
2572 if (inPathp == lastSlashp)
2574 *outPathp++ = *inPathp++;
2583 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2584 char **chainpp, int flags)
2587 afs_uint32 type = *inp++;
2590 * The first byte specifies the type of the input string.
2591 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2595 /* Length Counted */
2596 case 0x1: /* Data Block */
2597 case 0x5: /* Variable Block */
2598 cb = *inp++ << 16 | *inp++;
2601 /* Null-terminated string */
2602 case 0x4: /* ASCII */
2603 case 0x3: /* Pathname */
2604 case 0x2: /* Dialect */
2605 cb = sizeof(pktp->data) - (inp - pktp->data);
2606 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2607 #ifdef DEBUG_UNICODE
2610 cb = sizeof(pktp->data);
2615 return NULL; /* invalid input */
2619 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2620 flags |= SMB_STRF_FORCEASCII;
2623 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2626 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2627 char ** chainpp, int flags)
2632 if (!WANTS_UNICODE(pktp))
2633 flags |= SMB_STRF_FORCEASCII;
2636 cb = sizeof(pktp->data) - (inp - pktp->data);
2637 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2638 #ifdef DEBUG_UNICODE
2641 cb = sizeof(pktp->data);
2643 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2644 flags | SMB_STRF_SRCNULTERM);
2647 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2648 size_t cb, char ** chainpp, int flags)
2651 if (!WANTS_UNICODE(pktp))
2652 flags |= SMB_STRF_FORCEASCII;
2655 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2658 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2659 size_t cch, char ** chainpp, int flags)
2664 if (!WANTS_UNICODE(pktp))
2665 flags |= SMB_STRF_FORCEASCII;
2667 cb = cch * sizeof(wchar_t);
2670 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2674 smb_ParseStringBuf(const unsigned char * bufbase,
2675 cm_space_t ** stringspp,
2676 unsigned char *inp, size_t *pcb_max,
2677 char **chainpp, int flags)
2680 if (!(flags & SMB_STRF_FORCEASCII)) {
2682 cm_space_t * spacep;
2685 if (bufbase && ((inp - bufbase) % 2) != 0) {
2686 inp++; /* unicode strings are always word aligned */
2690 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2692 cch_src = *pcb_max / sizeof(wchar_t);
2696 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2703 spacep = cm_GetSpace();
2704 spacep->nextp = *stringspp;
2705 *stringspp = spacep;
2709 *chainpp = inp + sizeof(wchar_t);
2712 *(spacep->wdata) = 0;
2713 return spacep->wdata;
2716 StringCchCopyNW(spacep->wdata,
2717 lengthof(spacep->wdata),
2718 (const clientchar_t *) inp, cch_src);
2721 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2723 return spacep->wdata;
2727 cm_space_t * spacep;
2730 /* Not using Unicode */
2732 *chainpp = inp + strlen(inp) + 1;
2735 spacep = cm_GetSpace();
2736 spacep->nextp = *stringspp;
2737 *stringspp = spacep;
2739 cchdest = lengthof(spacep->wdata);
2740 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2741 spacep->wdata, cchdest);
2743 return spacep->wdata;
2749 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2751 size_t * plen, int flags)
2757 /* we are only calculating the required size */
2764 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2766 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2767 if (!(flags & SMB_STRF_IGNORENUL))
2768 *plen += sizeof(wchar_t);
2770 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2780 cch_str = cm_ClientStrLen(str);
2781 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2784 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2792 /* if outp != NULL ... */
2794 /* Number of bytes left in the buffer.
2796 If outp lies inside the packet data buffer, we assume that the
2797 buffer is the packet data buffer. Otherwise we assume that the
2798 buffer is sizeof(packet->data).
2801 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2802 align = (int)((outp - pktp->data) % 2);
2803 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2805 align = (int)(((size_t) outp) % 2);
2806 buffersize = (int)sizeof(pktp->data);
2811 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2817 if (*str == _C('\0')) {
2819 if (buffersize < sizeof(wchar_t))
2822 *((wchar_t *) outp) = L'\0';
2823 if (plen && !(flags & SMB_STRF_IGNORENUL))
2824 *plen += sizeof(wchar_t);
2825 return outp + sizeof(wchar_t);
2828 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2830 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2831 osi_LogSaveClientString(smb_logp, str),
2837 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2839 return outp + sizeof(wchar_t) * nchars;
2847 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2850 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2852 return outp + cch_dest;
2856 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2862 tlen = inp[0] + (inp[1]<<8);
2863 inp += 2; /* skip length field */
2866 *chainpp = inp + tlen;
2875 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2879 if (*inp++ != 0x1) return NULL;
2880 tlen = inp[0] + (inp[1]<<8);
2881 inp += 2; /* skip length field */
2884 *chainpp = inp + tlen;
2887 if (lengthp) *lengthp = tlen;
2892 /* format a packet as a response */
2893 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2898 outp = (smb_t *) op;
2900 /* zero the basic structure through the smb_wct field, and zero the data
2901 * size field, assuming that wct stays zero; otherwise, you have to
2902 * explicitly set the data size field, too.
2904 inSmbp = (smb_t *) inp;
2905 memset(outp, 0, sizeof(smb_t)+2);
2911 outp->com = inSmbp->com;
2912 outp->tid = inSmbp->tid;
2913 outp->pid = inSmbp->pid;
2914 outp->uid = inSmbp->uid;
2915 outp->mid = inSmbp->mid;
2916 outp->res[0] = inSmbp->res[0];
2917 outp->res[1] = inSmbp->res[1];
2918 op->inCom = inSmbp->com;
2920 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2921 #ifdef SEND_CANONICAL_PATHNAMES
2922 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2924 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2926 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2927 outp->flg2 |= SMB_FLAGS2_UNICODE;
2930 /* copy fields in generic packet area */
2931 op->wctp = &outp->wct;
2934 /* send a (probably response) packet; vcp tells us to whom to send it.
2935 * we compute the length by looking at wct and bcc fields.
2937 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2947 ncbp = smb_GetNCB();
2951 memset(ncbp, 0, sizeof(NCB));
2953 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2954 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2955 extra += tp[0] + (tp[1]<<8);
2956 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2957 extra += 3; /* wct and length fields */
2959 ncbp->ncb_length = extra; /* bytes to send */
2960 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2961 ncbp->ncb_lana_num = vcp->lana;
2962 ncbp->ncb_command = NCBSEND; /* op means send data */
2963 ncbp->ncb_buffer = (char *) inp;/* packet */
2964 code = Netbios(ncbp);
2967 const char * s = ncb_error_string(code);
2968 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2969 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2971 lock_ObtainMutex(&vcp->mx);
2972 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2973 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2975 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2976 lock_ReleaseMutex(&vcp->mx);
2977 lock_ObtainWrite(&smb_globalLock);
2978 dead_sessions[vcp->session] = TRUE;
2979 lock_ReleaseWrite(&smb_globalLock);
2980 smb_CleanupDeadVC(vcp);
2982 lock_ReleaseMutex(&vcp->mx);
2990 void smb_MapNTError(long code, unsigned long *NTStatusp)
2992 unsigned long NTStatus;
2994 /* map CM_ERROR_* errors to NT 32-bit status codes */
2995 /* NT Status codes are listed in ntstatus.h not winerror.h */
2999 else if (code == CM_ERROR_NOSUCHCELL) {
3000 NTStatus = 0xC0000034L; /* Name not found */
3002 else if (code == CM_ERROR_NOSUCHVOLUME) {
3003 NTStatus = 0xC0000034L; /* Name not found */
3005 else if (code == CM_ERROR_TIMEDOUT) {
3007 NTStatus = 0xC00000CFL; /* Sharing Paused */
3009 /* Do not send Timeout to the SMB redirector.
3010 * It causes the redirector to drop the connection */
3011 NTStatus = 0x00000102L; /* Timeout */
3012 /* do not send Retry to the SMB redirector.
3013 * It believes the error comes from the transport
3014 * layer not from the SMB server. */
3015 NTStatus = 0xC000022DL; /* Retry */
3017 NTStatus = 0xC00000B5L; /* I/O Timeout */
3020 else if (code == CM_ERROR_RETRY) {
3022 NTStatus = 0xC000022DL; /* Retry */
3024 NTStatus = 0xC00000B5L; /* I/O Timeout */
3027 else if (code == CM_ERROR_NOACCESS) {
3028 NTStatus = 0xC0000022L; /* Access denied */
3030 else if (code == CM_ERROR_READONLY) {
3031 NTStatus = 0xC00000A2L; /* Write protected */
3033 else if (code == CM_ERROR_NOSUCHFILE ||
3034 code == CM_ERROR_BPLUS_NOMATCH) {
3035 NTStatus = 0xC0000034L; /* Name not found */
3037 else if (code == CM_ERROR_NOSUCHPATH) {
3038 NTStatus = 0xC000003AL; /* Object path not found */
3040 else if (code == CM_ERROR_TOOBIG) {
3041 NTStatus = 0xC000007BL; /* Invalid image format */
3043 else if (code == CM_ERROR_INVAL) {
3044 NTStatus = 0xC000000DL; /* Invalid parameter */
3046 else if (code == CM_ERROR_BADFD) {
3047 NTStatus = 0xC0000008L; /* Invalid handle */
3049 else if (code == CM_ERROR_BADFDOP) {
3050 NTStatus = 0xC0000022L; /* Access denied */
3052 else if (code == CM_ERROR_UNKNOWN) {
3053 NTStatus = 0xC0000022L; /* Access denied */
3055 else if (code == CM_ERROR_EXISTS) {
3056 NTStatus = 0xC0000035L; /* Object name collision */
3058 else if (code == CM_ERROR_NOTEMPTY) {
3059 NTStatus = 0xC0000101L; /* Directory not empty */
3061 else if (code == CM_ERROR_CROSSDEVLINK) {
3062 NTStatus = 0xC00000D4L; /* Not same device */
3064 else if (code == CM_ERROR_NOTDIR) {
3065 NTStatus = 0xC0000103L; /* Not a directory */
3067 else if (code == CM_ERROR_ISDIR) {
3068 NTStatus = 0xC00000BAL; /* File is a directory */
3070 else if (code == CM_ERROR_BADOP) {
3072 /* I have no idea where this comes from */
3073 NTStatus = 0xC09820FFL; /* SMB no support */
3075 NTStatus = 0xC00000BBL; /* Not supported */
3076 #endif /* COMMENT */
3078 else if (code == CM_ERROR_BADSHARENAME) {
3079 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3081 else if (code == CM_ERROR_NOIPC) {
3083 NTStatus = 0xC0000022L; /* Access Denied */
3085 NTStatus = 0xC000013DL; /* Remote Resources */
3088 else if (code == CM_ERROR_CLOCKSKEW ||
3089 code == RXKADNOAUTH) {
3090 NTStatus = 0xC0000133L; /* Time difference at DC */
3092 else if (code == CM_ERROR_BADTID) {
3093 NTStatus = 0xC0982005L; /* SMB bad TID */
3095 else if (code == CM_ERROR_USESTD) {
3096 NTStatus = 0xC09820FBL; /* SMB use standard */
3098 else if (code == CM_ERROR_QUOTA) {
3099 NTStatus = 0xC0000044L; /* Quota exceeded */
3101 else if (code == CM_ERROR_SPACE) {
3102 NTStatus = 0xC000007FL; /* Disk full */
3104 else if (code == CM_ERROR_ATSYS) {
3105 NTStatus = 0xC0000033L; /* Object name invalid */
3107 else if (code == CM_ERROR_BADNTFILENAME) {
3108 NTStatus = 0xC0000033L; /* Object name invalid */
3110 else if (code == CM_ERROR_WOULDBLOCK) {
3111 NTStatus = 0xC00000D8L; /* Can't wait */
3113 else if (code == CM_ERROR_SHARING_VIOLATION) {
3114 NTStatus = 0xC0000043L; /* Sharing violation */
3116 else if (code == CM_ERROR_LOCK_CONFLICT) {
3117 NTStatus = 0xC0000054L; /* Lock conflict */
3119 else if (code == CM_ERROR_PARTIALWRITE) {
3120 NTStatus = 0xC000007FL; /* Disk full */
3122 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3123 NTStatus = 0xC0000023L; /* Buffer too small */
3125 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3126 NTStatus = 0xC0000035L; /* Object name collision */
3128 else if (code == CM_ERROR_BADPASSWORD) {
3129 NTStatus = 0xC000006DL; /* unknown username or bad password */
3131 else if (code == CM_ERROR_BADLOGONTYPE) {
3132 NTStatus = 0xC000015BL; /* logon type not granted */
3134 else if (code == CM_ERROR_GSSCONTINUE) {
3135 NTStatus = 0xC0000016L; /* more processing required */
3137 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3139 NTStatus = 0xC0000280L; /* reparse point not resolved */
3141 NTStatus = 0xC0000022L; /* Access Denied */
3144 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3145 NTStatus = 0xC0000257L; /* Path Not Covered */
3147 else if (code == CM_ERROR_ALLBUSY) {
3149 NTStatus = 0xC000022DL; /* Retry */
3151 NTStatus = 0xC00000B5L; /* I/O Timeout */
3154 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3155 NTStatus = 0xC000003AL; /* Path not found */
3157 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3158 NTStatus = 0xC0000322L; /* No Kerberos key */
3160 else if (code == CM_ERROR_BAD_LEVEL) {
3161 NTStatus = 0xC0000148L; /* Invalid Level */
3163 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3164 NTStatus = 0xC000007EL; /* Range Not Locked */
3166 else if (code == CM_ERROR_NOSUCHDEVICE) {
3167 NTStatus = 0xC000000EL; /* No Such Device */
3169 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3170 NTStatus = 0xC0000055L; /* Lock Not Granted */
3172 else if (code == ENOMEM) {
3173 NTStatus = 0xC0000017L; /* Out of Memory */
3175 else if (code == CM_ERROR_RPC_MOREDATA) {
3176 NTStatus = 0x80000005L; /* Buffer overflow */
3179 NTStatus = 0xC0982001L; /* SMB non-specific error */
3182 *NTStatusp = NTStatus;
3183 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3187 * NTSTATUS <-> Win32 Error Translation
3188 * http://support.microsoft.com/kb/113996
3190 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3192 unsigned long Win32E;
3194 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3198 else if (code == CM_ERROR_NOSUCHCELL) {
3199 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3201 else if (code == CM_ERROR_NOSUCHVOLUME) {
3202 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3204 else if (code == CM_ERROR_TIMEDOUT) {
3206 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3208 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3211 else if (code == CM_ERROR_RETRY) {
3212 Win32E = ERROR_RETRY; /* Retry */
3214 else if (code == CM_ERROR_NOACCESS) {
3215 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3217 else if (code == CM_ERROR_READONLY) {
3218 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3220 else if (code == CM_ERROR_NOSUCHFILE ||
3221 code == CM_ERROR_BPLUS_NOMATCH) {
3222 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3224 else if (code == CM_ERROR_NOSUCHPATH) {
3225 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3227 else if (code == CM_ERROR_TOOBIG) {
3228 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3230 else if (code == CM_ERROR_INVAL) {
3231 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3233 else if (code == CM_ERROR_BADFD) {
3234 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3236 else if (code == CM_ERROR_BADFDOP) {
3237 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3239 else if (code == CM_ERROR_UNKNOWN) {
3240 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3242 else if (code == CM_ERROR_EXISTS) {
3243 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3245 else if (code == CM_ERROR_NOTEMPTY) {
3246 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3248 else if (code == CM_ERROR_CROSSDEVLINK) {
3249 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3251 else if (code == CM_ERROR_NOTDIR) {
3252 Win32E = ERROR_DIRECTORY; /* Not a directory */
3254 else if (code == CM_ERROR_ISDIR) {
3255 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3257 else if (code == CM_ERROR_BADOP) {
3258 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3260 else if (code == CM_ERROR_BADSHARENAME) {
3261 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3263 else if (code == CM_ERROR_NOIPC) {
3265 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3267 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3270 else if (code == CM_ERROR_CLOCKSKEW ||
3271 code == RXKADNOAUTH) {
3272 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3274 else if (code == CM_ERROR_BADTID) {
3275 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3277 else if (code == CM_ERROR_USESTD) {
3278 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3280 else if (code == CM_ERROR_QUOTA) {
3281 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3283 else if (code == CM_ERROR_SPACE) {
3284 Win32E = ERROR_DISK_FULL; /* Disk full */
3286 else if (code == CM_ERROR_ATSYS) {
3287 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3289 else if (code == CM_ERROR_BADNTFILENAME) {
3290 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3292 else if (code == CM_ERROR_WOULDBLOCK) {
3293 Win32E = WAIT_TIMEOUT; /* Can't wait */
3295 else if (code == CM_ERROR_SHARING_VIOLATION) {
3296 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3298 else if (code == CM_ERROR_LOCK_CONFLICT) {
3299 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3301 else if (code == CM_ERROR_PARTIALWRITE) {
3302 Win32E = ERROR_DISK_FULL; /* Disk full */
3304 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3305 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3307 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3308 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3310 else if (code == CM_ERROR_BADPASSWORD) {
3311 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3313 else if (code == CM_ERROR_BADLOGONTYPE) {
3314 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3316 else if (code == CM_ERROR_GSSCONTINUE) {
3317 Win32E = ERROR_MORE_DATA; /* more processing required */
3319 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3321 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3323 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3326 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3327 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3329 else if (code == CM_ERROR_ALLBUSY) {
3330 Win32E = ERROR_RETRY; /* Retry */
3332 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3333 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3335 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3336 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3338 else if (code == CM_ERROR_BAD_LEVEL) {
3339 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3341 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3342 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3344 else if (code == CM_ERROR_NOSUCHDEVICE) {
3345 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3347 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3348 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3350 else if (code == ENOMEM) {
3351 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3353 else if (code == CM_ERROR_RPC_MOREDATA) {
3354 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3357 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3361 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3364 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3365 unsigned char *classp)
3367 unsigned char class;
3368 unsigned short error;
3370 /* map CM_ERROR_* errors to SMB errors */
3371 if (code == CM_ERROR_NOSUCHCELL) {
3373 error = 3; /* bad path */
3375 else if (code == CM_ERROR_NOSUCHVOLUME) {
3377 error = 3; /* bad path */
3379 else if (code == CM_ERROR_TIMEDOUT) {
3381 error = 81; /* server is paused */
3383 else if (code == CM_ERROR_RETRY) {
3384 class = 2; /* shouldn't happen */
3387 else if (code == CM_ERROR_NOACCESS) {
3389 error = 4; /* bad access */
3391 else if (code == CM_ERROR_READONLY) {
3393 error = 19; /* read only */
3395 else if (code == CM_ERROR_NOSUCHFILE ||
3396 code == CM_ERROR_BPLUS_NOMATCH) {
3398 error = 2; /* ENOENT! */
3400 else if (code == CM_ERROR_NOSUCHPATH) {
3402 error = 3; /* Bad path */
3404 else if (code == CM_ERROR_TOOBIG) {
3406 error = 11; /* bad format */
3408 else if (code == CM_ERROR_INVAL) {
3409 class = 2; /* server non-specific error code */
3412 else if (code == CM_ERROR_BADFD) {
3414 error = 6; /* invalid file handle */
3416 else if (code == CM_ERROR_BADFDOP) {
3417 class = 1; /* invalid op on FD */
3420 else if (code == CM_ERROR_EXISTS) {
3422 error = 80; /* file already exists */
3424 else if (code == CM_ERROR_NOTEMPTY) {
3426 error = 5; /* delete directory not empty */
3428 else if (code == CM_ERROR_CROSSDEVLINK) {
3430 error = 17; /* EXDEV */
3432 else if (code == CM_ERROR_NOTDIR) {
3433 class = 1; /* bad path */
3436 else if (code == CM_ERROR_ISDIR) {
3437 class = 1; /* access denied; DOS doesn't have a good match */
3440 else if (code == CM_ERROR_BADOP) {
3444 else if (code == CM_ERROR_BADSHARENAME) {
3448 else if (code == CM_ERROR_NOIPC) {
3450 error = 4; /* bad access */
3452 else if (code == CM_ERROR_CLOCKSKEW) {
3453 class = 1; /* invalid function */
3456 else if (code == CM_ERROR_BADTID) {
3460 else if (code == CM_ERROR_USESTD) {
3464 else if (code == CM_ERROR_REMOTECONN) {
3468 else if (code == CM_ERROR_QUOTA) {
3469 if (vcp->flags & SMB_VCFLAG_USEV3) {
3471 error = 39; /* disk full */
3475 error = 5; /* access denied */
3478 else if (code == CM_ERROR_SPACE) {
3479 if (vcp->flags & SMB_VCFLAG_USEV3) {
3481 error = 39; /* disk full */
3485 error = 5; /* access denied */
3488 else if (code == CM_ERROR_PARTIALWRITE) {
3490 error = 39; /* disk full */
3492 else if (code == CM_ERROR_ATSYS) {
3494 error = 2; /* ENOENT */
3496 else if (code == CM_ERROR_WOULDBLOCK) {
3498 error = 33; /* lock conflict */
3500 else if (code == CM_ERROR_LOCK_CONFLICT) {
3502 error = 33; /* lock conflict */
3504 else if (code == CM_ERROR_SHARING_VIOLATION) {
3506 error = 33; /* lock conflict */
3508 else if (code == CM_ERROR_NOFILES) {
3510 error = 18; /* no files in search */
3512 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3514 error = 183; /* Samba uses this */
3516 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3517 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3519 error = 2; /* bad password */
3521 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3523 error = 3; /* bad path */
3532 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3535 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3537 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3538 return CM_ERROR_BADOP;
3542 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3544 unsigned short EchoCount, i;
3545 char *data, *outdata;
3548 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3550 for (i=1; i<=EchoCount; i++) {
3551 data = smb_GetSMBData(inp, &dataSize);
3552 smb_SetSMBParm(outp, 0, i);
3553 smb_SetSMBDataLength(outp, dataSize);
3554 outdata = smb_GetSMBData(outp, NULL);
3555 memcpy(outdata, data, dataSize);
3556 smb_SendPacket(vcp, outp);
3562 /* SMB_COM_READ_RAW */
3563 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3566 long count, minCount, finalCount;
3570 smb_t *smbp = (smb_t*) inp;
3572 cm_user_t *userp = NULL;
3575 char *rawBuf = NULL;
3580 fd = smb_GetSMBParm(inp, 0);
3581 count = smb_GetSMBParm(inp, 3);
3582 minCount = smb_GetSMBParm(inp, 4);
3583 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3585 if (*inp->wctp == 10) {
3586 /* we were sent a request with 64-bit file offsets */
3587 #ifdef AFS_LARGEFILES
3588 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3590 if (LargeIntegerLessThanZero(offset)) {
3591 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3595 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3596 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3599 offset.HighPart = 0;
3603 /* we were sent a request with 32-bit file offsets */
3604 offset.HighPart = 0;
3607 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3608 fd, offset.HighPart, offset.LowPart, count);
3610 fidp = smb_FindFID(vcp, fd, 0);
3612 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3616 lock_ObtainMutex(&fidp->mx);
3618 lock_ReleaseMutex(&fidp->mx);
3619 smb_ReleaseFID(fidp);
3620 return CM_ERROR_BADFD;
3623 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3624 lock_ReleaseMutex(&fidp->mx);
3625 smb_CloseFID(vcp, fidp, NULL, 0);
3626 code = CM_ERROR_NOSUCHFILE;
3632 LARGE_INTEGER LOffset, LLength;
3635 key = cm_GenerateKey(vcp->vcID, pid, fd);
3637 LOffset.HighPart = offset.HighPart;
3638 LOffset.LowPart = offset.LowPart;
3639 LLength.HighPart = 0;
3640 LLength.LowPart = count;
3642 lock_ObtainWrite(&fidp->scp->rw);
3643 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3644 lock_ReleaseWrite(&fidp->scp->rw);
3647 lock_ReleaseMutex(&fidp->mx);
3651 lock_ObtainMutex(&smb_RawBufLock);
3653 /* Get a raw buf, from head of list */
3654 rawBuf = smb_RawBufs;
3655 smb_RawBufs = *(char **)smb_RawBufs;
3657 lock_ReleaseMutex(&smb_RawBufLock);
3659 lock_ReleaseMutex(&fidp->mx);
3663 if (fidp->flags & SMB_FID_IOCTL)
3665 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3667 /* Give back raw buffer */
3668 lock_ObtainMutex(&smb_RawBufLock);
3669 *((char **) rawBuf) = smb_RawBufs;
3671 smb_RawBufs = rawBuf;
3672 lock_ReleaseMutex(&smb_RawBufLock);
3675 lock_ReleaseMutex(&fidp->mx);
3676 smb_ReleaseFID(fidp);
3679 lock_ReleaseMutex(&fidp->mx);
3681 userp = smb_GetUserFromVCP(vcp, inp);
3683 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3689 cm_ReleaseUser(userp);
3692 smb_ReleaseFID(fidp);
3696 memset(ncbp, 0, sizeof(NCB));
3698 ncbp->ncb_length = (unsigned short) finalCount;
3699 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3700 ncbp->ncb_lana_num = vcp->lana;
3701 ncbp->ncb_command = NCBSEND;
3702 ncbp->ncb_buffer = rawBuf;
3704 code = Netbios(ncbp);
3706 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3709 /* Give back raw buffer */
3710 lock_ObtainMutex(&smb_RawBufLock);
3711 *((char **) rawBuf) = smb_RawBufs;
3713 smb_RawBufs = rawBuf;
3714 lock_ReleaseMutex(&smb_RawBufLock);
3720 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3722 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3727 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3729 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3734 /* SMB_COM_NEGOTIATE */
3735 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3742 int VistaProtoIndex;
3743 int protoIndex; /* index we're using */
3748 char protocol_array[10][1024]; /* protocol signature of the client */
3749 int caps; /* capabilities */
3752 TIME_ZONE_INFORMATION tzi;
3754 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3757 namep = smb_GetSMBData(inp, &dbytes);
3760 coreProtoIndex = -1; /* not found */
3763 VistaProtoIndex = -1;
3764 while(namex < dbytes) {
3765 osi_Log1(smb_logp, "Protocol %s",
3766 osi_LogSaveString(smb_logp, namep+1));
3767 strcpy(protocol_array[tcounter], namep+1);
3769 /* namep points at the first protocol, or really, a 0x02
3770 * byte preceding the null-terminated ASCII name.
3772 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3773 coreProtoIndex = tcounter;
3775 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3776 v3ProtoIndex = tcounter;
3778 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3779 NTProtoIndex = tcounter;
3781 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3782 VistaProtoIndex = tcounter;
3785 /* compute size of protocol entry */
3786 entryLength = (int)strlen(namep+1);
3787 entryLength += 2; /* 0x02 bytes and null termination */
3789 /* advance over this protocol entry */
3790 namex += entryLength;
3791 namep += entryLength;
3792 tcounter++; /* which proto entry we're looking at */
3795 lock_ObtainMutex(&vcp->mx);
3797 if (VistaProtoIndex != -1) {
3798 protoIndex = VistaProtoIndex;
3799 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3802 if (NTProtoIndex != -1) {
3803 protoIndex = NTProtoIndex;
3804 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3806 else if (v3ProtoIndex != -1) {
3807 protoIndex = v3ProtoIndex;
3808 vcp->flags |= SMB_VCFLAG_USEV3;
3810 else if (coreProtoIndex != -1) {
3811 protoIndex = coreProtoIndex;
3812 vcp->flags |= SMB_VCFLAG_USECORE;
3814 else protoIndex = -1;
3815 lock_ReleaseMutex(&vcp->mx);
3817 if (protoIndex == -1)
3818 return CM_ERROR_INVAL;
3819 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3820 smb_SetSMBParm(outp, 0, protoIndex);
3821 if (smb_authType != SMB_AUTH_NONE) {
3822 smb_SetSMBParmByte(outp, 1,
3823 NEGOTIATE_SECURITY_USER_LEVEL |
3824 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3826 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3828 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3829 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3830 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3831 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3832 /* The session key is not a well documented field however most clients
3833 * will echo back the session key to the server. Currently we are using
3834 * the same value for all sessions. We should generate a random value
3835 * and store it into the vcp
3837 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3838 smb_SetSMBParm(outp, 8, 1);
3840 * Tried changing the capabilities to support for W2K - defect 117695
3841 * Maybe something else needs to be changed here?
3845 smb_SetSMBParmLong(outp, 9, 0x43fd);
3847 smb_SetSMBParmLong(outp, 9, 0x251);
3850 * 32-bit error codes *
3856 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3858 NTNEGOTIATE_CAPABILITY_DFS |
3860 #ifdef AFS_LARGEFILES
3861 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3863 NTNEGOTIATE_CAPABILITY_NTFIND |
3864 NTNEGOTIATE_CAPABILITY_RAWMODE |
3865 NTNEGOTIATE_CAPABILITY_NTSMB;
3867 if ( smb_authType == SMB_AUTH_EXTENDED )
3868 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3871 if ( smb_UseUnicode ) {
3872 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3876 smb_SetSMBParmLong(outp, 9, caps);
3878 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3879 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3880 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3882 GetTimeZoneInformation(&tzi);
3883 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3885 if (smb_authType == SMB_AUTH_NTLM) {
3886 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3887 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3888 /* paste in encryption key */
3889 datap = smb_GetSMBData(outp, NULL);
3890 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3891 /* and the faux domain name */
3892 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3893 datap + MSV1_0_CHALLENGE_LENGTH,
3894 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3895 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3899 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3901 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3903 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3905 datap = smb_GetSMBData(outp, NULL);
3906 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3909 datap += sizeof(smb_ServerGUID);
3910 memcpy(datap, secBlob, secBlobLength);
3914 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3915 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3918 else if (v3ProtoIndex != -1) {
3919 smb_SetSMBParm(outp, 0, protoIndex);
3921 /* NOTE: Extended authentication cannot be negotiated with v3
3922 * therefore we fail over to NTLM
3924 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3925 smb_SetSMBParm(outp, 1,
3926 NEGOTIATE_SECURITY_USER_LEVEL |
3927 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3929 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3931 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3932 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3933 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3934 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3935 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3936 smb_SetSMBParm(outp, 7, 1);
3938 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3939 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3940 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3942 GetTimeZoneInformation(&tzi);
3943 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3945 /* NOTE: Extended authentication cannot be negotiated with v3
3946 * therefore we fail over to NTLM
3948 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3949 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3950 smb_SetSMBParm(outp, 12, 0); /* resvd */
3951 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3952 datap = smb_GetSMBData(outp, NULL);
3953 /* paste in a new encryption key */
3954 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3955 /* and the faux domain name */
3956 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3957 datap + MSV1_0_CHALLENGE_LENGTH,
3958 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3960 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3961 smb_SetSMBParm(outp, 12, 0); /* resvd */
3962 smb_SetSMBDataLength(outp, 0);
3965 else if (coreProtoIndex != -1) { /* not really supported anymore */
3966 smb_SetSMBParm(outp, 0, protoIndex);
3967 smb_SetSMBDataLength(outp, 0);
3972 void smb_CheckVCs(void)
3974 smb_vc_t * vcp, *nextp;
3975 smb_packet_t * outp = smb_GetPacket();
3978 lock_ObtainWrite(&smb_rctLock);
3979 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3981 if (vcp->magic != SMB_VC_MAGIC)
3982 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3983 __FILE__, __LINE__);
3985 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3987 smb_HoldVCNoLock(vcp);
3990 * obtain a reference to 'nextp' now because we drop the
3991 * smb_rctLock later and the list contents could change
3992 * or 'vcp' could be destroyed when released.
3996 smb_HoldVCNoLock(nextp);
3998 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3999 smb_ReleaseVCNoLock(vcp);
4003 smb_FormatResponsePacket(vcp, NULL, outp);
4004 smbp = (smb_t *)outp;
4005 outp->inCom = smbp->com = 0x2b /* Echo */;
4013 smb_SetSMBParm(outp, 0, 0);
4014 smb_SetSMBDataLength(outp, 0);
4015 lock_ReleaseWrite(&smb_rctLock);
4017 smb_SendPacket(vcp, outp);
4019 lock_ObtainWrite(&smb_rctLock);
4020 smb_ReleaseVCNoLock(vcp);
4022 lock_ReleaseWrite(&smb_rctLock);
4023 smb_FreePacket(outp);
4026 void smb_Daemon(void *parmp)
4028 afs_uint32 count = 0;
4029 smb_username_t **unpp;
4032 while(smbShutdownFlag == 0) {
4036 if (smbShutdownFlag == 1)
4039 if ((count % 72) == 0) { /* every five minutes */
4041 time_t old_localZero = smb_localZero;
4043 /* Initialize smb_localZero */
4044 myTime.tm_isdst = -1; /* compute whether on DST or not */
4045 myTime.tm_year = 70;
4051 smb_localZero = mktime(&myTime);
4053 #ifdef AFS_FREELANCE
4054 if ( smb_localZero != old_localZero )
4055 cm_noteLocalMountPointChange();
4061 /* GC smb_username_t objects that will no longer be used */
4063 lock_ObtainWrite(&smb_rctLock);
4064 for ( unpp=&usernamesp; *unpp; ) {
4066 smb_username_t *unp;
4068 lock_ObtainMutex(&(*unpp)->mx);
4069 if ( (*unpp)->refCount > 0 ||
4070 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4071 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4073 else if (!smb_LogoffTokenTransfer ||
4074 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4076 lock_ReleaseMutex(&(*unpp)->mx);
4084 lock_FinalizeMutex(&unp->mx);
4090 cm_ReleaseUser(userp);
4092 unpp = &(*unpp)->nextp;
4095 lock_ReleaseWrite(&smb_rctLock);
4097 /* XXX GC dir search entries */
4101 void smb_WaitingLocksDaemon()
4103 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4104 smb_waitingLock_t *wl, *wlNext;
4107 smb_packet_t *inp, *outp;
4111 while (smbShutdownFlag == 0) {
4112 lock_ObtainWrite(&smb_globalLock);
4113 nwlRequest = smb_allWaitingLocks;
4114 if (nwlRequest == NULL) {
4115 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4120 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4127 lock_ObtainWrite(&smb_globalLock);
4129 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4131 wlRequest = nwlRequest;
4132 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4133 lock_ReleaseWrite(&smb_globalLock);
4137 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4138 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4141 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4142 code = CM_ERROR_LOCK_NOT_GRANTED;
4146 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4148 /* wl->state is either _DONE or _WAITING. _ERROR
4149 would no longer be on the queue. */
4150 code = cm_RetryLock( wl->lockp,
4151 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4154 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4155 } else if (code != CM_ERROR_WOULDBLOCK) {
4156 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4161 if (code == CM_ERROR_WOULDBLOCK) {
4164 if (wlRequest->msTimeout != 0xffffffff
4165 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4177 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4180 scp = wlRequest->scp;
4181 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4185 lock_ObtainWrite(&scp->rw);
4187 for (wl = wlRequest->locks; wl; wl = wlNext) {
4188 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4190 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4191 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4192 wl->LLength, wl->key, 0, NULL, &req);
4194 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4199 lock_ReleaseWrite(&scp->rw);
4203 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4206 for (wl = wlRequest->locks; wl; wl = wlNext) {
4207 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4208 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4213 vcp = wlRequest->vcp;
4214 inp = wlRequest->inp;
4215 outp = wlRequest->outp;
4216 ncbp = smb_GetNCB();
4217 ncbp->ncb_length = inp->ncb_length;
4218 inp->spacep = cm_GetSpace();
4220 /* Remove waitingLock from list */
4221 lock_ObtainWrite(&smb_globalLock);
4222 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4224 lock_ReleaseWrite(&smb_globalLock);
4226 /* Resume packet processing */
4228 smb_SetSMBDataLength(outp, 0);
4229 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4230 outp->resumeCode = code;
4232 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4235 cm_FreeSpace(inp->spacep);
4236 smb_FreePacket(inp);
4237 smb_FreePacket(outp);
4239 cm_ReleaseSCache(wlRequest->scp);
4242 } while (nwlRequest && smbShutdownFlag == 0);
4247 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4249 osi_Log0(smb_logp, "SMB receive get disk attributes");
4251 smb_SetSMBParm(outp, 0, 32000);
4252 smb_SetSMBParm(outp, 1, 64);
4253 smb_SetSMBParm(outp, 2, 1024);
4254 smb_SetSMBParm(outp, 3, 30000);
4255 smb_SetSMBParm(outp, 4, 0);
4256 smb_SetSMBDataLength(outp, 0);
4260 /* SMB_COM_TREE_CONNECT */
4261 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4265 unsigned short newTid;
4266 clientchar_t shareName[AFSPATHMAX];
4267 clientchar_t *sharePath;
4270 clientchar_t *pathp;
4273 osi_Log0(smb_logp, "SMB receive tree connect");
4275 /* parse input parameters */
4278 tbp = smb_GetSMBData(inp, NULL);
4279 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4281 return CM_ERROR_BADSMB;
4283 tp = cm_ClientStrRChr(pathp, '\\');
4285 return CM_ERROR_BADSMB;
4286 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4288 lock_ObtainMutex(&vcp->mx);
4289 newTid = vcp->tidCounter++;
4290 lock_ReleaseMutex(&vcp->mx);
4292 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4293 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4295 return CM_ERROR_BADSMB;
4296 userp = smb_GetUserFromUID(uidp);
4297 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4298 smb_ReleaseUID(uidp);
4300 smb_ReleaseTID(tidp, FALSE);
4301 return CM_ERROR_BADSHARENAME;
4303 lock_ObtainMutex(&tidp->mx);
4304 tidp->userp = userp;
4305 tidp->pathname = sharePath;
4306 lock_ReleaseMutex(&tidp->mx);
4307 smb_ReleaseTID(tidp, FALSE);
4309 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4310 smb_SetSMBParm(rsp, 1, newTid);
4311 smb_SetSMBDataLength(rsp, 0);
4313 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4317 /* set maskp to the mask part of the incoming path.
4318 * Mask is 11 bytes long (8.3 with the dot elided).
4319 * Returns true if succeeds with a valid name, otherwise it does
4320 * its best, but returns false.
4322 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4330 /* starts off valid */
4333 /* mask starts out all blanks */
4334 memset(maskp, ' ', 11);
4337 /* find last backslash, or use whole thing if there is none */
4338 tp = cm_ClientStrRChr(pathp, '\\');
4342 tp++; /* skip slash */
4346 /* names starting with a dot are illegal */
4354 if (tc == '.' || tc == '"')
4362 /* if we get here, tp point after the dot */
4363 up = maskp+8; /* ext goes here */
4370 if (tc == '.' || tc == '"')
4373 /* copy extension if not too long */
4383 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4385 clientchar_t umask[11];
4393 /* XXX redo this, calling cm_MatchMask with a converted mask */
4395 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4399 /* otherwise, we have a valid 8.3 name; see if we have a match,
4400 * treating '?' as a wildcard in maskp (but not in the file name).
4402 tp1 = umask; /* real name, in mask format */
4403 tp2 = maskp; /* mask, in mask format */
4404 for(i=0; i<11; i++) {
4405 tc1 = *tp1++; /* clientchar_t from real name */
4406 tc2 = *tp2++; /* clientchar_t from mask */
4407 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4408 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4411 if (tc2 == '?' && tc1 != ' ')
4418 /* we got a match */
4422 clientchar_t *smb_FindMask(clientchar_t *pathp)
4426 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4429 return tp+1; /* skip the slash */
4431 return pathp; /* no slash, return the entire path */
4434 /* SMB_COM_SEARCH for a volume label
4436 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4437 dispatch function.) */
4438 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4440 clientchar_t *pathp;
4442 clientchar_t mask[12];
4443 unsigned char *statBlockp;
4444 unsigned char initStatBlock[21];
4447 osi_Log0(smb_logp, "SMB receive search volume");
4449 /* pull pathname and stat block out of request */
4450 tp = smb_GetSMBData(inp, NULL);
4451 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4452 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4454 return CM_ERROR_BADSMB;
4455 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4456 osi_assertx(statBlockp != NULL, "null statBlock");
4458 statBlockp = initStatBlock;
4462 /* for returning to caller */
4463 smb_Get8Dot3MaskFromPath(mask, pathp);
4465 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4466 tp = smb_GetSMBData(outp, NULL);
4468 *tp++ = 43; /* bytes in a dir entry */
4469 *tp++ = 0; /* high byte in counter */
4471 /* now marshall the dir entry, starting with the search status */
4472 *tp++ = statBlockp[0]; /* Reserved */
4473 memcpy(tp, mask, 11); tp += 11; /* FileName */
4475 /* now pass back server use info, with 1st byte non-zero */
4477 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4479 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4481 *tp++ = 0x8; /* attribute: volume */
4491 /* 4 byte file size */
4497 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4500 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4501 memset(tp, ' ', 13);
4504 /* set the length of the data part of the packet to 43 + 3, for the dir
4505 * entry plus the 5 and the length fields.
4507 smb_SetSMBDataLength(outp, 46);
4512 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4513 clientchar_t * tidPathp, clientchar_t * relPathp,
4514 cm_user_t *userp, cm_req_t *reqp)
4522 smb_dirListPatch_t *patchp;
4523 smb_dirListPatch_t *npatchp;
4524 clientchar_t path[AFSPATHMAX];
4526 afs_int32 mustFake = 0;
4528 code = cm_FindACLCache(dscp, userp, &rights);
4530 lock_ObtainWrite(&dscp->rw);
4531 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4532 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4533 lock_ReleaseWrite(&dscp->rw);
4534 if (code == CM_ERROR_NOACCESS) {
4542 if (!mustFake) { /* Bulk Stat */
4544 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4546 memset(bsp, 0, sizeof(cm_bulkStat_t));
4548 for (patchp = *dirPatchespp, count=0;
4550 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4551 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4555 if (lock_TryWrite(&tscp->rw)) {
4556 /* we have an entry that we can look at */
4557 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4558 /* we have a callback on it. Don't bother
4559 * fetching this stat entry, since we're happy
4560 * with the info we have.
4562 lock_ReleaseWrite(&tscp->rw);
4563 cm_ReleaseSCache(tscp);
4566 lock_ReleaseWrite(&tscp->rw);
4568 cm_ReleaseSCache(tscp);
4572 bsp->fids[i].Volume = patchp->fid.volume;
4573 bsp->fids[i].Vnode = patchp->fid.vnode;
4574 bsp->fids[i].Unique = patchp->fid.unique;
4576 if (bsp->counter == AFSCBMAX) {
4577 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4578 memset(bsp, 0, sizeof(cm_bulkStat_t));
4582 if (bsp->counter > 0)
4583 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4588 for (patchp = *dirPatchespp; patchp; patchp =
4589 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4591 dptr = patchp->dptr;
4593 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4594 relPathp ? relPathp : _C(""), patchp->dep->name);
4595 reqp->relPathp = path;
4596 reqp->tidPathp = tidPathp;
4598 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4599 reqp->relPathp = reqp->tidPathp = NULL;
4602 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4603 *dptr++ = SMB_ATTR_HIDDEN;
4606 lock_ObtainWrite(&scp->rw);
4607 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4608 lock_ReleaseWrite(&scp->rw);
4610 /* set the attribute */
4611 switch (scp->fileType) {
4612 case CM_SCACHETYPE_DIRECTORY:
4613 case CM_SCACHETYPE_MOUNTPOINT:
4614 case CM_SCACHETYPE_INVALID:
4615 attr = SMB_ATTR_DIRECTORY;
4617 case CM_SCACHETYPE_SYMLINK:
4618 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4619 attr = SMB_ATTR_DIRECTORY;
4621 attr = SMB_ATTR_NORMAL;
4624 /* if we get here we either have a normal file
4625 * or we have a file for which we have never
4626 * received status info. In this case, we can
4627 * check the even/odd value of the entry's vnode.
4628 * odd means it is to be treated as a directory
4629 * and even means it is to be treated as a file.
4631 if (mustFake && (scp->fid.vnode & 0x1))
4632 attr = SMB_ATTR_DIRECTORY;
4634 attr = SMB_ATTR_NORMAL;
4638 /* 1969-12-31 23:59:58 +00*/
4639 dosTime = 0xEBBFBF7D;
4642 shortTemp = (unsigned short) (dosTime & 0xffff);
4643 *((u_short *)dptr) = shortTemp;
4646 /* and copy out date */
4647 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4648 *((u_short *)dptr) = shortTemp;
4651 /* copy out file length */
4652 *((u_long *)dptr) = 0;
4655 lock_ConvertWToR(&scp->rw);
4656 attr = smb_Attributes(scp);
4657 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4658 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4659 attr |= SMB_ATTR_HIDDEN;
4663 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4666 shortTemp = (unsigned short) (dosTime & 0xffff);
4667 *((u_short *)dptr) = shortTemp;
4670 /* and copy out date */
4671 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4672 *((u_short *)dptr) = shortTemp;
4675 /* copy out file length */
4676 *((u_long *)dptr) = scp->length.LowPart;
4678 lock_ReleaseRead(&scp->rw);
4680 cm_ReleaseSCache(scp);
4683 /* now free the patches */
4684 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4685 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4689 /* and mark the list as empty */
4690 *dirPatchespp = NULL;
4696 /* SMB_COM_SEARCH */
4697 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4703 clientchar_t *pathp;
4704 cm_dirEntry_t *dep = 0;
4706 smb_dirListPatch_t *dirListPatchesp;
4707 smb_dirListPatch_t *curPatchp;
4711 osi_hyper_t dirLength;
4712 osi_hyper_t bufferOffset;
4713 osi_hyper_t curOffset;
4715 unsigned char *inCookiep;
4716 smb_dirSearch_t *dsp;
4720 unsigned long clientCookie;
4721 cm_pageHeader_t *pageHeaderp;
4722 cm_user_t *userp = NULL;
4724 clientchar_t mask[12];
4726 long nextEntryCookie;
4727 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4728 char resByte; /* reserved byte from the cookie */
4729 char *op; /* output data ptr */
4730 char *origOp; /* original value of op */
4731 cm_space_t *spacep; /* for pathname buffer */
4735 clientchar_t *tidPathp = 0;
4742 maxCount = smb_GetSMBParm(inp, 0);
4744 dirListPatchesp = NULL;
4746 caseFold = CM_FLAG_CASEFOLD;
4748 tp = smb_GetSMBData(inp, NULL);
4749 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4750 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4752 return CM_ERROR_BADSMB;
4754 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4756 return CM_ERROR_BADSMB;
4758 /* We can handle long names */
4759 if (vcp->flags & SMB_VCFLAG_USENT)
4760 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4762 /* make sure we got a whole search status */
4763 if (dataLength < 21) {
4764 nextCookie = 0; /* start at the beginning of the dir */
4767 attribute = smb_GetSMBParm(inp, 1);
4769 /* handle volume info in another function */
4770 if (attribute & 0x8)
4771 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4773 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4774 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4776 if (*pathp == 0) { /* null pathp, treat as root dir */
4777 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4778 return CM_ERROR_NOFILES;
4782 dsp = smb_NewDirSearch(0);
4783 dsp->attribute = attribute;
4784 smb_Get8Dot3MaskFromPath(mask, pathp);
4785 memcpy(dsp->mask, mask, 12);
4787 /* track if this is likely to match a lot of entries */
4788 if (smb_Is8Dot3StarMask(mask))
4793 /* pull the next cookie value out of the search status block */
4794 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4795 + (inCookiep[16]<<24);
4796 dsp = smb_FindDirSearch(inCookiep[12]);
4798 /* can't find dir search status; fatal error */
4799 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4800 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4801 return CM_ERROR_BADFD;
4803 attribute = dsp->attribute;
4804 resByte = inCookiep[0];
4806 /* copy out client cookie, in host byte order. Don't bother
4807 * interpreting it, since we're just passing it through, anyway.
4809 memcpy(&clientCookie, &inCookiep[17], 4);
4811 memcpy(mask, dsp->mask, 12);
4813 /* assume we're doing a star match if it has continued for more
4819 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4820 nextCookie, dsp->cookie, attribute);
4822 userp = smb_GetUserFromVCP(vcp, inp);
4824 /* try to get the vnode for the path name next */
4825 lock_ObtainMutex(&dsp->mx);
4828 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4832 spacep = inp->spacep;
4833 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4834 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4836 lock_ReleaseMutex(&dsp->mx);
4837 cm_ReleaseUser(userp);
4838 smb_DeleteDirSearch(dsp);
4839 smb_ReleaseDirSearch(dsp);
4840 return CM_ERROR_NOFILES;
4842 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4843 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4845 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4846 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4849 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4852 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4853 cm_ReleaseSCache(scp);
4854 lock_ReleaseMutex(&dsp->mx);
4855 cm_ReleaseUser(userp);
4856 smb_DeleteDirSearch(dsp);
4857 smb_ReleaseDirSearch(dsp);
4858 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4859 return CM_ERROR_PATH_NOT_COVERED;
4861 return CM_ERROR_NOSUCHPATH;
4863 #endif /* DFS_SUPPORT */
4866 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4867 /* we need one hold for the entry we just stored into,
4868 * and one for our own processing. When we're done with this
4869 * function, we'll drop the one for our own processing.
4870 * We held it once from the namei call, and so we do another hold
4874 lock_ObtainWrite(&scp->rw);
4875 dsp->flags |= SMB_DIRSEARCH_BULKST;
4876 lock_ReleaseWrite(&scp->rw);
4879 lock_ReleaseMutex(&dsp->mx);
4881 cm_ReleaseUser(userp);
4882 smb_DeleteDirSearch(dsp);
4883 smb_ReleaseDirSearch(dsp);
4887 /* reserves space for parameter; we'll adjust it again later to the
4888 * real count of the # of entries we returned once we've actually
4889 * assembled the directory listing.
4891 smb_SetSMBParm(outp, 0, 0);
4893 /* get the directory size */
4894 lock_ObtainWrite(&scp->rw);
4895 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4896 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4898 lock_ReleaseWrite(&scp->rw);
4899 cm_ReleaseSCache(scp);
4900 cm_ReleaseUser(userp);
4901 smb_DeleteDirSearch(dsp);
4902 smb_ReleaseDirSearch(dsp);
4906 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4908 dirLength = scp->length;
4910 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4911 curOffset.HighPart = 0;
4912 curOffset.LowPart = nextCookie;
4913 origOp = op = smb_GetSMBData(outp, NULL);
4914 /* and write out the basic header */
4915 *op++ = 5; /* variable block */
4916 op += 2; /* skip vbl block length; we'll fill it in later */
4920 clientchar_t *actualName = NULL;
4921 int free_actualName = 0;
4922 clientchar_t shortName[13];
4923 clientchar_t *shortNameEnd;
4925 /* make sure that curOffset.LowPart doesn't point to the first
4926 * 32 bytes in the 2nd through last dir page, and that it doesn't
4927 * point at the first 13 32-byte chunks in the first dir page,
4928 * since those are dir and page headers, and don't contain useful
4931 temp = curOffset.LowPart & (2048-1);
4932 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4933 /* we're in the first page */
4934 if (temp < 13*32) temp = 13*32;
4937 /* we're in a later dir page */
4938 if (temp < 32) temp = 32;
4941 /* make sure the low order 5 bits are zero */
4944 /* now put temp bits back ito curOffset.LowPart */
4945 curOffset.LowPart &= ~(2048-1);
4946 curOffset.LowPart |= temp;
4948 /* check if we've returned all the names that will fit in the
4951 if (returnedNames >= maxCount) {
4952 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4953 returnedNames, maxCount);
4957 /* check if we've passed the dir's EOF */
4958 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4960 /* see if we can use the bufferp we have now; compute in which page
4961 * the current offset would be, and check whether that's the offset
4962 * of the buffer we have. If not, get the buffer.
4964 thyper.HighPart = curOffset.HighPart;
4965 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4966 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4969 buf_Release(bufferp);
4972 lock_ReleaseWrite(&scp->rw);
4973 code = buf_Get(scp, &thyper, &req, &bufferp);
4974 lock_ObtainMutex(&dsp->mx);
4976 /* now, if we're doing a star match, do bulk fetching of all of
4977 * the status info for files in the dir.
4980 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4982 lock_ObtainWrite(&scp->rw);
4983 lock_ReleaseMutex(&dsp->mx);
4985 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4989 bufferOffset = thyper;
4991 /* now get the data in the cache */
4993 code = cm_SyncOp(scp, bufferp, userp, &req,
4995 CM_SCACHESYNC_NEEDCALLBACK |
4996 CM_SCACHESYNC_READ);
4998 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5002 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5004 if (cm_HaveBuffer(scp, bufferp, 0)) {
5005 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5009 /* otherwise, load the buffer and try again */
5010 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5012 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5013 scp, bufferp, code);
5018 buf_Release(bufferp);
5022 } /* if (wrong buffer) ... */
5024 /* now we have the buffer containing the entry we're interested in; copy
5025 * it out if it represents a non-deleted entry.
5027 entryInDir = curOffset.LowPart & (2048-1);
5028 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5030 /* page header will help tell us which entries are free. Page header
5031 * can change more often than once per buffer, since AFS 3 dir page size
5032 * may be less than (but not more than a buffer package buffer.
5034 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5035 temp &= ~(2048 - 1); /* turn off intra-page bits */
5036 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5038 /* now determine which entry we're looking at in the page. If it is
5039 * free (there's a free bitmap at the start of the dir), we should
5040 * skip these 32 bytes.
5042 slotInPage = (entryInDir & 0x7e0) >> 5;
5043 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5044 /* this entry is free */
5045 numDirChunks = 1; /* only skip this guy */
5049 tp = bufferp->datap + entryInBuffer;
5050 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5052 /* while we're here, compute the next entry's location, too,
5053 * since we'll need it when writing out the cookie into the dir
5056 * XXXX Probably should do more sanity checking.
5058 numDirChunks = cm_NameEntries(dep->name, NULL);
5060 /* compute the offset of the cookie representing the next entry */
5061 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5063 /* Compute 8.3 name if necessary */
5064 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5065 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5068 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5069 actualName = shortName;
5070 free_actualName = 0;
5072 free_actualName = 1;
5075 if (actualName == NULL) {
5076 /* Couldn't convert the name for some reason */
5077 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5078 osi_LogSaveString(smb_logp, dep->name));
5082 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5083 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5084 osi_LogSaveClientString(smb_logp, actualName));
5086 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5087 /* this is one of the entries to use: it is not deleted
5088 * and it matches the star pattern we're looking for.
5091 /* Eliminate entries that don't match requested
5094 /* no hidden files */
5095 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5096 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5100 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5102 /* We have already done the cm_TryBulkStat above */
5103 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5104 fileType = cm_FindFileType(&fid);
5105 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5106 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5108 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5109 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5110 fileType == CM_SCACHETYPE_DFSLINK ||
5111 fileType == CM_SCACHETYPE_INVALID)
5112 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5117 memcpy(op, mask, 11); op += 11;
5118 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5119 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5120 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5121 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5122 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5123 memcpy(op, &clientCookie, 4); op += 4;
5125 /* now we emit the attribute. This is sort of tricky,
5126 * since we need to really stat the file to find out
5127 * what type of entry we've got. Right now, we're
5128 * copying out data from a buffer, while holding the
5129 * scp locked, so it isn't really convenient to stat
5130 * something now. We'll put in a place holder now,
5131 * and make a second pass before returning this to get
5132 * the real attributes. So, we just skip the data for
5133 * now, and adjust it later. We allocate a patch
5134 * record to make it easy to find this point later.
5135 * The replay will happen at a time when it is safe to
5136 * unlock the directory.
5138 curPatchp = malloc(sizeof(*curPatchp));
5139 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5140 curPatchp->dptr = op;
5141 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5143 /* do hidden attribute here since name won't be around when applying
5147 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5148 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5150 curPatchp->flags = 0;
5152 op += 9; /* skip attr, time, date and size */
5154 /* zero out name area. The spec says to pad with
5155 * spaces, but Samba doesn't, and neither do we.
5159 /* finally, we get to copy out the name; we know that
5160 * it fits in 8.3 or the pattern wouldn't match, but it
5161 * never hurts to be sure.
5163 cm_ClientStringToUtf8(actualName, -1, op, 13);
5164 if (smb_StoreAnsiFilenames)
5166 /* This is a UCHAR field, which is ASCII even if Unicode
5169 /* Uppercase if requested by client */
5170 if (!KNOWS_LONG_NAMES(inp))
5175 /* now, adjust the # of entries copied */
5177 } /* if we're including this name */
5180 if (free_actualName && actualName) {
5185 /* and adjust curOffset to be where the new cookie is */
5186 thyper.HighPart = 0;
5187 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5188 curOffset = LargeIntegerAdd(thyper, curOffset);
5189 } /* while copying data for dir listing */
5191 /* release the mutex */
5192 lock_ReleaseWrite(&scp->rw);
5194 buf_Release(bufferp);
5198 /* apply and free last set of patches; if not doing a star match, this
5199 * will be empty, but better safe (and freeing everything) than sorry.
5201 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5203 /* special return code for unsuccessful search */
5204 if (code == 0 && dataLength < 21 && returnedNames == 0)
5205 code = CM_ERROR_NOFILES;
5207 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5208 returnedNames, code);
5211 smb_DeleteDirSearch(dsp);
5212 smb_ReleaseDirSearch(dsp);
5213 cm_ReleaseSCache(scp);
5214 cm_ReleaseUser(userp);
5218 /* finalize the output buffer */
5219 smb_SetSMBParm(outp, 0, returnedNames);
5220 temp = (long) (op - origOp);
5221 smb_SetSMBDataLength(outp, temp);
5223 /* the data area is a variable block, which has a 5 (already there)
5224 * followed by the length of the # of data bytes. We now know this to
5225 * be "temp," although that includes the 3 bytes of vbl block header.
5226 * Deduct for them and fill in the length field.
5228 temp -= 3; /* deduct vbl block info */
5229 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5230 origOp[1] = (unsigned char)(temp & 0xff);
5231 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5232 if (returnedNames == 0)
5233 smb_DeleteDirSearch(dsp);
5234 smb_ReleaseDirSearch(dsp);
5235 cm_ReleaseSCache(scp);
5236 cm_ReleaseUser(userp);
5241 /* verify that this is a valid path to a directory. I don't know why they
5242 * don't use the get file attributes call.
5244 * SMB_COM_CHECK_DIRECTORY
5246 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5248 clientchar_t *pathp;
5250 cm_scache_t *rootScp;
5251 cm_scache_t *newScp;
5255 clientchar_t *tidPathp;
5261 pdata = smb_GetSMBData(inp, NULL);
5262 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5264 return CM_ERROR_BADSMB;
5265 osi_Log1(smb_logp, "SMB receive check path %S",
5266 osi_LogSaveClientString(smb_logp, pathp));
5268 rootScp = cm_data.rootSCachep;
5270 userp = smb_GetUserFromVCP(vcp, inp);
5272 caseFold = CM_FLAG_CASEFOLD;
5274 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5276 cm_ReleaseUser(userp);
5277 return CM_ERROR_NOSUCHPATH;
5279 code = cm_NameI(rootScp, pathp,
5280 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5281 userp, tidPathp, &req, &newScp);
5284 cm_ReleaseUser(userp);
5289 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5290 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5291 cm_ReleaseSCache(newScp);
5292 cm_ReleaseUser(userp);
5293 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5294 return CM_ERROR_PATH_NOT_COVERED;
5296 return CM_ERROR_NOSUCHPATH;
5298 #endif /* DFS_SUPPORT */
5300 /* now lock the vnode with a callback; returns with newScp locked */
5301 lock_ObtainWrite(&newScp->rw);
5302 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5303 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5305 if (code != CM_ERROR_NOACCESS) {
5306 lock_ReleaseWrite(&newScp->rw);
5307 cm_ReleaseSCache(newScp);
5308 cm_ReleaseUser(userp);
5312 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5315 attrs = smb_Attributes(newScp);
5317 if (!(attrs & SMB_ATTR_DIRECTORY))
5318 code = CM_ERROR_NOTDIR;
5320 lock_ReleaseWrite(&newScp->rw);
5322 cm_ReleaseSCache(newScp);
5323 cm_ReleaseUser(userp);
5327 /* SMB_COM_SET_INFORMATION */
5328 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5330 clientchar_t *pathp;
5332 cm_scache_t *rootScp;
5333 unsigned short attribute;
5335 cm_scache_t *newScp;
5339 clientchar_t *tidPathp;
5345 /* decode basic attributes we're passed */
5346 attribute = smb_GetSMBParm(inp, 0);
5347 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5349 datap = smb_GetSMBData(inp, NULL);
5350 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5352 return CM_ERROR_BADSMB;
5354 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5355 dosTime, attribute);
5357 rootScp = cm_data.rootSCachep;
5359 userp = smb_GetUserFromVCP(vcp, inp);
5361 caseFold = CM_FLAG_CASEFOLD;
5363 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5365 cm_ReleaseUser(userp);
5366 return CM_ERROR_NOSUCHFILE;
5368 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5369 tidPathp, &req, &newScp);
5372 cm_ReleaseUser(userp);
5377 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5378 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5379 cm_ReleaseSCache(newScp);
5380 cm_ReleaseUser(userp);
5381 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5382 return CM_ERROR_PATH_NOT_COVERED;
5384 return CM_ERROR_NOSUCHPATH;
5386 #endif /* DFS_SUPPORT */
5388 /* now lock the vnode with a callback; returns with newScp locked; we
5389 * need the current status to determine what the new status is, in some
5392 lock_ObtainWrite(&newScp->rw);
5393 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5394 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5396 lock_ReleaseWrite(&newScp->rw);
5397 cm_ReleaseSCache(newScp);
5398 cm_ReleaseUser(userp);
5402 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5404 /* Check for RO volume */
5405 if (newScp->flags & CM_SCACHEFLAG_RO) {
5406 lock_ReleaseWrite(&newScp->rw);
5407 cm_ReleaseSCache(newScp);
5408 cm_ReleaseUser(userp);
5409 return CM_ERROR_READONLY;
5412 /* prepare for setattr call */
5415 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5416 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5418 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5419 /* we're told to make a writable file read-only */
5420 attr.unixModeBits = newScp->unixModeBits & ~0222;
5421 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5423 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5424 /* we're told to make a read-only file writable */
5425 attr.unixModeBits = newScp->unixModeBits | 0222;
5426 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5428 lock_ReleaseWrite(&newScp->rw);
5430 /* now call setattr */
5432 code = cm_SetAttr(newScp, &attr, userp, &req);
5436 cm_ReleaseSCache(newScp);
5437 cm_ReleaseUser(userp);
5443 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5445 clientchar_t *pathp;
5447 cm_scache_t *rootScp;
5448 cm_scache_t *newScp, *dscp;
5453 clientchar_t *tidPathp;
5455 clientchar_t *lastComp;
5461 datap = smb_GetSMBData(inp, NULL);
5462 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5464 return CM_ERROR_BADSMB;
5466 if (*pathp == 0) /* null path */
5469 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5470 osi_LogSaveClientString(smb_logp, pathp));
5472 rootScp = cm_data.rootSCachep;
5474 userp = smb_GetUserFromVCP(vcp, inp);
5476 /* we shouldn't need this for V3 requests, but we seem to */
5477 caseFold = CM_FLAG_CASEFOLD;
5479 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5481 cm_ReleaseUser(userp);
5482 return CM_ERROR_NOSUCHFILE;
5486 * XXX Strange hack XXX
5488 * As of Patch 5 (16 July 97), we are having the following problem:
5489 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5490 * requests to look up "desktop.ini" in all the subdirectories.
5491 * This can cause zillions of timeouts looking up non-existent cells
5492 * and volumes, especially in the top-level directory.
5494 * We have not found any way to avoid this or work around it except
5495 * to explicitly ignore the requests for mount points that haven't
5496 * yet been evaluated and for directories that haven't yet been
5499 * We should modify this hack to provide a fake desktop.ini file
5500 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5502 spacep = inp->spacep;
5503 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5504 #ifndef SPECIAL_FOLDERS
5505 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5506 code = cm_NameI(rootScp, spacep->wdata,
5507 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5508 userp, tidPathp, &req, &dscp);
5511 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5512 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5514 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5515 return CM_ERROR_PATH_NOT_COVERED;
5517 return CM_ERROR_NOSUCHPATH;
5519 #endif /* DFS_SUPPORT */
5520 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5521 code = CM_ERROR_NOSUCHFILE;
5522 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5523 cm_buf_t *bp = buf_Find(dscp, &hzero);
5528 code = CM_ERROR_NOSUCHFILE;
5530 cm_ReleaseSCache(dscp);
5532 cm_ReleaseUser(userp);
5537 #endif /* SPECIAL_FOLDERS */
5539 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5540 tidPathp, &req, &newScp);
5542 cm_ReleaseUser(userp);
5547 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5548 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5549 cm_ReleaseSCache(newScp);
5550 cm_ReleaseUser(userp);
5551 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5552 return CM_ERROR_PATH_NOT_COVERED;
5554 return CM_ERROR_NOSUCHPATH;
5556 #endif /* DFS_SUPPORT */
5558 /* now lock the vnode with a callback; returns with newScp locked */
5559 lock_ObtainWrite(&newScp->rw);
5560 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5561 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5563 lock_ReleaseWrite(&newScp->rw);
5564 cm_ReleaseSCache(newScp);
5565 cm_ReleaseUser(userp);
5569 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5571 attrs = smb_Attributes(newScp);
5573 smb_SetSMBParm(outp, 0, attrs);
5575 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5576 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5577 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5578 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5579 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5580 smb_SetSMBParm(outp, 5, 0);
5581 smb_SetSMBParm(outp, 6, 0);
5582 smb_SetSMBParm(outp, 7, 0);
5583 smb_SetSMBParm(outp, 8, 0);
5584 smb_SetSMBParm(outp, 9, 0);
5585 smb_SetSMBDataLength(outp, 0);
5586 lock_ReleaseWrite(&newScp->rw);
5588 cm_ReleaseSCache(newScp);
5589 cm_ReleaseUser(userp);
5594 /* SMB_COM_TREE_DISCONNECT */
5595 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5599 osi_Log0(smb_logp, "SMB receive tree disconnect");
5601 /* find the tree and free it */
5602 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5604 lock_ObtainWrite(&smb_rctLock);
5606 smb_ReleaseTID(tidp, TRUE);
5607 lock_ReleaseWrite(&smb_rctLock);
5614 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5617 clientchar_t *pathp;
5618 clientchar_t *lastNamep;
5627 clientchar_t *tidPathp;
5633 datap = smb_GetSMBData(inp, NULL);
5634 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5636 return CM_ERROR_BADSMB;
5638 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5640 #ifdef DEBUG_VERBOSE
5644 hexpath = osi_HexifyString( pathp );
5645 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5650 share = smb_GetSMBParm(inp, 0);
5651 attribute = smb_GetSMBParm(inp, 1);
5653 spacep = inp->spacep;
5654 /* smb_StripLastComponent will strip "::$DATA" if present */
5655 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5657 if (!cm_IsValidClientString(pathp)) {
5659 clientchar_t * hexp;
5661 hexp = cm_GetRawCharsAlloc(pathp, -1);
5662 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5663 osi_LogSaveClientString(smb_logp, hexp));
5667 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5669 return CM_ERROR_BADNTFILENAME;
5672 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5673 /* special case magic file name for receiving IOCTL requests
5674 * (since IOCTL calls themselves aren't getting through).
5676 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5677 smb_SetupIoctlFid(fidp, spacep);
5678 smb_SetSMBParm(outp, 0, fidp->fid);
5679 smb_SetSMBParm(outp, 1, 0); /* attrs */
5680 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5681 smb_SetSMBParm(outp, 3, 0);
5682 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5683 smb_SetSMBParm(outp, 5, 0x7fff);
5684 /* pass the open mode back */
5685 smb_SetSMBParm(outp, 6, (share & 0xf));
5686 smb_SetSMBDataLength(outp, 0);
5687 smb_ReleaseFID(fidp);
5691 userp = smb_GetUserFromVCP(vcp, inp);
5693 caseFold = CM_FLAG_CASEFOLD;
5695 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5697 cm_ReleaseUser(userp);
5698 return CM_ERROR_NOSUCHPATH;
5700 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5701 tidPathp, &req, &scp);
5704 cm_ReleaseUser(userp);
5709 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5710 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5711 cm_ReleaseSCache(scp);
5712 cm_ReleaseUser(userp);
5713 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5714 return CM_ERROR_PATH_NOT_COVERED;
5716 return CM_ERROR_NOSUCHPATH;
5718 #endif /* DFS_SUPPORT */
5720 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5722 cm_ReleaseSCache(scp);
5723 cm_ReleaseUser(userp);
5727 /* don't need callback to check file type, since file types never
5728 * change, and namei and cm_Lookup all stat the object at least once on
5729 * a successful return.
5731 if (scp->fileType != CM_SCACHETYPE_FILE) {
5732 cm_ReleaseSCache(scp);
5733 cm_ReleaseUser(userp);
5734 return CM_ERROR_ISDIR;
5737 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5738 osi_assertx(fidp, "null smb_fid_t");
5740 lock_ObtainMutex(&fidp->mx);
5741 if ((share & 0xf) == 0)
5742 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5743 else if ((share & 0xf) == 1)
5744 fidp->flags |= SMB_FID_OPENWRITE;
5746 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5750 fidp->userp = userp;
5752 /* and a pointer to the vnode */
5754 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5755 lock_ObtainWrite(&scp->rw);
5756 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5758 smb_SetSMBParm(outp, 0, fidp->fid);
5759 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5760 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5761 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5762 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5763 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5764 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5765 /* pass the open mode back; XXXX add access checks */
5766 smb_SetSMBParm(outp, 6, (share & 0xf));
5767 smb_SetSMBDataLength(outp, 0);
5768 lock_ReleaseMutex(&fidp->mx);
5769 lock_ReleaseRead(&scp->rw);
5772 cm_Open(scp, 0, userp);
5774 /* send and free packet */
5775 smb_ReleaseFID(fidp);
5776 cm_ReleaseUser(userp);
5777 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5781 typedef struct smb_unlinkRock {
5786 clientchar_t *maskp; /* pointer to the star pattern */
5789 cm_dirEntryList_t * matches;
5792 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5795 smb_unlinkRock_t *rockp;
5798 normchar_t matchName[MAX_PATH];
5802 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5803 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5804 caseFold |= CM_FLAG_8DOT3;
5806 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5807 /* Can't convert name */
5808 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5809 osi_LogSaveString(smb_logp, dep->name));
5813 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5815 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5816 !cm_Is8Dot3(matchName)) {
5817 cm_Gen8Dot3Name(dep, matchName, NULL);
5818 /* 8.3 matches are always case insensitive */
5819 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5822 osi_Log1(smb_logp, "Found match %S",
5823 osi_LogSaveClientString(smb_logp, matchName));
5825 cm_DirEntryListAdd(dep->name, &rockp->matches);
5829 /* If we made a case sensitive exact match, we might as well quit now. */
5830 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5831 code = CM_ERROR_STOPNOW;
5840 /* SMB_COM_DELETE */
5841 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5845 clientchar_t *pathp;
5849 clientchar_t *lastNamep;
5850 smb_unlinkRock_t rock;
5854 clientchar_t *tidPathp;
5858 memset(&rock, 0, sizeof(rock));
5860 attribute = smb_GetSMBParm(inp, 0);
5862 tp = smb_GetSMBData(inp, NULL);
5863 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5865 return CM_ERROR_BADSMB;
5867 osi_Log1(smb_logp, "SMB receive unlink %S",
5868 osi_LogSaveClientString(smb_logp, pathp));
5870 spacep = inp->spacep;
5871 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5873 userp = smb_GetUserFromVCP(vcp, inp);
5875 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5877 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5879 cm_ReleaseUser(userp);
5880 return CM_ERROR_NOSUCHPATH;
5882 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5885 cm_ReleaseUser(userp);
5890 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5891 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5892 cm_ReleaseSCache(dscp);
5893 cm_ReleaseUser(userp);
5894 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5895 return CM_ERROR_PATH_NOT_COVERED;
5897 return CM_ERROR_NOSUCHPATH;
5899 #endif /* DFS_SUPPORT */
5901 /* otherwise, scp points to the parent directory. */
5908 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5910 code = CM_ERROR_NOSUCHFILE;
5913 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5916 thyper.HighPart = 0;
5921 rock.matches = NULL;
5923 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5924 * match. If that fails, we do a case insensitve match.
5926 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5927 !smb_IsStarMask(rock.maskp)) {
5928 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5931 thyper.HighPart = 0;
5932 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5937 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5939 if (code == CM_ERROR_STOPNOW)
5942 if (code == 0 && rock.matches) {
5943 cm_dirEntryList_t * entry;
5945 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5946 normchar_t normalizedName[MAX_PATH];
5948 /* Note: entry->name is a non-normalized name */
5950 osi_Log1(smb_logp, "Unlinking %s",
5951 osi_LogSaveString(smb_logp, entry->name));
5953 /* We assume this works because entry->name was
5954 successfully converted in smb_UnlinkProc() once. */
5955 cm_FsStringToNormString(entry->name, -1,
5956 normalizedName, lengthof(normalizedName));
5958 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5960 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5961 smb_NotifyChange(FILE_ACTION_REMOVED,
5962 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5963 dscp, normalizedName, NULL, TRUE);
5967 cm_DirEntryListFree(&rock.matches);
5971 cm_ReleaseUser(userp);
5974 cm_ReleaseSCache(dscp);
5979 if (code == 0 && !rock.any)
5980 code = CM_ERROR_NOSUCHFILE;
5984 typedef struct smb_renameRock {
5985 cm_scache_t *odscp; /* old dir */
5986 cm_scache_t *ndscp; /* new dir */
5987 cm_user_t *userp; /* user */
5988 cm_req_t *reqp; /* request struct */
5989 smb_vc_t *vcp; /* virtual circuit */
5990 normchar_t *maskp; /* pointer to star pattern of old file name */
5991 int flags; /* tilde, casefold, etc */
5992 clientchar_t *newNamep; /* ptr to the new file's name */
5993 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5994 clientchar_t clOldName[MAX_PATH]; /* client name */
5998 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6001 smb_renameRock_t *rockp;
6004 normchar_t matchName[MAX_PATH];
6006 rockp = (smb_renameRock_t *) vrockp;
6008 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6009 /* Can't convert string */
6010 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6011 osi_LogSaveString(smb_logp, dep->name));
6015 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6016 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6017 caseFold |= CM_FLAG_8DOT3;
6019 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6021 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6022 !cm_Is8Dot3(matchName)) {
6023 cm_Gen8Dot3Name(dep, matchName, NULL);
6024 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6029 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6030 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6032 code = CM_ERROR_STOPNOW;
6042 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6045 cm_space_t *spacep = NULL;
6046 smb_renameRock_t rock;
6047 cm_scache_t *oldDscp = NULL;
6048 cm_scache_t *newDscp = NULL;
6049 cm_scache_t *tmpscp= NULL;
6050 cm_scache_t *tmpscp2 = NULL;
6051 clientchar_t *oldLastNamep;
6052 clientchar_t *newLastNamep;
6056 clientchar_t *tidPathp;
6060 userp = smb_GetUserFromVCP(vcp, inp);
6061 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6063 cm_ReleaseUser(userp);
6064 return CM_ERROR_NOSUCHPATH;
6068 memset(&rock, 0, sizeof(rock));
6070 spacep = inp->spacep;
6071 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6073 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6074 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6075 userp, tidPathp, &req, &oldDscp);
6077 cm_ReleaseUser(userp);
6082 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6083 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6084 cm_ReleaseSCache(oldDscp);
6085 cm_ReleaseUser(userp);
6086 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6087 return CM_ERROR_PATH_NOT_COVERED;
6089 return CM_ERROR_NOSUCHPATH;
6091 #endif /* DFS_SUPPORT */
6093 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6094 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6095 userp, tidPathp, &req, &newDscp);
6098 cm_ReleaseSCache(oldDscp);
6099 cm_ReleaseUser(userp);
6104 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6105 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6106 cm_ReleaseSCache(oldDscp);
6107 cm_ReleaseSCache(newDscp);
6108 cm_ReleaseUser(userp);
6109 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6110 return CM_ERROR_PATH_NOT_COVERED;
6112 return CM_ERROR_NOSUCHPATH;
6114 #endif /* DFS_SUPPORT */
6117 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6118 * next, get the component names, and lower case them.
6121 /* handle the old name first */
6123 oldLastNamep = oldPathp;
6127 /* and handle the new name, too */
6129 newLastNamep = newPathp;
6133 /* TODO: The old name could be a wildcard. The new name must not be */
6135 /* Check if the file already exists; if so return error */
6136 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6137 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6138 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6140 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6141 osi_LogSaveClientString(smb_logp, newLastNamep));
6143 /* Check if the old and the new names differ only in case. If so return
6144 * success, else return CM_ERROR_EXISTS
6146 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6148 /* This would be a success only if the old file is *as same as* the new file */
6149 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6151 if (tmpscp == tmpscp2)
6154 code = CM_ERROR_EXISTS;
6155 cm_ReleaseSCache(tmpscp2);
6158 code = CM_ERROR_NOSUCHFILE;
6161 /* file exist, do not rename, also fixes move */
6162 osi_Log0(smb_logp, "Can't rename. Target already exists");
6163 code = CM_ERROR_EXISTS;
6168 /* do the vnode call */
6169 rock.odscp = oldDscp;
6170 rock.ndscp = newDscp;
6174 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6176 code = CM_ERROR_NOSUCHFILE;
6179 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6180 rock.newNamep = newLastNamep;
6181 rock.fsOldName[0] = '\0';
6182 rock.clOldName[0] = '\0';
6185 /* Now search the directory for the pattern, and do the appropriate rename when found */
6186 thyper.LowPart = 0; /* search dir from here */
6187 thyper.HighPart = 0;
6189 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6190 if (code == 0 && !rock.any) {
6192 thyper.HighPart = 0;
6193 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6194 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6196 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6198 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6199 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6200 rock.ndscp, rock.newNamep, rock.userp,
6202 /* if the call worked, stop doing the search now, since we
6203 * really only want to rename one file.
6206 osi_Log0(smb_logp, "cm_Rename failure");
6207 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6208 } else if (code == 0) {
6209 code = CM_ERROR_NOSUCHFILE;
6212 /* Handle Change Notification */
6214 * Being lazy, not distinguishing between files and dirs in this
6215 * filter, since we'd have to do a lookup.
6218 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6219 if (oldDscp == newDscp) {
6220 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6221 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6222 filter, oldDscp, rock.clOldName,
6223 newLastNamep, TRUE);
6225 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6226 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6227 filter, oldDscp, rock.clOldName,
6229 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6230 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6231 filter, newDscp, newLastNamep,
6238 cm_ReleaseSCache(tmpscp);
6240 cm_ReleaseUser(userp);
6242 cm_ReleaseSCache(oldDscp);
6244 cm_ReleaseSCache(newDscp);
6252 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6255 cm_space_t *spacep = NULL;
6256 cm_scache_t *oldDscp = NULL;
6257 cm_scache_t *newDscp = NULL;
6258 cm_scache_t *tmpscp= NULL;
6259 cm_scache_t *tmpscp2 = NULL;
6260 cm_scache_t *sscp = NULL;
6261 clientchar_t *oldLastNamep;
6262 clientchar_t *newLastNamep;
6265 clientchar_t *tidPathp;
6269 userp = smb_GetUserFromVCP(vcp, inp);
6271 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6273 cm_ReleaseUser(userp);
6274 return CM_ERROR_NOSUCHPATH;
6279 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6281 spacep = inp->spacep;
6282 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6284 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6285 userp, tidPathp, &req, &oldDscp);
6287 cm_ReleaseUser(userp);
6292 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6293 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6294 cm_ReleaseSCache(oldDscp);
6295 cm_ReleaseUser(userp);
6296 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6297 return CM_ERROR_PATH_NOT_COVERED;
6299 return CM_ERROR_NOSUCHPATH;
6301 #endif /* DFS_SUPPORT */
6303 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6304 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6305 userp, tidPathp, &req, &newDscp);
6307 cm_ReleaseSCache(oldDscp);
6308 cm_ReleaseUser(userp);
6313 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6314 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6315 cm_ReleaseSCache(newDscp);
6316 cm_ReleaseSCache(oldDscp);
6317 cm_ReleaseUser(userp);
6318 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6319 return CM_ERROR_PATH_NOT_COVERED;
6321 return CM_ERROR_NOSUCHPATH;
6323 #endif /* DFS_SUPPORT */
6325 /* Now, although we did two lookups for the two directories (because the same
6326 * directory can be referenced through different paths), we only allow hard links
6327 * within the same directory. */
6328 if (oldDscp != newDscp) {
6329 cm_ReleaseSCache(oldDscp);
6330 cm_ReleaseSCache(newDscp);
6331 cm_ReleaseUser(userp);
6332 return CM_ERROR_CROSSDEVLINK;
6335 /* handle the old name first */
6337 oldLastNamep = oldPathp;
6341 /* and handle the new name, too */
6343 newLastNamep = newPathp;
6347 /* now lookup the old name */
6348 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6349 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6351 cm_ReleaseSCache(oldDscp);
6352 cm_ReleaseSCache(newDscp);
6353 cm_ReleaseUser(userp);
6357 /* Check if the file already exists; if so return error */
6358 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6359 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6360 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6362 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6363 osi_LogSaveClientString(smb_logp, newLastNamep));
6365 /* if the existing link is to the same file, then we return success */
6367 if(sscp == tmpscp) {
6370 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6371 code = CM_ERROR_EXISTS;
6376 cm_ReleaseSCache(tmpscp);
6377 cm_ReleaseSCache(sscp);
6378 cm_ReleaseSCache(newDscp);
6379 cm_ReleaseSCache(oldDscp);
6380 cm_ReleaseUser(userp);
6384 /* now create the hardlink */
6385 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6386 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6387 osi_Log1(smb_logp," Link returns 0x%x", code);
6389 /* Handle Change Notification */
6391 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6392 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6393 smb_NotifyChange(FILE_ACTION_ADDED,
6394 filter, newDscp, newLastNamep,
6399 cm_ReleaseSCache(tmpscp);
6400 cm_ReleaseUser(userp);
6401 cm_ReleaseSCache(sscp);
6402 cm_ReleaseSCache(oldDscp);
6403 cm_ReleaseSCache(newDscp);
6407 /* SMB_COM_RENAME */
6409 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6411 clientchar_t *oldPathp;
6412 clientchar_t *newPathp;
6416 tp = smb_GetSMBData(inp, NULL);
6417 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6419 return CM_ERROR_BADSMB;
6420 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6422 return CM_ERROR_BADSMB;
6424 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6425 osi_LogSaveClientString(smb_logp, oldPathp),
6426 osi_LogSaveClientString(smb_logp, newPathp));
6428 if (!cm_IsValidClientString(newPathp)) {
6430 clientchar_t * hexp;
6432 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6433 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6434 osi_LogSaveClientString(smb_logp, hexp));
6438 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6440 return CM_ERROR_BADNTFILENAME;
6443 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6445 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6451 typedef struct smb_rmdirRock {
6455 normchar_t *maskp; /* pointer to the star pattern */
6458 cm_dirEntryList_t * matches;
6461 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6464 smb_rmdirRock_t *rockp;
6466 normchar_t matchName[MAX_PATH];
6468 rockp = (smb_rmdirRock_t *) vrockp;
6470 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6471 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6472 osi_LogSaveString(smb_logp, dep->name));
6476 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6477 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6479 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6481 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6482 !cm_Is8Dot3(matchName)) {
6483 cm_Gen8Dot3Name(dep, matchName, NULL);
6484 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6489 cm_DirEntryListAdd(dep->name, &rockp->matches);
6496 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6499 clientchar_t *pathp;
6503 clientchar_t *lastNamep;
6504 smb_rmdirRock_t rock;
6508 clientchar_t *tidPathp;
6512 memset(&rock, 0, sizeof(rock));
6514 tp = smb_GetSMBData(inp, NULL);
6515 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6517 return CM_ERROR_BADSMB;
6519 spacep = inp->spacep;
6520 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6522 userp = smb_GetUserFromVCP(vcp, inp);
6524 caseFold = CM_FLAG_CASEFOLD;
6526 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6528 cm_ReleaseUser(userp);
6529 return CM_ERROR_NOSUCHPATH;
6531 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6532 userp, tidPathp, &req, &dscp);
6535 cm_ReleaseUser(userp);
6540 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6541 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6542 cm_ReleaseSCache(dscp);
6543 cm_ReleaseUser(userp);
6544 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6545 return CM_ERROR_PATH_NOT_COVERED;
6547 return CM_ERROR_NOSUCHPATH;
6549 #endif /* DFS_SUPPORT */
6551 /* otherwise, scp points to the parent directory. */
6558 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6560 code = CM_ERROR_NOSUCHFILE;
6563 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6566 thyper.HighPart = 0;
6570 rock.matches = NULL;
6572 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6573 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6574 if (code == 0 && !rock.any) {
6576 thyper.HighPart = 0;
6577 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6578 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6581 if (code == 0 && rock.matches) {
6582 cm_dirEntryList_t * entry;
6584 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6585 clientchar_t clientName[MAX_PATH];
6587 /* We assume this will succeed because smb_RmdirProc()
6588 successfully converted entry->name once above. */
6589 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6591 osi_Log1(smb_logp, "Removing directory %s",
6592 osi_LogSaveString(smb_logp, entry->name));
6594 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6596 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6597 smb_NotifyChange(FILE_ACTION_REMOVED,
6598 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6599 dscp, clientName, NULL, TRUE);
6605 cm_DirEntryListFree(&rock.matches);
6608 cm_ReleaseUser(userp);
6611 cm_ReleaseSCache(dscp);
6613 if (code == 0 && !rock.any)
6614 code = CM_ERROR_NOSUCHFILE;
6623 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6633 fid = smb_GetSMBParm(inp, 0);
6635 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6637 fid = smb_ChainFID(fid, inp);
6638 fidp = smb_FindFID(vcp, fid, 0);
6640 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6642 return CM_ERROR_BADFD;
6644 userp = smb_GetUserFromVCP(vcp, inp);
6646 lock_ObtainMutex(&fidp->mx);
6647 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6648 cm_ReleaseUser(userp);
6649 lock_ReleaseMutex(&fidp->mx);
6650 smb_ReleaseFID(fidp);
6651 return CM_ERROR_BADFD;
6654 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6655 lock_ReleaseMutex(&fidp->mx);
6656 cm_ReleaseUser(userp);
6657 smb_CloseFID(vcp, fidp, NULL, 0);
6658 smb_ReleaseFID(fidp);
6659 return CM_ERROR_NOSUCHFILE;
6662 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6663 cm_scache_t * scp = fidp->scp;
6665 lock_ReleaseMutex(&fidp->mx);
6666 code = cm_FSync(scp, userp, &req);
6667 cm_ReleaseSCache(scp);
6669 lock_ReleaseMutex(&fidp->mx);
6673 cm_ReleaseUser(userp);
6674 smb_ReleaseFID(fidp);
6678 struct smb_FullNameRock {
6681 clientchar_t *fullName;
6682 fschar_t *originalName;
6685 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6688 normchar_t matchName[MAX_PATH];
6689 struct smb_FullNameRock *vrockp;
6691 vrockp = (struct smb_FullNameRock *)rockp;
6693 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6694 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6695 osi_LogSaveString(smb_logp, dep->name));
6699 if (!cm_Is8Dot3(matchName)) {
6700 clientchar_t shortName[13];
6702 cm_Gen8Dot3Name(dep, shortName, NULL);
6704 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6705 vrockp->fullName = cm_ClientStrDup(matchName);
6706 vrockp->originalName = cm_FsStrDup(dep->name);
6707 return CM_ERROR_STOPNOW;
6710 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6711 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6712 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6713 vrockp->fullName = cm_ClientStrDup(matchName);
6714 vrockp->originalName = cm_FsStrDup(dep->name);
6715 return CM_ERROR_STOPNOW;
6720 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6721 clientchar_t **newPathp, fschar_t ** originalPathp,
6722 cm_user_t *userp, cm_req_t *reqp)
6724 struct smb_FullNameRock rock;
6727 memset(&rock, 0, sizeof(rock));
6731 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6732 if (code == CM_ERROR_STOPNOW) {
6733 *newPathp = rock.fullName;
6734 *originalPathp = rock.originalName;
6736 *newPathp = cm_ClientStrDup(pathp);
6737 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6741 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6742 afs_uint32 dosTime) {
6745 cm_scache_t *dscp = NULL;
6746 clientchar_t *pathp = NULL;
6747 cm_scache_t * scp = NULL;
6748 cm_scache_t *delscp = NULL;
6749 int nullcreator = 0;
6751 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6752 fidp, fidp->fid, scp, vcp);
6755 lock_ObtainMutex(&fidp->mx);
6756 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6758 lock_ReleaseMutex(&fidp->mx);
6759 osi_Log0(smb_logp, " No user specified. Not closing fid");
6760 return CM_ERROR_BADFD;
6763 userp = fidp->userp; /* no hold required since fidp is held
6764 throughout the function */
6765 lock_ReleaseMutex(&fidp->mx);
6770 lock_ObtainWrite(&smb_rctLock);
6771 if (fidp->deleteOk) {
6772 osi_Log0(smb_logp, " Fid already closed.");
6773 lock_ReleaseWrite(&smb_rctLock);
6774 return CM_ERROR_BADFD;
6777 lock_ReleaseWrite(&smb_rctLock);
6779 lock_ObtainMutex(&fidp->mx);
6780 if (fidp->NTopen_dscp) {
6781 dscp = fidp->NTopen_dscp;
6782 cm_HoldSCache(dscp);
6785 if (fidp->NTopen_pathp)
6786 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6793 /* Don't jump the gun on an async raw write */
6794 while (fidp->raw_writers) {
6795 lock_ReleaseMutex(&fidp->mx);
6796 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6797 lock_ObtainMutex(&fidp->mx);
6800 /* watch for ioctl closes, and read-only opens */
6802 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6803 == SMB_FID_OPENWRITE) {
6804 if (dosTime != 0 && dosTime != -1) {
6805 lock_ObtainWrite(&fidp->scp->rw);
6806 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6807 /* This fixes defect 10958 */
6808 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6809 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6810 lock_ReleaseWrite(&fidp->scp->rw);
6812 if (smb_AsyncStore != 2) {
6813 lock_ReleaseMutex(&fidp->mx);
6814 code = cm_FSync(scp, userp, &req);
6815 lock_ObtainMutex(&fidp->mx);
6821 /* unlock any pending locks */
6822 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6823 scp->fileType == CM_SCACHETYPE_FILE) {
6827 lock_ReleaseMutex(&fidp->mx);
6829 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6831 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6832 lock_ObtainWrite(&scp->rw);
6834 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6835 CM_SCACHESYNC_NEEDCALLBACK
6836 | CM_SCACHESYNC_GETSTATUS
6837 | CM_SCACHESYNC_LOCK);
6841 "smb CoreClose SyncOp failure code 0x%x", tcode);
6842 goto post_syncopdone;
6845 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6847 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6851 lock_ReleaseWrite(&scp->rw);
6852 lock_ObtainMutex(&fidp->mx);
6855 if (fidp->flags & SMB_FID_DELONCLOSE) {
6856 clientchar_t *fullPathp = NULL;
6857 fschar_t *originalNamep = NULL;
6859 lock_ReleaseMutex(&fidp->mx);
6861 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6866 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6867 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6868 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6870 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6871 smb_NotifyChange(FILE_ACTION_REMOVED,
6872 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6873 dscp, fullPathp, NULL, TRUE);
6876 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6878 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6879 smb_NotifyChange(FILE_ACTION_REMOVED,
6880 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6881 dscp, fullPathp, NULL, TRUE);
6888 free(originalNamep);
6890 lock_ObtainMutex(&fidp->mx);
6891 fidp->flags &= ~SMB_FID_DELONCLOSE;
6894 /* if this was a newly created file, then clear the creator
6895 * in the stat cache entry. */
6896 if (fidp->flags & SMB_FID_CREATED) {
6898 fidp->flags &= ~SMB_FID_CREATED;
6901 if (fidp->flags & SMB_FID_NTOPEN) {
6902 cm_ReleaseSCache(fidp->NTopen_dscp);
6903 fidp->NTopen_dscp = NULL;
6904 free(fidp->NTopen_pathp);
6905 fidp->NTopen_pathp = NULL;
6906 fidp->flags &= ~SMB_FID_NTOPEN;
6908 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6909 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6912 if (fidp->NTopen_wholepathp) {
6913 free(fidp->NTopen_wholepathp);
6914 fidp->NTopen_wholepathp = NULL;
6918 cm_ReleaseSCache(fidp->scp);
6921 lock_ReleaseMutex(&fidp->mx);
6924 cm_ReleaseSCache(dscp);
6927 cm_ReleaseSCache(delscp);
6931 lock_ObtainWrite(&scp->rw);
6932 if (nullcreator && scp->creator == userp)
6933 scp->creator = NULL;
6934 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6935 lock_ReleaseWrite(&scp->rw);
6936 cm_ReleaseSCache(scp);
6946 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6954 fid = smb_GetSMBParm(inp, 0);
6955 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6957 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6959 fid = smb_ChainFID(fid, inp);
6960 fidp = smb_FindFID(vcp, fid, 0);
6962 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
6964 return CM_ERROR_BADFD;
6967 userp = smb_GetUserFromVCP(vcp, inp);
6969 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6971 smb_ReleaseFID(fidp);
6972 cm_ReleaseUser(userp);
6977 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6979 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6980 cm_user_t *userp, long *readp)
6986 osi_hyper_t fileLength;
6988 osi_hyper_t lastByte;
6989 osi_hyper_t bufferOffset;
6993 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6996 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6997 fidp->fid, offsetp->LowPart, count);
7001 lock_ObtainMutex(&fidp->mx);
7002 /* make sure we have a readable FD */
7003 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7004 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7005 fidp->fid, fidp->flags);
7006 lock_ReleaseMutex(&fidp->mx);
7007 code = CM_ERROR_BADFDOP;
7012 lock_ReleaseMutex(&fidp->mx);
7013 code = CM_ERROR_BADFD;
7024 lock_ObtainWrite(&scp->rw);
7026 if (offset.HighPart == 0) {
7027 chunk = offset.LowPart >> cm_logChunkSize;
7028 if (chunk != fidp->curr_chunk) {
7029 fidp->prev_chunk = fidp->curr_chunk;
7030 fidp->curr_chunk = chunk;
7032 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7035 lock_ReleaseMutex(&fidp->mx);
7037 /* start by looking up the file's end */
7038 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7039 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7043 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7045 /* now we have the entry locked, look up the length */
7046 fileLength = scp->length;
7048 /* adjust count down so that it won't go past EOF */
7049 thyper.LowPart = count;
7050 thyper.HighPart = 0;
7051 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7053 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7054 /* we'd read past EOF, so just stop at fileLength bytes.
7055 * Start by computing how many bytes remain in the file.
7057 thyper = LargeIntegerSubtract(fileLength, offset);
7059 /* if we are past EOF, read 0 bytes */
7060 if (LargeIntegerLessThanZero(thyper))
7063 count = thyper.LowPart;
7068 /* now, copy the data one buffer at a time,
7069 * until we've filled the request packet
7072 /* if we've copied all the data requested, we're done */
7073 if (count <= 0) break;
7075 /* otherwise, load up a buffer of data */
7076 thyper.HighPart = offset.HighPart;
7077 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7078 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7081 buf_Release(bufferp);
7084 lock_ReleaseWrite(&scp->rw);
7086 code = buf_Get(scp, &thyper, &req, &bufferp);
7088 lock_ObtainWrite(&scp->rw);
7089 if (code) goto done;
7090 bufferOffset = thyper;
7092 /* now get the data in the cache */
7094 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7095 CM_SCACHESYNC_NEEDCALLBACK |
7096 CM_SCACHESYNC_READ);
7100 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7102 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7104 /* otherwise, load the buffer and try again */
7105 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7109 buf_Release(bufferp);
7113 } /* if (wrong buffer) ... */
7115 /* now we have the right buffer loaded. Copy out the
7116 * data from here to the user's buffer.
7118 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7120 /* and figure out how many bytes we want from this buffer */
7121 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7122 if (nbytes > count) nbytes = count; /* don't go past EOF */
7124 /* now copy the data */
7125 memcpy(op, bufferp->datap + bufIndex, nbytes);
7127 /* adjust counters, pointers, etc. */
7130 thyper.LowPart = nbytes;
7131 thyper.HighPart = 0;
7132 offset = LargeIntegerAdd(thyper, offset);
7136 lock_ReleaseWrite(&scp->rw);
7138 buf_Release(bufferp);
7140 if (code == 0 && sequential)
7141 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7143 cm_ReleaseSCache(scp);
7146 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7147 fidp->fid, code, *readp);
7152 * smb_WriteData -- common code for Write and Raw Write
7154 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7155 cm_user_t *userp, long *writtenp)
7157 osi_hyper_t offset = *offsetp;
7160 cm_scache_t *scp = NULL;
7161 osi_hyper_t fileLength; /* file's length at start of write */
7162 osi_hyper_t minLength; /* don't read past this */
7163 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7164 cm_buf_t *bufferp = NULL;
7165 osi_hyper_t thyper; /* hyper tmp variable */
7166 osi_hyper_t bufferOffset;
7167 afs_uint32 bufIndex; /* index in buffer where our data is */
7168 int doWriteBack = 0;
7169 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7173 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7174 fidp->fid, offsetp->LowPart, count);
7178 lock_ObtainMutex(&fidp->mx);
7179 /* make sure we have a writable FD */
7180 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7181 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7182 fidp->fid, fidp->flags);
7183 lock_ReleaseMutex(&fidp->mx);
7184 code = CM_ERROR_BADFDOP;
7192 lock_ReleaseMutex(&fidp->mx);
7194 lock_ObtainWrite(&scp->rw);
7195 /* start by looking up the file's end */
7196 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7197 CM_SCACHESYNC_NEEDCALLBACK
7198 | CM_SCACHESYNC_SETSTATUS
7199 | CM_SCACHESYNC_GETSTATUS);
7203 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7205 /* now we have the entry locked, look up the length */
7206 fileLength = scp->length;
7207 minLength = fileLength;
7208 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7209 minLength = scp->serverLength;
7211 /* adjust file length if we extend past EOF */
7212 thyper.LowPart = count;
7213 thyper.HighPart = 0;
7214 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7215 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7216 /* we'd write past EOF, so extend the file */
7217 scp->mask |= CM_SCACHEMASK_LENGTH;
7218 scp->length = thyper;
7219 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7221 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7223 /* now, if the new position (thyper) and the old (offset) are in
7224 * different storeback windows, remember to store back the previous
7225 * storeback window when we're done with the write.
7227 * the purpose of this logic is to slow down the CIFS client
7228 * in order to avoid the client disconnecting during the CLOSE
7229 * operation if there are too many dirty buffers left to write
7230 * than can be accomplished during 45 seconds. This used to be
7231 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7232 * so that we can read larger amounts of data at a time.
7234 if (smb_AsyncStore == 1 &&
7235 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7236 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7237 /* they're different */
7239 writeBackOffset.HighPart = offset.HighPart;
7240 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7245 /* now, copy the data one buffer at a time, until we've filled the
7248 /* if we've copied all the data requested, we're done */
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 lock_ReleaseMutex(&bufferp->mx);
7266 buf_Release(bufferp);
7269 lock_ReleaseWrite(&scp->rw);
7271 code = buf_Get(scp, &thyper, &req, &bufferp);
7273 lock_ObtainMutex(&bufferp->mx);
7274 lock_ObtainWrite(&scp->rw);
7275 if (code) goto done;
7277 bufferOffset = thyper;
7279 /* now get the data in the cache */
7281 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7282 CM_SCACHESYNC_NEEDCALLBACK
7283 | CM_SCACHESYNC_WRITE
7284 | CM_SCACHESYNC_BUFLOCKED);
7288 cm_SyncOpDone(scp, bufferp,
7289 CM_SCACHESYNC_NEEDCALLBACK
7290 | CM_SCACHESYNC_WRITE
7291 | CM_SCACHESYNC_BUFLOCKED);
7293 /* If we're overwriting the entire buffer, or
7294 * if we're writing at or past EOF, mark the
7295 * buffer as current so we don't call
7296 * cm_GetBuffer. This skips the fetch from the
7297 * server in those cases where we're going to
7298 * obliterate all the data in the buffer anyway,
7299 * or in those cases where there is no useful
7300 * data at the server to start with.
7302 * Use minLength instead of scp->length, since
7303 * the latter has already been updated by this
7306 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7307 || LargeIntegerEqualTo(offset, bufferp->offset)
7308 && (count >= cm_data.buf_blockSize
7309 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7310 ConvertLongToLargeInteger(count)),
7312 if (count < cm_data.buf_blockSize
7313 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7314 memset(bufferp->datap, 0,
7315 cm_data.buf_blockSize);
7316 bufferp->dataVersion = scp->dataVersion;
7319 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7321 /* otherwise, load the buffer and try again */
7322 lock_ReleaseMutex(&bufferp->mx);
7323 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7325 lock_ReleaseWrite(&scp->rw);
7326 lock_ObtainMutex(&bufferp->mx);
7327 lock_ObtainWrite(&scp->rw);
7331 lock_ReleaseMutex(&bufferp->mx);
7332 buf_Release(bufferp);
7336 } /* if (wrong buffer) ... */
7338 /* now we have the right buffer loaded. Copy out the
7339 * data from here to the user's buffer.
7341 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7343 /* and figure out how many bytes we want from this buffer */
7344 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7346 nbytes = count; /* don't go past end of request */
7348 /* now copy the data */
7349 memcpy(bufferp->datap + bufIndex, op, nbytes);
7350 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7352 /* adjust counters, pointers, etc. */
7356 thyper.LowPart = nbytes;
7357 thyper.HighPart = 0;
7358 offset = LargeIntegerAdd(thyper, offset);
7362 lock_ReleaseWrite(&scp->rw);
7365 lock_ReleaseMutex(&bufferp->mx);
7366 buf_Release(bufferp);
7369 lock_ObtainMutex(&fidp->mx);
7370 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7371 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7373 lock_ReleaseMutex(&fidp->mx);
7374 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7375 fidp->NTopen_dscp, fidp->NTopen_pathp,
7378 lock_ReleaseMutex(&fidp->mx);
7382 if (smb_AsyncStore > 0) {
7386 lock_ObtainWrite(&scp->rw);
7387 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7389 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7390 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7392 lock_ReleaseWrite(&scp->rw);
7393 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7394 writeBackOffset.HighPart,
7395 smb_AsyncStoreSize, 0, userp);
7396 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7399 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7403 cm_ReleaseSCache(scp);
7406 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7407 fidp->fid, code, *writtenp);
7412 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7415 unsigned short count;
7417 unsigned short hint;
7418 long written = 0, total_written = 0;
7421 smb_t* smbp = (smb_t*) inp;
7425 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7427 int inDataBlockCount;
7429 fd = smb_GetSMBParm(inp, 0);
7430 count = smb_GetSMBParm(inp, 1);
7431 offset.HighPart = 0; /* too bad */
7432 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7433 hint = smb_GetSMBParm(inp, 4);
7435 op = smb_GetSMBData(inp, NULL);
7436 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7438 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7439 fd, offset.LowPart, count);
7441 fd = smb_ChainFID(fd, inp);
7442 fidp = smb_FindFID(vcp, fd, 0);
7444 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7446 return CM_ERROR_BADFD;
7449 lock_ObtainMutex(&fidp->mx);
7450 if (fidp->flags & SMB_FID_IOCTL) {
7451 lock_ReleaseMutex(&fidp->mx);
7452 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7453 smb_ReleaseFID(fidp);
7454 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7458 if (fidp->flags & SMB_FID_RPC) {
7459 lock_ReleaseMutex(&fidp->mx);
7460 code = smb_RPCWrite(fidp, vcp, inp, outp);
7461 smb_ReleaseFID(fidp);
7462 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7467 lock_ReleaseMutex(&fidp->mx);
7468 smb_ReleaseFID(fidp);
7469 return CM_ERROR_BADFD;
7472 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7473 lock_ReleaseMutex(&fidp->mx);
7474 smb_CloseFID(vcp, fidp, NULL, 0);
7475 smb_ReleaseFID(fidp);
7476 return CM_ERROR_NOSUCHFILE;
7481 lock_ReleaseMutex(&fidp->mx);
7482 userp = smb_GetUserFromVCP(vcp, inp);
7486 LARGE_INTEGER LOffset;
7487 LARGE_INTEGER LLength;
7490 key = cm_GenerateKey(vcp->vcID, pid, fd);
7492 LOffset.HighPart = offset.HighPart;
7493 LOffset.LowPart = offset.LowPart;
7494 LLength.HighPart = 0;
7495 LLength.LowPart = count;
7497 lock_ObtainWrite(&scp->rw);
7498 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7499 lock_ReleaseWrite(&scp->rw);
7502 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7507 /* special case: 0 bytes transferred means truncate to this position */
7511 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7515 truncAttr.mask = CM_ATTRMASK_LENGTH;
7516 truncAttr.length.LowPart = offset.LowPart;
7517 truncAttr.length.HighPart = 0;
7518 lock_ObtainMutex(&fidp->mx);
7519 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7520 fidp->flags |= SMB_FID_LENGTHSETDONE;
7521 lock_ReleaseMutex(&fidp->mx);
7522 smb_SetSMBParm(outp, 0, 0 /* count */);
7523 smb_SetSMBDataLength(outp, 0);
7528 * Work around bug in NT client
7530 * When copying a file, the NT client should first copy the data,
7531 * then copy the last write time. But sometimes the NT client does
7532 * these in the wrong order, so the data copies would inadvertently
7533 * cause the last write time to be overwritten. We try to detect this,
7534 * and don't set client mod time if we think that would go against the
7537 lock_ObtainMutex(&fidp->mx);
7538 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7539 lock_ObtainWrite(&fidp->scp->rw);
7540 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7541 fidp->scp->clientModTime = time(NULL);
7542 lock_ReleaseWrite(&fidp->scp->rw);
7544 lock_ReleaseMutex(&fidp->mx);
7547 while ( code == 0 && count > 0 ) {
7548 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7549 if (code == 0 && written == 0)
7550 code = CM_ERROR_PARTIALWRITE;
7552 offset = LargeIntegerAdd(offset,
7553 ConvertLongToLargeInteger(written));
7554 count -= (unsigned short)written;
7555 total_written += written;
7559 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7560 total_written, code);
7562 /* set the packet data length to 3 bytes for the data block header,
7563 * plus the size of the data.
7565 smb_SetSMBParm(outp, 0, total_written);
7566 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7567 smb_SetSMBParm(outp, 3, hint);
7568 smb_SetSMBDataLength(outp, 0);
7571 smb_ReleaseFID(fidp);
7572 cm_ReleaseUser(userp);
7573 cm_ReleaseSCache(scp);
7578 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7579 NCB *ncbp, raw_write_cont_t *rwcp)
7588 fd = smb_GetSMBParm(inp, 0);
7589 fidp = smb_FindFID(vcp, fd, 0);
7591 lock_ObtainMutex(&fidp->mx);
7593 lock_ReleaseMutex(&fidp->mx);
7594 smb_ReleaseFID(fidp);
7598 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7599 lock_ReleaseMutex(&fidp->mx);
7600 smb_CloseFID(vcp, fidp, NULL, 0);
7601 smb_ReleaseFID(fidp);
7604 lock_ReleaseMutex(&fidp->mx);
7606 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7607 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7609 userp = smb_GetUserFromVCP(vcp, inp);
7612 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7614 if (rwcp->writeMode & 0x1) { /* synchronous */
7617 smb_FormatResponsePacket(vcp, inp, outp);
7618 op = (smb_t *) outp;
7619 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7620 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7621 smb_SetSMBDataLength(outp, 0);
7622 smb_SendPacket(vcp, outp);
7623 smb_FreePacket(outp);
7625 else { /* asynchronous */
7626 lock_ObtainMutex(&fidp->mx);
7627 fidp->raw_writers--;
7628 if (fidp->raw_writers == 0)
7629 thrd_SetEvent(fidp->raw_write_event);
7630 lock_ReleaseMutex(&fidp->mx);
7633 /* Give back raw buffer */
7634 lock_ObtainMutex(&smb_RawBufLock);
7635 *((char **)rawBuf) = smb_RawBufs;
7636 smb_RawBufs = rawBuf;
7637 lock_ReleaseMutex(&smb_RawBufLock);
7639 smb_ReleaseFID(fidp);
7640 cm_ReleaseUser(userp);
7643 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7648 /* SMB_COM_WRITE_RAW */
7649 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7652 long count, written = 0, total_written = 0;
7656 smb_t *smbp = (smb_t*) inp;
7661 unsigned short writeMode;
7663 fd = smb_GetSMBParm(inp, 0);
7664 totalCount = smb_GetSMBParm(inp, 1);
7665 count = smb_GetSMBParm(inp, 10);
7666 writeMode = smb_GetSMBParm(inp, 7);
7668 op = (char *) inp->data;
7669 op += smb_GetSMBParm(inp, 11);
7671 offset.HighPart = 0;
7672 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7674 if (*inp->wctp == 14) {
7675 /* we received a 64-bit file offset */
7676 #ifdef AFS_LARGEFILES
7677 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7679 if (LargeIntegerLessThanZero(offset)) {
7681 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7682 offset.HighPart, offset.LowPart);
7683 return CM_ERROR_BADSMB;
7686 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7688 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7689 return CM_ERROR_BADSMB;
7692 offset.HighPart = 0;
7695 offset.HighPart = 0; /* 32-bit file offset */
7699 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7700 fd, offset.HighPart, offset.LowPart, count);
7702 " WriteRaw WriteMode 0x%x",
7705 fd = smb_ChainFID(fd, inp);
7706 fidp = smb_FindFID(vcp, fd, 0);
7708 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7710 return CM_ERROR_BADFD;
7712 lock_ObtainMutex(&fidp->mx);
7714 lock_ReleaseMutex(&fidp->mx);
7715 smb_ReleaseFID(fidp);
7716 return CM_ERROR_BADFD;
7719 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7720 lock_ReleaseMutex(&fidp->mx);
7721 smb_CloseFID(vcp, fidp, NULL, 0);
7722 smb_ReleaseFID(fidp);
7723 return CM_ERROR_NOSUCHFILE;
7728 lock_ReleaseMutex(&fidp->mx);
7733 LARGE_INTEGER LOffset;
7734 LARGE_INTEGER LLength;
7737 key = cm_GenerateKey(vcp->vcID, pid, fd);
7739 LOffset.HighPart = offset.HighPart;
7740 LOffset.LowPart = offset.LowPart;
7741 LLength.HighPart = 0;
7742 LLength.LowPart = count;
7744 lock_ObtainWrite(&scp->rw);
7745 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7746 lock_ReleaseWrite(&scp->rw);
7749 cm_ReleaseSCache(scp);
7750 smb_ReleaseFID(fidp);
7755 userp = smb_GetUserFromVCP(vcp, inp);
7758 * Work around bug in NT client
7760 * When copying a file, the NT client should first copy the data,
7761 * then copy the last write time. But sometimes the NT client does
7762 * these in the wrong order, so the data copies would inadvertently
7763 * cause the last write time to be overwritten. We try to detect this,
7764 * and don't set client mod time if we think that would go against the
7767 lock_ObtainMutex(&fidp->mx);
7768 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7769 lock_ObtainWrite(&fidp->scp->rw);
7770 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7771 fidp->scp->clientModTime = time(NULL);
7772 lock_ReleaseWrite(&fidp->scp->rw);
7774 lock_ReleaseMutex(&fidp->mx);
7777 while ( code == 0 && count > 0 ) {
7778 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7779 if (code == 0 && written == 0)
7780 code = CM_ERROR_PARTIALWRITE;
7782 offset = LargeIntegerAdd(offset,
7783 ConvertLongToLargeInteger(written));
7786 total_written += written;
7790 /* Get a raw buffer */
7793 lock_ObtainMutex(&smb_RawBufLock);
7795 /* Get a raw buf, from head of list */
7796 rawBuf = smb_RawBufs;
7797 smb_RawBufs = *(char **)smb_RawBufs;
7800 code = CM_ERROR_USESTD;
7802 lock_ReleaseMutex(&smb_RawBufLock);
7805 /* Don't allow a premature Close */
7806 if (code == 0 && (writeMode & 1) == 0) {
7807 lock_ObtainMutex(&fidp->mx);
7808 fidp->raw_writers++;
7809 thrd_ResetEvent(fidp->raw_write_event);
7810 lock_ReleaseMutex(&fidp->mx);
7813 smb_ReleaseFID(fidp);
7814 cm_ReleaseUser(userp);
7815 cm_ReleaseSCache(scp);
7818 smb_SetSMBParm(outp, 0, total_written);
7819 smb_SetSMBDataLength(outp, 0);
7820 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7825 offset = LargeIntegerAdd(offset,
7826 ConvertLongToLargeInteger(count));
7830 rwcp->offset.HighPart = offset.HighPart;
7831 rwcp->offset.LowPart = offset.LowPart;
7832 rwcp->count = totalCount - count;
7833 rwcp->writeMode = writeMode;
7834 rwcp->alreadyWritten = total_written;
7836 /* set the packet data length to 3 bytes for the data block header,
7837 * plus the size of the data.
7839 smb_SetSMBParm(outp, 0, 0xffff);
7840 smb_SetSMBDataLength(outp, 0);
7846 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7849 long count, finalCount;
7853 smb_t *smbp = (smb_t*) inp;
7859 fd = smb_GetSMBParm(inp, 0);
7860 count = smb_GetSMBParm(inp, 1);
7861 offset.HighPart = 0; /* too bad */
7862 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7864 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7865 fd, offset.LowPart, count);
7867 fd = smb_ChainFID(fd, inp);
7868 fidp = smb_FindFID(vcp, fd, 0);
7870 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7872 return CM_ERROR_BADFD;
7874 lock_ObtainMutex(&fidp->mx);
7875 if (fidp->flags & SMB_FID_IOCTL) {
7876 lock_ReleaseMutex(&fidp->mx);
7877 code = smb_IoctlRead(fidp, vcp, inp, outp);
7878 smb_ReleaseFID(fidp);
7882 if (fidp->flags & SMB_FID_RPC) {
7883 lock_ReleaseMutex(&fidp->mx);
7884 code = smb_RPCRead(fidp, vcp, inp, outp);
7885 smb_ReleaseFID(fidp);
7890 lock_ReleaseMutex(&fidp->mx);
7891 smb_ReleaseFID(fidp);
7892 return CM_ERROR_BADFD;
7895 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7896 lock_ReleaseMutex(&fidp->mx);
7897 smb_CloseFID(vcp, fidp, NULL, 0);
7898 smb_ReleaseFID(fidp);
7899 return CM_ERROR_NOSUCHFILE;
7904 lock_ReleaseMutex(&fidp->mx);
7907 LARGE_INTEGER LOffset, LLength;
7911 key = cm_GenerateKey(vcp->vcID, pid, fd);
7913 LOffset.HighPart = 0;
7914 LOffset.LowPart = offset.LowPart;
7915 LLength.HighPart = 0;
7916 LLength.LowPart = count;
7918 lock_ObtainWrite(&scp->rw);
7919 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7920 lock_ReleaseWrite(&scp->rw);
7923 cm_ReleaseSCache(scp);
7924 smb_ReleaseFID(fidp);
7928 userp = smb_GetUserFromVCP(vcp, inp);
7930 /* remember this for final results */
7931 smb_SetSMBParm(outp, 0, count);
7932 smb_SetSMBParm(outp, 1, 0);
7933 smb_SetSMBParm(outp, 2, 0);
7934 smb_SetSMBParm(outp, 3, 0);
7935 smb_SetSMBParm(outp, 4, 0);
7937 /* set the packet data length to 3 bytes for the data block header,
7938 * plus the size of the data.
7940 smb_SetSMBDataLength(outp, count+3);
7942 /* get op ptr after putting in the parms, since otherwise we don't
7943 * know where the data really is.
7945 op = smb_GetSMBData(outp, NULL);
7947 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7948 *op++ = 1; /* data block marker */
7949 *op++ = (unsigned char) (count & 0xff);
7950 *op++ = (unsigned char) ((count >> 8) & 0xff);
7952 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7954 /* fix some things up */
7955 smb_SetSMBParm(outp, 0, finalCount);
7956 smb_SetSMBDataLength(outp, finalCount+3);
7958 smb_ReleaseFID(fidp);
7960 cm_ReleaseUser(userp);
7961 cm_ReleaseSCache(scp);
7965 /* SMB_COM_CREATE_DIRECTORY */
7966 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7968 clientchar_t *pathp;
7973 cm_scache_t *dscp; /* dir we're dealing with */
7974 cm_scache_t *scp; /* file we're creating */
7976 int initialModeBits;
7977 clientchar_t *lastNamep;
7979 clientchar_t *tidPathp;
7986 /* compute initial mode bits based on read-only flag in attributes */
7987 initialModeBits = 0777;
7989 tp = smb_GetSMBData(inp, NULL);
7990 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7992 return CM_ERROR_BADSMB;
7994 spacep = inp->spacep;
7995 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7997 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7998 return CM_ERROR_EXISTS;
8000 userp = smb_GetUserFromVCP(vcp, inp);
8002 caseFold = CM_FLAG_CASEFOLD;
8004 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8006 cm_ReleaseUser(userp);
8007 return CM_ERROR_NOSUCHPATH;
8010 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
8011 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8012 userp, tidPathp, &req, &dscp);
8015 cm_ReleaseUser(userp);
8020 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8021 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8022 cm_ReleaseSCache(dscp);
8023 cm_ReleaseUser(userp);
8024 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8025 return CM_ERROR_PATH_NOT_COVERED;
8027 return CM_ERROR_NOSUCHPATH;
8029 #endif /* DFS_SUPPORT */
8031 /* otherwise, scp points to the parent directory. Do a lookup, and
8032 * fail if we find it. Otherwise, we do the create.
8038 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8039 if (scp) cm_ReleaseSCache(scp);
8040 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8041 if (code == 0) code = CM_ERROR_EXISTS;
8042 cm_ReleaseSCache(dscp);
8043 cm_ReleaseUser(userp);
8047 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8048 setAttr.clientModTime = time(NULL);
8049 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8050 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8051 smb_NotifyChange(FILE_ACTION_ADDED,
8052 FILE_NOTIFY_CHANGE_DIR_NAME,
8053 dscp, lastNamep, NULL, TRUE);
8055 /* we don't need this any longer */
8056 cm_ReleaseSCache(dscp);
8059 /* something went wrong creating or truncating the file */
8060 cm_ReleaseUser(userp);
8064 /* otherwise we succeeded */
8065 smb_SetSMBDataLength(outp, 0);
8066 cm_ReleaseUser(userp);
8071 BOOL smb_IsLegalFilename(clientchar_t *filename)
8074 * Find the longest substring of filename that does not contain
8075 * any of the chars in illegalChars. If that substring is less
8076 * than the length of the whole string, then one or more of the
8077 * illegal chars is in filename.
8079 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8085 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8086 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8088 clientchar_t *pathp;
8094 cm_scache_t *dscp; /* dir we're dealing with */
8095 cm_scache_t *scp; /* file we're creating */
8097 int initialModeBits;
8100 clientchar_t *lastNamep;
8103 clientchar_t *tidPathp;
8105 int created = 0; /* the file was new */
8110 excl = (inp->inCom == 0x03)? 0 : 1;
8112 attributes = smb_GetSMBParm(inp, 0);
8113 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8115 /* compute initial mode bits based on read-only flag in attributes */
8116 initialModeBits = 0666;
8117 if (attributes & SMB_ATTR_READONLY)
8118 initialModeBits &= ~0222;
8120 tp = smb_GetSMBData(inp, NULL);
8121 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8123 return CM_ERROR_BADSMB;
8125 spacep = inp->spacep;
8126 /* smb_StripLastComponent will strip "::$DATA" if present */
8127 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8129 if (!cm_IsValidClientString(pathp)) {
8131 clientchar_t * hexp;
8133 hexp = cm_GetRawCharsAlloc(pathp, -1);
8134 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8135 osi_LogSaveClientString(smb_logp, hexp));
8139 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8141 return CM_ERROR_BADNTFILENAME;
8144 userp = smb_GetUserFromVCP(vcp, inp);
8146 caseFold = CM_FLAG_CASEFOLD;
8148 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8150 cm_ReleaseUser(userp);
8151 return CM_ERROR_NOSUCHPATH;
8153 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8154 userp, tidPathp, &req, &dscp);
8157 cm_ReleaseUser(userp);
8162 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8163 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8164 cm_ReleaseSCache(dscp);
8165 cm_ReleaseUser(userp);
8166 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8167 return CM_ERROR_PATH_NOT_COVERED;
8169 return CM_ERROR_NOSUCHPATH;
8171 #endif /* DFS_SUPPORT */
8173 /* otherwise, scp points to the parent directory. Do a lookup, and
8174 * truncate the file if we find it, otherwise we create the file.
8181 if (!smb_IsLegalFilename(lastNamep))
8182 return CM_ERROR_BADNTFILENAME;
8184 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8185 #ifdef DEBUG_VERBOSE
8188 hexp = osi_HexifyString( lastNamep );
8189 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8194 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8195 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8196 cm_ReleaseSCache(dscp);
8197 cm_ReleaseUser(userp);
8201 /* if we get here, if code is 0, the file exists and is represented by
8202 * scp. Otherwise, we have to create it.
8206 /* oops, file shouldn't be there */
8207 cm_ReleaseSCache(dscp);
8208 cm_ReleaseSCache(scp);
8209 cm_ReleaseUser(userp);
8210 return CM_ERROR_EXISTS;
8213 setAttr.mask = CM_ATTRMASK_LENGTH;
8214 setAttr.length.LowPart = 0;
8215 setAttr.length.HighPart = 0;
8216 code = cm_SetAttr(scp, &setAttr, userp, &req);
8219 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8220 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8221 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8225 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8226 smb_NotifyChange(FILE_ACTION_ADDED,
8227 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8228 dscp, lastNamep, NULL, TRUE);
8229 } else if (!excl && code == CM_ERROR_EXISTS) {
8230 /* not an exclusive create, and someone else tried
8231 * creating it already, then we open it anyway. We
8232 * don't bother retrying after this, since if this next
8233 * fails, that means that the file was deleted after
8234 * we started this call.
8236 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8239 setAttr.mask = CM_ATTRMASK_LENGTH;
8240 setAttr.length.LowPart = 0;
8241 setAttr.length.HighPart = 0;
8242 code = cm_SetAttr(scp, &setAttr, userp, &req);
8247 /* we don't need this any longer */
8248 cm_ReleaseSCache(dscp);
8251 /* something went wrong creating or truncating the file */
8252 if (scp) cm_ReleaseSCache(scp);
8253 cm_ReleaseUser(userp);
8257 /* make sure we only open files */
8258 if (scp->fileType != CM_SCACHETYPE_FILE) {
8259 cm_ReleaseSCache(scp);
8260 cm_ReleaseUser(userp);
8261 return CM_ERROR_ISDIR;
8264 /* now all we have to do is open the file itself */
8265 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8266 osi_assertx(fidp, "null smb_fid_t");
8270 lock_ObtainMutex(&fidp->mx);
8271 /* always create it open for read/write */
8272 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8274 /* remember that the file was newly created */
8276 fidp->flags |= SMB_FID_CREATED;
8278 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8280 /* save a pointer to the vnode */
8282 lock_ObtainWrite(&scp->rw);
8283 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8284 lock_ReleaseWrite(&scp->rw);
8287 fidp->userp = userp;
8288 lock_ReleaseMutex(&fidp->mx);
8290 smb_SetSMBParm(outp, 0, fidp->fid);
8291 smb_SetSMBDataLength(outp, 0);
8293 cm_Open(scp, 0, userp);
8295 smb_ReleaseFID(fidp);
8296 cm_ReleaseUser(userp);
8297 /* leave scp held since we put it in fidp->scp */
8302 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8305 osi_hyper_t new_offset;
8316 fd = smb_GetSMBParm(inp, 0);
8317 whence = smb_GetSMBParm(inp, 1);
8318 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8320 /* try to find the file descriptor */
8321 fd = smb_ChainFID(fd, inp);
8322 fidp = smb_FindFID(vcp, fd, 0);
8324 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8326 return CM_ERROR_BADFD;
8328 lock_ObtainMutex(&fidp->mx);
8329 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8330 lock_ReleaseMutex(&fidp->mx);
8331 smb_ReleaseFID(fidp);
8332 return CM_ERROR_BADFD;
8335 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8336 lock_ReleaseMutex(&fidp->mx);
8337 smb_CloseFID(vcp, fidp, NULL, 0);
8338 smb_ReleaseFID(fidp);
8339 return CM_ERROR_NOSUCHFILE;
8342 lock_ReleaseMutex(&fidp->mx);
8344 userp = smb_GetUserFromVCP(vcp, inp);
8346 lock_ObtainMutex(&fidp->mx);
8349 lock_ReleaseMutex(&fidp->mx);
8350 lock_ObtainWrite(&scp->rw);
8351 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8352 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8354 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8356 /* offset from current offset */
8357 new_offset = LargeIntegerAdd(fidp->offset,
8358 ConvertLongToLargeInteger(offset));
8360 else if (whence == 2) {
8361 /* offset from current EOF */
8362 new_offset = LargeIntegerAdd(scp->length,
8363 ConvertLongToLargeInteger(offset));
8365 new_offset = ConvertLongToLargeInteger(offset);
8368 fidp->offset = new_offset;
8369 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8370 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8371 smb_SetSMBDataLength(outp, 0);
8373 lock_ReleaseWrite(&scp->rw);
8374 smb_ReleaseFID(fidp);
8375 cm_ReleaseSCache(scp);
8376 cm_ReleaseUser(userp);
8380 /* dispatch all of the requests received in a packet. Due to chaining, this may
8381 * be more than one request.
8383 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8384 NCB *ncbp, raw_write_cont_t *rwcp)
8388 unsigned long code = 0;
8389 unsigned char *outWctp;
8390 int nparms; /* # of bytes of parameters */
8392 int nbytes; /* bytes of data, excluding count */
8395 unsigned short errCode;
8396 unsigned long NTStatus;
8398 unsigned char errClass;
8399 unsigned int oldGen;
8400 DWORD oldTime, newTime;
8402 /* get easy pointer to the data */
8403 smbp = (smb_t *) inp->data;
8405 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8406 /* setup the basic parms for the initial request in the packet */
8407 inp->inCom = smbp->com;
8408 inp->wctp = &smbp->wct;
8410 inp->ncb_length = ncbp->ncb_length;
8415 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8416 /* log it and discard it */
8417 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8418 __FILE__, __LINE__, ncbp->ncb_length);
8419 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8423 /* We are an ongoing op */
8424 thrd_Increment(&ongoingOps);
8426 /* set up response packet for receiving output */
8427 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8428 smb_FormatResponsePacket(vcp, inp, outp);
8429 outWctp = outp->wctp;
8431 /* Remember session generation number and time */
8432 oldGen = sessionGen;
8433 oldTime = GetTickCount();
8435 while (inp->inCom != 0xff) {
8436 dp = &smb_dispatchTable[inp->inCom];
8438 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8439 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8440 code = outp->resumeCode;
8444 /* process each request in the packet; inCom, wctp and inCount
8445 * are already set up.
8447 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8450 /* now do the dispatch */
8451 /* start by formatting the response record a little, as a default */
8452 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8454 outWctp[1] = 0xff; /* no operation */
8455 outWctp[2] = 0; /* padding */
8460 /* not a chained request, this is a more reasonable default */
8461 outWctp[0] = 0; /* wct of zero */
8462 outWctp[1] = 0; /* and bcc (word) of zero */
8466 /* once set, stays set. Doesn't matter, since we never chain
8467 * "no response" calls.
8469 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8473 /* we have a recognized operation */
8474 char * opName = myCrt_Dispatch(inp->inCom);
8477 smbp = (smb_t *) inp;
8479 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8480 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8481 if (inp->inCom == 0x1d) {
8483 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8485 code = (*(dp->procp)) (vcp, inp, outp);
8487 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8488 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8490 newTime = GetTickCount();
8491 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8492 opName, smbp->mid, newTime - oldTime);
8495 if ( code == CM_ERROR_BADSMB ||
8496 code == CM_ERROR_BADOP )
8498 #endif /* LOG_PACKET */
8500 /* ReceiveV3Tran2A handles its own logging */
8501 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8504 clientchar_t *treepath = NULL; /* do not free */
8505 clientchar_t *pathname = NULL;
8506 cm_fid_t afid = {0,0,0,0,0};
8508 uidp = smb_FindUID(vcp, smbp->uid, 0);
8509 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8510 fidp = smb_FindFID(vcp, inp->fid, 0);
8513 lock_ObtainMutex(&fidp->mx);
8514 if (fidp->NTopen_pathp)
8515 pathname = fidp->NTopen_pathp;
8517 afid = fidp->scp->fid;
8519 if (inp->stringsp->wdata)
8520 pathname = inp->stringsp->wdata;
8523 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)",
8524 opName, newTime - oldTime,
8525 smbp->uid, uidp ? uidp->unp->name : NULL,
8526 smbp->pid, smbp->mid, smbp->tid,
8529 afid.cell, afid.volume, afid.vnode, afid.unique);
8532 lock_ReleaseMutex(&fidp->mx);
8535 smb_ReleaseUID(uidp);
8537 smb_ReleaseFID(fidp);
8540 if (oldGen != sessionGen) {
8541 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8542 newTime - oldTime, ncbp->ncb_length);
8543 osi_Log3(smb_logp, "Request %s straddled session startup, "
8544 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8547 FreeSMBStrings(inp);
8549 /* bad opcode, fail the request, after displaying it */
8550 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8553 #endif /* LOG_PACKET */
8556 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8557 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8558 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8559 if (code == IDCANCEL)
8562 code = CM_ERROR_BADOP;
8565 /* catastrophic failure: log as much as possible */
8566 if (code == CM_ERROR_BADSMB) {
8567 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8571 #endif /* LOG_PACKET */
8572 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8575 code = CM_ERROR_INVAL;
8578 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8579 thrd_Decrement(&ongoingOps);
8584 /* now, if we failed, turn the current response into an empty
8585 * one, and fill in the response packet's error code.
8588 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8589 smb_MapNTError(code, &NTStatus);
8590 outWctp = outp->wctp;
8591 smbp = (smb_t *) &outp->data;
8592 if (code != CM_ERROR_PARTIALWRITE
8593 && code != CM_ERROR_BUFFERTOOSMALL
8594 && code != CM_ERROR_GSSCONTINUE) {
8595 /* nuke wct and bcc. For a partial
8596 * write or an in-process authentication handshake,
8597 * assume they're OK.
8603 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8604 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8605 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8606 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8607 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8611 smb_MapCoreError(code, vcp, &errCode, &errClass);
8612 outWctp = outp->wctp;
8613 smbp = (smb_t *) &outp->data;
8614 if (code != CM_ERROR_PARTIALWRITE) {
8615 /* nuke wct and bcc. For a partial
8616 * write, assume they're OK.
8622 smbp->errLow = (unsigned char) (errCode & 0xff);
8623 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8624 smbp->rcls = errClass;
8627 } /* error occurred */
8629 /* if we're here, we've finished one request. Look to see if
8630 * this is a chained opcode. If it is, setup things to process
8631 * the chained request, and setup the output buffer to hold the
8632 * chained response. Start by finding the next input record.
8634 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8635 break; /* not a chained req */
8636 tp = inp->wctp; /* points to start of last request */
8637 /* in a chained request, the first two
8638 * parm fields are required, and are
8639 * AndXCommand/AndXReserved and
8641 if (tp[0] < 2) break;
8642 if (tp[1] == 0xff) break; /* no more chained opcodes */
8644 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8647 /* and now append the next output request to the end of this
8648 * last request. Begin by finding out where the last response
8649 * ends, since that's where we'll put our new response.
8651 outWctp = outp->wctp; /* ptr to out parameters */
8652 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8653 nparms = outWctp[0] << 1;
8654 tp = outWctp + nparms + 1; /* now points to bcc field */
8655 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8656 tp += 2 /* for the count itself */ + nbytes;
8657 /* tp now points to the new output record; go back and patch the
8658 * second parameter (off2) to point to the new record.
8660 temp = (unsigned int)(tp - outp->data);
8661 outWctp[3] = (unsigned char) (temp & 0xff);
8662 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8663 outWctp[2] = 0; /* padding */
8664 outWctp[1] = inp->inCom; /* next opcode */
8666 /* finally, setup for the next iteration */
8669 } /* while loop over all requests in the packet */
8671 /* now send the output packet, and return */
8673 smb_SendPacket(vcp, outp);
8674 thrd_Decrement(&ongoingOps);
8679 /* Wait for Netbios() calls to return, and make the results available to server
8680 * threads. Note that server threads can't wait on the NCBevents array
8681 * themselves, because NCB events are manual-reset, and the servers would race
8682 * each other to reset them.
8684 void smb_ClientWaiter(void *parmp)
8689 while (smbShutdownFlag == 0) {
8690 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8692 if (code == WAIT_OBJECT_0)
8695 /* error checking */
8696 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8698 int abandonIdx = code - WAIT_ABANDONED_0;
8699 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8702 if (code == WAIT_IO_COMPLETION)
8704 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8708 if (code == WAIT_TIMEOUT)
8710 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8713 if (code == WAIT_FAILED)
8715 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8718 idx = code - WAIT_OBJECT_0;
8720 /* check idx range! */
8721 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8723 /* this is fatal - log as much as possible */
8724 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8725 osi_assertx(0, "invalid index");
8728 thrd_ResetEvent(NCBevents[idx]);
8729 thrd_SetEvent(NCBreturns[0][idx]);
8734 * Try to have one NCBRECV request waiting for every live session. Not more
8735 * than one, because if there is more than one, it's hard to handle Write Raw.
8737 void smb_ServerWaiter(void *parmp)
8740 int idx_session, idx_NCB;
8743 while (smbShutdownFlag == 0) {
8745 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8747 if (code == WAIT_OBJECT_0)
8750 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8752 int abandonIdx = code - WAIT_ABANDONED_0;
8753 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8756 if (code == WAIT_IO_COMPLETION)
8758 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8762 if (code == WAIT_TIMEOUT)
8764 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8767 if (code == WAIT_FAILED)
8769 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8772 idx_session = code - WAIT_OBJECT_0;
8774 /* check idx range! */
8775 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8777 /* this is fatal - log as much as possible */
8778 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8779 osi_assertx(0, "invalid index");
8784 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8786 if (code == WAIT_OBJECT_0) {
8787 if (smbShutdownFlag == 1)
8793 /* error checking */
8794 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8796 int abandonIdx = code - WAIT_ABANDONED_0;
8797 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8800 if (code == WAIT_IO_COMPLETION)
8802 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8806 if (code == WAIT_TIMEOUT)
8808 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8811 if (code == WAIT_FAILED)
8813 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8816 idx_NCB = code - WAIT_OBJECT_0;
8818 /* check idx range! */
8819 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8821 /* this is fatal - log as much as possible */
8822 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8823 osi_assertx(0, "invalid index");
8826 /* Link them together */
8827 NCBsessions[idx_NCB] = idx_session;
8830 ncbp = NCBs[idx_NCB];
8831 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8832 ncbp->ncb_command = NCBRECV | ASYNCH;
8833 ncbp->ncb_lana_num = lanas[idx_session];
8834 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8835 ncbp->ncb_event = NCBevents[idx_NCB];
8836 ncbp->ncb_length = SMB_PACKETSIZE;
8842 * The top level loop for handling SMB request messages. Each server thread
8843 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8844 * NCB and buffer for the incoming request are loaned to us.
8846 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8847 * to immediately send a request for the rest of the data. This must come
8848 * before any other traffic for that session, so we delay setting the session
8849 * event until that data has come in.
8851 void smb_Server(VOID *parmp)
8853 INT_PTR myIdx = (INT_PTR) parmp;
8857 smb_packet_t *outbufp;
8859 int idx_NCB, idx_session;
8861 smb_vc_t *vcp = NULL;
8863 extern void rx_StartClientThread(void);
8865 rx_StartClientThread();
8867 outncbp = smb_GetNCB();
8868 outbufp = smb_GetPacket();
8869 outbufp->ncbp = outncbp;
8877 cm_ResetServerPriority();
8879 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8882 /* terminate silently if shutdown flag is set */
8883 if (code == WAIT_OBJECT_0) {
8884 if (smbShutdownFlag == 1) {
8885 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8891 /* error checking */
8892 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8894 int abandonIdx = code - WAIT_ABANDONED_0;
8895 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8898 if (code == WAIT_IO_COMPLETION)
8900 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8904 if (code == WAIT_TIMEOUT)
8906 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8909 if (code == WAIT_FAILED)
8911 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8914 idx_NCB = code - WAIT_OBJECT_0;
8916 /* check idx range! */
8917 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8919 /* this is fatal - log as much as possible */
8920 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8921 osi_assertx(0, "invalid index");
8924 ncbp = NCBs[idx_NCB];
8925 idx_session = NCBsessions[idx_NCB];
8926 rc = ncbp->ncb_retcode;
8928 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8929 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8933 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8937 /* Can this happen? Or is it just my UNIX paranoia? */
8938 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8943 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8946 /* Client closed session */
8947 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8949 lock_ObtainMutex(&vcp->mx);
8950 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8951 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8953 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8954 lock_ReleaseMutex(&vcp->mx);
8955 lock_ObtainWrite(&smb_globalLock);
8956 dead_sessions[vcp->session] = TRUE;
8957 lock_ReleaseWrite(&smb_globalLock);
8959 lock_ReleaseMutex(&vcp->mx);
8961 smb_CleanupDeadVC(vcp);
8968 /* Treat as transient error */
8969 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8972 "dispatch smb recv failed, message incomplete, ncb_length %d",
8975 "SMB message incomplete, "
8976 "length %d", ncbp->ncb_length);
8979 * We used to discard the packet.
8980 * Instead, try handling it normally.
8984 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8988 /* A weird error code. Log it, sleep, and continue. */
8989 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8991 lock_ObtainMutex(&vcp->mx);
8992 if (vcp->errorCount++ > 3) {
8993 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8994 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8995 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8997 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8998 lock_ReleaseMutex(&vcp->mx);
8999 lock_ObtainWrite(&smb_globalLock);
9000 dead_sessions[vcp->session] = TRUE;
9001 lock_ReleaseWrite(&smb_globalLock);
9003 lock_ReleaseMutex(&vcp->mx);
9005 smb_CleanupDeadVC(vcp);
9011 lock_ReleaseMutex(&vcp->mx);
9015 thrd_SetEvent(SessionEvents[idx_session]);
9021 /* Success, so now dispatch on all the data in the packet */
9023 smb_concurrentCalls++;
9024 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9025 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9028 * If at this point vcp is NULL (implies that packet was invalid)
9029 * then we are in big trouble. This means either :
9030 * a) we have the wrong NCB.
9031 * b) Netbios screwed up the call.
9032 * c) The VC was already marked dead before we were able to
9034 * Obviously this implies that
9035 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9036 * lanas[idx_session] != ncbp->ncb_lana_num )
9037 * Either way, we can't do anything with this packet.
9038 * Log, sleep and resume.
9041 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9045 ncbp->ncb_lana_num);
9047 /* Also log in the trace log. */
9048 osi_Log4(smb_logp, "Server: VCP does not exist!"
9049 "LSNs[idx_session]=[%d],"
9050 "lanas[idx_session]=[%d],"
9051 "ncbp->ncb_lsn=[%d],"
9052 "ncbp->ncb_lana_num=[%d]",
9056 ncbp->ncb_lana_num);
9058 /* thrd_Sleep(1000); Don't bother sleeping */
9059 thrd_SetEvent(SessionEvents[idx_session]);
9060 smb_concurrentCalls--;
9064 cm_SetRequestStartTime();
9066 vcp->errorCount = 0;
9067 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9068 smbp = (smb_t *)bufp->data;
9075 if (smbp->com == 0x1d) {
9076 /* Special handling for Write Raw */
9077 raw_write_cont_t rwc;
9079 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9080 if (rwc.code == 0) {
9081 EVENT_HANDLE rwevent;
9082 char eventName[MAX_PATH];
9084 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9085 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9086 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9087 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9089 ncbp->ncb_command = NCBRECV | ASYNCH;
9090 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9091 ncbp->ncb_lana_num = vcp->lana;
9092 ncbp->ncb_buffer = rwc.buf;
9093 ncbp->ncb_length = 65535;
9094 ncbp->ncb_event = rwevent;
9096 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9097 thrd_CloseHandle(rwevent);
9099 thrd_SetEvent(SessionEvents[idx_session]);
9101 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9103 else if (smbp->com == 0xa0) {
9105 * Serialize the handling for NT Transact
9108 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9109 thrd_SetEvent(SessionEvents[idx_session]);
9111 thrd_SetEvent(SessionEvents[idx_session]);
9112 /* TODO: what else needs to be serialized? */
9113 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9117 __except( smb_ServerExceptionFilter() ) {
9121 smb_concurrentCalls--;
9124 thrd_SetEvent(NCBavails[idx_NCB]);
9129 smb_FreePacket(outbufp);
9131 smb_FreeNCB(outncbp);
9135 * Exception filter for the server threads. If an exception occurs in the
9136 * dispatch routines, which is where exceptions are most common, then do a
9137 * force trace and give control to upstream exception handlers. Useful for
9140 DWORD smb_ServerExceptionFilter(void) {
9141 /* While this is not the best time to do a trace, if it succeeds, then
9142 * we have a trace (assuming tracing was enabled). Otherwise, this should
9143 * throw a second exception.
9145 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9146 afsd_ForceTrace(TRUE);
9147 buf_ForceTrace(TRUE);
9148 return EXCEPTION_CONTINUE_SEARCH;
9152 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9153 * If the number of server threads is M, and the number of live sessions is
9154 * N, then the number of NCB's in use at any time either waiting for, or
9155 * holding, received messages is M + N, so that is how many NCB's get created.
9157 void InitNCBslot(int idx)
9159 struct smb_packet *bufp;
9160 EVENT_HANDLE retHandle;
9162 char eventName[MAX_PATH];
9164 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9166 NCBs[idx] = smb_GetNCB();
9167 sprintf(eventName,"NCBavails[%d]", idx);
9168 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9169 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9170 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9171 sprintf(eventName,"NCBevents[%d]", idx);
9172 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9173 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9174 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9175 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9176 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9177 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9178 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9179 for (i=0; i<smb_NumServerThreads; i++)
9180 NCBreturns[i][idx] = retHandle;
9181 bufp = smb_GetPacket();
9182 bufp->spacep = cm_GetSpace();
9186 /* listen for new connections */
9187 void smb_Listener(void *parmp)
9193 afs_uint32 session, thread;
9194 smb_vc_t *vcp = NULL;
9196 char rname[NCBNAMSZ+1];
9197 char cname[MAX_COMPUTERNAME_LENGTH+1];
9198 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9199 INT_PTR lana = (INT_PTR) parmp;
9200 char eventName[MAX_PATH];
9201 int bridgeCount = 0;
9202 int nowildCount = 0;
9204 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9205 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9206 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9207 thrd_ResetEvent(ListenerShutdown[lana]);
9209 ncbp = smb_GetNCB();
9211 /* retrieve computer name */
9212 GetComputerName(cname, &cnamelen);
9215 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9216 memset(ncbp, 0, sizeof(NCB));
9219 ncbp->ncb_command = NCBLISTEN;
9220 ncbp->ncb_rto = 0; /* No receive timeout */
9221 ncbp->ncb_sto = 0; /* No send timeout */
9223 /* pad out with spaces instead of null termination */
9224 len = (long)strlen(smb_localNamep);
9225 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9226 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9228 strcpy(ncbp->ncb_callname, "*");
9229 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9231 ncbp->ncb_lana_num = (UCHAR)lana;
9233 code = Netbios(ncbp);
9235 if (code == NRC_NAMERR) {
9236 /* An smb shutdown or Vista resume must have taken place */
9238 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9239 ncbp->ncb_lana_num);
9240 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9242 if (lock_TryMutex(&smb_StartedLock)) {
9243 lana_list.lana[i] = LANA_INVALID;
9244 lock_ReleaseMutex(&smb_StartedLock);
9247 } else if (code == NRC_BRIDGE || code != 0) {
9248 int lanaRemaining = 0;
9250 if (code == NRC_BRIDGE) {
9251 if (++bridgeCount <= 5) {
9252 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9255 } else if (code == NRC_NOWILD) {
9256 if (++nowildCount <= 5) {
9257 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9259 if (bridgeCount > 0) {
9260 memset(ncbp, 0, sizeof(*ncbp));
9261 ncbp->ncb_command = NCBADDNAME;
9262 ncbp->ncb_lana_num = (UCHAR)lana;
9263 /* pad out with spaces instead of null termination */
9264 len = (long)strlen(smb_localNamep);
9265 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9266 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9267 code = Netbios(ncbp);
9273 while (!lock_TryMutex(&smb_StartedLock)) {
9274 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9280 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9281 ncbp->ncb_lana_num, ncb_error_string(code));
9282 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9283 ncbp->ncb_lana_num, ncb_error_string(code));
9285 for (i = 0; i < lana_list.length; i++) {
9286 if (lana_list.lana[i] == lana) {
9287 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9288 lana_list.lana[i] = LANA_INVALID;
9290 if (lana_list.lana[i] != LANA_INVALID)
9294 if (lanaRemaining == 0) {
9295 cm_VolStatus_Network_Stopped(cm_NetbiosName
9300 smb_ListenerState = SMB_LISTENER_STOPPED;
9301 smb_LANadapter = LANA_INVALID;
9302 lana_list.length = 0;
9304 lock_ReleaseMutex(&smb_StartedLock);
9308 else if (code != 0) {
9309 char tbuffer[AFSPATHMAX];
9311 /* terminate silently if shutdown flag is set */
9312 while (!lock_TryMutex(&smb_StartedLock)) {
9313 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9319 "NCBLISTEN lana=%d failed with code %d [%s]",
9320 ncbp->ncb_lana_num, code, ncb_error_string(code));
9322 "Client exiting due to network failure. Please restart client.\n");
9325 "Client exiting due to network failure. Please restart client.\n"
9326 "NCBLISTEN lana=%d failed with code %d [%s]",
9327 ncbp->ncb_lana_num, code, ncb_error_string(code));
9329 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9330 MB_OK|MB_SERVICE_NOTIFICATION);
9331 osi_panic(tbuffer, __FILE__, __LINE__);
9333 lock_ReleaseMutex(&smb_StartedLock);
9338 /* a successful packet received. clear bridge error count */
9342 /* check for remote conns */
9343 /* first get remote name and insert null terminator */
9344 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9345 for (i=NCBNAMSZ; i>0; i--) {
9346 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9352 /* compare with local name */
9354 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9355 flags |= SMB_VCFLAG_REMOTECONN;
9358 lock_ObtainMutex(&smb_ListenerLock);
9360 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9361 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9363 /* now ncbp->ncb_lsn is the connection ID */
9364 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9365 if (vcp->session == 0) {
9366 /* New generation */
9367 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9370 /* Log session startup */
9372 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9373 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9374 #endif /* NOTSERVICE */
9375 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9376 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9378 if (reportSessionStartups) {
9379 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9382 lock_ObtainMutex(&vcp->mx);
9383 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9384 vcp->flags |= flags;
9385 lock_ReleaseMutex(&vcp->mx);
9387 /* Allocate slot in session arrays */
9388 /* Re-use dead session if possible, otherwise add one more */
9389 /* But don't look at session[0], it is reserved */
9390 lock_ObtainWrite(&smb_globalLock);
9391 for (session = 1; session < numSessions; session++) {
9392 if (dead_sessions[session]) {
9393 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9394 dead_sessions[session] = FALSE;
9398 lock_ReleaseWrite(&smb_globalLock);
9400 /* We are re-using an existing VC because the lsn and lana
9402 session = vcp->session;
9404 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9406 /* Log session startup */
9408 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9409 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9410 #endif /* NOTSERVICE */
9411 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9412 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9414 if (reportSessionStartups) {
9415 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9419 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9420 unsigned long code = CM_ERROR_ALLBUSY;
9421 smb_packet_t * outp = smb_GetPacket();
9422 unsigned char *outWctp;
9425 smb_FormatResponsePacket(vcp, NULL, outp);
9428 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9429 unsigned long NTStatus;
9430 smb_MapNTError(code, &NTStatus);
9431 outWctp = outp->wctp;
9432 smbp = (smb_t *) &outp->data;
9436 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9437 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9438 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9439 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9440 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9442 unsigned short errCode;
9443 unsigned char errClass;
9444 smb_MapCoreError(code, vcp, &errCode, &errClass);
9445 outWctp = outp->wctp;
9446 smbp = (smb_t *) &outp->data;
9450 smbp->errLow = (unsigned char) (errCode & 0xff);
9451 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9452 smbp->rcls = errClass;
9455 smb_SendPacket(vcp, outp);
9456 smb_FreePacket(outp);
9458 lock_ObtainMutex(&vcp->mx);
9459 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9460 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9462 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9463 lock_ReleaseMutex(&vcp->mx);
9464 lock_ObtainWrite(&smb_globalLock);
9465 dead_sessions[vcp->session] = TRUE;
9466 lock_ReleaseWrite(&smb_globalLock);
9467 smb_CleanupDeadVC(vcp);
9469 lock_ReleaseMutex(&vcp->mx);
9472 /* assert that we do not exceed the maximum number of sessions or NCBs.
9473 * we should probably want to wait for a session to be freed in case
9476 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9477 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9479 lock_ObtainMutex(&vcp->mx);
9480 vcp->session = session;
9481 lock_ReleaseMutex(&vcp->mx);
9482 lock_ObtainWrite(&smb_globalLock);
9483 LSNs[session] = ncbp->ncb_lsn;
9484 lanas[session] = ncbp->ncb_lana_num;
9485 lock_ReleaseWrite(&smb_globalLock);
9487 if (session == numSessions) {
9488 /* Add new NCB for new session */
9489 char eventName[MAX_PATH];
9491 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9493 InitNCBslot(numNCBs);
9494 lock_ObtainWrite(&smb_globalLock);
9496 lock_ReleaseWrite(&smb_globalLock);
9497 thrd_SetEvent(NCBavails[0]);
9498 thrd_SetEvent(NCBevents[0]);
9499 for (thread = 0; thread < smb_NumServerThreads; thread++)
9500 thrd_SetEvent(NCBreturns[thread][0]);
9501 /* Also add new session event */
9502 sprintf(eventName, "SessionEvents[%d]", session);
9503 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9504 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9505 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9506 lock_ObtainWrite(&smb_globalLock);
9508 lock_ReleaseWrite(&smb_globalLock);
9509 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9510 thrd_SetEvent(SessionEvents[0]);
9512 thrd_SetEvent(SessionEvents[session]);
9518 lock_ReleaseMutex(&smb_ListenerLock);
9519 } /* dispatch while loop */
9523 thrd_SetEvent(ListenerShutdown[lana]);
9528 configureBackConnectionHostNames(void)
9530 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9531 * there is a restriction on the use of SMB authentication on loopback connections.
9532 * There are two work arounds available:
9534 * (1) We can disable the check for matching host names. This does not
9536 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9537 * "DisableLoopbackCheck"=dword:00000001
9539 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9540 * does require a reboot:
9541 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9542 * "BackConnectionHostNames"=multi-sz
9544 * The algorithm will be:
9545 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9546 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9547 * (2b1) and check to see if DisableLoopbackCheck is set.
9548 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9549 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9550 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9551 * check for the UnsetDisableLoopbackCheck value.
9552 * If set, set the DisableLoopbackCheck flag to 0x0
9553 * and delete the UnsetDisableLoopbackCheck value
9555 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9556 * force Windows to use the loopback authentication mechanism for the specified
9559 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9560 * service session that set it.
9566 DWORD dwSize, dwAllocSize;
9568 PBYTE pHostNames = NULL, pName = NULL;
9569 BOOL bNameFound = FALSE;
9570 static BOOL bLoopbackCheckDisabled = FALSE;
9572 /* BackConnectionHostNames and DisableLoopbackCheck */
9573 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9574 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9577 &hkMSV10) == ERROR_SUCCESS )
9579 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9580 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9581 (dwType == REG_MULTI_SZ))
9583 dwAllocSize += 1 /* in case the source string is not nul terminated */
9584 + (DWORD)strlen(cm_NetbiosName) + 2;
9585 pHostNames = malloc(dwAllocSize);
9586 dwSize = dwAllocSize;
9587 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9588 pHostNames, &dwSize) == ERROR_SUCCESS)
9590 for (pName = pHostNames;
9591 (pName - pHostNames < (int) dwSize) && *pName ;
9592 pName += strlen(pName) + 1)
9594 if ( !stricmp(pName, cm_NetbiosName) ) {
9602 if ( !bNameFound ) {
9603 size_t size = strlen(cm_NetbiosName) + 2;
9604 if ( !pHostNames ) {
9605 pHostNames = malloc(size);
9608 StringCbCopyA(pName, size, cm_NetbiosName);
9610 *pName = '\0'; /* add a second nul terminator */
9612 dwType = REG_MULTI_SZ;
9613 dwSize = (DWORD)(pName - pHostNames + 1);
9614 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9616 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9617 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9620 &hkLsa) == ERROR_SUCCESS )
9622 dwSize = sizeof(DWORD);
9623 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9626 dwSize = sizeof(DWORD);
9628 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9630 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9631 AFSREG_CLT_OPENAFS_SUBKEY,
9634 REG_OPTION_NON_VOLATILE,
9638 NULL) == ERROR_SUCCESS) {
9641 dwSize = sizeof(DWORD);
9643 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9644 bLoopbackCheckDisabled = TRUE;
9645 RegCloseKey(hkClient);
9650 } else if (!bLoopbackCheckDisabled) {
9651 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9652 AFSREG_CLT_OPENAFS_SUBKEY,
9655 REG_OPTION_NON_VOLATILE,
9659 NULL) == ERROR_SUCCESS) {
9661 dwSize = sizeof(DWORD);
9662 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9664 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9665 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9668 &hkLsa) == ERROR_SUCCESS )
9670 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9674 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9675 RegCloseKey(hkClient);
9684 RegCloseKey(hkMSV10);
9690 configureExtendedSMBSessionTimeouts(void)
9693 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9694 * new functionality:
9696 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9697 * "ReconnectableServers" REG_MULTI_SZ
9698 * "ExtendedSessTimeout" REG_DWORD (seconds)
9699 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
9701 * These values can be used to prevent the smb redirector from timing out
9702 * smb connection to the afs smb server prematurely.
9706 DWORD dwSize, dwAllocSize;
9708 PBYTE pHostNames = NULL, pName = NULL;
9709 BOOL bNameFound = FALSE;
9711 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9712 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9715 &hkLanMan) == ERROR_SUCCESS )
9717 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
9718 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9719 (dwType == REG_MULTI_SZ))
9721 dwAllocSize += 1 /* in case the source string is not nul terminated */
9722 + (DWORD)strlen(cm_NetbiosName) + 2;
9723 pHostNames = malloc(dwAllocSize);
9724 dwSize = dwAllocSize;
9725 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
9726 pHostNames, &dwSize) == ERROR_SUCCESS)
9728 for (pName = pHostNames;
9729 (pName - pHostNames < (int) dwSize) && *pName ;
9730 pName += strlen(pName) + 1)
9732 if ( !stricmp(pName, cm_NetbiosName) ) {
9740 if ( !bNameFound ) {
9741 size_t size = strlen(cm_NetbiosName) + 2;
9742 if ( !pHostNames ) {
9743 pHostNames = malloc(size);
9746 StringCbCopyA(pName, size, cm_NetbiosName);
9748 *pName = '\0'; /* add a second nul terminator */
9750 dwType = REG_MULTI_SZ;
9751 dwSize = (DWORD)(pName - pHostNames + 1);
9752 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9760 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
9761 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9762 (dwType == REG_MULTI_SZ))
9764 dwAllocSize += 1 /* in case the source string is not nul terminated */
9765 + (DWORD)strlen(cm_NetbiosName) + 2;
9766 pHostNames = malloc(dwAllocSize);
9767 dwSize = dwAllocSize;
9768 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
9769 pHostNames, &dwSize) == ERROR_SUCCESS)
9771 for (pName = pHostNames;
9772 (pName - pHostNames < (int) dwSize) && *pName ;
9773 pName += strlen(pName) + 1)
9775 if ( !stricmp(pName, cm_NetbiosName) ) {
9783 if ( !bNameFound ) {
9784 size_t size = strlen(cm_NetbiosName) + 2;
9785 if ( !pHostNames ) {
9786 pHostNames = malloc(size);
9789 StringCbCopyA(pName, size, cm_NetbiosName);
9791 *pName = '\0'; /* add a second nul terminator */
9793 dwType = REG_MULTI_SZ;
9794 dwSize = (DWORD)(pName - pHostNames + 1);
9795 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9803 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
9804 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9805 (dwType != REG_DWORD))
9808 dwSize = sizeof(dwValue);
9809 dwValue = 300; /* 5 minutes */
9810 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9812 RegCloseKey(hkLanMan);
9817 smb_LanAdapterChangeThread(void *param)
9820 * Give the IPAddrDaemon thread a chance
9821 * to block before we trigger.
9824 smb_LanAdapterChange(0);
9827 void smb_SetLanAdapterChangeDetected(void)
9832 lock_ObtainMutex(&smb_StartedLock);
9834 if (!powerStateSuspended) {
9835 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9836 NULL, 0, &lpid, "smb_LanAdapterChange");
9837 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9838 thrd_CloseHandle(phandle);
9841 smb_LanAdapterChangeDetected = 1;
9842 lock_ReleaseMutex(&smb_StartedLock);
9845 void smb_LanAdapterChange(int locked) {
9846 lana_number_t lanaNum;
9848 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9850 LANA_ENUM temp_list;
9855 afsi_log("smb_LanAdapterChange");
9858 lock_ObtainMutex(&smb_StartedLock);
9860 smb_LanAdapterChangeDetected = 0;
9862 if (!powerStateSuspended &&
9863 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9864 LANA_NETBIOS_NAME_FULL)) &&
9865 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9866 if ( isGateway != bGateway ) {
9867 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9868 smb_LANadapter, lanaNum, isGateway, bGateway);
9870 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9871 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9872 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9875 NCB *ncbp = smb_GetNCB();
9876 ncbp->ncb_command = NCBENUM;
9877 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9878 ncbp->ncb_length = sizeof(temp_list);
9879 code = Netbios(ncbp);
9881 if (temp_list.length != lana_list.length) {
9882 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9883 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9886 for (i=0; i<lana_list.length; i++) {
9887 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9888 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9889 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9901 smb_StopListeners(1);
9902 smb_RestartListeners(1);
9905 lock_ReleaseMutex(&smb_StartedLock);
9908 /* initialize Netbios */
9909 int smb_NetbiosInit(int locked)
9912 int i, lana, code, l;
9914 int delname_tried=0;
9917 lana_number_t lanaNum;
9920 lock_ObtainMutex(&smb_StartedLock);
9922 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9923 smb_ListenerState != SMB_LISTENER_STOPPED) {
9926 lock_ReleaseMutex(&smb_StartedLock);
9929 /* setup the NCB system */
9930 ncbp = smb_GetNCB();
9932 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9933 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9934 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9936 if (smb_LANadapter != LANA_INVALID)
9937 afsi_log("LAN adapter number %d", smb_LANadapter);
9939 afsi_log("LAN adapter number not determined");
9942 afsi_log("Set for gateway service");
9944 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9946 /* something went horribly wrong. We can't proceed without a netbios name */
9948 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9949 osi_panic(buf, __FILE__, __LINE__);
9952 /* remember the name */
9953 len = (int)strlen(cm_NetbiosName);
9955 free(smb_localNamep);
9956 smb_localNamep = malloc(len+1);
9957 strcpy(smb_localNamep, cm_NetbiosName);
9958 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9960 /* Also copy the value to the client character encoded string */
9961 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9963 if (smb_LANadapter == LANA_INVALID) {
9964 ncbp->ncb_command = NCBENUM;
9965 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9966 ncbp->ncb_length = sizeof(lana_list);
9967 code = Netbios(ncbp);
9969 afsi_log("Netbios NCBENUM error code %d", code);
9970 osi_panic(s, __FILE__, __LINE__);
9974 lana_list.length = 1;
9975 lana_list.lana[0] = smb_LANadapter;
9978 for (i = 0; i < lana_list.length; i++) {
9979 /* reset the adaptor: in Win32, this is required for every process, and
9980 * acts as an init call, not as a real hardware reset.
9982 ncbp->ncb_command = NCBRESET;
9983 ncbp->ncb_callname[0] = 100;
9984 ncbp->ncb_callname[2] = 100;
9985 ncbp->ncb_lana_num = lana_list.lana[i];
9986 code = Netbios(ncbp);
9988 code = ncbp->ncb_retcode;
9990 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9991 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9993 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9997 /* and declare our name so we can receive connections */
9998 memset(ncbp, 0, sizeof(*ncbp));
9999 len=lstrlen(smb_localNamep);
10000 memset(smb_sharename,' ',NCBNAMSZ);
10001 memcpy(smb_sharename,smb_localNamep,len);
10002 afsi_log("lana_list.length %d", lana_list.length);
10004 /* Keep the name so we can unregister it later */
10005 for (l = 0; l < lana_list.length; l++) {
10006 lana = lana_list.lana[l];
10008 ncbp->ncb_command = NCBADDNAME;
10009 ncbp->ncb_lana_num = lana;
10010 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10011 code = Netbios(ncbp);
10013 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10014 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10016 char name[NCBNAMSZ+1];
10018 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10019 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10023 code = ncbp->ncb_retcode;
10026 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10029 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10030 if (code == NRC_BRIDGE) { /* invalid LANA num */
10031 lana_list.lana[l] = LANA_INVALID;
10034 else if (code == NRC_DUPNAME) {
10035 afsi_log("Name already exists; try to delete it");
10036 memset(ncbp, 0, sizeof(*ncbp));
10037 ncbp->ncb_command = NCBDELNAME;
10038 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10039 ncbp->ncb_lana_num = lana;
10040 code = Netbios(ncbp);
10042 code = ncbp->ncb_retcode;
10044 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10046 if (code != 0 || delname_tried) {
10047 lana_list.lana[l] = LANA_INVALID;
10049 else if (code == 0) {
10050 if (!delname_tried) {
10058 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10059 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10063 smb_LANadapter = lana;
10064 lana_found = 1; /* at least one worked */
10068 osi_assertx(lana_list.length >= 0, "empty lana list");
10070 afsi_log("No valid LANA numbers found!");
10071 lana_list.length = 0;
10072 smb_LANadapter = LANA_INVALID;
10073 smb_ListenerState = SMB_LISTENER_STOPPED;
10074 cm_VolStatus_Network_Stopped(cm_NetbiosName
10081 /* we're done with the NCB now */
10084 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10085 if (lana_list.length > 0)
10086 osi_assert(smb_LANadapter != LANA_INVALID);
10089 lock_ReleaseMutex(&smb_StartedLock);
10091 return (lana_list.length > 0 ? 1 : 0);
10094 void smb_StartListeners(int locked)
10101 lock_ObtainMutex(&smb_StartedLock);
10103 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10105 lock_ReleaseMutex(&smb_StartedLock);
10109 afsi_log("smb_StartListeners");
10110 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10111 configureBackConnectionHostNames();
10113 /* Configure Extended SMB Session Timeouts */
10114 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10115 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10116 configureExtendedSMBSessionTimeouts();
10119 smb_ListenerState = SMB_LISTENER_STARTED;
10120 cm_VolStatus_Network_Started(cm_NetbiosName
10126 for (i = 0; i < lana_list.length; i++) {
10127 if (lana_list.lana[i] == LANA_INVALID)
10129 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10130 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10131 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10132 thrd_CloseHandle(phandle);
10135 lock_ReleaseMutex(&smb_StartedLock);
10138 void smb_RestartListeners(int locked)
10141 lock_ObtainMutex(&smb_StartedLock);
10143 if (powerStateSuspended)
10144 afsi_log("smb_RestartListeners called while suspended");
10146 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10147 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10148 if (smb_NetbiosInit(1))
10149 smb_StartListeners(1);
10150 } else if (smb_LanAdapterChangeDetected) {
10151 smb_LanAdapterChange(1);
10155 lock_ReleaseMutex(&smb_StartedLock);
10158 void smb_StopListener(NCB *ncbp, int lana, int wait)
10162 memset(ncbp, 0, sizeof(*ncbp));
10163 ncbp->ncb_command = NCBDELNAME;
10164 ncbp->ncb_lana_num = lana;
10165 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10166 code = Netbios(ncbp);
10168 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10169 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10171 /* and then reset the LANA; this will cause the listener threads to exit */
10172 ncbp->ncb_command = NCBRESET;
10173 ncbp->ncb_callname[0] = 100;
10174 ncbp->ncb_callname[2] = 100;
10175 ncbp->ncb_lana_num = lana;
10176 code = Netbios(ncbp);
10178 code = ncbp->ncb_retcode;
10180 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10182 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10186 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10189 void smb_StopListeners(int locked)
10195 lock_ObtainMutex(&smb_StartedLock);
10197 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10199 lock_ReleaseMutex(&smb_StartedLock);
10203 afsi_log("smb_StopListeners");
10204 smb_ListenerState = SMB_LISTENER_STOPPED;
10205 cm_VolStatus_Network_Stopped(cm_NetbiosName
10211 ncbp = smb_GetNCB();
10213 /* Unregister the SMB name */
10214 for (l = 0; l < lana_list.length; l++) {
10215 lana = lana_list.lana[l];
10217 if (lana != LANA_INVALID) {
10218 smb_StopListener(ncbp, lana, TRUE);
10220 /* mark the adapter invalid */
10221 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10225 /* force a re-evaluation of the network adapters */
10226 lana_list.length = 0;
10227 smb_LANadapter = LANA_INVALID;
10230 lock_ReleaseMutex(&smb_StartedLock);
10233 void smb_Init(osi_log_t *logp, int useV3,
10243 EVENT_HANDLE retHandle;
10244 char eventName[MAX_PATH];
10245 int startListeners = 0;
10247 smb_MBfunc = aMBfunc;
10251 /* Initialize smb_localZero */
10252 myTime.tm_isdst = -1; /* compute whether on DST or not */
10253 myTime.tm_year = 70;
10255 myTime.tm_mday = 1;
10256 myTime.tm_hour = 0;
10259 smb_localZero = mktime(&myTime);
10261 #ifdef AFS_FREELANCE_CLIENT
10262 /* Make sure the root.afs volume has the correct time */
10263 cm_noteLocalMountPointChange();
10266 /* initialize the remote debugging log */
10269 /* and the global lock */
10270 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10271 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10273 /* Raw I/O data structures */
10274 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10276 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10277 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10279 /* 4 Raw I/O buffers */
10280 smb_RawBufs = calloc(65536,1);
10281 *((char **)smb_RawBufs) = NULL;
10282 for (i=0; i<3; i++) {
10283 char *rawBuf = calloc(65536,1);
10284 *((char **)rawBuf) = smb_RawBufs;
10285 smb_RawBufs = rawBuf;
10288 /* global free lists */
10289 smb_ncbFreeListp = NULL;
10290 smb_packetFreeListp = NULL;
10292 lock_ObtainMutex(&smb_StartedLock);
10293 startListeners = smb_NetbiosInit(1);
10295 /* Initialize listener and server structures */
10297 memset(dead_sessions, 0, sizeof(dead_sessions));
10298 sprintf(eventName, "SessionEvents[0]");
10299 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10300 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10301 afsi_log("Event Object Already Exists: %s", eventName);
10303 smb_NumServerThreads = nThreads;
10304 sprintf(eventName, "NCBavails[0]");
10305 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10306 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10307 afsi_log("Event Object Already Exists: %s", eventName);
10308 sprintf(eventName, "NCBevents[0]");
10309 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10310 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10311 afsi_log("Event Object Already Exists: %s", eventName);
10312 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10313 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10314 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10315 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10316 afsi_log("Event Object Already Exists: %s", eventName);
10317 for (i = 0; i < smb_NumServerThreads; i++) {
10318 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10319 NCBreturns[i][0] = retHandle;
10322 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10323 for (i = 0; i < smb_NumServerThreads; i++) {
10324 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10325 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10326 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10327 afsi_log("Event Object Already Exists: %s", eventName);
10328 InitNCBslot((int)(i+1));
10330 numNCBs = smb_NumServerThreads + 1;
10332 /* Initialize dispatch table */
10333 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10334 /* Prepare the table for unknown operations */
10335 for(i=0; i<= SMB_NOPCODES; i++) {
10336 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10338 /* Fill in the ones we do know */
10339 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10340 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10341 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10342 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10343 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10344 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10345 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10346 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10347 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10348 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10349 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10350 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10351 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10352 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10353 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10354 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10355 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10356 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10357 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10358 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10359 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10360 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10361 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10362 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10363 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10364 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10365 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10366 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10367 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10368 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10369 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10370 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10371 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10372 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10373 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10374 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10375 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10376 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10377 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10378 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10379 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10380 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10381 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10382 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10383 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10384 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10385 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10386 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10387 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10388 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10389 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10390 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10391 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10392 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10393 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10394 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10395 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10396 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10397 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10398 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10399 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10400 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10401 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10402 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10403 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10404 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10405 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10406 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10407 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10408 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10409 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10410 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10411 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10412 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10414 /* setup tran 2 dispatch table */
10415 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10416 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10417 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10418 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10419 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10420 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10421 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10422 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10423 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10424 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10425 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10426 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10427 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10428 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10429 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10430 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10431 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10432 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10434 /* setup the rap dispatch table */
10435 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10436 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10437 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10438 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10439 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10443 /* if we are doing SMB authentication we have register outselves as a logon process */
10444 if (smb_authType != SMB_AUTH_NONE) {
10445 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10446 LSA_STRING afsProcessName;
10447 LSA_OPERATIONAL_MODE dummy; /*junk*/
10449 afsProcessName.Buffer = "OpenAFSClientDaemon";
10450 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10451 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10453 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10455 if (nts == STATUS_SUCCESS) {
10456 LSA_STRING packageName;
10457 /* we are registered. Find out the security package id */
10458 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10459 packageName.Length = (USHORT)strlen(packageName.Buffer);
10460 packageName.MaximumLength = packageName.Length + 1;
10461 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10462 if (nts == STATUS_SUCCESS) {
10464 * This code forces Windows to authenticate against the Logon Cache
10465 * first instead of attempting to authenticate against the Domain
10466 * Controller. When the Windows logon cache is enabled this improves
10467 * performance by removing the network access and works around a bug
10468 * seen at sites which are using a MIT Kerberos principal to login
10469 * to machines joined to a non-root domain in a multi-domain forest.
10470 * MsV1_0SetProcessOption was added in Windows XP.
10472 PVOID pResponse = NULL;
10473 ULONG cbResponse = 0;
10474 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10476 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10477 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10478 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10479 OptionsRequest.DisableOptions = FALSE;
10481 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10484 sizeof(OptionsRequest),
10490 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10491 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10494 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10496 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10497 afsi_log("MsV1_0SetProcessOption success");
10499 /* END - code from Larry */
10501 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10502 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10503 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10505 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10507 /* something went wrong. We report the error and revert back to no authentication
10508 because we can't perform any auth requests without a successful lsa handle
10509 or sec package id. */
10510 afsi_log("Reverting to NO SMB AUTH");
10511 smb_authType = SMB_AUTH_NONE;
10514 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10516 /* something went wrong. We report the error and revert back to no authentication
10517 because we can't perform any auth requests without a successful lsa handle
10518 or sec package id. */
10519 afsi_log("Reverting to NO SMB AUTH");
10520 smb_authType = SMB_AUTH_NONE;
10524 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10525 * time prevents the failure of authentication when logged into Windows with an
10526 * external Kerberos principal mapped to a local account.
10528 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10529 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10530 * then the only option is NTLMSSP anyway; so just fallback.
10535 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10536 if (secBlobLength == 0) {
10537 smb_authType = SMB_AUTH_NTLM;
10538 afsi_log("Reverting to SMB AUTH NTLM");
10547 /* Now get ourselves a domain name. */
10548 /* For now we are using the local computer name as the domain name.
10549 * It is actually the domain for local logins, and we are acting as
10550 * a local SMB server.
10552 bufsize = lengthof(smb_ServerDomainName) - 1;
10553 GetComputerNameW(smb_ServerDomainName, &bufsize);
10554 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10555 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10558 /* Start listeners, waiters, servers, and daemons */
10559 if (startListeners)
10560 smb_StartListeners(1);
10562 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10563 NULL, 0, &lpid, "smb_ClientWaiter");
10564 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10565 thrd_CloseHandle(phandle);
10567 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10568 NULL, 0, &lpid, "smb_ServerWaiter");
10569 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10570 thrd_CloseHandle(phandle);
10572 for (i=0; i<smb_NumServerThreads; i++) {
10573 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10574 (void *) i, 0, &lpid, "smb_Server");
10575 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10576 thrd_CloseHandle(phandle);
10579 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10580 NULL, 0, &lpid, "smb_Daemon");
10581 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10582 thrd_CloseHandle(phandle);
10584 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10585 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10586 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10587 thrd_CloseHandle(phandle);
10589 lock_ReleaseMutex(&smb_StartedLock);
10593 void smb_Shutdown(void)
10600 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10602 /* setup the NCB system */
10603 ncbp = smb_GetNCB();
10605 /* Block new sessions by setting shutdown flag */
10606 smbShutdownFlag = 1;
10608 /* Hang up all sessions */
10609 memset(ncbp, 0, sizeof(NCB));
10610 for (i = 1; i < numSessions; i++)
10612 if (dead_sessions[i])
10615 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10616 ncbp->ncb_command = NCBHANGUP;
10617 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10618 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10619 code = Netbios(ncbp);
10620 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10621 if (code == 0) code = ncbp->ncb_retcode;
10623 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10624 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10628 /* Trigger the shutdown of all SMB threads */
10629 for (i = 0; i < smb_NumServerThreads; i++)
10630 thrd_SetEvent(NCBreturns[i][0]);
10632 thrd_SetEvent(NCBevents[0]);
10633 thrd_SetEvent(SessionEvents[0]);
10634 thrd_SetEvent(NCBavails[0]);
10636 for (i = 0;i < smb_NumServerThreads; i++) {
10637 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10638 if (code == WAIT_OBJECT_0) {
10641 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10642 thrd_SetEvent(NCBreturns[i--][0]);
10646 /* Delete Netbios name */
10647 memset(ncbp, 0, sizeof(NCB));
10648 for (i = 0; i < lana_list.length; i++) {
10649 if (lana_list.lana[i] == LANA_INVALID) continue;
10650 ncbp->ncb_command = NCBDELNAME;
10651 ncbp->ncb_lana_num = lana_list.lana[i];
10652 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10653 code = Netbios(ncbp);
10655 code = ncbp->ncb_retcode;
10657 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10658 ncbp->ncb_lana_num, code);
10663 /* Release the reference counts held by the VCs */
10664 lock_ObtainWrite(&smb_rctLock);
10665 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10670 if (vcp->magic != SMB_VC_MAGIC)
10671 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10672 __FILE__, __LINE__);
10674 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10676 if (fidp->scp != NULL) {
10679 lock_ReleaseWrite(&smb_rctLock);
10680 lock_ObtainMutex(&fidp->mx);
10681 if (fidp->scp != NULL) {
10684 lock_ObtainWrite(&scp->rw);
10685 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10686 lock_ReleaseWrite(&scp->rw);
10687 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10688 cm_ReleaseSCache(scp);
10690 lock_ReleaseMutex(&fidp->mx);
10691 lock_ObtainWrite(&smb_rctLock);
10695 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10697 smb_ReleaseVCNoLock(tidp->vcp);
10699 cm_user_t *userp = tidp->userp;
10700 tidp->userp = NULL;
10701 cm_ReleaseUser(userp);
10705 lock_ReleaseWrite(&smb_rctLock);
10709 /* Get the UNC \\<servername>\<sharename> prefix. */
10710 char *smb_GetSharename()
10715 /* Make sure we have been properly initialized. */
10716 if (smb_localNamep == NULL)
10719 /* Allocate space for \\<servername>\<sharename>, plus the
10722 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10723 name = malloc(len);
10724 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10730 void smb_LogPacket(smb_packet_t *packet)
10734 unsigned length, paramlen, datalen, i, j;
10736 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10738 if (!packet) return;
10740 osi_Log0(smb_logp, "*** SMB packet dump ***");
10742 smbp = (smb_t *) packet->data;
10743 vp = (BYTE *) packet->data;
10745 paramlen = smbp->wct * 2;
10746 datalen = *((WORD *) (smbp->vdata + paramlen));
10747 length = sizeof(*smbp) + paramlen + 1 + datalen;
10749 for (i=0;i < length; i+=16)
10751 memset( buf, ' ', 80 );
10754 itoa( i, buf, 16 );
10756 buf[strlen(buf)] = ' ';
10758 cp = (BYTE*) buf + 7;
10760 for (j=0;j < 16 && (i+j)<length; j++)
10762 *(cp++) = hex[vp[i+j] >> 4];
10763 *(cp++) = hex[vp[i+j] & 0xf];
10773 for (j=0;j < 16 && (i+j)<length;j++)
10775 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10786 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10789 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10791 #endif /* LOG_PACKET */
10794 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10800 smb_username_t *unp;
10801 smb_waitingLockRequest_t *wlrp;
10804 lock_ObtainRead(&smb_rctLock);
10806 sprintf(output, "begin dumping smb_username_t\r\n");
10807 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10808 for (unp = usernamesp; unp; unp=unp->nextp)
10810 cm_ucell_t *ucellp;
10812 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10813 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10814 unp->name ? unp->name : _C("NULL"),
10815 unp->machine ? unp->machine : _C("NULL"));
10816 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10818 sprintf(output, " begin dumping cm_ucell_t\r\n");
10819 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10821 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10822 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",
10823 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10824 ucellp->expirationTime, ucellp->gen,
10826 ucellp->cellp->name);
10827 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10830 sprintf(output, " done dumping cm_ucell_t\r\n");
10831 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10834 sprintf(output, "done dumping smb_username_t\r\n");
10835 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10838 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10839 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10842 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10843 smb_waitingLock_t *lockp;
10845 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10846 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10847 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10849 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10850 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10851 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10852 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10853 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10854 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10856 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10857 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10860 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10861 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10863 sprintf(output, "begin dumping smb_vc_t\r\n");
10864 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10866 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10872 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10873 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10874 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10876 sprintf(output, " begin dumping smb_user_t\r\n");
10877 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10878 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10879 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10880 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10881 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10883 sprintf(output, " done dumping smb_user_t\r\n");
10884 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10886 sprintf(output, " begin dumping smb_tid_t\r\n");
10887 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10888 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10889 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",
10890 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10891 tidp->pathname ? tidp->pathname : _C("NULL"));
10892 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10894 sprintf(output, " done dumping smb_tid_t\r\n");
10895 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10897 sprintf(output, " begin dumping smb_fid_t\r\n");
10898 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10900 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10902 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",
10903 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10904 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10905 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10906 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10909 sprintf(output, " done dumping smb_fid_t\r\n");
10910 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10913 sprintf(output, "done dumping smb_vc_t\r\n");
10914 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10916 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10917 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10919 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10925 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10926 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10927 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10929 sprintf(output, " begin dumping smb_user_t\r\n");
10930 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10931 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10932 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10933 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10934 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10936 sprintf(output, " done dumping smb_user_t\r\n");
10937 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10939 sprintf(output, " begin dumping smb_tid_t\r\n");
10940 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10941 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10942 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",
10943 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10944 tidp->pathname ? tidp->pathname : _C("NULL"));
10945 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10947 sprintf(output, " done dumping smb_tid_t\r\n");
10948 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10950 sprintf(output, " begin dumping smb_fid_t\r\n");
10951 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10953 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10955 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",
10956 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10957 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10958 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10959 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10962 sprintf(output, " done dumping smb_fid_t\r\n");
10963 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10966 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10967 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10970 lock_ReleaseRead(&smb_rctLock);
10974 long smb_IsNetworkStarted(void)
10977 lock_ObtainWrite(&smb_globalLock);
10978 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10979 lock_ReleaseWrite(&smb_globalLock);