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(ncbp, 0, sizeof(NCB));
2955 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2956 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2957 extra += tp[0] + (tp[1]<<8);
2958 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2959 extra += 3; /* wct and length fields */
2961 ncbp->ncb_length = extra; /* bytes to send */
2962 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2963 ncbp->ncb_lana_num = vcp->lana;
2964 ncbp->ncb_command = NCBSEND; /* op means send data */
2965 ncbp->ncb_buffer = (char *) inp;/* packet */
2966 code = Netbios(ncbp);
2969 const char * s = ncb_error_string(code);
2970 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2971 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2973 lock_ObtainMutex(&vcp->mx);
2974 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2975 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2977 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2978 lock_ReleaseMutex(&vcp->mx);
2979 lock_ObtainWrite(&smb_globalLock);
2980 dead_sessions[vcp->session] = TRUE;
2981 lock_ReleaseWrite(&smb_globalLock);
2982 smb_CleanupDeadVC(vcp);
2984 lock_ReleaseMutex(&vcp->mx);
2992 void smb_MapNTError(long code, unsigned long *NTStatusp)
2994 unsigned long NTStatus;
2996 /* map CM_ERROR_* errors to NT 32-bit status codes */
2997 /* NT Status codes are listed in ntstatus.h not winerror.h */
3001 else if (code == CM_ERROR_NOSUCHCELL) {
3002 NTStatus = 0xC0000034L; /* Name not found */
3004 else if (code == CM_ERROR_NOSUCHVOLUME) {
3005 NTStatus = 0xC0000034L; /* Name not found */
3007 else if (code == CM_ERROR_TIMEDOUT) {
3009 NTStatus = 0xC00000CFL; /* Sharing Paused */
3011 /* Do not send Timeout to the SMB redirector.
3012 * It causes the redirector to drop the connection */
3013 NTStatus = 0x00000102L; /* Timeout */
3015 NTStatus = 0xC000022DL; /* Retry */
3018 else if (code == CM_ERROR_RETRY) {
3019 NTStatus = 0xC000022DL; /* Retry */
3021 else if (code == CM_ERROR_NOACCESS) {
3022 NTStatus = 0xC0000022L; /* Access denied */
3024 else if (code == CM_ERROR_READONLY) {
3025 NTStatus = 0xC00000A2L; /* Write protected */
3027 else if (code == CM_ERROR_NOSUCHFILE ||
3028 code == CM_ERROR_BPLUS_NOMATCH) {
3029 NTStatus = 0xC0000034L; /* Name not found */
3031 else if (code == CM_ERROR_NOSUCHPATH) {
3032 NTStatus = 0xC000003AL; /* Object path not found */
3034 else if (code == CM_ERROR_TOOBIG) {
3035 NTStatus = 0xC000007BL; /* Invalid image format */
3037 else if (code == CM_ERROR_INVAL) {
3038 NTStatus = 0xC000000DL; /* Invalid parameter */
3040 else if (code == CM_ERROR_BADFD) {
3041 NTStatus = 0xC0000008L; /* Invalid handle */
3043 else if (code == CM_ERROR_BADFDOP) {
3044 NTStatus = 0xC0000022L; /* Access denied */
3046 else if (code == CM_ERROR_UNKNOWN) {
3047 NTStatus = 0xC0000022L; /* Access denied */
3049 else if (code == CM_ERROR_EXISTS) {
3050 NTStatus = 0xC0000035L; /* Object name collision */
3052 else if (code == CM_ERROR_NOTEMPTY) {
3053 NTStatus = 0xC0000101L; /* Directory not empty */
3055 else if (code == CM_ERROR_CROSSDEVLINK) {
3056 NTStatus = 0xC00000D4L; /* Not same device */
3058 else if (code == CM_ERROR_NOTDIR) {
3059 NTStatus = 0xC0000103L; /* Not a directory */
3061 else if (code == CM_ERROR_ISDIR) {
3062 NTStatus = 0xC00000BAL; /* File is a directory */
3064 else if (code == CM_ERROR_BADOP) {
3066 /* I have no idea where this comes from */
3067 NTStatus = 0xC09820FFL; /* SMB no support */
3069 NTStatus = 0xC00000BBL; /* Not supported */
3070 #endif /* COMMENT */
3072 else if (code == CM_ERROR_BADSHARENAME) {
3073 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3075 else if (code == CM_ERROR_NOIPC) {
3077 NTStatus = 0xC0000022L; /* Access Denied */
3079 NTStatus = 0xC000013DL; /* Remote Resources */
3082 else if (code == CM_ERROR_CLOCKSKEW ||
3083 code == RXKADNOAUTH) {
3084 NTStatus = 0xC0000133L; /* Time difference at DC */
3086 else if (code == CM_ERROR_BADTID) {
3087 NTStatus = 0xC0982005L; /* SMB bad TID */
3089 else if (code == CM_ERROR_USESTD) {
3090 NTStatus = 0xC09820FBL; /* SMB use standard */
3092 else if (code == CM_ERROR_QUOTA) {
3093 NTStatus = 0xC0000044L; /* Quota exceeded */
3095 else if (code == CM_ERROR_SPACE) {
3096 NTStatus = 0xC000007FL; /* Disk full */
3098 else if (code == CM_ERROR_ATSYS) {
3099 NTStatus = 0xC0000033L; /* Object name invalid */
3101 else if (code == CM_ERROR_BADNTFILENAME) {
3102 NTStatus = 0xC0000033L; /* Object name invalid */
3104 else if (code == CM_ERROR_WOULDBLOCK) {
3105 NTStatus = 0xC00000D8L; /* Can't wait */
3107 else if (code == CM_ERROR_SHARING_VIOLATION) {
3108 NTStatus = 0xC0000043L; /* Sharing violation */
3110 else if (code == CM_ERROR_LOCK_CONFLICT) {
3111 NTStatus = 0xC0000054L; /* Lock conflict */
3113 else if (code == CM_ERROR_PARTIALWRITE) {
3114 NTStatus = 0xC000007FL; /* Disk full */
3116 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3117 NTStatus = 0xC0000023L; /* Buffer too small */
3119 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3120 NTStatus = 0xC0000035L; /* Object name collision */
3122 else if (code == CM_ERROR_BADPASSWORD) {
3123 NTStatus = 0xC000006DL; /* unknown username or bad password */
3125 else if (code == CM_ERROR_BADLOGONTYPE) {
3126 NTStatus = 0xC000015BL; /* logon type not granted */
3128 else if (code == CM_ERROR_GSSCONTINUE) {
3129 NTStatus = 0xC0000016L; /* more processing required */
3131 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3133 NTStatus = 0xC0000280L; /* reparse point not resolved */
3135 NTStatus = 0xC0000022L; /* Access Denied */
3138 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3139 NTStatus = 0xC0000257L; /* Path Not Covered */
3141 else if (code == CM_ERROR_ALLBUSY) {
3142 NTStatus = 0xC000022DL; /* Retry */
3144 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3145 NTStatus = 0xC000003AL; /* Path not found */
3147 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3148 NTStatus = 0xC0000322L; /* No Kerberos key */
3150 else if (code == CM_ERROR_BAD_LEVEL) {
3151 NTStatus = 0xC0000148L; /* Invalid Level */
3153 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3154 NTStatus = 0xC000007EL; /* Range Not Locked */
3156 else if (code == CM_ERROR_NOSUCHDEVICE) {
3157 NTStatus = 0xC000000EL; /* No Such Device */
3159 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3160 NTStatus = 0xC0000055L; /* Lock Not Granted */
3162 else if (code == ENOMEM) {
3163 NTStatus = 0xC0000017L; /* Out of Memory */
3165 else if (code == CM_ERROR_RPC_MOREDATA) {
3166 NTStatus = 0x80000005L; /* Buffer overflow */
3169 NTStatus = 0xC0982001L; /* SMB non-specific error */
3172 *NTStatusp = NTStatus;
3173 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3177 * NTSTATUS <-> Win32 Error Translation
3178 * http://support.microsoft.com/kb/113996
3180 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3182 unsigned long Win32E;
3184 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3188 else if (code == CM_ERROR_NOSUCHCELL) {
3189 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3191 else if (code == CM_ERROR_NOSUCHVOLUME) {
3192 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3194 else if (code == CM_ERROR_TIMEDOUT) {
3196 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3198 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3201 else if (code == CM_ERROR_RETRY) {
3202 Win32E = ERROR_RETRY; /* Retry */
3204 else if (code == CM_ERROR_NOACCESS) {
3205 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3207 else if (code == CM_ERROR_READONLY) {
3208 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3210 else if (code == CM_ERROR_NOSUCHFILE ||
3211 code == CM_ERROR_BPLUS_NOMATCH) {
3212 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3214 else if (code == CM_ERROR_NOSUCHPATH) {
3215 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3217 else if (code == CM_ERROR_TOOBIG) {
3218 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3220 else if (code == CM_ERROR_INVAL) {
3221 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3223 else if (code == CM_ERROR_BADFD) {
3224 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3226 else if (code == CM_ERROR_BADFDOP) {
3227 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3229 else if (code == CM_ERROR_UNKNOWN) {
3230 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3232 else if (code == CM_ERROR_EXISTS) {
3233 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3235 else if (code == CM_ERROR_NOTEMPTY) {
3236 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3238 else if (code == CM_ERROR_CROSSDEVLINK) {
3239 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3241 else if (code == CM_ERROR_NOTDIR) {
3242 Win32E = ERROR_DIRECTORY; /* Not a directory */
3244 else if (code == CM_ERROR_ISDIR) {
3245 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3247 else if (code == CM_ERROR_BADOP) {
3248 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3250 else if (code == CM_ERROR_BADSHARENAME) {
3251 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3253 else if (code == CM_ERROR_NOIPC) {
3255 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3257 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3260 else if (code == CM_ERROR_CLOCKSKEW ||
3261 code == RXKADNOAUTH) {
3262 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3264 else if (code == CM_ERROR_BADTID) {
3265 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3267 else if (code == CM_ERROR_USESTD) {
3268 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3270 else if (code == CM_ERROR_QUOTA) {
3271 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3273 else if (code == CM_ERROR_SPACE) {
3274 Win32E = ERROR_DISK_FULL; /* Disk full */
3276 else if (code == CM_ERROR_ATSYS) {
3277 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3279 else if (code == CM_ERROR_BADNTFILENAME) {
3280 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3282 else if (code == CM_ERROR_WOULDBLOCK) {
3283 Win32E = WAIT_TIMEOUT; /* Can't wait */
3285 else if (code == CM_ERROR_SHARING_VIOLATION) {
3286 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3288 else if (code == CM_ERROR_LOCK_CONFLICT) {
3289 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3291 else if (code == CM_ERROR_PARTIALWRITE) {
3292 Win32E = ERROR_DISK_FULL; /* Disk full */
3294 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3295 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3297 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3298 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3300 else if (code == CM_ERROR_BADPASSWORD) {
3301 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3303 else if (code == CM_ERROR_BADLOGONTYPE) {
3304 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3306 else if (code == CM_ERROR_GSSCONTINUE) {
3307 Win32E = ERROR_MORE_DATA; /* more processing required */
3309 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3311 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3313 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3316 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3317 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3319 else if (code == CM_ERROR_ALLBUSY) {
3320 Win32E = ERROR_RETRY; /* Retry */
3322 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3323 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3325 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3326 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3328 else if (code == CM_ERROR_BAD_LEVEL) {
3329 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3331 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3332 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3334 else if (code == CM_ERROR_NOSUCHDEVICE) {
3335 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3337 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3338 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3340 else if (code == ENOMEM) {
3341 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3343 else if (code == CM_ERROR_RPC_MOREDATA) {
3344 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3347 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3351 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3354 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3355 unsigned char *classp)
3357 unsigned char class;
3358 unsigned short error;
3360 /* map CM_ERROR_* errors to SMB errors */
3361 if (code == CM_ERROR_NOSUCHCELL) {
3363 error = 3; /* bad path */
3365 else if (code == CM_ERROR_NOSUCHVOLUME) {
3367 error = 3; /* bad path */
3369 else if (code == CM_ERROR_TIMEDOUT) {
3371 error = 81; /* server is paused */
3373 else if (code == CM_ERROR_RETRY) {
3374 class = 2; /* shouldn't happen */
3377 else if (code == CM_ERROR_NOACCESS) {
3379 error = 4; /* bad access */
3381 else if (code == CM_ERROR_READONLY) {
3383 error = 19; /* read only */
3385 else if (code == CM_ERROR_NOSUCHFILE ||
3386 code == CM_ERROR_BPLUS_NOMATCH) {
3388 error = 2; /* ENOENT! */
3390 else if (code == CM_ERROR_NOSUCHPATH) {
3392 error = 3; /* Bad path */
3394 else if (code == CM_ERROR_TOOBIG) {
3396 error = 11; /* bad format */
3398 else if (code == CM_ERROR_INVAL) {
3399 class = 2; /* server non-specific error code */
3402 else if (code == CM_ERROR_BADFD) {
3404 error = 6; /* invalid file handle */
3406 else if (code == CM_ERROR_BADFDOP) {
3407 class = 1; /* invalid op on FD */
3410 else if (code == CM_ERROR_EXISTS) {
3412 error = 80; /* file already exists */
3414 else if (code == CM_ERROR_NOTEMPTY) {
3416 error = 5; /* delete directory not empty */
3418 else if (code == CM_ERROR_CROSSDEVLINK) {
3420 error = 17; /* EXDEV */
3422 else if (code == CM_ERROR_NOTDIR) {
3423 class = 1; /* bad path */
3426 else if (code == CM_ERROR_ISDIR) {
3427 class = 1; /* access denied; DOS doesn't have a good match */
3430 else if (code == CM_ERROR_BADOP) {
3434 else if (code == CM_ERROR_BADSHARENAME) {
3438 else if (code == CM_ERROR_NOIPC) {
3440 error = 4; /* bad access */
3442 else if (code == CM_ERROR_CLOCKSKEW) {
3443 class = 1; /* invalid function */
3446 else if (code == CM_ERROR_BADTID) {
3450 else if (code == CM_ERROR_USESTD) {
3454 else if (code == CM_ERROR_REMOTECONN) {
3458 else if (code == CM_ERROR_QUOTA) {
3459 if (vcp->flags & SMB_VCFLAG_USEV3) {
3461 error = 39; /* disk full */
3465 error = 5; /* access denied */
3468 else if (code == CM_ERROR_SPACE) {
3469 if (vcp->flags & SMB_VCFLAG_USEV3) {
3471 error = 39; /* disk full */
3475 error = 5; /* access denied */
3478 else if (code == CM_ERROR_PARTIALWRITE) {
3480 error = 39; /* disk full */
3482 else if (code == CM_ERROR_ATSYS) {
3484 error = 2; /* ENOENT */
3486 else if (code == CM_ERROR_WOULDBLOCK) {
3488 error = 33; /* lock conflict */
3490 else if (code == CM_ERROR_LOCK_CONFLICT) {
3492 error = 33; /* lock conflict */
3494 else if (code == CM_ERROR_SHARING_VIOLATION) {
3496 error = 33; /* lock conflict */
3498 else if (code == CM_ERROR_NOFILES) {
3500 error = 18; /* no files in search */
3502 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3504 error = 183; /* Samba uses this */
3506 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3507 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3509 error = 2; /* bad password */
3511 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3513 error = 3; /* bad path */
3522 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3525 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3527 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3528 return CM_ERROR_BADOP;
3532 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3534 unsigned short EchoCount, i;
3535 char *data, *outdata;
3538 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3540 for (i=1; i<=EchoCount; i++) {
3541 data = smb_GetSMBData(inp, &dataSize);
3542 smb_SetSMBParm(outp, 0, i);
3543 smb_SetSMBDataLength(outp, dataSize);
3544 outdata = smb_GetSMBData(outp, NULL);
3545 memcpy(outdata, data, dataSize);
3546 smb_SendPacket(vcp, outp);
3552 /* SMB_COM_READ_RAW */
3553 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3556 long count, minCount, finalCount;
3560 smb_t *smbp = (smb_t*) inp;
3562 cm_user_t *userp = NULL;
3565 char *rawBuf = NULL;
3570 fd = smb_GetSMBParm(inp, 0);
3571 count = smb_GetSMBParm(inp, 3);
3572 minCount = smb_GetSMBParm(inp, 4);
3573 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3575 if (*inp->wctp == 10) {
3576 /* we were sent a request with 64-bit file offsets */
3577 #ifdef AFS_LARGEFILES
3578 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3580 if (LargeIntegerLessThanZero(offset)) {
3581 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3585 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3586 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3589 offset.HighPart = 0;
3593 /* we were sent a request with 32-bit file offsets */
3594 offset.HighPart = 0;
3597 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3598 fd, offset.HighPart, offset.LowPart, count);
3600 fidp = smb_FindFID(vcp, fd, 0);
3602 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3606 lock_ObtainMutex(&fidp->mx);
3608 lock_ReleaseMutex(&fidp->mx);
3609 smb_ReleaseFID(fidp);
3610 return CM_ERROR_BADFD;
3613 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3614 lock_ReleaseMutex(&fidp->mx);
3615 smb_CloseFID(vcp, fidp, NULL, 0);
3616 code = CM_ERROR_NOSUCHFILE;
3622 LARGE_INTEGER LOffset, LLength;
3625 key = cm_GenerateKey(vcp->vcID, pid, fd);
3627 LOffset.HighPart = offset.HighPart;
3628 LOffset.LowPart = offset.LowPart;
3629 LLength.HighPart = 0;
3630 LLength.LowPart = count;
3632 lock_ObtainWrite(&fidp->scp->rw);
3633 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3634 lock_ReleaseWrite(&fidp->scp->rw);
3637 lock_ReleaseMutex(&fidp->mx);
3641 lock_ObtainMutex(&smb_RawBufLock);
3643 /* Get a raw buf, from head of list */
3644 rawBuf = smb_RawBufs;
3645 smb_RawBufs = *(char **)smb_RawBufs;
3647 lock_ReleaseMutex(&smb_RawBufLock);
3649 lock_ReleaseMutex(&fidp->mx);
3653 if (fidp->flags & SMB_FID_IOCTL)
3655 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3657 /* Give back raw buffer */
3658 lock_ObtainMutex(&smb_RawBufLock);
3659 *((char **) rawBuf) = smb_RawBufs;
3661 smb_RawBufs = rawBuf;
3662 lock_ReleaseMutex(&smb_RawBufLock);
3665 lock_ReleaseMutex(&fidp->mx);
3666 smb_ReleaseFID(fidp);
3669 lock_ReleaseMutex(&fidp->mx);
3671 userp = smb_GetUserFromVCP(vcp, inp);
3673 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3679 cm_ReleaseUser(userp);
3682 smb_ReleaseFID(fidp);
3686 memset(ncbp, 0, sizeof(NCB));
3688 ncbp->ncb_length = (unsigned short) finalCount;
3689 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3690 ncbp->ncb_lana_num = vcp->lana;
3691 ncbp->ncb_command = NCBSEND;
3692 ncbp->ncb_buffer = rawBuf;
3694 code = Netbios(ncbp);
3696 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3699 /* Give back raw buffer */
3700 lock_ObtainMutex(&smb_RawBufLock);
3701 *((char **) rawBuf) = smb_RawBufs;
3703 smb_RawBufs = rawBuf;
3704 lock_ReleaseMutex(&smb_RawBufLock);
3710 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3712 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3717 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3719 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3724 /* SMB_COM_NEGOTIATE */
3725 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3732 int VistaProtoIndex;
3733 int protoIndex; /* index we're using */
3738 char protocol_array[10][1024]; /* protocol signature of the client */
3739 int caps; /* capabilities */
3742 TIME_ZONE_INFORMATION tzi;
3744 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3747 namep = smb_GetSMBData(inp, &dbytes);
3750 coreProtoIndex = -1; /* not found */
3753 VistaProtoIndex = -1;
3754 while(namex < dbytes) {
3755 osi_Log1(smb_logp, "Protocol %s",
3756 osi_LogSaveString(smb_logp, namep+1));
3757 strcpy(protocol_array[tcounter], namep+1);
3759 /* namep points at the first protocol, or really, a 0x02
3760 * byte preceding the null-terminated ASCII name.
3762 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3763 coreProtoIndex = tcounter;
3765 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3766 v3ProtoIndex = tcounter;
3768 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3769 NTProtoIndex = tcounter;
3771 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3772 VistaProtoIndex = tcounter;
3775 /* compute size of protocol entry */
3776 entryLength = (int)strlen(namep+1);
3777 entryLength += 2; /* 0x02 bytes and null termination */
3779 /* advance over this protocol entry */
3780 namex += entryLength;
3781 namep += entryLength;
3782 tcounter++; /* which proto entry we're looking at */
3785 lock_ObtainMutex(&vcp->mx);
3787 if (VistaProtoIndex != -1) {
3788 protoIndex = VistaProtoIndex;
3789 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3792 if (NTProtoIndex != -1) {
3793 protoIndex = NTProtoIndex;
3794 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3796 else if (v3ProtoIndex != -1) {
3797 protoIndex = v3ProtoIndex;
3798 vcp->flags |= SMB_VCFLAG_USEV3;
3800 else if (coreProtoIndex != -1) {
3801 protoIndex = coreProtoIndex;
3802 vcp->flags |= SMB_VCFLAG_USECORE;
3804 else protoIndex = -1;
3805 lock_ReleaseMutex(&vcp->mx);
3807 if (protoIndex == -1)
3808 return CM_ERROR_INVAL;
3809 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3810 smb_SetSMBParm(outp, 0, protoIndex);
3811 if (smb_authType != SMB_AUTH_NONE) {
3812 smb_SetSMBParmByte(outp, 1,
3813 NEGOTIATE_SECURITY_USER_LEVEL |
3814 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3816 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3818 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3819 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3820 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3821 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3822 /* The session key is not a well documented field however most clients
3823 * will echo back the session key to the server. Currently we are using
3824 * the same value for all sessions. We should generate a random value
3825 * and store it into the vcp
3827 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3828 smb_SetSMBParm(outp, 8, 1);
3830 * Tried changing the capabilities to support for W2K - defect 117695
3831 * Maybe something else needs to be changed here?
3835 smb_SetSMBParmLong(outp, 9, 0x43fd);
3837 smb_SetSMBParmLong(outp, 9, 0x251);
3840 * 32-bit error codes *
3846 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3848 NTNEGOTIATE_CAPABILITY_DFS |
3850 #ifdef AFS_LARGEFILES
3851 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3853 NTNEGOTIATE_CAPABILITY_NTFIND |
3854 NTNEGOTIATE_CAPABILITY_RAWMODE |
3855 NTNEGOTIATE_CAPABILITY_NTSMB;
3857 if ( smb_authType == SMB_AUTH_EXTENDED )
3858 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3861 if ( smb_UseUnicode ) {
3862 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3866 smb_SetSMBParmLong(outp, 9, caps);
3868 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3869 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3870 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3872 GetTimeZoneInformation(&tzi);
3873 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3875 if (smb_authType == SMB_AUTH_NTLM) {
3876 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3877 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3878 /* paste in encryption key */
3879 datap = smb_GetSMBData(outp, NULL);
3880 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3881 /* and the faux domain name */
3882 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3883 datap + MSV1_0_CHALLENGE_LENGTH,
3884 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3885 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3889 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3891 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3893 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3895 datap = smb_GetSMBData(outp, NULL);
3896 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3899 datap += sizeof(smb_ServerGUID);
3900 memcpy(datap, secBlob, secBlobLength);
3904 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3905 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3908 else if (v3ProtoIndex != -1) {
3909 smb_SetSMBParm(outp, 0, protoIndex);
3911 /* NOTE: Extended authentication cannot be negotiated with v3
3912 * therefore we fail over to NTLM
3914 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3915 smb_SetSMBParm(outp, 1,
3916 NEGOTIATE_SECURITY_USER_LEVEL |
3917 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3919 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3921 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3922 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3923 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3924 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3925 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3926 smb_SetSMBParm(outp, 7, 1);
3928 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3929 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3930 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3932 GetTimeZoneInformation(&tzi);
3933 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3935 /* NOTE: Extended authentication cannot be negotiated with v3
3936 * therefore we fail over to NTLM
3938 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3939 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3940 smb_SetSMBParm(outp, 12, 0); /* resvd */
3941 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3942 datap = smb_GetSMBData(outp, NULL);
3943 /* paste in a new encryption key */
3944 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3945 /* and the faux domain name */
3946 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3947 datap + MSV1_0_CHALLENGE_LENGTH,
3948 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3950 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3951 smb_SetSMBParm(outp, 12, 0); /* resvd */
3952 smb_SetSMBDataLength(outp, 0);
3955 else if (coreProtoIndex != -1) { /* not really supported anymore */
3956 smb_SetSMBParm(outp, 0, protoIndex);
3957 smb_SetSMBDataLength(outp, 0);
3962 void smb_CheckVCs(void)
3964 smb_vc_t * vcp, *nextp;
3965 smb_packet_t * outp = smb_GetPacket();
3968 lock_ObtainWrite(&smb_rctLock);
3969 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3971 if (vcp->magic != SMB_VC_MAGIC)
3972 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3973 __FILE__, __LINE__);
3975 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3977 smb_HoldVCNoLock(vcp);
3980 * obtain a reference to 'nextp' now because we drop the
3981 * smb_rctLock later and the list contents could change
3982 * or 'vcp' could be destroyed when released.
3986 smb_HoldVCNoLock(nextp);
3988 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3989 smb_ReleaseVCNoLock(vcp);
3993 smb_FormatResponsePacket(vcp, NULL, outp);
3994 smbp = (smb_t *)outp;
3995 outp->inCom = smbp->com = 0x2b /* Echo */;
4003 smb_SetSMBParm(outp, 0, 0);
4004 smb_SetSMBDataLength(outp, 0);
4005 lock_ReleaseWrite(&smb_rctLock);
4007 smb_SendPacket(vcp, outp);
4009 lock_ObtainWrite(&smb_rctLock);
4010 smb_ReleaseVCNoLock(vcp);
4012 lock_ReleaseWrite(&smb_rctLock);
4013 smb_FreePacket(outp);
4016 void smb_Daemon(void *parmp)
4018 afs_uint32 count = 0;
4019 smb_username_t **unpp;
4022 while(smbShutdownFlag == 0) {
4026 if (smbShutdownFlag == 1)
4029 if ((count % 72) == 0) { /* every five minutes */
4031 time_t old_localZero = smb_localZero;
4033 /* Initialize smb_localZero */
4034 myTime.tm_isdst = -1; /* compute whether on DST or not */
4035 myTime.tm_year = 70;
4041 smb_localZero = mktime(&myTime);
4043 #ifdef AFS_FREELANCE
4044 if ( smb_localZero != old_localZero )
4045 cm_noteLocalMountPointChange();
4051 /* GC smb_username_t objects that will no longer be used */
4053 lock_ObtainWrite(&smb_rctLock);
4054 for ( unpp=&usernamesp; *unpp; ) {
4056 smb_username_t *unp;
4058 lock_ObtainMutex(&(*unpp)->mx);
4059 if ( (*unpp)->refCount > 0 ||
4060 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4061 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4063 else if (!smb_LogoffTokenTransfer ||
4064 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4066 lock_ReleaseMutex(&(*unpp)->mx);
4074 lock_FinalizeMutex(&unp->mx);
4080 cm_ReleaseUser(userp);
4082 unpp = &(*unpp)->nextp;
4085 lock_ReleaseWrite(&smb_rctLock);
4087 /* XXX GC dir search entries */
4091 void smb_WaitingLocksDaemon()
4093 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4094 smb_waitingLock_t *wl, *wlNext;
4097 smb_packet_t *inp, *outp;
4101 while (smbShutdownFlag == 0) {
4102 lock_ObtainWrite(&smb_globalLock);
4103 nwlRequest = smb_allWaitingLocks;
4104 if (nwlRequest == NULL) {
4105 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4110 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4117 lock_ObtainWrite(&smb_globalLock);
4119 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4121 wlRequest = nwlRequest;
4122 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4123 lock_ReleaseWrite(&smb_globalLock);
4127 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4128 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4131 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4132 code = CM_ERROR_LOCK_NOT_GRANTED;
4136 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4138 /* wl->state is either _DONE or _WAITING. _ERROR
4139 would no longer be on the queue. */
4140 code = cm_RetryLock( wl->lockp,
4141 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4144 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4145 } else if (code != CM_ERROR_WOULDBLOCK) {
4146 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4151 if (code == CM_ERROR_WOULDBLOCK) {
4154 if (wlRequest->msTimeout != 0xffffffff
4155 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4167 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4170 scp = wlRequest->scp;
4171 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4175 lock_ObtainWrite(&scp->rw);
4177 for (wl = wlRequest->locks; wl; wl = wlNext) {
4178 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4180 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4181 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4182 wl->LLength, wl->key, 0, NULL, &req);
4184 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4189 lock_ReleaseWrite(&scp->rw);
4193 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4196 for (wl = wlRequest->locks; wl; wl = wlNext) {
4197 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4198 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4203 vcp = wlRequest->vcp;
4204 inp = wlRequest->inp;
4205 outp = wlRequest->outp;
4206 ncbp = smb_GetNCB();
4207 ncbp->ncb_length = inp->ncb_length;
4208 inp->spacep = cm_GetSpace();
4210 /* Remove waitingLock from list */
4211 lock_ObtainWrite(&smb_globalLock);
4212 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4214 lock_ReleaseWrite(&smb_globalLock);
4216 /* Resume packet processing */
4218 smb_SetSMBDataLength(outp, 0);
4219 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4220 outp->resumeCode = code;
4222 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4225 cm_FreeSpace(inp->spacep);
4226 smb_FreePacket(inp);
4227 smb_FreePacket(outp);
4229 cm_ReleaseSCache(wlRequest->scp);
4232 } while (nwlRequest && smbShutdownFlag == 0);
4237 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4239 osi_Log0(smb_logp, "SMB receive get disk attributes");
4241 smb_SetSMBParm(outp, 0, 32000);
4242 smb_SetSMBParm(outp, 1, 64);
4243 smb_SetSMBParm(outp, 2, 1024);
4244 smb_SetSMBParm(outp, 3, 30000);
4245 smb_SetSMBParm(outp, 4, 0);
4246 smb_SetSMBDataLength(outp, 0);
4250 /* SMB_COM_TREE_CONNECT */
4251 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4255 unsigned short newTid;
4256 clientchar_t shareName[AFSPATHMAX];
4257 clientchar_t *sharePath;
4260 clientchar_t *pathp;
4263 osi_Log0(smb_logp, "SMB receive tree connect");
4265 /* parse input parameters */
4268 tbp = smb_GetSMBData(inp, NULL);
4269 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4271 return CM_ERROR_BADSMB;
4273 tp = cm_ClientStrRChr(pathp, '\\');
4275 return CM_ERROR_BADSMB;
4276 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4278 lock_ObtainMutex(&vcp->mx);
4279 newTid = vcp->tidCounter++;
4280 lock_ReleaseMutex(&vcp->mx);
4282 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4283 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4285 return CM_ERROR_BADSMB;
4286 userp = smb_GetUserFromUID(uidp);
4287 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4288 smb_ReleaseUID(uidp);
4290 smb_ReleaseTID(tidp, FALSE);
4291 return CM_ERROR_BADSHARENAME;
4293 lock_ObtainMutex(&tidp->mx);
4294 tidp->userp = userp;
4295 tidp->pathname = sharePath;
4296 lock_ReleaseMutex(&tidp->mx);
4297 smb_ReleaseTID(tidp, FALSE);
4299 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4300 smb_SetSMBParm(rsp, 1, newTid);
4301 smb_SetSMBDataLength(rsp, 0);
4303 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4307 /* set maskp to the mask part of the incoming path.
4308 * Mask is 11 bytes long (8.3 with the dot elided).
4309 * Returns true if succeeds with a valid name, otherwise it does
4310 * its best, but returns false.
4312 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4320 /* starts off valid */
4323 /* mask starts out all blanks */
4324 memset(maskp, ' ', 11);
4327 /* find last backslash, or use whole thing if there is none */
4328 tp = cm_ClientStrRChr(pathp, '\\');
4332 tp++; /* skip slash */
4336 /* names starting with a dot are illegal */
4344 if (tc == '.' || tc == '"')
4352 /* if we get here, tp point after the dot */
4353 up = maskp+8; /* ext goes here */
4360 if (tc == '.' || tc == '"')
4363 /* copy extension if not too long */
4373 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4375 clientchar_t umask[11];
4383 /* XXX redo this, calling cm_MatchMask with a converted mask */
4385 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4389 /* otherwise, we have a valid 8.3 name; see if we have a match,
4390 * treating '?' as a wildcard in maskp (but not in the file name).
4392 tp1 = umask; /* real name, in mask format */
4393 tp2 = maskp; /* mask, in mask format */
4394 for(i=0; i<11; i++) {
4395 tc1 = *tp1++; /* clientchar_t from real name */
4396 tc2 = *tp2++; /* clientchar_t from mask */
4397 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4398 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4401 if (tc2 == '?' && tc1 != ' ')
4408 /* we got a match */
4412 clientchar_t *smb_FindMask(clientchar_t *pathp)
4416 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4419 return tp+1; /* skip the slash */
4421 return pathp; /* no slash, return the entire path */
4424 /* SMB_COM_SEARCH for a volume label
4426 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4427 dispatch function.) */
4428 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4430 clientchar_t *pathp;
4432 clientchar_t mask[12];
4433 unsigned char *statBlockp;
4434 unsigned char initStatBlock[21];
4437 osi_Log0(smb_logp, "SMB receive search volume");
4439 /* pull pathname and stat block out of request */
4440 tp = smb_GetSMBData(inp, NULL);
4441 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4442 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4444 return CM_ERROR_BADSMB;
4445 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4446 osi_assertx(statBlockp != NULL, "null statBlock");
4448 statBlockp = initStatBlock;
4452 /* for returning to caller */
4453 smb_Get8Dot3MaskFromPath(mask, pathp);
4455 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4456 tp = smb_GetSMBData(outp, NULL);
4458 *tp++ = 43; /* bytes in a dir entry */
4459 *tp++ = 0; /* high byte in counter */
4461 /* now marshall the dir entry, starting with the search status */
4462 *tp++ = statBlockp[0]; /* Reserved */
4463 memcpy(tp, mask, 11); tp += 11; /* FileName */
4465 /* now pass back server use info, with 1st byte non-zero */
4467 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4469 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4471 *tp++ = 0x8; /* attribute: volume */
4481 /* 4 byte file size */
4487 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4490 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4491 memset(tp, ' ', 13);
4494 /* set the length of the data part of the packet to 43 + 3, for the dir
4495 * entry plus the 5 and the length fields.
4497 smb_SetSMBDataLength(outp, 46);
4502 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4503 clientchar_t * tidPathp, clientchar_t * relPathp,
4504 cm_user_t *userp, cm_req_t *reqp)
4512 smb_dirListPatch_t *patchp;
4513 smb_dirListPatch_t *npatchp;
4514 clientchar_t path[AFSPATHMAX];
4516 afs_int32 mustFake = 0;
4518 code = cm_FindACLCache(dscp, userp, &rights);
4520 lock_ObtainWrite(&dscp->rw);
4521 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4522 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4523 lock_ReleaseWrite(&dscp->rw);
4524 if (code == CM_ERROR_NOACCESS) {
4532 if (!mustFake) { /* Bulk Stat */
4534 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4536 memset(bsp, 0, sizeof(cm_bulkStat_t));
4538 for (patchp = *dirPatchespp, count=0;
4540 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4541 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4545 if (lock_TryWrite(&tscp->rw)) {
4546 /* we have an entry that we can look at */
4547 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4548 /* we have a callback on it. Don't bother
4549 * fetching this stat entry, since we're happy
4550 * with the info we have.
4552 lock_ReleaseWrite(&tscp->rw);
4553 cm_ReleaseSCache(tscp);
4556 lock_ReleaseWrite(&tscp->rw);
4558 cm_ReleaseSCache(tscp);
4562 bsp->fids[i].Volume = patchp->fid.volume;
4563 bsp->fids[i].Vnode = patchp->fid.vnode;
4564 bsp->fids[i].Unique = patchp->fid.unique;
4566 if (bsp->counter == AFSCBMAX) {
4567 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4568 memset(bsp, 0, sizeof(cm_bulkStat_t));
4572 if (bsp->counter > 0)
4573 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4578 for (patchp = *dirPatchespp; patchp; patchp =
4579 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4581 dptr = patchp->dptr;
4583 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4584 relPathp ? relPathp : _C(""), patchp->dep->name);
4585 reqp->relPathp = path;
4586 reqp->tidPathp = tidPathp;
4588 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4589 reqp->relPathp = reqp->tidPathp = NULL;
4592 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4593 *dptr++ = SMB_ATTR_HIDDEN;
4596 lock_ObtainWrite(&scp->rw);
4597 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4598 lock_ReleaseWrite(&scp->rw);
4600 /* set the attribute */
4601 switch (scp->fileType) {
4602 case CM_SCACHETYPE_DIRECTORY:
4603 case CM_SCACHETYPE_MOUNTPOINT:
4604 case CM_SCACHETYPE_INVALID:
4605 attr = SMB_ATTR_DIRECTORY;
4607 case CM_SCACHETYPE_SYMLINK:
4608 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4609 attr = SMB_ATTR_DIRECTORY;
4611 attr = SMB_ATTR_NORMAL;
4614 /* if we get here we either have a normal file
4615 * or we have a file for which we have never
4616 * received status info. In this case, we can
4617 * check the even/odd value of the entry's vnode.
4618 * odd means it is to be treated as a directory
4619 * and even means it is to be treated as a file.
4621 if (mustFake && (scp->fid.vnode & 0x1))
4622 attr = SMB_ATTR_DIRECTORY;
4624 attr = SMB_ATTR_NORMAL;
4628 /* 1969-12-31 23:59:58 +00*/
4629 dosTime = 0xEBBFBF7D;
4632 shortTemp = (unsigned short) (dosTime & 0xffff);
4633 *((u_short *)dptr) = shortTemp;
4636 /* and copy out date */
4637 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4638 *((u_short *)dptr) = shortTemp;
4641 /* copy out file length */
4642 *((u_long *)dptr) = 0;
4645 lock_ConvertWToR(&scp->rw);
4646 attr = smb_Attributes(scp);
4647 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4648 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4649 attr |= SMB_ATTR_HIDDEN;
4653 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4656 shortTemp = (unsigned short) (dosTime & 0xffff);
4657 *((u_short *)dptr) = shortTemp;
4660 /* and copy out date */
4661 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4662 *((u_short *)dptr) = shortTemp;
4665 /* copy out file length */
4666 *((u_long *)dptr) = scp->length.LowPart;
4668 lock_ReleaseRead(&scp->rw);
4670 cm_ReleaseSCache(scp);
4673 /* now free the patches */
4674 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4675 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4679 /* and mark the list as empty */
4680 *dirPatchespp = NULL;
4686 /* SMB_COM_SEARCH */
4687 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4693 clientchar_t *pathp;
4694 cm_dirEntry_t *dep = 0;
4696 smb_dirListPatch_t *dirListPatchesp;
4697 smb_dirListPatch_t *curPatchp;
4701 osi_hyper_t dirLength;
4702 osi_hyper_t bufferOffset;
4703 osi_hyper_t curOffset;
4705 unsigned char *inCookiep;
4706 smb_dirSearch_t *dsp;
4710 unsigned long clientCookie;
4711 cm_pageHeader_t *pageHeaderp;
4712 cm_user_t *userp = NULL;
4714 clientchar_t mask[12];
4716 long nextEntryCookie;
4717 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4718 char resByte; /* reserved byte from the cookie */
4719 char *op; /* output data ptr */
4720 char *origOp; /* original value of op */
4721 cm_space_t *spacep; /* for pathname buffer */
4725 clientchar_t *tidPathp = 0;
4732 maxCount = smb_GetSMBParm(inp, 0);
4734 dirListPatchesp = NULL;
4736 caseFold = CM_FLAG_CASEFOLD;
4738 tp = smb_GetSMBData(inp, NULL);
4739 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4740 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4742 return CM_ERROR_BADSMB;
4744 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4746 return CM_ERROR_BADSMB;
4748 /* We can handle long names */
4749 if (vcp->flags & SMB_VCFLAG_USENT)
4750 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4752 /* make sure we got a whole search status */
4753 if (dataLength < 21) {
4754 nextCookie = 0; /* start at the beginning of the dir */
4757 attribute = smb_GetSMBParm(inp, 1);
4759 /* handle volume info in another function */
4760 if (attribute & 0x8)
4761 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4763 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4764 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4766 if (*pathp == 0) { /* null pathp, treat as root dir */
4767 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4768 return CM_ERROR_NOFILES;
4772 dsp = smb_NewDirSearch(0);
4773 dsp->attribute = attribute;
4774 smb_Get8Dot3MaskFromPath(mask, pathp);
4775 memcpy(dsp->mask, mask, 12);
4777 /* track if this is likely to match a lot of entries */
4778 if (smb_Is8Dot3StarMask(mask))
4783 /* pull the next cookie value out of the search status block */
4784 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4785 + (inCookiep[16]<<24);
4786 dsp = smb_FindDirSearch(inCookiep[12]);
4788 /* can't find dir search status; fatal error */
4789 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4790 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4791 return CM_ERROR_BADFD;
4793 attribute = dsp->attribute;
4794 resByte = inCookiep[0];
4796 /* copy out client cookie, in host byte order. Don't bother
4797 * interpreting it, since we're just passing it through, anyway.
4799 memcpy(&clientCookie, &inCookiep[17], 4);
4801 memcpy(mask, dsp->mask, 12);
4803 /* assume we're doing a star match if it has continued for more
4809 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4810 nextCookie, dsp->cookie, attribute);
4812 userp = smb_GetUserFromVCP(vcp, inp);
4814 /* try to get the vnode for the path name next */
4815 lock_ObtainMutex(&dsp->mx);
4818 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4822 spacep = inp->spacep;
4823 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4824 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4826 lock_ReleaseMutex(&dsp->mx);
4827 cm_ReleaseUser(userp);
4828 smb_DeleteDirSearch(dsp);
4829 smb_ReleaseDirSearch(dsp);
4830 return CM_ERROR_NOFILES;
4832 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4833 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4835 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4836 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4839 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4842 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4843 cm_ReleaseSCache(scp);
4844 lock_ReleaseMutex(&dsp->mx);
4845 cm_ReleaseUser(userp);
4846 smb_DeleteDirSearch(dsp);
4847 smb_ReleaseDirSearch(dsp);
4848 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4849 return CM_ERROR_PATH_NOT_COVERED;
4851 return CM_ERROR_NOSUCHPATH;
4853 #endif /* DFS_SUPPORT */
4856 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4857 /* we need one hold for the entry we just stored into,
4858 * and one for our own processing. When we're done with this
4859 * function, we'll drop the one for our own processing.
4860 * We held it once from the namei call, and so we do another hold
4864 lock_ObtainWrite(&scp->rw);
4865 dsp->flags |= SMB_DIRSEARCH_BULKST;
4866 lock_ReleaseWrite(&scp->rw);
4869 lock_ReleaseMutex(&dsp->mx);
4871 cm_ReleaseUser(userp);
4872 smb_DeleteDirSearch(dsp);
4873 smb_ReleaseDirSearch(dsp);
4877 /* reserves space for parameter; we'll adjust it again later to the
4878 * real count of the # of entries we returned once we've actually
4879 * assembled the directory listing.
4881 smb_SetSMBParm(outp, 0, 0);
4883 /* get the directory size */
4884 lock_ObtainWrite(&scp->rw);
4885 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4886 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4888 lock_ReleaseWrite(&scp->rw);
4889 cm_ReleaseSCache(scp);
4890 cm_ReleaseUser(userp);
4891 smb_DeleteDirSearch(dsp);
4892 smb_ReleaseDirSearch(dsp);
4896 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4898 dirLength = scp->length;
4900 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4901 curOffset.HighPart = 0;
4902 curOffset.LowPart = nextCookie;
4903 origOp = op = smb_GetSMBData(outp, NULL);
4904 /* and write out the basic header */
4905 *op++ = 5; /* variable block */
4906 op += 2; /* skip vbl block length; we'll fill it in later */
4910 clientchar_t *actualName = NULL;
4911 int free_actualName = 0;
4912 clientchar_t shortName[13];
4913 clientchar_t *shortNameEnd;
4915 /* make sure that curOffset.LowPart doesn't point to the first
4916 * 32 bytes in the 2nd through last dir page, and that it doesn't
4917 * point at the first 13 32-byte chunks in the first dir page,
4918 * since those are dir and page headers, and don't contain useful
4921 temp = curOffset.LowPart & (2048-1);
4922 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4923 /* we're in the first page */
4924 if (temp < 13*32) temp = 13*32;
4927 /* we're in a later dir page */
4928 if (temp < 32) temp = 32;
4931 /* make sure the low order 5 bits are zero */
4934 /* now put temp bits back ito curOffset.LowPart */
4935 curOffset.LowPart &= ~(2048-1);
4936 curOffset.LowPart |= temp;
4938 /* check if we've returned all the names that will fit in the
4941 if (returnedNames >= maxCount) {
4942 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4943 returnedNames, maxCount);
4947 /* check if we've passed the dir's EOF */
4948 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4950 /* see if we can use the bufferp we have now; compute in which page
4951 * the current offset would be, and check whether that's the offset
4952 * of the buffer we have. If not, get the buffer.
4954 thyper.HighPart = curOffset.HighPart;
4955 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4956 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4959 buf_Release(bufferp);
4962 lock_ReleaseWrite(&scp->rw);
4963 code = buf_Get(scp, &thyper, &req, &bufferp);
4964 lock_ObtainMutex(&dsp->mx);
4966 /* now, if we're doing a star match, do bulk fetching of all of
4967 * the status info for files in the dir.
4970 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4972 lock_ObtainWrite(&scp->rw);
4973 lock_ReleaseMutex(&dsp->mx);
4975 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4979 bufferOffset = thyper;
4981 /* now get the data in the cache */
4983 code = cm_SyncOp(scp, bufferp, userp, &req,
4985 CM_SCACHESYNC_NEEDCALLBACK |
4986 CM_SCACHESYNC_READ);
4988 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4992 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4994 if (cm_HaveBuffer(scp, bufferp, 0)) {
4995 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4999 /* otherwise, load the buffer and try again */
5000 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5002 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5003 scp, bufferp, code);
5008 buf_Release(bufferp);
5012 } /* if (wrong buffer) ... */
5014 /* now we have the buffer containing the entry we're interested in; copy
5015 * it out if it represents a non-deleted entry.
5017 entryInDir = curOffset.LowPart & (2048-1);
5018 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5020 /* page header will help tell us which entries are free. Page header
5021 * can change more often than once per buffer, since AFS 3 dir page size
5022 * may be less than (but not more than a buffer package buffer.
5024 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5025 temp &= ~(2048 - 1); /* turn off intra-page bits */
5026 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5028 /* now determine which entry we're looking at in the page. If it is
5029 * free (there's a free bitmap at the start of the dir), we should
5030 * skip these 32 bytes.
5032 slotInPage = (entryInDir & 0x7e0) >> 5;
5033 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5034 /* this entry is free */
5035 numDirChunks = 1; /* only skip this guy */
5039 tp = bufferp->datap + entryInBuffer;
5040 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5042 /* while we're here, compute the next entry's location, too,
5043 * since we'll need it when writing out the cookie into the dir
5046 * XXXX Probably should do more sanity checking.
5048 numDirChunks = cm_NameEntries(dep->name, NULL);
5050 /* compute the offset of the cookie representing the next entry */
5051 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5053 /* Compute 8.3 name if necessary */
5054 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5055 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5058 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5059 actualName = shortName;
5060 free_actualName = 0;
5062 free_actualName = 1;
5065 if (actualName == NULL) {
5066 /* Couldn't convert the name for some reason */
5067 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5068 osi_LogSaveString(smb_logp, dep->name));
5072 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5073 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5074 osi_LogSaveClientString(smb_logp, actualName));
5076 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5077 /* this is one of the entries to use: it is not deleted
5078 * and it matches the star pattern we're looking for.
5081 /* Eliminate entries that don't match requested
5084 /* no hidden files */
5085 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5086 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5090 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5092 /* We have already done the cm_TryBulkStat above */
5093 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5094 fileType = cm_FindFileType(&fid);
5095 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5096 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5098 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5099 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5100 fileType == CM_SCACHETYPE_DFSLINK ||
5101 fileType == CM_SCACHETYPE_INVALID)
5102 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5107 memcpy(op, mask, 11); op += 11;
5108 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5109 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5110 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5111 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5112 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5113 memcpy(op, &clientCookie, 4); op += 4;
5115 /* now we emit the attribute. This is sort of tricky,
5116 * since we need to really stat the file to find out
5117 * what type of entry we've got. Right now, we're
5118 * copying out data from a buffer, while holding the
5119 * scp locked, so it isn't really convenient to stat
5120 * something now. We'll put in a place holder now,
5121 * and make a second pass before returning this to get
5122 * the real attributes. So, we just skip the data for
5123 * now, and adjust it later. We allocate a patch
5124 * record to make it easy to find this point later.
5125 * The replay will happen at a time when it is safe to
5126 * unlock the directory.
5128 curPatchp = malloc(sizeof(*curPatchp));
5129 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5130 curPatchp->dptr = op;
5131 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5133 /* do hidden attribute here since name won't be around when applying
5137 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5138 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5140 curPatchp->flags = 0;
5142 op += 9; /* skip attr, time, date and size */
5144 /* zero out name area. The spec says to pad with
5145 * spaces, but Samba doesn't, and neither do we.
5149 /* finally, we get to copy out the name; we know that
5150 * it fits in 8.3 or the pattern wouldn't match, but it
5151 * never hurts to be sure.
5153 cm_ClientStringToUtf8(actualName, -1, op, 13);
5154 if (smb_StoreAnsiFilenames)
5156 /* This is a UCHAR field, which is ASCII even if Unicode
5159 /* Uppercase if requested by client */
5160 if (!KNOWS_LONG_NAMES(inp))
5165 /* now, adjust the # of entries copied */
5167 } /* if we're including this name */
5170 if (free_actualName && actualName) {
5175 /* and adjust curOffset to be where the new cookie is */
5176 thyper.HighPart = 0;
5177 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5178 curOffset = LargeIntegerAdd(thyper, curOffset);
5179 } /* while copying data for dir listing */
5181 /* release the mutex */
5182 lock_ReleaseWrite(&scp->rw);
5184 buf_Release(bufferp);
5188 /* apply and free last set of patches; if not doing a star match, this
5189 * will be empty, but better safe (and freeing everything) than sorry.
5191 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5193 /* special return code for unsuccessful search */
5194 if (code == 0 && dataLength < 21 && returnedNames == 0)
5195 code = CM_ERROR_NOFILES;
5197 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5198 returnedNames, code);
5201 smb_DeleteDirSearch(dsp);
5202 smb_ReleaseDirSearch(dsp);
5203 cm_ReleaseSCache(scp);
5204 cm_ReleaseUser(userp);
5208 /* finalize the output buffer */
5209 smb_SetSMBParm(outp, 0, returnedNames);
5210 temp = (long) (op - origOp);
5211 smb_SetSMBDataLength(outp, temp);
5213 /* the data area is a variable block, which has a 5 (already there)
5214 * followed by the length of the # of data bytes. We now know this to
5215 * be "temp," although that includes the 3 bytes of vbl block header.
5216 * Deduct for them and fill in the length field.
5218 temp -= 3; /* deduct vbl block info */
5219 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5220 origOp[1] = (unsigned char)(temp & 0xff);
5221 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5222 if (returnedNames == 0)
5223 smb_DeleteDirSearch(dsp);
5224 smb_ReleaseDirSearch(dsp);
5225 cm_ReleaseSCache(scp);
5226 cm_ReleaseUser(userp);
5231 /* verify that this is a valid path to a directory. I don't know why they
5232 * don't use the get file attributes call.
5234 * SMB_COM_CHECK_DIRECTORY
5236 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5238 clientchar_t *pathp;
5240 cm_scache_t *rootScp;
5241 cm_scache_t *newScp;
5245 clientchar_t *tidPathp;
5251 pdata = smb_GetSMBData(inp, NULL);
5252 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5254 return CM_ERROR_BADSMB;
5255 osi_Log1(smb_logp, "SMB receive check path %S",
5256 osi_LogSaveClientString(smb_logp, pathp));
5258 rootScp = cm_data.rootSCachep;
5260 userp = smb_GetUserFromVCP(vcp, inp);
5262 caseFold = CM_FLAG_CASEFOLD;
5264 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5266 cm_ReleaseUser(userp);
5267 return CM_ERROR_NOSUCHPATH;
5269 code = cm_NameI(rootScp, pathp,
5270 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5271 userp, tidPathp, &req, &newScp);
5274 cm_ReleaseUser(userp);
5279 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5280 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5281 cm_ReleaseSCache(newScp);
5282 cm_ReleaseUser(userp);
5283 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5284 return CM_ERROR_PATH_NOT_COVERED;
5286 return CM_ERROR_NOSUCHPATH;
5288 #endif /* DFS_SUPPORT */
5290 /* now lock the vnode with a callback; returns with newScp locked */
5291 lock_ObtainWrite(&newScp->rw);
5292 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5293 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5295 if (code != CM_ERROR_NOACCESS) {
5296 lock_ReleaseWrite(&newScp->rw);
5297 cm_ReleaseSCache(newScp);
5298 cm_ReleaseUser(userp);
5302 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5305 attrs = smb_Attributes(newScp);
5307 if (!(attrs & SMB_ATTR_DIRECTORY))
5308 code = CM_ERROR_NOTDIR;
5310 lock_ReleaseWrite(&newScp->rw);
5312 cm_ReleaseSCache(newScp);
5313 cm_ReleaseUser(userp);
5317 /* SMB_COM_SET_INFORMATION */
5318 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5320 clientchar_t *pathp;
5322 cm_scache_t *rootScp;
5323 unsigned short attribute;
5325 cm_scache_t *newScp;
5329 clientchar_t *tidPathp;
5335 /* decode basic attributes we're passed */
5336 attribute = smb_GetSMBParm(inp, 0);
5337 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5339 datap = smb_GetSMBData(inp, NULL);
5340 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5342 return CM_ERROR_BADSMB;
5344 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5345 dosTime, attribute);
5347 rootScp = cm_data.rootSCachep;
5349 userp = smb_GetUserFromVCP(vcp, inp);
5351 caseFold = CM_FLAG_CASEFOLD;
5353 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5355 cm_ReleaseUser(userp);
5356 return CM_ERROR_NOSUCHFILE;
5358 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5359 tidPathp, &req, &newScp);
5362 cm_ReleaseUser(userp);
5367 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5368 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5369 cm_ReleaseSCache(newScp);
5370 cm_ReleaseUser(userp);
5371 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5372 return CM_ERROR_PATH_NOT_COVERED;
5374 return CM_ERROR_NOSUCHPATH;
5376 #endif /* DFS_SUPPORT */
5378 /* now lock the vnode with a callback; returns with newScp locked; we
5379 * need the current status to determine what the new status is, in some
5382 lock_ObtainWrite(&newScp->rw);
5383 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5384 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5386 lock_ReleaseWrite(&newScp->rw);
5387 cm_ReleaseSCache(newScp);
5388 cm_ReleaseUser(userp);
5392 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5394 /* Check for RO volume */
5395 if (newScp->flags & CM_SCACHEFLAG_RO) {
5396 lock_ReleaseWrite(&newScp->rw);
5397 cm_ReleaseSCache(newScp);
5398 cm_ReleaseUser(userp);
5399 return CM_ERROR_READONLY;
5402 /* prepare for setattr call */
5405 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5406 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5408 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5409 /* we're told to make a writable file read-only */
5410 attr.unixModeBits = newScp->unixModeBits & ~0222;
5411 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5413 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5414 /* we're told to make a read-only file writable */
5415 attr.unixModeBits = newScp->unixModeBits | 0222;
5416 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5418 lock_ReleaseWrite(&newScp->rw);
5420 /* now call setattr */
5422 code = cm_SetAttr(newScp, &attr, userp, &req);
5426 cm_ReleaseSCache(newScp);
5427 cm_ReleaseUser(userp);
5433 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5435 clientchar_t *pathp;
5437 cm_scache_t *rootScp;
5438 cm_scache_t *newScp, *dscp;
5443 clientchar_t *tidPathp;
5445 clientchar_t *lastComp;
5451 datap = smb_GetSMBData(inp, NULL);
5452 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5454 return CM_ERROR_BADSMB;
5456 if (*pathp == 0) /* null path */
5459 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5460 osi_LogSaveClientString(smb_logp, pathp));
5462 rootScp = cm_data.rootSCachep;
5464 userp = smb_GetUserFromVCP(vcp, inp);
5466 /* we shouldn't need this for V3 requests, but we seem to */
5467 caseFold = CM_FLAG_CASEFOLD;
5469 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5471 cm_ReleaseUser(userp);
5472 return CM_ERROR_NOSUCHFILE;
5476 * XXX Strange hack XXX
5478 * As of Patch 5 (16 July 97), we are having the following problem:
5479 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5480 * requests to look up "desktop.ini" in all the subdirectories.
5481 * This can cause zillions of timeouts looking up non-existent cells
5482 * and volumes, especially in the top-level directory.
5484 * We have not found any way to avoid this or work around it except
5485 * to explicitly ignore the requests for mount points that haven't
5486 * yet been evaluated and for directories that haven't yet been
5489 * We should modify this hack to provide a fake desktop.ini file
5490 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5492 spacep = inp->spacep;
5493 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5494 #ifndef SPECIAL_FOLDERS
5495 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5496 code = cm_NameI(rootScp, spacep->wdata,
5497 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5498 userp, tidPathp, &req, &dscp);
5501 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5502 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5504 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5505 return CM_ERROR_PATH_NOT_COVERED;
5507 return CM_ERROR_NOSUCHPATH;
5509 #endif /* DFS_SUPPORT */
5510 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5511 code = CM_ERROR_NOSUCHFILE;
5512 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5513 cm_buf_t *bp = buf_Find(dscp, &hzero);
5518 code = CM_ERROR_NOSUCHFILE;
5520 cm_ReleaseSCache(dscp);
5522 cm_ReleaseUser(userp);
5527 #endif /* SPECIAL_FOLDERS */
5529 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5530 tidPathp, &req, &newScp);
5532 cm_ReleaseUser(userp);
5537 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5538 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5539 cm_ReleaseSCache(newScp);
5540 cm_ReleaseUser(userp);
5541 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5542 return CM_ERROR_PATH_NOT_COVERED;
5544 return CM_ERROR_NOSUCHPATH;
5546 #endif /* DFS_SUPPORT */
5548 /* now lock the vnode with a callback; returns with newScp locked */
5549 lock_ObtainWrite(&newScp->rw);
5550 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5551 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5553 lock_ReleaseWrite(&newScp->rw);
5554 cm_ReleaseSCache(newScp);
5555 cm_ReleaseUser(userp);
5559 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5561 attrs = smb_Attributes(newScp);
5563 smb_SetSMBParm(outp, 0, attrs);
5565 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5566 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5567 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5568 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5569 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5570 smb_SetSMBParm(outp, 5, 0);
5571 smb_SetSMBParm(outp, 6, 0);
5572 smb_SetSMBParm(outp, 7, 0);
5573 smb_SetSMBParm(outp, 8, 0);
5574 smb_SetSMBParm(outp, 9, 0);
5575 smb_SetSMBDataLength(outp, 0);
5576 lock_ReleaseWrite(&newScp->rw);
5578 cm_ReleaseSCache(newScp);
5579 cm_ReleaseUser(userp);
5584 /* SMB_COM_TREE_DISCONNECT */
5585 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5589 osi_Log0(smb_logp, "SMB receive tree disconnect");
5591 /* find the tree and free it */
5592 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5594 lock_ObtainWrite(&smb_rctLock);
5596 smb_ReleaseTID(tidp, TRUE);
5597 lock_ReleaseWrite(&smb_rctLock);
5604 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5607 clientchar_t *pathp;
5608 clientchar_t *lastNamep;
5617 clientchar_t *tidPathp;
5623 datap = smb_GetSMBData(inp, NULL);
5624 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5626 return CM_ERROR_BADSMB;
5628 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5630 #ifdef DEBUG_VERBOSE
5634 hexpath = osi_HexifyString( pathp );
5635 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5640 share = smb_GetSMBParm(inp, 0);
5641 attribute = smb_GetSMBParm(inp, 1);
5643 spacep = inp->spacep;
5644 /* smb_StripLastComponent will strip "::$DATA" if present */
5645 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5647 if (!cm_IsValidClientString(pathp)) {
5649 clientchar_t * hexp;
5651 hexp = cm_GetRawCharsAlloc(pathp, -1);
5652 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5653 osi_LogSaveClientString(smb_logp, hexp));
5657 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5659 return CM_ERROR_BADNTFILENAME;
5662 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5663 /* special case magic file name for receiving IOCTL requests
5664 * (since IOCTL calls themselves aren't getting through).
5666 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5667 smb_SetupIoctlFid(fidp, spacep);
5668 smb_SetSMBParm(outp, 0, fidp->fid);
5669 smb_SetSMBParm(outp, 1, 0); /* attrs */
5670 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5671 smb_SetSMBParm(outp, 3, 0);
5672 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5673 smb_SetSMBParm(outp, 5, 0x7fff);
5674 /* pass the open mode back */
5675 smb_SetSMBParm(outp, 6, (share & 0xf));
5676 smb_SetSMBDataLength(outp, 0);
5677 smb_ReleaseFID(fidp);
5681 userp = smb_GetUserFromVCP(vcp, inp);
5683 caseFold = CM_FLAG_CASEFOLD;
5685 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5687 cm_ReleaseUser(userp);
5688 return CM_ERROR_NOSUCHPATH;
5690 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5691 tidPathp, &req, &scp);
5694 cm_ReleaseUser(userp);
5699 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5700 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5701 cm_ReleaseSCache(scp);
5702 cm_ReleaseUser(userp);
5703 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5704 return CM_ERROR_PATH_NOT_COVERED;
5706 return CM_ERROR_NOSUCHPATH;
5708 #endif /* DFS_SUPPORT */
5710 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5712 cm_ReleaseSCache(scp);
5713 cm_ReleaseUser(userp);
5717 /* don't need callback to check file type, since file types never
5718 * change, and namei and cm_Lookup all stat the object at least once on
5719 * a successful return.
5721 if (scp->fileType != CM_SCACHETYPE_FILE) {
5722 cm_ReleaseSCache(scp);
5723 cm_ReleaseUser(userp);
5724 return CM_ERROR_ISDIR;
5727 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5728 osi_assertx(fidp, "null smb_fid_t");
5730 lock_ObtainMutex(&fidp->mx);
5731 if ((share & 0xf) == 0)
5732 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5733 else if ((share & 0xf) == 1)
5734 fidp->flags |= SMB_FID_OPENWRITE;
5736 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5740 fidp->userp = userp;
5742 /* and a pointer to the vnode */
5744 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5745 lock_ObtainWrite(&scp->rw);
5746 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5748 smb_SetSMBParm(outp, 0, fidp->fid);
5749 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5750 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5751 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5752 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5753 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5754 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5755 /* pass the open mode back; XXXX add access checks */
5756 smb_SetSMBParm(outp, 6, (share & 0xf));
5757 smb_SetSMBDataLength(outp, 0);
5758 lock_ReleaseMutex(&fidp->mx);
5759 lock_ReleaseRead(&scp->rw);
5762 cm_Open(scp, 0, userp);
5764 /* send and free packet */
5765 smb_ReleaseFID(fidp);
5766 cm_ReleaseUser(userp);
5767 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5771 typedef struct smb_unlinkRock {
5776 clientchar_t *maskp; /* pointer to the star pattern */
5779 cm_dirEntryList_t * matches;
5782 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5785 smb_unlinkRock_t *rockp;
5788 normchar_t matchName[MAX_PATH];
5792 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5793 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5794 caseFold |= CM_FLAG_8DOT3;
5796 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5797 /* Can't convert name */
5798 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5799 osi_LogSaveString(smb_logp, dep->name));
5803 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5805 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5806 !cm_Is8Dot3(matchName)) {
5807 cm_Gen8Dot3Name(dep, matchName, NULL);
5808 /* 8.3 matches are always case insensitive */
5809 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5812 osi_Log1(smb_logp, "Found match %S",
5813 osi_LogSaveClientString(smb_logp, matchName));
5815 cm_DirEntryListAdd(dep->name, &rockp->matches);
5819 /* If we made a case sensitive exact match, we might as well quit now. */
5820 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5821 code = CM_ERROR_STOPNOW;
5830 /* SMB_COM_DELETE */
5831 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5835 clientchar_t *pathp;
5839 clientchar_t *lastNamep;
5840 smb_unlinkRock_t rock;
5844 clientchar_t *tidPathp;
5848 memset(&rock, 0, sizeof(rock));
5850 attribute = smb_GetSMBParm(inp, 0);
5852 tp = smb_GetSMBData(inp, NULL);
5853 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5855 return CM_ERROR_BADSMB;
5857 osi_Log1(smb_logp, "SMB receive unlink %S",
5858 osi_LogSaveClientString(smb_logp, pathp));
5860 spacep = inp->spacep;
5861 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5863 userp = smb_GetUserFromVCP(vcp, inp);
5865 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5867 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5869 cm_ReleaseUser(userp);
5870 return CM_ERROR_NOSUCHPATH;
5872 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5875 cm_ReleaseUser(userp);
5880 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5881 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5882 cm_ReleaseSCache(dscp);
5883 cm_ReleaseUser(userp);
5884 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5885 return CM_ERROR_PATH_NOT_COVERED;
5887 return CM_ERROR_NOSUCHPATH;
5889 #endif /* DFS_SUPPORT */
5891 /* otherwise, scp points to the parent directory. */
5898 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5900 code = CM_ERROR_NOSUCHFILE;
5903 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5906 thyper.HighPart = 0;
5911 rock.matches = NULL;
5913 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5914 * match. If that fails, we do a case insensitve match.
5916 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5917 !smb_IsStarMask(rock.maskp)) {
5918 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5921 thyper.HighPart = 0;
5922 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5927 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5929 if (code == CM_ERROR_STOPNOW)
5932 if (code == 0 && rock.matches) {
5933 cm_dirEntryList_t * entry;
5935 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5936 normchar_t normalizedName[MAX_PATH];
5938 /* Note: entry->name is a non-normalized name */
5940 osi_Log1(smb_logp, "Unlinking %s",
5941 osi_LogSaveString(smb_logp, entry->name));
5943 /* We assume this works because entry->name was
5944 successfully converted in smb_UnlinkProc() once. */
5945 cm_FsStringToNormString(entry->name, -1,
5946 normalizedName, lengthof(normalizedName));
5948 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5950 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5951 smb_NotifyChange(FILE_ACTION_REMOVED,
5952 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5953 dscp, normalizedName, NULL, TRUE);
5957 cm_DirEntryListFree(&rock.matches);
5961 cm_ReleaseUser(userp);
5964 cm_ReleaseSCache(dscp);
5969 if (code == 0 && !rock.any)
5970 code = CM_ERROR_NOSUCHFILE;
5974 typedef struct smb_renameRock {
5975 cm_scache_t *odscp; /* old dir */
5976 cm_scache_t *ndscp; /* new dir */
5977 cm_user_t *userp; /* user */
5978 cm_req_t *reqp; /* request struct */
5979 smb_vc_t *vcp; /* virtual circuit */
5980 normchar_t *maskp; /* pointer to star pattern of old file name */
5981 int flags; /* tilde, casefold, etc */
5982 clientchar_t *newNamep; /* ptr to the new file's name */
5983 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5984 clientchar_t clOldName[MAX_PATH]; /* client name */
5988 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5991 smb_renameRock_t *rockp;
5994 normchar_t matchName[MAX_PATH];
5996 rockp = (smb_renameRock_t *) vrockp;
5998 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5999 /* Can't convert string */
6000 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6001 osi_LogSaveString(smb_logp, dep->name));
6005 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6006 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6007 caseFold |= CM_FLAG_8DOT3;
6009 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6011 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6012 !cm_Is8Dot3(matchName)) {
6013 cm_Gen8Dot3Name(dep, matchName, NULL);
6014 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6019 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6020 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6022 code = CM_ERROR_STOPNOW;
6032 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6035 cm_space_t *spacep = NULL;
6036 smb_renameRock_t rock;
6037 cm_scache_t *oldDscp = NULL;
6038 cm_scache_t *newDscp = NULL;
6039 cm_scache_t *tmpscp= NULL;
6040 cm_scache_t *tmpscp2 = NULL;
6041 clientchar_t *oldLastNamep;
6042 clientchar_t *newLastNamep;
6046 clientchar_t *tidPathp;
6050 userp = smb_GetUserFromVCP(vcp, inp);
6051 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6053 cm_ReleaseUser(userp);
6054 return CM_ERROR_NOSUCHPATH;
6058 memset(&rock, 0, sizeof(rock));
6060 spacep = inp->spacep;
6061 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6063 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6064 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6065 userp, tidPathp, &req, &oldDscp);
6067 cm_ReleaseUser(userp);
6072 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6073 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6074 cm_ReleaseSCache(oldDscp);
6075 cm_ReleaseUser(userp);
6076 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6077 return CM_ERROR_PATH_NOT_COVERED;
6079 return CM_ERROR_NOSUCHPATH;
6081 #endif /* DFS_SUPPORT */
6083 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6084 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6085 userp, tidPathp, &req, &newDscp);
6088 cm_ReleaseSCache(oldDscp);
6089 cm_ReleaseUser(userp);
6094 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6095 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6096 cm_ReleaseSCache(oldDscp);
6097 cm_ReleaseSCache(newDscp);
6098 cm_ReleaseUser(userp);
6099 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6100 return CM_ERROR_PATH_NOT_COVERED;
6102 return CM_ERROR_NOSUCHPATH;
6104 #endif /* DFS_SUPPORT */
6107 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6108 * next, get the component names, and lower case them.
6111 /* handle the old name first */
6113 oldLastNamep = oldPathp;
6117 /* and handle the new name, too */
6119 newLastNamep = newPathp;
6123 /* TODO: The old name could be a wildcard. The new name must not be */
6125 /* Check if the file already exists; if so return error */
6126 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6127 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6128 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6130 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6131 osi_LogSaveClientString(smb_logp, newLastNamep));
6133 /* Check if the old and the new names differ only in case. If so return
6134 * success, else return CM_ERROR_EXISTS
6136 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6138 /* This would be a success only if the old file is *as same as* the new file */
6139 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6141 if (tmpscp == tmpscp2)
6144 code = CM_ERROR_EXISTS;
6145 cm_ReleaseSCache(tmpscp2);
6148 code = CM_ERROR_NOSUCHFILE;
6151 /* file exist, do not rename, also fixes move */
6152 osi_Log0(smb_logp, "Can't rename. Target already exists");
6153 code = CM_ERROR_EXISTS;
6158 /* do the vnode call */
6159 rock.odscp = oldDscp;
6160 rock.ndscp = newDscp;
6164 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6166 code = CM_ERROR_NOSUCHFILE;
6169 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6170 rock.newNamep = newLastNamep;
6171 rock.fsOldName[0] = '\0';
6172 rock.clOldName[0] = '\0';
6175 /* Now search the directory for the pattern, and do the appropriate rename when found */
6176 thyper.LowPart = 0; /* search dir from here */
6177 thyper.HighPart = 0;
6179 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6180 if (code == 0 && !rock.any) {
6182 thyper.HighPart = 0;
6183 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6184 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6186 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6188 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6189 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6190 rock.ndscp, rock.newNamep, rock.userp,
6192 /* if the call worked, stop doing the search now, since we
6193 * really only want to rename one file.
6196 osi_Log0(smb_logp, "cm_Rename failure");
6197 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6198 } else if (code == 0) {
6199 code = CM_ERROR_NOSUCHFILE;
6202 /* Handle Change Notification */
6204 * Being lazy, not distinguishing between files and dirs in this
6205 * filter, since we'd have to do a lookup.
6208 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6209 if (oldDscp == newDscp) {
6210 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6211 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6212 filter, oldDscp, rock.clOldName,
6213 newLastNamep, TRUE);
6215 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6216 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6217 filter, oldDscp, rock.clOldName,
6219 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6220 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6221 filter, newDscp, newLastNamep,
6228 cm_ReleaseSCache(tmpscp);
6230 cm_ReleaseUser(userp);
6232 cm_ReleaseSCache(oldDscp);
6234 cm_ReleaseSCache(newDscp);
6242 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6245 cm_space_t *spacep = NULL;
6246 cm_scache_t *oldDscp = NULL;
6247 cm_scache_t *newDscp = NULL;
6248 cm_scache_t *tmpscp= NULL;
6249 cm_scache_t *tmpscp2 = NULL;
6250 cm_scache_t *sscp = NULL;
6251 clientchar_t *oldLastNamep;
6252 clientchar_t *newLastNamep;
6255 clientchar_t *tidPathp;
6259 userp = smb_GetUserFromVCP(vcp, inp);
6261 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6263 cm_ReleaseUser(userp);
6264 return CM_ERROR_NOSUCHPATH;
6269 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6271 spacep = inp->spacep;
6272 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6274 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6275 userp, tidPathp, &req, &oldDscp);
6277 cm_ReleaseUser(userp);
6282 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6283 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6284 cm_ReleaseSCache(oldDscp);
6285 cm_ReleaseUser(userp);
6286 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6287 return CM_ERROR_PATH_NOT_COVERED;
6289 return CM_ERROR_NOSUCHPATH;
6291 #endif /* DFS_SUPPORT */
6293 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6294 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6295 userp, tidPathp, &req, &newDscp);
6297 cm_ReleaseSCache(oldDscp);
6298 cm_ReleaseUser(userp);
6303 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6304 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6305 cm_ReleaseSCache(newDscp);
6306 cm_ReleaseSCache(oldDscp);
6307 cm_ReleaseUser(userp);
6308 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6309 return CM_ERROR_PATH_NOT_COVERED;
6311 return CM_ERROR_NOSUCHPATH;
6313 #endif /* DFS_SUPPORT */
6315 /* Now, although we did two lookups for the two directories (because the same
6316 * directory can be referenced through different paths), we only allow hard links
6317 * within the same directory. */
6318 if (oldDscp != newDscp) {
6319 cm_ReleaseSCache(oldDscp);
6320 cm_ReleaseSCache(newDscp);
6321 cm_ReleaseUser(userp);
6322 return CM_ERROR_CROSSDEVLINK;
6325 /* handle the old name first */
6327 oldLastNamep = oldPathp;
6331 /* and handle the new name, too */
6333 newLastNamep = newPathp;
6337 /* now lookup the old name */
6338 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6339 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6341 cm_ReleaseSCache(oldDscp);
6342 cm_ReleaseSCache(newDscp);
6343 cm_ReleaseUser(userp);
6347 /* Check if the file already exists; if so return error */
6348 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6349 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6350 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6352 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6353 osi_LogSaveClientString(smb_logp, newLastNamep));
6355 /* if the existing link is to the same file, then we return success */
6357 if(sscp == tmpscp) {
6360 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6361 code = CM_ERROR_EXISTS;
6366 cm_ReleaseSCache(tmpscp);
6367 cm_ReleaseSCache(sscp);
6368 cm_ReleaseSCache(newDscp);
6369 cm_ReleaseSCache(oldDscp);
6370 cm_ReleaseUser(userp);
6374 /* now create the hardlink */
6375 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6376 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6377 osi_Log1(smb_logp," Link returns 0x%x", code);
6379 /* Handle Change Notification */
6381 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6382 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6383 smb_NotifyChange(FILE_ACTION_ADDED,
6384 filter, newDscp, newLastNamep,
6389 cm_ReleaseSCache(tmpscp);
6390 cm_ReleaseUser(userp);
6391 cm_ReleaseSCache(sscp);
6392 cm_ReleaseSCache(oldDscp);
6393 cm_ReleaseSCache(newDscp);
6397 /* SMB_COM_RENAME */
6399 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6401 clientchar_t *oldPathp;
6402 clientchar_t *newPathp;
6406 tp = smb_GetSMBData(inp, NULL);
6407 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6409 return CM_ERROR_BADSMB;
6410 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6412 return CM_ERROR_BADSMB;
6414 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6415 osi_LogSaveClientString(smb_logp, oldPathp),
6416 osi_LogSaveClientString(smb_logp, newPathp));
6418 if (!cm_IsValidClientString(newPathp)) {
6420 clientchar_t * hexp;
6422 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6423 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6424 osi_LogSaveClientString(smb_logp, hexp));
6428 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6430 return CM_ERROR_BADNTFILENAME;
6433 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6435 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6441 typedef struct smb_rmdirRock {
6445 normchar_t *maskp; /* pointer to the star pattern */
6448 cm_dirEntryList_t * matches;
6451 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6454 smb_rmdirRock_t *rockp;
6456 normchar_t matchName[MAX_PATH];
6458 rockp = (smb_rmdirRock_t *) vrockp;
6460 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6461 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6462 osi_LogSaveString(smb_logp, dep->name));
6466 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6467 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6469 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6471 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6472 !cm_Is8Dot3(matchName)) {
6473 cm_Gen8Dot3Name(dep, matchName, NULL);
6474 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6479 cm_DirEntryListAdd(dep->name, &rockp->matches);
6486 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6489 clientchar_t *pathp;
6493 clientchar_t *lastNamep;
6494 smb_rmdirRock_t rock;
6498 clientchar_t *tidPathp;
6502 memset(&rock, 0, sizeof(rock));
6504 tp = smb_GetSMBData(inp, NULL);
6505 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6507 return CM_ERROR_BADSMB;
6509 spacep = inp->spacep;
6510 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6512 userp = smb_GetUserFromVCP(vcp, inp);
6514 caseFold = CM_FLAG_CASEFOLD;
6516 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6518 cm_ReleaseUser(userp);
6519 return CM_ERROR_NOSUCHPATH;
6521 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6522 userp, tidPathp, &req, &dscp);
6525 cm_ReleaseUser(userp);
6530 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6531 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6532 cm_ReleaseSCache(dscp);
6533 cm_ReleaseUser(userp);
6534 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6535 return CM_ERROR_PATH_NOT_COVERED;
6537 return CM_ERROR_NOSUCHPATH;
6539 #endif /* DFS_SUPPORT */
6541 /* otherwise, scp points to the parent directory. */
6548 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6550 code = CM_ERROR_NOSUCHFILE;
6553 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6556 thyper.HighPart = 0;
6560 rock.matches = NULL;
6562 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6563 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6564 if (code == 0 && !rock.any) {
6566 thyper.HighPart = 0;
6567 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6568 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6571 if (code == 0 && rock.matches) {
6572 cm_dirEntryList_t * entry;
6574 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6575 clientchar_t clientName[MAX_PATH];
6577 /* We assume this will succeed because smb_RmdirProc()
6578 successfully converted entry->name once above. */
6579 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6581 osi_Log1(smb_logp, "Removing directory %s",
6582 osi_LogSaveString(smb_logp, entry->name));
6584 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6586 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6587 smb_NotifyChange(FILE_ACTION_REMOVED,
6588 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6589 dscp, clientName, NULL, TRUE);
6595 cm_DirEntryListFree(&rock.matches);
6598 cm_ReleaseUser(userp);
6601 cm_ReleaseSCache(dscp);
6603 if (code == 0 && !rock.any)
6604 code = CM_ERROR_NOSUCHFILE;
6613 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6623 fid = smb_GetSMBParm(inp, 0);
6625 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6627 fid = smb_ChainFID(fid, inp);
6628 fidp = smb_FindFID(vcp, fid, 0);
6630 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6632 return CM_ERROR_BADFD;
6634 userp = smb_GetUserFromVCP(vcp, inp);
6636 lock_ObtainMutex(&fidp->mx);
6637 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6638 cm_ReleaseUser(userp);
6639 lock_ReleaseMutex(&fidp->mx);
6640 smb_ReleaseFID(fidp);
6641 return CM_ERROR_BADFD;
6644 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6645 lock_ReleaseMutex(&fidp->mx);
6646 cm_ReleaseUser(userp);
6647 smb_CloseFID(vcp, fidp, NULL, 0);
6648 smb_ReleaseFID(fidp);
6649 return CM_ERROR_NOSUCHFILE;
6652 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6653 cm_scache_t * scp = fidp->scp;
6655 lock_ReleaseMutex(&fidp->mx);
6656 code = cm_FSync(scp, userp, &req);
6657 cm_ReleaseSCache(scp);
6659 lock_ReleaseMutex(&fidp->mx);
6663 cm_ReleaseUser(userp);
6664 smb_ReleaseFID(fidp);
6668 struct smb_FullNameRock {
6671 clientchar_t *fullName;
6672 fschar_t *originalName;
6675 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6678 normchar_t matchName[MAX_PATH];
6679 struct smb_FullNameRock *vrockp;
6681 vrockp = (struct smb_FullNameRock *)rockp;
6683 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6684 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6685 osi_LogSaveString(smb_logp, dep->name));
6689 if (!cm_Is8Dot3(matchName)) {
6690 clientchar_t shortName[13];
6692 cm_Gen8Dot3Name(dep, shortName, NULL);
6694 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6695 vrockp->fullName = cm_ClientStrDup(matchName);
6696 vrockp->originalName = cm_FsStrDup(dep->name);
6697 return CM_ERROR_STOPNOW;
6700 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6701 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6702 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6703 vrockp->fullName = cm_ClientStrDup(matchName);
6704 vrockp->originalName = cm_FsStrDup(dep->name);
6705 return CM_ERROR_STOPNOW;
6710 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6711 clientchar_t **newPathp, fschar_t ** originalPathp,
6712 cm_user_t *userp, cm_req_t *reqp)
6714 struct smb_FullNameRock rock;
6717 memset(&rock, 0, sizeof(rock));
6721 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6722 if (code == CM_ERROR_STOPNOW) {
6723 *newPathp = rock.fullName;
6724 *originalPathp = rock.originalName;
6726 *newPathp = cm_ClientStrDup(pathp);
6727 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6731 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6732 afs_uint32 dosTime) {
6735 cm_scache_t *dscp = NULL;
6736 clientchar_t *pathp = NULL;
6737 cm_scache_t * scp = NULL;
6738 cm_scache_t *delscp = NULL;
6739 int nullcreator = 0;
6741 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6742 fidp, fidp->fid, scp, vcp);
6745 lock_ObtainMutex(&fidp->mx);
6746 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6748 lock_ReleaseMutex(&fidp->mx);
6749 osi_Log0(smb_logp, " No user specified. Not closing fid");
6750 return CM_ERROR_BADFD;
6753 userp = fidp->userp; /* no hold required since fidp is held
6754 throughout the function */
6755 lock_ReleaseMutex(&fidp->mx);
6760 lock_ObtainWrite(&smb_rctLock);
6761 if (fidp->deleteOk) {
6762 osi_Log0(smb_logp, " Fid already closed.");
6763 lock_ReleaseWrite(&smb_rctLock);
6764 return CM_ERROR_BADFD;
6767 lock_ReleaseWrite(&smb_rctLock);
6769 lock_ObtainMutex(&fidp->mx);
6770 if (fidp->NTopen_dscp) {
6771 dscp = fidp->NTopen_dscp;
6772 cm_HoldSCache(dscp);
6775 if (fidp->NTopen_pathp)
6776 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6783 /* Don't jump the gun on an async raw write */
6784 while (fidp->raw_writers) {
6785 lock_ReleaseMutex(&fidp->mx);
6786 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6787 lock_ObtainMutex(&fidp->mx);
6790 /* watch for ioctl closes, and read-only opens */
6792 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6793 == SMB_FID_OPENWRITE) {
6794 if (dosTime != 0 && dosTime != -1) {
6795 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6796 /* This fixes defect 10958 */
6797 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6798 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6800 if (smb_AsyncStore != 2) {
6801 lock_ReleaseMutex(&fidp->mx);
6802 code = cm_FSync(scp, userp, &req);
6803 lock_ObtainMutex(&fidp->mx);
6809 /* unlock any pending locks */
6810 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6811 scp->fileType == CM_SCACHETYPE_FILE) {
6815 lock_ReleaseMutex(&fidp->mx);
6817 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6819 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6820 lock_ObtainWrite(&scp->rw);
6822 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6823 CM_SCACHESYNC_NEEDCALLBACK
6824 | CM_SCACHESYNC_GETSTATUS
6825 | CM_SCACHESYNC_LOCK);
6829 "smb CoreClose SyncOp failure code 0x%x", tcode);
6830 goto post_syncopdone;
6833 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6835 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6839 lock_ReleaseWrite(&scp->rw);
6840 lock_ObtainMutex(&fidp->mx);
6843 if (fidp->flags & SMB_FID_DELONCLOSE) {
6844 clientchar_t *fullPathp = NULL;
6845 fschar_t *originalNamep = NULL;
6847 lock_ReleaseMutex(&fidp->mx);
6849 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6854 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6855 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6856 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6858 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6859 smb_NotifyChange(FILE_ACTION_REMOVED,
6860 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6861 dscp, fullPathp, NULL, TRUE);
6864 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6866 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6867 smb_NotifyChange(FILE_ACTION_REMOVED,
6868 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6869 dscp, fullPathp, NULL, TRUE);
6876 free(originalNamep);
6878 lock_ObtainMutex(&fidp->mx);
6879 fidp->flags &= ~SMB_FID_DELONCLOSE;
6882 /* if this was a newly created file, then clear the creator
6883 * in the stat cache entry. */
6884 if (fidp->flags & SMB_FID_CREATED) {
6886 fidp->flags &= ~SMB_FID_CREATED;
6889 if (fidp->flags & SMB_FID_NTOPEN) {
6890 cm_ReleaseSCache(fidp->NTopen_dscp);
6891 fidp->NTopen_dscp = NULL;
6892 free(fidp->NTopen_pathp);
6893 fidp->NTopen_pathp = NULL;
6894 fidp->flags &= ~SMB_FID_NTOPEN;
6896 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6897 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6900 if (fidp->NTopen_wholepathp) {
6901 free(fidp->NTopen_wholepathp);
6902 fidp->NTopen_wholepathp = NULL;
6906 cm_ReleaseSCache(fidp->scp);
6909 lock_ReleaseMutex(&fidp->mx);
6912 cm_ReleaseSCache(dscp);
6915 cm_ReleaseSCache(delscp);
6919 lock_ObtainWrite(&scp->rw);
6920 if (nullcreator && scp->creator == userp)
6921 scp->creator = NULL;
6922 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6923 lock_ReleaseWrite(&scp->rw);
6924 cm_ReleaseSCache(scp);
6934 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6942 fid = smb_GetSMBParm(inp, 0);
6943 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6945 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6947 fid = smb_ChainFID(fid, inp);
6948 fidp = smb_FindFID(vcp, fid, 0);
6950 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
6952 return CM_ERROR_BADFD;
6955 userp = smb_GetUserFromVCP(vcp, inp);
6957 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6959 smb_ReleaseFID(fidp);
6960 cm_ReleaseUser(userp);
6965 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6967 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6968 cm_user_t *userp, long *readp)
6974 osi_hyper_t fileLength;
6976 osi_hyper_t lastByte;
6977 osi_hyper_t bufferOffset;
6981 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6984 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6985 fidp->fid, offsetp->LowPart, count);
6989 lock_ObtainMutex(&fidp->mx);
6990 /* make sure we have a readable FD */
6991 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6992 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6993 fidp->fid, fidp->flags);
6994 lock_ReleaseMutex(&fidp->mx);
6995 code = CM_ERROR_BADFDOP;
7000 lock_ReleaseMutex(&fidp->mx);
7001 code = CM_ERROR_BADFD;
7012 lock_ObtainWrite(&scp->rw);
7014 if (offset.HighPart == 0) {
7015 chunk = offset.LowPart >> cm_logChunkSize;
7016 if (chunk != fidp->curr_chunk) {
7017 fidp->prev_chunk = fidp->curr_chunk;
7018 fidp->curr_chunk = chunk;
7020 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7023 lock_ReleaseMutex(&fidp->mx);
7025 /* start by looking up the file's end */
7026 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7027 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7031 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7033 /* now we have the entry locked, look up the length */
7034 fileLength = scp->length;
7036 /* adjust count down so that it won't go past EOF */
7037 thyper.LowPart = count;
7038 thyper.HighPart = 0;
7039 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7041 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7042 /* we'd read past EOF, so just stop at fileLength bytes.
7043 * Start by computing how many bytes remain in the file.
7045 thyper = LargeIntegerSubtract(fileLength, offset);
7047 /* if we are past EOF, read 0 bytes */
7048 if (LargeIntegerLessThanZero(thyper))
7051 count = thyper.LowPart;
7056 /* now, copy the data one buffer at a time,
7057 * until we've filled the request packet
7060 /* if we've copied all the data requested, we're done */
7061 if (count <= 0) break;
7063 /* otherwise, load up a buffer of data */
7064 thyper.HighPart = offset.HighPart;
7065 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7066 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7069 buf_Release(bufferp);
7072 lock_ReleaseWrite(&scp->rw);
7074 code = buf_Get(scp, &thyper, &req, &bufferp);
7076 lock_ObtainWrite(&scp->rw);
7077 if (code) goto done;
7078 bufferOffset = thyper;
7080 /* now get the data in the cache */
7082 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7083 CM_SCACHESYNC_NEEDCALLBACK |
7084 CM_SCACHESYNC_READ);
7088 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7090 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7092 /* otherwise, load the buffer and try again */
7093 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7097 buf_Release(bufferp);
7101 } /* if (wrong buffer) ... */
7103 /* now we have the right buffer loaded. Copy out the
7104 * data from here to the user's buffer.
7106 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7108 /* and figure out how many bytes we want from this buffer */
7109 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7110 if (nbytes > count) nbytes = count; /* don't go past EOF */
7112 /* now copy the data */
7113 memcpy(op, bufferp->datap + bufIndex, nbytes);
7115 /* adjust counters, pointers, etc. */
7118 thyper.LowPart = nbytes;
7119 thyper.HighPart = 0;
7120 offset = LargeIntegerAdd(thyper, offset);
7124 lock_ReleaseWrite(&scp->rw);
7126 buf_Release(bufferp);
7128 if (code == 0 && sequential)
7129 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7131 cm_ReleaseSCache(scp);
7134 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7135 fidp->fid, code, *readp);
7140 * smb_WriteData -- common code for Write and Raw Write
7142 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7143 cm_user_t *userp, long *writtenp)
7145 osi_hyper_t offset = *offsetp;
7148 cm_scache_t *scp = NULL;
7149 osi_hyper_t fileLength; /* file's length at start of write */
7150 osi_hyper_t minLength; /* don't read past this */
7151 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7152 cm_buf_t *bufferp = NULL;
7153 osi_hyper_t thyper; /* hyper tmp variable */
7154 osi_hyper_t bufferOffset;
7155 afs_uint32 bufIndex; /* index in buffer where our data is */
7156 int doWriteBack = 0;
7157 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7161 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7162 fidp->fid, offsetp->LowPart, count);
7166 lock_ObtainMutex(&fidp->mx);
7167 /* make sure we have a writable FD */
7168 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7169 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7170 fidp->fid, fidp->flags);
7171 lock_ReleaseMutex(&fidp->mx);
7172 code = CM_ERROR_BADFDOP;
7180 lock_ReleaseMutex(&fidp->mx);
7182 lock_ObtainWrite(&scp->rw);
7183 /* start by looking up the file's end */
7184 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7185 CM_SCACHESYNC_NEEDCALLBACK
7186 | CM_SCACHESYNC_SETSTATUS
7187 | CM_SCACHESYNC_GETSTATUS);
7191 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7193 /* now we have the entry locked, look up the length */
7194 fileLength = scp->length;
7195 minLength = fileLength;
7196 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7197 minLength = scp->serverLength;
7199 /* adjust file length if we extend past EOF */
7200 thyper.LowPart = count;
7201 thyper.HighPart = 0;
7202 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7203 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7204 /* we'd write past EOF, so extend the file */
7205 scp->mask |= CM_SCACHEMASK_LENGTH;
7206 scp->length = thyper;
7207 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7209 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7211 /* now, if the new position (thyper) and the old (offset) are in
7212 * different storeback windows, remember to store back the previous
7213 * storeback window when we're done with the write.
7215 * the purpose of this logic is to slow down the CIFS client
7216 * in order to avoid the client disconnecting during the CLOSE
7217 * operation if there are too many dirty buffers left to write
7218 * than can be accomplished during 45 seconds. This used to be
7219 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7220 * so that we can read larger amounts of data at a time.
7222 if (smb_AsyncStore == 1 &&
7223 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7224 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7225 /* they're different */
7227 writeBackOffset.HighPart = offset.HighPart;
7228 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7233 /* now, copy the data one buffer at a time, until we've filled the
7236 /* if we've copied all the data requested, we're done */
7240 /* handle over quota or out of space */
7241 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7242 *writtenp = written;
7243 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7247 /* otherwise, load up a buffer of data */
7248 thyper.HighPart = offset.HighPart;
7249 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7250 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7253 lock_ReleaseMutex(&bufferp->mx);
7254 buf_Release(bufferp);
7257 lock_ReleaseWrite(&scp->rw);
7259 code = buf_Get(scp, &thyper, &req, &bufferp);
7261 lock_ObtainMutex(&bufferp->mx);
7262 lock_ObtainWrite(&scp->rw);
7263 if (code) goto done;
7265 bufferOffset = thyper;
7267 /* now get the data in the cache */
7269 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7270 CM_SCACHESYNC_NEEDCALLBACK
7271 | CM_SCACHESYNC_WRITE
7272 | CM_SCACHESYNC_BUFLOCKED);
7276 cm_SyncOpDone(scp, bufferp,
7277 CM_SCACHESYNC_NEEDCALLBACK
7278 | CM_SCACHESYNC_WRITE
7279 | CM_SCACHESYNC_BUFLOCKED);
7281 /* If we're overwriting the entire buffer, or
7282 * if we're writing at or past EOF, mark the
7283 * buffer as current so we don't call
7284 * cm_GetBuffer. This skips the fetch from the
7285 * server in those cases where we're going to
7286 * obliterate all the data in the buffer anyway,
7287 * or in those cases where there is no useful
7288 * data at the server to start with.
7290 * Use minLength instead of scp->length, since
7291 * the latter has already been updated by this
7294 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7295 || LargeIntegerEqualTo(offset, bufferp->offset)
7296 && (count >= cm_data.buf_blockSize
7297 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7298 ConvertLongToLargeInteger(count)),
7300 if (count < cm_data.buf_blockSize
7301 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7302 memset(bufferp->datap, 0,
7303 cm_data.buf_blockSize);
7304 bufferp->dataVersion = scp->dataVersion;
7307 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7309 /* otherwise, load the buffer and try again */
7310 lock_ReleaseMutex(&bufferp->mx);
7311 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7313 lock_ReleaseWrite(&scp->rw);
7314 lock_ObtainMutex(&bufferp->mx);
7315 lock_ObtainWrite(&scp->rw);
7319 lock_ReleaseMutex(&bufferp->mx);
7320 buf_Release(bufferp);
7324 } /* if (wrong buffer) ... */
7326 /* now we have the right buffer loaded. Copy out the
7327 * data from here to the user's buffer.
7329 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7331 /* and figure out how many bytes we want from this buffer */
7332 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7334 nbytes = count; /* don't go past end of request */
7336 /* now copy the data */
7337 memcpy(bufferp->datap + bufIndex, op, nbytes);
7338 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7340 /* adjust counters, pointers, etc. */
7344 thyper.LowPart = nbytes;
7345 thyper.HighPart = 0;
7346 offset = LargeIntegerAdd(thyper, offset);
7350 lock_ReleaseWrite(&scp->rw);
7353 lock_ReleaseMutex(&bufferp->mx);
7354 buf_Release(bufferp);
7357 lock_ObtainMutex(&fidp->mx);
7358 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7359 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7361 lock_ReleaseMutex(&fidp->mx);
7362 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7363 fidp->NTopen_dscp, fidp->NTopen_pathp,
7366 lock_ReleaseMutex(&fidp->mx);
7370 if (smb_AsyncStore > 0) {
7374 lock_ObtainWrite(&scp->rw);
7375 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7377 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7378 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7380 lock_ReleaseWrite(&scp->rw);
7381 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7382 writeBackOffset.HighPart,
7383 smb_AsyncStoreSize, 0, userp);
7384 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7387 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7391 cm_ReleaseSCache(scp);
7394 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7395 fidp->fid, code, *writtenp);
7400 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7403 unsigned short count;
7405 unsigned short hint;
7406 long written = 0, total_written = 0;
7409 smb_t* smbp = (smb_t*) inp;
7413 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7415 int inDataBlockCount;
7417 fd = smb_GetSMBParm(inp, 0);
7418 count = smb_GetSMBParm(inp, 1);
7419 offset.HighPart = 0; /* too bad */
7420 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7421 hint = smb_GetSMBParm(inp, 4);
7423 op = smb_GetSMBData(inp, NULL);
7424 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7426 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7427 fd, offset.LowPart, count);
7429 fd = smb_ChainFID(fd, inp);
7430 fidp = smb_FindFID(vcp, fd, 0);
7432 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7434 return CM_ERROR_BADFD;
7437 lock_ObtainMutex(&fidp->mx);
7438 if (fidp->flags & SMB_FID_IOCTL) {
7439 lock_ReleaseMutex(&fidp->mx);
7440 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7441 smb_ReleaseFID(fidp);
7442 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7446 if (fidp->flags & SMB_FID_RPC) {
7447 lock_ReleaseMutex(&fidp->mx);
7448 code = smb_RPCWrite(fidp, vcp, inp, outp);
7449 smb_ReleaseFID(fidp);
7450 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7455 lock_ReleaseMutex(&fidp->mx);
7456 smb_ReleaseFID(fidp);
7457 return CM_ERROR_BADFD;
7460 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7461 lock_ReleaseMutex(&fidp->mx);
7462 smb_CloseFID(vcp, fidp, NULL, 0);
7463 smb_ReleaseFID(fidp);
7464 return CM_ERROR_NOSUCHFILE;
7469 lock_ReleaseMutex(&fidp->mx);
7470 userp = smb_GetUserFromVCP(vcp, inp);
7474 LARGE_INTEGER LOffset;
7475 LARGE_INTEGER LLength;
7478 key = cm_GenerateKey(vcp->vcID, pid, fd);
7480 LOffset.HighPart = offset.HighPart;
7481 LOffset.LowPart = offset.LowPart;
7482 LLength.HighPart = 0;
7483 LLength.LowPart = count;
7485 lock_ObtainWrite(&scp->rw);
7486 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7487 lock_ReleaseWrite(&scp->rw);
7490 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7495 /* special case: 0 bytes transferred means truncate to this position */
7499 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7503 truncAttr.mask = CM_ATTRMASK_LENGTH;
7504 truncAttr.length.LowPart = offset.LowPart;
7505 truncAttr.length.HighPart = 0;
7506 lock_ObtainMutex(&fidp->mx);
7507 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7508 fidp->flags |= SMB_FID_LENGTHSETDONE;
7509 lock_ReleaseMutex(&fidp->mx);
7510 smb_SetSMBParm(outp, 0, 0 /* count */);
7511 smb_SetSMBDataLength(outp, 0);
7516 * Work around bug in NT client
7518 * When copying a file, the NT client should first copy the data,
7519 * then copy the last write time. But sometimes the NT client does
7520 * these in the wrong order, so the data copies would inadvertently
7521 * cause the last write time to be overwritten. We try to detect this,
7522 * and don't set client mod time if we think that would go against the
7525 lock_ObtainMutex(&fidp->mx);
7526 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7527 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7528 fidp->scp->clientModTime = time(NULL);
7530 lock_ReleaseMutex(&fidp->mx);
7533 while ( code == 0 && count > 0 ) {
7534 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7535 if (code == 0 && written == 0)
7536 code = CM_ERROR_PARTIALWRITE;
7538 offset = LargeIntegerAdd(offset,
7539 ConvertLongToLargeInteger(written));
7540 count -= (unsigned short)written;
7541 total_written += written;
7545 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7546 total_written, code);
7548 /* set the packet data length to 3 bytes for the data block header,
7549 * plus the size of the data.
7551 smb_SetSMBParm(outp, 0, total_written);
7552 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7553 smb_SetSMBParm(outp, 3, hint);
7554 smb_SetSMBDataLength(outp, 0);
7557 smb_ReleaseFID(fidp);
7558 cm_ReleaseUser(userp);
7559 cm_ReleaseSCache(scp);
7564 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7565 NCB *ncbp, raw_write_cont_t *rwcp)
7574 fd = smb_GetSMBParm(inp, 0);
7575 fidp = smb_FindFID(vcp, fd, 0);
7577 lock_ObtainMutex(&fidp->mx);
7579 lock_ReleaseMutex(&fidp->mx);
7580 smb_ReleaseFID(fidp);
7584 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7585 lock_ReleaseMutex(&fidp->mx);
7586 smb_CloseFID(vcp, fidp, NULL, 0);
7587 smb_ReleaseFID(fidp);
7590 lock_ReleaseMutex(&fidp->mx);
7592 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7593 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7595 userp = smb_GetUserFromVCP(vcp, inp);
7598 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7600 if (rwcp->writeMode & 0x1) { /* synchronous */
7603 smb_FormatResponsePacket(vcp, inp, outp);
7604 op = (smb_t *) outp;
7605 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7606 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7607 smb_SetSMBDataLength(outp, 0);
7608 smb_SendPacket(vcp, outp);
7609 smb_FreePacket(outp);
7611 else { /* asynchronous */
7612 lock_ObtainMutex(&fidp->mx);
7613 fidp->raw_writers--;
7614 if (fidp->raw_writers == 0)
7615 thrd_SetEvent(fidp->raw_write_event);
7616 lock_ReleaseMutex(&fidp->mx);
7619 /* Give back raw buffer */
7620 lock_ObtainMutex(&smb_RawBufLock);
7621 *((char **)rawBuf) = smb_RawBufs;
7622 smb_RawBufs = rawBuf;
7623 lock_ReleaseMutex(&smb_RawBufLock);
7625 smb_ReleaseFID(fidp);
7626 cm_ReleaseUser(userp);
7629 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7634 /* SMB_COM_WRITE_RAW */
7635 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7638 long count, written = 0, total_written = 0;
7642 smb_t *smbp = (smb_t*) inp;
7647 unsigned short writeMode;
7649 fd = smb_GetSMBParm(inp, 0);
7650 totalCount = smb_GetSMBParm(inp, 1);
7651 count = smb_GetSMBParm(inp, 10);
7652 writeMode = smb_GetSMBParm(inp, 7);
7654 op = (char *) inp->data;
7655 op += smb_GetSMBParm(inp, 11);
7657 offset.HighPart = 0;
7658 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7660 if (*inp->wctp == 14) {
7661 /* we received a 64-bit file offset */
7662 #ifdef AFS_LARGEFILES
7663 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7665 if (LargeIntegerLessThanZero(offset)) {
7667 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7668 offset.HighPart, offset.LowPart);
7669 return CM_ERROR_BADSMB;
7672 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7674 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7675 return CM_ERROR_BADSMB;
7678 offset.HighPart = 0;
7681 offset.HighPart = 0; /* 32-bit file offset */
7685 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7686 fd, offset.HighPart, offset.LowPart, count);
7688 " WriteRaw WriteMode 0x%x",
7691 fd = smb_ChainFID(fd, inp);
7692 fidp = smb_FindFID(vcp, fd, 0);
7694 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7696 return CM_ERROR_BADFD;
7698 lock_ObtainMutex(&fidp->mx);
7700 lock_ReleaseMutex(&fidp->mx);
7701 smb_ReleaseFID(fidp);
7702 return CM_ERROR_BADFD;
7705 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7706 lock_ReleaseMutex(&fidp->mx);
7707 smb_CloseFID(vcp, fidp, NULL, 0);
7708 smb_ReleaseFID(fidp);
7709 return CM_ERROR_NOSUCHFILE;
7714 lock_ReleaseMutex(&fidp->mx);
7719 LARGE_INTEGER LOffset;
7720 LARGE_INTEGER LLength;
7723 key = cm_GenerateKey(vcp->vcID, pid, fd);
7725 LOffset.HighPart = offset.HighPart;
7726 LOffset.LowPart = offset.LowPart;
7727 LLength.HighPart = 0;
7728 LLength.LowPart = count;
7730 lock_ObtainWrite(&scp->rw);
7731 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7732 lock_ReleaseWrite(&scp->rw);
7735 cm_ReleaseSCache(scp);
7736 smb_ReleaseFID(fidp);
7741 userp = smb_GetUserFromVCP(vcp, inp);
7744 * Work around bug in NT client
7746 * When copying a file, the NT client should first copy the data,
7747 * then copy the last write time. But sometimes the NT client does
7748 * these in the wrong order, so the data copies would inadvertently
7749 * cause the last write time to be overwritten. We try to detect this,
7750 * and don't set client mod time if we think that would go against the
7753 lock_ObtainMutex(&fidp->mx);
7754 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7755 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7756 fidp->scp->clientModTime = time(NULL);
7758 lock_ReleaseMutex(&fidp->mx);
7761 while ( code == 0 && count > 0 ) {
7762 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7763 if (code == 0 && written == 0)
7764 code = CM_ERROR_PARTIALWRITE;
7766 offset = LargeIntegerAdd(offset,
7767 ConvertLongToLargeInteger(written));
7770 total_written += written;
7774 /* Get a raw buffer */
7777 lock_ObtainMutex(&smb_RawBufLock);
7779 /* Get a raw buf, from head of list */
7780 rawBuf = smb_RawBufs;
7781 smb_RawBufs = *(char **)smb_RawBufs;
7784 code = CM_ERROR_USESTD;
7786 lock_ReleaseMutex(&smb_RawBufLock);
7789 /* Don't allow a premature Close */
7790 if (code == 0 && (writeMode & 1) == 0) {
7791 lock_ObtainMutex(&fidp->mx);
7792 fidp->raw_writers++;
7793 thrd_ResetEvent(fidp->raw_write_event);
7794 lock_ReleaseMutex(&fidp->mx);
7797 smb_ReleaseFID(fidp);
7798 cm_ReleaseUser(userp);
7799 cm_ReleaseSCache(scp);
7802 smb_SetSMBParm(outp, 0, total_written);
7803 smb_SetSMBDataLength(outp, 0);
7804 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7809 offset = LargeIntegerAdd(offset,
7810 ConvertLongToLargeInteger(count));
7814 rwcp->offset.HighPart = offset.HighPart;
7815 rwcp->offset.LowPart = offset.LowPart;
7816 rwcp->count = totalCount - count;
7817 rwcp->writeMode = writeMode;
7818 rwcp->alreadyWritten = total_written;
7820 /* set the packet data length to 3 bytes for the data block header,
7821 * plus the size of the data.
7823 smb_SetSMBParm(outp, 0, 0xffff);
7824 smb_SetSMBDataLength(outp, 0);
7830 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7833 long count, finalCount;
7837 smb_t *smbp = (smb_t*) inp;
7843 fd = smb_GetSMBParm(inp, 0);
7844 count = smb_GetSMBParm(inp, 1);
7845 offset.HighPart = 0; /* too bad */
7846 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7848 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7849 fd, offset.LowPart, count);
7851 fd = smb_ChainFID(fd, inp);
7852 fidp = smb_FindFID(vcp, fd, 0);
7854 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7856 return CM_ERROR_BADFD;
7858 lock_ObtainMutex(&fidp->mx);
7859 if (fidp->flags & SMB_FID_IOCTL) {
7860 lock_ReleaseMutex(&fidp->mx);
7861 code = smb_IoctlRead(fidp, vcp, inp, outp);
7862 smb_ReleaseFID(fidp);
7866 if (fidp->flags & SMB_FID_RPC) {
7867 lock_ReleaseMutex(&fidp->mx);
7868 code = smb_RPCRead(fidp, vcp, inp, outp);
7869 smb_ReleaseFID(fidp);
7874 lock_ReleaseMutex(&fidp->mx);
7875 smb_ReleaseFID(fidp);
7876 return CM_ERROR_BADFD;
7879 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7880 lock_ReleaseMutex(&fidp->mx);
7881 smb_CloseFID(vcp, fidp, NULL, 0);
7882 smb_ReleaseFID(fidp);
7883 return CM_ERROR_NOSUCHFILE;
7888 lock_ReleaseMutex(&fidp->mx);
7891 LARGE_INTEGER LOffset, LLength;
7895 key = cm_GenerateKey(vcp->vcID, pid, fd);
7897 LOffset.HighPart = 0;
7898 LOffset.LowPart = offset.LowPart;
7899 LLength.HighPart = 0;
7900 LLength.LowPart = count;
7902 lock_ObtainWrite(&scp->rw);
7903 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7904 lock_ReleaseWrite(&scp->rw);
7907 cm_ReleaseSCache(scp);
7908 smb_ReleaseFID(fidp);
7912 userp = smb_GetUserFromVCP(vcp, inp);
7914 /* remember this for final results */
7915 smb_SetSMBParm(outp, 0, count);
7916 smb_SetSMBParm(outp, 1, 0);
7917 smb_SetSMBParm(outp, 2, 0);
7918 smb_SetSMBParm(outp, 3, 0);
7919 smb_SetSMBParm(outp, 4, 0);
7921 /* set the packet data length to 3 bytes for the data block header,
7922 * plus the size of the data.
7924 smb_SetSMBDataLength(outp, count+3);
7926 /* get op ptr after putting in the parms, since otherwise we don't
7927 * know where the data really is.
7929 op = smb_GetSMBData(outp, NULL);
7931 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7932 *op++ = 1; /* data block marker */
7933 *op++ = (unsigned char) (count & 0xff);
7934 *op++ = (unsigned char) ((count >> 8) & 0xff);
7936 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7938 /* fix some things up */
7939 smb_SetSMBParm(outp, 0, finalCount);
7940 smb_SetSMBDataLength(outp, finalCount+3);
7942 smb_ReleaseFID(fidp);
7944 cm_ReleaseUser(userp);
7945 cm_ReleaseSCache(scp);
7949 /* SMB_COM_CREATE_DIRECTORY */
7950 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7952 clientchar_t *pathp;
7957 cm_scache_t *dscp; /* dir we're dealing with */
7958 cm_scache_t *scp; /* file we're creating */
7960 int initialModeBits;
7961 clientchar_t *lastNamep;
7963 clientchar_t *tidPathp;
7970 /* compute initial mode bits based on read-only flag in attributes */
7971 initialModeBits = 0777;
7973 tp = smb_GetSMBData(inp, NULL);
7974 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7976 return CM_ERROR_BADSMB;
7978 spacep = inp->spacep;
7979 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7981 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7982 return CM_ERROR_EXISTS;
7984 userp = smb_GetUserFromVCP(vcp, inp);
7986 caseFold = CM_FLAG_CASEFOLD;
7988 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7990 cm_ReleaseUser(userp);
7991 return CM_ERROR_NOSUCHPATH;
7994 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7995 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7996 userp, tidPathp, &req, &dscp);
7999 cm_ReleaseUser(userp);
8004 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8005 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8006 cm_ReleaseSCache(dscp);
8007 cm_ReleaseUser(userp);
8008 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8009 return CM_ERROR_PATH_NOT_COVERED;
8011 return CM_ERROR_NOSUCHPATH;
8013 #endif /* DFS_SUPPORT */
8015 /* otherwise, scp points to the parent directory. Do a lookup, and
8016 * fail if we find it. Otherwise, we do the create.
8022 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8023 if (scp) cm_ReleaseSCache(scp);
8024 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8025 if (code == 0) code = CM_ERROR_EXISTS;
8026 cm_ReleaseSCache(dscp);
8027 cm_ReleaseUser(userp);
8031 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8032 setAttr.clientModTime = time(NULL);
8033 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8034 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8035 smb_NotifyChange(FILE_ACTION_ADDED,
8036 FILE_NOTIFY_CHANGE_DIR_NAME,
8037 dscp, lastNamep, NULL, TRUE);
8039 /* we don't need this any longer */
8040 cm_ReleaseSCache(dscp);
8043 /* something went wrong creating or truncating the file */
8044 cm_ReleaseUser(userp);
8048 /* otherwise we succeeded */
8049 smb_SetSMBDataLength(outp, 0);
8050 cm_ReleaseUser(userp);
8055 BOOL smb_IsLegalFilename(clientchar_t *filename)
8058 * Find the longest substring of filename that does not contain
8059 * any of the chars in illegalChars. If that substring is less
8060 * than the length of the whole string, then one or more of the
8061 * illegal chars is in filename.
8063 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8069 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8070 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8072 clientchar_t *pathp;
8078 cm_scache_t *dscp; /* dir we're dealing with */
8079 cm_scache_t *scp; /* file we're creating */
8081 int initialModeBits;
8084 clientchar_t *lastNamep;
8087 clientchar_t *tidPathp;
8089 int created = 0; /* the file was new */
8094 excl = (inp->inCom == 0x03)? 0 : 1;
8096 attributes = smb_GetSMBParm(inp, 0);
8097 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8099 /* compute initial mode bits based on read-only flag in attributes */
8100 initialModeBits = 0666;
8101 if (attributes & SMB_ATTR_READONLY)
8102 initialModeBits &= ~0222;
8104 tp = smb_GetSMBData(inp, NULL);
8105 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8107 return CM_ERROR_BADSMB;
8109 spacep = inp->spacep;
8110 /* smb_StripLastComponent will strip "::$DATA" if present */
8111 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8113 if (!cm_IsValidClientString(pathp)) {
8115 clientchar_t * hexp;
8117 hexp = cm_GetRawCharsAlloc(pathp, -1);
8118 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8119 osi_LogSaveClientString(smb_logp, hexp));
8123 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8125 return CM_ERROR_BADNTFILENAME;
8128 userp = smb_GetUserFromVCP(vcp, inp);
8130 caseFold = CM_FLAG_CASEFOLD;
8132 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8134 cm_ReleaseUser(userp);
8135 return CM_ERROR_NOSUCHPATH;
8137 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8138 userp, tidPathp, &req, &dscp);
8141 cm_ReleaseUser(userp);
8146 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8147 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8148 cm_ReleaseSCache(dscp);
8149 cm_ReleaseUser(userp);
8150 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8151 return CM_ERROR_PATH_NOT_COVERED;
8153 return CM_ERROR_NOSUCHPATH;
8155 #endif /* DFS_SUPPORT */
8157 /* otherwise, scp points to the parent directory. Do a lookup, and
8158 * truncate the file if we find it, otherwise we create the file.
8165 if (!smb_IsLegalFilename(lastNamep))
8166 return CM_ERROR_BADNTFILENAME;
8168 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8169 #ifdef DEBUG_VERBOSE
8172 hexp = osi_HexifyString( lastNamep );
8173 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8178 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8179 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8180 cm_ReleaseSCache(dscp);
8181 cm_ReleaseUser(userp);
8185 /* if we get here, if code is 0, the file exists and is represented by
8186 * scp. Otherwise, we have to create it.
8190 /* oops, file shouldn't be there */
8191 cm_ReleaseSCache(dscp);
8192 cm_ReleaseSCache(scp);
8193 cm_ReleaseUser(userp);
8194 return CM_ERROR_EXISTS;
8197 setAttr.mask = CM_ATTRMASK_LENGTH;
8198 setAttr.length.LowPart = 0;
8199 setAttr.length.HighPart = 0;
8200 code = cm_SetAttr(scp, &setAttr, userp, &req);
8203 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8204 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8205 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8209 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8210 smb_NotifyChange(FILE_ACTION_ADDED,
8211 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8212 dscp, lastNamep, NULL, TRUE);
8213 } else if (!excl && code == CM_ERROR_EXISTS) {
8214 /* not an exclusive create, and someone else tried
8215 * creating it already, then we open it anyway. We
8216 * don't bother retrying after this, since if this next
8217 * fails, that means that the file was deleted after
8218 * we started this call.
8220 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8223 setAttr.mask = CM_ATTRMASK_LENGTH;
8224 setAttr.length.LowPart = 0;
8225 setAttr.length.HighPart = 0;
8226 code = cm_SetAttr(scp, &setAttr, userp, &req);
8231 /* we don't need this any longer */
8232 cm_ReleaseSCache(dscp);
8235 /* something went wrong creating or truncating the file */
8236 if (scp) cm_ReleaseSCache(scp);
8237 cm_ReleaseUser(userp);
8241 /* make sure we only open files */
8242 if (scp->fileType != CM_SCACHETYPE_FILE) {
8243 cm_ReleaseSCache(scp);
8244 cm_ReleaseUser(userp);
8245 return CM_ERROR_ISDIR;
8248 /* now all we have to do is open the file itself */
8249 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8250 osi_assertx(fidp, "null smb_fid_t");
8254 lock_ObtainMutex(&fidp->mx);
8255 /* always create it open for read/write */
8256 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8258 /* remember that the file was newly created */
8260 fidp->flags |= SMB_FID_CREATED;
8262 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8264 /* save a pointer to the vnode */
8266 lock_ObtainWrite(&scp->rw);
8267 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8268 lock_ReleaseWrite(&scp->rw);
8271 fidp->userp = userp;
8272 lock_ReleaseMutex(&fidp->mx);
8274 smb_SetSMBParm(outp, 0, fidp->fid);
8275 smb_SetSMBDataLength(outp, 0);
8277 cm_Open(scp, 0, userp);
8279 smb_ReleaseFID(fidp);
8280 cm_ReleaseUser(userp);
8281 /* leave scp held since we put it in fidp->scp */
8286 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8289 osi_hyper_t new_offset;
8300 fd = smb_GetSMBParm(inp, 0);
8301 whence = smb_GetSMBParm(inp, 1);
8302 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8304 /* try to find the file descriptor */
8305 fd = smb_ChainFID(fd, inp);
8306 fidp = smb_FindFID(vcp, fd, 0);
8308 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8310 return CM_ERROR_BADFD;
8312 lock_ObtainMutex(&fidp->mx);
8313 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8314 lock_ReleaseMutex(&fidp->mx);
8315 smb_ReleaseFID(fidp);
8316 return CM_ERROR_BADFD;
8319 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8320 lock_ReleaseMutex(&fidp->mx);
8321 smb_CloseFID(vcp, fidp, NULL, 0);
8322 smb_ReleaseFID(fidp);
8323 return CM_ERROR_NOSUCHFILE;
8326 lock_ReleaseMutex(&fidp->mx);
8328 userp = smb_GetUserFromVCP(vcp, inp);
8330 lock_ObtainMutex(&fidp->mx);
8333 lock_ReleaseMutex(&fidp->mx);
8334 lock_ObtainWrite(&scp->rw);
8335 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8336 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8338 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8340 /* offset from current offset */
8341 new_offset = LargeIntegerAdd(fidp->offset,
8342 ConvertLongToLargeInteger(offset));
8344 else if (whence == 2) {
8345 /* offset from current EOF */
8346 new_offset = LargeIntegerAdd(scp->length,
8347 ConvertLongToLargeInteger(offset));
8349 new_offset = ConvertLongToLargeInteger(offset);
8352 fidp->offset = new_offset;
8353 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8354 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8355 smb_SetSMBDataLength(outp, 0);
8357 lock_ReleaseWrite(&scp->rw);
8358 smb_ReleaseFID(fidp);
8359 cm_ReleaseSCache(scp);
8360 cm_ReleaseUser(userp);
8364 /* dispatch all of the requests received in a packet. Due to chaining, this may
8365 * be more than one request.
8367 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8368 NCB *ncbp, raw_write_cont_t *rwcp)
8372 unsigned long code = 0;
8373 unsigned char *outWctp;
8374 int nparms; /* # of bytes of parameters */
8376 int nbytes; /* bytes of data, excluding count */
8379 unsigned short errCode;
8380 unsigned long NTStatus;
8382 unsigned char errClass;
8383 unsigned int oldGen;
8384 DWORD oldTime, newTime;
8386 /* get easy pointer to the data */
8387 smbp = (smb_t *) inp->data;
8389 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8390 /* setup the basic parms for the initial request in the packet */
8391 inp->inCom = smbp->com;
8392 inp->wctp = &smbp->wct;
8394 inp->ncb_length = ncbp->ncb_length;
8399 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8400 /* log it and discard it */
8401 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8402 __FILE__, __LINE__, ncbp->ncb_length);
8403 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8407 /* We are an ongoing op */
8408 thrd_Increment(&ongoingOps);
8410 /* set up response packet for receiving output */
8411 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8412 smb_FormatResponsePacket(vcp, inp, outp);
8413 outWctp = outp->wctp;
8415 /* Remember session generation number and time */
8416 oldGen = sessionGen;
8417 oldTime = GetTickCount();
8419 while (inp->inCom != 0xff) {
8420 dp = &smb_dispatchTable[inp->inCom];
8422 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8423 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8424 code = outp->resumeCode;
8428 /* process each request in the packet; inCom, wctp and inCount
8429 * are already set up.
8431 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8434 /* now do the dispatch */
8435 /* start by formatting the response record a little, as a default */
8436 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8438 outWctp[1] = 0xff; /* no operation */
8439 outWctp[2] = 0; /* padding */
8444 /* not a chained request, this is a more reasonable default */
8445 outWctp[0] = 0; /* wct of zero */
8446 outWctp[1] = 0; /* and bcc (word) of zero */
8450 /* once set, stays set. Doesn't matter, since we never chain
8451 * "no response" calls.
8453 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8457 /* we have a recognized operation */
8458 char * opName = myCrt_Dispatch(inp->inCom);
8461 smbp = (smb_t *) inp;
8463 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8464 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8465 if (inp->inCom == 0x1d) {
8467 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8469 code = (*(dp->procp)) (vcp, inp, outp);
8471 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8472 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8474 newTime = GetTickCount();
8475 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8476 opName, smbp->mid, newTime - oldTime);
8479 if ( code == CM_ERROR_BADSMB ||
8480 code == CM_ERROR_BADOP )
8482 #endif /* LOG_PACKET */
8484 /* ReceiveV3Tran2A handles its own logging */
8485 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8488 clientchar_t *treepath = NULL; /* do not free */
8489 clientchar_t *pathname = NULL;
8490 cm_fid_t afid = {0,0,0,0,0};
8492 uidp = smb_FindUID(vcp, smbp->uid, 0);
8493 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8494 fidp = smb_FindFID(vcp, inp->fid, 0);
8497 lock_ObtainMutex(&fidp->mx);
8498 if (fidp->NTopen_pathp)
8499 pathname = fidp->NTopen_pathp;
8501 afid = fidp->scp->fid;
8503 if (inp->stringsp->wdata)
8504 pathname = inp->stringsp->wdata;
8507 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)",
8508 opName, newTime - oldTime,
8509 smbp->uid, uidp ? uidp->unp->name : NULL,
8510 smbp->pid, smbp->mid, smbp->tid,
8513 afid.cell, afid.volume, afid.vnode, afid.unique);
8516 lock_ReleaseMutex(&fidp->mx);
8519 smb_ReleaseUID(uidp);
8521 smb_ReleaseFID(fidp);
8524 if (oldGen != sessionGen) {
8525 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8526 newTime - oldTime, ncbp->ncb_length);
8527 osi_Log3(smb_logp, "Request %s straddled session startup, "
8528 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8531 FreeSMBStrings(inp);
8533 /* bad opcode, fail the request, after displaying it */
8534 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8537 #endif /* LOG_PACKET */
8540 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8541 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8542 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8543 if (code == IDCANCEL)
8546 code = CM_ERROR_BADOP;
8549 /* catastrophic failure: log as much as possible */
8550 if (code == CM_ERROR_BADSMB) {
8551 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8555 #endif /* LOG_PACKET */
8556 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8559 code = CM_ERROR_INVAL;
8562 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8563 thrd_Decrement(&ongoingOps);
8568 /* now, if we failed, turn the current response into an empty
8569 * one, and fill in the response packet's error code.
8572 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8573 smb_MapNTError(code, &NTStatus);
8574 outWctp = outp->wctp;
8575 smbp = (smb_t *) &outp->data;
8576 if (code != CM_ERROR_PARTIALWRITE
8577 && code != CM_ERROR_BUFFERTOOSMALL
8578 && code != CM_ERROR_GSSCONTINUE) {
8579 /* nuke wct and bcc. For a partial
8580 * write or an in-process authentication handshake,
8581 * assume they're OK.
8587 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8588 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8589 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8590 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8591 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8595 smb_MapCoreError(code, vcp, &errCode, &errClass);
8596 outWctp = outp->wctp;
8597 smbp = (smb_t *) &outp->data;
8598 if (code != CM_ERROR_PARTIALWRITE) {
8599 /* nuke wct and bcc. For a partial
8600 * write, assume they're OK.
8606 smbp->errLow = (unsigned char) (errCode & 0xff);
8607 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8608 smbp->rcls = errClass;
8611 } /* error occurred */
8613 /* if we're here, we've finished one request. Look to see if
8614 * this is a chained opcode. If it is, setup things to process
8615 * the chained request, and setup the output buffer to hold the
8616 * chained response. Start by finding the next input record.
8618 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8619 break; /* not a chained req */
8620 tp = inp->wctp; /* points to start of last request */
8621 /* in a chained request, the first two
8622 * parm fields are required, and are
8623 * AndXCommand/AndXReserved and
8625 if (tp[0] < 2) break;
8626 if (tp[1] == 0xff) break; /* no more chained opcodes */
8628 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8631 /* and now append the next output request to the end of this
8632 * last request. Begin by finding out where the last response
8633 * ends, since that's where we'll put our new response.
8635 outWctp = outp->wctp; /* ptr to out parameters */
8636 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8637 nparms = outWctp[0] << 1;
8638 tp = outWctp + nparms + 1; /* now points to bcc field */
8639 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8640 tp += 2 /* for the count itself */ + nbytes;
8641 /* tp now points to the new output record; go back and patch the
8642 * second parameter (off2) to point to the new record.
8644 temp = (unsigned int)(tp - outp->data);
8645 outWctp[3] = (unsigned char) (temp & 0xff);
8646 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8647 outWctp[2] = 0; /* padding */
8648 outWctp[1] = inp->inCom; /* next opcode */
8650 /* finally, setup for the next iteration */
8653 } /* while loop over all requests in the packet */
8655 /* now send the output packet, and return */
8657 smb_SendPacket(vcp, outp);
8658 thrd_Decrement(&ongoingOps);
8663 /* Wait for Netbios() calls to return, and make the results available to server
8664 * threads. Note that server threads can't wait on the NCBevents array
8665 * themselves, because NCB events are manual-reset, and the servers would race
8666 * each other to reset them.
8668 void smb_ClientWaiter(void *parmp)
8673 while (smbShutdownFlag == 0) {
8674 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8676 if (code == WAIT_OBJECT_0)
8679 /* error checking */
8680 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8682 int abandonIdx = code - WAIT_ABANDONED_0;
8683 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8686 if (code == WAIT_IO_COMPLETION)
8688 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8692 if (code == WAIT_TIMEOUT)
8694 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8697 if (code == WAIT_FAILED)
8699 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8702 idx = code - WAIT_OBJECT_0;
8704 /* check idx range! */
8705 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8707 /* this is fatal - log as much as possible */
8708 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8709 osi_assertx(0, "invalid index");
8712 thrd_ResetEvent(NCBevents[idx]);
8713 thrd_SetEvent(NCBreturns[0][idx]);
8718 * Try to have one NCBRECV request waiting for every live session. Not more
8719 * than one, because if there is more than one, it's hard to handle Write Raw.
8721 void smb_ServerWaiter(void *parmp)
8724 int idx_session, idx_NCB;
8727 while (smbShutdownFlag == 0) {
8729 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8731 if (code == WAIT_OBJECT_0)
8734 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8736 int abandonIdx = code - WAIT_ABANDONED_0;
8737 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8740 if (code == WAIT_IO_COMPLETION)
8742 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8746 if (code == WAIT_TIMEOUT)
8748 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8751 if (code == WAIT_FAILED)
8753 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8756 idx_session = code - WAIT_OBJECT_0;
8758 /* check idx range! */
8759 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8761 /* this is fatal - log as much as possible */
8762 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8763 osi_assertx(0, "invalid index");
8768 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8770 if (code == WAIT_OBJECT_0) {
8771 if (smbShutdownFlag == 1)
8777 /* error checking */
8778 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8780 int abandonIdx = code - WAIT_ABANDONED_0;
8781 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8784 if (code == WAIT_IO_COMPLETION)
8786 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8790 if (code == WAIT_TIMEOUT)
8792 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8795 if (code == WAIT_FAILED)
8797 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8800 idx_NCB = code - WAIT_OBJECT_0;
8802 /* check idx range! */
8803 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8805 /* this is fatal - log as much as possible */
8806 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8807 osi_assertx(0, "invalid index");
8810 /* Link them together */
8811 NCBsessions[idx_NCB] = idx_session;
8814 ncbp = NCBs[idx_NCB];
8815 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8816 ncbp->ncb_command = NCBRECV | ASYNCH;
8817 ncbp->ncb_lana_num = lanas[idx_session];
8818 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8819 ncbp->ncb_event = NCBevents[idx_NCB];
8820 ncbp->ncb_length = SMB_PACKETSIZE;
8826 * The top level loop for handling SMB request messages. Each server thread
8827 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8828 * NCB and buffer for the incoming request are loaned to us.
8830 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8831 * to immediately send a request for the rest of the data. This must come
8832 * before any other traffic for that session, so we delay setting the session
8833 * event until that data has come in.
8835 void smb_Server(VOID *parmp)
8837 INT_PTR myIdx = (INT_PTR) parmp;
8841 smb_packet_t *outbufp;
8843 int idx_NCB, idx_session;
8845 smb_vc_t *vcp = NULL;
8847 extern void rx_StartClientThread(void);
8849 rx_StartClientThread();
8851 outncbp = smb_GetNCB();
8852 outbufp = smb_GetPacket();
8853 outbufp->ncbp = outncbp;
8861 cm_ResetServerPriority();
8863 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8866 /* terminate silently if shutdown flag is set */
8867 if (code == WAIT_OBJECT_0) {
8868 if (smbShutdownFlag == 1) {
8869 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8875 /* error checking */
8876 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8878 int abandonIdx = code - WAIT_ABANDONED_0;
8879 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8882 if (code == WAIT_IO_COMPLETION)
8884 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8888 if (code == WAIT_TIMEOUT)
8890 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8893 if (code == WAIT_FAILED)
8895 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8898 idx_NCB = code - WAIT_OBJECT_0;
8900 /* check idx range! */
8901 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8903 /* this is fatal - log as much as possible */
8904 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8905 osi_assertx(0, "invalid index");
8908 ncbp = NCBs[idx_NCB];
8909 idx_session = NCBsessions[idx_NCB];
8910 rc = ncbp->ncb_retcode;
8912 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8913 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8917 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8921 /* Can this happen? Or is it just my UNIX paranoia? */
8922 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8927 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8930 /* Client closed session */
8931 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8933 lock_ObtainMutex(&vcp->mx);
8934 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8935 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8937 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8938 lock_ReleaseMutex(&vcp->mx);
8939 lock_ObtainWrite(&smb_globalLock);
8940 dead_sessions[vcp->session] = TRUE;
8941 lock_ReleaseWrite(&smb_globalLock);
8943 lock_ReleaseMutex(&vcp->mx);
8945 smb_CleanupDeadVC(vcp);
8952 /* Treat as transient error */
8953 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8956 "dispatch smb recv failed, message incomplete, ncb_length %d",
8959 "SMB message incomplete, "
8960 "length %d", ncbp->ncb_length);
8963 * We used to discard the packet.
8964 * Instead, try handling it normally.
8968 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8972 /* A weird error code. Log it, sleep, and continue. */
8973 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8975 lock_ObtainMutex(&vcp->mx);
8976 if (vcp->errorCount++ > 3) {
8977 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8978 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8979 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8981 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8982 lock_ReleaseMutex(&vcp->mx);
8983 lock_ObtainWrite(&smb_globalLock);
8984 dead_sessions[vcp->session] = TRUE;
8985 lock_ReleaseWrite(&smb_globalLock);
8987 lock_ReleaseMutex(&vcp->mx);
8989 smb_CleanupDeadVC(vcp);
8995 lock_ReleaseMutex(&vcp->mx);
8999 thrd_SetEvent(SessionEvents[idx_session]);
9005 /* Success, so now dispatch on all the data in the packet */
9007 smb_concurrentCalls++;
9008 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9009 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9012 * If at this point vcp is NULL (implies that packet was invalid)
9013 * then we are in big trouble. This means either :
9014 * a) we have the wrong NCB.
9015 * b) Netbios screwed up the call.
9016 * c) The VC was already marked dead before we were able to
9018 * Obviously this implies that
9019 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9020 * lanas[idx_session] != ncbp->ncb_lana_num )
9021 * Either way, we can't do anything with this packet.
9022 * Log, sleep and resume.
9025 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9029 ncbp->ncb_lana_num);
9031 /* Also log in the trace log. */
9032 osi_Log4(smb_logp, "Server: VCP does not exist!"
9033 "LSNs[idx_session]=[%d],"
9034 "lanas[idx_session]=[%d],"
9035 "ncbp->ncb_lsn=[%d],"
9036 "ncbp->ncb_lana_num=[%d]",
9040 ncbp->ncb_lana_num);
9042 /* thrd_Sleep(1000); Don't bother sleeping */
9043 thrd_SetEvent(SessionEvents[idx_session]);
9044 smb_concurrentCalls--;
9048 cm_SetRequestStartTime();
9050 vcp->errorCount = 0;
9051 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9052 smbp = (smb_t *)bufp->data;
9059 if (smbp->com == 0x1d) {
9060 /* Special handling for Write Raw */
9061 raw_write_cont_t rwc;
9063 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9064 if (rwc.code == 0) {
9065 EVENT_HANDLE rwevent;
9066 char eventName[MAX_PATH];
9068 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9069 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9070 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9071 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9073 ncbp->ncb_command = NCBRECV | ASYNCH;
9074 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9075 ncbp->ncb_lana_num = vcp->lana;
9076 ncbp->ncb_buffer = rwc.buf;
9077 ncbp->ncb_length = 65535;
9078 ncbp->ncb_event = rwevent;
9080 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9081 thrd_CloseHandle(rwevent);
9083 thrd_SetEvent(SessionEvents[idx_session]);
9085 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9087 else if (smbp->com == 0xa0) {
9089 * Serialize the handling for NT Transact
9092 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9093 thrd_SetEvent(SessionEvents[idx_session]);
9095 thrd_SetEvent(SessionEvents[idx_session]);
9096 /* TODO: what else needs to be serialized? */
9097 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9101 __except( smb_ServerExceptionFilter() ) {
9105 smb_concurrentCalls--;
9108 thrd_SetEvent(NCBavails[idx_NCB]);
9113 smb_FreePacket(outbufp);
9115 smb_FreeNCB(outncbp);
9119 * Exception filter for the server threads. If an exception occurs in the
9120 * dispatch routines, which is where exceptions are most common, then do a
9121 * force trace and give control to upstream exception handlers. Useful for
9124 DWORD smb_ServerExceptionFilter(void) {
9125 /* While this is not the best time to do a trace, if it succeeds, then
9126 * we have a trace (assuming tracing was enabled). Otherwise, this should
9127 * throw a second exception.
9129 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9130 afsd_ForceTrace(TRUE);
9131 buf_ForceTrace(TRUE);
9132 return EXCEPTION_CONTINUE_SEARCH;
9136 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9137 * If the number of server threads is M, and the number of live sessions is
9138 * N, then the number of NCB's in use at any time either waiting for, or
9139 * holding, received messages is M + N, so that is how many NCB's get created.
9141 void InitNCBslot(int idx)
9143 struct smb_packet *bufp;
9144 EVENT_HANDLE retHandle;
9146 char eventName[MAX_PATH];
9148 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9150 NCBs[idx] = smb_GetNCB();
9151 sprintf(eventName,"NCBavails[%d]", idx);
9152 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9153 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9154 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9155 sprintf(eventName,"NCBevents[%d]", idx);
9156 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9157 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9158 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9159 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9160 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9161 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9162 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9163 for (i=0; i<smb_NumServerThreads; i++)
9164 NCBreturns[i][idx] = retHandle;
9165 bufp = smb_GetPacket();
9166 bufp->spacep = cm_GetSpace();
9170 /* listen for new connections */
9171 void smb_Listener(void *parmp)
9177 afs_uint32 session, thread;
9178 smb_vc_t *vcp = NULL;
9180 char rname[NCBNAMSZ+1];
9181 char cname[MAX_COMPUTERNAME_LENGTH+1];
9182 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9183 INT_PTR lana = (INT_PTR) parmp;
9184 char eventName[MAX_PATH];
9185 int bridgeCount = 0;
9186 int nowildCount = 0;
9188 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9189 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9190 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9191 thrd_ResetEvent(ListenerShutdown[lana]);
9193 ncbp = smb_GetNCB();
9195 /* retrieve computer name */
9196 GetComputerName(cname, &cnamelen);
9199 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9200 memset(ncbp, 0, sizeof(NCB));
9203 ncbp->ncb_command = NCBLISTEN;
9204 ncbp->ncb_rto = 0; /* No receive timeout */
9205 ncbp->ncb_sto = 0; /* No send timeout */
9207 /* pad out with spaces instead of null termination */
9208 len = (long)strlen(smb_localNamep);
9209 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9210 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9212 strcpy(ncbp->ncb_callname, "*");
9213 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9215 ncbp->ncb_lana_num = (UCHAR)lana;
9217 code = Netbios(ncbp);
9219 if (code == NRC_NAMERR) {
9220 /* An smb shutdown or Vista resume must have taken place */
9222 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9223 ncbp->ncb_lana_num);
9224 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9226 if (lock_TryMutex(&smb_StartedLock)) {
9227 lana_list.lana[i] = LANA_INVALID;
9228 lock_ReleaseMutex(&smb_StartedLock);
9231 } else if (code == NRC_BRIDGE || code != 0) {
9232 int lanaRemaining = 0;
9234 if (code == NRC_BRIDGE) {
9235 if (++bridgeCount <= 5) {
9236 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9239 } else if (code == NRC_NOWILD) {
9240 if (++nowildCount <= 5) {
9241 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9243 if (bridgeCount > 0) {
9244 memset(ncbp, 0, sizeof(*ncbp));
9245 ncbp->ncb_command = NCBADDNAME;
9246 ncbp->ncb_lana_num = (UCHAR)lana;
9247 /* pad out with spaces instead of null termination */
9248 len = (long)strlen(smb_localNamep);
9249 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9250 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9251 code = Netbios(ncbp);
9257 while (!lock_TryMutex(&smb_StartedLock)) {
9258 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9264 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9265 ncbp->ncb_lana_num, ncb_error_string(code));
9266 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9267 ncbp->ncb_lana_num, ncb_error_string(code));
9269 for (i = 0; i < lana_list.length; i++) {
9270 if (lana_list.lana[i] == lana) {
9271 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9272 lana_list.lana[i] = LANA_INVALID;
9274 if (lana_list.lana[i] != LANA_INVALID)
9278 if (lanaRemaining == 0) {
9279 cm_VolStatus_Network_Stopped(cm_NetbiosName
9284 smb_ListenerState = SMB_LISTENER_STOPPED;
9285 smb_LANadapter = LANA_INVALID;
9286 lana_list.length = 0;
9288 lock_ReleaseMutex(&smb_StartedLock);
9292 else if (code != 0) {
9293 char tbuffer[AFSPATHMAX];
9295 /* terminate silently if shutdown flag is set */
9296 while (!lock_TryMutex(&smb_StartedLock)) {
9297 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9303 "NCBLISTEN lana=%d failed with code %d [%s]",
9304 ncbp->ncb_lana_num, code, ncb_error_string(code));
9306 "Client exiting due to network failure. Please restart client.\n");
9309 "Client exiting due to network failure. Please restart client.\n"
9310 "NCBLISTEN lana=%d failed with code %d [%s]",
9311 ncbp->ncb_lana_num, code, ncb_error_string(code));
9313 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9314 MB_OK|MB_SERVICE_NOTIFICATION);
9315 osi_panic(tbuffer, __FILE__, __LINE__);
9317 lock_ReleaseMutex(&smb_StartedLock);
9322 /* a successful packet received. clear bridge error count */
9326 /* check for remote conns */
9327 /* first get remote name and insert null terminator */
9328 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9329 for (i=NCBNAMSZ; i>0; i--) {
9330 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9336 /* compare with local name */
9338 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9339 flags |= SMB_VCFLAG_REMOTECONN;
9342 lock_ObtainMutex(&smb_ListenerLock);
9344 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9345 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9347 /* now ncbp->ncb_lsn is the connection ID */
9348 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9349 if (vcp->session == 0) {
9350 /* New generation */
9351 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9354 /* Log session startup */
9356 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9357 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9358 #endif /* NOTSERVICE */
9359 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9360 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9362 if (reportSessionStartups) {
9363 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9366 lock_ObtainMutex(&vcp->mx);
9367 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9368 vcp->flags |= flags;
9369 lock_ReleaseMutex(&vcp->mx);
9371 /* Allocate slot in session arrays */
9372 /* Re-use dead session if possible, otherwise add one more */
9373 /* But don't look at session[0], it is reserved */
9374 lock_ObtainWrite(&smb_globalLock);
9375 for (session = 1; session < numSessions; session++) {
9376 if (dead_sessions[session]) {
9377 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9378 dead_sessions[session] = FALSE;
9382 lock_ReleaseWrite(&smb_globalLock);
9384 /* We are re-using an existing VC because the lsn and lana
9386 session = vcp->session;
9388 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9390 /* Log session startup */
9392 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9393 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9394 #endif /* NOTSERVICE */
9395 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9396 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9398 if (reportSessionStartups) {
9399 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9403 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9404 unsigned long code = CM_ERROR_ALLBUSY;
9405 smb_packet_t * outp = smb_GetPacket();
9406 unsigned char *outWctp;
9409 smb_FormatResponsePacket(vcp, NULL, outp);
9412 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9413 unsigned long NTStatus;
9414 smb_MapNTError(code, &NTStatus);
9415 outWctp = outp->wctp;
9416 smbp = (smb_t *) &outp->data;
9420 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9421 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9422 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9423 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9424 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9426 unsigned short errCode;
9427 unsigned char errClass;
9428 smb_MapCoreError(code, vcp, &errCode, &errClass);
9429 outWctp = outp->wctp;
9430 smbp = (smb_t *) &outp->data;
9434 smbp->errLow = (unsigned char) (errCode & 0xff);
9435 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9436 smbp->rcls = errClass;
9439 smb_SendPacket(vcp, outp);
9440 smb_FreePacket(outp);
9442 lock_ObtainMutex(&vcp->mx);
9443 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9444 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9446 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9447 lock_ReleaseMutex(&vcp->mx);
9448 lock_ObtainWrite(&smb_globalLock);
9449 dead_sessions[vcp->session] = TRUE;
9450 lock_ReleaseWrite(&smb_globalLock);
9451 smb_CleanupDeadVC(vcp);
9453 lock_ReleaseMutex(&vcp->mx);
9456 /* assert that we do not exceed the maximum number of sessions or NCBs.
9457 * we should probably want to wait for a session to be freed in case
9460 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9461 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9463 lock_ObtainMutex(&vcp->mx);
9464 vcp->session = session;
9465 lock_ReleaseMutex(&vcp->mx);
9466 lock_ObtainWrite(&smb_globalLock);
9467 LSNs[session] = ncbp->ncb_lsn;
9468 lanas[session] = ncbp->ncb_lana_num;
9469 lock_ReleaseWrite(&smb_globalLock);
9471 if (session == numSessions) {
9472 /* Add new NCB for new session */
9473 char eventName[MAX_PATH];
9475 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9477 InitNCBslot(numNCBs);
9478 lock_ObtainWrite(&smb_globalLock);
9480 lock_ReleaseWrite(&smb_globalLock);
9481 thrd_SetEvent(NCBavails[0]);
9482 thrd_SetEvent(NCBevents[0]);
9483 for (thread = 0; thread < smb_NumServerThreads; thread++)
9484 thrd_SetEvent(NCBreturns[thread][0]);
9485 /* Also add new session event */
9486 sprintf(eventName, "SessionEvents[%d]", session);
9487 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9488 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9489 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9490 lock_ObtainWrite(&smb_globalLock);
9492 lock_ReleaseWrite(&smb_globalLock);
9493 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9494 thrd_SetEvent(SessionEvents[0]);
9496 thrd_SetEvent(SessionEvents[session]);
9502 lock_ReleaseMutex(&smb_ListenerLock);
9503 } /* dispatch while loop */
9507 thrd_SetEvent(ListenerShutdown[lana]);
9512 configureBackConnectionHostNames(void)
9514 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9515 * there is a restriction on the use of SMB authentication on loopback connections.
9516 * There are two work arounds available:
9518 * (1) We can disable the check for matching host names. This does not
9520 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9521 * "DisableLoopbackCheck"=dword:00000001
9523 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9524 * does require a reboot:
9525 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9526 * "BackConnectionHostNames"=multi-sz
9528 * The algorithm will be:
9529 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9530 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9531 * (2b1) and check to see if DisableLoopbackCheck is set.
9532 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9533 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9534 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9535 * check for the UnsetDisableLoopbackCheck value.
9536 * If set, set the DisableLoopbackCheck flag to 0x0
9537 * and delete the UnsetDisableLoopbackCheck value
9539 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9540 * force Windows to use the loopback authentication mechanism for the specified
9543 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9544 * service session that set it.
9550 DWORD dwSize, dwAllocSize;
9552 PBYTE pHostNames = NULL, pName = NULL;
9553 BOOL bNameFound = FALSE;
9554 static BOOL bLoopbackCheckDisabled = FALSE;
9556 /* BackConnectionHostNames and DisableLoopbackCheck */
9557 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9558 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9561 &hkMSV10) == ERROR_SUCCESS )
9563 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9564 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9565 (dwType == REG_MULTI_SZ))
9567 dwAllocSize += 1 /* in case the source string is not nul terminated */
9568 + (DWORD)strlen(cm_NetbiosName) + 2;
9569 pHostNames = malloc(dwAllocSize);
9570 dwSize = dwAllocSize;
9571 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9572 pHostNames, &dwSize) == ERROR_SUCCESS)
9574 for (pName = pHostNames;
9575 (pName - pHostNames < (int) dwSize) && *pName ;
9576 pName += strlen(pName) + 1)
9578 if ( !stricmp(pName, cm_NetbiosName) ) {
9586 if ( !bNameFound ) {
9587 size_t size = strlen(cm_NetbiosName) + 2;
9588 if ( !pHostNames ) {
9589 pHostNames = malloc(size);
9592 StringCbCopyA(pName, size, cm_NetbiosName);
9594 *pName = '\0'; /* add a second nul terminator */
9596 dwType = REG_MULTI_SZ;
9597 dwSize = (DWORD)(pName - pHostNames + 1);
9598 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9600 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9601 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9604 &hkLsa) == ERROR_SUCCESS )
9606 dwSize = sizeof(DWORD);
9607 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9610 dwSize = sizeof(DWORD);
9612 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9614 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9615 AFSREG_CLT_OPENAFS_SUBKEY,
9618 REG_OPTION_NON_VOLATILE,
9622 NULL) == ERROR_SUCCESS) {
9625 dwSize = sizeof(DWORD);
9627 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9628 bLoopbackCheckDisabled = TRUE;
9629 RegCloseKey(hkClient);
9634 } else if (!bLoopbackCheckDisabled) {
9635 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9636 AFSREG_CLT_OPENAFS_SUBKEY,
9639 REG_OPTION_NON_VOLATILE,
9643 NULL) == ERROR_SUCCESS) {
9645 dwSize = sizeof(DWORD);
9646 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9648 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9649 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9652 &hkLsa) == ERROR_SUCCESS )
9654 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9658 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9659 RegCloseKey(hkClient);
9668 RegCloseKey(hkMSV10);
9674 configureExtendedSMBSessionTimeouts(void)
9677 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9678 * new functionality:
9680 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9681 * "ReconnectableServers" REG_MULTI_SZ
9682 * "ExtendedSessTimeout" REG_DWORD (seconds)
9683 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
9685 * These values can be used to prevent the smb redirector from timing out
9686 * smb connection to the afs smb server prematurely.
9690 DWORD dwSize, dwAllocSize;
9692 PBYTE pHostNames = NULL, pName = NULL;
9693 BOOL bNameFound = FALSE;
9695 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9696 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9699 &hkLanMan) == ERROR_SUCCESS )
9701 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
9702 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9703 (dwType == REG_MULTI_SZ))
9705 dwAllocSize += 1 /* in case the source string is not nul terminated */
9706 + (DWORD)strlen(cm_NetbiosName) + 2;
9707 pHostNames = malloc(dwAllocSize);
9708 dwSize = dwAllocSize;
9709 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
9710 pHostNames, &dwSize) == ERROR_SUCCESS)
9712 for (pName = pHostNames;
9713 (pName - pHostNames < (int) dwSize) && *pName ;
9714 pName += strlen(pName) + 1)
9716 if ( !stricmp(pName, cm_NetbiosName) ) {
9724 if ( !bNameFound ) {
9725 size_t size = strlen(cm_NetbiosName) + 2;
9726 if ( !pHostNames ) {
9727 pHostNames = malloc(size);
9730 StringCbCopyA(pName, size, cm_NetbiosName);
9732 *pName = '\0'; /* add a second nul terminator */
9734 dwType = REG_MULTI_SZ;
9735 dwSize = (DWORD)(pName - pHostNames + 1);
9736 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9744 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
9745 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9746 (dwType == REG_MULTI_SZ))
9748 dwAllocSize += 1 /* in case the source string is not nul terminated */
9749 + (DWORD)strlen(cm_NetbiosName) + 2;
9750 pHostNames = malloc(dwAllocSize);
9751 dwSize = dwAllocSize;
9752 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
9753 pHostNames, &dwSize) == ERROR_SUCCESS)
9755 for (pName = pHostNames;
9756 (pName - pHostNames < (int) dwSize) && *pName ;
9757 pName += strlen(pName) + 1)
9759 if ( !stricmp(pName, cm_NetbiosName) ) {
9767 if ( !bNameFound ) {
9768 size_t size = strlen(cm_NetbiosName) + 2;
9769 if ( !pHostNames ) {
9770 pHostNames = malloc(size);
9773 StringCbCopyA(pName, size, cm_NetbiosName);
9775 *pName = '\0'; /* add a second nul terminator */
9777 dwType = REG_MULTI_SZ;
9778 dwSize = (DWORD)(pName - pHostNames + 1);
9779 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9787 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
9788 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9789 (dwType != REG_DWORD))
9792 dwSize = sizeof(dwValue);
9793 dwValue = 300; /* 5 minutes */
9794 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9796 RegCloseKey(hkLanMan);
9801 smb_LanAdapterChangeThread(void *param)
9804 * Give the IPAddrDaemon thread a chance
9805 * to block before we trigger.
9808 smb_LanAdapterChange(0);
9811 void smb_SetLanAdapterChangeDetected(void)
9816 lock_ObtainMutex(&smb_StartedLock);
9818 if (!powerStateSuspended) {
9819 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9820 NULL, 0, &lpid, "smb_LanAdapterChange");
9821 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9822 thrd_CloseHandle(phandle);
9825 smb_LanAdapterChangeDetected = 1;
9826 lock_ReleaseMutex(&smb_StartedLock);
9829 void smb_LanAdapterChange(int locked) {
9830 lana_number_t lanaNum;
9832 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9834 LANA_ENUM temp_list;
9839 afsi_log("smb_LanAdapterChange");
9842 lock_ObtainMutex(&smb_StartedLock);
9844 smb_LanAdapterChangeDetected = 0;
9846 if (!powerStateSuspended &&
9847 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9848 LANA_NETBIOS_NAME_FULL)) &&
9849 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9850 if ( isGateway != bGateway ) {
9851 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9852 smb_LANadapter, lanaNum, isGateway, bGateway);
9854 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9855 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9856 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9859 NCB *ncbp = smb_GetNCB();
9860 ncbp->ncb_command = NCBENUM;
9861 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9862 ncbp->ncb_length = sizeof(temp_list);
9863 code = Netbios(ncbp);
9865 if (temp_list.length != lana_list.length) {
9866 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9867 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9870 for (i=0; i<lana_list.length; i++) {
9871 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9872 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9873 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9885 smb_StopListeners(1);
9886 smb_RestartListeners(1);
9889 lock_ReleaseMutex(&smb_StartedLock);
9892 /* initialize Netbios */
9893 int smb_NetbiosInit(int locked)
9896 int i, lana, code, l;
9898 int delname_tried=0;
9901 lana_number_t lanaNum;
9904 lock_ObtainMutex(&smb_StartedLock);
9906 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9907 smb_ListenerState != SMB_LISTENER_STOPPED) {
9910 lock_ReleaseMutex(&smb_StartedLock);
9913 /* setup the NCB system */
9914 ncbp = smb_GetNCB();
9916 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9917 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9918 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9920 if (smb_LANadapter != LANA_INVALID)
9921 afsi_log("LAN adapter number %d", smb_LANadapter);
9923 afsi_log("LAN adapter number not determined");
9926 afsi_log("Set for gateway service");
9928 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9930 /* something went horribly wrong. We can't proceed without a netbios name */
9932 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9933 osi_panic(buf, __FILE__, __LINE__);
9936 /* remember the name */
9937 len = (int)strlen(cm_NetbiosName);
9939 free(smb_localNamep);
9940 smb_localNamep = malloc(len+1);
9941 strcpy(smb_localNamep, cm_NetbiosName);
9942 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9944 /* Also copy the value to the client character encoded string */
9945 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9947 if (smb_LANadapter == LANA_INVALID) {
9948 ncbp->ncb_command = NCBENUM;
9949 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9950 ncbp->ncb_length = sizeof(lana_list);
9951 code = Netbios(ncbp);
9953 afsi_log("Netbios NCBENUM error code %d", code);
9954 osi_panic(s, __FILE__, __LINE__);
9958 lana_list.length = 1;
9959 lana_list.lana[0] = smb_LANadapter;
9962 for (i = 0; i < lana_list.length; i++) {
9963 /* reset the adaptor: in Win32, this is required for every process, and
9964 * acts as an init call, not as a real hardware reset.
9966 ncbp->ncb_command = NCBRESET;
9967 ncbp->ncb_callname[0] = 100;
9968 ncbp->ncb_callname[2] = 100;
9969 ncbp->ncb_lana_num = lana_list.lana[i];
9970 code = Netbios(ncbp);
9972 code = ncbp->ncb_retcode;
9974 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9975 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9977 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9981 /* and declare our name so we can receive connections */
9982 memset(ncbp, 0, sizeof(*ncbp));
9983 len=lstrlen(smb_localNamep);
9984 memset(smb_sharename,' ',NCBNAMSZ);
9985 memcpy(smb_sharename,smb_localNamep,len);
9986 afsi_log("lana_list.length %d", lana_list.length);
9988 /* Keep the name so we can unregister it later */
9989 for (l = 0; l < lana_list.length; l++) {
9990 lana = lana_list.lana[l];
9992 ncbp->ncb_command = NCBADDNAME;
9993 ncbp->ncb_lana_num = lana;
9994 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9995 code = Netbios(ncbp);
9997 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9998 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10000 char name[NCBNAMSZ+1];
10002 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10003 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10007 code = ncbp->ncb_retcode;
10010 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10013 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10014 if (code == NRC_BRIDGE) { /* invalid LANA num */
10015 lana_list.lana[l] = LANA_INVALID;
10018 else if (code == NRC_DUPNAME) {
10019 afsi_log("Name already exists; try to delete it");
10020 memset(ncbp, 0, sizeof(*ncbp));
10021 ncbp->ncb_command = NCBDELNAME;
10022 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10023 ncbp->ncb_lana_num = lana;
10024 code = Netbios(ncbp);
10026 code = ncbp->ncb_retcode;
10028 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10030 if (code != 0 || delname_tried) {
10031 lana_list.lana[l] = LANA_INVALID;
10033 else if (code == 0) {
10034 if (!delname_tried) {
10042 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10043 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10047 smb_LANadapter = lana;
10048 lana_found = 1; /* at least one worked */
10052 osi_assertx(lana_list.length >= 0, "empty lana list");
10054 afsi_log("No valid LANA numbers found!");
10055 lana_list.length = 0;
10056 smb_LANadapter = LANA_INVALID;
10057 smb_ListenerState = SMB_LISTENER_STOPPED;
10058 cm_VolStatus_Network_Stopped(cm_NetbiosName
10065 /* we're done with the NCB now */
10068 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10069 if (lana_list.length > 0)
10070 osi_assert(smb_LANadapter != LANA_INVALID);
10073 lock_ReleaseMutex(&smb_StartedLock);
10075 return (lana_list.length > 0 ? 1 : 0);
10078 void smb_StartListeners(int locked)
10085 lock_ObtainMutex(&smb_StartedLock);
10087 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10089 lock_ReleaseMutex(&smb_StartedLock);
10093 afsi_log("smb_StartListeners");
10094 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10095 configureBackConnectionHostNames();
10097 /* Configure Extended SMB Session Timeouts */
10098 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10099 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10100 configureExtendedSMBSessionTimeouts();
10103 smb_ListenerState = SMB_LISTENER_STARTED;
10104 cm_VolStatus_Network_Started(cm_NetbiosName
10110 for (i = 0; i < lana_list.length; i++) {
10111 if (lana_list.lana[i] == LANA_INVALID)
10113 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10114 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10115 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10116 thrd_CloseHandle(phandle);
10119 lock_ReleaseMutex(&smb_StartedLock);
10122 void smb_RestartListeners(int locked)
10125 lock_ObtainMutex(&smb_StartedLock);
10127 if (powerStateSuspended)
10128 afsi_log("smb_RestartListeners called while suspended");
10130 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10131 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10132 if (smb_NetbiosInit(1))
10133 smb_StartListeners(1);
10134 } else if (smb_LanAdapterChangeDetected) {
10135 smb_LanAdapterChange(1);
10139 lock_ReleaseMutex(&smb_StartedLock);
10142 void smb_StopListener(NCB *ncbp, int lana, int wait)
10146 memset(ncbp, 0, sizeof(*ncbp));
10147 ncbp->ncb_command = NCBDELNAME;
10148 ncbp->ncb_lana_num = lana;
10149 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10150 code = Netbios(ncbp);
10152 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10153 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10155 /* and then reset the LANA; this will cause the listener threads to exit */
10156 ncbp->ncb_command = NCBRESET;
10157 ncbp->ncb_callname[0] = 100;
10158 ncbp->ncb_callname[2] = 100;
10159 ncbp->ncb_lana_num = lana;
10160 code = Netbios(ncbp);
10162 code = ncbp->ncb_retcode;
10164 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10166 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10170 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10173 void smb_StopListeners(int locked)
10179 lock_ObtainMutex(&smb_StartedLock);
10181 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10183 lock_ReleaseMutex(&smb_StartedLock);
10187 afsi_log("smb_StopListeners");
10188 smb_ListenerState = SMB_LISTENER_STOPPED;
10189 cm_VolStatus_Network_Stopped(cm_NetbiosName
10195 ncbp = smb_GetNCB();
10197 /* Unregister the SMB name */
10198 for (l = 0; l < lana_list.length; l++) {
10199 lana = lana_list.lana[l];
10201 if (lana != LANA_INVALID) {
10202 smb_StopListener(ncbp, lana, TRUE);
10204 /* mark the adapter invalid */
10205 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10209 /* force a re-evaluation of the network adapters */
10210 lana_list.length = 0;
10211 smb_LANadapter = LANA_INVALID;
10214 lock_ReleaseMutex(&smb_StartedLock);
10217 void smb_Init(osi_log_t *logp, int useV3,
10227 EVENT_HANDLE retHandle;
10228 char eventName[MAX_PATH];
10229 int startListeners = 0;
10231 smb_MBfunc = aMBfunc;
10235 /* Initialize smb_localZero */
10236 myTime.tm_isdst = -1; /* compute whether on DST or not */
10237 myTime.tm_year = 70;
10239 myTime.tm_mday = 1;
10240 myTime.tm_hour = 0;
10243 smb_localZero = mktime(&myTime);
10245 #ifdef AFS_FREELANCE_CLIENT
10246 /* Make sure the root.afs volume has the correct time */
10247 cm_noteLocalMountPointChange();
10250 /* initialize the remote debugging log */
10253 /* and the global lock */
10254 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10255 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10257 /* Raw I/O data structures */
10258 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10260 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10261 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10263 /* 4 Raw I/O buffers */
10264 smb_RawBufs = calloc(65536,1);
10265 *((char **)smb_RawBufs) = NULL;
10266 for (i=0; i<3; i++) {
10267 char *rawBuf = calloc(65536,1);
10268 *((char **)rawBuf) = smb_RawBufs;
10269 smb_RawBufs = rawBuf;
10272 /* global free lists */
10273 smb_ncbFreeListp = NULL;
10274 smb_packetFreeListp = NULL;
10276 lock_ObtainMutex(&smb_StartedLock);
10277 startListeners = smb_NetbiosInit(1);
10279 /* Initialize listener and server structures */
10281 memset(dead_sessions, 0, sizeof(dead_sessions));
10282 sprintf(eventName, "SessionEvents[0]");
10283 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10284 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10285 afsi_log("Event Object Already Exists: %s", eventName);
10287 smb_NumServerThreads = nThreads;
10288 sprintf(eventName, "NCBavails[0]");
10289 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10290 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10291 afsi_log("Event Object Already Exists: %s", eventName);
10292 sprintf(eventName, "NCBevents[0]");
10293 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10294 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10295 afsi_log("Event Object Already Exists: %s", eventName);
10296 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10297 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10298 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10299 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10300 afsi_log("Event Object Already Exists: %s", eventName);
10301 for (i = 0; i < smb_NumServerThreads; i++) {
10302 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10303 NCBreturns[i][0] = retHandle;
10306 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10307 for (i = 0; i < smb_NumServerThreads; i++) {
10308 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10309 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10310 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10311 afsi_log("Event Object Already Exists: %s", eventName);
10312 InitNCBslot((int)(i+1));
10314 numNCBs = smb_NumServerThreads + 1;
10316 /* Initialize dispatch table */
10317 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10318 /* Prepare the table for unknown operations */
10319 for(i=0; i<= SMB_NOPCODES; i++) {
10320 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10322 /* Fill in the ones we do know */
10323 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10324 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10325 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10326 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10327 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10328 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10329 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10330 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10331 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10332 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10333 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10334 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10335 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10336 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10337 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10338 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10339 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10340 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10341 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10342 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10343 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10344 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10345 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10346 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10347 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10348 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10349 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10350 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10351 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10352 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10353 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10354 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10355 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10356 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10357 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10358 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10359 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10360 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10361 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10362 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10363 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10364 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10365 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10366 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10367 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10368 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10369 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10370 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10371 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10372 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10373 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10374 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10375 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10376 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10377 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10378 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10379 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10380 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10381 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10382 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10383 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10384 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10385 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10386 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10387 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10388 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10389 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10390 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10391 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10392 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10393 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10394 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10395 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10396 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10398 /* setup tran 2 dispatch table */
10399 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10400 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10401 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10402 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10403 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10404 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10405 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10406 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10407 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10408 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10409 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10410 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10411 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10412 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10413 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10414 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10415 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10416 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10418 /* setup the rap dispatch table */
10419 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10420 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10421 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10422 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10423 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10427 /* if we are doing SMB authentication we have register outselves as a logon process */
10428 if (smb_authType != SMB_AUTH_NONE) {
10429 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10430 LSA_STRING afsProcessName;
10431 LSA_OPERATIONAL_MODE dummy; /*junk*/
10433 afsProcessName.Buffer = "OpenAFSClientDaemon";
10434 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10435 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10437 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10439 if (nts == STATUS_SUCCESS) {
10440 LSA_STRING packageName;
10441 /* we are registered. Find out the security package id */
10442 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10443 packageName.Length = (USHORT)strlen(packageName.Buffer);
10444 packageName.MaximumLength = packageName.Length + 1;
10445 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10446 if (nts == STATUS_SUCCESS) {
10448 * This code forces Windows to authenticate against the Logon Cache
10449 * first instead of attempting to authenticate against the Domain
10450 * Controller. When the Windows logon cache is enabled this improves
10451 * performance by removing the network access and works around a bug
10452 * seen at sites which are using a MIT Kerberos principal to login
10453 * to machines joined to a non-root domain in a multi-domain forest.
10454 * MsV1_0SetProcessOption was added in Windows XP.
10456 PVOID pResponse = NULL;
10457 ULONG cbResponse = 0;
10458 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10460 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10461 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10462 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10463 OptionsRequest.DisableOptions = FALSE;
10465 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10468 sizeof(OptionsRequest),
10474 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10475 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10478 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10480 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10481 afsi_log("MsV1_0SetProcessOption success");
10483 /* END - code from Larry */
10485 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10486 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10487 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10489 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10491 /* something went wrong. We report the error and revert back to no authentication
10492 because we can't perform any auth requests without a successful lsa handle
10493 or sec package id. */
10494 afsi_log("Reverting to NO SMB AUTH");
10495 smb_authType = SMB_AUTH_NONE;
10498 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10500 /* something went wrong. We report the error and revert back to no authentication
10501 because we can't perform any auth requests without a successful lsa handle
10502 or sec package id. */
10503 afsi_log("Reverting to NO SMB AUTH");
10504 smb_authType = SMB_AUTH_NONE;
10508 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10509 * time prevents the failure of authentication when logged into Windows with an
10510 * external Kerberos principal mapped to a local account.
10512 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10513 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10514 * then the only option is NTLMSSP anyway; so just fallback.
10519 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10520 if (secBlobLength == 0) {
10521 smb_authType = SMB_AUTH_NTLM;
10522 afsi_log("Reverting to SMB AUTH NTLM");
10531 /* Now get ourselves a domain name. */
10532 /* For now we are using the local computer name as the domain name.
10533 * It is actually the domain for local logins, and we are acting as
10534 * a local SMB server.
10536 bufsize = lengthof(smb_ServerDomainName) - 1;
10537 GetComputerNameW(smb_ServerDomainName, &bufsize);
10538 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10539 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10542 /* Start listeners, waiters, servers, and daemons */
10543 if (startListeners)
10544 smb_StartListeners(1);
10546 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10547 NULL, 0, &lpid, "smb_ClientWaiter");
10548 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10549 thrd_CloseHandle(phandle);
10551 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10552 NULL, 0, &lpid, "smb_ServerWaiter");
10553 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10554 thrd_CloseHandle(phandle);
10556 for (i=0; i<smb_NumServerThreads; i++) {
10557 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10558 (void *) i, 0, &lpid, "smb_Server");
10559 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10560 thrd_CloseHandle(phandle);
10563 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10564 NULL, 0, &lpid, "smb_Daemon");
10565 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10566 thrd_CloseHandle(phandle);
10568 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10569 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10570 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10571 thrd_CloseHandle(phandle);
10573 lock_ReleaseMutex(&smb_StartedLock);
10577 void smb_Shutdown(void)
10584 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10586 /* setup the NCB system */
10587 ncbp = smb_GetNCB();
10589 /* Block new sessions by setting shutdown flag */
10590 smbShutdownFlag = 1;
10592 /* Hang up all sessions */
10593 memset(ncbp, 0, sizeof(NCB));
10594 for (i = 1; i < numSessions; i++)
10596 if (dead_sessions[i])
10599 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10600 ncbp->ncb_command = NCBHANGUP;
10601 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10602 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10603 code = Netbios(ncbp);
10604 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10605 if (code == 0) code = ncbp->ncb_retcode;
10607 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10608 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10612 /* Trigger the shutdown of all SMB threads */
10613 for (i = 0; i < smb_NumServerThreads; i++)
10614 thrd_SetEvent(NCBreturns[i][0]);
10616 thrd_SetEvent(NCBevents[0]);
10617 thrd_SetEvent(SessionEvents[0]);
10618 thrd_SetEvent(NCBavails[0]);
10620 for (i = 0;i < smb_NumServerThreads; i++) {
10621 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10622 if (code == WAIT_OBJECT_0) {
10625 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10626 thrd_SetEvent(NCBreturns[i--][0]);
10630 /* Delete Netbios name */
10631 memset(ncbp, 0, sizeof(NCB));
10632 for (i = 0; i < lana_list.length; i++) {
10633 if (lana_list.lana[i] == LANA_INVALID) continue;
10634 ncbp->ncb_command = NCBDELNAME;
10635 ncbp->ncb_lana_num = lana_list.lana[i];
10636 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10637 code = Netbios(ncbp);
10639 code = ncbp->ncb_retcode;
10641 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10642 ncbp->ncb_lana_num, code);
10647 /* Release the reference counts held by the VCs */
10648 lock_ObtainWrite(&smb_rctLock);
10649 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10654 if (vcp->magic != SMB_VC_MAGIC)
10655 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10656 __FILE__, __LINE__);
10658 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10660 if (fidp->scp != NULL) {
10663 lock_ReleaseWrite(&smb_rctLock);
10664 lock_ObtainMutex(&fidp->mx);
10665 if (fidp->scp != NULL) {
10668 lock_ObtainWrite(&scp->rw);
10669 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10670 lock_ReleaseWrite(&scp->rw);
10671 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10672 cm_ReleaseSCache(scp);
10674 lock_ReleaseMutex(&fidp->mx);
10675 lock_ObtainWrite(&smb_rctLock);
10679 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10681 smb_ReleaseVCNoLock(tidp->vcp);
10683 cm_user_t *userp = tidp->userp;
10684 tidp->userp = NULL;
10685 cm_ReleaseUser(userp);
10689 lock_ReleaseWrite(&smb_rctLock);
10693 /* Get the UNC \\<servername>\<sharename> prefix. */
10694 char *smb_GetSharename()
10699 /* Make sure we have been properly initialized. */
10700 if (smb_localNamep == NULL)
10703 /* Allocate space for \\<servername>\<sharename>, plus the
10706 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10707 name = malloc(len);
10708 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10714 void smb_LogPacket(smb_packet_t *packet)
10718 unsigned length, paramlen, datalen, i, j;
10720 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10722 if (!packet) return;
10724 osi_Log0(smb_logp, "*** SMB packet dump ***");
10726 smbp = (smb_t *) packet->data;
10727 vp = (BYTE *) packet->data;
10729 paramlen = smbp->wct * 2;
10730 datalen = *((WORD *) (smbp->vdata + paramlen));
10731 length = sizeof(*smbp) + paramlen + 1 + datalen;
10733 for (i=0;i < length; i+=16)
10735 memset( buf, ' ', 80 );
10738 itoa( i, buf, 16 );
10740 buf[strlen(buf)] = ' ';
10742 cp = (BYTE*) buf + 7;
10744 for (j=0;j < 16 && (i+j)<length; j++)
10746 *(cp++) = hex[vp[i+j] >> 4];
10747 *(cp++) = hex[vp[i+j] & 0xf];
10757 for (j=0;j < 16 && (i+j)<length;j++)
10759 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10770 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10773 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10775 #endif /* LOG_PACKET */
10778 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10784 smb_username_t *unp;
10785 smb_waitingLockRequest_t *wlrp;
10788 lock_ObtainRead(&smb_rctLock);
10790 sprintf(output, "begin dumping smb_username_t\r\n");
10791 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10792 for (unp = usernamesp; unp; unp=unp->nextp)
10794 cm_ucell_t *ucellp;
10796 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10797 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10798 unp->name ? unp->name : _C("NULL"),
10799 unp->machine ? unp->machine : _C("NULL"));
10800 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10802 sprintf(output, " begin dumping cm_ucell_t\r\n");
10803 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10805 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10806 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",
10807 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10808 ucellp->expirationTime, ucellp->gen,
10810 ucellp->cellp->name);
10811 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10814 sprintf(output, " done dumping cm_ucell_t\r\n");
10815 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10818 sprintf(output, "done dumping smb_username_t\r\n");
10819 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10822 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10823 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10826 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10827 smb_waitingLock_t *lockp;
10829 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10830 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10831 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10833 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10834 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10835 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10836 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10837 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10838 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10840 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10841 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10844 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10845 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10847 sprintf(output, "begin dumping smb_vc_t\r\n");
10848 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10850 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10856 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10857 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10858 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10860 sprintf(output, " begin dumping smb_user_t\r\n");
10861 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10862 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10863 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10864 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10865 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10867 sprintf(output, " done dumping smb_user_t\r\n");
10868 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10870 sprintf(output, " begin dumping smb_tid_t\r\n");
10871 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10872 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10873 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",
10874 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10875 tidp->pathname ? tidp->pathname : _C("NULL"));
10876 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10878 sprintf(output, " done dumping smb_tid_t\r\n");
10879 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10881 sprintf(output, " begin dumping smb_fid_t\r\n");
10882 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10884 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10886 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",
10887 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10888 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10889 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10890 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10893 sprintf(output, " done dumping smb_fid_t\r\n");
10894 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10897 sprintf(output, "done dumping smb_vc_t\r\n");
10898 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10900 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10901 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10903 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10909 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10910 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10911 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10913 sprintf(output, " begin dumping smb_user_t\r\n");
10914 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10915 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10916 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10917 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10918 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10920 sprintf(output, " done dumping smb_user_t\r\n");
10921 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10923 sprintf(output, " begin dumping smb_tid_t\r\n");
10924 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10925 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10926 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",
10927 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10928 tidp->pathname ? tidp->pathname : _C("NULL"));
10929 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10931 sprintf(output, " done dumping smb_tid_t\r\n");
10932 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10934 sprintf(output, " begin dumping smb_fid_t\r\n");
10935 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10937 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10939 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",
10940 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10941 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10942 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10943 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10946 sprintf(output, " done dumping smb_fid_t\r\n");
10947 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10950 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10951 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10954 lock_ReleaseRead(&smb_rctLock);
10958 long smb_IsNetworkStarted(void)
10961 lock_ObtainWrite(&smb_globalLock);
10962 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10963 lock_ReleaseWrite(&smb_globalLock);