2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
33 #include "lanahelper.h"
35 #define STRSAFE_NO_DEPRECATE
38 /* These characters are illegal in Windows filenames */
39 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
41 static int smbShutdownFlag = 0;
42 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
44 int smb_LogoffTokenTransfer;
45 time_t smb_LogoffTransferTimeout;
47 int smb_StoreAnsiFilenames = 0;
49 DWORD last_msg_time = 0;
53 unsigned int sessionGen = 0;
55 extern void afsi_log(char *pattern, ...);
56 extern HANDLE afsi_file;
57 extern int powerStateSuspended;
59 osi_hyper_t hzero = {0, 0};
60 osi_hyper_t hones = {0xFFFFFFFF, -1};
63 osi_rwlock_t smb_globalLock;
64 osi_rwlock_t smb_rctLock;
65 osi_mutex_t smb_ListenerLock;
66 osi_mutex_t smb_StartedLock;
68 unsigned char smb_LANadapter = LANA_INVALID;
69 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
70 int smb_LanAdapterChangeDetected = 0;
71 afs_uint32 smb_AsyncStore = 1;
72 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
74 BOOL isGateway = FALSE;
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
85 afs_uint32 smb_NumServerThreads;
87 afs_uint32 numNCBs, numSessions, numVCs;
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
92 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
94 ULONG smb_lsaSecPackage;
95 LSA_STRING smb_lsaLogonOrigin;
97 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
99 EVENT_HANDLE **NCBreturns;
100 EVENT_HANDLE **NCBShutdown;
101 EVENT_HANDLE *smb_ServerShutdown;
102 EVENT_HANDLE ListenerShutdown[256];
103 DWORD NCBsessions[NCB_MAX];
105 struct smb_packet *bufs[NCB_MAX];
107 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
108 EVENT_HANDLE SessionEvents[SESSION_MAX];
109 unsigned short LSNs[SESSION_MAX];
110 int lanas[SESSION_MAX];
111 BOOL dead_sessions[SESSION_MAX];
114 osi_mutex_t smb_RawBufLock;
117 #define SMB_MASKFLAG_TILDE 1
118 #define SMB_MASKFLAG_CASEFOLD 2
120 #define RAWTIMEOUT INFINITE
123 typedef struct raw_write_cont {
132 /* dir search stuff */
133 long smb_dirSearchCounter = 1;
134 smb_dirSearch_t *smb_firstDirSearchp;
135 smb_dirSearch_t *smb_lastDirSearchp;
137 /* hide dot files? */
138 int smb_hideDotFiles;
140 /* Negotiate Unicode support? */
143 /* global state about V3 protocols */
144 int smb_useV3; /* try to negotiate V3 */
146 static int showErrors = 0;
147 /* MessageBox or something like it */
148 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
152 * Time in Unix format of midnight, 1/1/1970 local time.
153 * When added to dosUTime, gives Unix (AFS) time.
155 time_t smb_localZero = 0;
157 char *smb_localNamep = NULL;
159 smb_vc_t *smb_allVCsp;
160 smb_vc_t *smb_deadVCsp;
162 smb_username_t *usernamesp = NULL;
164 smb_waitingLockRequest_t *smb_allWaitingLocks;
167 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
168 NCB *ncbp, raw_write_cont_t *rwcp);
169 int smb_NetbiosInit(int);
172 void smb_LogPacket(smb_packet_t *packet);
173 #endif /* LOG_PACKET */
175 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
176 int smb_ServerDomainNameLength = 0;
177 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
178 int smb_ServerOSLength = lengthof(smb_ServerOS);
179 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
180 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
182 /* Faux server GUID. This is never checked. */
183 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
185 void smb_InitReq(cm_req_t *reqp)
188 reqp->flags |= CM_REQ_SOURCE_SMB;
191 const char * ncb_error_string(int code)
195 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
196 case 0x03: s = "NRC_ILLCMD illegal command"; break;
197 case 0x05: s = "NRC_CMDTMO command timed out"; break;
198 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
199 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
200 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
201 case 0x09: s = "NRC_NORES no resource available"; break;
202 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
203 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
204 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
205 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
206 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
207 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
208 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
209 case 0x13: s = "NRC_ILLNN illegal name number"; break;
210 case 0x14: s = "NRC_NOCALL no callname"; break;
211 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
212 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
213 case 0x17: s = "NRC_NAMERR name deleted"; break;
214 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
215 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
216 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
217 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
218 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
219 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
220 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
221 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
222 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
223 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
224 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
225 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
226 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
227 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
228 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
229 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
230 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
231 case 0x40: s = "NRC_SYSTEM system error"; break;
232 default: s = "unknown error";
238 char * myCrt_Dispatch(int i)
243 return "(00)ReceiveCoreMakeDir";
245 return "(01)ReceiveCoreRemoveDir";
247 return "(02)ReceiveCoreOpen";
249 return "(03)ReceiveCoreCreate";
251 return "(04)ReceiveCoreClose";
253 return "(05)ReceiveCoreFlush";
255 return "(06)ReceiveCoreUnlink";
257 return "(07)ReceiveCoreRename";
259 return "(08)ReceiveCoreGetFileAttributes";
261 return "(09)ReceiveCoreSetFileAttributes";
263 return "(0a)ReceiveCoreRead";
265 return "(0b)ReceiveCoreWrite";
267 return "(0c)ReceiveCoreLockRecord";
269 return "(0d)ReceiveCoreUnlockRecord";
271 return "(0e)SendCoreBadOp";
273 return "(0f)ReceiveCoreCreate";
275 return "(10)ReceiveCoreCheckPath";
277 return "(11)SendCoreBadOp";
279 return "(12)ReceiveCoreSeek";
281 return "(1a)ReceiveCoreReadRaw";
283 return "(1d)ReceiveCoreWriteRawDummy";
285 return "(22)ReceiveV3SetAttributes";
287 return "(23)ReceiveV3GetAttributes";
289 return "(24)ReceiveV3LockingX";
291 return "(25)ReceiveV3Trans";
293 return "(26)ReceiveV3Trans[aux]";
295 return "(29)SendCoreBadOp";
297 return "(2b)ReceiveCoreEcho";
299 return "(2d)ReceiveV3OpenX";
301 return "(2e)ReceiveV3ReadX";
303 return "(2f)ReceiveV3WriteX";
305 return "(32)ReceiveV3Tran2A";
307 return "(33)ReceiveV3Tran2A[aux]";
309 return "(34)ReceiveV3FindClose";
311 return "(35)ReceiveV3FindNotifyClose";
313 return "(70)ReceiveCoreTreeConnect";
315 return "(71)ReceiveCoreTreeDisconnect";
317 return "(72)ReceiveNegotiate";
319 return "(73)ReceiveV3SessionSetupX";
321 return "(74)ReceiveV3UserLogoffX";
323 return "(75)ReceiveV3TreeConnectX";
325 return "(80)ReceiveCoreGetDiskAttributes";
327 return "(81)ReceiveCoreSearchDir";
331 return "(83)FindUnique";
333 return "(84)FindClose";
335 return "(A0)ReceiveNTTransact";
337 return "(A2)ReceiveNTCreateX";
339 return "(A4)ReceiveNTCancel";
341 return "(A5)ReceiveNTRename";
343 return "(C0)OpenPrintFile";
345 return "(C1)WritePrintFile";
347 return "(C2)ClosePrintFile";
349 return "(C3)GetPrintQueue";
351 return "(D8)ReadBulk";
353 return "(D9)WriteBulk";
355 return "(DA)WriteBulkData";
357 return "unknown SMB op";
361 char * myCrt_2Dispatch(int i)
366 return "unknown SMB op-2";
368 return "S(00)CreateFile_ReceiveTran2Open";
370 return "S(01)FindFirst_ReceiveTran2SearchDir";
372 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
374 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
376 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
378 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
380 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
382 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
384 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
386 return "S(09)_ReceiveTran2FSCTL";
388 return "S(0a)_ReceiveTran2IOCTL";
390 return "S(0b)_ReceiveTran2FindNotifyFirst";
392 return "S(0c)_ReceiveTran2FindNotifyNext";
394 return "S(0d)_ReceiveTran2CreateDirectory";
396 return "S(0e)_ReceiveTran2SessionSetup";
398 return "S(0f)_QueryFileSystemInformationFid";
400 return "S(10)_ReceiveTran2GetDfsReferral";
402 return "S(11)_ReceiveTran2ReportDfsInconsistency";
406 char * myCrt_RapDispatch(int i)
411 return "unknown RAP OP";
413 return "RAP(0)NetShareEnum";
415 return "RAP(1)NetShareGetInfo";
417 return "RAP(13)NetServerGetInfo";
419 return "RAP(63)NetWkStaGetInfo";
423 char * myCrt_NmpipeDispatch(int i)
426 case SMB_TRANS_SET_NMPIPE_STATE:
427 return "SET NMPIPE STATE";
429 case SMB_TRANS_RAW_READ_NMPIPE:
430 return "RAW READ NMPIPE";
432 case SMB_TRANS_QUERY_NMPIPE_STATE:
433 return "QUERY NMPIPE STATE";
435 case SMB_TRANS_QUERY_NMPIPE_INFO:
436 return "QUERY NMPIPE INFO";
438 case SMB_TRANS_PEEK_NMPIPE:
439 return "PEEK NMPIPE";
441 case SMB_TRANS_TRANSACT_NMPIPE:
442 return "TRANSACT NMPIPE";
444 case SMB_TRANS_RAW_WRITE_NMPIPE:
445 return "WRITE NMPIPE";
447 case SMB_TRANS_READ_NMPIPE:
448 return "READ NMPIPE";
450 case SMB_TRANS_WRITE_NMPIPE:
451 return "WRITE NMPIPE";
453 case SMB_TRANS_WAIT_NMPIPE:
454 return "WAIT NMPIPE";
456 case SMB_TRANS_CALL_NMPIPE:
457 return "CALL NMPIPE";
462 /* scache must be locked */
463 unsigned int smb_Attributes(cm_scache_t *scp)
467 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
468 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
469 scp->fileType == CM_SCACHETYPE_INVALID)
471 attrs = SMB_ATTR_DIRECTORY;
472 #ifdef SPECIAL_FOLDERS
473 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
474 #endif /* SPECIAL_FOLDERS */
475 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
476 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
481 * We used to mark a file RO if it was in an RO volume, but that
482 * turns out to be impolitic in NT. See defect 10007.
485 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
486 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
488 if ((scp->unixModeBits & 0222) == 0)
489 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
495 /* Check if the named file/dir is a dotfile/dotdir */
496 /* String pointed to by lastComp can have leading slashes, but otherwise should have
497 no other patch components */
498 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
502 /* skip over slashes */
503 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
508 /* nulls, curdir and parent dir doesn't count */
514 if(*(s+1) == _C('.') && !*(s + 2))
521 static int ExtractBits(WORD bits, short start, short len)
528 num = bits << (16 - end);
529 num = num >> ((16 - end) + start);
534 void ShowUnixTime(char *FuncName, time_t unixTime)
539 cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
541 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
542 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
544 int day, month, year, sec, min, hour;
547 day = ExtractBits(wDate, 0, 5);
548 month = ExtractBits(wDate, 5, 4);
549 year = ExtractBits(wDate, 9, 7) + 1980;
551 sec = ExtractBits(wTime, 0, 5);
552 min = ExtractBits(wTime, 5, 6);
553 hour = ExtractBits(wTime, 11, 5);
555 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
556 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
560 /* Determine if we are observing daylight savings time */
561 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
563 TIME_ZONE_INFORMATION timeZoneInformation;
564 SYSTEMTIME utc, local, localDST;
566 /* Get the time zone info. NT uses this to calc if we are in DST. */
567 GetTimeZoneInformation(&timeZoneInformation);
569 /* Return the daylight bias */
570 *pDstBias = timeZoneInformation.DaylightBias;
572 /* Return the bias */
573 *pBias = timeZoneInformation.Bias;
575 /* Now determine if DST is being observed */
577 /* Get the UTC (GMT) time */
580 /* Convert UTC time to local time using the time zone info. If we are
581 observing DST, the calculated local time will include this.
583 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
585 /* Set the daylight bias to 0. The daylight bias is the amount of change
586 * in time that we use for daylight savings time. By setting this to 0
587 * we cause there to be no change in time during daylight savings time.
589 timeZoneInformation.DaylightBias = 0;
591 /* Convert the utc time to local time again, but this time without any
592 adjustment for daylight savings time.
594 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
596 /* If the two times are different, then it means that the localDST that
597 we calculated includes the daylight bias, and therefore we are
598 observing daylight savings time.
600 *pDST = localDST.wHour != local.wHour;
604 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
606 BOOL dst; /* Will be TRUE if observing DST */
607 LONG dstBias; /* Offset from local time if observing DST */
608 LONG bias; /* Offset from GMT for local time */
611 * This function will adjust the last write time to compensate
612 * for two bugs in the smb client:
614 * 1) During Daylight Savings Time, the LastWriteTime is ahead
615 * in time by the DaylightBias (ignoring the sign - the
616 * DaylightBias is always stored as a negative number). If
617 * the DaylightBias is -60, then the LastWriteTime will be
618 * ahead by 60 minutes.
620 * 2) If the local time zone is a positive offset from GMT, then
621 * the LastWriteTime will be the correct local time plus the
622 * Bias (ignoring the sign - a positive offset from GMT is
623 * always stored as a negative Bias). If the Bias is -120,
624 * then the LastWriteTime will be ahead by 120 minutes.
626 * These bugs can occur at the same time.
629 GetTimeZoneInfo(&dst, &dstBias, &bias);
631 /* First adjust for DST */
633 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
635 /* Now adjust for a positive offset from GMT (a negative bias). */
637 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
640 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
642 time_t diff_t = unixTime - smb_localZero;
643 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
644 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
646 *dosUTimep = (afs_uint32)diff_t;
649 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
651 *unixTimep = dosTime + smb_localZero;
654 void smb_MarkAllVCsDead(smb_vc_t * exclude)
657 smb_vc_t **vcp_to_cleanup = NULL;
658 int n_to_cleanup = 0;
661 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
663 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
664 lock_ObtainWrite(&smb_rctLock);
665 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
667 if (vcp->magic != SMB_VC_MAGIC)
668 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
674 lock_ObtainMutex(&vcp->mx);
675 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
676 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
677 lock_ReleaseMutex(&vcp->mx);
678 dead_sessions[vcp->session] = TRUE;
680 lock_ReleaseMutex(&vcp->mx);
685 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
687 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
691 vcp_to_cleanup[i++] = vcp;
692 smb_HoldVCNoLock(vcp);
695 osi_assert(i == n_to_cleanup);
697 lock_ReleaseWrite(&smb_rctLock);
698 lock_ReleaseWrite(&smb_globalLock);
700 for (i=0; i < n_to_cleanup; i++) {
701 smb_CleanupDeadVC(vcp_to_cleanup[i]);
702 smb_ReleaseVC(vcp_to_cleanup[i]);
703 vcp_to_cleanup[i] = 0;
706 free(vcp_to_cleanup);
709 #ifdef DEBUG_SMB_REFCOUNT
710 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
712 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
717 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
718 lock_ObtainWrite(&smb_rctLock);
719 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
720 if (vcp->magic != SMB_VC_MAGIC)
721 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
724 lock_ObtainMutex(&vcp->mx);
725 if (lsn == vcp->lsn && lana == vcp->lana &&
726 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
727 lock_ReleaseMutex(&vcp->mx);
728 smb_HoldVCNoLock(vcp);
731 lock_ReleaseMutex(&vcp->mx);
733 if (!vcp && (flags & SMB_FLAG_CREATE)) {
734 vcp = malloc(sizeof(*vcp));
735 memset(vcp, 0, sizeof(*vcp));
736 vcp->vcID = ++numVCs;
737 vcp->magic = SMB_VC_MAGIC;
738 vcp->refCount = 2; /* smb_allVCsp and caller */
741 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
742 vcp->nextp = smb_allVCsp;
744 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
749 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
750 /* We must obtain a challenge for extended auth
751 * in case the client negotiates smb v3
753 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
754 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
755 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
756 ULONG lsaRespSize = 0;
758 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
760 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
767 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
768 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
769 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
770 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
771 nts, ntsEx, lsaRespSize);
773 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
775 if (ntsEx == STATUS_SUCCESS) {
776 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
779 * This will cause the subsequent authentication to fail but
780 * that is better than us dereferencing a NULL pointer and
783 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
786 LsaFreeReturnBuffer(lsaResp);
789 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
791 if (numVCs >= CM_SESSION_RESERVED) {
793 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
796 #ifdef DEBUG_SMB_REFCOUNT
798 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
799 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
802 lock_ReleaseWrite(&smb_rctLock);
803 lock_ReleaseWrite(&smb_globalLock);
807 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
812 for(i=0; i<11; i++) {
814 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
820 static int smb_IsStarMask(clientchar_t *maskp)
826 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
832 #ifdef DEBUG_SMB_REFCOUNT
833 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
834 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
836 void smb_ReleaseVCInternal(smb_vc_t *vcp)
842 lock_AssertWrite(&smb_rctLock);
845 if (vcp->refCount == 0) {
846 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
847 #ifdef DEBUG_SMB_REFCOUNT
848 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
849 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
851 /* remove VCP from smb_deadVCsp */
852 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
858 lock_FinalizeMutex(&vcp->mx);
859 memset(vcp,0,sizeof(smb_vc_t));
862 #ifdef DEBUG_SMB_REFCOUNT
863 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
865 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
869 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
870 avcp?"":"not ",vcp, vcp->refCount);
872 /* This is a wrong. However, I suspect that there is an undercount
873 * and I don't want to release 1.4.1 in a state that will allow
874 * smb_vc_t objects to be deallocated while still in the
875 * smb_allVCsp list. The list is supposed to keep a reference
876 * to the smb_vc_t. Put it back.
880 #ifdef DEBUG_SMB_REFCOUNT
881 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
882 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
886 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
887 /* The reference count is non-zero but the VC is dead.
888 * This implies that some FIDs, TIDs, etc on the VC have yet to
889 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
890 * add a reference that will be dropped by
891 * smb_CleanupDeadVC() and try to cleanup the VC again.
892 * Eventually the refCount will drop to zero when all of the
893 * active threads working with the VC end their task.
895 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
896 vcp->refCount++; /* put the refCount back */
897 lock_ReleaseWrite(&smb_rctLock);
898 smb_CleanupDeadVC(vcp);
899 #ifdef DEBUG_SMB_REFCOUNT
900 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
901 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
903 lock_ObtainWrite(&smb_rctLock);
906 #ifdef DEBUG_SMB_REFCOUNT
907 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
908 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
913 #ifdef DEBUG_SMB_REFCOUNT
914 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
916 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
919 lock_AssertWrite(&smb_rctLock);
920 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
921 smb_ReleaseVCInternal(vcp);
924 #ifdef DEBUG_SMB_REFCOUNT
925 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
927 void smb_ReleaseVC(smb_vc_t *vcp)
930 lock_ObtainWrite(&smb_rctLock);
931 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
932 smb_ReleaseVCInternal(vcp);
933 lock_ReleaseWrite(&smb_rctLock);
936 #ifdef DEBUG_SMB_REFCOUNT
937 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
939 void smb_HoldVCNoLock(smb_vc_t *vcp)
942 lock_AssertWrite(&smb_rctLock);
944 #ifdef DEBUG_SMB_REFCOUNT
945 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
946 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
948 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
952 #ifdef DEBUG_SMB_REFCOUNT
953 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
955 void smb_HoldVC(smb_vc_t *vcp)
958 lock_ObtainWrite(&smb_rctLock);
960 #ifdef DEBUG_SMB_REFCOUNT
961 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
962 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
964 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
966 lock_ReleaseWrite(&smb_rctLock);
969 void smb_CleanupDeadVC(smb_vc_t *vcp)
977 smb_user_t *uidpIter;
978 smb_user_t *uidpNext;
980 afs_uint32 refCount = 0;
982 lock_ObtainMutex(&vcp->mx);
983 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
984 lock_ReleaseMutex(&vcp->mx);
985 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
988 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
989 lock_ReleaseMutex(&vcp->mx);
990 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
992 lock_ObtainWrite(&smb_rctLock);
993 /* remove VCP from smb_allVCsp */
994 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
995 if ((*vcpp)->magic != SMB_VC_MAGIC)
996 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1000 vcp->nextp = smb_deadVCsp;
1002 /* Hold onto the reference until we are done with this function */
1007 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1008 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1010 if (fidpIter->deleteOk)
1013 fid = fidpIter->fid;
1014 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1016 smb_HoldFIDNoLock(fidpIter);
1017 lock_ReleaseWrite(&smb_rctLock);
1019 smb_CloseFID(vcp, fidpIter, NULL, 0);
1020 smb_ReleaseFID(fidpIter);
1022 lock_ObtainWrite(&smb_rctLock);
1023 fidpNext = vcp->fidsp;
1026 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1027 tidpNext = tidpIter->nextp;
1028 if (tidpIter->deleteOk)
1030 tidpIter->deleteOk = 1;
1032 tid = tidpIter->tid;
1033 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1035 smb_HoldTIDNoLock(tidpIter);
1036 smb_ReleaseTID(tidpIter, TRUE);
1037 tidpNext = vcp->tidsp;
1040 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1041 uidpNext = uidpIter->nextp;
1042 if (uidpIter->deleteOk)
1044 uidpIter->deleteOk = 1;
1046 /* do not add an additional reference count for the smb_user_t
1047 * as the smb_vc_t already is holding a reference */
1048 lock_ReleaseWrite(&smb_rctLock);
1050 smb_ReleaseUID(uidpIter);
1052 lock_ObtainWrite(&smb_rctLock);
1053 uidpNext = vcp->usersp;
1056 /* The vcp is now on the deadVCsp list. We intentionally drop the
1057 * reference so that the refcount can reach 0 and we can delete it
1059 * If the refCount == 1 going into the ReleaseVCNoLock call
1060 * the object will be freed and it won't be safe to clear
1063 refCount = vcp->refCount;
1064 smb_ReleaseVCNoLock(vcp);
1066 lock_ObtainMutex(&vcp->mx);
1067 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1068 lock_ReleaseMutex(&vcp->mx);
1071 lock_ReleaseWrite(&smb_rctLock);
1072 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1075 #ifdef DEBUG_SMB_REFCOUNT
1076 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1078 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1083 lock_ObtainWrite(&smb_rctLock);
1085 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1086 if (tidp->refCount == 0 && tidp->deleteOk) {
1088 smb_ReleaseTID(tidp, TRUE);
1092 if (tid == tidp->tid) {
1097 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1098 tidp = malloc(sizeof(*tidp));
1099 memset(tidp, 0, sizeof(*tidp));
1100 tidp->nextp = vcp->tidsp;
1103 smb_HoldVCNoLock(vcp);
1105 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1108 #ifdef DEBUG_SMB_REFCOUNT
1110 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1111 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1114 lock_ReleaseWrite(&smb_rctLock);
1118 #ifdef DEBUG_SMB_REFCOUNT
1119 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1121 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1124 lock_AssertWrite(&smb_rctLock);
1126 #ifdef DEBUG_SMB_REFCOUNT
1127 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1128 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1132 #ifdef DEBUG_SMB_REFCOUNT
1133 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1135 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1140 cm_user_t *userp = NULL;
1141 smb_vc_t *vcp = NULL;
1144 lock_ObtainWrite(&smb_rctLock);
1146 lock_AssertWrite(&smb_rctLock);
1148 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1149 #ifdef DEBUG_SMB_REFCOUNT
1150 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1151 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1153 if (tidp->refCount == 0) {
1154 if (tidp->deleteOk) {
1155 ltpp = &tidp->vcp->tidsp;
1156 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1160 osi_assertx(tp != NULL, "null smb_tid_t");
1162 lock_FinalizeMutex(&tidp->mx);
1163 userp = tidp->userp; /* remember to drop ref later */
1171 smb_ReleaseVCNoLock(vcp);
1173 lock_ReleaseWrite(&smb_rctLock);
1175 cm_ReleaseUser(userp);
1178 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1180 smb_user_t *uidp = NULL;
1182 lock_ObtainWrite(&smb_rctLock);
1183 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1184 if (uid == uidp->userID) {
1186 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1188 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1192 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1193 uidp = malloc(sizeof(*uidp));
1194 memset(uidp, 0, sizeof(*uidp));
1195 uidp->nextp = vcp->usersp;
1196 uidp->refCount = 2; /* one for the vcp and one for the caller */
1198 smb_HoldVCNoLock(vcp);
1200 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1202 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1204 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1206 lock_ReleaseWrite(&smb_rctLock);
1210 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1213 smb_username_t *unp= NULL;
1215 lock_ObtainWrite(&smb_rctLock);
1216 for(unp = usernamesp; unp; unp = unp->nextp) {
1217 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1218 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1223 if (!unp && (flags & SMB_FLAG_CREATE)) {
1224 unp = malloc(sizeof(*unp));
1225 memset(unp, 0, sizeof(*unp));
1227 unp->nextp = usernamesp;
1228 unp->name = cm_ClientStrDup(usern);
1229 unp->machine = cm_ClientStrDup(machine);
1231 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1232 if (flags & SMB_FLAG_AFSLOGON)
1233 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1236 lock_ReleaseWrite(&smb_rctLock);
1240 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1242 smb_user_t *uidp= NULL;
1244 lock_ObtainWrite(&smb_rctLock);
1245 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1248 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1250 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1251 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1256 lock_ReleaseWrite(&smb_rctLock);
1260 void smb_ReleaseUsername(smb_username_t *unp)
1263 smb_username_t **lupp;
1264 cm_user_t *userp = NULL;
1265 time_t now = osi_Time();
1267 lock_ObtainWrite(&smb_rctLock);
1268 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1269 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1270 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1272 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1276 osi_assertx(up != NULL, "null smb_username_t");
1278 up->nextp = NULL; /* do not remove this */
1279 lock_FinalizeMutex(&unp->mx);
1285 lock_ReleaseWrite(&smb_rctLock);
1287 cm_ReleaseUser(userp);
1290 void smb_HoldUIDNoLock(smb_user_t *uidp)
1292 lock_AssertWrite(&smb_rctLock);
1296 void smb_ReleaseUID(smb_user_t *uidp)
1300 smb_username_t *unp = NULL;
1302 lock_ObtainWrite(&smb_rctLock);
1303 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1304 if (uidp->refCount == 0) {
1305 lupp = &uidp->vcp->usersp;
1306 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1310 osi_assertx(up != NULL, "null smb_user_t");
1312 lock_FinalizeMutex(&uidp->mx);
1314 smb_ReleaseVCNoLock(uidp->vcp);
1318 lock_ReleaseWrite(&smb_rctLock);
1322 cm_ReleaseUserVCRef(unp->userp);
1323 smb_ReleaseUsername(unp);
1327 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1329 cm_user_t *up = NULL;
1334 lock_ObtainMutex(&uidp->mx);
1336 up = uidp->unp->userp;
1339 lock_ReleaseMutex(&uidp->mx);
1345 /* retrieve a held reference to a user structure corresponding to an incoming
1347 * corresponding release function is cm_ReleaseUser.
1349 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1352 cm_user_t *up = NULL;
1355 smbp = (smb_t *) inp;
1356 uidp = smb_FindUID(vcp, smbp->uid, 0);
1360 up = smb_GetUserFromUID(uidp);
1362 smb_ReleaseUID(uidp);
1367 * Return a pointer to a pathname extracted from a TID structure. The
1368 * TID structure is not held; assume it won't go away.
1370 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1375 tidp = smb_FindTID(vcp, tid, 0);
1379 if (tidp->flags & SMB_TIDFLAG_IPC) {
1380 code = CM_ERROR_TIDIPC;
1381 /* tidp->pathname would be NULL, but that's fine */
1383 *treepath = tidp->pathname;
1384 smb_ReleaseTID(tidp, FALSE);
1389 /* check to see if we have a chained fid, that is, a fid that comes from an
1390 * OpenAndX message that ran earlier in this packet. In this case, the fid
1391 * field in a read, for example, request, isn't set, since the value is
1392 * supposed to be inherited from the openAndX call.
1394 int smb_ChainFID(int fid, smb_packet_t *inp)
1396 if (inp->fid == 0 || inp->inCount == 0)
1402 /* are we a priv'd user? What does this mean on NT? */
1403 int smb_SUser(cm_user_t *userp)
1408 /* find a file ID. If we pass in 0 we select an unused File ID.
1409 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1410 * smb_fid_t data structure if desired File ID cannot be found.
1412 #ifdef DEBUG_SMB_REFCOUNT
1413 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1415 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1422 if (!(flags & SMB_FLAG_CREATE))
1427 lock_ObtainWrite(&smb_rctLock);
1429 fid = vcp->fidCounter;
1432 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1433 if (fidp->refCount == 0 && fidp->deleteOk) {
1435 lock_ReleaseWrite(&smb_rctLock);
1436 smb_ReleaseFID(fidp);
1437 lock_ObtainWrite(&smb_rctLock);
1439 * We dropped the smb_rctLock so the fid value we are using
1440 * may now be used by another thread. Start over with the
1441 * current vcp->fidCounter.
1444 fid = vcp->fidCounter;
1447 if (fid == fidp->fid) {
1449 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1451 if (fid == 0xFFFF) {
1453 "New FID number wraps on vcp 0x%x", vcp);
1463 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1464 char eventName[MAX_PATH];
1468 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1470 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1472 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1473 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1474 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1475 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1476 thrd_CloseHandle(event);
1478 if (fid == 0xFFFF) {
1479 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1485 fidp = malloc(sizeof(*fidp));
1486 memset(fidp, 0, sizeof(*fidp));
1487 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1490 smb_HoldVCNoLock(vcp);
1491 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1493 fidp->curr_chunk = fidp->prev_chunk = -2;
1494 fidp->raw_write_event = event;
1496 vcp->fidCounter = fid+1;
1497 if (vcp->fidCounter == 0xFFFF) {
1498 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1500 vcp->fidCounter = 1;
1505 #ifdef DEBUG_SMB_REFCOUNT
1507 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1508 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1511 lock_ReleaseWrite(&smb_rctLock);
1516 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1517 #ifdef DEBUG_SMB_REFCOUNT
1518 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1520 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1523 smb_fid_t *fidp = NULL, *nextp = NULL;
1529 * If the fidp->scp changes out from under us then
1530 * we must not grab a refCount. It means the *fidp
1531 * was processed by smb_CloseFID() and the *fidp is
1532 * no longer valid for use.
1534 lock_ObtainWrite(&smb_rctLock);
1535 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1536 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1540 if (scp == fidp->scp) {
1541 lock_ReleaseWrite(&smb_rctLock);
1542 lock_ObtainMutex(&fidp->mx);
1543 lock_ObtainWrite(&smb_rctLock);
1544 if (scp == fidp->scp) {
1545 lock_ReleaseMutex(&fidp->mx);
1548 lock_ReleaseMutex(&fidp->mx);
1551 if (fidp->refCount > 1) {
1554 lock_ReleaseWrite(&smb_rctLock);
1555 smb_ReleaseFID(fidp);
1556 lock_ObtainWrite(&smb_rctLock);
1561 if (nextp->refCount > 1) {
1564 lock_ReleaseWrite(&smb_rctLock);
1565 smb_ReleaseFID(nextp);
1566 lock_ObtainWrite(&smb_rctLock);
1570 #ifdef DEBUG_SMB_REFCOUNT
1572 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1573 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1576 lock_ReleaseWrite(&smb_rctLock);
1580 #ifdef DEBUG_SMB_REFCOUNT
1581 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1583 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1586 lock_AssertWrite(&smb_rctLock);
1588 #ifdef DEBUG_SMB_REFCOUNT
1589 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1590 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1596 /* the smb_fid_t->mx and smb_rctLock must not be held */
1597 #ifdef DEBUG_SMB_REFCOUNT
1598 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1600 void smb_ReleaseFID(smb_fid_t *fidp)
1603 cm_scache_t *scp = NULL;
1604 cm_user_t *userp = NULL;
1605 smb_vc_t *vcp = NULL;
1606 smb_ioctl_t *ioctlp;
1608 lock_ObtainMutex(&fidp->mx);
1609 lock_ObtainWrite(&smb_rctLock);
1610 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1611 #ifdef DEBUG_SMB_REFCOUNT
1612 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1613 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1615 if (fidp->refCount == 0) {
1616 if (fidp->deleteOk) {
1619 scp = fidp->scp; /* release after lock is released */
1621 lock_ObtainWrite(&scp->rw);
1622 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1623 lock_ReleaseWrite(&scp->rw);
1624 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1627 userp = fidp->userp;
1631 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1632 thrd_CloseHandle(fidp->raw_write_event);
1634 /* and see if there is ioctl stuff to free */
1635 ioctlp = fidp->ioctlp;
1638 cm_FreeSpace(ioctlp->prefix);
1639 if (ioctlp->ioctl.inAllocp)
1640 free(ioctlp->ioctl.inAllocp);
1641 if (ioctlp->ioctl.outAllocp)
1642 free(ioctlp->ioctl.outAllocp);
1646 smb_CleanupRPCFid(fidp);
1648 lock_ReleaseMutex(&fidp->mx);
1649 lock_FinalizeMutex(&fidp->mx);
1654 smb_ReleaseVCNoLock(vcp);
1658 lock_ReleaseMutex(&fidp->mx);
1660 lock_ReleaseWrite(&smb_rctLock);
1662 /* now release the scache structure */
1664 cm_ReleaseSCache(scp);
1667 cm_ReleaseUser(userp);
1671 * Case-insensitive search for one string in another;
1672 * used to find variable names in submount pathnames.
1674 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1676 clientchar_t *cursor;
1678 for (cursor = str1; *cursor; cursor++)
1679 if (cm_ClientStrCmpI(cursor, str2) == 0)
1686 * Substitute a variable value for its name in a submount pathname. Variable
1687 * name has been identified by smb_stristr() and is in substr. Variable name
1688 * length (plus one) is in substr_size. Variable value is in newstr.
1690 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1691 unsigned int substr_size, clientchar_t *newstr)
1693 clientchar_t temp[1024];
1695 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1696 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1697 cm_ClientStrCat(str1, cchstr1, temp);
1700 clientchar_t VNUserName[] = _C("%USERNAME%");
1701 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1702 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1703 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1705 typedef struct smb_findShare_rock {
1706 clientchar_t * shareName;
1707 clientchar_t * match;
1709 } smb_findShare_rock_t;
1711 #define SMB_FINDSHARE_EXACT_MATCH 1
1712 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1714 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1718 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1719 normchar_t normName[MAX_PATH];
1721 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1722 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1723 osi_LogSaveString(smb_logp, dep->name));
1727 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1728 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1729 matchType = SMB_FINDSHARE_EXACT_MATCH;
1731 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1734 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1735 vrock->matchType = matchType;
1737 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1738 return CM_ERROR_STOPNOW;
1744 /* find a shareName in the table of submounts */
1745 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1746 clientchar_t *shareName,
1747 clientchar_t **pathNamep)
1751 clientchar_t pathName[1024];
1754 clientchar_t *p, *q;
1755 fschar_t *cellname = NULL;
1758 DWORD allSubmount = 1;
1760 /* if allSubmounts == 0, only return the //mountRoot/all share
1761 * if in fact it has been been created in the subMounts table.
1762 * This is to allow sites that want to restrict access to the
1765 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1766 0, KEY_QUERY_VALUE, &parmKey);
1767 if (code == ERROR_SUCCESS) {
1768 cblen = sizeof(allSubmount);
1769 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1770 (BYTE *) &allSubmount, &cblen);
1771 if (code != ERROR_SUCCESS) {
1774 RegCloseKey (parmKey);
1777 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1782 /* In case, the all share is disabled we need to still be able
1783 * to handle ioctl requests
1785 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1786 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1790 if (MSRPC_IsWellKnownService(shareName) ||
1791 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1792 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1798 /* Check for volume references
1800 * They look like <cell>{%,#}<volume>
1802 if (cm_ClientStrChr(shareName, '%') != NULL ||
1803 cm_ClientStrChr(shareName, '#') != NULL) {
1804 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1805 /* make room for '/@vol:' + mountchar + NULL terminator*/
1807 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1808 osi_LogSaveClientString(smb_logp, shareName));
1810 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1811 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1812 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1814 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1816 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1817 cm_ClientStrLwr(*pathNamep);
1818 osi_Log1(smb_logp, " returning pathname [%S]",
1819 osi_LogSaveClientString(smb_logp, *pathNamep));
1827 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1828 0, KEY_QUERY_VALUE, &parmKey);
1829 if (code == ERROR_SUCCESS) {
1830 cblen = sizeof(pathName);
1831 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1832 (BYTE *) pathName, &cblen);
1833 if (code != ERROR_SUCCESS)
1835 RegCloseKey (parmKey);
1839 cchlen = cblen / sizeof(clientchar_t);
1840 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1841 /* We can accept either unix or PC style AFS pathnames. Convert
1842 * Unix-style to PC style here for internal use.
1845 cchlen = lengthof(pathName);
1847 /* within this code block, we maintain, cchlen = writeable
1848 buffer length of p */
1850 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1851 p += cm_mountRootCLen; /* skip mount path */
1852 cchlen -= (DWORD)(p - pathName);
1857 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1863 clientchar_t temp[1024];
1865 if (var = smb_stristr(p, VNUserName)) {
1866 if (uidp && uidp->unp)
1867 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1869 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1871 else if (var = smb_stristr(p, VNLCUserName))
1873 if (uidp && uidp->unp)
1874 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1876 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1877 cm_ClientStrLwr(temp);
1878 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1880 else if (var = smb_stristr(p, VNComputerName))
1882 sizeTemp = lengthof(temp);
1883 GetComputerNameW(temp, &sizeTemp);
1884 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1886 else if (var = smb_stristr(p, VNLCComputerName))
1888 sizeTemp = lengthof(temp);
1889 GetComputerName((LPTSTR)temp, &sizeTemp);
1890 cm_ClientStrLwr(temp);
1891 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1896 *pathNamep = cm_ClientStrDup(p);
1901 /* First lookup shareName in root.afs */
1903 smb_findShare_rock_t vrock;
1905 fschar_t ftemp[1024];
1906 clientchar_t * p = shareName;
1909 /* attempt to locate a partial match in root.afs. This is because
1910 when using the ANSI RAP calls, the share name is limited to 13 chars
1911 and hence is truncated. Of course we prefer exact matches. */
1913 thyper.HighPart = 0;
1916 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1917 if (vrock.shareName == NULL)
1920 vrock.matchType = 0;
1922 cm_HoldSCache(cm_data.rootSCachep);
1923 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1924 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1925 cm_ReleaseSCache(cm_data.rootSCachep);
1927 free(vrock.shareName);
1928 vrock.shareName = NULL;
1930 if (vrock.matchType) {
1931 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1932 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1937 /* if we get here, there was no match for the share in root.afs */
1938 /* so try to create \\<netbiosName>\<cellname> */
1943 /* Get the full name for this cell */
1944 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1945 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
1946 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
1947 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1948 #ifdef AFS_AFSDB_ENV
1949 if (code && cm_dnsEnabled) {
1951 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1957 /* construct the path */
1959 clientchar_t temp[1024];
1961 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
1962 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
1963 rw ? _C("/.%S/") : _C("/%S/"), temp);
1964 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1974 /* Client-side offline caching policy types */
1975 #define CSC_POLICY_MANUAL 0
1976 #define CSC_POLICY_DOCUMENTS 1
1977 #define CSC_POLICY_PROGRAMS 2
1978 #define CSC_POLICY_DISABLE 3
1980 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1983 clientchar_t policy[1024];
1986 int retval = CSC_POLICY_MANUAL;
1988 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1989 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1992 REG_OPTION_NON_VOLATILE,
1996 NULL ) != ERROR_SUCCESS)
1997 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1999 len = sizeof(policy);
2000 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2002 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2004 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2006 retval = CSC_POLICY_MANUAL;
2008 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2010 retval = CSC_POLICY_DOCUMENTS;
2012 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2014 retval = CSC_POLICY_PROGRAMS;
2016 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2018 retval = CSC_POLICY_DISABLE;
2021 RegCloseKey(hkCSCPolicy);
2025 /* find a dir search structure by cookie value, and return it held.
2026 * Must be called with smb_globalLock held.
2028 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2030 smb_dirSearch_t *dsp;
2032 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2033 if (dsp->cookie == cookie) {
2034 if (dsp != smb_firstDirSearchp) {
2035 /* move to head of LRU queue, too, if we're not already there */
2036 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2037 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2038 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2039 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2040 if (!smb_lastDirSearchp)
2041 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2049 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2050 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2051 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2057 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2059 lock_ObtainMutex(&dsp->mx);
2060 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2061 dsp->cookie, dsp, dsp->scp);
2062 dsp->flags |= SMB_DIRSEARCH_DELETE;
2063 if (dsp->scp != NULL) {
2064 lock_ObtainWrite(&dsp->scp->rw);
2065 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2066 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2067 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2068 dsp->scp->bulkStatProgress = hzero;
2070 lock_ReleaseWrite(&dsp->scp->rw);
2072 lock_ReleaseMutex(&dsp->mx);
2075 /* Must be called with the smb_globalLock held */
2076 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2078 cm_scache_t *scp = NULL;
2080 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2081 if (dsp->refCount == 0) {
2082 lock_ObtainMutex(&dsp->mx);
2083 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2084 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2085 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2086 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2087 lock_ReleaseMutex(&dsp->mx);
2088 lock_FinalizeMutex(&dsp->mx);
2090 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2091 dsp->cookie, dsp, scp);
2094 lock_ReleaseMutex(&dsp->mx);
2097 /* do this now to avoid spurious locking hierarchy creation */
2099 cm_ReleaseSCache(scp);
2102 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2104 lock_ObtainWrite(&smb_globalLock);
2105 smb_ReleaseDirSearchNoLock(dsp);
2106 lock_ReleaseWrite(&smb_globalLock);
2109 /* find a dir search structure by cookie value, and return it held */
2110 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2112 smb_dirSearch_t *dsp;
2114 lock_ObtainWrite(&smb_globalLock);
2115 dsp = smb_FindDirSearchNoLock(cookie);
2116 lock_ReleaseWrite(&smb_globalLock);
2120 /* GC some dir search entries, in the address space expected by the specific protocol.
2121 * Must be called with smb_globalLock held; release the lock temporarily.
2123 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2124 void smb_GCDirSearches(int isV3)
2126 smb_dirSearch_t *prevp;
2127 smb_dirSearch_t *dsp;
2128 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2132 victimCount = 0; /* how many have we got so far */
2133 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2134 /* we'll move tp from queue, so
2137 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2138 /* if no one is using this guy, and we're either in the new protocol,
2139 * or we're in the old one and this is a small enough ID to be useful
2140 * to the old protocol, GC this guy.
2142 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2143 /* hold and delete */
2144 lock_ObtainMutex(&dsp->mx);
2145 dsp->flags |= SMB_DIRSEARCH_DELETE;
2146 lock_ReleaseMutex(&dsp->mx);
2147 victimsp[victimCount++] = dsp;
2151 /* don't do more than this */
2152 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2156 /* now release them */
2157 for (i = 0; i < victimCount; i++) {
2158 smb_ReleaseDirSearchNoLock(victimsp[i]);
2162 /* function for allocating a dir search entry. We need these to remember enough context
2163 * since we don't get passed the path from call to call during a directory search.
2165 * Returns a held dir search structure, and bumps the reference count on the vnode,
2166 * since it saves a pointer to the vnode.
2168 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2170 smb_dirSearch_t *dsp;
2176 lock_ObtainWrite(&smb_globalLock);
2179 /* what's the biggest ID allowed in this version of the protocol */
2180 /* TODO: do we really want a non v3 dir search request to wrap
2181 smb_dirSearchCounter? */
2182 maxAllowed = isV3 ? 65535 : 255;
2183 if (smb_dirSearchCounter > maxAllowed)
2184 smb_dirSearchCounter = 1;
2186 start = smb_dirSearchCounter;
2189 /* twice so we have enough tries to find guys we GC after one pass;
2190 * 10 extra is just in case I mis-counted.
2192 if (++counter > 2*maxAllowed+10)
2193 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2195 if (smb_dirSearchCounter > maxAllowed) {
2196 smb_dirSearchCounter = 1;
2198 if (smb_dirSearchCounter == start) {
2200 smb_GCDirSearches(isV3);
2203 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2205 /* don't need to watch for refcount zero and deleted, since
2206 * we haven't dropped the global lock.
2209 ++smb_dirSearchCounter;
2213 dsp = malloc(sizeof(*dsp));
2214 memset(dsp, 0, sizeof(*dsp));
2215 dsp->cookie = smb_dirSearchCounter;
2216 ++smb_dirSearchCounter;
2218 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2219 dsp->lastTime = osi_Time();
2220 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2221 if (!smb_lastDirSearchp)
2222 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2224 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2228 lock_ReleaseWrite(&smb_globalLock);
2232 static smb_packet_t *smb_GetPacket(void)
2236 lock_ObtainWrite(&smb_globalLock);
2237 tbp = smb_packetFreeListp;
2239 smb_packetFreeListp = tbp->nextp;
2240 lock_ReleaseWrite(&smb_globalLock);
2242 tbp = calloc(sizeof(*tbp),1);
2243 tbp->magic = SMB_PACKETMAGIC;
2246 tbp->resumeCode = 0;
2252 tbp->ncb_length = 0;
2255 tbp->stringsp = NULL;
2257 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2262 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2265 tbp = smb_GetPacket();
2266 memcpy(tbp, pkt, sizeof(smb_packet_t));
2267 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2268 tbp->stringsp = NULL;
2270 smb_HoldVC(tbp->vcp);
2274 static NCB *smb_GetNCB(void)
2279 lock_ObtainWrite(&smb_globalLock);
2280 tbp = smb_ncbFreeListp;
2282 smb_ncbFreeListp = tbp->nextp;
2283 lock_ReleaseWrite(&smb_globalLock);
2285 tbp = calloc(sizeof(*tbp),1);
2286 tbp->magic = SMB_NCBMAGIC;
2289 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2291 memset(&tbp->ncb, 0, sizeof(NCB));
2296 static void FreeSMBStrings(smb_packet_t * pkt)
2301 for (s = pkt->stringsp; s; s = ns) {
2305 pkt->stringsp = NULL;
2308 void smb_FreePacket(smb_packet_t *tbp)
2310 smb_vc_t * vcp = NULL;
2311 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2313 lock_ObtainWrite(&smb_globalLock);
2314 tbp->nextp = smb_packetFreeListp;
2315 smb_packetFreeListp = tbp;
2316 tbp->magic = SMB_PACKETMAGIC;
2320 tbp->resumeCode = 0;
2326 tbp->ncb_length = 0;
2328 FreeSMBStrings(tbp);
2329 lock_ReleaseWrite(&smb_globalLock);
2335 static void smb_FreeNCB(NCB *bufferp)
2339 tbp = (smb_ncb_t *) bufferp;
2340 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2342 lock_ObtainWrite(&smb_globalLock);
2343 tbp->nextp = smb_ncbFreeListp;
2344 smb_ncbFreeListp = tbp;
2345 lock_ReleaseWrite(&smb_globalLock);
2348 /* get a ptr to the data part of a packet, and its count */
2349 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2353 unsigned char *afterParmsp;
2355 parmBytes = *smbp->wctp << 1;
2356 afterParmsp = smbp->wctp + parmBytes + 1;
2358 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2359 if (nbytesp) *nbytesp = dataBytes;
2361 /* don't forget to skip the data byte count, since it follows
2362 * the parameters; that's where the "2" comes from below.
2364 return (unsigned char *) (afterParmsp + 2);
2367 /* must set all the returned parameters before playing around with the
2368 * data region, since the data region is located past the end of the
2369 * variable number of parameters.
2371 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2373 unsigned char *afterParmsp;
2375 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2377 *afterParmsp++ = dsize & 0xff;
2378 *afterParmsp = (dsize>>8) & 0xff;
2381 /* return the parm'th parameter in the smbp packet */
2382 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2385 unsigned char *parmDatap;
2387 parmCount = *smbp->wctp;
2389 if (parm >= parmCount) {
2392 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2393 parm, parmCount, smbp->ncb_length);
2394 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2395 parm, parmCount, smbp->ncb_length);
2396 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2397 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2398 osi_panic(s, __FILE__, __LINE__);
2400 parmDatap = smbp->wctp + (2*parm) + 1;
2402 return parmDatap[0] + (parmDatap[1] << 8);
2405 /* return the parm'th parameter in the smbp packet */
2406 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2409 unsigned char *parmDatap;
2411 parmCount = *smbp->wctp;
2413 if (parm >= parmCount) {
2416 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2417 parm, parmCount, smbp->ncb_length);
2418 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2419 parm, parmCount, smbp->ncb_length);
2420 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2421 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2422 osi_panic(s, __FILE__, __LINE__);
2424 parmDatap = smbp->wctp + (2*parm) + 1;
2426 return parmDatap[0];
2429 /* return the parm'th parameter in the smbp packet */
2430 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2433 unsigned char *parmDatap;
2435 parmCount = *smbp->wctp;
2437 if (parm + 1 >= parmCount) {
2440 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2441 parm, parmCount, smbp->ncb_length);
2442 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2443 parm, parmCount, smbp->ncb_length);
2444 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2445 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2446 osi_panic(s, __FILE__, __LINE__);
2448 parmDatap = smbp->wctp + (2*parm) + 1;
2450 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2453 /* return the parm'th parameter in the smbp packet */
2454 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2457 unsigned char *parmDatap;
2459 parmCount = *smbp->wctp;
2461 if (parm * 2 + offset >= parmCount * 2) {
2464 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2465 parm, offset, parmCount, smbp->ncb_length);
2466 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2467 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2468 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2469 parm, offset, parmCount, smbp->ncb_length);
2470 osi_panic(s, __FILE__, __LINE__);
2472 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2474 return parmDatap[0] + (parmDatap[1] << 8);
2477 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2479 unsigned char *parmDatap;
2481 /* make sure we have enough slots */
2482 if (*smbp->wctp <= slot)
2483 *smbp->wctp = slot+1;
2485 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2486 *parmDatap++ = parmValue & 0xff;
2487 *parmDatap = (parmValue>>8) & 0xff;
2490 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2492 unsigned char *parmDatap;
2494 /* make sure we have enough slots */
2495 if (*smbp->wctp <= slot)
2496 *smbp->wctp = slot+2;
2498 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2499 *parmDatap++ = parmValue & 0xff;
2500 *parmDatap++ = (parmValue>>8) & 0xff;
2501 *parmDatap++ = (parmValue>>16) & 0xff;
2502 *parmDatap = (parmValue>>24) & 0xff;
2505 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2507 unsigned char *parmDatap;
2510 /* make sure we have enough slots */
2511 if (*smbp->wctp <= slot)
2512 *smbp->wctp = slot+4;
2514 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2516 *parmDatap++ = *parmValuep++;
2519 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2521 unsigned char *parmDatap;
2523 /* make sure we have enough slots */
2524 if (*smbp->wctp <= slot) {
2525 if (smbp->oddByte) {
2527 *smbp->wctp = slot+1;
2532 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2533 *parmDatap++ = parmValue & 0xff;
2538 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2539 clientchar_t *inPathp)
2541 clientchar_t *lastSlashp;
2542 clientchar_t *streamp = NULL;
2543 clientchar_t *typep = NULL;
2545 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2546 if (lastComponentp) {
2547 *lastComponentp = lastSlashp;
2551 * If the name contains a stream name and a type
2552 * and the stream name is the nul-string and the
2553 * type is $DATA, then strip "::$DATA" from the
2554 * last component string that is returned.
2556 * Otherwise, return the full path name and allow
2557 * the file name to be rejected because it contains
2560 typep = cm_ClientStrRChr(lastSlashp, L':');
2561 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2563 streamp = cm_ClientStrRChr(lastSlashp, L':');
2564 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2568 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2569 osi_LogSaveClientString(smb_logp,streamp),
2570 osi_LogSaveClientString(smb_logp,typep));
2574 if (inPathp == lastSlashp)
2576 *outPathp++ = *inPathp++;
2585 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2586 char **chainpp, int flags)
2589 afs_uint32 type = *inp++;
2592 * The first byte specifies the type of the input string.
2593 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2597 /* Length Counted */
2598 case 0x1: /* Data Block */
2599 case 0x5: /* Variable Block */
2600 cb = *inp++ << 16 | *inp++;
2603 /* Null-terminated string */
2604 case 0x4: /* ASCII */
2605 case 0x3: /* Pathname */
2606 case 0x2: /* Dialect */
2607 cb = sizeof(pktp->data) - (inp - pktp->data);
2608 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2609 #ifdef DEBUG_UNICODE
2612 cb = sizeof(pktp->data);
2617 return NULL; /* invalid input */
2621 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2622 flags |= SMB_STRF_FORCEASCII;
2625 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2628 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2629 char ** chainpp, int flags)
2634 if (!WANTS_UNICODE(pktp))
2635 flags |= SMB_STRF_FORCEASCII;
2638 cb = sizeof(pktp->data) - (inp - pktp->data);
2639 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2640 #ifdef DEBUG_UNICODE
2643 cb = sizeof(pktp->data);
2645 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2646 flags | SMB_STRF_SRCNULTERM);
2649 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2650 size_t cb, char ** chainpp, int flags)
2653 if (!WANTS_UNICODE(pktp))
2654 flags |= SMB_STRF_FORCEASCII;
2657 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2660 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2661 size_t cch, char ** chainpp, int flags)
2666 if (!WANTS_UNICODE(pktp))
2667 flags |= SMB_STRF_FORCEASCII;
2669 cb = cch * sizeof(wchar_t);
2672 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2676 smb_ParseStringBuf(const unsigned char * bufbase,
2677 cm_space_t ** stringspp,
2678 unsigned char *inp, size_t *pcb_max,
2679 char **chainpp, int flags)
2682 if (!(flags & SMB_STRF_FORCEASCII)) {
2684 cm_space_t * spacep;
2687 if (bufbase && ((inp - bufbase) % 2) != 0) {
2688 inp++; /* unicode strings are always word aligned */
2692 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2694 cch_src = *pcb_max / sizeof(wchar_t);
2698 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2705 spacep = cm_GetSpace();
2706 spacep->nextp = *stringspp;
2707 *stringspp = spacep;
2711 *chainpp = inp + sizeof(wchar_t);
2714 *(spacep->wdata) = 0;
2715 return spacep->wdata;
2718 StringCchCopyNW(spacep->wdata,
2719 lengthof(spacep->wdata),
2720 (const clientchar_t *) inp, cch_src);
2723 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2725 return spacep->wdata;
2729 cm_space_t * spacep;
2732 /* Not using Unicode */
2734 *chainpp = inp + strlen(inp) + 1;
2737 spacep = cm_GetSpace();
2738 spacep->nextp = *stringspp;
2739 *stringspp = spacep;
2741 cchdest = lengthof(spacep->wdata);
2742 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2743 spacep->wdata, cchdest);
2745 return spacep->wdata;
2751 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2753 size_t * plen, int flags)
2759 /* we are only calculating the required size */
2766 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2768 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2769 if (!(flags & SMB_STRF_IGNORENUL))
2770 *plen += sizeof(wchar_t);
2772 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2782 cch_str = cm_ClientStrLen(str);
2783 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2786 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2794 /* if outp != NULL ... */
2796 /* Number of bytes left in the buffer.
2798 If outp lies inside the packet data buffer, we assume that the
2799 buffer is the packet data buffer. Otherwise we assume that the
2800 buffer is sizeof(packet->data).
2803 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2804 align = (int)((outp - pktp->data) % 2);
2805 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2807 align = (int)(((size_t) outp) % 2);
2808 buffersize = (int)sizeof(pktp->data);
2813 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2819 if (*str == _C('\0')) {
2821 if (buffersize < sizeof(wchar_t))
2824 *((wchar_t *) outp) = L'\0';
2825 if (plen && !(flags & SMB_STRF_IGNORENUL))
2826 *plen += sizeof(wchar_t);
2827 return outp + sizeof(wchar_t);
2830 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2832 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2833 osi_LogSaveClientString(smb_logp, str),
2839 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2841 return outp + sizeof(wchar_t) * nchars;
2849 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2852 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2854 return outp + cch_dest;
2858 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2864 tlen = inp[0] + (inp[1]<<8);
2865 inp += 2; /* skip length field */
2868 *chainpp = inp + tlen;
2877 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2881 if (*inp++ != 0x1) return NULL;
2882 tlen = inp[0] + (inp[1]<<8);
2883 inp += 2; /* skip length field */
2886 *chainpp = inp + tlen;
2889 if (lengthp) *lengthp = tlen;
2894 /* format a packet as a response */
2895 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2900 outp = (smb_t *) op;
2902 /* zero the basic structure through the smb_wct field, and zero the data
2903 * size field, assuming that wct stays zero; otherwise, you have to
2904 * explicitly set the data size field, too.
2906 inSmbp = (smb_t *) inp;
2907 memset(outp, 0, sizeof(smb_t)+2);
2913 outp->com = inSmbp->com;
2914 outp->tid = inSmbp->tid;
2915 outp->pid = inSmbp->pid;
2916 outp->uid = inSmbp->uid;
2917 outp->mid = inSmbp->mid;
2918 outp->res[0] = inSmbp->res[0];
2919 outp->res[1] = inSmbp->res[1];
2920 op->inCom = inSmbp->com;
2922 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2923 #ifdef SEND_CANONICAL_PATHNAMES
2924 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2926 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2928 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2929 outp->flg2 |= SMB_FLAGS2_UNICODE;
2932 /* copy fields in generic packet area */
2933 op->wctp = &outp->wct;
2936 /* send a (probably response) packet; vcp tells us to whom to send it.
2937 * we compute the length by looking at wct and bcc fields.
2939 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2949 ncbp = smb_GetNCB();
2953 memset((char *)ncbp, 0, sizeof(NCB));
2955 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2956 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2957 extra += tp[0] + (tp[1]<<8);
2958 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2959 extra += 3; /* wct and length fields */
2961 ncbp->ncb_length = extra; /* bytes to send */
2962 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2963 ncbp->ncb_lana_num = vcp->lana;
2964 ncbp->ncb_command = NCBSEND; /* op means send data */
2965 ncbp->ncb_buffer = (char *) inp;/* packet */
2966 code = Netbios(ncbp);
2969 const char * s = ncb_error_string(code);
2970 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2971 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2973 lock_ObtainMutex(&vcp->mx);
2974 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2975 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2977 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2978 lock_ReleaseMutex(&vcp->mx);
2979 lock_ObtainWrite(&smb_globalLock);
2980 dead_sessions[vcp->session] = TRUE;
2981 lock_ReleaseWrite(&smb_globalLock);
2982 smb_CleanupDeadVC(vcp);
2984 lock_ReleaseMutex(&vcp->mx);
2992 void smb_MapNTError(long code, unsigned long *NTStatusp)
2994 unsigned long NTStatus;
2996 /* map CM_ERROR_* errors to NT 32-bit status codes */
2997 /* NT Status codes are listed in ntstatus.h not winerror.h */
3001 else if (code == CM_ERROR_NOSUCHCELL) {
3002 NTStatus = 0xC0000034L; /* Name not found */
3004 else if (code == CM_ERROR_NOSUCHVOLUME) {
3005 NTStatus = 0xC0000034L; /* Name not found */
3007 else if (code == CM_ERROR_TIMEDOUT) {
3009 NTStatus = 0xC00000CFL; /* Sharing Paused */
3011 NTStatus = 0x00000102L; /* Timeout */
3014 else if (code == CM_ERROR_RETRY) {
3015 NTStatus = 0xC000022DL; /* Retry */
3017 else if (code == CM_ERROR_NOACCESS) {
3018 NTStatus = 0xC0000022L; /* Access denied */
3020 else if (code == CM_ERROR_READONLY) {
3021 NTStatus = 0xC00000A2L; /* Write protected */
3023 else if (code == CM_ERROR_NOSUCHFILE ||
3024 code == CM_ERROR_BPLUS_NOMATCH) {
3025 NTStatus = 0xC0000034L; /* Name not found */
3027 else if (code == CM_ERROR_NOSUCHPATH) {
3028 NTStatus = 0xC000003AL; /* Object path not found */
3030 else if (code == CM_ERROR_TOOBIG) {
3031 NTStatus = 0xC000007BL; /* Invalid image format */
3033 else if (code == CM_ERROR_INVAL) {
3034 NTStatus = 0xC000000DL; /* Invalid parameter */
3036 else if (code == CM_ERROR_BADFD) {
3037 NTStatus = 0xC0000008L; /* Invalid handle */
3039 else if (code == CM_ERROR_BADFDOP) {
3040 NTStatus = 0xC0000022L; /* Access denied */
3042 else if (code == CM_ERROR_EXISTS) {
3043 NTStatus = 0xC0000035L; /* Object name collision */
3045 else if (code == CM_ERROR_NOTEMPTY) {
3046 NTStatus = 0xC0000101L; /* Directory not empty */
3048 else if (code == CM_ERROR_CROSSDEVLINK) {
3049 NTStatus = 0xC00000D4L; /* Not same device */
3051 else if (code == CM_ERROR_NOTDIR) {
3052 NTStatus = 0xC0000103L; /* Not a directory */
3054 else if (code == CM_ERROR_ISDIR) {
3055 NTStatus = 0xC00000BAL; /* File is a directory */
3057 else if (code == CM_ERROR_BADOP) {
3059 /* I have no idea where this comes from */
3060 NTStatus = 0xC09820FFL; /* SMB no support */
3062 NTStatus = 0xC00000BBL; /* Not supported */
3063 #endif /* COMMENT */
3065 else if (code == CM_ERROR_BADSHARENAME) {
3066 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3068 else if (code == CM_ERROR_NOIPC) {
3070 NTStatus = 0xC0000022L; /* Access Denied */
3072 NTStatus = 0xC000013DL; /* Remote Resources */
3075 else if (code == CM_ERROR_CLOCKSKEW) {
3076 NTStatus = 0xC0000133L; /* Time difference at DC */
3078 else if (code == CM_ERROR_BADTID) {
3079 NTStatus = 0xC0982005L; /* SMB bad TID */
3081 else if (code == CM_ERROR_USESTD) {
3082 NTStatus = 0xC09820FBL; /* SMB use standard */
3084 else if (code == CM_ERROR_QUOTA) {
3085 NTStatus = 0xC0000044L; /* Quota exceeded */
3087 else if (code == CM_ERROR_SPACE) {
3088 NTStatus = 0xC000007FL; /* Disk full */
3090 else if (code == CM_ERROR_ATSYS) {
3091 NTStatus = 0xC0000033L; /* Object name invalid */
3093 else if (code == CM_ERROR_BADNTFILENAME) {
3094 NTStatus = 0xC0000033L; /* Object name invalid */
3096 else if (code == CM_ERROR_WOULDBLOCK) {
3097 NTStatus = 0xC00000D8L; /* Can't wait */
3099 else if (code == CM_ERROR_SHARING_VIOLATION) {
3100 NTStatus = 0xC0000043L; /* Sharing violation */
3102 else if (code == CM_ERROR_LOCK_CONFLICT) {
3103 NTStatus = 0xC0000054L; /* Lock conflict */
3105 else if (code == CM_ERROR_PARTIALWRITE) {
3106 NTStatus = 0xC000007FL; /* Disk full */
3108 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3109 NTStatus = 0xC0000023L; /* Buffer too small */
3111 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3112 NTStatus = 0xC0000035L; /* Object name collision */
3114 else if (code == CM_ERROR_BADPASSWORD) {
3115 NTStatus = 0xC000006DL; /* unknown username or bad password */
3117 else if (code == CM_ERROR_BADLOGONTYPE) {
3118 NTStatus = 0xC000015BL; /* logon type not granted */
3120 else if (code == CM_ERROR_GSSCONTINUE) {
3121 NTStatus = 0xC0000016L; /* more processing required */
3123 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3125 NTStatus = 0xC0000280L; /* reparse point not resolved */
3127 NTStatus = 0xC0000022L; /* Access Denied */
3130 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3131 NTStatus = 0xC0000257L; /* Path Not Covered */
3133 else if (code == CM_ERROR_ALLBUSY) {
3134 NTStatus = 0xC000022DL; /* Retry */
3136 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3137 NTStatus = 0xC000003AL; /* Path not found */
3139 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3140 NTStatus = 0xC0000322L; /* No Kerberos key */
3142 else if (code == CM_ERROR_BAD_LEVEL) {
3143 NTStatus = 0xC0000148L; /* Invalid Level */
3145 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3146 NTStatus = 0xC000007EL; /* Range Not Locked */
3148 else if (code == CM_ERROR_NOSUCHDEVICE) {
3149 NTStatus = 0xC000000EL; /* No Such Device */
3151 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3152 NTStatus = 0xC0000055L; /* Lock Not Granted */
3154 else if (code == ENOMEM) {
3155 NTStatus = 0xC0000017L; /* Out of Memory */
3157 else if (code == CM_ERROR_RPC_MOREDATA) {
3158 NTStatus = 0x80000005L; /* Buffer overflow */
3161 NTStatus = 0xC0982001L; /* SMB non-specific error */
3164 *NTStatusp = NTStatus;
3165 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3169 * NTSTATUS <-> Win32 Error Translation
3170 * http://support.microsoft.com/kb/113996
3172 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3174 unsigned long Win32E;
3176 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3180 else if (code == CM_ERROR_NOSUCHCELL) {
3181 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3183 else if (code == CM_ERROR_NOSUCHVOLUME) {
3184 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3186 else if (code == CM_ERROR_TIMEDOUT) {
3188 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3190 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3193 else if (code == CM_ERROR_RETRY) {
3194 Win32E = ERROR_RETRY; /* Retry */
3196 else if (code == CM_ERROR_NOACCESS) {
3197 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3199 else if (code == CM_ERROR_READONLY) {
3200 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3202 else if (code == CM_ERROR_NOSUCHFILE ||
3203 code == CM_ERROR_BPLUS_NOMATCH) {
3204 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3206 else if (code == CM_ERROR_NOSUCHPATH) {
3207 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3209 else if (code == CM_ERROR_TOOBIG) {
3210 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3212 else if (code == CM_ERROR_INVAL) {
3213 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3215 else if (code == CM_ERROR_BADFD) {
3216 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3218 else if (code == CM_ERROR_BADFDOP) {
3219 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3221 else if (code == CM_ERROR_EXISTS) {
3222 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3224 else if (code == CM_ERROR_NOTEMPTY) {
3225 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3227 else if (code == CM_ERROR_CROSSDEVLINK) {
3228 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3230 else if (code == CM_ERROR_NOTDIR) {
3231 Win32E = ERROR_DIRECTORY; /* Not a directory */
3233 else if (code == CM_ERROR_ISDIR) {
3234 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3236 else if (code == CM_ERROR_BADOP) {
3237 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3239 else if (code == CM_ERROR_BADSHARENAME) {
3240 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3242 else if (code == CM_ERROR_NOIPC) {
3244 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3246 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3249 else if (code == CM_ERROR_CLOCKSKEW) {
3250 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3252 else if (code == CM_ERROR_BADTID) {
3253 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3255 else if (code == CM_ERROR_USESTD) {
3256 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3258 else if (code == CM_ERROR_QUOTA) {
3259 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3261 else if (code == CM_ERROR_SPACE) {
3262 Win32E = ERROR_DISK_FULL; /* Disk full */
3264 else if (code == CM_ERROR_ATSYS) {
3265 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3267 else if (code == CM_ERROR_BADNTFILENAME) {
3268 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3270 else if (code == CM_ERROR_WOULDBLOCK) {
3271 Win32E = WAIT_TIMEOUT; /* Can't wait */
3273 else if (code == CM_ERROR_SHARING_VIOLATION) {
3274 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3276 else if (code == CM_ERROR_LOCK_CONFLICT) {
3277 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3279 else if (code == CM_ERROR_PARTIALWRITE) {
3280 Win32E = ERROR_DISK_FULL; /* Disk full */
3282 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3283 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3285 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3286 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3288 else if (code == CM_ERROR_BADPASSWORD) {
3289 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3291 else if (code == CM_ERROR_BADLOGONTYPE) {
3292 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3294 else if (code == CM_ERROR_GSSCONTINUE) {
3295 Win32E = ERROR_MORE_DATA; /* more processing required */
3297 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3299 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3301 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3304 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3305 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3307 else if (code == CM_ERROR_ALLBUSY) {
3308 Win32E = ERROR_RETRY; /* Retry */
3310 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3311 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3313 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3314 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3316 else if (code == CM_ERROR_BAD_LEVEL) {
3317 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3319 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3320 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3322 else if (code == CM_ERROR_NOSUCHDEVICE) {
3323 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3325 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3326 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3328 else if (code == ENOMEM) {
3329 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3331 else if (code == CM_ERROR_RPC_MOREDATA) {
3332 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3335 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3339 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3342 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3343 unsigned char *classp)
3345 unsigned char class;
3346 unsigned short error;
3348 /* map CM_ERROR_* errors to SMB errors */
3349 if (code == CM_ERROR_NOSUCHCELL) {
3351 error = 3; /* bad path */
3353 else if (code == CM_ERROR_NOSUCHVOLUME) {
3355 error = 3; /* bad path */
3357 else if (code == CM_ERROR_TIMEDOUT) {
3359 error = 81; /* server is paused */
3361 else if (code == CM_ERROR_RETRY) {
3362 class = 2; /* shouldn't happen */
3365 else if (code == CM_ERROR_NOACCESS) {
3367 error = 4; /* bad access */
3369 else if (code == CM_ERROR_READONLY) {
3371 error = 19; /* read only */
3373 else if (code == CM_ERROR_NOSUCHFILE ||
3374 code == CM_ERROR_BPLUS_NOMATCH) {
3376 error = 2; /* ENOENT! */
3378 else if (code == CM_ERROR_NOSUCHPATH) {
3380 error = 3; /* Bad path */
3382 else if (code == CM_ERROR_TOOBIG) {
3384 error = 11; /* bad format */
3386 else if (code == CM_ERROR_INVAL) {
3387 class = 2; /* server non-specific error code */
3390 else if (code == CM_ERROR_BADFD) {
3392 error = 6; /* invalid file handle */
3394 else if (code == CM_ERROR_BADFDOP) {
3395 class = 1; /* invalid op on FD */
3398 else if (code == CM_ERROR_EXISTS) {
3400 error = 80; /* file already exists */
3402 else if (code == CM_ERROR_NOTEMPTY) {
3404 error = 5; /* delete directory not empty */
3406 else if (code == CM_ERROR_CROSSDEVLINK) {
3408 error = 17; /* EXDEV */
3410 else if (code == CM_ERROR_NOTDIR) {
3411 class = 1; /* bad path */
3414 else if (code == CM_ERROR_ISDIR) {
3415 class = 1; /* access denied; DOS doesn't have a good match */
3418 else if (code == CM_ERROR_BADOP) {
3422 else if (code == CM_ERROR_BADSHARENAME) {
3426 else if (code == CM_ERROR_NOIPC) {
3428 error = 4; /* bad access */
3430 else if (code == CM_ERROR_CLOCKSKEW) {
3431 class = 1; /* invalid function */
3434 else if (code == CM_ERROR_BADTID) {
3438 else if (code == CM_ERROR_USESTD) {
3442 else if (code == CM_ERROR_REMOTECONN) {
3446 else if (code == CM_ERROR_QUOTA) {
3447 if (vcp->flags & SMB_VCFLAG_USEV3) {
3449 error = 39; /* disk full */
3453 error = 5; /* access denied */
3456 else if (code == CM_ERROR_SPACE) {
3457 if (vcp->flags & SMB_VCFLAG_USEV3) {
3459 error = 39; /* disk full */
3463 error = 5; /* access denied */
3466 else if (code == CM_ERROR_PARTIALWRITE) {
3468 error = 39; /* disk full */
3470 else if (code == CM_ERROR_ATSYS) {
3472 error = 2; /* ENOENT */
3474 else if (code == CM_ERROR_WOULDBLOCK) {
3476 error = 33; /* lock conflict */
3478 else if (code == CM_ERROR_LOCK_CONFLICT) {
3480 error = 33; /* lock conflict */
3482 else if (code == CM_ERROR_SHARING_VIOLATION) {
3484 error = 33; /* lock conflict */
3486 else if (code == CM_ERROR_NOFILES) {
3488 error = 18; /* no files in search */
3490 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3492 error = 183; /* Samba uses this */
3494 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3495 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3497 error = 2; /* bad password */
3499 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3501 error = 3; /* bad path */
3510 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3513 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3515 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3516 return CM_ERROR_BADOP;
3520 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3522 unsigned short EchoCount, i;
3523 char *data, *outdata;
3526 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3528 for (i=1; i<=EchoCount; i++) {
3529 data = smb_GetSMBData(inp, &dataSize);
3530 smb_SetSMBParm(outp, 0, i);
3531 smb_SetSMBDataLength(outp, dataSize);
3532 outdata = smb_GetSMBData(outp, NULL);
3533 memcpy(outdata, data, dataSize);
3534 smb_SendPacket(vcp, outp);
3540 /* SMB_COM_READ_RAW */
3541 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3544 long count, minCount, finalCount;
3548 smb_t *smbp = (smb_t*) inp;
3550 cm_user_t *userp = NULL;
3553 char *rawBuf = NULL;
3558 fd = smb_GetSMBParm(inp, 0);
3559 count = smb_GetSMBParm(inp, 3);
3560 minCount = smb_GetSMBParm(inp, 4);
3561 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3563 if (*inp->wctp == 10) {
3564 /* we were sent a request with 64-bit file offsets */
3565 #ifdef AFS_LARGEFILES
3566 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3568 if (LargeIntegerLessThanZero(offset)) {
3569 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3573 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3574 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3577 offset.HighPart = 0;
3581 /* we were sent a request with 32-bit file offsets */
3582 offset.HighPart = 0;
3585 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3586 fd, offset.HighPart, offset.LowPart, count);
3588 fidp = smb_FindFID(vcp, fd, 0);
3590 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3594 lock_ObtainMutex(&fidp->mx);
3596 lock_ReleaseMutex(&fidp->mx);
3597 smb_ReleaseFID(fidp);
3598 return CM_ERROR_BADFD;
3601 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3602 lock_ReleaseMutex(&fidp->mx);
3603 smb_CloseFID(vcp, fidp, NULL, 0);
3604 code = CM_ERROR_NOSUCHFILE;
3610 LARGE_INTEGER LOffset, LLength;
3613 key = cm_GenerateKey(vcp->vcID, pid, fd);
3615 LOffset.HighPart = offset.HighPart;
3616 LOffset.LowPart = offset.LowPart;
3617 LLength.HighPart = 0;
3618 LLength.LowPart = count;
3620 lock_ObtainWrite(&fidp->scp->rw);
3621 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3622 lock_ReleaseWrite(&fidp->scp->rw);
3625 lock_ReleaseMutex(&fidp->mx);
3629 lock_ObtainMutex(&smb_RawBufLock);
3631 /* Get a raw buf, from head of list */
3632 rawBuf = smb_RawBufs;
3633 smb_RawBufs = *(char **)smb_RawBufs;
3635 lock_ReleaseMutex(&smb_RawBufLock);
3637 lock_ReleaseMutex(&fidp->mx);
3641 if (fidp->flags & SMB_FID_IOCTL)
3643 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3645 /* Give back raw buffer */
3646 lock_ObtainMutex(&smb_RawBufLock);
3647 *((char **) rawBuf) = smb_RawBufs;
3649 smb_RawBufs = rawBuf;
3650 lock_ReleaseMutex(&smb_RawBufLock);
3653 lock_ReleaseMutex(&fidp->mx);
3654 smb_ReleaseFID(fidp);
3657 lock_ReleaseMutex(&fidp->mx);
3659 userp = smb_GetUserFromVCP(vcp, inp);
3661 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3667 cm_ReleaseUser(userp);
3670 smb_ReleaseFID(fidp);
3674 memset((char *)ncbp, 0, sizeof(NCB));
3676 ncbp->ncb_length = (unsigned short) finalCount;
3677 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3678 ncbp->ncb_lana_num = vcp->lana;
3679 ncbp->ncb_command = NCBSEND;
3680 ncbp->ncb_buffer = rawBuf;
3682 code = Netbios(ncbp);
3684 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3687 /* Give back raw buffer */
3688 lock_ObtainMutex(&smb_RawBufLock);
3689 *((char **) rawBuf) = smb_RawBufs;
3691 smb_RawBufs = rawBuf;
3692 lock_ReleaseMutex(&smb_RawBufLock);
3698 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3700 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3705 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3707 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3712 /* SMB_COM_NEGOTIATE */
3713 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3720 int VistaProtoIndex;
3721 int protoIndex; /* index we're using */
3726 char protocol_array[10][1024]; /* protocol signature of the client */
3727 int caps; /* capabilities */
3730 TIME_ZONE_INFORMATION tzi;
3732 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3735 namep = smb_GetSMBData(inp, &dbytes);
3738 coreProtoIndex = -1; /* not found */
3741 VistaProtoIndex = -1;
3742 while(namex < dbytes) {
3743 osi_Log1(smb_logp, "Protocol %s",
3744 osi_LogSaveString(smb_logp, namep+1));
3745 strcpy(protocol_array[tcounter], namep+1);
3747 /* namep points at the first protocol, or really, a 0x02
3748 * byte preceding the null-terminated ASCII name.
3750 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3751 coreProtoIndex = tcounter;
3753 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3754 v3ProtoIndex = tcounter;
3756 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3757 NTProtoIndex = tcounter;
3759 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3760 VistaProtoIndex = tcounter;
3763 /* compute size of protocol entry */
3764 entryLength = (int)strlen(namep+1);
3765 entryLength += 2; /* 0x02 bytes and null termination */
3767 /* advance over this protocol entry */
3768 namex += entryLength;
3769 namep += entryLength;
3770 tcounter++; /* which proto entry we're looking at */
3773 lock_ObtainMutex(&vcp->mx);
3775 if (VistaProtoIndex != -1) {
3776 protoIndex = VistaProtoIndex;
3777 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3780 if (NTProtoIndex != -1) {
3781 protoIndex = NTProtoIndex;
3782 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3784 else if (v3ProtoIndex != -1) {
3785 protoIndex = v3ProtoIndex;
3786 vcp->flags |= SMB_VCFLAG_USEV3;
3788 else if (coreProtoIndex != -1) {
3789 protoIndex = coreProtoIndex;
3790 vcp->flags |= SMB_VCFLAG_USECORE;
3792 else protoIndex = -1;
3793 lock_ReleaseMutex(&vcp->mx);
3795 if (protoIndex == -1)
3796 return CM_ERROR_INVAL;
3797 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3798 smb_SetSMBParm(outp, 0, protoIndex);
3799 if (smb_authType != SMB_AUTH_NONE) {
3800 smb_SetSMBParmByte(outp, 1,
3801 NEGOTIATE_SECURITY_USER_LEVEL |
3802 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3804 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3806 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3807 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3808 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3809 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3810 /* The session key is not a well documented field however most clients
3811 * will echo back the session key to the server. Currently we are using
3812 * the same value for all sessions. We should generate a random value
3813 * and store it into the vcp
3815 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3816 smb_SetSMBParm(outp, 8, 1);
3818 * Tried changing the capabilities to support for W2K - defect 117695
3819 * Maybe something else needs to be changed here?
3823 smb_SetSMBParmLong(outp, 9, 0x43fd);
3825 smb_SetSMBParmLong(outp, 9, 0x251);
3828 * 32-bit error codes *
3834 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3836 NTNEGOTIATE_CAPABILITY_DFS |
3838 #ifdef AFS_LARGEFILES
3839 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3841 NTNEGOTIATE_CAPABILITY_NTFIND |
3842 NTNEGOTIATE_CAPABILITY_RAWMODE |
3843 NTNEGOTIATE_CAPABILITY_NTSMB;
3845 if ( smb_authType == SMB_AUTH_EXTENDED )
3846 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3849 if ( smb_UseUnicode ) {
3850 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3854 smb_SetSMBParmLong(outp, 9, caps);
3856 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3857 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3858 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3860 GetTimeZoneInformation(&tzi);
3861 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3863 if (smb_authType == SMB_AUTH_NTLM) {
3864 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3865 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3866 /* paste in encryption key */
3867 datap = smb_GetSMBData(outp, NULL);
3868 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3869 /* and the faux domain name */
3870 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3871 datap + MSV1_0_CHALLENGE_LENGTH,
3872 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3873 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3877 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3879 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3881 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3883 datap = smb_GetSMBData(outp, NULL);
3884 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3887 datap += sizeof(smb_ServerGUID);
3888 memcpy(datap, secBlob, secBlobLength);
3892 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3893 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3896 else if (v3ProtoIndex != -1) {
3897 smb_SetSMBParm(outp, 0, protoIndex);
3899 /* NOTE: Extended authentication cannot be negotiated with v3
3900 * therefore we fail over to NTLM
3902 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3903 smb_SetSMBParm(outp, 1,
3904 NEGOTIATE_SECURITY_USER_LEVEL |
3905 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3907 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3909 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3910 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3911 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3912 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3913 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3914 smb_SetSMBParm(outp, 7, 1);
3916 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3917 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3918 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3920 GetTimeZoneInformation(&tzi);
3921 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3923 /* NOTE: Extended authentication cannot be negotiated with v3
3924 * therefore we fail over to NTLM
3926 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3927 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3928 smb_SetSMBParm(outp, 12, 0); /* resvd */
3929 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3930 datap = smb_GetSMBData(outp, NULL);
3931 /* paste in a new encryption key */
3932 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3933 /* and the faux domain name */
3934 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3935 datap + MSV1_0_CHALLENGE_LENGTH,
3936 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3938 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3939 smb_SetSMBParm(outp, 12, 0); /* resvd */
3940 smb_SetSMBDataLength(outp, 0);
3943 else if (coreProtoIndex != -1) { /* not really supported anymore */
3944 smb_SetSMBParm(outp, 0, protoIndex);
3945 smb_SetSMBDataLength(outp, 0);
3950 void smb_CheckVCs(void)
3952 smb_vc_t * vcp, *nextp;
3953 smb_packet_t * outp = smb_GetPacket();
3956 lock_ObtainWrite(&smb_rctLock);
3957 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3959 if (vcp->magic != SMB_VC_MAGIC)
3960 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3961 __FILE__, __LINE__);
3963 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3965 smb_HoldVCNoLock(vcp);
3968 * obtain a reference to 'nextp' now because we drop the
3969 * smb_rctLock later and the list contents could change
3970 * or 'vcp' could be destroyed when released.
3974 smb_HoldVCNoLock(nextp);
3976 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3977 smb_ReleaseVCNoLock(vcp);
3981 smb_FormatResponsePacket(vcp, NULL, outp);
3982 smbp = (smb_t *)outp;
3983 outp->inCom = smbp->com = 0x2b /* Echo */;
3991 smb_SetSMBParm(outp, 0, 0);
3992 smb_SetSMBDataLength(outp, 0);
3993 lock_ReleaseWrite(&smb_rctLock);
3995 smb_SendPacket(vcp, outp);
3997 lock_ObtainWrite(&smb_rctLock);
3998 smb_ReleaseVCNoLock(vcp);
4000 lock_ReleaseWrite(&smb_rctLock);
4001 smb_FreePacket(outp);
4004 void smb_Daemon(void *parmp)
4006 afs_uint32 count = 0;
4007 smb_username_t **unpp;
4010 while(smbShutdownFlag == 0) {
4014 if (smbShutdownFlag == 1)
4017 if ((count % 72) == 0) { /* every five minutes */
4019 time_t old_localZero = smb_localZero;
4021 /* Initialize smb_localZero */
4022 myTime.tm_isdst = -1; /* compute whether on DST or not */
4023 myTime.tm_year = 70;
4029 smb_localZero = mktime(&myTime);
4031 #ifdef AFS_FREELANCE
4032 if ( smb_localZero != old_localZero )
4033 cm_noteLocalMountPointChange();
4039 /* GC smb_username_t objects that will no longer be used */
4041 lock_ObtainWrite(&smb_rctLock);
4042 for ( unpp=&usernamesp; *unpp; ) {
4044 smb_username_t *unp;
4046 lock_ObtainMutex(&(*unpp)->mx);
4047 if ( (*unpp)->refCount > 0 ||
4048 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4049 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4051 else if (!smb_LogoffTokenTransfer ||
4052 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4054 lock_ReleaseMutex(&(*unpp)->mx);
4062 lock_FinalizeMutex(&unp->mx);
4068 cm_ReleaseUser(userp);
4070 unpp = &(*unpp)->nextp;
4073 lock_ReleaseWrite(&smb_rctLock);
4075 /* XXX GC dir search entries */
4079 void smb_WaitingLocksDaemon()
4081 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4082 smb_waitingLock_t *wl, *wlNext;
4085 smb_packet_t *inp, *outp;
4089 while (smbShutdownFlag == 0) {
4090 lock_ObtainWrite(&smb_globalLock);
4091 nwlRequest = smb_allWaitingLocks;
4092 if (nwlRequest == NULL) {
4093 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4098 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4105 lock_ObtainWrite(&smb_globalLock);
4107 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4109 wlRequest = nwlRequest;
4110 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4111 lock_ReleaseWrite(&smb_globalLock);
4115 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4116 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4119 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4120 code = CM_ERROR_LOCK_NOT_GRANTED;
4124 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4126 /* wl->state is either _DONE or _WAITING. _ERROR
4127 would no longer be on the queue. */
4128 code = cm_RetryLock( wl->lockp,
4129 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4132 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4133 } else if (code != CM_ERROR_WOULDBLOCK) {
4134 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4139 if (code == CM_ERROR_WOULDBLOCK) {
4142 if (wlRequest->msTimeout != 0xffffffff
4143 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4155 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4158 scp = wlRequest->scp;
4159 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4163 lock_ObtainWrite(&scp->rw);
4165 for (wl = wlRequest->locks; wl; wl = wlNext) {
4166 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4168 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4169 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4170 wl->LLength, wl->key, 0, NULL, &req);
4172 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4177 lock_ReleaseWrite(&scp->rw);
4181 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4184 for (wl = wlRequest->locks; wl; wl = wlNext) {
4185 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4186 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4191 vcp = wlRequest->vcp;
4192 inp = wlRequest->inp;
4193 outp = wlRequest->outp;
4194 ncbp = smb_GetNCB();
4195 ncbp->ncb_length = inp->ncb_length;
4196 inp->spacep = cm_GetSpace();
4198 /* Remove waitingLock from list */
4199 lock_ObtainWrite(&smb_globalLock);
4200 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4202 lock_ReleaseWrite(&smb_globalLock);
4204 /* Resume packet processing */
4206 smb_SetSMBDataLength(outp, 0);
4207 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4208 outp->resumeCode = code;
4210 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4213 cm_FreeSpace(inp->spacep);
4214 smb_FreePacket(inp);
4215 smb_FreePacket(outp);
4217 cm_ReleaseSCache(wlRequest->scp);
4220 } while (nwlRequest && smbShutdownFlag == 0);
4225 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4227 osi_Log0(smb_logp, "SMB receive get disk attributes");
4229 smb_SetSMBParm(outp, 0, 32000);
4230 smb_SetSMBParm(outp, 1, 64);
4231 smb_SetSMBParm(outp, 2, 1024);
4232 smb_SetSMBParm(outp, 3, 30000);
4233 smb_SetSMBParm(outp, 4, 0);
4234 smb_SetSMBDataLength(outp, 0);
4238 /* SMB_COM_TREE_CONNECT */
4239 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4243 unsigned short newTid;
4244 clientchar_t shareName[AFSPATHMAX];
4245 clientchar_t *sharePath;
4248 clientchar_t *pathp;
4251 osi_Log0(smb_logp, "SMB receive tree connect");
4253 /* parse input parameters */
4256 tbp = smb_GetSMBData(inp, NULL);
4257 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4259 return CM_ERROR_BADSMB;
4261 tp = cm_ClientStrRChr(pathp, '\\');
4263 return CM_ERROR_BADSMB;
4264 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4266 lock_ObtainMutex(&vcp->mx);
4267 newTid = vcp->tidCounter++;
4268 lock_ReleaseMutex(&vcp->mx);
4270 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4271 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4273 return CM_ERROR_BADSMB;
4274 userp = smb_GetUserFromUID(uidp);
4275 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4276 smb_ReleaseUID(uidp);
4278 smb_ReleaseTID(tidp, FALSE);
4279 return CM_ERROR_BADSHARENAME;
4281 lock_ObtainMutex(&tidp->mx);
4282 tidp->userp = userp;
4283 tidp->pathname = sharePath;
4284 lock_ReleaseMutex(&tidp->mx);
4285 smb_ReleaseTID(tidp, FALSE);
4287 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4288 smb_SetSMBParm(rsp, 1, newTid);
4289 smb_SetSMBDataLength(rsp, 0);
4291 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4295 /* set maskp to the mask part of the incoming path.
4296 * Mask is 11 bytes long (8.3 with the dot elided).
4297 * Returns true if succeeds with a valid name, otherwise it does
4298 * its best, but returns false.
4300 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4308 /* starts off valid */
4311 /* mask starts out all blanks */
4312 memset(maskp, ' ', 11);
4315 /* find last backslash, or use whole thing if there is none */
4316 tp = cm_ClientStrRChr(pathp, '\\');
4320 tp++; /* skip slash */
4324 /* names starting with a dot are illegal */
4332 if (tc == '.' || tc == '"')
4340 /* if we get here, tp point after the dot */
4341 up = maskp+8; /* ext goes here */
4348 if (tc == '.' || tc == '"')
4351 /* copy extension if not too long */
4361 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4363 clientchar_t umask[11];
4371 /* XXX redo this, calling cm_MatchMask with a converted mask */
4373 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4377 /* otherwise, we have a valid 8.3 name; see if we have a match,
4378 * treating '?' as a wildcard in maskp (but not in the file name).
4380 tp1 = umask; /* real name, in mask format */
4381 tp2 = maskp; /* mask, in mask format */
4382 for(i=0; i<11; i++) {
4383 tc1 = *tp1++; /* clientchar_t from real name */
4384 tc2 = *tp2++; /* clientchar_t from mask */
4385 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4386 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4389 if (tc2 == '?' && tc1 != ' ')
4396 /* we got a match */
4400 clientchar_t *smb_FindMask(clientchar_t *pathp)
4404 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4407 return tp+1; /* skip the slash */
4409 return pathp; /* no slash, return the entire path */
4412 /* SMB_COM_SEARCH for a volume label
4414 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4415 dispatch function.) */
4416 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4418 clientchar_t *pathp;
4420 clientchar_t mask[12];
4421 unsigned char *statBlockp;
4422 unsigned char initStatBlock[21];
4425 osi_Log0(smb_logp, "SMB receive search volume");
4427 /* pull pathname and stat block out of request */
4428 tp = smb_GetSMBData(inp, NULL);
4429 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4430 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4432 return CM_ERROR_BADSMB;
4433 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4434 osi_assertx(statBlockp != NULL, "null statBlock");
4436 statBlockp = initStatBlock;
4440 /* for returning to caller */
4441 smb_Get8Dot3MaskFromPath(mask, pathp);
4443 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4444 tp = smb_GetSMBData(outp, NULL);
4446 *tp++ = 43; /* bytes in a dir entry */
4447 *tp++ = 0; /* high byte in counter */
4449 /* now marshall the dir entry, starting with the search status */
4450 *tp++ = statBlockp[0]; /* Reserved */
4451 memcpy(tp, mask, 11); tp += 11; /* FileName */
4453 /* now pass back server use info, with 1st byte non-zero */
4455 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4457 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4459 *tp++ = 0x8; /* attribute: volume */
4469 /* 4 byte file size */
4475 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4478 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4479 memset(tp, ' ', 13);
4482 /* set the length of the data part of the packet to 43 + 3, for the dir
4483 * entry plus the 5 and the length fields.
4485 smb_SetSMBDataLength(outp, 46);
4490 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4491 clientchar_t * tidPathp, clientchar_t * relPathp,
4492 cm_user_t *userp, cm_req_t *reqp)
4500 smb_dirListPatch_t *patchp;
4501 smb_dirListPatch_t *npatchp;
4502 clientchar_t path[AFSPATHMAX];
4504 afs_int32 mustFake = 0;
4506 code = cm_FindACLCache(dscp, userp, &rights);
4508 lock_ObtainWrite(&dscp->rw);
4509 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4510 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4511 lock_ReleaseWrite(&dscp->rw);
4512 if (code == CM_ERROR_NOACCESS) {
4520 if (!mustFake) { /* Bulk Stat */
4522 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4524 memset(bsp, 0, sizeof(cm_bulkStat_t));
4526 for (patchp = *dirPatchespp, count=0;
4528 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4529 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4533 if (lock_TryWrite(&tscp->rw)) {
4534 /* we have an entry that we can look at */
4535 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4536 /* we have a callback on it. Don't bother
4537 * fetching this stat entry, since we're happy
4538 * with the info we have.
4540 lock_ReleaseWrite(&tscp->rw);
4541 cm_ReleaseSCache(tscp);
4544 lock_ReleaseWrite(&tscp->rw);
4546 cm_ReleaseSCache(tscp);
4550 bsp->fids[i].Volume = patchp->fid.volume;
4551 bsp->fids[i].Vnode = patchp->fid.vnode;
4552 bsp->fids[i].Unique = patchp->fid.unique;
4554 if (bsp->counter == AFSCBMAX) {
4555 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4556 memset(bsp, 0, sizeof(cm_bulkStat_t));
4560 if (bsp->counter > 0)
4561 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4566 for (patchp = *dirPatchespp; patchp; patchp =
4567 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4569 dptr = patchp->dptr;
4571 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4572 relPathp ? relPathp : _C(""), patchp->dep->name);
4573 reqp->relPathp = path;
4574 reqp->tidPathp = tidPathp;
4576 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4577 reqp->relPathp = reqp->tidPathp = NULL;
4580 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4581 *dptr++ = SMB_ATTR_HIDDEN;
4584 lock_ObtainWrite(&scp->rw);
4585 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4586 lock_ReleaseWrite(&scp->rw);
4588 /* set the attribute */
4589 switch (scp->fileType) {
4590 case CM_SCACHETYPE_DIRECTORY:
4591 case CM_SCACHETYPE_MOUNTPOINT:
4592 case CM_SCACHETYPE_INVALID:
4593 attr = SMB_ATTR_DIRECTORY;
4595 case CM_SCACHETYPE_SYMLINK:
4596 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4597 attr = SMB_ATTR_DIRECTORY;
4599 attr = SMB_ATTR_NORMAL;
4602 /* if we get here we either have a normal file
4603 * or we have a file for which we have never
4604 * received status info. In this case, we can
4605 * check the even/odd value of the entry's vnode.
4606 * odd means it is to be treated as a directory
4607 * and even means it is to be treated as a file.
4609 if (mustFake && (scp->fid.vnode & 0x1))
4610 attr = SMB_ATTR_DIRECTORY;
4612 attr = SMB_ATTR_NORMAL;
4616 /* 1969-12-31 23:59:58 +00*/
4617 dosTime = 0xEBBFBF7D;
4620 shortTemp = (unsigned short) (dosTime & 0xffff);
4621 *((u_short *)dptr) = shortTemp;
4624 /* and copy out date */
4625 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4626 *((u_short *)dptr) = shortTemp;
4629 /* copy out file length */
4630 *((u_long *)dptr) = 0;
4633 lock_ConvertWToR(&scp->rw);
4634 attr = smb_Attributes(scp);
4635 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4636 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4637 attr |= SMB_ATTR_HIDDEN;
4641 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4644 shortTemp = (unsigned short) (dosTime & 0xffff);
4645 *((u_short *)dptr) = shortTemp;
4648 /* and copy out date */
4649 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4650 *((u_short *)dptr) = shortTemp;
4653 /* copy out file length */
4654 *((u_long *)dptr) = scp->length.LowPart;
4656 lock_ReleaseRead(&scp->rw);
4658 cm_ReleaseSCache(scp);
4661 /* now free the patches */
4662 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4663 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4667 /* and mark the list as empty */
4668 *dirPatchespp = NULL;
4674 /* SMB_COM_SEARCH */
4675 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4681 clientchar_t *pathp;
4682 cm_dirEntry_t *dep = 0;
4684 smb_dirListPatch_t *dirListPatchesp;
4685 smb_dirListPatch_t *curPatchp;
4689 osi_hyper_t dirLength;
4690 osi_hyper_t bufferOffset;
4691 osi_hyper_t curOffset;
4693 unsigned char *inCookiep;
4694 smb_dirSearch_t *dsp;
4698 unsigned long clientCookie;
4699 cm_pageHeader_t *pageHeaderp;
4700 cm_user_t *userp = NULL;
4702 clientchar_t mask[12];
4704 long nextEntryCookie;
4705 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4706 char resByte; /* reserved byte from the cookie */
4707 char *op; /* output data ptr */
4708 char *origOp; /* original value of op */
4709 cm_space_t *spacep; /* for pathname buffer */
4713 clientchar_t *tidPathp = 0;
4720 maxCount = smb_GetSMBParm(inp, 0);
4722 dirListPatchesp = NULL;
4724 caseFold = CM_FLAG_CASEFOLD;
4726 tp = smb_GetSMBData(inp, NULL);
4727 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4728 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4730 return CM_ERROR_BADSMB;
4732 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4734 return CM_ERROR_BADSMB;
4736 /* We can handle long names */
4737 if (vcp->flags & SMB_VCFLAG_USENT)
4738 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4740 /* make sure we got a whole search status */
4741 if (dataLength < 21) {
4742 nextCookie = 0; /* start at the beginning of the dir */
4745 attribute = smb_GetSMBParm(inp, 1);
4747 /* handle volume info in another function */
4748 if (attribute & 0x8)
4749 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4751 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4752 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4754 if (*pathp == 0) { /* null pathp, treat as root dir */
4755 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4756 return CM_ERROR_NOFILES;
4760 dsp = smb_NewDirSearch(0);
4761 dsp->attribute = attribute;
4762 smb_Get8Dot3MaskFromPath(mask, pathp);
4763 memcpy(dsp->mask, mask, 12);
4765 /* track if this is likely to match a lot of entries */
4766 if (smb_Is8Dot3StarMask(mask))
4771 /* pull the next cookie value out of the search status block */
4772 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4773 + (inCookiep[16]<<24);
4774 dsp = smb_FindDirSearch(inCookiep[12]);
4776 /* can't find dir search status; fatal error */
4777 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4778 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4779 return CM_ERROR_BADFD;
4781 attribute = dsp->attribute;
4782 resByte = inCookiep[0];
4784 /* copy out client cookie, in host byte order. Don't bother
4785 * interpreting it, since we're just passing it through, anyway.
4787 memcpy(&clientCookie, &inCookiep[17], 4);
4789 memcpy(mask, dsp->mask, 12);
4791 /* assume we're doing a star match if it has continued for more
4797 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4798 nextCookie, dsp->cookie, attribute);
4800 userp = smb_GetUserFromVCP(vcp, inp);
4802 /* try to get the vnode for the path name next */
4803 lock_ObtainMutex(&dsp->mx);
4806 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4810 spacep = inp->spacep;
4811 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4812 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4814 lock_ReleaseMutex(&dsp->mx);
4815 cm_ReleaseUser(userp);
4816 smb_DeleteDirSearch(dsp);
4817 smb_ReleaseDirSearch(dsp);
4818 return CM_ERROR_NOFILES;
4820 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4821 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4823 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4824 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4827 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4830 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4831 cm_ReleaseSCache(scp);
4832 lock_ReleaseMutex(&dsp->mx);
4833 cm_ReleaseUser(userp);
4834 smb_DeleteDirSearch(dsp);
4835 smb_ReleaseDirSearch(dsp);
4836 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4837 return CM_ERROR_PATH_NOT_COVERED;
4839 return CM_ERROR_NOSUCHPATH;
4841 #endif /* DFS_SUPPORT */
4844 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4845 /* we need one hold for the entry we just stored into,
4846 * and one for our own processing. When we're done with this
4847 * function, we'll drop the one for our own processing.
4848 * We held it once from the namei call, and so we do another hold
4852 lock_ObtainWrite(&scp->rw);
4853 dsp->flags |= SMB_DIRSEARCH_BULKST;
4854 lock_ReleaseWrite(&scp->rw);
4857 lock_ReleaseMutex(&dsp->mx);
4859 cm_ReleaseUser(userp);
4860 smb_DeleteDirSearch(dsp);
4861 smb_ReleaseDirSearch(dsp);
4865 /* reserves space for parameter; we'll adjust it again later to the
4866 * real count of the # of entries we returned once we've actually
4867 * assembled the directory listing.
4869 smb_SetSMBParm(outp, 0, 0);
4871 /* get the directory size */
4872 lock_ObtainWrite(&scp->rw);
4873 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4874 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4876 lock_ReleaseWrite(&scp->rw);
4877 cm_ReleaseSCache(scp);
4878 cm_ReleaseUser(userp);
4879 smb_DeleteDirSearch(dsp);
4880 smb_ReleaseDirSearch(dsp);
4884 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4886 dirLength = scp->length;
4888 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4889 curOffset.HighPart = 0;
4890 curOffset.LowPart = nextCookie;
4891 origOp = op = smb_GetSMBData(outp, NULL);
4892 /* and write out the basic header */
4893 *op++ = 5; /* variable block */
4894 op += 2; /* skip vbl block length; we'll fill it in later */
4898 clientchar_t *actualName = NULL;
4899 int free_actualName = 0;
4900 clientchar_t shortName[13];
4901 clientchar_t *shortNameEnd;
4903 /* make sure that curOffset.LowPart doesn't point to the first
4904 * 32 bytes in the 2nd through last dir page, and that it doesn't
4905 * point at the first 13 32-byte chunks in the first dir page,
4906 * since those are dir and page headers, and don't contain useful
4909 temp = curOffset.LowPart & (2048-1);
4910 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4911 /* we're in the first page */
4912 if (temp < 13*32) temp = 13*32;
4915 /* we're in a later dir page */
4916 if (temp < 32) temp = 32;
4919 /* make sure the low order 5 bits are zero */
4922 /* now put temp bits back ito curOffset.LowPart */
4923 curOffset.LowPart &= ~(2048-1);
4924 curOffset.LowPart |= temp;
4926 /* check if we've returned all the names that will fit in the
4929 if (returnedNames >= maxCount) {
4930 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4931 returnedNames, maxCount);
4935 /* check if we've passed the dir's EOF */
4936 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4938 /* see if we can use the bufferp we have now; compute in which page
4939 * the current offset would be, and check whether that's the offset
4940 * of the buffer we have. If not, get the buffer.
4942 thyper.HighPart = curOffset.HighPart;
4943 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4944 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4947 buf_Release(bufferp);
4950 lock_ReleaseWrite(&scp->rw);
4951 code = buf_Get(scp, &thyper, &req, &bufferp);
4952 lock_ObtainMutex(&dsp->mx);
4954 /* now, if we're doing a star match, do bulk fetching of all of
4955 * the status info for files in the dir.
4958 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4960 lock_ObtainWrite(&scp->rw);
4961 lock_ReleaseMutex(&dsp->mx);
4963 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4967 bufferOffset = thyper;
4969 /* now get the data in the cache */
4971 code = cm_SyncOp(scp, bufferp, userp, &req,
4973 CM_SCACHESYNC_NEEDCALLBACK |
4974 CM_SCACHESYNC_READ);
4976 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4980 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4982 if (cm_HaveBuffer(scp, bufferp, 0)) {
4983 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4987 /* otherwise, load the buffer and try again */
4988 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4990 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4991 scp, bufferp, code);
4996 buf_Release(bufferp);
5000 } /* if (wrong buffer) ... */
5002 /* now we have the buffer containing the entry we're interested in; copy
5003 * it out if it represents a non-deleted entry.
5005 entryInDir = curOffset.LowPart & (2048-1);
5006 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5008 /* page header will help tell us which entries are free. Page header
5009 * can change more often than once per buffer, since AFS 3 dir page size
5010 * may be less than (but not more than a buffer package buffer.
5012 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5013 temp &= ~(2048 - 1); /* turn off intra-page bits */
5014 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5016 /* now determine which entry we're looking at in the page. If it is
5017 * free (there's a free bitmap at the start of the dir), we should
5018 * skip these 32 bytes.
5020 slotInPage = (entryInDir & 0x7e0) >> 5;
5021 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5022 /* this entry is free */
5023 numDirChunks = 1; /* only skip this guy */
5027 tp = bufferp->datap + entryInBuffer;
5028 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5030 /* while we're here, compute the next entry's location, too,
5031 * since we'll need it when writing out the cookie into the dir
5034 * XXXX Probably should do more sanity checking.
5036 numDirChunks = cm_NameEntries(dep->name, NULL);
5038 /* compute the offset of the cookie representing the next entry */
5039 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5041 /* Compute 8.3 name if necessary */
5042 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5043 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5046 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5047 actualName = shortName;
5048 free_actualName = 0;
5050 free_actualName = 1;
5053 if (actualName == NULL) {
5054 /* Couldn't convert the name for some reason */
5055 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5056 osi_LogSaveString(smb_logp, dep->name));
5060 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5061 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5062 osi_LogSaveClientString(smb_logp, actualName));
5064 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5065 /* this is one of the entries to use: it is not deleted
5066 * and it matches the star pattern we're looking for.
5069 /* Eliminate entries that don't match requested
5072 /* no hidden files */
5073 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5074 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5078 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5080 /* We have already done the cm_TryBulkStat above */
5081 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5082 fileType = cm_FindFileType(&fid);
5083 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5084 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5086 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5087 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5088 fileType == CM_SCACHETYPE_DFSLINK ||
5089 fileType == CM_SCACHETYPE_INVALID)
5090 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5095 memcpy(op, mask, 11); op += 11;
5096 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5097 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5098 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5099 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5100 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5101 memcpy(op, &clientCookie, 4); op += 4;
5103 /* now we emit the attribute. This is sort of tricky,
5104 * since we need to really stat the file to find out
5105 * what type of entry we've got. Right now, we're
5106 * copying out data from a buffer, while holding the
5107 * scp locked, so it isn't really convenient to stat
5108 * something now. We'll put in a place holder now,
5109 * and make a second pass before returning this to get
5110 * the real attributes. So, we just skip the data for
5111 * now, and adjust it later. We allocate a patch
5112 * record to make it easy to find this point later.
5113 * The replay will happen at a time when it is safe to
5114 * unlock the directory.
5116 curPatchp = malloc(sizeof(*curPatchp));
5117 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5118 curPatchp->dptr = op;
5119 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5121 /* do hidden attribute here since name won't be around when applying
5125 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5126 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5128 curPatchp->flags = 0;
5130 op += 9; /* skip attr, time, date and size */
5132 /* zero out name area. The spec says to pad with
5133 * spaces, but Samba doesn't, and neither do we.
5137 /* finally, we get to copy out the name; we know that
5138 * it fits in 8.3 or the pattern wouldn't match, but it
5139 * never hurts to be sure.
5141 cm_ClientStringToUtf8(actualName, -1, op, 13);
5142 if (smb_StoreAnsiFilenames)
5144 /* This is a UCHAR field, which is ASCII even if Unicode
5147 /* Uppercase if requested by client */
5148 if (!KNOWS_LONG_NAMES(inp))
5153 /* now, adjust the # of entries copied */
5155 } /* if we're including this name */
5158 if (free_actualName && actualName) {
5163 /* and adjust curOffset to be where the new cookie is */
5164 thyper.HighPart = 0;
5165 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5166 curOffset = LargeIntegerAdd(thyper, curOffset);
5167 } /* while copying data for dir listing */
5169 /* release the mutex */
5170 lock_ReleaseWrite(&scp->rw);
5172 buf_Release(bufferp);
5176 /* apply and free last set of patches; if not doing a star match, this
5177 * will be empty, but better safe (and freeing everything) than sorry.
5179 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5181 /* special return code for unsuccessful search */
5182 if (code == 0 && dataLength < 21 && returnedNames == 0)
5183 code = CM_ERROR_NOFILES;
5185 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5186 returnedNames, code);
5189 smb_DeleteDirSearch(dsp);
5190 smb_ReleaseDirSearch(dsp);
5191 cm_ReleaseSCache(scp);
5192 cm_ReleaseUser(userp);
5196 /* finalize the output buffer */
5197 smb_SetSMBParm(outp, 0, returnedNames);
5198 temp = (long) (op - origOp);
5199 smb_SetSMBDataLength(outp, temp);
5201 /* the data area is a variable block, which has a 5 (already there)
5202 * followed by the length of the # of data bytes. We now know this to
5203 * be "temp," although that includes the 3 bytes of vbl block header.
5204 * Deduct for them and fill in the length field.
5206 temp -= 3; /* deduct vbl block info */
5207 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5208 origOp[1] = (unsigned char)(temp & 0xff);
5209 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5210 if (returnedNames == 0)
5211 smb_DeleteDirSearch(dsp);
5212 smb_ReleaseDirSearch(dsp);
5213 cm_ReleaseSCache(scp);
5214 cm_ReleaseUser(userp);
5219 /* verify that this is a valid path to a directory. I don't know why they
5220 * don't use the get file attributes call.
5222 * SMB_COM_CHECK_DIRECTORY
5224 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5226 clientchar_t *pathp;
5228 cm_scache_t *rootScp;
5229 cm_scache_t *newScp;
5233 clientchar_t *tidPathp;
5239 pdata = smb_GetSMBData(inp, NULL);
5240 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5242 return CM_ERROR_BADSMB;
5243 osi_Log1(smb_logp, "SMB receive check path %S",
5244 osi_LogSaveClientString(smb_logp, pathp));
5246 rootScp = cm_data.rootSCachep;
5248 userp = smb_GetUserFromVCP(vcp, inp);
5250 caseFold = CM_FLAG_CASEFOLD;
5252 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5254 cm_ReleaseUser(userp);
5255 return CM_ERROR_NOSUCHPATH;
5257 code = cm_NameI(rootScp, pathp,
5258 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5259 userp, tidPathp, &req, &newScp);
5262 cm_ReleaseUser(userp);
5267 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5268 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5269 cm_ReleaseSCache(newScp);
5270 cm_ReleaseUser(userp);
5271 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5272 return CM_ERROR_PATH_NOT_COVERED;
5274 return CM_ERROR_NOSUCHPATH;
5276 #endif /* DFS_SUPPORT */
5278 /* now lock the vnode with a callback; returns with newScp locked */
5279 lock_ObtainWrite(&newScp->rw);
5280 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5281 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5283 if (code != CM_ERROR_NOACCESS) {
5284 lock_ReleaseWrite(&newScp->rw);
5285 cm_ReleaseSCache(newScp);
5286 cm_ReleaseUser(userp);
5290 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5293 attrs = smb_Attributes(newScp);
5295 if (!(attrs & SMB_ATTR_DIRECTORY))
5296 code = CM_ERROR_NOTDIR;
5298 lock_ReleaseWrite(&newScp->rw);
5300 cm_ReleaseSCache(newScp);
5301 cm_ReleaseUser(userp);
5305 /* SMB_COM_SET_INFORMATION */
5306 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5308 clientchar_t *pathp;
5310 cm_scache_t *rootScp;
5311 unsigned short attribute;
5313 cm_scache_t *newScp;
5317 clientchar_t *tidPathp;
5323 /* decode basic attributes we're passed */
5324 attribute = smb_GetSMBParm(inp, 0);
5325 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5327 datap = smb_GetSMBData(inp, NULL);
5328 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5330 return CM_ERROR_BADSMB;
5332 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5333 dosTime, attribute);
5335 rootScp = cm_data.rootSCachep;
5337 userp = smb_GetUserFromVCP(vcp, inp);
5339 caseFold = CM_FLAG_CASEFOLD;
5341 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5343 cm_ReleaseUser(userp);
5344 return CM_ERROR_NOSUCHFILE;
5346 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5347 tidPathp, &req, &newScp);
5350 cm_ReleaseUser(userp);
5355 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5356 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5357 cm_ReleaseSCache(newScp);
5358 cm_ReleaseUser(userp);
5359 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5360 return CM_ERROR_PATH_NOT_COVERED;
5362 return CM_ERROR_NOSUCHPATH;
5364 #endif /* DFS_SUPPORT */
5366 /* now lock the vnode with a callback; returns with newScp locked; we
5367 * need the current status to determine what the new status is, in some
5370 lock_ObtainWrite(&newScp->rw);
5371 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5372 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5374 lock_ReleaseWrite(&newScp->rw);
5375 cm_ReleaseSCache(newScp);
5376 cm_ReleaseUser(userp);
5380 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5382 /* Check for RO volume */
5383 if (newScp->flags & CM_SCACHEFLAG_RO) {
5384 lock_ReleaseWrite(&newScp->rw);
5385 cm_ReleaseSCache(newScp);
5386 cm_ReleaseUser(userp);
5387 return CM_ERROR_READONLY;
5390 /* prepare for setattr call */
5393 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5394 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5396 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5397 /* we're told to make a writable file read-only */
5398 attr.unixModeBits = newScp->unixModeBits & ~0222;
5399 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5401 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5402 /* we're told to make a read-only file writable */
5403 attr.unixModeBits = newScp->unixModeBits | 0222;
5404 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5406 lock_ReleaseWrite(&newScp->rw);
5408 /* now call setattr */
5410 code = cm_SetAttr(newScp, &attr, userp, &req);
5414 cm_ReleaseSCache(newScp);
5415 cm_ReleaseUser(userp);
5421 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5423 clientchar_t *pathp;
5425 cm_scache_t *rootScp;
5426 cm_scache_t *newScp, *dscp;
5431 clientchar_t *tidPathp;
5433 clientchar_t *lastComp;
5439 datap = smb_GetSMBData(inp, NULL);
5440 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5442 return CM_ERROR_BADSMB;
5444 if (*pathp == 0) /* null path */
5447 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5448 osi_LogSaveClientString(smb_logp, pathp));
5450 rootScp = cm_data.rootSCachep;
5452 userp = smb_GetUserFromVCP(vcp, inp);
5454 /* we shouldn't need this for V3 requests, but we seem to */
5455 caseFold = CM_FLAG_CASEFOLD;
5457 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5459 cm_ReleaseUser(userp);
5460 return CM_ERROR_NOSUCHFILE;
5464 * XXX Strange hack XXX
5466 * As of Patch 5 (16 July 97), we are having the following problem:
5467 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5468 * requests to look up "desktop.ini" in all the subdirectories.
5469 * This can cause zillions of timeouts looking up non-existent cells
5470 * and volumes, especially in the top-level directory.
5472 * We have not found any way to avoid this or work around it except
5473 * to explicitly ignore the requests for mount points that haven't
5474 * yet been evaluated and for directories that haven't yet been
5477 * We should modify this hack to provide a fake desktop.ini file
5478 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5480 spacep = inp->spacep;
5481 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5482 #ifndef SPECIAL_FOLDERS
5483 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5484 code = cm_NameI(rootScp, spacep->wdata,
5485 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5486 userp, tidPathp, &req, &dscp);
5489 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5490 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5492 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5493 return CM_ERROR_PATH_NOT_COVERED;
5495 return CM_ERROR_NOSUCHPATH;
5497 #endif /* DFS_SUPPORT */
5498 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5499 code = CM_ERROR_NOSUCHFILE;
5500 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5501 cm_buf_t *bp = buf_Find(dscp, &hzero);
5506 code = CM_ERROR_NOSUCHFILE;
5508 cm_ReleaseSCache(dscp);
5510 cm_ReleaseUser(userp);
5515 #endif /* SPECIAL_FOLDERS */
5517 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5518 tidPathp, &req, &newScp);
5520 cm_ReleaseUser(userp);
5525 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5526 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5527 cm_ReleaseSCache(newScp);
5528 cm_ReleaseUser(userp);
5529 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5530 return CM_ERROR_PATH_NOT_COVERED;
5532 return CM_ERROR_NOSUCHPATH;
5534 #endif /* DFS_SUPPORT */
5536 /* now lock the vnode with a callback; returns with newScp locked */
5537 lock_ObtainWrite(&newScp->rw);
5538 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5539 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5541 lock_ReleaseWrite(&newScp->rw);
5542 cm_ReleaseSCache(newScp);
5543 cm_ReleaseUser(userp);
5547 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5549 attrs = smb_Attributes(newScp);
5551 smb_SetSMBParm(outp, 0, attrs);
5553 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5554 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5555 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5556 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5557 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5558 smb_SetSMBParm(outp, 5, 0);
5559 smb_SetSMBParm(outp, 6, 0);
5560 smb_SetSMBParm(outp, 7, 0);
5561 smb_SetSMBParm(outp, 8, 0);
5562 smb_SetSMBParm(outp, 9, 0);
5563 smb_SetSMBDataLength(outp, 0);
5564 lock_ReleaseWrite(&newScp->rw);
5566 cm_ReleaseSCache(newScp);
5567 cm_ReleaseUser(userp);
5572 /* SMB_COM_TREE_DISCONNECT */
5573 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5577 osi_Log0(smb_logp, "SMB receive tree disconnect");
5579 /* find the tree and free it */
5580 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5582 lock_ObtainWrite(&smb_rctLock);
5584 smb_ReleaseTID(tidp, TRUE);
5585 lock_ReleaseWrite(&smb_rctLock);
5592 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5595 clientchar_t *pathp;
5596 clientchar_t *lastNamep;
5605 clientchar_t *tidPathp;
5611 datap = smb_GetSMBData(inp, NULL);
5612 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5614 return CM_ERROR_BADSMB;
5616 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5618 #ifdef DEBUG_VERBOSE
5622 hexpath = osi_HexifyString( pathp );
5623 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5628 share = smb_GetSMBParm(inp, 0);
5629 attribute = smb_GetSMBParm(inp, 1);
5631 spacep = inp->spacep;
5632 /* smb_StripLastComponent will strip "::$DATA" if present */
5633 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5635 if (!cm_IsValidClientString(pathp)) {
5637 clientchar_t * hexp;
5639 hexp = cm_GetRawCharsAlloc(pathp, -1);
5640 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5641 osi_LogSaveClientString(smb_logp, hexp));
5645 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5647 return CM_ERROR_BADNTFILENAME;
5650 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5651 /* special case magic file name for receiving IOCTL requests
5652 * (since IOCTL calls themselves aren't getting through).
5654 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5655 smb_SetupIoctlFid(fidp, spacep);
5656 smb_SetSMBParm(outp, 0, fidp->fid);
5657 smb_SetSMBParm(outp, 1, 0); /* attrs */
5658 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5659 smb_SetSMBParm(outp, 3, 0);
5660 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5661 smb_SetSMBParm(outp, 5, 0x7fff);
5662 /* pass the open mode back */
5663 smb_SetSMBParm(outp, 6, (share & 0xf));
5664 smb_SetSMBDataLength(outp, 0);
5665 smb_ReleaseFID(fidp);
5669 userp = smb_GetUserFromVCP(vcp, inp);
5671 caseFold = CM_FLAG_CASEFOLD;
5673 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5675 cm_ReleaseUser(userp);
5676 return CM_ERROR_NOSUCHPATH;
5678 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5679 tidPathp, &req, &scp);
5682 cm_ReleaseUser(userp);
5687 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5688 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5689 cm_ReleaseSCache(scp);
5690 cm_ReleaseUser(userp);
5691 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5692 return CM_ERROR_PATH_NOT_COVERED;
5694 return CM_ERROR_NOSUCHPATH;
5696 #endif /* DFS_SUPPORT */
5698 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5700 cm_ReleaseSCache(scp);
5701 cm_ReleaseUser(userp);
5705 /* don't need callback to check file type, since file types never
5706 * change, and namei and cm_Lookup all stat the object at least once on
5707 * a successful return.
5709 if (scp->fileType != CM_SCACHETYPE_FILE) {
5710 cm_ReleaseSCache(scp);
5711 cm_ReleaseUser(userp);
5712 return CM_ERROR_ISDIR;
5715 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5716 osi_assertx(fidp, "null smb_fid_t");
5718 lock_ObtainMutex(&fidp->mx);
5719 if ((share & 0xf) == 0)
5720 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5721 else if ((share & 0xf) == 1)
5722 fidp->flags |= SMB_FID_OPENWRITE;
5724 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5728 fidp->userp = userp;
5730 /* and a pointer to the vnode */
5732 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5733 lock_ObtainWrite(&scp->rw);
5734 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5736 smb_SetSMBParm(outp, 0, fidp->fid);
5737 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5738 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5739 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5740 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5741 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5742 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5743 /* pass the open mode back; XXXX add access checks */
5744 smb_SetSMBParm(outp, 6, (share & 0xf));
5745 smb_SetSMBDataLength(outp, 0);
5746 lock_ReleaseMutex(&fidp->mx);
5747 lock_ReleaseRead(&scp->rw);
5750 cm_Open(scp, 0, userp);
5752 /* send and free packet */
5753 smb_ReleaseFID(fidp);
5754 cm_ReleaseUser(userp);
5755 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5759 typedef struct smb_unlinkRock {
5764 clientchar_t *maskp; /* pointer to the star pattern */
5767 cm_dirEntryList_t * matches;
5770 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5773 smb_unlinkRock_t *rockp;
5776 normchar_t matchName[MAX_PATH];
5780 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5781 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5782 caseFold |= CM_FLAG_8DOT3;
5784 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5785 /* Can't convert name */
5786 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5787 osi_LogSaveString(smb_logp, dep->name));
5791 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5793 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5794 !cm_Is8Dot3(matchName)) {
5795 cm_Gen8Dot3Name(dep, matchName, NULL);
5796 /* 8.3 matches are always case insensitive */
5797 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5800 osi_Log1(smb_logp, "Found match %S",
5801 osi_LogSaveClientString(smb_logp, matchName));
5803 cm_DirEntryListAdd(dep->name, &rockp->matches);
5807 /* If we made a case sensitive exact match, we might as well quit now. */
5808 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5809 code = CM_ERROR_STOPNOW;
5818 /* SMB_COM_DELETE */
5819 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5823 clientchar_t *pathp;
5827 clientchar_t *lastNamep;
5828 smb_unlinkRock_t rock;
5832 clientchar_t *tidPathp;
5836 memset(&rock, 0, sizeof(rock));
5838 attribute = smb_GetSMBParm(inp, 0);
5840 tp = smb_GetSMBData(inp, NULL);
5841 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5843 return CM_ERROR_BADSMB;
5845 osi_Log1(smb_logp, "SMB receive unlink %S",
5846 osi_LogSaveClientString(smb_logp, pathp));
5848 spacep = inp->spacep;
5849 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5851 userp = smb_GetUserFromVCP(vcp, inp);
5853 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5855 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5857 cm_ReleaseUser(userp);
5858 return CM_ERROR_NOSUCHPATH;
5860 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5863 cm_ReleaseUser(userp);
5868 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5869 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5870 cm_ReleaseSCache(dscp);
5871 cm_ReleaseUser(userp);
5872 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5873 return CM_ERROR_PATH_NOT_COVERED;
5875 return CM_ERROR_NOSUCHPATH;
5877 #endif /* DFS_SUPPORT */
5879 /* otherwise, scp points to the parent directory. */
5886 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5888 code = CM_ERROR_NOSUCHFILE;
5891 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5894 thyper.HighPart = 0;
5899 rock.matches = NULL;
5901 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5902 * match. If that fails, we do a case insensitve match.
5904 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5905 !smb_IsStarMask(rock.maskp)) {
5906 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5909 thyper.HighPart = 0;
5910 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5915 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5917 if (code == CM_ERROR_STOPNOW)
5920 if (code == 0 && rock.matches) {
5921 cm_dirEntryList_t * entry;
5923 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5924 normchar_t normalizedName[MAX_PATH];
5926 /* Note: entry->name is a non-normalized name */
5928 osi_Log1(smb_logp, "Unlinking %s",
5929 osi_LogSaveString(smb_logp, entry->name));
5931 /* We assume this works because entry->name was
5932 successfully converted in smb_UnlinkProc() once. */
5933 cm_FsStringToNormString(entry->name, -1,
5934 normalizedName, lengthof(normalizedName));
5936 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5938 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5939 smb_NotifyChange(FILE_ACTION_REMOVED,
5940 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5941 dscp, normalizedName, NULL, TRUE);
5945 cm_DirEntryListFree(&rock.matches);
5949 cm_ReleaseUser(userp);
5952 cm_ReleaseSCache(dscp);
5957 if (code == 0 && !rock.any)
5958 code = CM_ERROR_NOSUCHFILE;
5962 typedef struct smb_renameRock {
5963 cm_scache_t *odscp; /* old dir */
5964 cm_scache_t *ndscp; /* new dir */
5965 cm_user_t *userp; /* user */
5966 cm_req_t *reqp; /* request struct */
5967 smb_vc_t *vcp; /* virtual circuit */
5968 normchar_t *maskp; /* pointer to star pattern of old file name */
5969 int flags; /* tilde, casefold, etc */
5970 clientchar_t *newNamep; /* ptr to the new file's name */
5971 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5972 clientchar_t clOldName[MAX_PATH]; /* client name */
5976 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5979 smb_renameRock_t *rockp;
5982 normchar_t matchName[MAX_PATH];
5984 rockp = (smb_renameRock_t *) vrockp;
5986 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5987 /* Can't convert string */
5988 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
5989 osi_LogSaveString(smb_logp, dep->name));
5993 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5994 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5995 caseFold |= CM_FLAG_8DOT3;
5997 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5999 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6000 !cm_Is8Dot3(matchName)) {
6001 cm_Gen8Dot3Name(dep, matchName, NULL);
6002 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6007 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6008 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6010 code = CM_ERROR_STOPNOW;
6020 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6023 cm_space_t *spacep = NULL;
6024 smb_renameRock_t rock;
6025 cm_scache_t *oldDscp = NULL;
6026 cm_scache_t *newDscp = NULL;
6027 cm_scache_t *tmpscp= NULL;
6028 cm_scache_t *tmpscp2 = NULL;
6029 clientchar_t *oldLastNamep;
6030 clientchar_t *newLastNamep;
6034 clientchar_t *tidPathp;
6038 userp = smb_GetUserFromVCP(vcp, inp);
6039 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6041 cm_ReleaseUser(userp);
6042 return CM_ERROR_NOSUCHPATH;
6046 memset(&rock, 0, sizeof(rock));
6048 spacep = inp->spacep;
6049 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6051 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6052 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6053 userp, tidPathp, &req, &oldDscp);
6055 cm_ReleaseUser(userp);
6060 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6061 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6062 cm_ReleaseSCache(oldDscp);
6063 cm_ReleaseUser(userp);
6064 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6065 return CM_ERROR_PATH_NOT_COVERED;
6067 return CM_ERROR_NOSUCHPATH;
6069 #endif /* DFS_SUPPORT */
6071 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6072 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6073 userp, tidPathp, &req, &newDscp);
6076 cm_ReleaseSCache(oldDscp);
6077 cm_ReleaseUser(userp);
6082 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6083 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6084 cm_ReleaseSCache(oldDscp);
6085 cm_ReleaseSCache(newDscp);
6086 cm_ReleaseUser(userp);
6087 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6088 return CM_ERROR_PATH_NOT_COVERED;
6090 return CM_ERROR_NOSUCHPATH;
6092 #endif /* DFS_SUPPORT */
6095 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6096 * next, get the component names, and lower case them.
6099 /* handle the old name first */
6101 oldLastNamep = oldPathp;
6105 /* and handle the new name, too */
6107 newLastNamep = newPathp;
6111 /* TODO: The old name could be a wildcard. The new name must not be */
6113 /* Check if the file already exists; if so return error */
6114 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6115 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6116 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6118 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6119 osi_LogSaveClientString(smb_logp, newLastNamep));
6121 /* Check if the old and the new names differ only in case. If so return
6122 * success, else return CM_ERROR_EXISTS
6124 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6126 /* This would be a success only if the old file is *as same as* the new file */
6127 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6129 if (tmpscp == tmpscp2)
6132 code = CM_ERROR_EXISTS;
6133 cm_ReleaseSCache(tmpscp2);
6136 code = CM_ERROR_NOSUCHFILE;
6139 /* file exist, do not rename, also fixes move */
6140 osi_Log0(smb_logp, "Can't rename. Target already exists");
6141 code = CM_ERROR_EXISTS;
6146 /* do the vnode call */
6147 rock.odscp = oldDscp;
6148 rock.ndscp = newDscp;
6152 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6154 code = CM_ERROR_NOSUCHFILE;
6157 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6158 rock.newNamep = newLastNamep;
6159 rock.fsOldName[0] = '\0';
6160 rock.clOldName[0] = '\0';
6163 /* Now search the directory for the pattern, and do the appropriate rename when found */
6164 thyper.LowPart = 0; /* search dir from here */
6165 thyper.HighPart = 0;
6167 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6168 if (code == 0 && !rock.any) {
6170 thyper.HighPart = 0;
6171 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6172 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6174 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6176 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6177 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6178 rock.ndscp, rock.newNamep, rock.userp,
6180 /* if the call worked, stop doing the search now, since we
6181 * really only want to rename one file.
6184 osi_Log0(smb_logp, "cm_Rename failure");
6185 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6186 } else if (code == 0) {
6187 code = CM_ERROR_NOSUCHFILE;
6190 /* Handle Change Notification */
6192 * Being lazy, not distinguishing between files and dirs in this
6193 * filter, since we'd have to do a lookup.
6196 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6197 if (oldDscp == newDscp) {
6198 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6199 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6200 filter, oldDscp, rock.clOldName,
6201 newLastNamep, TRUE);
6203 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6204 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6205 filter, oldDscp, rock.clOldName,
6207 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6208 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6209 filter, newDscp, newLastNamep,
6216 cm_ReleaseSCache(tmpscp);
6218 cm_ReleaseUser(userp);
6220 cm_ReleaseSCache(oldDscp);
6222 cm_ReleaseSCache(newDscp);
6230 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6233 cm_space_t *spacep = NULL;
6234 cm_scache_t *oldDscp = NULL;
6235 cm_scache_t *newDscp = NULL;
6236 cm_scache_t *tmpscp= NULL;
6237 cm_scache_t *tmpscp2 = NULL;
6238 cm_scache_t *sscp = NULL;
6239 clientchar_t *oldLastNamep;
6240 clientchar_t *newLastNamep;
6243 clientchar_t *tidPathp;
6247 userp = smb_GetUserFromVCP(vcp, inp);
6249 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6251 cm_ReleaseUser(userp);
6252 return CM_ERROR_NOSUCHPATH;
6257 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6259 spacep = inp->spacep;
6260 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6262 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6263 userp, tidPathp, &req, &oldDscp);
6265 cm_ReleaseUser(userp);
6270 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6271 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6272 cm_ReleaseSCache(oldDscp);
6273 cm_ReleaseUser(userp);
6274 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6275 return CM_ERROR_PATH_NOT_COVERED;
6277 return CM_ERROR_NOSUCHPATH;
6279 #endif /* DFS_SUPPORT */
6281 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6282 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6283 userp, tidPathp, &req, &newDscp);
6285 cm_ReleaseSCache(oldDscp);
6286 cm_ReleaseUser(userp);
6291 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6292 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6293 cm_ReleaseSCache(newDscp);
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 /* Now, although we did two lookups for the two directories (because the same
6304 * directory can be referenced through different paths), we only allow hard links
6305 * within the same directory. */
6306 if (oldDscp != newDscp) {
6307 cm_ReleaseSCache(oldDscp);
6308 cm_ReleaseSCache(newDscp);
6309 cm_ReleaseUser(userp);
6310 return CM_ERROR_CROSSDEVLINK;
6313 /* handle the old name first */
6315 oldLastNamep = oldPathp;
6319 /* and handle the new name, too */
6321 newLastNamep = newPathp;
6325 /* now lookup the old name */
6326 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6327 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6329 cm_ReleaseSCache(oldDscp);
6330 cm_ReleaseSCache(newDscp);
6331 cm_ReleaseUser(userp);
6335 /* Check if the file already exists; if so return error */
6336 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6337 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6338 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6340 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6341 osi_LogSaveClientString(smb_logp, newLastNamep));
6343 /* if the existing link is to the same file, then we return success */
6345 if(sscp == tmpscp) {
6348 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6349 code = CM_ERROR_EXISTS;
6354 cm_ReleaseSCache(tmpscp);
6355 cm_ReleaseSCache(sscp);
6356 cm_ReleaseSCache(newDscp);
6357 cm_ReleaseSCache(oldDscp);
6358 cm_ReleaseUser(userp);
6362 /* now create the hardlink */
6363 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6364 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6365 osi_Log1(smb_logp," Link returns 0x%x", code);
6367 /* Handle Change Notification */
6369 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6370 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6371 smb_NotifyChange(FILE_ACTION_ADDED,
6372 filter, newDscp, newLastNamep,
6377 cm_ReleaseSCache(tmpscp);
6378 cm_ReleaseUser(userp);
6379 cm_ReleaseSCache(sscp);
6380 cm_ReleaseSCache(oldDscp);
6381 cm_ReleaseSCache(newDscp);
6385 /* SMB_COM_RENAME */
6387 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6389 clientchar_t *oldPathp;
6390 clientchar_t *newPathp;
6394 tp = smb_GetSMBData(inp, NULL);
6395 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6397 return CM_ERROR_BADSMB;
6398 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6400 return CM_ERROR_BADSMB;
6402 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6403 osi_LogSaveClientString(smb_logp, oldPathp),
6404 osi_LogSaveClientString(smb_logp, newPathp));
6406 if (!cm_IsValidClientString(newPathp)) {
6408 clientchar_t * hexp;
6410 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6411 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6412 osi_LogSaveClientString(smb_logp, hexp));
6416 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6418 return CM_ERROR_BADNTFILENAME;
6421 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6423 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6429 typedef struct smb_rmdirRock {
6433 normchar_t *maskp; /* pointer to the star pattern */
6436 cm_dirEntryList_t * matches;
6439 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6442 smb_rmdirRock_t *rockp;
6444 normchar_t matchName[MAX_PATH];
6446 rockp = (smb_rmdirRock_t *) vrockp;
6448 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6449 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6450 osi_LogSaveString(smb_logp, dep->name));
6454 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6455 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6457 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6459 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6460 !cm_Is8Dot3(matchName)) {
6461 cm_Gen8Dot3Name(dep, matchName, NULL);
6462 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6467 cm_DirEntryListAdd(dep->name, &rockp->matches);
6474 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6477 clientchar_t *pathp;
6481 clientchar_t *lastNamep;
6482 smb_rmdirRock_t rock;
6486 clientchar_t *tidPathp;
6490 memset(&rock, 0, sizeof(rock));
6492 tp = smb_GetSMBData(inp, NULL);
6493 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6495 return CM_ERROR_BADSMB;
6497 spacep = inp->spacep;
6498 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6500 userp = smb_GetUserFromVCP(vcp, inp);
6502 caseFold = CM_FLAG_CASEFOLD;
6504 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6506 cm_ReleaseUser(userp);
6507 return CM_ERROR_NOSUCHPATH;
6509 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6510 userp, tidPathp, &req, &dscp);
6513 cm_ReleaseUser(userp);
6518 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6519 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6520 cm_ReleaseSCache(dscp);
6521 cm_ReleaseUser(userp);
6522 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6523 return CM_ERROR_PATH_NOT_COVERED;
6525 return CM_ERROR_NOSUCHPATH;
6527 #endif /* DFS_SUPPORT */
6529 /* otherwise, scp points to the parent directory. */
6536 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6538 code = CM_ERROR_NOSUCHFILE;
6541 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6544 thyper.HighPart = 0;
6548 rock.matches = NULL;
6550 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6551 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6552 if (code == 0 && !rock.any) {
6554 thyper.HighPart = 0;
6555 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6556 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6559 if (code == 0 && rock.matches) {
6560 cm_dirEntryList_t * entry;
6562 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6563 clientchar_t clientName[MAX_PATH];
6565 /* We assume this will succeed because smb_RmdirProc()
6566 successfully converted entry->name once above. */
6567 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6569 osi_Log1(smb_logp, "Removing directory %s",
6570 osi_LogSaveString(smb_logp, entry->name));
6572 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6574 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6575 smb_NotifyChange(FILE_ACTION_REMOVED,
6576 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6577 dscp, clientName, NULL, TRUE);
6583 cm_DirEntryListFree(&rock.matches);
6586 cm_ReleaseUser(userp);
6589 cm_ReleaseSCache(dscp);
6591 if (code == 0 && !rock.any)
6592 code = CM_ERROR_NOSUCHFILE;
6601 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6611 fid = smb_GetSMBParm(inp, 0);
6613 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6615 fid = smb_ChainFID(fid, inp);
6616 fidp = smb_FindFID(vcp, fid, 0);
6618 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6620 return CM_ERROR_BADFD;
6622 userp = smb_GetUserFromVCP(vcp, inp);
6624 lock_ObtainMutex(&fidp->mx);
6625 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6626 cm_ReleaseUser(userp);
6627 lock_ReleaseMutex(&fidp->mx);
6628 smb_ReleaseFID(fidp);
6629 return CM_ERROR_BADFD;
6632 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6633 lock_ReleaseMutex(&fidp->mx);
6634 cm_ReleaseUser(userp);
6635 smb_CloseFID(vcp, fidp, NULL, 0);
6636 smb_ReleaseFID(fidp);
6637 return CM_ERROR_NOSUCHFILE;
6640 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6641 cm_scache_t * scp = fidp->scp;
6643 lock_ReleaseMutex(&fidp->mx);
6644 code = cm_FSync(scp, userp, &req);
6645 cm_ReleaseSCache(scp);
6647 lock_ReleaseMutex(&fidp->mx);
6651 cm_ReleaseUser(userp);
6652 smb_ReleaseFID(fidp);
6656 struct smb_FullNameRock {
6659 clientchar_t *fullName;
6660 fschar_t *originalName;
6663 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6666 normchar_t matchName[MAX_PATH];
6667 struct smb_FullNameRock *vrockp;
6669 vrockp = (struct smb_FullNameRock *)rockp;
6671 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6672 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6673 osi_LogSaveString(smb_logp, dep->name));
6677 if (!cm_Is8Dot3(matchName)) {
6678 clientchar_t shortName[13];
6680 cm_Gen8Dot3Name(dep, shortName, NULL);
6682 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6683 vrockp->fullName = cm_ClientStrDup(matchName);
6684 vrockp->originalName = cm_FsStrDup(dep->name);
6685 return CM_ERROR_STOPNOW;
6688 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6689 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6690 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6691 vrockp->fullName = cm_ClientStrDup(matchName);
6692 vrockp->originalName = cm_FsStrDup(dep->name);
6693 return CM_ERROR_STOPNOW;
6698 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6699 clientchar_t **newPathp, fschar_t ** originalPathp,
6700 cm_user_t *userp, cm_req_t *reqp)
6702 struct smb_FullNameRock rock;
6705 memset(&rock, 0, sizeof(rock));
6709 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6710 if (code == CM_ERROR_STOPNOW) {
6711 *newPathp = rock.fullName;
6712 *originalPathp = rock.originalName;
6714 *newPathp = cm_ClientStrDup(pathp);
6715 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6719 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6720 afs_uint32 dosTime) {
6723 cm_scache_t *dscp = NULL;
6724 clientchar_t *pathp = NULL;
6725 cm_scache_t * scp = NULL;
6726 cm_scache_t *delscp = NULL;
6727 int nullcreator = 0;
6729 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6730 fidp, fidp->fid, scp, vcp);
6733 lock_ObtainMutex(&fidp->mx);
6734 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6736 lock_ReleaseMutex(&fidp->mx);
6737 osi_Log0(smb_logp, " No user specified. Not closing fid");
6738 return CM_ERROR_BADFD;
6741 userp = fidp->userp; /* no hold required since fidp is held
6742 throughout the function */
6743 lock_ReleaseMutex(&fidp->mx);
6748 lock_ObtainWrite(&smb_rctLock);
6749 if (fidp->deleteOk) {
6750 osi_Log0(smb_logp, " Fid already closed.");
6751 lock_ReleaseWrite(&smb_rctLock);
6752 return CM_ERROR_BADFD;
6755 lock_ReleaseWrite(&smb_rctLock);
6757 lock_ObtainMutex(&fidp->mx);
6758 if (fidp->NTopen_dscp) {
6759 dscp = fidp->NTopen_dscp;
6760 cm_HoldSCache(dscp);
6763 if (fidp->NTopen_pathp)
6764 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6771 /* Don't jump the gun on an async raw write */
6772 while (fidp->raw_writers) {
6773 lock_ReleaseMutex(&fidp->mx);
6774 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6775 lock_ObtainMutex(&fidp->mx);
6778 /* watch for ioctl closes, and read-only opens */
6780 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6781 == SMB_FID_OPENWRITE) {
6782 if (dosTime != 0 && dosTime != -1) {
6783 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6784 /* This fixes defect 10958 */
6785 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6786 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6788 if (smb_AsyncStore != 2) {
6789 lock_ReleaseMutex(&fidp->mx);
6790 code = cm_FSync(scp, userp, &req);
6791 lock_ObtainMutex(&fidp->mx);
6797 /* unlock any pending locks */
6798 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6799 scp->fileType == CM_SCACHETYPE_FILE) {
6803 lock_ReleaseMutex(&fidp->mx);
6805 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6807 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6808 lock_ObtainWrite(&scp->rw);
6810 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6811 CM_SCACHESYNC_NEEDCALLBACK
6812 | CM_SCACHESYNC_GETSTATUS
6813 | CM_SCACHESYNC_LOCK);
6817 "smb CoreClose SyncOp failure code 0x%x", tcode);
6818 goto post_syncopdone;
6821 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6823 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6827 lock_ReleaseWrite(&scp->rw);
6828 lock_ObtainMutex(&fidp->mx);
6831 if (fidp->flags & SMB_FID_DELONCLOSE) {
6832 clientchar_t *fullPathp = NULL;
6833 fschar_t *originalNamep = NULL;
6835 lock_ReleaseMutex(&fidp->mx);
6837 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6842 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6843 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6844 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6846 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6847 smb_NotifyChange(FILE_ACTION_REMOVED,
6848 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6849 dscp, fullPathp, NULL, TRUE);
6852 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6854 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6855 smb_NotifyChange(FILE_ACTION_REMOVED,
6856 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6857 dscp, fullPathp, NULL, TRUE);
6864 free(originalNamep);
6866 lock_ObtainMutex(&fidp->mx);
6867 fidp->flags &= ~SMB_FID_DELONCLOSE;
6870 /* if this was a newly created file, then clear the creator
6871 * in the stat cache entry. */
6872 if (fidp->flags & SMB_FID_CREATED) {
6874 fidp->flags &= ~SMB_FID_CREATED;
6877 if (fidp->flags & SMB_FID_NTOPEN) {
6878 cm_ReleaseSCache(fidp->NTopen_dscp);
6879 fidp->NTopen_dscp = NULL;
6880 free(fidp->NTopen_pathp);
6881 fidp->NTopen_pathp = NULL;
6882 fidp->flags &= ~SMB_FID_NTOPEN;
6884 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6885 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6888 if (fidp->NTopen_wholepathp) {
6889 free(fidp->NTopen_wholepathp);
6890 fidp->NTopen_wholepathp = NULL;
6894 cm_ReleaseSCache(fidp->scp);
6897 lock_ReleaseMutex(&fidp->mx);
6900 cm_ReleaseSCache(dscp);
6903 cm_ReleaseSCache(delscp);
6907 lock_ObtainWrite(&scp->rw);
6908 if (nullcreator && scp->creator == userp)
6909 scp->creator = NULL;
6910 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6911 lock_ReleaseWrite(&scp->rw);
6912 cm_ReleaseSCache(scp);
6922 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6930 fid = smb_GetSMBParm(inp, 0);
6931 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6933 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6935 fid = smb_ChainFID(fid, inp);
6936 fidp = smb_FindFID(vcp, fid, 0);
6938 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
6940 return CM_ERROR_BADFD;
6943 userp = smb_GetUserFromVCP(vcp, inp);
6945 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6947 smb_ReleaseFID(fidp);
6948 cm_ReleaseUser(userp);
6953 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6955 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6956 cm_user_t *userp, long *readp)
6962 osi_hyper_t fileLength;
6964 osi_hyper_t lastByte;
6965 osi_hyper_t bufferOffset;
6969 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6972 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6973 fidp->fid, offsetp->LowPart, count);
6977 lock_ObtainMutex(&fidp->mx);
6978 /* make sure we have a readable FD */
6979 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6980 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6981 fidp->fid, fidp->flags);
6982 lock_ReleaseMutex(&fidp->mx);
6983 code = CM_ERROR_BADFDOP;
6988 lock_ReleaseMutex(&fidp->mx);
6989 code = CM_ERROR_BADFD;
7000 lock_ObtainWrite(&scp->rw);
7002 if (offset.HighPart == 0) {
7003 chunk = offset.LowPart >> cm_logChunkSize;
7004 if (chunk != fidp->curr_chunk) {
7005 fidp->prev_chunk = fidp->curr_chunk;
7006 fidp->curr_chunk = chunk;
7008 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7011 lock_ReleaseMutex(&fidp->mx);
7013 /* start by looking up the file's end */
7014 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7015 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7019 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7021 /* now we have the entry locked, look up the length */
7022 fileLength = scp->length;
7024 /* adjust count down so that it won't go past EOF */
7025 thyper.LowPart = count;
7026 thyper.HighPart = 0;
7027 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7029 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7030 /* we'd read past EOF, so just stop at fileLength bytes.
7031 * Start by computing how many bytes remain in the file.
7033 thyper = LargeIntegerSubtract(fileLength, offset);
7035 /* if we are past EOF, read 0 bytes */
7036 if (LargeIntegerLessThanZero(thyper))
7039 count = thyper.LowPart;
7044 /* now, copy the data one buffer at a time,
7045 * until we've filled the request packet
7048 /* if we've copied all the data requested, we're done */
7049 if (count <= 0) break;
7051 /* otherwise, load up a buffer of data */
7052 thyper.HighPart = offset.HighPart;
7053 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7054 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7057 buf_Release(bufferp);
7060 lock_ReleaseWrite(&scp->rw);
7062 code = buf_Get(scp, &thyper, &req, &bufferp);
7064 lock_ObtainWrite(&scp->rw);
7065 if (code) goto done;
7066 bufferOffset = thyper;
7068 /* now get the data in the cache */
7070 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7071 CM_SCACHESYNC_NEEDCALLBACK |
7072 CM_SCACHESYNC_READ);
7076 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7078 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7080 /* otherwise, load the buffer and try again */
7081 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7085 buf_Release(bufferp);
7089 } /* if (wrong buffer) ... */
7091 /* now we have the right buffer loaded. Copy out the
7092 * data from here to the user's buffer.
7094 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7096 /* and figure out how many bytes we want from this buffer */
7097 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7098 if (nbytes > count) nbytes = count; /* don't go past EOF */
7100 /* now copy the data */
7101 memcpy(op, bufferp->datap + bufIndex, nbytes);
7103 /* adjust counters, pointers, etc. */
7106 thyper.LowPart = nbytes;
7107 thyper.HighPart = 0;
7108 offset = LargeIntegerAdd(thyper, offset);
7112 lock_ReleaseWrite(&scp->rw);
7114 buf_Release(bufferp);
7116 if (code == 0 && sequential)
7117 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7119 cm_ReleaseSCache(scp);
7122 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7123 fidp->fid, code, *readp);
7128 * smb_WriteData -- common code for Write and Raw Write
7130 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7131 cm_user_t *userp, long *writtenp)
7133 osi_hyper_t offset = *offsetp;
7136 cm_scache_t *scp = NULL;
7137 osi_hyper_t fileLength; /* file's length at start of write */
7138 osi_hyper_t minLength; /* don't read past this */
7139 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7140 cm_buf_t *bufferp = NULL;
7141 osi_hyper_t thyper; /* hyper tmp variable */
7142 osi_hyper_t bufferOffset;
7143 afs_uint32 bufIndex; /* index in buffer where our data is */
7144 int doWriteBack = 0;
7145 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7149 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7150 fidp->fid, offsetp->LowPart, count);
7154 lock_ObtainMutex(&fidp->mx);
7155 /* make sure we have a writable FD */
7156 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7157 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7158 fidp->fid, fidp->flags);
7159 lock_ReleaseMutex(&fidp->mx);
7160 code = CM_ERROR_BADFDOP;
7168 lock_ReleaseMutex(&fidp->mx);
7170 lock_ObtainWrite(&scp->rw);
7171 /* start by looking up the file's end */
7172 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7173 CM_SCACHESYNC_NEEDCALLBACK
7174 | CM_SCACHESYNC_SETSTATUS
7175 | CM_SCACHESYNC_GETSTATUS);
7179 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7181 /* now we have the entry locked, look up the length */
7182 fileLength = scp->length;
7183 minLength = fileLength;
7184 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7185 minLength = scp->serverLength;
7187 /* adjust file length if we extend past EOF */
7188 thyper.LowPart = count;
7189 thyper.HighPart = 0;
7190 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7191 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7192 /* we'd write past EOF, so extend the file */
7193 scp->mask |= CM_SCACHEMASK_LENGTH;
7194 scp->length = thyper;
7195 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7197 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7199 /* now, if the new position (thyper) and the old (offset) are in
7200 * different storeback windows, remember to store back the previous
7201 * storeback window when we're done with the write.
7203 * the purpose of this logic is to slow down the CIFS client
7204 * in order to avoid the client disconnecting during the CLOSE
7205 * operation if there are too many dirty buffers left to write
7206 * than can be accomplished during 45 seconds. This used to be
7207 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7208 * so that we can read larger amounts of data at a time.
7210 if (smb_AsyncStore == 1 &&
7211 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7212 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7213 /* they're different */
7215 writeBackOffset.HighPart = offset.HighPart;
7216 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7221 /* now, copy the data one buffer at a time, until we've filled the
7224 /* if we've copied all the data requested, we're done */
7228 /* handle over quota or out of space */
7229 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7230 *writtenp = written;
7231 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7235 /* otherwise, load up a buffer of data */
7236 thyper.HighPart = offset.HighPart;
7237 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7238 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7241 lock_ReleaseMutex(&bufferp->mx);
7242 buf_Release(bufferp);
7245 lock_ReleaseWrite(&scp->rw);
7247 code = buf_Get(scp, &thyper, &req, &bufferp);
7249 lock_ObtainMutex(&bufferp->mx);
7250 lock_ObtainWrite(&scp->rw);
7251 if (code) goto done;
7253 bufferOffset = thyper;
7255 /* now get the data in the cache */
7257 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7258 CM_SCACHESYNC_NEEDCALLBACK
7259 | CM_SCACHESYNC_WRITE
7260 | CM_SCACHESYNC_BUFLOCKED);
7264 cm_SyncOpDone(scp, bufferp,
7265 CM_SCACHESYNC_NEEDCALLBACK
7266 | CM_SCACHESYNC_WRITE
7267 | CM_SCACHESYNC_BUFLOCKED);
7269 /* If we're overwriting the entire buffer, or
7270 * if we're writing at or past EOF, mark the
7271 * buffer as current so we don't call
7272 * cm_GetBuffer. This skips the fetch from the
7273 * server in those cases where we're going to
7274 * obliterate all the data in the buffer anyway,
7275 * or in those cases where there is no useful
7276 * data at the server to start with.
7278 * Use minLength instead of scp->length, since
7279 * the latter has already been updated by this
7282 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7283 || LargeIntegerEqualTo(offset, bufferp->offset)
7284 && (count >= cm_data.buf_blockSize
7285 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7286 ConvertLongToLargeInteger(count)),
7288 if (count < cm_data.buf_blockSize
7289 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7290 memset(bufferp->datap, 0,
7291 cm_data.buf_blockSize);
7292 bufferp->dataVersion = scp->dataVersion;
7295 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7297 /* otherwise, load the buffer and try again */
7298 lock_ReleaseMutex(&bufferp->mx);
7299 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7301 lock_ReleaseWrite(&scp->rw);
7302 lock_ObtainMutex(&bufferp->mx);
7303 lock_ObtainWrite(&scp->rw);
7307 lock_ReleaseMutex(&bufferp->mx);
7308 buf_Release(bufferp);
7312 } /* if (wrong buffer) ... */
7314 /* now we have the right buffer loaded. Copy out the
7315 * data from here to the user's buffer.
7317 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7319 /* and figure out how many bytes we want from this buffer */
7320 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7322 nbytes = count; /* don't go past end of request */
7324 /* now copy the data */
7325 memcpy(bufferp->datap + bufIndex, op, nbytes);
7326 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7328 /* adjust counters, pointers, etc. */
7332 thyper.LowPart = nbytes;
7333 thyper.HighPart = 0;
7334 offset = LargeIntegerAdd(thyper, offset);
7338 lock_ReleaseWrite(&scp->rw);
7341 lock_ReleaseMutex(&bufferp->mx);
7342 buf_Release(bufferp);
7345 lock_ObtainMutex(&fidp->mx);
7346 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7347 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7349 lock_ReleaseMutex(&fidp->mx);
7350 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7351 fidp->NTopen_dscp, fidp->NTopen_pathp,
7354 lock_ReleaseMutex(&fidp->mx);
7358 if (smb_AsyncStore > 0) {
7362 lock_ObtainWrite(&scp->rw);
7363 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7365 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7366 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7368 lock_ReleaseWrite(&scp->rw);
7369 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7370 writeBackOffset.HighPart,
7371 smb_AsyncStoreSize, 0, userp);
7372 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7375 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7379 cm_ReleaseSCache(scp);
7382 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7383 fidp->fid, code, *writtenp);
7388 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7391 unsigned short count;
7393 unsigned short hint;
7394 long written = 0, total_written = 0;
7397 smb_t* smbp = (smb_t*) inp;
7401 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7403 int inDataBlockCount;
7405 fd = smb_GetSMBParm(inp, 0);
7406 count = smb_GetSMBParm(inp, 1);
7407 offset.HighPart = 0; /* too bad */
7408 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7409 hint = smb_GetSMBParm(inp, 4);
7411 op = smb_GetSMBData(inp, NULL);
7412 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7414 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7415 fd, offset.LowPart, count);
7417 fd = smb_ChainFID(fd, inp);
7418 fidp = smb_FindFID(vcp, fd, 0);
7420 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7422 return CM_ERROR_BADFD;
7425 lock_ObtainMutex(&fidp->mx);
7426 if (fidp->flags & SMB_FID_IOCTL) {
7427 lock_ReleaseMutex(&fidp->mx);
7428 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7429 smb_ReleaseFID(fidp);
7430 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7434 if (fidp->flags & SMB_FID_RPC) {
7435 lock_ReleaseMutex(&fidp->mx);
7436 code = smb_RPCWrite(fidp, vcp, inp, outp);
7437 smb_ReleaseFID(fidp);
7438 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7443 lock_ReleaseMutex(&fidp->mx);
7444 smb_ReleaseFID(fidp);
7445 return CM_ERROR_BADFD;
7448 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7449 lock_ReleaseMutex(&fidp->mx);
7450 smb_CloseFID(vcp, fidp, NULL, 0);
7451 smb_ReleaseFID(fidp);
7452 return CM_ERROR_NOSUCHFILE;
7457 lock_ReleaseMutex(&fidp->mx);
7458 userp = smb_GetUserFromVCP(vcp, inp);
7462 LARGE_INTEGER LOffset;
7463 LARGE_INTEGER LLength;
7466 key = cm_GenerateKey(vcp->vcID, pid, fd);
7468 LOffset.HighPart = offset.HighPart;
7469 LOffset.LowPart = offset.LowPart;
7470 LLength.HighPart = 0;
7471 LLength.LowPart = count;
7473 lock_ObtainWrite(&scp->rw);
7474 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7475 lock_ReleaseWrite(&scp->rw);
7478 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7483 /* special case: 0 bytes transferred means truncate to this position */
7487 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7491 truncAttr.mask = CM_ATTRMASK_LENGTH;
7492 truncAttr.length.LowPart = offset.LowPart;
7493 truncAttr.length.HighPart = 0;
7494 lock_ObtainMutex(&fidp->mx);
7495 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7496 fidp->flags |= SMB_FID_LENGTHSETDONE;
7497 lock_ReleaseMutex(&fidp->mx);
7498 smb_SetSMBParm(outp, 0, 0 /* count */);
7499 smb_SetSMBDataLength(outp, 0);
7504 * Work around bug in NT client
7506 * When copying a file, the NT client should first copy the data,
7507 * then copy the last write time. But sometimes the NT client does
7508 * these in the wrong order, so the data copies would inadvertently
7509 * cause the last write time to be overwritten. We try to detect this,
7510 * and don't set client mod time if we think that would go against the
7513 lock_ObtainMutex(&fidp->mx);
7514 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7515 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7516 fidp->scp->clientModTime = time(NULL);
7518 lock_ReleaseMutex(&fidp->mx);
7521 while ( code == 0 && count > 0 ) {
7522 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7523 if (code == 0 && written == 0)
7524 code = CM_ERROR_PARTIALWRITE;
7526 offset = LargeIntegerAdd(offset,
7527 ConvertLongToLargeInteger(written));
7528 count -= (unsigned short)written;
7529 total_written += written;
7533 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7534 total_written, code);
7536 /* set the packet data length to 3 bytes for the data block header,
7537 * plus the size of the data.
7539 smb_SetSMBParm(outp, 0, total_written);
7540 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7541 smb_SetSMBParm(outp, 3, hint);
7542 smb_SetSMBDataLength(outp, 0);
7545 smb_ReleaseFID(fidp);
7546 cm_ReleaseUser(userp);
7547 cm_ReleaseSCache(scp);
7552 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7553 NCB *ncbp, raw_write_cont_t *rwcp)
7562 fd = smb_GetSMBParm(inp, 0);
7563 fidp = smb_FindFID(vcp, fd, 0);
7565 lock_ObtainMutex(&fidp->mx);
7567 lock_ReleaseMutex(&fidp->mx);
7568 smb_ReleaseFID(fidp);
7572 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7573 lock_ReleaseMutex(&fidp->mx);
7574 smb_CloseFID(vcp, fidp, NULL, 0);
7575 smb_ReleaseFID(fidp);
7578 lock_ReleaseMutex(&fidp->mx);
7580 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7581 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7583 userp = smb_GetUserFromVCP(vcp, inp);
7586 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7588 if (rwcp->writeMode & 0x1) { /* synchronous */
7591 smb_FormatResponsePacket(vcp, inp, outp);
7592 op = (smb_t *) outp;
7593 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7594 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7595 smb_SetSMBDataLength(outp, 0);
7596 smb_SendPacket(vcp, outp);
7597 smb_FreePacket(outp);
7599 else { /* asynchronous */
7600 lock_ObtainMutex(&fidp->mx);
7601 fidp->raw_writers--;
7602 if (fidp->raw_writers == 0)
7603 thrd_SetEvent(fidp->raw_write_event);
7604 lock_ReleaseMutex(&fidp->mx);
7607 /* Give back raw buffer */
7608 lock_ObtainMutex(&smb_RawBufLock);
7609 *((char **)rawBuf) = smb_RawBufs;
7610 smb_RawBufs = rawBuf;
7611 lock_ReleaseMutex(&smb_RawBufLock);
7613 smb_ReleaseFID(fidp);
7614 cm_ReleaseUser(userp);
7617 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7622 /* SMB_COM_WRITE_RAW */
7623 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7626 long count, written = 0, total_written = 0;
7630 smb_t *smbp = (smb_t*) inp;
7635 unsigned short writeMode;
7637 fd = smb_GetSMBParm(inp, 0);
7638 totalCount = smb_GetSMBParm(inp, 1);
7639 count = smb_GetSMBParm(inp, 10);
7640 writeMode = smb_GetSMBParm(inp, 7);
7642 op = (char *) inp->data;
7643 op += smb_GetSMBParm(inp, 11);
7645 offset.HighPart = 0;
7646 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7648 if (*inp->wctp == 14) {
7649 /* we received a 64-bit file offset */
7650 #ifdef AFS_LARGEFILES
7651 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7653 if (LargeIntegerLessThanZero(offset)) {
7655 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7656 offset.HighPart, offset.LowPart);
7657 return CM_ERROR_BADSMB;
7660 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7662 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7663 return CM_ERROR_BADSMB;
7666 offset.HighPart = 0;
7669 offset.HighPart = 0; /* 32-bit file offset */
7673 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7674 fd, offset.HighPart, offset.LowPart, count);
7676 " WriteRaw WriteMode 0x%x",
7679 fd = smb_ChainFID(fd, inp);
7680 fidp = smb_FindFID(vcp, fd, 0);
7682 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7684 return CM_ERROR_BADFD;
7686 lock_ObtainMutex(&fidp->mx);
7688 lock_ReleaseMutex(&fidp->mx);
7689 smb_ReleaseFID(fidp);
7690 return CM_ERROR_BADFD;
7693 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7694 lock_ReleaseMutex(&fidp->mx);
7695 smb_CloseFID(vcp, fidp, NULL, 0);
7696 smb_ReleaseFID(fidp);
7697 return CM_ERROR_NOSUCHFILE;
7702 lock_ReleaseMutex(&fidp->mx);
7707 LARGE_INTEGER LOffset;
7708 LARGE_INTEGER LLength;
7711 key = cm_GenerateKey(vcp->vcID, pid, fd);
7713 LOffset.HighPart = offset.HighPart;
7714 LOffset.LowPart = offset.LowPart;
7715 LLength.HighPart = 0;
7716 LLength.LowPart = count;
7718 lock_ObtainWrite(&scp->rw);
7719 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7720 lock_ReleaseWrite(&scp->rw);
7723 cm_ReleaseSCache(scp);
7724 smb_ReleaseFID(fidp);
7729 userp = smb_GetUserFromVCP(vcp, inp);
7732 * Work around bug in NT client
7734 * When copying a file, the NT client should first copy the data,
7735 * then copy the last write time. But sometimes the NT client does
7736 * these in the wrong order, so the data copies would inadvertently
7737 * cause the last write time to be overwritten. We try to detect this,
7738 * and don't set client mod time if we think that would go against the
7741 lock_ObtainMutex(&fidp->mx);
7742 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7743 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7744 fidp->scp->clientModTime = time(NULL);
7746 lock_ReleaseMutex(&fidp->mx);
7749 while ( code == 0 && count > 0 ) {
7750 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7751 if (code == 0 && written == 0)
7752 code = CM_ERROR_PARTIALWRITE;
7754 offset = LargeIntegerAdd(offset,
7755 ConvertLongToLargeInteger(written));
7758 total_written += written;
7762 /* Get a raw buffer */
7765 lock_ObtainMutex(&smb_RawBufLock);
7767 /* Get a raw buf, from head of list */
7768 rawBuf = smb_RawBufs;
7769 smb_RawBufs = *(char **)smb_RawBufs;
7772 code = CM_ERROR_USESTD;
7774 lock_ReleaseMutex(&smb_RawBufLock);
7777 /* Don't allow a premature Close */
7778 if (code == 0 && (writeMode & 1) == 0) {
7779 lock_ObtainMutex(&fidp->mx);
7780 fidp->raw_writers++;
7781 thrd_ResetEvent(fidp->raw_write_event);
7782 lock_ReleaseMutex(&fidp->mx);
7785 smb_ReleaseFID(fidp);
7786 cm_ReleaseUser(userp);
7787 cm_ReleaseSCache(scp);
7790 smb_SetSMBParm(outp, 0, total_written);
7791 smb_SetSMBDataLength(outp, 0);
7792 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7797 offset = LargeIntegerAdd(offset,
7798 ConvertLongToLargeInteger(count));
7802 rwcp->offset.HighPart = offset.HighPart;
7803 rwcp->offset.LowPart = offset.LowPart;
7804 rwcp->count = totalCount - count;
7805 rwcp->writeMode = writeMode;
7806 rwcp->alreadyWritten = total_written;
7808 /* set the packet data length to 3 bytes for the data block header,
7809 * plus the size of the data.
7811 smb_SetSMBParm(outp, 0, 0xffff);
7812 smb_SetSMBDataLength(outp, 0);
7818 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7821 long count, finalCount;
7825 smb_t *smbp = (smb_t*) inp;
7831 fd = smb_GetSMBParm(inp, 0);
7832 count = smb_GetSMBParm(inp, 1);
7833 offset.HighPart = 0; /* too bad */
7834 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7836 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7837 fd, offset.LowPart, count);
7839 fd = smb_ChainFID(fd, inp);
7840 fidp = smb_FindFID(vcp, fd, 0);
7842 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7844 return CM_ERROR_BADFD;
7846 lock_ObtainMutex(&fidp->mx);
7847 if (fidp->flags & SMB_FID_IOCTL) {
7848 lock_ReleaseMutex(&fidp->mx);
7849 code = smb_IoctlRead(fidp, vcp, inp, outp);
7850 smb_ReleaseFID(fidp);
7854 if (fidp->flags & SMB_FID_RPC) {
7855 lock_ReleaseMutex(&fidp->mx);
7856 code = smb_RPCRead(fidp, vcp, inp, outp);
7857 smb_ReleaseFID(fidp);
7862 lock_ReleaseMutex(&fidp->mx);
7863 smb_ReleaseFID(fidp);
7864 return CM_ERROR_BADFD;
7867 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7868 lock_ReleaseMutex(&fidp->mx);
7869 smb_CloseFID(vcp, fidp, NULL, 0);
7870 smb_ReleaseFID(fidp);
7871 return CM_ERROR_NOSUCHFILE;
7876 lock_ReleaseMutex(&fidp->mx);
7879 LARGE_INTEGER LOffset, LLength;
7883 key = cm_GenerateKey(vcp->vcID, pid, fd);
7885 LOffset.HighPart = 0;
7886 LOffset.LowPart = offset.LowPart;
7887 LLength.HighPart = 0;
7888 LLength.LowPart = count;
7890 lock_ObtainWrite(&scp->rw);
7891 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7892 lock_ReleaseWrite(&scp->rw);
7895 cm_ReleaseSCache(scp);
7896 smb_ReleaseFID(fidp);
7900 userp = smb_GetUserFromVCP(vcp, inp);
7902 /* remember this for final results */
7903 smb_SetSMBParm(outp, 0, count);
7904 smb_SetSMBParm(outp, 1, 0);
7905 smb_SetSMBParm(outp, 2, 0);
7906 smb_SetSMBParm(outp, 3, 0);
7907 smb_SetSMBParm(outp, 4, 0);
7909 /* set the packet data length to 3 bytes for the data block header,
7910 * plus the size of the data.
7912 smb_SetSMBDataLength(outp, count+3);
7914 /* get op ptr after putting in the parms, since otherwise we don't
7915 * know where the data really is.
7917 op = smb_GetSMBData(outp, NULL);
7919 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7920 *op++ = 1; /* data block marker */
7921 *op++ = (unsigned char) (count & 0xff);
7922 *op++ = (unsigned char) ((count >> 8) & 0xff);
7924 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7926 /* fix some things up */
7927 smb_SetSMBParm(outp, 0, finalCount);
7928 smb_SetSMBDataLength(outp, finalCount+3);
7930 smb_ReleaseFID(fidp);
7932 cm_ReleaseUser(userp);
7933 cm_ReleaseSCache(scp);
7937 /* SMB_COM_CREATE_DIRECTORY */
7938 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7940 clientchar_t *pathp;
7945 cm_scache_t *dscp; /* dir we're dealing with */
7946 cm_scache_t *scp; /* file we're creating */
7948 int initialModeBits;
7949 clientchar_t *lastNamep;
7951 clientchar_t *tidPathp;
7958 /* compute initial mode bits based on read-only flag in attributes */
7959 initialModeBits = 0777;
7961 tp = smb_GetSMBData(inp, NULL);
7962 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7964 return CM_ERROR_BADSMB;
7966 spacep = inp->spacep;
7967 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7969 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7970 return CM_ERROR_EXISTS;
7972 userp = smb_GetUserFromVCP(vcp, inp);
7974 caseFold = CM_FLAG_CASEFOLD;
7976 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7978 cm_ReleaseUser(userp);
7979 return CM_ERROR_NOSUCHPATH;
7982 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7983 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7984 userp, tidPathp, &req, &dscp);
7987 cm_ReleaseUser(userp);
7992 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7993 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7994 cm_ReleaseSCache(dscp);
7995 cm_ReleaseUser(userp);
7996 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7997 return CM_ERROR_PATH_NOT_COVERED;
7999 return CM_ERROR_NOSUCHPATH;
8001 #endif /* DFS_SUPPORT */
8003 /* otherwise, scp points to the parent directory. Do a lookup, and
8004 * fail if we find it. Otherwise, we do the create.
8010 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8011 if (scp) cm_ReleaseSCache(scp);
8012 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8013 if (code == 0) code = CM_ERROR_EXISTS;
8014 cm_ReleaseSCache(dscp);
8015 cm_ReleaseUser(userp);
8019 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8020 setAttr.clientModTime = time(NULL);
8021 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8022 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8023 smb_NotifyChange(FILE_ACTION_ADDED,
8024 FILE_NOTIFY_CHANGE_DIR_NAME,
8025 dscp, lastNamep, NULL, TRUE);
8027 /* we don't need this any longer */
8028 cm_ReleaseSCache(dscp);
8031 /* something went wrong creating or truncating the file */
8032 cm_ReleaseUser(userp);
8036 /* otherwise we succeeded */
8037 smb_SetSMBDataLength(outp, 0);
8038 cm_ReleaseUser(userp);
8043 BOOL smb_IsLegalFilename(clientchar_t *filename)
8046 * Find the longest substring of filename that does not contain
8047 * any of the chars in illegalChars. If that substring is less
8048 * than the length of the whole string, then one or more of the
8049 * illegal chars is in filename.
8051 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8057 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8058 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8060 clientchar_t *pathp;
8066 cm_scache_t *dscp; /* dir we're dealing with */
8067 cm_scache_t *scp; /* file we're creating */
8069 int initialModeBits;
8072 clientchar_t *lastNamep;
8075 clientchar_t *tidPathp;
8077 int created = 0; /* the file was new */
8082 excl = (inp->inCom == 0x03)? 0 : 1;
8084 attributes = smb_GetSMBParm(inp, 0);
8085 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8087 /* compute initial mode bits based on read-only flag in attributes */
8088 initialModeBits = 0666;
8089 if (attributes & SMB_ATTR_READONLY)
8090 initialModeBits &= ~0222;
8092 tp = smb_GetSMBData(inp, NULL);
8093 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8095 return CM_ERROR_BADSMB;
8097 spacep = inp->spacep;
8098 /* smb_StripLastComponent will strip "::$DATA" if present */
8099 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8101 if (!cm_IsValidClientString(pathp)) {
8103 clientchar_t * hexp;
8105 hexp = cm_GetRawCharsAlloc(pathp, -1);
8106 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8107 osi_LogSaveClientString(smb_logp, hexp));
8111 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8113 return CM_ERROR_BADNTFILENAME;
8116 userp = smb_GetUserFromVCP(vcp, inp);
8118 caseFold = CM_FLAG_CASEFOLD;
8120 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8122 cm_ReleaseUser(userp);
8123 return CM_ERROR_NOSUCHPATH;
8125 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8126 userp, tidPathp, &req, &dscp);
8129 cm_ReleaseUser(userp);
8134 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8135 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8136 cm_ReleaseSCache(dscp);
8137 cm_ReleaseUser(userp);
8138 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8139 return CM_ERROR_PATH_NOT_COVERED;
8141 return CM_ERROR_NOSUCHPATH;
8143 #endif /* DFS_SUPPORT */
8145 /* otherwise, scp points to the parent directory. Do a lookup, and
8146 * truncate the file if we find it, otherwise we create the file.
8153 if (!smb_IsLegalFilename(lastNamep))
8154 return CM_ERROR_BADNTFILENAME;
8156 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8157 #ifdef DEBUG_VERBOSE
8160 hexp = osi_HexifyString( lastNamep );
8161 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8166 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8167 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8168 cm_ReleaseSCache(dscp);
8169 cm_ReleaseUser(userp);
8173 /* if we get here, if code is 0, the file exists and is represented by
8174 * scp. Otherwise, we have to create it.
8178 /* oops, file shouldn't be there */
8179 cm_ReleaseSCache(dscp);
8180 cm_ReleaseSCache(scp);
8181 cm_ReleaseUser(userp);
8182 return CM_ERROR_EXISTS;
8185 setAttr.mask = CM_ATTRMASK_LENGTH;
8186 setAttr.length.LowPart = 0;
8187 setAttr.length.HighPart = 0;
8188 code = cm_SetAttr(scp, &setAttr, userp, &req);
8191 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8192 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8193 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8197 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8198 smb_NotifyChange(FILE_ACTION_ADDED,
8199 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8200 dscp, lastNamep, NULL, TRUE);
8201 } else if (!excl && code == CM_ERROR_EXISTS) {
8202 /* not an exclusive create, and someone else tried
8203 * creating it already, then we open it anyway. We
8204 * don't bother retrying after this, since if this next
8205 * fails, that means that the file was deleted after
8206 * we started this call.
8208 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8211 setAttr.mask = CM_ATTRMASK_LENGTH;
8212 setAttr.length.LowPart = 0;
8213 setAttr.length.HighPart = 0;
8214 code = cm_SetAttr(scp, &setAttr, userp, &req);
8219 /* we don't need this any longer */
8220 cm_ReleaseSCache(dscp);
8223 /* something went wrong creating or truncating the file */
8224 if (scp) cm_ReleaseSCache(scp);
8225 cm_ReleaseUser(userp);
8229 /* make sure we only open files */
8230 if (scp->fileType != CM_SCACHETYPE_FILE) {
8231 cm_ReleaseSCache(scp);
8232 cm_ReleaseUser(userp);
8233 return CM_ERROR_ISDIR;
8236 /* now all we have to do is open the file itself */
8237 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8238 osi_assertx(fidp, "null smb_fid_t");
8242 lock_ObtainMutex(&fidp->mx);
8243 /* always create it open for read/write */
8244 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8246 /* remember that the file was newly created */
8248 fidp->flags |= SMB_FID_CREATED;
8250 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8252 /* save a pointer to the vnode */
8254 lock_ObtainWrite(&scp->rw);
8255 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8256 lock_ReleaseWrite(&scp->rw);
8259 fidp->userp = userp;
8260 lock_ReleaseMutex(&fidp->mx);
8262 smb_SetSMBParm(outp, 0, fidp->fid);
8263 smb_SetSMBDataLength(outp, 0);
8265 cm_Open(scp, 0, userp);
8267 smb_ReleaseFID(fidp);
8268 cm_ReleaseUser(userp);
8269 /* leave scp held since we put it in fidp->scp */
8274 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8277 osi_hyper_t new_offset;
8288 fd = smb_GetSMBParm(inp, 0);
8289 whence = smb_GetSMBParm(inp, 1);
8290 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8292 /* try to find the file descriptor */
8293 fd = smb_ChainFID(fd, inp);
8294 fidp = smb_FindFID(vcp, fd, 0);
8296 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8298 return CM_ERROR_BADFD;
8300 lock_ObtainMutex(&fidp->mx);
8301 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8302 lock_ReleaseMutex(&fidp->mx);
8303 smb_ReleaseFID(fidp);
8304 return CM_ERROR_BADFD;
8307 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8308 lock_ReleaseMutex(&fidp->mx);
8309 smb_CloseFID(vcp, fidp, NULL, 0);
8310 smb_ReleaseFID(fidp);
8311 return CM_ERROR_NOSUCHFILE;
8314 lock_ReleaseMutex(&fidp->mx);
8316 userp = smb_GetUserFromVCP(vcp, inp);
8318 lock_ObtainMutex(&fidp->mx);
8321 lock_ReleaseMutex(&fidp->mx);
8322 lock_ObtainWrite(&scp->rw);
8323 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8324 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8326 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8328 /* offset from current offset */
8329 new_offset = LargeIntegerAdd(fidp->offset,
8330 ConvertLongToLargeInteger(offset));
8332 else if (whence == 2) {
8333 /* offset from current EOF */
8334 new_offset = LargeIntegerAdd(scp->length,
8335 ConvertLongToLargeInteger(offset));
8337 new_offset = ConvertLongToLargeInteger(offset);
8340 fidp->offset = new_offset;
8341 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8342 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8343 smb_SetSMBDataLength(outp, 0);
8345 lock_ReleaseWrite(&scp->rw);
8346 smb_ReleaseFID(fidp);
8347 cm_ReleaseSCache(scp);
8348 cm_ReleaseUser(userp);
8352 /* dispatch all of the requests received in a packet. Due to chaining, this may
8353 * be more than one request.
8355 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8356 NCB *ncbp, raw_write_cont_t *rwcp)
8360 unsigned long code = 0;
8361 unsigned char *outWctp;
8362 int nparms; /* # of bytes of parameters */
8364 int nbytes; /* bytes of data, excluding count */
8367 unsigned short errCode;
8368 unsigned long NTStatus;
8370 unsigned char errClass;
8371 unsigned int oldGen;
8372 DWORD oldTime, newTime;
8374 /* get easy pointer to the data */
8375 smbp = (smb_t *) inp->data;
8377 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8378 /* setup the basic parms for the initial request in the packet */
8379 inp->inCom = smbp->com;
8380 inp->wctp = &smbp->wct;
8382 inp->ncb_length = ncbp->ncb_length;
8387 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8388 /* log it and discard it */
8389 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8390 __FILE__, __LINE__, ncbp->ncb_length);
8391 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8395 /* We are an ongoing op */
8396 thrd_Increment(&ongoingOps);
8398 /* set up response packet for receiving output */
8399 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8400 smb_FormatResponsePacket(vcp, inp, outp);
8401 outWctp = outp->wctp;
8403 /* Remember session generation number and time */
8404 oldGen = sessionGen;
8405 oldTime = GetTickCount();
8407 while (inp->inCom != 0xff) {
8408 dp = &smb_dispatchTable[inp->inCom];
8410 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8411 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8412 code = outp->resumeCode;
8416 /* process each request in the packet; inCom, wctp and inCount
8417 * are already set up.
8419 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8422 /* now do the dispatch */
8423 /* start by formatting the response record a little, as a default */
8424 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8426 outWctp[1] = 0xff; /* no operation */
8427 outWctp[2] = 0; /* padding */
8432 /* not a chained request, this is a more reasonable default */
8433 outWctp[0] = 0; /* wct of zero */
8434 outWctp[1] = 0; /* and bcc (word) of zero */
8438 /* once set, stays set. Doesn't matter, since we never chain
8439 * "no response" calls.
8441 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8445 /* we have a recognized operation */
8446 char * opName = myCrt_Dispatch(inp->inCom);
8449 smbp = (smb_t *) inp;
8451 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8452 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8453 if (inp->inCom == 0x1d) {
8455 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8457 code = (*(dp->procp)) (vcp, inp, outp);
8459 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8460 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8462 newTime = GetTickCount();
8463 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8464 opName, smbp->mid, newTime - oldTime);
8467 if ( code == CM_ERROR_BADSMB ||
8468 code == CM_ERROR_BADOP )
8470 #endif /* LOG_PACKET */
8472 /* ReceiveV3Tran2A handles its own logging */
8473 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8476 clientchar_t *treepath = NULL; /* do not free */
8477 clientchar_t *pathname = NULL;
8478 cm_fid_t afid = {0,0,0,0,0};
8480 uidp = smb_FindUID(vcp, smbp->uid, 0);
8481 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8482 fidp = smb_FindFID(vcp, inp->fid, 0);
8485 lock_ObtainMutex(&fidp->mx);
8486 if (fidp->NTopen_pathp)
8487 pathname = fidp->NTopen_pathp;
8489 afid = fidp->scp->fid;
8491 if (inp->stringsp->wdata)
8492 pathname = inp->stringsp->wdata;
8495 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)",
8496 opName, newTime - oldTime,
8497 smbp->uid, uidp ? uidp->unp->name : NULL,
8498 smbp->pid, smbp->mid, smbp->tid,
8501 afid.cell, afid.volume, afid.vnode, afid.unique);
8504 lock_ReleaseMutex(&fidp->mx);
8507 smb_ReleaseUID(uidp);
8509 smb_ReleaseFID(fidp);
8512 if (oldGen != sessionGen) {
8513 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8514 newTime - oldTime, ncbp->ncb_length);
8515 osi_Log3(smb_logp, "Request %s straddled session startup, "
8516 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8519 FreeSMBStrings(inp);
8521 /* bad opcode, fail the request, after displaying it */
8522 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8525 #endif /* LOG_PACKET */
8528 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8529 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8530 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8531 if (code == IDCANCEL)
8534 code = CM_ERROR_BADOP;
8537 /* catastrophic failure: log as much as possible */
8538 if (code == CM_ERROR_BADSMB) {
8539 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8543 #endif /* LOG_PACKET */
8544 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8547 code = CM_ERROR_INVAL;
8550 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8551 thrd_Decrement(&ongoingOps);
8556 /* now, if we failed, turn the current response into an empty
8557 * one, and fill in the response packet's error code.
8560 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8561 smb_MapNTError(code, &NTStatus);
8562 outWctp = outp->wctp;
8563 smbp = (smb_t *) &outp->data;
8564 if (code != CM_ERROR_PARTIALWRITE
8565 && code != CM_ERROR_BUFFERTOOSMALL
8566 && code != CM_ERROR_GSSCONTINUE) {
8567 /* nuke wct and bcc. For a partial
8568 * write or an in-process authentication handshake,
8569 * assume they're OK.
8575 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8576 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8577 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8578 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8579 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8583 smb_MapCoreError(code, vcp, &errCode, &errClass);
8584 outWctp = outp->wctp;
8585 smbp = (smb_t *) &outp->data;
8586 if (code != CM_ERROR_PARTIALWRITE) {
8587 /* nuke wct and bcc. For a partial
8588 * write, assume they're OK.
8594 smbp->errLow = (unsigned char) (errCode & 0xff);
8595 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8596 smbp->rcls = errClass;
8599 } /* error occurred */
8601 /* if we're here, we've finished one request. Look to see if
8602 * this is a chained opcode. If it is, setup things to process
8603 * the chained request, and setup the output buffer to hold the
8604 * chained response. Start by finding the next input record.
8606 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8607 break; /* not a chained req */
8608 tp = inp->wctp; /* points to start of last request */
8609 /* in a chained request, the first two
8610 * parm fields are required, and are
8611 * AndXCommand/AndXReserved and
8613 if (tp[0] < 2) break;
8614 if (tp[1] == 0xff) break; /* no more chained opcodes */
8616 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8619 /* and now append the next output request to the end of this
8620 * last request. Begin by finding out where the last response
8621 * ends, since that's where we'll put our new response.
8623 outWctp = outp->wctp; /* ptr to out parameters */
8624 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8625 nparms = outWctp[0] << 1;
8626 tp = outWctp + nparms + 1; /* now points to bcc field */
8627 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8628 tp += 2 /* for the count itself */ + nbytes;
8629 /* tp now points to the new output record; go back and patch the
8630 * second parameter (off2) to point to the new record.
8632 temp = (unsigned int)(tp - outp->data);
8633 outWctp[3] = (unsigned char) (temp & 0xff);
8634 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8635 outWctp[2] = 0; /* padding */
8636 outWctp[1] = inp->inCom; /* next opcode */
8638 /* finally, setup for the next iteration */
8641 } /* while loop over all requests in the packet */
8643 /* now send the output packet, and return */
8645 smb_SendPacket(vcp, outp);
8646 thrd_Decrement(&ongoingOps);
8651 /* Wait for Netbios() calls to return, and make the results available to server
8652 * threads. Note that server threads can't wait on the NCBevents array
8653 * themselves, because NCB events are manual-reset, and the servers would race
8654 * each other to reset them.
8656 void smb_ClientWaiter(void *parmp)
8661 while (smbShutdownFlag == 0) {
8662 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8664 if (code == WAIT_OBJECT_0)
8667 /* error checking */
8668 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8670 int abandonIdx = code - WAIT_ABANDONED_0;
8671 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8674 if (code == WAIT_IO_COMPLETION)
8676 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8680 if (code == WAIT_TIMEOUT)
8682 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8685 if (code == WAIT_FAILED)
8687 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8690 idx = code - WAIT_OBJECT_0;
8692 /* check idx range! */
8693 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8695 /* this is fatal - log as much as possible */
8696 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8697 osi_assertx(0, "invalid index");
8700 thrd_ResetEvent(NCBevents[idx]);
8701 thrd_SetEvent(NCBreturns[0][idx]);
8706 * Try to have one NCBRECV request waiting for every live session. Not more
8707 * than one, because if there is more than one, it's hard to handle Write Raw.
8709 void smb_ServerWaiter(void *parmp)
8712 int idx_session, idx_NCB;
8715 while (smbShutdownFlag == 0) {
8717 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8719 if (code == WAIT_OBJECT_0)
8722 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8724 int abandonIdx = code - WAIT_ABANDONED_0;
8725 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8728 if (code == WAIT_IO_COMPLETION)
8730 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8734 if (code == WAIT_TIMEOUT)
8736 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8739 if (code == WAIT_FAILED)
8741 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8744 idx_session = code - WAIT_OBJECT_0;
8746 /* check idx range! */
8747 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8749 /* this is fatal - log as much as possible */
8750 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8751 osi_assertx(0, "invalid index");
8756 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8758 if (code == WAIT_OBJECT_0) {
8759 if (smbShutdownFlag == 1)
8765 /* error checking */
8766 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8768 int abandonIdx = code - WAIT_ABANDONED_0;
8769 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8772 if (code == WAIT_IO_COMPLETION)
8774 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8778 if (code == WAIT_TIMEOUT)
8780 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8783 if (code == WAIT_FAILED)
8785 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8788 idx_NCB = code - WAIT_OBJECT_0;
8790 /* check idx range! */
8791 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8793 /* this is fatal - log as much as possible */
8794 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8795 osi_assertx(0, "invalid index");
8798 /* Link them together */
8799 NCBsessions[idx_NCB] = idx_session;
8802 ncbp = NCBs[idx_NCB];
8803 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8804 ncbp->ncb_command = NCBRECV | ASYNCH;
8805 ncbp->ncb_lana_num = lanas[idx_session];
8806 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8807 ncbp->ncb_event = NCBevents[idx_NCB];
8808 ncbp->ncb_length = SMB_PACKETSIZE;
8814 * The top level loop for handling SMB request messages. Each server thread
8815 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8816 * NCB and buffer for the incoming request are loaned to us.
8818 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8819 * to immediately send a request for the rest of the data. This must come
8820 * before any other traffic for that session, so we delay setting the session
8821 * event until that data has come in.
8823 void smb_Server(VOID *parmp)
8825 INT_PTR myIdx = (INT_PTR) parmp;
8829 smb_packet_t *outbufp;
8831 int idx_NCB, idx_session;
8833 smb_vc_t *vcp = NULL;
8835 extern void rx_StartClientThread(void);
8837 rx_StartClientThread();
8839 outncbp = smb_GetNCB();
8840 outbufp = smb_GetPacket();
8841 outbufp->ncbp = outncbp;
8849 cm_ResetServerPriority();
8851 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8854 /* terminate silently if shutdown flag is set */
8855 if (code == WAIT_OBJECT_0) {
8856 if (smbShutdownFlag == 1) {
8857 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8863 /* error checking */
8864 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8866 int abandonIdx = code - WAIT_ABANDONED_0;
8867 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8870 if (code == WAIT_IO_COMPLETION)
8872 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8876 if (code == WAIT_TIMEOUT)
8878 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8881 if (code == WAIT_FAILED)
8883 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8886 idx_NCB = code - WAIT_OBJECT_0;
8888 /* check idx range! */
8889 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8891 /* this is fatal - log as much as possible */
8892 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8893 osi_assertx(0, "invalid index");
8896 ncbp = NCBs[idx_NCB];
8897 idx_session = NCBsessions[idx_NCB];
8898 rc = ncbp->ncb_retcode;
8900 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8901 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8905 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8909 /* Can this happen? Or is it just my UNIX paranoia? */
8910 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8915 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8918 /* Client closed session */
8919 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8921 lock_ObtainMutex(&vcp->mx);
8922 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8923 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8925 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8926 lock_ReleaseMutex(&vcp->mx);
8927 lock_ObtainWrite(&smb_globalLock);
8928 dead_sessions[vcp->session] = TRUE;
8929 lock_ReleaseWrite(&smb_globalLock);
8931 lock_ReleaseMutex(&vcp->mx);
8933 smb_CleanupDeadVC(vcp);
8940 /* Treat as transient error */
8941 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8944 "dispatch smb recv failed, message incomplete, ncb_length %d",
8947 "SMB message incomplete, "
8948 "length %d", ncbp->ncb_length);
8951 * We used to discard the packet.
8952 * Instead, try handling it normally.
8956 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8960 /* A weird error code. Log it, sleep, and continue. */
8961 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8963 lock_ObtainMutex(&vcp->mx);
8964 if (vcp->errorCount++ > 3) {
8965 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8966 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8967 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8969 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8970 lock_ReleaseMutex(&vcp->mx);
8971 lock_ObtainWrite(&smb_globalLock);
8972 dead_sessions[vcp->session] = TRUE;
8973 lock_ReleaseWrite(&smb_globalLock);
8975 lock_ReleaseMutex(&vcp->mx);
8977 smb_CleanupDeadVC(vcp);
8983 lock_ReleaseMutex(&vcp->mx);
8987 thrd_SetEvent(SessionEvents[idx_session]);
8993 /* Success, so now dispatch on all the data in the packet */
8995 smb_concurrentCalls++;
8996 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8997 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9000 * If at this point vcp is NULL (implies that packet was invalid)
9001 * then we are in big trouble. This means either :
9002 * a) we have the wrong NCB.
9003 * b) Netbios screwed up the call.
9004 * c) The VC was already marked dead before we were able to
9006 * Obviously this implies that
9007 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9008 * lanas[idx_session] != ncbp->ncb_lana_num )
9009 * Either way, we can't do anything with this packet.
9010 * Log, sleep and resume.
9013 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9017 ncbp->ncb_lana_num);
9019 /* Also log in the trace log. */
9020 osi_Log4(smb_logp, "Server: VCP does not exist!"
9021 "LSNs[idx_session]=[%d],"
9022 "lanas[idx_session]=[%d],"
9023 "ncbp->ncb_lsn=[%d],"
9024 "ncbp->ncb_lana_num=[%d]",
9028 ncbp->ncb_lana_num);
9030 /* thrd_Sleep(1000); Don't bother sleeping */
9031 thrd_SetEvent(SessionEvents[idx_session]);
9032 smb_concurrentCalls--;
9036 cm_SetRequestStartTime();
9038 vcp->errorCount = 0;
9039 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9040 smbp = (smb_t *)bufp->data;
9047 if (smbp->com == 0x1d) {
9048 /* Special handling for Write Raw */
9049 raw_write_cont_t rwc;
9051 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9052 if (rwc.code == 0) {
9053 EVENT_HANDLE rwevent;
9054 char eventName[MAX_PATH];
9056 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9057 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9058 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9059 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9061 ncbp->ncb_command = NCBRECV | ASYNCH;
9062 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9063 ncbp->ncb_lana_num = vcp->lana;
9064 ncbp->ncb_buffer = rwc.buf;
9065 ncbp->ncb_length = 65535;
9066 ncbp->ncb_event = rwevent;
9068 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9069 thrd_CloseHandle(rwevent);
9071 thrd_SetEvent(SessionEvents[idx_session]);
9073 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9075 else if (smbp->com == 0xa0) {
9077 * Serialize the handling for NT Transact
9080 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9081 thrd_SetEvent(SessionEvents[idx_session]);
9083 thrd_SetEvent(SessionEvents[idx_session]);
9084 /* TODO: what else needs to be serialized? */
9085 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9089 __except( smb_ServerExceptionFilter() ) {
9093 smb_concurrentCalls--;
9096 thrd_SetEvent(NCBavails[idx_NCB]);
9101 smb_FreePacket(outbufp);
9103 smb_FreeNCB(outncbp);
9107 * Exception filter for the server threads. If an exception occurs in the
9108 * dispatch routines, which is where exceptions are most common, then do a
9109 * force trace and give control to upstream exception handlers. Useful for
9112 DWORD smb_ServerExceptionFilter(void) {
9113 /* While this is not the best time to do a trace, if it succeeds, then
9114 * we have a trace (assuming tracing was enabled). Otherwise, this should
9115 * throw a second exception.
9117 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9118 afsd_ForceTrace(TRUE);
9119 buf_ForceTrace(TRUE);
9120 return EXCEPTION_CONTINUE_SEARCH;
9124 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9125 * If the number of server threads is M, and the number of live sessions is
9126 * N, then the number of NCB's in use at any time either waiting for, or
9127 * holding, received messages is M + N, so that is how many NCB's get created.
9129 void InitNCBslot(int idx)
9131 struct smb_packet *bufp;
9132 EVENT_HANDLE retHandle;
9134 char eventName[MAX_PATH];
9136 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9138 NCBs[idx] = smb_GetNCB();
9139 sprintf(eventName,"NCBavails[%d]", idx);
9140 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9141 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9142 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9143 sprintf(eventName,"NCBevents[%d]", idx);
9144 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9145 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9146 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9147 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9148 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9149 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9150 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9151 for (i=0; i<smb_NumServerThreads; i++)
9152 NCBreturns[i][idx] = retHandle;
9153 bufp = smb_GetPacket();
9154 bufp->spacep = cm_GetSpace();
9158 /* listen for new connections */
9159 void smb_Listener(void *parmp)
9165 afs_uint32 session, thread;
9166 smb_vc_t *vcp = NULL;
9168 char rname[NCBNAMSZ+1];
9169 char cname[MAX_COMPUTERNAME_LENGTH+1];
9170 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9171 INT_PTR lana = (INT_PTR) parmp;
9172 char eventName[MAX_PATH];
9173 int bridgeCount = 0;
9174 int nowildCount = 0;
9176 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9177 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9178 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9179 thrd_ResetEvent(ListenerShutdown[lana]);
9181 ncbp = smb_GetNCB();
9183 /* retrieve computer name */
9184 GetComputerName(cname, &cnamelen);
9187 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9188 memset(ncbp, 0, sizeof(NCB));
9191 ncbp->ncb_command = NCBLISTEN;
9192 ncbp->ncb_rto = 0; /* No receive timeout */
9193 ncbp->ncb_sto = 0; /* No send timeout */
9195 /* pad out with spaces instead of null termination */
9196 len = (long)strlen(smb_localNamep);
9197 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9198 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9200 strcpy(ncbp->ncb_callname, "*");
9201 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9203 ncbp->ncb_lana_num = (UCHAR)lana;
9205 code = Netbios(ncbp);
9207 if (code == NRC_NAMERR) {
9208 /* An smb shutdown or Vista resume must have taken place */
9210 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9211 ncbp->ncb_lana_num);
9212 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9214 if (lock_TryMutex(&smb_StartedLock)) {
9215 lana_list.lana[i] = LANA_INVALID;
9216 lock_ReleaseMutex(&smb_StartedLock);
9219 } else if (code == NRC_BRIDGE || code != 0) {
9220 int lanaRemaining = 0;
9222 if (code == NRC_BRIDGE) {
9223 if (++bridgeCount <= 5) {
9224 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9227 } else if (code == NRC_NOWILD) {
9228 if (++nowildCount <= 5) {
9229 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9231 if (bridgeCount > 0) {
9232 memset(ncbp, 0, sizeof(*ncbp));
9233 ncbp->ncb_command = NCBADDNAME;
9234 ncbp->ncb_lana_num = (UCHAR)lana;
9235 /* pad out with spaces instead of null termination */
9236 len = (long)strlen(smb_localNamep);
9237 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9238 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9239 code = Netbios(ncbp);
9245 while (!lock_TryMutex(&smb_StartedLock)) {
9246 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9252 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9253 ncbp->ncb_lana_num, ncb_error_string(code));
9254 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9255 ncbp->ncb_lana_num, ncb_error_string(code));
9257 for (i = 0; i < lana_list.length; i++) {
9258 if (lana_list.lana[i] == lana) {
9259 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9260 lana_list.lana[i] = LANA_INVALID;
9262 if (lana_list.lana[i] != LANA_INVALID)
9266 if (lanaRemaining == 0) {
9267 cm_VolStatus_Network_Stopped(cm_NetbiosName
9272 smb_ListenerState = SMB_LISTENER_STOPPED;
9273 smb_LANadapter = LANA_INVALID;
9274 lana_list.length = 0;
9276 lock_ReleaseMutex(&smb_StartedLock);
9280 else if (code != 0) {
9281 char tbuffer[AFSPATHMAX];
9283 /* terminate silently if shutdown flag is set */
9284 while (!lock_TryMutex(&smb_StartedLock)) {
9285 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9291 "NCBLISTEN lana=%d failed with code %d [%s]",
9292 ncbp->ncb_lana_num, code, ncb_error_string(code));
9294 "Client exiting due to network failure. Please restart client.\n");
9297 "Client exiting due to network failure. Please restart client.\n"
9298 "NCBLISTEN lana=%d failed with code %d [%s]",
9299 ncbp->ncb_lana_num, code, ncb_error_string(code));
9301 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9302 MB_OK|MB_SERVICE_NOTIFICATION);
9303 osi_panic(tbuffer, __FILE__, __LINE__);
9305 lock_ReleaseMutex(&smb_StartedLock);
9310 /* a successful packet received. clear bridge error count */
9314 /* check for remote conns */
9315 /* first get remote name and insert null terminator */
9316 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9317 for (i=NCBNAMSZ; i>0; i--) {
9318 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9324 /* compare with local name */
9326 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9327 flags |= SMB_VCFLAG_REMOTECONN;
9330 lock_ObtainMutex(&smb_ListenerLock);
9332 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9333 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9335 /* now ncbp->ncb_lsn is the connection ID */
9336 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9337 if (vcp->session == 0) {
9338 /* New generation */
9339 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9342 /* Log session startup */
9344 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9345 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9346 #endif /* NOTSERVICE */
9347 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9348 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9350 if (reportSessionStartups) {
9351 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9354 lock_ObtainMutex(&vcp->mx);
9355 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9356 vcp->flags |= flags;
9357 lock_ReleaseMutex(&vcp->mx);
9359 /* Allocate slot in session arrays */
9360 /* Re-use dead session if possible, otherwise add one more */
9361 /* But don't look at session[0], it is reserved */
9362 lock_ObtainWrite(&smb_globalLock);
9363 for (session = 1; session < numSessions; session++) {
9364 if (dead_sessions[session]) {
9365 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9366 dead_sessions[session] = FALSE;
9370 lock_ReleaseWrite(&smb_globalLock);
9372 /* We are re-using an existing VC because the lsn and lana
9374 session = vcp->session;
9376 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9378 /* Log session startup */
9380 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9381 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9382 #endif /* NOTSERVICE */
9383 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9384 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9386 if (reportSessionStartups) {
9387 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9391 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9392 unsigned long code = CM_ERROR_ALLBUSY;
9393 smb_packet_t * outp = smb_GetPacket();
9394 unsigned char *outWctp;
9397 smb_FormatResponsePacket(vcp, NULL, outp);
9400 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9401 unsigned long NTStatus;
9402 smb_MapNTError(code, &NTStatus);
9403 outWctp = outp->wctp;
9404 smbp = (smb_t *) &outp->data;
9408 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9409 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9410 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9411 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9412 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9414 unsigned short errCode;
9415 unsigned char errClass;
9416 smb_MapCoreError(code, vcp, &errCode, &errClass);
9417 outWctp = outp->wctp;
9418 smbp = (smb_t *) &outp->data;
9422 smbp->errLow = (unsigned char) (errCode & 0xff);
9423 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9424 smbp->rcls = errClass;
9427 smb_SendPacket(vcp, outp);
9428 smb_FreePacket(outp);
9430 lock_ObtainMutex(&vcp->mx);
9431 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9432 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9434 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9435 lock_ReleaseMutex(&vcp->mx);
9436 lock_ObtainWrite(&smb_globalLock);
9437 dead_sessions[vcp->session] = TRUE;
9438 lock_ReleaseWrite(&smb_globalLock);
9439 smb_CleanupDeadVC(vcp);
9441 lock_ReleaseMutex(&vcp->mx);
9444 /* assert that we do not exceed the maximum number of sessions or NCBs.
9445 * we should probably want to wait for a session to be freed in case
9448 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9449 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9451 lock_ObtainMutex(&vcp->mx);
9452 vcp->session = session;
9453 lock_ReleaseMutex(&vcp->mx);
9454 lock_ObtainWrite(&smb_globalLock);
9455 LSNs[session] = ncbp->ncb_lsn;
9456 lanas[session] = ncbp->ncb_lana_num;
9457 lock_ReleaseWrite(&smb_globalLock);
9459 if (session == numSessions) {
9460 /* Add new NCB for new session */
9461 char eventName[MAX_PATH];
9463 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9465 InitNCBslot(numNCBs);
9466 lock_ObtainWrite(&smb_globalLock);
9468 lock_ReleaseWrite(&smb_globalLock);
9469 thrd_SetEvent(NCBavails[0]);
9470 thrd_SetEvent(NCBevents[0]);
9471 for (thread = 0; thread < smb_NumServerThreads; thread++)
9472 thrd_SetEvent(NCBreturns[thread][0]);
9473 /* Also add new session event */
9474 sprintf(eventName, "SessionEvents[%d]", session);
9475 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9476 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9477 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9478 lock_ObtainWrite(&smb_globalLock);
9480 lock_ReleaseWrite(&smb_globalLock);
9481 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9482 thrd_SetEvent(SessionEvents[0]);
9484 thrd_SetEvent(SessionEvents[session]);
9490 lock_ReleaseMutex(&smb_ListenerLock);
9491 } /* dispatch while loop */
9495 thrd_SetEvent(ListenerShutdown[lana]);
9500 configureBackConnectionHostNames(void)
9502 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9503 * there is a restriction on the use of SMB authentication on loopback connections.
9504 * There are two work arounds available:
9506 * (1) We can disable the check for matching host names. This does not
9508 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9509 * "DisableLoopbackCheck"=dword:00000001
9511 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9512 * does require a reboot:
9513 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9514 * "BackConnectionHostNames"=multi-sz
9516 * The algorithm will be:
9517 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9518 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9519 * (2b1) and check to see if DisableLoopbackCheck is set.
9520 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9521 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9522 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9523 * check for the UnsetDisableLoopbackCheck value.
9524 * If set, set the DisableLoopbackCheck flag to 0x0
9525 * and delete the UnsetDisableLoopbackCheck value
9527 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9528 * force Windows to use the loopback authentication mechanism for the specified
9531 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9532 * service session that set it.
9538 DWORD dwSize, dwAllocSize;
9540 PBYTE pHostNames = NULL, pName = NULL;
9541 BOOL bNameFound = FALSE;
9542 static BOOL bLoopbackCheckDisabled = FALSE;
9544 /* BackConnectionHostNames and DisableLoopbackCheck */
9545 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9546 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9549 &hkMSV10) == ERROR_SUCCESS )
9551 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9552 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9553 (dwType == REG_MULTI_SZ))
9555 dwAllocSize += 1 /* in case the source string is not nul terminated */
9556 + (DWORD)strlen(cm_NetbiosName) + 2;
9557 pHostNames = malloc(dwAllocSize);
9558 dwSize = dwAllocSize;
9559 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9560 pHostNames, &dwSize) == ERROR_SUCCESS)
9562 for (pName = pHostNames;
9563 (pName - pHostNames < (int) dwSize) && *pName ;
9564 pName += strlen(pName) + 1)
9566 if ( !stricmp(pName, cm_NetbiosName) ) {
9574 if ( !bNameFound ) {
9575 size_t size = strlen(cm_NetbiosName) + 2;
9576 if ( !pHostNames ) {
9577 pHostNames = malloc(size);
9580 StringCbCopyA(pName, size, cm_NetbiosName);
9582 *pName = '\0'; /* add a second nul terminator */
9584 dwType = REG_MULTI_SZ;
9585 dwSize = (DWORD)(pName - pHostNames + 1);
9586 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9588 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9589 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9592 &hkLsa) == ERROR_SUCCESS )
9594 dwSize = sizeof(DWORD);
9595 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9598 dwSize = sizeof(DWORD);
9600 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9602 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9603 AFSREG_CLT_OPENAFS_SUBKEY,
9606 REG_OPTION_NON_VOLATILE,
9610 NULL) == ERROR_SUCCESS) {
9613 dwSize = sizeof(DWORD);
9615 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9616 bLoopbackCheckDisabled = TRUE;
9617 RegCloseKey(hkClient);
9622 } else if (!bLoopbackCheckDisabled) {
9623 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9624 AFSREG_CLT_OPENAFS_SUBKEY,
9627 REG_OPTION_NON_VOLATILE,
9631 NULL) == ERROR_SUCCESS) {
9633 dwSize = sizeof(DWORD);
9634 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9636 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9637 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9640 &hkLsa) == ERROR_SUCCESS )
9642 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9646 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9647 RegCloseKey(hkClient);
9656 RegCloseKey(hkMSV10);
9662 configureExtendedSMBSessionTimeouts(void)
9665 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9666 * new functionality:
9668 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9669 * "ReconnectableServers" REG_MULTI_SZ
9670 * "ExtendedSessTimeout" REG_DWORD (seconds)
9671 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
9673 * These values can be used to prevent the smb redirector from timing out
9674 * smb connection to the afs smb server prematurely.
9678 DWORD dwSize, dwAllocSize;
9680 PBYTE pHostNames = NULL, pName = NULL;
9681 BOOL bNameFound = FALSE;
9683 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9684 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9687 &hkLanMan) == ERROR_SUCCESS )
9689 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
9690 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9691 (dwType == REG_MULTI_SZ))
9693 dwAllocSize += 1 /* in case the source string is not nul terminated */
9694 + (DWORD)strlen(cm_NetbiosName) + 2;
9695 pHostNames = malloc(dwAllocSize);
9696 dwSize = dwAllocSize;
9697 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
9698 pHostNames, &dwSize) == ERROR_SUCCESS)
9700 for (pName = pHostNames;
9701 (pName - pHostNames < (int) dwSize) && *pName ;
9702 pName += strlen(pName) + 1)
9704 if ( !stricmp(pName, cm_NetbiosName) ) {
9712 if ( !bNameFound ) {
9713 size_t size = strlen(cm_NetbiosName) + 2;
9714 if ( !pHostNames ) {
9715 pHostNames = malloc(size);
9718 StringCbCopyA(pName, size, cm_NetbiosName);
9720 *pName = '\0'; /* add a second nul terminator */
9722 dwType = REG_MULTI_SZ;
9723 dwSize = (DWORD)(pName - pHostNames + 1);
9724 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9732 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
9733 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9734 (dwType == REG_MULTI_SZ))
9736 dwAllocSize += 1 /* in case the source string is not nul terminated */
9737 + (DWORD)strlen(cm_NetbiosName) + 2;
9738 pHostNames = malloc(dwAllocSize);
9739 dwSize = dwAllocSize;
9740 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
9741 pHostNames, &dwSize) == ERROR_SUCCESS)
9743 for (pName = pHostNames;
9744 (pName - pHostNames < (int) dwSize) && *pName ;
9745 pName += strlen(pName) + 1)
9747 if ( !stricmp(pName, cm_NetbiosName) ) {
9755 if ( !bNameFound ) {
9756 size_t size = strlen(cm_NetbiosName) + 2;
9757 if ( !pHostNames ) {
9758 pHostNames = malloc(size);
9761 StringCbCopyA(pName, size, cm_NetbiosName);
9763 *pName = '\0'; /* add a second nul terminator */
9765 dwType = REG_MULTI_SZ;
9766 dwSize = (DWORD)(pName - pHostNames + 1);
9767 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9775 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
9776 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9777 (dwType != REG_DWORD))
9780 dwSize = sizeof(dwValue);
9781 dwValue = 300; /* 5 minutes */
9782 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9784 RegCloseKey(hkLanMan);
9789 smb_LanAdapterChangeThread(void *param)
9792 * Give the IPAddrDaemon thread a chance
9793 * to block before we trigger.
9796 smb_LanAdapterChange(0);
9799 void smb_SetLanAdapterChangeDetected(void)
9804 lock_ObtainMutex(&smb_StartedLock);
9806 if (!powerStateSuspended) {
9807 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9808 NULL, 0, &lpid, "smb_LanAdapterChange");
9809 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9810 thrd_CloseHandle(phandle);
9813 smb_LanAdapterChangeDetected = 1;
9814 lock_ReleaseMutex(&smb_StartedLock);
9817 void smb_LanAdapterChange(int locked) {
9818 lana_number_t lanaNum;
9820 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9822 LANA_ENUM temp_list;
9827 afsi_log("smb_LanAdapterChange");
9830 lock_ObtainMutex(&smb_StartedLock);
9832 smb_LanAdapterChangeDetected = 0;
9834 if (!powerStateSuspended &&
9835 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9836 LANA_NETBIOS_NAME_FULL)) &&
9837 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9838 if ( isGateway != bGateway ) {
9839 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9840 smb_LANadapter, lanaNum, isGateway, bGateway);
9842 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9843 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9844 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9847 NCB *ncbp = smb_GetNCB();
9848 ncbp->ncb_command = NCBENUM;
9849 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9850 ncbp->ncb_length = sizeof(temp_list);
9851 code = Netbios(ncbp);
9853 if (temp_list.length != lana_list.length) {
9854 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9855 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9858 for (i=0; i<lana_list.length; i++) {
9859 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9860 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9861 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9873 smb_StopListeners(1);
9874 smb_RestartListeners(1);
9877 lock_ReleaseMutex(&smb_StartedLock);
9880 /* initialize Netbios */
9881 int smb_NetbiosInit(int locked)
9884 int i, lana, code, l;
9886 int delname_tried=0;
9889 lana_number_t lanaNum;
9892 lock_ObtainMutex(&smb_StartedLock);
9894 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9895 smb_ListenerState != SMB_LISTENER_STOPPED) {
9898 lock_ReleaseMutex(&smb_StartedLock);
9901 /* setup the NCB system */
9902 ncbp = smb_GetNCB();
9904 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9905 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9906 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9908 if (smb_LANadapter != LANA_INVALID)
9909 afsi_log("LAN adapter number %d", smb_LANadapter);
9911 afsi_log("LAN adapter number not determined");
9914 afsi_log("Set for gateway service");
9916 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9918 /* something went horribly wrong. We can't proceed without a netbios name */
9920 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9921 osi_panic(buf, __FILE__, __LINE__);
9924 /* remember the name */
9925 len = (int)strlen(cm_NetbiosName);
9927 free(smb_localNamep);
9928 smb_localNamep = malloc(len+1);
9929 strcpy(smb_localNamep, cm_NetbiosName);
9930 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9932 /* Also copy the value to the client character encoded string */
9933 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9935 if (smb_LANadapter == LANA_INVALID) {
9936 ncbp->ncb_command = NCBENUM;
9937 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9938 ncbp->ncb_length = sizeof(lana_list);
9939 code = Netbios(ncbp);
9941 afsi_log("Netbios NCBENUM error code %d", code);
9942 osi_panic(s, __FILE__, __LINE__);
9946 lana_list.length = 1;
9947 lana_list.lana[0] = smb_LANadapter;
9950 for (i = 0; i < lana_list.length; i++) {
9951 /* reset the adaptor: in Win32, this is required for every process, and
9952 * acts as an init call, not as a real hardware reset.
9954 ncbp->ncb_command = NCBRESET;
9955 ncbp->ncb_callname[0] = 100;
9956 ncbp->ncb_callname[2] = 100;
9957 ncbp->ncb_lana_num = lana_list.lana[i];
9958 code = Netbios(ncbp);
9960 code = ncbp->ncb_retcode;
9962 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9963 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9965 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9969 /* and declare our name so we can receive connections */
9970 memset(ncbp, 0, sizeof(*ncbp));
9971 len=lstrlen(smb_localNamep);
9972 memset(smb_sharename,' ',NCBNAMSZ);
9973 memcpy(smb_sharename,smb_localNamep,len);
9974 afsi_log("lana_list.length %d", lana_list.length);
9976 /* Keep the name so we can unregister it later */
9977 for (l = 0; l < lana_list.length; l++) {
9978 lana = lana_list.lana[l];
9980 ncbp->ncb_command = NCBADDNAME;
9981 ncbp->ncb_lana_num = lana;
9982 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9983 code = Netbios(ncbp);
9985 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9986 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9988 char name[NCBNAMSZ+1];
9990 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9991 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9995 code = ncbp->ncb_retcode;
9998 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10001 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10002 if (code == NRC_BRIDGE) { /* invalid LANA num */
10003 lana_list.lana[l] = LANA_INVALID;
10006 else if (code == NRC_DUPNAME) {
10007 afsi_log("Name already exists; try to delete it");
10008 memset(ncbp, 0, sizeof(*ncbp));
10009 ncbp->ncb_command = NCBDELNAME;
10010 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10011 ncbp->ncb_lana_num = lana;
10012 code = Netbios(ncbp);
10014 code = ncbp->ncb_retcode;
10016 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10018 if (code != 0 || delname_tried) {
10019 lana_list.lana[l] = LANA_INVALID;
10021 else if (code == 0) {
10022 if (!delname_tried) {
10030 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10031 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10035 smb_LANadapter = lana;
10036 lana_found = 1; /* at least one worked */
10040 osi_assertx(lana_list.length >= 0, "empty lana list");
10042 afsi_log("No valid LANA numbers found!");
10043 lana_list.length = 0;
10044 smb_LANadapter = LANA_INVALID;
10045 smb_ListenerState = SMB_LISTENER_STOPPED;
10046 cm_VolStatus_Network_Stopped(cm_NetbiosName
10053 /* we're done with the NCB now */
10056 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10057 if (lana_list.length > 0)
10058 osi_assert(smb_LANadapter != LANA_INVALID);
10061 lock_ReleaseMutex(&smb_StartedLock);
10063 return (lana_list.length > 0 ? 1 : 0);
10066 void smb_StartListeners(int locked)
10073 lock_ObtainMutex(&smb_StartedLock);
10075 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10077 lock_ReleaseMutex(&smb_StartedLock);
10081 afsi_log("smb_StartListeners");
10082 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10083 configureBackConnectionHostNames();
10085 /* Configure Extended SMB Session Timeouts */
10086 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10087 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10088 configureExtendedSMBSessionTimeouts();
10091 smb_ListenerState = SMB_LISTENER_STARTED;
10092 cm_VolStatus_Network_Started(cm_NetbiosName
10098 for (i = 0; i < lana_list.length; i++) {
10099 if (lana_list.lana[i] == LANA_INVALID)
10101 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10102 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10103 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10104 thrd_CloseHandle(phandle);
10107 lock_ReleaseMutex(&smb_StartedLock);
10110 void smb_RestartListeners(int locked)
10113 lock_ObtainMutex(&smb_StartedLock);
10115 if (powerStateSuspended)
10116 afsi_log("smb_RestartListeners called while suspended");
10118 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10119 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10120 if (smb_NetbiosInit(1))
10121 smb_StartListeners(1);
10122 } else if (smb_LanAdapterChangeDetected) {
10123 smb_LanAdapterChange(1);
10127 lock_ReleaseMutex(&smb_StartedLock);
10130 void smb_StopListener(NCB *ncbp, int lana, int wait)
10134 memset(ncbp, 0, sizeof(*ncbp));
10135 ncbp->ncb_command = NCBDELNAME;
10136 ncbp->ncb_lana_num = lana;
10137 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10138 code = Netbios(ncbp);
10140 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10141 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10143 /* and then reset the LANA; this will cause the listener threads to exit */
10144 ncbp->ncb_command = NCBRESET;
10145 ncbp->ncb_callname[0] = 100;
10146 ncbp->ncb_callname[2] = 100;
10147 ncbp->ncb_lana_num = lana;
10148 code = Netbios(ncbp);
10150 code = ncbp->ncb_retcode;
10152 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10154 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10158 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10161 void smb_StopListeners(int locked)
10167 lock_ObtainMutex(&smb_StartedLock);
10169 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10171 lock_ReleaseMutex(&smb_StartedLock);
10175 afsi_log("smb_StopListeners");
10176 smb_ListenerState = SMB_LISTENER_STOPPED;
10177 cm_VolStatus_Network_Stopped(cm_NetbiosName
10183 ncbp = smb_GetNCB();
10185 /* Unregister the SMB name */
10186 for (l = 0; l < lana_list.length; l++) {
10187 lana = lana_list.lana[l];
10189 if (lana != LANA_INVALID) {
10190 smb_StopListener(ncbp, lana, TRUE);
10192 /* mark the adapter invalid */
10193 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10197 /* force a re-evaluation of the network adapters */
10198 lana_list.length = 0;
10199 smb_LANadapter = LANA_INVALID;
10202 lock_ReleaseMutex(&smb_StartedLock);
10205 void smb_Init(osi_log_t *logp, int useV3,
10215 EVENT_HANDLE retHandle;
10216 char eventName[MAX_PATH];
10217 int startListeners = 0;
10219 smb_MBfunc = aMBfunc;
10223 /* Initialize smb_localZero */
10224 myTime.tm_isdst = -1; /* compute whether on DST or not */
10225 myTime.tm_year = 70;
10227 myTime.tm_mday = 1;
10228 myTime.tm_hour = 0;
10231 smb_localZero = mktime(&myTime);
10233 #ifdef AFS_FREELANCE_CLIENT
10234 /* Make sure the root.afs volume has the correct time */
10235 cm_noteLocalMountPointChange();
10238 /* initialize the remote debugging log */
10241 /* and the global lock */
10242 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10243 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10245 /* Raw I/O data structures */
10246 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10248 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10249 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10251 /* 4 Raw I/O buffers */
10252 smb_RawBufs = calloc(65536,1);
10253 *((char **)smb_RawBufs) = NULL;
10254 for (i=0; i<3; i++) {
10255 char *rawBuf = calloc(65536,1);
10256 *((char **)rawBuf) = smb_RawBufs;
10257 smb_RawBufs = rawBuf;
10260 /* global free lists */
10261 smb_ncbFreeListp = NULL;
10262 smb_packetFreeListp = NULL;
10264 lock_ObtainMutex(&smb_StartedLock);
10265 startListeners = smb_NetbiosInit(1);
10267 /* Initialize listener and server structures */
10269 memset(dead_sessions, 0, sizeof(dead_sessions));
10270 sprintf(eventName, "SessionEvents[0]");
10271 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10272 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10273 afsi_log("Event Object Already Exists: %s", eventName);
10275 smb_NumServerThreads = nThreads;
10276 sprintf(eventName, "NCBavails[0]");
10277 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10278 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10279 afsi_log("Event Object Already Exists: %s", eventName);
10280 sprintf(eventName, "NCBevents[0]");
10281 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10282 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10283 afsi_log("Event Object Already Exists: %s", eventName);
10284 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10285 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10286 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10287 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10288 afsi_log("Event Object Already Exists: %s", eventName);
10289 for (i = 0; i < smb_NumServerThreads; i++) {
10290 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10291 NCBreturns[i][0] = retHandle;
10294 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10295 for (i = 0; i < smb_NumServerThreads; i++) {
10296 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10297 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10298 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10299 afsi_log("Event Object Already Exists: %s", eventName);
10300 InitNCBslot((int)(i+1));
10302 numNCBs = smb_NumServerThreads + 1;
10304 /* Initialize dispatch table */
10305 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10306 /* Prepare the table for unknown operations */
10307 for(i=0; i<= SMB_NOPCODES; i++) {
10308 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10310 /* Fill in the ones we do know */
10311 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10312 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10313 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10314 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10315 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10316 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10317 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10318 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10319 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10320 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10321 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10322 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10323 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10324 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10325 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10326 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10327 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10328 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10329 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10330 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10331 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10332 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10333 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10334 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10335 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10336 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10337 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10338 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10339 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10340 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10341 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10342 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10343 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10344 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10345 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10346 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10347 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10348 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10349 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10350 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10351 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10352 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10353 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10354 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10355 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10356 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10357 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10358 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10359 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10360 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10361 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10362 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10363 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10364 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10365 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10366 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10367 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10368 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10369 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10370 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10371 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10372 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10373 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10374 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10375 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10376 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10377 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10378 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10379 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10380 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10381 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10382 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10383 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10384 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10386 /* setup tran 2 dispatch table */
10387 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10388 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10389 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10390 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10391 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10392 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10393 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10394 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10395 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10396 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10397 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10398 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10399 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10400 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10401 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10402 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10403 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10404 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10406 /* setup the rap dispatch table */
10407 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10408 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10409 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10410 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10411 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10415 /* if we are doing SMB authentication we have register outselves as a logon process */
10416 if (smb_authType != SMB_AUTH_NONE) {
10417 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10418 LSA_STRING afsProcessName;
10419 LSA_OPERATIONAL_MODE dummy; /*junk*/
10421 afsProcessName.Buffer = "OpenAFSClientDaemon";
10422 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10423 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10425 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10427 if (nts == STATUS_SUCCESS) {
10428 LSA_STRING packageName;
10429 /* we are registered. Find out the security package id */
10430 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10431 packageName.Length = (USHORT)strlen(packageName.Buffer);
10432 packageName.MaximumLength = packageName.Length + 1;
10433 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10434 if (nts == STATUS_SUCCESS) {
10436 * This code forces Windows to authenticate against the Logon Cache
10437 * first instead of attempting to authenticate against the Domain
10438 * Controller. When the Windows logon cache is enabled this improves
10439 * performance by removing the network access and works around a bug
10440 * seen at sites which are using a MIT Kerberos principal to login
10441 * to machines joined to a non-root domain in a multi-domain forest.
10442 * MsV1_0SetProcessOption was added in Windows XP.
10444 PVOID pResponse = NULL;
10445 ULONG cbResponse = 0;
10446 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10448 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10449 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10450 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10451 OptionsRequest.DisableOptions = FALSE;
10453 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10456 sizeof(OptionsRequest),
10462 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10463 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10466 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10468 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10469 afsi_log("MsV1_0SetProcessOption success");
10471 /* END - code from Larry */
10473 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10474 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10475 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10477 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10479 /* something went wrong. We report the error and revert back to no authentication
10480 because we can't perform any auth requests without a successful lsa handle
10481 or sec package id. */
10482 afsi_log("Reverting to NO SMB AUTH");
10483 smb_authType = SMB_AUTH_NONE;
10486 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10488 /* something went wrong. We report the error and revert back to no authentication
10489 because we can't perform any auth requests without a successful lsa handle
10490 or sec package id. */
10491 afsi_log("Reverting to NO SMB AUTH");
10492 smb_authType = SMB_AUTH_NONE;
10496 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10497 * time prevents the failure of authentication when logged into Windows with an
10498 * external Kerberos principal mapped to a local account.
10500 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10501 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10502 * then the only option is NTLMSSP anyway; so just fallback.
10507 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10508 if (secBlobLength == 0) {
10509 smb_authType = SMB_AUTH_NTLM;
10510 afsi_log("Reverting to SMB AUTH NTLM");
10519 /* Now get ourselves a domain name. */
10520 /* For now we are using the local computer name as the domain name.
10521 * It is actually the domain for local logins, and we are acting as
10522 * a local SMB server.
10524 bufsize = lengthof(smb_ServerDomainName) - 1;
10525 GetComputerNameW(smb_ServerDomainName, &bufsize);
10526 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10527 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10530 /* Start listeners, waiters, servers, and daemons */
10531 if (startListeners)
10532 smb_StartListeners(1);
10534 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10535 NULL, 0, &lpid, "smb_ClientWaiter");
10536 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10537 thrd_CloseHandle(phandle);
10539 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10540 NULL, 0, &lpid, "smb_ServerWaiter");
10541 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10542 thrd_CloseHandle(phandle);
10544 for (i=0; i<smb_NumServerThreads; i++) {
10545 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10546 (void *) i, 0, &lpid, "smb_Server");
10547 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10548 thrd_CloseHandle(phandle);
10551 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10552 NULL, 0, &lpid, "smb_Daemon");
10553 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10554 thrd_CloseHandle(phandle);
10556 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10557 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10558 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10559 thrd_CloseHandle(phandle);
10561 lock_ReleaseMutex(&smb_StartedLock);
10565 void smb_Shutdown(void)
10572 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10574 /* setup the NCB system */
10575 ncbp = smb_GetNCB();
10577 /* Block new sessions by setting shutdown flag */
10578 smbShutdownFlag = 1;
10580 /* Hang up all sessions */
10581 memset((char *)ncbp, 0, sizeof(NCB));
10582 for (i = 1; i < numSessions; i++)
10584 if (dead_sessions[i])
10587 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10588 ncbp->ncb_command = NCBHANGUP;
10589 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10590 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10591 code = Netbios(ncbp);
10592 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10593 if (code == 0) code = ncbp->ncb_retcode;
10595 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10596 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10600 /* Trigger the shutdown of all SMB threads */
10601 for (i = 0; i < smb_NumServerThreads; i++)
10602 thrd_SetEvent(NCBreturns[i][0]);
10604 thrd_SetEvent(NCBevents[0]);
10605 thrd_SetEvent(SessionEvents[0]);
10606 thrd_SetEvent(NCBavails[0]);
10608 for (i = 0;i < smb_NumServerThreads; i++) {
10609 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10610 if (code == WAIT_OBJECT_0) {
10613 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10614 thrd_SetEvent(NCBreturns[i--][0]);
10618 /* Delete Netbios name */
10619 memset((char *)ncbp, 0, sizeof(NCB));
10620 for (i = 0; i < lana_list.length; i++) {
10621 if (lana_list.lana[i] == LANA_INVALID) continue;
10622 ncbp->ncb_command = NCBDELNAME;
10623 ncbp->ncb_lana_num = lana_list.lana[i];
10624 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10625 code = Netbios(ncbp);
10627 code = ncbp->ncb_retcode;
10629 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10630 ncbp->ncb_lana_num, code);
10635 /* Release the reference counts held by the VCs */
10636 lock_ObtainWrite(&smb_rctLock);
10637 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10642 if (vcp->magic != SMB_VC_MAGIC)
10643 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10644 __FILE__, __LINE__);
10646 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10648 if (fidp->scp != NULL) {
10651 lock_ReleaseWrite(&smb_rctLock);
10652 lock_ObtainMutex(&fidp->mx);
10653 if (fidp->scp != NULL) {
10656 lock_ObtainWrite(&scp->rw);
10657 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10658 lock_ReleaseWrite(&scp->rw);
10659 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10660 cm_ReleaseSCache(scp);
10662 lock_ReleaseMutex(&fidp->mx);
10663 lock_ObtainWrite(&smb_rctLock);
10667 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10669 smb_ReleaseVCNoLock(tidp->vcp);
10671 cm_user_t *userp = tidp->userp;
10672 tidp->userp = NULL;
10673 cm_ReleaseUser(userp);
10677 lock_ReleaseWrite(&smb_rctLock);
10681 /* Get the UNC \\<servername>\<sharename> prefix. */
10682 char *smb_GetSharename()
10687 /* Make sure we have been properly initialized. */
10688 if (smb_localNamep == NULL)
10691 /* Allocate space for \\<servername>\<sharename>, plus the
10694 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10695 name = malloc(len);
10696 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10702 void smb_LogPacket(smb_packet_t *packet)
10706 unsigned length, paramlen, datalen, i, j;
10708 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10710 if (!packet) return;
10712 osi_Log0(smb_logp, "*** SMB packet dump ***");
10714 smbp = (smb_t *) packet->data;
10715 vp = (BYTE *) packet->data;
10717 paramlen = smbp->wct * 2;
10718 datalen = *((WORD *) (smbp->vdata + paramlen));
10719 length = sizeof(*smbp) + paramlen + 1 + datalen;
10721 for (i=0;i < length; i+=16)
10723 memset( buf, ' ', 80 );
10726 itoa( i, buf, 16 );
10728 buf[strlen(buf)] = ' ';
10730 cp = (BYTE*) buf + 7;
10732 for (j=0;j < 16 && (i+j)<length; j++)
10734 *(cp++) = hex[vp[i+j] >> 4];
10735 *(cp++) = hex[vp[i+j] & 0xf];
10745 for (j=0;j < 16 && (i+j)<length;j++)
10747 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10758 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10761 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10763 #endif /* LOG_PACKET */
10766 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10772 smb_username_t *unp;
10773 smb_waitingLockRequest_t *wlrp;
10776 lock_ObtainRead(&smb_rctLock);
10778 sprintf(output, "begin dumping smb_username_t\r\n");
10779 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10780 for (unp = usernamesp; unp; unp=unp->nextp)
10782 cm_ucell_t *ucellp;
10784 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10785 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10786 unp->name ? unp->name : _C("NULL"),
10787 unp->machine ? unp->machine : _C("NULL"));
10788 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10790 sprintf(output, " begin dumping cm_ucell_t\r\n");
10791 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10793 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10794 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",
10795 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10796 ucellp->expirationTime, ucellp->gen,
10798 ucellp->cellp->name);
10799 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10802 sprintf(output, " done dumping cm_ucell_t\r\n");
10803 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10806 sprintf(output, "done dumping smb_username_t\r\n");
10807 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10810 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10811 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10814 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10815 smb_waitingLock_t *lockp;
10817 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10818 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10819 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10821 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10822 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10823 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10824 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10825 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10826 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10828 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10829 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10832 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10833 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10835 sprintf(output, "begin dumping smb_vc_t\r\n");
10836 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10838 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10844 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10845 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10846 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10848 sprintf(output, " begin dumping smb_user_t\r\n");
10849 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10850 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10851 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10852 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10853 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10855 sprintf(output, " done dumping smb_user_t\r\n");
10856 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10858 sprintf(output, " begin dumping smb_tid_t\r\n");
10859 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10860 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10861 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",
10862 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10863 tidp->pathname ? tidp->pathname : _C("NULL"));
10864 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10866 sprintf(output, " done dumping smb_tid_t\r\n");
10867 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10869 sprintf(output, " begin dumping smb_fid_t\r\n");
10870 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10872 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10874 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",
10875 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10876 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10877 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10878 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10881 sprintf(output, " done dumping smb_fid_t\r\n");
10882 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10885 sprintf(output, "done dumping smb_vc_t\r\n");
10886 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10888 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10889 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10891 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10897 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10898 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10899 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10901 sprintf(output, " begin dumping smb_user_t\r\n");
10902 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10903 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10904 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10905 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10906 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10908 sprintf(output, " done dumping smb_user_t\r\n");
10909 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10911 sprintf(output, " begin dumping smb_tid_t\r\n");
10912 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10913 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10914 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",
10915 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10916 tidp->pathname ? tidp->pathname : _C("NULL"));
10917 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10919 sprintf(output, " done dumping smb_tid_t\r\n");
10920 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10922 sprintf(output, " begin dumping smb_fid_t\r\n");
10923 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10925 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10927 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",
10928 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10929 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10930 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10931 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10934 sprintf(output, " done dumping smb_fid_t\r\n");
10935 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10938 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10939 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10942 lock_ReleaseRead(&smb_rctLock);
10946 long smb_IsNetworkStarted(void)
10949 lock_ObtainWrite(&smb_globalLock);
10950 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10951 lock_ReleaseWrite(&smb_globalLock);