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)
2571 if (inPathp == lastSlashp)
2573 *outPathp++ = *inPathp++;
2582 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2583 char **chainpp, int flags)
2586 afs_uint32 type = *inp++;
2589 * The first byte specifies the type of the input string.
2590 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2594 /* Length Counted */
2595 case 0x1: /* Data Block */
2596 case 0x5: /* Variable Block */
2597 cb = *inp++ << 16 | *inp++;
2600 /* Null-terminated string */
2601 case 0x4: /* ASCII */
2602 case 0x3: /* Pathname */
2603 case 0x2: /* Dialect */
2604 cb = sizeof(pktp->data) - (inp - pktp->data);
2605 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2606 #ifdef DEBUG_UNICODE
2609 cb = sizeof(pktp->data);
2614 return NULL; /* invalid input */
2618 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2619 flags |= SMB_STRF_FORCEASCII;
2622 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2625 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2626 char ** chainpp, int flags)
2631 if (!WANTS_UNICODE(pktp))
2632 flags |= SMB_STRF_FORCEASCII;
2635 cb = sizeof(pktp->data) - (inp - pktp->data);
2636 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2637 #ifdef DEBUG_UNICODE
2640 cb = sizeof(pktp->data);
2642 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2643 flags | SMB_STRF_SRCNULTERM);
2646 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2647 size_t cb, char ** chainpp, int flags)
2650 if (!WANTS_UNICODE(pktp))
2651 flags |= SMB_STRF_FORCEASCII;
2654 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2657 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2658 size_t cch, char ** chainpp, int flags)
2663 if (!WANTS_UNICODE(pktp))
2664 flags |= SMB_STRF_FORCEASCII;
2666 cb = cch * sizeof(wchar_t);
2669 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2673 smb_ParseStringBuf(const unsigned char * bufbase,
2674 cm_space_t ** stringspp,
2675 unsigned char *inp, size_t *pcb_max,
2676 char **chainpp, int flags)
2679 if (!(flags & SMB_STRF_FORCEASCII)) {
2681 cm_space_t * spacep;
2684 if (bufbase && ((inp - bufbase) % 2) != 0) {
2685 inp++; /* unicode strings are always word aligned */
2689 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2691 cch_src = *pcb_max / sizeof(wchar_t);
2695 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2702 spacep = cm_GetSpace();
2703 spacep->nextp = *stringspp;
2704 *stringspp = spacep;
2708 *chainpp = inp + sizeof(wchar_t);
2711 *(spacep->wdata) = 0;
2712 return spacep->wdata;
2715 StringCchCopyNW(spacep->wdata,
2716 lengthof(spacep->wdata),
2717 (const clientchar_t *) inp, cch_src);
2720 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2722 return spacep->wdata;
2726 cm_space_t * spacep;
2729 /* Not using Unicode */
2731 *chainpp = inp + strlen(inp) + 1;
2734 spacep = cm_GetSpace();
2735 spacep->nextp = *stringspp;
2736 *stringspp = spacep;
2738 cchdest = lengthof(spacep->wdata);
2739 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2740 spacep->wdata, cchdest);
2742 return spacep->wdata;
2748 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2750 size_t * plen, int flags)
2756 /* we are only calculating the required size */
2763 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2765 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2766 if (!(flags & SMB_STRF_IGNORENUL))
2767 *plen += sizeof(wchar_t);
2769 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2779 cch_str = cm_ClientStrLen(str);
2780 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2783 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2791 /* if outp != NULL ... */
2793 /* Number of bytes left in the buffer.
2795 If outp lies inside the packet data buffer, we assume that the
2796 buffer is the packet data buffer. Otherwise we assume that the
2797 buffer is sizeof(packet->data).
2800 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2801 align = (int)((outp - pktp->data) % 2);
2802 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2804 align = (int)(((size_t) outp) % 2);
2805 buffersize = (int)sizeof(pktp->data);
2810 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2816 if (*str == _C('\0')) {
2818 if (buffersize < sizeof(wchar_t))
2821 *((wchar_t *) outp) = L'\0';
2822 if (plen && !(flags & SMB_STRF_IGNORENUL))
2823 *plen += sizeof(wchar_t);
2824 return outp + sizeof(wchar_t);
2827 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2829 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2830 osi_LogSaveClientString(smb_logp, str),
2836 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2838 return outp + sizeof(wchar_t) * nchars;
2846 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2849 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2851 return outp + cch_dest;
2855 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2861 tlen = inp[0] + (inp[1]<<8);
2862 inp += 2; /* skip length field */
2865 *chainpp = inp + tlen;
2874 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2878 if (*inp++ != 0x1) return NULL;
2879 tlen = inp[0] + (inp[1]<<8);
2880 inp += 2; /* skip length field */
2883 *chainpp = inp + tlen;
2886 if (lengthp) *lengthp = tlen;
2891 /* format a packet as a response */
2892 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2897 outp = (smb_t *) op;
2899 /* zero the basic structure through the smb_wct field, and zero the data
2900 * size field, assuming that wct stays zero; otherwise, you have to
2901 * explicitly set the data size field, too.
2903 inSmbp = (smb_t *) inp;
2904 memset(outp, 0, sizeof(smb_t)+2);
2910 outp->com = inSmbp->com;
2911 outp->tid = inSmbp->tid;
2912 outp->pid = inSmbp->pid;
2913 outp->uid = inSmbp->uid;
2914 outp->mid = inSmbp->mid;
2915 outp->res[0] = inSmbp->res[0];
2916 outp->res[1] = inSmbp->res[1];
2917 op->inCom = inSmbp->com;
2919 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2920 #ifdef SEND_CANONICAL_PATHNAMES
2921 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2923 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2925 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2926 outp->flg2 |= SMB_FLAGS2_UNICODE;
2929 /* copy fields in generic packet area */
2930 op->wctp = &outp->wct;
2933 /* send a (probably response) packet; vcp tells us to whom to send it.
2934 * we compute the length by looking at wct and bcc fields.
2936 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2946 ncbp = smb_GetNCB();
2950 memset((char *)ncbp, 0, sizeof(NCB));
2952 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2953 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2954 extra += tp[0] + (tp[1]<<8);
2955 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2956 extra += 3; /* wct and length fields */
2958 ncbp->ncb_length = extra; /* bytes to send */
2959 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2960 ncbp->ncb_lana_num = vcp->lana;
2961 ncbp->ncb_command = NCBSEND; /* op means send data */
2962 ncbp->ncb_buffer = (char *) inp;/* packet */
2963 code = Netbios(ncbp);
2966 const char * s = ncb_error_string(code);
2967 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2968 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2970 lock_ObtainMutex(&vcp->mx);
2971 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2972 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2974 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2975 lock_ReleaseMutex(&vcp->mx);
2976 lock_ObtainWrite(&smb_globalLock);
2977 dead_sessions[vcp->session] = TRUE;
2978 lock_ReleaseWrite(&smb_globalLock);
2979 smb_CleanupDeadVC(vcp);
2981 lock_ReleaseMutex(&vcp->mx);
2989 void smb_MapNTError(long code, unsigned long *NTStatusp)
2991 unsigned long NTStatus;
2993 /* map CM_ERROR_* errors to NT 32-bit status codes */
2994 /* NT Status codes are listed in ntstatus.h not winerror.h */
2998 else if (code == CM_ERROR_NOSUCHCELL) {
2999 NTStatus = 0xC000000FL; /* No such file */
3001 else if (code == CM_ERROR_NOSUCHVOLUME) {
3002 NTStatus = 0xC000000FL; /* No such file */
3004 else if (code == CM_ERROR_TIMEDOUT) {
3006 NTStatus = 0xC00000CFL; /* Sharing Paused */
3008 NTStatus = 0x00000102L; /* Timeout */
3011 else if (code == CM_ERROR_RETRY) {
3012 NTStatus = 0xC000022DL; /* Retry */
3014 else if (code == CM_ERROR_NOACCESS) {
3015 NTStatus = 0xC0000022L; /* Access denied */
3017 else if (code == CM_ERROR_READONLY) {
3018 NTStatus = 0xC00000A2L; /* Write protected */
3020 else if (code == CM_ERROR_NOSUCHFILE ||
3021 code == CM_ERROR_BPLUS_NOMATCH) {
3022 NTStatus = 0xC000000FL; /* No such file */
3024 else if (code == CM_ERROR_NOSUCHPATH) {
3025 NTStatus = 0xC000003AL; /* Object path not found */
3027 else if (code == CM_ERROR_TOOBIG) {
3028 NTStatus = 0xC000007BL; /* Invalid image format */
3030 else if (code == CM_ERROR_INVAL) {
3031 NTStatus = 0xC000000DL; /* Invalid parameter */
3033 else if (code == CM_ERROR_BADFD) {
3034 NTStatus = 0xC0000008L; /* Invalid handle */
3036 else if (code == CM_ERROR_BADFDOP) {
3037 NTStatus = 0xC0000022L; /* Access denied */
3039 else if (code == CM_ERROR_EXISTS) {
3040 NTStatus = 0xC0000035L; /* Object name collision */
3042 else if (code == CM_ERROR_NOTEMPTY) {
3043 NTStatus = 0xC0000101L; /* Directory not empty */
3045 else if (code == CM_ERROR_CROSSDEVLINK) {
3046 NTStatus = 0xC00000D4L; /* Not same device */
3048 else if (code == CM_ERROR_NOTDIR) {
3049 NTStatus = 0xC0000103L; /* Not a directory */
3051 else if (code == CM_ERROR_ISDIR) {
3052 NTStatus = 0xC00000BAL; /* File is a directory */
3054 else if (code == CM_ERROR_BADOP) {
3056 /* I have no idea where this comes from */
3057 NTStatus = 0xC09820FFL; /* SMB no support */
3059 NTStatus = 0xC00000BBL; /* Not supported */
3060 #endif /* COMMENT */
3062 else if (code == CM_ERROR_BADSHARENAME) {
3063 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3065 else if (code == CM_ERROR_NOIPC) {
3067 NTStatus = 0xC0000022L; /* Access Denied */
3069 NTStatus = 0xC000013DL; /* Remote Resources */
3072 else if (code == CM_ERROR_CLOCKSKEW) {
3073 NTStatus = 0xC0000133L; /* Time difference at DC */
3075 else if (code == CM_ERROR_BADTID) {
3076 NTStatus = 0xC0982005L; /* SMB bad TID */
3078 else if (code == CM_ERROR_USESTD) {
3079 NTStatus = 0xC09820FBL; /* SMB use standard */
3081 else if (code == CM_ERROR_QUOTA) {
3082 NTStatus = 0xC0000044L; /* Quota exceeded */
3084 else if (code == CM_ERROR_SPACE) {
3085 NTStatus = 0xC000007FL; /* Disk full */
3087 else if (code == CM_ERROR_ATSYS) {
3088 NTStatus = 0xC0000033L; /* Object name invalid */
3090 else if (code == CM_ERROR_BADNTFILENAME) {
3091 NTStatus = 0xC0000033L; /* Object name invalid */
3093 else if (code == CM_ERROR_WOULDBLOCK) {
3094 NTStatus = 0xC00000D8L; /* Can't wait */
3096 else if (code == CM_ERROR_SHARING_VIOLATION) {
3097 NTStatus = 0xC0000043L; /* Sharing violation */
3099 else if (code == CM_ERROR_LOCK_CONFLICT) {
3100 NTStatus = 0xC0000054L; /* Lock conflict */
3102 else if (code == CM_ERROR_PARTIALWRITE) {
3103 NTStatus = 0xC000007FL; /* Disk full */
3105 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3106 NTStatus = 0xC0000023L; /* Buffer too small */
3108 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3109 NTStatus = 0xC0000035L; /* Object name collision */
3111 else if (code == CM_ERROR_BADPASSWORD) {
3112 NTStatus = 0xC000006DL; /* unknown username or bad password */
3114 else if (code == CM_ERROR_BADLOGONTYPE) {
3115 NTStatus = 0xC000015BL; /* logon type not granted */
3117 else if (code == CM_ERROR_GSSCONTINUE) {
3118 NTStatus = 0xC0000016L; /* more processing required */
3120 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3122 NTStatus = 0xC0000280L; /* reparse point not resolved */
3124 NTStatus = 0xC0000022L; /* Access Denied */
3127 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3128 NTStatus = 0xC0000257L; /* Path Not Covered */
3130 else if (code == CM_ERROR_ALLBUSY) {
3131 NTStatus = 0xC000022DL; /* Retry */
3133 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3134 NTStatus = 0xC000003AL; /* Path not found */
3136 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3137 NTStatus = 0xC0000322L; /* No Kerberos key */
3139 else if (code == CM_ERROR_BAD_LEVEL) {
3140 NTStatus = 0xC0000148L; /* Invalid Level */
3142 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3143 NTStatus = 0xC000007EL; /* Range Not Locked */
3145 else if (code == CM_ERROR_NOSUCHDEVICE) {
3146 NTStatus = 0xC000000EL; /* No Such Device */
3148 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3149 NTStatus = 0xC0000055L; /* Lock Not Granted */
3151 else if (code == ENOMEM) {
3152 NTStatus = 0xC0000017L; /* Out of Memory */
3154 else if (code == CM_ERROR_RPC_MOREDATA) {
3155 NTStatus = 0x80000005L; /* Buffer overflow */
3158 NTStatus = 0xC0982001L; /* SMB non-specific error */
3161 *NTStatusp = NTStatus;
3162 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3166 * NTSTATUS <-> Win32 Error Translation
3167 * http://support.microsoft.com/kb/113996
3169 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3171 unsigned long Win32E;
3173 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3177 else if (code == CM_ERROR_NOSUCHCELL) {
3178 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3180 else if (code == CM_ERROR_NOSUCHVOLUME) {
3181 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3183 else if (code == CM_ERROR_TIMEDOUT) {
3185 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3187 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3190 else if (code == CM_ERROR_RETRY) {
3191 Win32E = ERROR_RETRY; /* Retry */
3193 else if (code == CM_ERROR_NOACCESS) {
3194 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3196 else if (code == CM_ERROR_READONLY) {
3197 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3199 else if (code == CM_ERROR_NOSUCHFILE ||
3200 code == CM_ERROR_BPLUS_NOMATCH) {
3201 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3203 else if (code == CM_ERROR_NOSUCHPATH) {
3204 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3206 else if (code == CM_ERROR_TOOBIG) {
3207 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3209 else if (code == CM_ERROR_INVAL) {
3210 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3212 else if (code == CM_ERROR_BADFD) {
3213 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3215 else if (code == CM_ERROR_BADFDOP) {
3216 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3218 else if (code == CM_ERROR_EXISTS) {
3219 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3221 else if (code == CM_ERROR_NOTEMPTY) {
3222 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3224 else if (code == CM_ERROR_CROSSDEVLINK) {
3225 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3227 else if (code == CM_ERROR_NOTDIR) {
3228 Win32E = ERROR_DIRECTORY; /* Not a directory */
3230 else if (code == CM_ERROR_ISDIR) {
3231 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3233 else if (code == CM_ERROR_BADOP) {
3234 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3236 else if (code == CM_ERROR_BADSHARENAME) {
3237 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3239 else if (code == CM_ERROR_NOIPC) {
3241 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3243 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3246 else if (code == CM_ERROR_CLOCKSKEW) {
3247 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3249 else if (code == CM_ERROR_BADTID) {
3250 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3252 else if (code == CM_ERROR_USESTD) {
3253 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3255 else if (code == CM_ERROR_QUOTA) {
3256 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3258 else if (code == CM_ERROR_SPACE) {
3259 Win32E = ERROR_DISK_FULL; /* Disk full */
3261 else if (code == CM_ERROR_ATSYS) {
3262 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3264 else if (code == CM_ERROR_BADNTFILENAME) {
3265 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3267 else if (code == CM_ERROR_WOULDBLOCK) {
3268 Win32E = WAIT_TIMEOUT; /* Can't wait */
3270 else if (code == CM_ERROR_SHARING_VIOLATION) {
3271 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3273 else if (code == CM_ERROR_LOCK_CONFLICT) {
3274 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3276 else if (code == CM_ERROR_PARTIALWRITE) {
3277 Win32E = ERROR_DISK_FULL; /* Disk full */
3279 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3280 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3282 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3283 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3285 else if (code == CM_ERROR_BADPASSWORD) {
3286 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3288 else if (code == CM_ERROR_BADLOGONTYPE) {
3289 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3291 else if (code == CM_ERROR_GSSCONTINUE) {
3292 Win32E = ERROR_MORE_DATA; /* more processing required */
3294 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3296 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3298 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3301 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3302 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3304 else if (code == CM_ERROR_ALLBUSY) {
3305 Win32E = ERROR_RETRY; /* Retry */
3307 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3308 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3310 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3311 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3313 else if (code == CM_ERROR_BAD_LEVEL) {
3314 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3316 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3317 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3319 else if (code == CM_ERROR_NOSUCHDEVICE) {
3320 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3322 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3323 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3325 else if (code == ENOMEM) {
3326 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3328 else if (code == CM_ERROR_RPC_MOREDATA) {
3329 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3332 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3336 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3339 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3340 unsigned char *classp)
3342 unsigned char class;
3343 unsigned short error;
3345 /* map CM_ERROR_* errors to SMB errors */
3346 if (code == CM_ERROR_NOSUCHCELL) {
3348 error = 3; /* bad path */
3350 else if (code == CM_ERROR_NOSUCHVOLUME) {
3352 error = 3; /* bad path */
3354 else if (code == CM_ERROR_TIMEDOUT) {
3356 error = 81; /* server is paused */
3358 else if (code == CM_ERROR_RETRY) {
3359 class = 2; /* shouldn't happen */
3362 else if (code == CM_ERROR_NOACCESS) {
3364 error = 4; /* bad access */
3366 else if (code == CM_ERROR_READONLY) {
3368 error = 19; /* read only */
3370 else if (code == CM_ERROR_NOSUCHFILE ||
3371 code == CM_ERROR_BPLUS_NOMATCH) {
3373 error = 2; /* ENOENT! */
3375 else if (code == CM_ERROR_NOSUCHPATH) {
3377 error = 3; /* Bad path */
3379 else if (code == CM_ERROR_TOOBIG) {
3381 error = 11; /* bad format */
3383 else if (code == CM_ERROR_INVAL) {
3384 class = 2; /* server non-specific error code */
3387 else if (code == CM_ERROR_BADFD) {
3389 error = 6; /* invalid file handle */
3391 else if (code == CM_ERROR_BADFDOP) {
3392 class = 1; /* invalid op on FD */
3395 else if (code == CM_ERROR_EXISTS) {
3397 error = 80; /* file already exists */
3399 else if (code == CM_ERROR_NOTEMPTY) {
3401 error = 5; /* delete directory not empty */
3403 else if (code == CM_ERROR_CROSSDEVLINK) {
3405 error = 17; /* EXDEV */
3407 else if (code == CM_ERROR_NOTDIR) {
3408 class = 1; /* bad path */
3411 else if (code == CM_ERROR_ISDIR) {
3412 class = 1; /* access denied; DOS doesn't have a good match */
3415 else if (code == CM_ERROR_BADOP) {
3419 else if (code == CM_ERROR_BADSHARENAME) {
3423 else if (code == CM_ERROR_NOIPC) {
3425 error = 4; /* bad access */
3427 else if (code == CM_ERROR_CLOCKSKEW) {
3428 class = 1; /* invalid function */
3431 else if (code == CM_ERROR_BADTID) {
3435 else if (code == CM_ERROR_USESTD) {
3439 else if (code == CM_ERROR_REMOTECONN) {
3443 else if (code == CM_ERROR_QUOTA) {
3444 if (vcp->flags & SMB_VCFLAG_USEV3) {
3446 error = 39; /* disk full */
3450 error = 5; /* access denied */
3453 else if (code == CM_ERROR_SPACE) {
3454 if (vcp->flags & SMB_VCFLAG_USEV3) {
3456 error = 39; /* disk full */
3460 error = 5; /* access denied */
3463 else if (code == CM_ERROR_PARTIALWRITE) {
3465 error = 39; /* disk full */
3467 else if (code == CM_ERROR_ATSYS) {
3469 error = 2; /* ENOENT */
3471 else if (code == CM_ERROR_WOULDBLOCK) {
3473 error = 33; /* lock conflict */
3475 else if (code == CM_ERROR_LOCK_CONFLICT) {
3477 error = 33; /* lock conflict */
3479 else if (code == CM_ERROR_SHARING_VIOLATION) {
3481 error = 33; /* lock conflict */
3483 else if (code == CM_ERROR_NOFILES) {
3485 error = 18; /* no files in search */
3487 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3489 error = 183; /* Samba uses this */
3491 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3492 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3494 error = 2; /* bad password */
3496 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3498 error = 3; /* bad path */
3507 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3510 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3512 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3513 return CM_ERROR_BADOP;
3517 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3519 unsigned short EchoCount, i;
3520 char *data, *outdata;
3523 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3525 for (i=1; i<=EchoCount; i++) {
3526 data = smb_GetSMBData(inp, &dataSize);
3527 smb_SetSMBParm(outp, 0, i);
3528 smb_SetSMBDataLength(outp, dataSize);
3529 outdata = smb_GetSMBData(outp, NULL);
3530 memcpy(outdata, data, dataSize);
3531 smb_SendPacket(vcp, outp);
3537 /* SMB_COM_READ_RAW */
3538 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3541 long count, minCount, finalCount;
3545 smb_t *smbp = (smb_t*) inp;
3547 cm_user_t *userp = NULL;
3550 char *rawBuf = NULL;
3555 fd = smb_GetSMBParm(inp, 0);
3556 count = smb_GetSMBParm(inp, 3);
3557 minCount = smb_GetSMBParm(inp, 4);
3558 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3560 if (*inp->wctp == 10) {
3561 /* we were sent a request with 64-bit file offsets */
3562 #ifdef AFS_LARGEFILES
3563 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3565 if (LargeIntegerLessThanZero(offset)) {
3566 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3570 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3571 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3574 offset.HighPart = 0;
3578 /* we were sent a request with 32-bit file offsets */
3579 offset.HighPart = 0;
3582 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3583 fd, offset.HighPart, offset.LowPart, count);
3585 fidp = smb_FindFID(vcp, fd, 0);
3589 lock_ObtainMutex(&fidp->mx);
3591 lock_ReleaseMutex(&fidp->mx);
3592 smb_ReleaseFID(fidp);
3593 return CM_ERROR_BADFD;
3596 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3597 lock_ReleaseMutex(&fidp->mx);
3598 smb_CloseFID(vcp, fidp, NULL, 0);
3599 code = CM_ERROR_NOSUCHFILE;
3605 LARGE_INTEGER LOffset, LLength;
3608 key = cm_GenerateKey(vcp->vcID, pid, fd);
3610 LOffset.HighPart = offset.HighPart;
3611 LOffset.LowPart = offset.LowPart;
3612 LLength.HighPart = 0;
3613 LLength.LowPart = count;
3615 lock_ObtainWrite(&fidp->scp->rw);
3616 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3617 lock_ReleaseWrite(&fidp->scp->rw);
3620 lock_ReleaseMutex(&fidp->mx);
3624 lock_ObtainMutex(&smb_RawBufLock);
3626 /* Get a raw buf, from head of list */
3627 rawBuf = smb_RawBufs;
3628 smb_RawBufs = *(char **)smb_RawBufs;
3630 lock_ReleaseMutex(&smb_RawBufLock);
3632 lock_ReleaseMutex(&fidp->mx);
3636 if (fidp->flags & SMB_FID_IOCTL)
3638 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3640 /* Give back raw buffer */
3641 lock_ObtainMutex(&smb_RawBufLock);
3642 *((char **) rawBuf) = smb_RawBufs;
3644 smb_RawBufs = rawBuf;
3645 lock_ReleaseMutex(&smb_RawBufLock);
3648 lock_ReleaseMutex(&fidp->mx);
3649 smb_ReleaseFID(fidp);
3652 lock_ReleaseMutex(&fidp->mx);
3654 userp = smb_GetUserFromVCP(vcp, inp);
3656 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3662 cm_ReleaseUser(userp);
3665 smb_ReleaseFID(fidp);
3669 memset((char *)ncbp, 0, sizeof(NCB));
3671 ncbp->ncb_length = (unsigned short) finalCount;
3672 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3673 ncbp->ncb_lana_num = vcp->lana;
3674 ncbp->ncb_command = NCBSEND;
3675 ncbp->ncb_buffer = rawBuf;
3677 code = Netbios(ncbp);
3679 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3682 /* Give back raw buffer */
3683 lock_ObtainMutex(&smb_RawBufLock);
3684 *((char **) rawBuf) = smb_RawBufs;
3686 smb_RawBufs = rawBuf;
3687 lock_ReleaseMutex(&smb_RawBufLock);
3693 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3695 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3700 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3702 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3707 /* SMB_COM_NEGOTIATE */
3708 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3715 int VistaProtoIndex;
3716 int protoIndex; /* index we're using */
3721 char protocol_array[10][1024]; /* protocol signature of the client */
3722 int caps; /* capabilities */
3725 TIME_ZONE_INFORMATION tzi;
3727 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3730 namep = smb_GetSMBData(inp, &dbytes);
3733 coreProtoIndex = -1; /* not found */
3736 VistaProtoIndex = -1;
3737 while(namex < dbytes) {
3738 osi_Log1(smb_logp, "Protocol %s",
3739 osi_LogSaveString(smb_logp, namep+1));
3740 strcpy(protocol_array[tcounter], namep+1);
3742 /* namep points at the first protocol, or really, a 0x02
3743 * byte preceding the null-terminated ASCII name.
3745 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3746 coreProtoIndex = tcounter;
3748 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3749 v3ProtoIndex = tcounter;
3751 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3752 NTProtoIndex = tcounter;
3754 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3755 VistaProtoIndex = tcounter;
3758 /* compute size of protocol entry */
3759 entryLength = (int)strlen(namep+1);
3760 entryLength += 2; /* 0x02 bytes and null termination */
3762 /* advance over this protocol entry */
3763 namex += entryLength;
3764 namep += entryLength;
3765 tcounter++; /* which proto entry we're looking at */
3768 lock_ObtainMutex(&vcp->mx);
3770 if (VistaProtoIndex != -1) {
3771 protoIndex = VistaProtoIndex;
3772 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3775 if (NTProtoIndex != -1) {
3776 protoIndex = NTProtoIndex;
3777 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3779 else if (v3ProtoIndex != -1) {
3780 protoIndex = v3ProtoIndex;
3781 vcp->flags |= SMB_VCFLAG_USEV3;
3783 else if (coreProtoIndex != -1) {
3784 protoIndex = coreProtoIndex;
3785 vcp->flags |= SMB_VCFLAG_USECORE;
3787 else protoIndex = -1;
3788 lock_ReleaseMutex(&vcp->mx);
3790 if (protoIndex == -1)
3791 return CM_ERROR_INVAL;
3792 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3793 smb_SetSMBParm(outp, 0, protoIndex);
3794 if (smb_authType != SMB_AUTH_NONE) {
3795 smb_SetSMBParmByte(outp, 1,
3796 NEGOTIATE_SECURITY_USER_LEVEL |
3797 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3799 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3801 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3802 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3803 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3804 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3805 /* The session key is not a well documented field however most clients
3806 * will echo back the session key to the server. Currently we are using
3807 * the same value for all sessions. We should generate a random value
3808 * and store it into the vcp
3810 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3811 smb_SetSMBParm(outp, 8, 1);
3813 * Tried changing the capabilities to support for W2K - defect 117695
3814 * Maybe something else needs to be changed here?
3818 smb_SetSMBParmLong(outp, 9, 0x43fd);
3820 smb_SetSMBParmLong(outp, 9, 0x251);
3823 * 32-bit error codes *
3829 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3831 NTNEGOTIATE_CAPABILITY_DFS |
3833 #ifdef AFS_LARGEFILES
3834 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3836 NTNEGOTIATE_CAPABILITY_NTFIND |
3837 NTNEGOTIATE_CAPABILITY_RAWMODE |
3838 NTNEGOTIATE_CAPABILITY_NTSMB;
3840 if ( smb_authType == SMB_AUTH_EXTENDED )
3841 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3844 if ( smb_UseUnicode ) {
3845 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3849 smb_SetSMBParmLong(outp, 9, caps);
3851 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3852 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3853 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3855 GetTimeZoneInformation(&tzi);
3856 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3858 if (smb_authType == SMB_AUTH_NTLM) {
3859 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3860 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3861 /* paste in encryption key */
3862 datap = smb_GetSMBData(outp, NULL);
3863 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3864 /* and the faux domain name */
3865 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3866 datap + MSV1_0_CHALLENGE_LENGTH,
3867 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3868 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3872 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3874 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3876 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3878 datap = smb_GetSMBData(outp, NULL);
3879 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3882 datap += sizeof(smb_ServerGUID);
3883 memcpy(datap, secBlob, secBlobLength);
3887 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3888 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3891 else if (v3ProtoIndex != -1) {
3892 smb_SetSMBParm(outp, 0, protoIndex);
3894 /* NOTE: Extended authentication cannot be negotiated with v3
3895 * therefore we fail over to NTLM
3897 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3898 smb_SetSMBParm(outp, 1,
3899 NEGOTIATE_SECURITY_USER_LEVEL |
3900 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3902 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3904 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3905 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3906 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3907 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3908 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3909 smb_SetSMBParm(outp, 7, 1);
3911 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3912 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3913 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3915 GetTimeZoneInformation(&tzi);
3916 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3918 /* NOTE: Extended authentication cannot be negotiated with v3
3919 * therefore we fail over to NTLM
3921 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3922 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3923 smb_SetSMBParm(outp, 12, 0); /* resvd */
3924 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3925 datap = smb_GetSMBData(outp, NULL);
3926 /* paste in a new encryption key */
3927 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3928 /* and the faux domain name */
3929 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3930 datap + MSV1_0_CHALLENGE_LENGTH,
3931 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3933 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3934 smb_SetSMBParm(outp, 12, 0); /* resvd */
3935 smb_SetSMBDataLength(outp, 0);
3938 else if (coreProtoIndex != -1) { /* not really supported anymore */
3939 smb_SetSMBParm(outp, 0, protoIndex);
3940 smb_SetSMBDataLength(outp, 0);
3945 void smb_CheckVCs(void)
3947 smb_vc_t * vcp, *nextp;
3948 smb_packet_t * outp = smb_GetPacket();
3951 lock_ObtainWrite(&smb_rctLock);
3952 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3954 if (vcp->magic != SMB_VC_MAGIC)
3955 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3956 __FILE__, __LINE__);
3958 /* on the first pass hold 'vcp' which was not held as 'nextp' */
3960 smb_HoldVCNoLock(vcp);
3963 * obtain a reference to 'nextp' now because we drop the
3964 * smb_rctLock later and the list contents could change
3965 * or 'vcp' could be destroyed when released.
3969 smb_HoldVCNoLock(nextp);
3971 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3972 smb_ReleaseVCNoLock(vcp);
3976 smb_FormatResponsePacket(vcp, NULL, outp);
3977 smbp = (smb_t *)outp;
3978 outp->inCom = smbp->com = 0x2b /* Echo */;
3986 smb_SetSMBParm(outp, 0, 0);
3987 smb_SetSMBDataLength(outp, 0);
3988 lock_ReleaseWrite(&smb_rctLock);
3990 smb_SendPacket(vcp, outp);
3992 lock_ObtainWrite(&smb_rctLock);
3993 smb_ReleaseVCNoLock(vcp);
3995 lock_ReleaseWrite(&smb_rctLock);
3996 smb_FreePacket(outp);
3999 void smb_Daemon(void *parmp)
4001 afs_uint32 count = 0;
4002 smb_username_t **unpp;
4005 while(smbShutdownFlag == 0) {
4009 if (smbShutdownFlag == 1)
4012 if ((count % 72) == 0) { /* every five minutes */
4014 time_t old_localZero = smb_localZero;
4016 /* Initialize smb_localZero */
4017 myTime.tm_isdst = -1; /* compute whether on DST or not */
4018 myTime.tm_year = 70;
4024 smb_localZero = mktime(&myTime);
4026 #ifdef AFS_FREELANCE
4027 if ( smb_localZero != old_localZero )
4028 cm_noteLocalMountPointChange();
4034 /* GC smb_username_t objects that will no longer be used */
4036 lock_ObtainWrite(&smb_rctLock);
4037 for ( unpp=&usernamesp; *unpp; ) {
4039 smb_username_t *unp;
4041 lock_ObtainMutex(&(*unpp)->mx);
4042 if ( (*unpp)->refCount > 0 ||
4043 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4044 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4046 else if (!smb_LogoffTokenTransfer ||
4047 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4049 lock_ReleaseMutex(&(*unpp)->mx);
4057 lock_FinalizeMutex(&unp->mx);
4063 cm_ReleaseUser(userp);
4065 unpp = &(*unpp)->nextp;
4068 lock_ReleaseWrite(&smb_rctLock);
4070 /* XXX GC dir search entries */
4074 void smb_WaitingLocksDaemon()
4076 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4077 smb_waitingLock_t *wl, *wlNext;
4080 smb_packet_t *inp, *outp;
4084 while (smbShutdownFlag == 0) {
4085 lock_ObtainWrite(&smb_globalLock);
4086 nwlRequest = smb_allWaitingLocks;
4087 if (nwlRequest == NULL) {
4088 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4093 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4100 lock_ObtainWrite(&smb_globalLock);
4102 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4104 wlRequest = nwlRequest;
4105 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4106 lock_ReleaseWrite(&smb_globalLock);
4110 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4111 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4114 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4115 code = CM_ERROR_LOCK_NOT_GRANTED;
4119 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4121 /* wl->state is either _DONE or _WAITING. _ERROR
4122 would no longer be on the queue. */
4123 code = cm_RetryLock( wl->lockp,
4124 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4127 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4128 } else if (code != CM_ERROR_WOULDBLOCK) {
4129 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4134 if (code == CM_ERROR_WOULDBLOCK) {
4137 if (wlRequest->msTimeout != 0xffffffff
4138 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4150 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4153 scp = wlRequest->scp;
4154 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4158 lock_ObtainWrite(&scp->rw);
4160 for (wl = wlRequest->locks; wl; wl = wlNext) {
4161 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4163 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4164 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4165 wl->LLength, wl->key, 0, NULL, &req);
4167 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4172 lock_ReleaseWrite(&scp->rw);
4176 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4179 for (wl = wlRequest->locks; wl; wl = wlNext) {
4180 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4181 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4186 vcp = wlRequest->vcp;
4187 inp = wlRequest->inp;
4188 outp = wlRequest->outp;
4189 ncbp = smb_GetNCB();
4190 ncbp->ncb_length = inp->ncb_length;
4191 inp->spacep = cm_GetSpace();
4193 /* Remove waitingLock from list */
4194 lock_ObtainWrite(&smb_globalLock);
4195 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4197 lock_ReleaseWrite(&smb_globalLock);
4199 /* Resume packet processing */
4201 smb_SetSMBDataLength(outp, 0);
4202 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4203 outp->resumeCode = code;
4205 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4208 cm_FreeSpace(inp->spacep);
4209 smb_FreePacket(inp);
4210 smb_FreePacket(outp);
4212 cm_ReleaseSCache(wlRequest->scp);
4215 } while (nwlRequest && smbShutdownFlag == 0);
4220 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4222 osi_Log0(smb_logp, "SMB receive get disk attributes");
4224 smb_SetSMBParm(outp, 0, 32000);
4225 smb_SetSMBParm(outp, 1, 64);
4226 smb_SetSMBParm(outp, 2, 1024);
4227 smb_SetSMBParm(outp, 3, 30000);
4228 smb_SetSMBParm(outp, 4, 0);
4229 smb_SetSMBDataLength(outp, 0);
4233 /* SMB_COM_TREE_CONNECT */
4234 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4238 unsigned short newTid;
4239 clientchar_t shareName[AFSPATHMAX];
4240 clientchar_t *sharePath;
4243 clientchar_t *pathp;
4246 osi_Log0(smb_logp, "SMB receive tree connect");
4248 /* parse input parameters */
4251 tbp = smb_GetSMBData(inp, NULL);
4252 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4254 return CM_ERROR_BADSMB;
4256 tp = cm_ClientStrRChr(pathp, '\\');
4258 return CM_ERROR_BADSMB;
4259 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4261 lock_ObtainMutex(&vcp->mx);
4262 newTid = vcp->tidCounter++;
4263 lock_ReleaseMutex(&vcp->mx);
4265 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4266 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4268 return CM_ERROR_BADSMB;
4269 userp = smb_GetUserFromUID(uidp);
4270 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4271 smb_ReleaseUID(uidp);
4273 smb_ReleaseTID(tidp, FALSE);
4274 return CM_ERROR_BADSHARENAME;
4276 lock_ObtainMutex(&tidp->mx);
4277 tidp->userp = userp;
4278 tidp->pathname = sharePath;
4279 lock_ReleaseMutex(&tidp->mx);
4280 smb_ReleaseTID(tidp, FALSE);
4282 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4283 smb_SetSMBParm(rsp, 1, newTid);
4284 smb_SetSMBDataLength(rsp, 0);
4286 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4290 /* set maskp to the mask part of the incoming path.
4291 * Mask is 11 bytes long (8.3 with the dot elided).
4292 * Returns true if succeeds with a valid name, otherwise it does
4293 * its best, but returns false.
4295 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4303 /* starts off valid */
4306 /* mask starts out all blanks */
4307 memset(maskp, ' ', 11);
4310 /* find last backslash, or use whole thing if there is none */
4311 tp = cm_ClientStrRChr(pathp, '\\');
4315 tp++; /* skip slash */
4319 /* names starting with a dot are illegal */
4327 if (tc == '.' || tc == '"')
4335 /* if we get here, tp point after the dot */
4336 up = maskp+8; /* ext goes here */
4343 if (tc == '.' || tc == '"')
4346 /* copy extension if not too long */
4356 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4358 clientchar_t umask[11];
4366 /* XXX redo this, calling cm_MatchMask with a converted mask */
4368 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4372 /* otherwise, we have a valid 8.3 name; see if we have a match,
4373 * treating '?' as a wildcard in maskp (but not in the file name).
4375 tp1 = umask; /* real name, in mask format */
4376 tp2 = maskp; /* mask, in mask format */
4377 for(i=0; i<11; i++) {
4378 tc1 = *tp1++; /* clientchar_t from real name */
4379 tc2 = *tp2++; /* clientchar_t from mask */
4380 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4381 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4384 if (tc2 == '?' && tc1 != ' ')
4391 /* we got a match */
4395 clientchar_t *smb_FindMask(clientchar_t *pathp)
4399 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4402 return tp+1; /* skip the slash */
4404 return pathp; /* no slash, return the entire path */
4407 /* SMB_COM_SEARCH for a volume label
4409 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4410 dispatch function.) */
4411 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4413 clientchar_t *pathp;
4415 clientchar_t mask[12];
4416 unsigned char *statBlockp;
4417 unsigned char initStatBlock[21];
4420 osi_Log0(smb_logp, "SMB receive search volume");
4422 /* pull pathname and stat block out of request */
4423 tp = smb_GetSMBData(inp, NULL);
4424 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4425 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4427 return CM_ERROR_BADSMB;
4428 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4429 osi_assertx(statBlockp != NULL, "null statBlock");
4431 statBlockp = initStatBlock;
4435 /* for returning to caller */
4436 smb_Get8Dot3MaskFromPath(mask, pathp);
4438 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4439 tp = smb_GetSMBData(outp, NULL);
4441 *tp++ = 43; /* bytes in a dir entry */
4442 *tp++ = 0; /* high byte in counter */
4444 /* now marshall the dir entry, starting with the search status */
4445 *tp++ = statBlockp[0]; /* Reserved */
4446 memcpy(tp, mask, 11); tp += 11; /* FileName */
4448 /* now pass back server use info, with 1st byte non-zero */
4450 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4452 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4454 *tp++ = 0x8; /* attribute: volume */
4464 /* 4 byte file size */
4470 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4473 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4474 memset(tp, ' ', 13);
4477 /* set the length of the data part of the packet to 43 + 3, for the dir
4478 * entry plus the 5 and the length fields.
4480 smb_SetSMBDataLength(outp, 46);
4485 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4486 clientchar_t * tidPathp, clientchar_t * relPathp,
4487 cm_user_t *userp, cm_req_t *reqp)
4495 smb_dirListPatch_t *patchp;
4496 smb_dirListPatch_t *npatchp;
4497 clientchar_t path[AFSPATHMAX];
4499 afs_int32 mustFake = 0;
4501 code = cm_FindACLCache(dscp, userp, &rights);
4503 lock_ObtainWrite(&dscp->rw);
4504 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4505 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4506 lock_ReleaseWrite(&dscp->rw);
4507 if (code == CM_ERROR_NOACCESS) {
4515 if (!mustFake) { /* Bulk Stat */
4517 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4519 memset(bsp, 0, sizeof(cm_bulkStat_t));
4521 for (patchp = *dirPatchespp, count=0;
4523 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4524 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4528 if (lock_TryWrite(&tscp->rw)) {
4529 /* we have an entry that we can look at */
4530 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4531 /* we have a callback on it. Don't bother
4532 * fetching this stat entry, since we're happy
4533 * with the info we have.
4535 lock_ReleaseWrite(&tscp->rw);
4536 cm_ReleaseSCache(tscp);
4539 lock_ReleaseWrite(&tscp->rw);
4541 cm_ReleaseSCache(tscp);
4545 bsp->fids[i].Volume = patchp->fid.volume;
4546 bsp->fids[i].Vnode = patchp->fid.vnode;
4547 bsp->fids[i].Unique = patchp->fid.unique;
4549 if (bsp->counter == AFSCBMAX) {
4550 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4551 memset(bsp, 0, sizeof(cm_bulkStat_t));
4555 if (bsp->counter > 0)
4556 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4561 for (patchp = *dirPatchespp; patchp; patchp =
4562 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4564 dptr = patchp->dptr;
4566 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4567 relPathp ? relPathp : _C(""), patchp->dep->name);
4568 reqp->relPathp = path;
4569 reqp->tidPathp = tidPathp;
4571 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4572 reqp->relPathp = reqp->tidPathp = NULL;
4575 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4576 *dptr++ = SMB_ATTR_HIDDEN;
4579 lock_ObtainWrite(&scp->rw);
4580 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4581 lock_ReleaseWrite(&scp->rw);
4583 /* set the attribute */
4584 switch (scp->fileType) {
4585 case CM_SCACHETYPE_DIRECTORY:
4586 case CM_SCACHETYPE_MOUNTPOINT:
4587 case CM_SCACHETYPE_INVALID:
4588 attr = SMB_ATTR_DIRECTORY;
4590 case CM_SCACHETYPE_SYMLINK:
4591 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4592 attr = SMB_ATTR_DIRECTORY;
4594 attr = SMB_ATTR_NORMAL;
4597 /* if we get here we either have a normal file
4598 * or we have a file for which we have never
4599 * received status info. In this case, we can
4600 * check the even/odd value of the entry's vnode.
4601 * odd means it is to be treated as a directory
4602 * and even means it is to be treated as a file.
4604 if (mustFake && (scp->fid.vnode & 0x1))
4605 attr = SMB_ATTR_DIRECTORY;
4607 attr = SMB_ATTR_NORMAL;
4611 /* 1969-12-31 23:59:58 +00*/
4612 dosTime = 0xEBBFBF7D;
4615 shortTemp = (unsigned short) (dosTime & 0xffff);
4616 *((u_short *)dptr) = shortTemp;
4619 /* and copy out date */
4620 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4621 *((u_short *)dptr) = shortTemp;
4624 /* copy out file length */
4625 *((u_long *)dptr) = 0;
4628 lock_ConvertWToR(&scp->rw);
4629 attr = smb_Attributes(scp);
4630 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4631 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4632 attr |= SMB_ATTR_HIDDEN;
4636 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4639 shortTemp = (unsigned short) (dosTime & 0xffff);
4640 *((u_short *)dptr) = shortTemp;
4643 /* and copy out date */
4644 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4645 *((u_short *)dptr) = shortTemp;
4648 /* copy out file length */
4649 *((u_long *)dptr) = scp->length.LowPart;
4651 lock_ReleaseRead(&scp->rw);
4653 cm_ReleaseSCache(scp);
4656 /* now free the patches */
4657 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4658 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4662 /* and mark the list as empty */
4663 *dirPatchespp = NULL;
4669 /* SMB_COM_SEARCH */
4670 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4676 clientchar_t *pathp;
4677 cm_dirEntry_t *dep = 0;
4679 smb_dirListPatch_t *dirListPatchesp;
4680 smb_dirListPatch_t *curPatchp;
4684 osi_hyper_t dirLength;
4685 osi_hyper_t bufferOffset;
4686 osi_hyper_t curOffset;
4688 unsigned char *inCookiep;
4689 smb_dirSearch_t *dsp;
4693 unsigned long clientCookie;
4694 cm_pageHeader_t *pageHeaderp;
4695 cm_user_t *userp = NULL;
4697 clientchar_t mask[12];
4699 long nextEntryCookie;
4700 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4701 char resByte; /* reserved byte from the cookie */
4702 char *op; /* output data ptr */
4703 char *origOp; /* original value of op */
4704 cm_space_t *spacep; /* for pathname buffer */
4708 clientchar_t *tidPathp = 0;
4715 maxCount = smb_GetSMBParm(inp, 0);
4717 dirListPatchesp = NULL;
4719 caseFold = CM_FLAG_CASEFOLD;
4721 tp = smb_GetSMBData(inp, NULL);
4722 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4723 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4725 return CM_ERROR_BADSMB;
4727 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4729 return CM_ERROR_BADSMB;
4731 /* We can handle long names */
4732 if (vcp->flags & SMB_VCFLAG_USENT)
4733 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4735 /* make sure we got a whole search status */
4736 if (dataLength < 21) {
4737 nextCookie = 0; /* start at the beginning of the dir */
4740 attribute = smb_GetSMBParm(inp, 1);
4742 /* handle volume info in another function */
4743 if (attribute & 0x8)
4744 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4746 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4747 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4749 if (*pathp == 0) { /* null pathp, treat as root dir */
4750 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4751 return CM_ERROR_NOFILES;
4755 dsp = smb_NewDirSearch(0);
4756 dsp->attribute = attribute;
4757 smb_Get8Dot3MaskFromPath(mask, pathp);
4758 memcpy(dsp->mask, mask, 12);
4760 /* track if this is likely to match a lot of entries */
4761 if (smb_Is8Dot3StarMask(mask))
4766 /* pull the next cookie value out of the search status block */
4767 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4768 + (inCookiep[16]<<24);
4769 dsp = smb_FindDirSearch(inCookiep[12]);
4771 /* can't find dir search status; fatal error */
4772 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4773 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4774 return CM_ERROR_BADFD;
4776 attribute = dsp->attribute;
4777 resByte = inCookiep[0];
4779 /* copy out client cookie, in host byte order. Don't bother
4780 * interpreting it, since we're just passing it through, anyway.
4782 memcpy(&clientCookie, &inCookiep[17], 4);
4784 memcpy(mask, dsp->mask, 12);
4786 /* assume we're doing a star match if it has continued for more
4792 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4793 nextCookie, dsp->cookie, attribute);
4795 userp = smb_GetUserFromVCP(vcp, inp);
4797 /* try to get the vnode for the path name next */
4798 lock_ObtainMutex(&dsp->mx);
4801 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4805 spacep = inp->spacep;
4806 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4807 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4809 lock_ReleaseMutex(&dsp->mx);
4810 cm_ReleaseUser(userp);
4811 smb_DeleteDirSearch(dsp);
4812 smb_ReleaseDirSearch(dsp);
4813 return CM_ERROR_NOFILES;
4815 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4816 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4818 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4819 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4822 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4825 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4826 cm_ReleaseSCache(scp);
4827 lock_ReleaseMutex(&dsp->mx);
4828 cm_ReleaseUser(userp);
4829 smb_DeleteDirSearch(dsp);
4830 smb_ReleaseDirSearch(dsp);
4831 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4832 return CM_ERROR_PATH_NOT_COVERED;
4834 return CM_ERROR_NOSUCHPATH;
4836 #endif /* DFS_SUPPORT */
4839 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4840 /* we need one hold for the entry we just stored into,
4841 * and one for our own processing. When we're done with this
4842 * function, we'll drop the one for our own processing.
4843 * We held it once from the namei call, and so we do another hold
4847 lock_ObtainWrite(&scp->rw);
4848 dsp->flags |= SMB_DIRSEARCH_BULKST;
4849 lock_ReleaseWrite(&scp->rw);
4852 lock_ReleaseMutex(&dsp->mx);
4854 cm_ReleaseUser(userp);
4855 smb_DeleteDirSearch(dsp);
4856 smb_ReleaseDirSearch(dsp);
4860 /* reserves space for parameter; we'll adjust it again later to the
4861 * real count of the # of entries we returned once we've actually
4862 * assembled the directory listing.
4864 smb_SetSMBParm(outp, 0, 0);
4866 /* get the directory size */
4867 lock_ObtainWrite(&scp->rw);
4868 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4869 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4871 lock_ReleaseWrite(&scp->rw);
4872 cm_ReleaseSCache(scp);
4873 cm_ReleaseUser(userp);
4874 smb_DeleteDirSearch(dsp);
4875 smb_ReleaseDirSearch(dsp);
4879 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4881 dirLength = scp->length;
4883 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4884 curOffset.HighPart = 0;
4885 curOffset.LowPart = nextCookie;
4886 origOp = op = smb_GetSMBData(outp, NULL);
4887 /* and write out the basic header */
4888 *op++ = 5; /* variable block */
4889 op += 2; /* skip vbl block length; we'll fill it in later */
4893 clientchar_t *actualName = NULL;
4894 int free_actualName = 0;
4895 clientchar_t shortName[13];
4896 clientchar_t *shortNameEnd;
4898 /* make sure that curOffset.LowPart doesn't point to the first
4899 * 32 bytes in the 2nd through last dir page, and that it doesn't
4900 * point at the first 13 32-byte chunks in the first dir page,
4901 * since those are dir and page headers, and don't contain useful
4904 temp = curOffset.LowPart & (2048-1);
4905 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4906 /* we're in the first page */
4907 if (temp < 13*32) temp = 13*32;
4910 /* we're in a later dir page */
4911 if (temp < 32) temp = 32;
4914 /* make sure the low order 5 bits are zero */
4917 /* now put temp bits back ito curOffset.LowPart */
4918 curOffset.LowPart &= ~(2048-1);
4919 curOffset.LowPart |= temp;
4921 /* check if we've returned all the names that will fit in the
4924 if (returnedNames >= maxCount) {
4925 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4926 returnedNames, maxCount);
4930 /* check if we've passed the dir's EOF */
4931 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4933 /* see if we can use the bufferp we have now; compute in which page
4934 * the current offset would be, and check whether that's the offset
4935 * of the buffer we have. If not, get the buffer.
4937 thyper.HighPart = curOffset.HighPart;
4938 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4939 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4942 buf_Release(bufferp);
4945 lock_ReleaseWrite(&scp->rw);
4946 code = buf_Get(scp, &thyper, &req, &bufferp);
4947 lock_ObtainMutex(&dsp->mx);
4949 /* now, if we're doing a star match, do bulk fetching of all of
4950 * the status info for files in the dir.
4953 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4955 lock_ObtainWrite(&scp->rw);
4956 lock_ReleaseMutex(&dsp->mx);
4958 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4962 bufferOffset = thyper;
4964 /* now get the data in the cache */
4966 code = cm_SyncOp(scp, bufferp, userp, &req,
4968 CM_SCACHESYNC_NEEDCALLBACK |
4969 CM_SCACHESYNC_READ);
4971 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4975 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4977 if (cm_HaveBuffer(scp, bufferp, 0)) {
4978 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4982 /* otherwise, load the buffer and try again */
4983 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4985 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4986 scp, bufferp, code);
4991 buf_Release(bufferp);
4995 } /* if (wrong buffer) ... */
4997 /* now we have the buffer containing the entry we're interested in; copy
4998 * it out if it represents a non-deleted entry.
5000 entryInDir = curOffset.LowPart & (2048-1);
5001 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5003 /* page header will help tell us which entries are free. Page header
5004 * can change more often than once per buffer, since AFS 3 dir page size
5005 * may be less than (but not more than a buffer package buffer.
5007 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5008 temp &= ~(2048 - 1); /* turn off intra-page bits */
5009 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5011 /* now determine which entry we're looking at in the page. If it is
5012 * free (there's a free bitmap at the start of the dir), we should
5013 * skip these 32 bytes.
5015 slotInPage = (entryInDir & 0x7e0) >> 5;
5016 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5017 /* this entry is free */
5018 numDirChunks = 1; /* only skip this guy */
5022 tp = bufferp->datap + entryInBuffer;
5023 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5025 /* while we're here, compute the next entry's location, too,
5026 * since we'll need it when writing out the cookie into the dir
5029 * XXXX Probably should do more sanity checking.
5031 numDirChunks = cm_NameEntries(dep->name, NULL);
5033 /* compute the offset of the cookie representing the next entry */
5034 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5036 /* Compute 8.3 name if necessary */
5037 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5038 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5041 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5042 actualName = shortName;
5043 free_actualName = 0;
5045 free_actualName = 1;
5048 if (actualName == NULL) {
5049 /* Couldn't convert the name for some reason */
5050 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5051 osi_LogSaveString(smb_logp, dep->name));
5055 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5056 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5057 osi_LogSaveClientString(smb_logp, actualName));
5059 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5060 /* this is one of the entries to use: it is not deleted
5061 * and it matches the star pattern we're looking for.
5064 /* Eliminate entries that don't match requested
5067 /* no hidden files */
5068 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5069 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5073 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5075 /* We have already done the cm_TryBulkStat above */
5076 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5077 fileType = cm_FindFileType(&fid);
5078 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5079 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5081 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5082 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5083 fileType == CM_SCACHETYPE_DFSLINK ||
5084 fileType == CM_SCACHETYPE_INVALID)
5085 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5090 memcpy(op, mask, 11); op += 11;
5091 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5092 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5093 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5094 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5095 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5096 memcpy(op, &clientCookie, 4); op += 4;
5098 /* now we emit the attribute. This is sort of tricky,
5099 * since we need to really stat the file to find out
5100 * what type of entry we've got. Right now, we're
5101 * copying out data from a buffer, while holding the
5102 * scp locked, so it isn't really convenient to stat
5103 * something now. We'll put in a place holder now,
5104 * and make a second pass before returning this to get
5105 * the real attributes. So, we just skip the data for
5106 * now, and adjust it later. We allocate a patch
5107 * record to make it easy to find this point later.
5108 * The replay will happen at a time when it is safe to
5109 * unlock the directory.
5111 curPatchp = malloc(sizeof(*curPatchp));
5112 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5113 curPatchp->dptr = op;
5114 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5116 /* do hidden attribute here since name won't be around when applying
5120 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5121 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5123 curPatchp->flags = 0;
5125 op += 9; /* skip attr, time, date and size */
5127 /* zero out name area. The spec says to pad with
5128 * spaces, but Samba doesn't, and neither do we.
5132 /* finally, we get to copy out the name; we know that
5133 * it fits in 8.3 or the pattern wouldn't match, but it
5134 * never hurts to be sure.
5136 cm_ClientStringToUtf8(actualName, -1, op, 13);
5137 if (smb_StoreAnsiFilenames)
5139 /* This is a UCHAR field, which is ASCII even if Unicode
5142 /* Uppercase if requested by client */
5143 if (!KNOWS_LONG_NAMES(inp))
5148 /* now, adjust the # of entries copied */
5150 } /* if we're including this name */
5153 if (free_actualName && actualName) {
5158 /* and adjust curOffset to be where the new cookie is */
5159 thyper.HighPart = 0;
5160 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5161 curOffset = LargeIntegerAdd(thyper, curOffset);
5162 } /* while copying data for dir listing */
5164 /* release the mutex */
5165 lock_ReleaseWrite(&scp->rw);
5167 buf_Release(bufferp);
5171 /* apply and free last set of patches; if not doing a star match, this
5172 * will be empty, but better safe (and freeing everything) than sorry.
5174 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5176 /* special return code for unsuccessful search */
5177 if (code == 0 && dataLength < 21 && returnedNames == 0)
5178 code = CM_ERROR_NOFILES;
5180 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5181 returnedNames, code);
5184 smb_DeleteDirSearch(dsp);
5185 smb_ReleaseDirSearch(dsp);
5186 cm_ReleaseSCache(scp);
5187 cm_ReleaseUser(userp);
5191 /* finalize the output buffer */
5192 smb_SetSMBParm(outp, 0, returnedNames);
5193 temp = (long) (op - origOp);
5194 smb_SetSMBDataLength(outp, temp);
5196 /* the data area is a variable block, which has a 5 (already there)
5197 * followed by the length of the # of data bytes. We now know this to
5198 * be "temp," although that includes the 3 bytes of vbl block header.
5199 * Deduct for them and fill in the length field.
5201 temp -= 3; /* deduct vbl block info */
5202 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5203 origOp[1] = (unsigned char)(temp & 0xff);
5204 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5205 if (returnedNames == 0)
5206 smb_DeleteDirSearch(dsp);
5207 smb_ReleaseDirSearch(dsp);
5208 cm_ReleaseSCache(scp);
5209 cm_ReleaseUser(userp);
5214 /* verify that this is a valid path to a directory. I don't know why they
5215 * don't use the get file attributes call.
5217 * SMB_COM_CHECK_DIRECTORY
5219 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5221 clientchar_t *pathp;
5223 cm_scache_t *rootScp;
5224 cm_scache_t *newScp;
5228 clientchar_t *tidPathp;
5234 pdata = smb_GetSMBData(inp, NULL);
5235 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5237 return CM_ERROR_BADSMB;
5238 osi_Log1(smb_logp, "SMB receive check path %S",
5239 osi_LogSaveClientString(smb_logp, pathp));
5241 rootScp = cm_data.rootSCachep;
5243 userp = smb_GetUserFromVCP(vcp, inp);
5245 caseFold = CM_FLAG_CASEFOLD;
5247 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5249 cm_ReleaseUser(userp);
5250 return CM_ERROR_NOSUCHPATH;
5252 code = cm_NameI(rootScp, pathp,
5253 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5254 userp, tidPathp, &req, &newScp);
5257 cm_ReleaseUser(userp);
5262 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5263 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5264 cm_ReleaseSCache(newScp);
5265 cm_ReleaseUser(userp);
5266 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5267 return CM_ERROR_PATH_NOT_COVERED;
5269 return CM_ERROR_NOSUCHPATH;
5271 #endif /* DFS_SUPPORT */
5273 /* now lock the vnode with a callback; returns with newScp locked */
5274 lock_ObtainWrite(&newScp->rw);
5275 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5276 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5278 if (code != CM_ERROR_NOACCESS) {
5279 lock_ReleaseWrite(&newScp->rw);
5280 cm_ReleaseSCache(newScp);
5281 cm_ReleaseUser(userp);
5285 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5288 attrs = smb_Attributes(newScp);
5290 if (!(attrs & SMB_ATTR_DIRECTORY))
5291 code = CM_ERROR_NOTDIR;
5293 lock_ReleaseWrite(&newScp->rw);
5295 cm_ReleaseSCache(newScp);
5296 cm_ReleaseUser(userp);
5300 /* SMB_COM_SET_INFORMATION */
5301 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5303 clientchar_t *pathp;
5305 cm_scache_t *rootScp;
5306 unsigned short attribute;
5308 cm_scache_t *newScp;
5312 clientchar_t *tidPathp;
5318 /* decode basic attributes we're passed */
5319 attribute = smb_GetSMBParm(inp, 0);
5320 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5322 datap = smb_GetSMBData(inp, NULL);
5323 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5325 return CM_ERROR_BADSMB;
5327 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5328 dosTime, attribute);
5330 rootScp = cm_data.rootSCachep;
5332 userp = smb_GetUserFromVCP(vcp, inp);
5334 caseFold = CM_FLAG_CASEFOLD;
5336 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5338 cm_ReleaseUser(userp);
5339 return CM_ERROR_NOSUCHFILE;
5341 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5342 tidPathp, &req, &newScp);
5345 cm_ReleaseUser(userp);
5350 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5351 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5352 cm_ReleaseSCache(newScp);
5353 cm_ReleaseUser(userp);
5354 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5355 return CM_ERROR_PATH_NOT_COVERED;
5357 return CM_ERROR_NOSUCHPATH;
5359 #endif /* DFS_SUPPORT */
5361 /* now lock the vnode with a callback; returns with newScp locked; we
5362 * need the current status to determine what the new status is, in some
5365 lock_ObtainWrite(&newScp->rw);
5366 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5367 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5369 lock_ReleaseWrite(&newScp->rw);
5370 cm_ReleaseSCache(newScp);
5371 cm_ReleaseUser(userp);
5375 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5377 /* Check for RO volume */
5378 if (newScp->flags & CM_SCACHEFLAG_RO) {
5379 lock_ReleaseWrite(&newScp->rw);
5380 cm_ReleaseSCache(newScp);
5381 cm_ReleaseUser(userp);
5382 return CM_ERROR_READONLY;
5385 /* prepare for setattr call */
5388 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5389 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5391 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
5392 /* we're told to make a writable file read-only */
5393 attr.unixModeBits = newScp->unixModeBits & ~0222;
5394 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5396 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5397 /* we're told to make a read-only file writable */
5398 attr.unixModeBits = newScp->unixModeBits | 0222;
5399 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5401 lock_ReleaseWrite(&newScp->rw);
5403 /* now call setattr */
5405 code = cm_SetAttr(newScp, &attr, userp, &req);
5409 cm_ReleaseSCache(newScp);
5410 cm_ReleaseUser(userp);
5416 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5418 clientchar_t *pathp;
5420 cm_scache_t *rootScp;
5421 cm_scache_t *newScp, *dscp;
5426 clientchar_t *tidPathp;
5428 clientchar_t *lastComp;
5434 datap = smb_GetSMBData(inp, NULL);
5435 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5437 return CM_ERROR_BADSMB;
5439 if (*pathp == 0) /* null path */
5442 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5443 osi_LogSaveClientString(smb_logp, pathp));
5445 rootScp = cm_data.rootSCachep;
5447 userp = smb_GetUserFromVCP(vcp, inp);
5449 /* we shouldn't need this for V3 requests, but we seem to */
5450 caseFold = CM_FLAG_CASEFOLD;
5452 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5454 cm_ReleaseUser(userp);
5455 return CM_ERROR_NOSUCHFILE;
5459 * XXX Strange hack XXX
5461 * As of Patch 5 (16 July 97), we are having the following problem:
5462 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5463 * requests to look up "desktop.ini" in all the subdirectories.
5464 * This can cause zillions of timeouts looking up non-existent cells
5465 * and volumes, especially in the top-level directory.
5467 * We have not found any way to avoid this or work around it except
5468 * to explicitly ignore the requests for mount points that haven't
5469 * yet been evaluated and for directories that haven't yet been
5472 * We should modify this hack to provide a fake desktop.ini file
5473 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5475 spacep = inp->spacep;
5476 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5477 #ifndef SPECIAL_FOLDERS
5478 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5479 code = cm_NameI(rootScp, spacep->wdata,
5480 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5481 userp, tidPathp, &req, &dscp);
5484 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5485 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5487 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5488 return CM_ERROR_PATH_NOT_COVERED;
5490 return CM_ERROR_NOSUCHPATH;
5492 #endif /* DFS_SUPPORT */
5493 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5494 code = CM_ERROR_NOSUCHFILE;
5495 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5496 cm_buf_t *bp = buf_Find(dscp, &hzero);
5501 code = CM_ERROR_NOSUCHFILE;
5503 cm_ReleaseSCache(dscp);
5505 cm_ReleaseUser(userp);
5510 #endif /* SPECIAL_FOLDERS */
5512 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5513 tidPathp, &req, &newScp);
5515 cm_ReleaseUser(userp);
5520 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5521 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5522 cm_ReleaseSCache(newScp);
5523 cm_ReleaseUser(userp);
5524 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5525 return CM_ERROR_PATH_NOT_COVERED;
5527 return CM_ERROR_NOSUCHPATH;
5529 #endif /* DFS_SUPPORT */
5531 /* now lock the vnode with a callback; returns with newScp locked */
5532 lock_ObtainWrite(&newScp->rw);
5533 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5534 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5536 lock_ReleaseWrite(&newScp->rw);
5537 cm_ReleaseSCache(newScp);
5538 cm_ReleaseUser(userp);
5542 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5544 attrs = smb_Attributes(newScp);
5546 smb_SetSMBParm(outp, 0, attrs);
5548 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5549 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5550 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5551 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5552 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5553 smb_SetSMBParm(outp, 5, 0);
5554 smb_SetSMBParm(outp, 6, 0);
5555 smb_SetSMBParm(outp, 7, 0);
5556 smb_SetSMBParm(outp, 8, 0);
5557 smb_SetSMBParm(outp, 9, 0);
5558 smb_SetSMBDataLength(outp, 0);
5559 lock_ReleaseWrite(&newScp->rw);
5561 cm_ReleaseSCache(newScp);
5562 cm_ReleaseUser(userp);
5567 /* SMB_COM_TREE_DISCONNECT */
5568 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5572 osi_Log0(smb_logp, "SMB receive tree disconnect");
5574 /* find the tree and free it */
5575 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5577 lock_ObtainWrite(&smb_rctLock);
5579 smb_ReleaseTID(tidp, TRUE);
5580 lock_ReleaseWrite(&smb_rctLock);
5587 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5590 clientchar_t *pathp;
5591 clientchar_t *lastNamep;
5600 clientchar_t *tidPathp;
5606 datap = smb_GetSMBData(inp, NULL);
5607 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5609 return CM_ERROR_BADSMB;
5611 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5613 #ifdef DEBUG_VERBOSE
5617 hexpath = osi_HexifyString( pathp );
5618 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5623 share = smb_GetSMBParm(inp, 0);
5624 attribute = smb_GetSMBParm(inp, 1);
5626 spacep = inp->spacep;
5627 /* smb_StripLastComponent will strip "::$DATA" if present */
5628 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5630 if (!cm_IsValidClientString(pathp)) {
5632 clientchar_t * hexp;
5634 hexp = cm_GetRawCharsAlloc(pathp, -1);
5635 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5636 osi_LogSaveClientString(smb_logp, hexp));
5640 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5642 return CM_ERROR_BADNTFILENAME;
5645 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5646 /* special case magic file name for receiving IOCTL requests
5647 * (since IOCTL calls themselves aren't getting through).
5649 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5650 smb_SetupIoctlFid(fidp, spacep);
5651 smb_SetSMBParm(outp, 0, fidp->fid);
5652 smb_SetSMBParm(outp, 1, 0); /* attrs */
5653 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5654 smb_SetSMBParm(outp, 3, 0);
5655 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5656 smb_SetSMBParm(outp, 5, 0x7fff);
5657 /* pass the open mode back */
5658 smb_SetSMBParm(outp, 6, (share & 0xf));
5659 smb_SetSMBDataLength(outp, 0);
5660 smb_ReleaseFID(fidp);
5664 userp = smb_GetUserFromVCP(vcp, inp);
5666 caseFold = CM_FLAG_CASEFOLD;
5668 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5670 cm_ReleaseUser(userp);
5671 return CM_ERROR_NOSUCHPATH;
5673 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5674 tidPathp, &req, &scp);
5677 cm_ReleaseUser(userp);
5682 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5683 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5684 cm_ReleaseSCache(scp);
5685 cm_ReleaseUser(userp);
5686 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5687 return CM_ERROR_PATH_NOT_COVERED;
5689 return CM_ERROR_NOSUCHPATH;
5691 #endif /* DFS_SUPPORT */
5693 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5695 cm_ReleaseSCache(scp);
5696 cm_ReleaseUser(userp);
5700 /* don't need callback to check file type, since file types never
5701 * change, and namei and cm_Lookup all stat the object at least once on
5702 * a successful return.
5704 if (scp->fileType != CM_SCACHETYPE_FILE) {
5705 cm_ReleaseSCache(scp);
5706 cm_ReleaseUser(userp);
5707 return CM_ERROR_ISDIR;
5710 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5711 osi_assertx(fidp, "null smb_fid_t");
5713 lock_ObtainMutex(&fidp->mx);
5714 if ((share & 0xf) == 0)
5715 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5716 else if ((share & 0xf) == 1)
5717 fidp->flags |= SMB_FID_OPENWRITE;
5719 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5723 fidp->userp = userp;
5725 /* and a pointer to the vnode */
5727 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5728 lock_ObtainWrite(&scp->rw);
5729 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5731 smb_SetSMBParm(outp, 0, fidp->fid);
5732 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5733 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5734 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5735 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5736 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5737 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5738 /* pass the open mode back; XXXX add access checks */
5739 smb_SetSMBParm(outp, 6, (share & 0xf));
5740 smb_SetSMBDataLength(outp, 0);
5741 lock_ReleaseMutex(&fidp->mx);
5742 lock_ReleaseRead(&scp->rw);
5745 cm_Open(scp, 0, userp);
5747 /* send and free packet */
5748 smb_ReleaseFID(fidp);
5749 cm_ReleaseUser(userp);
5750 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5754 typedef struct smb_unlinkRock {
5759 clientchar_t *maskp; /* pointer to the star pattern */
5762 cm_dirEntryList_t * matches;
5765 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5768 smb_unlinkRock_t *rockp;
5771 normchar_t matchName[MAX_PATH];
5775 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5776 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5777 caseFold |= CM_FLAG_8DOT3;
5779 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5780 /* Can't convert name */
5781 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5782 osi_LogSaveString(smb_logp, dep->name));
5786 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5788 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5789 !cm_Is8Dot3(matchName)) {
5790 cm_Gen8Dot3Name(dep, matchName, NULL);
5791 /* 8.3 matches are always case insensitive */
5792 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5795 osi_Log1(smb_logp, "Found match %S",
5796 osi_LogSaveClientString(smb_logp, matchName));
5798 cm_DirEntryListAdd(dep->name, &rockp->matches);
5802 /* If we made a case sensitive exact match, we might as well quit now. */
5803 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5804 code = CM_ERROR_STOPNOW;
5813 /* SMB_COM_DELETE */
5814 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5818 clientchar_t *pathp;
5822 clientchar_t *lastNamep;
5823 smb_unlinkRock_t rock;
5827 clientchar_t *tidPathp;
5831 memset(&rock, 0, sizeof(rock));
5833 attribute = smb_GetSMBParm(inp, 0);
5835 tp = smb_GetSMBData(inp, NULL);
5836 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5838 return CM_ERROR_BADSMB;
5840 osi_Log1(smb_logp, "SMB receive unlink %S",
5841 osi_LogSaveClientString(smb_logp, pathp));
5843 spacep = inp->spacep;
5844 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5846 userp = smb_GetUserFromVCP(vcp, inp);
5848 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5850 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5852 cm_ReleaseUser(userp);
5853 return CM_ERROR_NOSUCHPATH;
5855 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5858 cm_ReleaseUser(userp);
5863 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5864 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5865 cm_ReleaseSCache(dscp);
5866 cm_ReleaseUser(userp);
5867 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5868 return CM_ERROR_PATH_NOT_COVERED;
5870 return CM_ERROR_NOSUCHPATH;
5872 #endif /* DFS_SUPPORT */
5874 /* otherwise, scp points to the parent directory. */
5881 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5883 code = CM_ERROR_NOSUCHFILE;
5886 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5889 thyper.HighPart = 0;
5894 rock.matches = NULL;
5896 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5897 * match. If that fails, we do a case insensitve match.
5899 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5900 !smb_IsStarMask(rock.maskp)) {
5901 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5904 thyper.HighPart = 0;
5905 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5910 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5912 if (code == CM_ERROR_STOPNOW)
5915 if (code == 0 && rock.matches) {
5916 cm_dirEntryList_t * entry;
5918 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5919 normchar_t normalizedName[MAX_PATH];
5921 /* Note: entry->name is a non-normalized name */
5923 osi_Log1(smb_logp, "Unlinking %s",
5924 osi_LogSaveString(smb_logp, entry->name));
5926 /* We assume this works because entry->name was
5927 successfully converted in smb_UnlinkProc() once. */
5928 cm_FsStringToNormString(entry->name, -1,
5929 normalizedName, lengthof(normalizedName));
5931 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5933 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5934 smb_NotifyChange(FILE_ACTION_REMOVED,
5935 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5936 dscp, normalizedName, NULL, TRUE);
5940 cm_DirEntryListFree(&rock.matches);
5944 cm_ReleaseUser(userp);
5947 cm_ReleaseSCache(dscp);
5952 if (code == 0 && !rock.any)
5953 code = CM_ERROR_NOSUCHFILE;
5957 typedef struct smb_renameRock {
5958 cm_scache_t *odscp; /* old dir */
5959 cm_scache_t *ndscp; /* new dir */
5960 cm_user_t *userp; /* user */
5961 cm_req_t *reqp; /* request struct */
5962 smb_vc_t *vcp; /* virtual circuit */
5963 normchar_t *maskp; /* pointer to star pattern of old file name */
5964 int flags; /* tilde, casefold, etc */
5965 clientchar_t *newNamep; /* ptr to the new file's name */
5966 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5967 clientchar_t clOldName[MAX_PATH]; /* client name */
5971 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5974 smb_renameRock_t *rockp;
5977 normchar_t matchName[MAX_PATH];
5979 rockp = (smb_renameRock_t *) vrockp;
5981 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5982 /* Can't convert string */
5983 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
5984 osi_LogSaveString(smb_logp, dep->name));
5988 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5989 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5990 caseFold |= CM_FLAG_8DOT3;
5992 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5994 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5995 !cm_Is8Dot3(matchName)) {
5996 cm_Gen8Dot3Name(dep, matchName, NULL);
5997 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6002 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6003 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6005 code = CM_ERROR_STOPNOW;
6015 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6018 cm_space_t *spacep = NULL;
6019 smb_renameRock_t rock;
6020 cm_scache_t *oldDscp = NULL;
6021 cm_scache_t *newDscp = NULL;
6022 cm_scache_t *tmpscp= NULL;
6023 cm_scache_t *tmpscp2 = NULL;
6024 clientchar_t *oldLastNamep;
6025 clientchar_t *newLastNamep;
6029 clientchar_t *tidPathp;
6033 userp = smb_GetUserFromVCP(vcp, inp);
6034 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6036 cm_ReleaseUser(userp);
6037 return CM_ERROR_NOSUCHPATH;
6041 memset(&rock, 0, sizeof(rock));
6043 spacep = inp->spacep;
6044 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6046 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6047 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6048 userp, tidPathp, &req, &oldDscp);
6050 cm_ReleaseUser(userp);
6055 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6056 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6057 cm_ReleaseSCache(oldDscp);
6058 cm_ReleaseUser(userp);
6059 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6060 return CM_ERROR_PATH_NOT_COVERED;
6062 return CM_ERROR_NOSUCHPATH;
6064 #endif /* DFS_SUPPORT */
6066 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6067 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6068 userp, tidPathp, &req, &newDscp);
6071 cm_ReleaseSCache(oldDscp);
6072 cm_ReleaseUser(userp);
6077 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6078 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6079 cm_ReleaseSCache(oldDscp);
6080 cm_ReleaseSCache(newDscp);
6081 cm_ReleaseUser(userp);
6082 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6083 return CM_ERROR_PATH_NOT_COVERED;
6085 return CM_ERROR_NOSUCHPATH;
6087 #endif /* DFS_SUPPORT */
6090 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6091 * next, get the component names, and lower case them.
6094 /* handle the old name first */
6096 oldLastNamep = oldPathp;
6100 /* and handle the new name, too */
6102 newLastNamep = newPathp;
6106 /* TODO: The old name could be a wildcard. The new name must not be */
6108 /* Check if the file already exists; if so return error */
6109 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6110 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6111 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6113 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6114 osi_LogSaveClientString(smb_logp, newLastNamep));
6116 /* Check if the old and the new names differ only in case. If so return
6117 * success, else return CM_ERROR_EXISTS
6119 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6121 /* This would be a success only if the old file is *as same as* the new file */
6122 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6124 if (tmpscp == tmpscp2)
6127 code = CM_ERROR_EXISTS;
6128 cm_ReleaseSCache(tmpscp2);
6131 code = CM_ERROR_NOSUCHFILE;
6134 /* file exist, do not rename, also fixes move */
6135 osi_Log0(smb_logp, "Can't rename. Target already exists");
6136 code = CM_ERROR_EXISTS;
6141 /* do the vnode call */
6142 rock.odscp = oldDscp;
6143 rock.ndscp = newDscp;
6147 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6149 code = CM_ERROR_NOSUCHFILE;
6152 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6153 rock.newNamep = newLastNamep;
6154 rock.fsOldName[0] = '\0';
6155 rock.clOldName[0] = '\0';
6158 /* Now search the directory for the pattern, and do the appropriate rename when found */
6159 thyper.LowPart = 0; /* search dir from here */
6160 thyper.HighPart = 0;
6162 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6163 if (code == 0 && !rock.any) {
6165 thyper.HighPart = 0;
6166 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6167 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6169 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6171 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6172 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6173 rock.ndscp, rock.newNamep, rock.userp,
6175 /* if the call worked, stop doing the search now, since we
6176 * really only want to rename one file.
6179 osi_Log0(smb_logp, "cm_Rename failure");
6180 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6181 } else if (code == 0) {
6182 code = CM_ERROR_NOSUCHFILE;
6185 /* Handle Change Notification */
6187 * Being lazy, not distinguishing between files and dirs in this
6188 * filter, since we'd have to do a lookup.
6191 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6192 if (oldDscp == newDscp) {
6193 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6194 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6195 filter, oldDscp, rock.clOldName,
6196 newLastNamep, TRUE);
6198 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6199 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6200 filter, oldDscp, rock.clOldName,
6202 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6203 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6204 filter, newDscp, newLastNamep,
6211 cm_ReleaseSCache(tmpscp);
6213 cm_ReleaseUser(userp);
6215 cm_ReleaseSCache(oldDscp);
6217 cm_ReleaseSCache(newDscp);
6225 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6228 cm_space_t *spacep = NULL;
6229 cm_scache_t *oldDscp = NULL;
6230 cm_scache_t *newDscp = NULL;
6231 cm_scache_t *tmpscp= NULL;
6232 cm_scache_t *tmpscp2 = NULL;
6233 cm_scache_t *sscp = NULL;
6234 clientchar_t *oldLastNamep;
6235 clientchar_t *newLastNamep;
6238 clientchar_t *tidPathp;
6242 userp = smb_GetUserFromVCP(vcp, inp);
6244 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6246 cm_ReleaseUser(userp);
6247 return CM_ERROR_NOSUCHPATH;
6252 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6254 spacep = inp->spacep;
6255 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6257 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6258 userp, tidPathp, &req, &oldDscp);
6260 cm_ReleaseUser(userp);
6265 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6266 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6267 cm_ReleaseSCache(oldDscp);
6268 cm_ReleaseUser(userp);
6269 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6270 return CM_ERROR_PATH_NOT_COVERED;
6272 return CM_ERROR_NOSUCHPATH;
6274 #endif /* DFS_SUPPORT */
6276 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6277 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6278 userp, tidPathp, &req, &newDscp);
6280 cm_ReleaseSCache(oldDscp);
6281 cm_ReleaseUser(userp);
6286 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6287 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6288 cm_ReleaseSCache(newDscp);
6289 cm_ReleaseSCache(oldDscp);
6290 cm_ReleaseUser(userp);
6291 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6292 return CM_ERROR_PATH_NOT_COVERED;
6294 return CM_ERROR_NOSUCHPATH;
6296 #endif /* DFS_SUPPORT */
6298 /* Now, although we did two lookups for the two directories (because the same
6299 * directory can be referenced through different paths), we only allow hard links
6300 * within the same directory. */
6301 if (oldDscp != newDscp) {
6302 cm_ReleaseSCache(oldDscp);
6303 cm_ReleaseSCache(newDscp);
6304 cm_ReleaseUser(userp);
6305 return CM_ERROR_CROSSDEVLINK;
6308 /* handle the old name first */
6310 oldLastNamep = oldPathp;
6314 /* and handle the new name, too */
6316 newLastNamep = newPathp;
6320 /* now lookup the old name */
6321 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6322 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6324 cm_ReleaseSCache(oldDscp);
6325 cm_ReleaseSCache(newDscp);
6326 cm_ReleaseUser(userp);
6330 /* Check if the file already exists; if so return error */
6331 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6332 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6333 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6335 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6336 osi_LogSaveClientString(smb_logp, newLastNamep));
6338 /* if the existing link is to the same file, then we return success */
6340 if(sscp == tmpscp) {
6343 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6344 code = CM_ERROR_EXISTS;
6349 cm_ReleaseSCache(tmpscp);
6350 cm_ReleaseSCache(sscp);
6351 cm_ReleaseSCache(newDscp);
6352 cm_ReleaseSCache(oldDscp);
6353 cm_ReleaseUser(userp);
6357 /* now create the hardlink */
6358 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6359 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6360 osi_Log1(smb_logp," Link returns 0x%x", code);
6362 /* Handle Change Notification */
6364 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6365 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6366 smb_NotifyChange(FILE_ACTION_ADDED,
6367 filter, newDscp, newLastNamep,
6372 cm_ReleaseSCache(tmpscp);
6373 cm_ReleaseUser(userp);
6374 cm_ReleaseSCache(sscp);
6375 cm_ReleaseSCache(oldDscp);
6376 cm_ReleaseSCache(newDscp);
6380 /* SMB_COM_RENAME */
6382 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6384 clientchar_t *oldPathp;
6385 clientchar_t *newPathp;
6389 tp = smb_GetSMBData(inp, NULL);
6390 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6392 return CM_ERROR_BADSMB;
6393 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6395 return CM_ERROR_BADSMB;
6397 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6398 osi_LogSaveClientString(smb_logp, oldPathp),
6399 osi_LogSaveClientString(smb_logp, newPathp));
6401 if (!cm_IsValidClientString(newPathp)) {
6403 clientchar_t * hexp;
6405 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6406 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6407 osi_LogSaveClientString(smb_logp, hexp));
6411 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6413 return CM_ERROR_BADNTFILENAME;
6416 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6418 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6424 typedef struct smb_rmdirRock {
6428 normchar_t *maskp; /* pointer to the star pattern */
6431 cm_dirEntryList_t * matches;
6434 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6437 smb_rmdirRock_t *rockp;
6439 normchar_t matchName[MAX_PATH];
6441 rockp = (smb_rmdirRock_t *) vrockp;
6443 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6444 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6445 osi_LogSaveString(smb_logp, dep->name));
6449 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6450 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6452 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6454 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6455 !cm_Is8Dot3(matchName)) {
6456 cm_Gen8Dot3Name(dep, matchName, NULL);
6457 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6462 cm_DirEntryListAdd(dep->name, &rockp->matches);
6469 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6472 clientchar_t *pathp;
6476 clientchar_t *lastNamep;
6477 smb_rmdirRock_t rock;
6481 clientchar_t *tidPathp;
6485 memset(&rock, 0, sizeof(rock));
6487 tp = smb_GetSMBData(inp, NULL);
6488 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6490 return CM_ERROR_BADSMB;
6492 spacep = inp->spacep;
6493 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6495 userp = smb_GetUserFromVCP(vcp, inp);
6497 caseFold = CM_FLAG_CASEFOLD;
6499 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6501 cm_ReleaseUser(userp);
6502 return CM_ERROR_NOSUCHPATH;
6504 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6505 userp, tidPathp, &req, &dscp);
6508 cm_ReleaseUser(userp);
6513 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6514 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6515 cm_ReleaseSCache(dscp);
6516 cm_ReleaseUser(userp);
6517 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6518 return CM_ERROR_PATH_NOT_COVERED;
6520 return CM_ERROR_NOSUCHPATH;
6522 #endif /* DFS_SUPPORT */
6524 /* otherwise, scp points to the parent directory. */
6531 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6533 code = CM_ERROR_NOSUCHFILE;
6536 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6539 thyper.HighPart = 0;
6543 rock.matches = NULL;
6545 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6546 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6547 if (code == 0 && !rock.any) {
6549 thyper.HighPart = 0;
6550 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6551 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6554 if (code == 0 && rock.matches) {
6555 cm_dirEntryList_t * entry;
6557 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6558 clientchar_t clientName[MAX_PATH];
6560 /* We assume this will succeed because smb_RmdirProc()
6561 successfully converted entry->name once above. */
6562 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6564 osi_Log1(smb_logp, "Removing directory %s",
6565 osi_LogSaveString(smb_logp, entry->name));
6567 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6569 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6570 smb_NotifyChange(FILE_ACTION_REMOVED,
6571 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6572 dscp, clientName, NULL, TRUE);
6578 cm_DirEntryListFree(&rock.matches);
6581 cm_ReleaseUser(userp);
6584 cm_ReleaseSCache(dscp);
6586 if (code == 0 && !rock.any)
6587 code = CM_ERROR_NOSUCHFILE;
6596 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6606 fid = smb_GetSMBParm(inp, 0);
6608 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6610 fid = smb_ChainFID(fid, inp);
6611 fidp = smb_FindFID(vcp, fid, 0);
6613 return CM_ERROR_BADFD;
6615 userp = smb_GetUserFromVCP(vcp, inp);
6617 lock_ObtainMutex(&fidp->mx);
6618 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6619 cm_ReleaseUser(userp);
6620 lock_ReleaseMutex(&fidp->mx);
6621 smb_ReleaseFID(fidp);
6622 return CM_ERROR_BADFD;
6625 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6626 lock_ReleaseMutex(&fidp->mx);
6627 cm_ReleaseUser(userp);
6628 smb_CloseFID(vcp, fidp, NULL, 0);
6629 smb_ReleaseFID(fidp);
6630 return CM_ERROR_NOSUCHFILE;
6633 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6634 cm_scache_t * scp = fidp->scp;
6636 lock_ReleaseMutex(&fidp->mx);
6637 code = cm_FSync(scp, userp, &req);
6638 cm_ReleaseSCache(scp);
6640 lock_ReleaseMutex(&fidp->mx);
6644 cm_ReleaseUser(userp);
6645 smb_ReleaseFID(fidp);
6649 struct smb_FullNameRock {
6652 clientchar_t *fullName;
6653 fschar_t *originalName;
6656 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6659 normchar_t matchName[MAX_PATH];
6660 struct smb_FullNameRock *vrockp;
6662 vrockp = (struct smb_FullNameRock *)rockp;
6664 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6665 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6666 osi_LogSaveString(smb_logp, dep->name));
6670 if (!cm_Is8Dot3(matchName)) {
6671 clientchar_t shortName[13];
6673 cm_Gen8Dot3Name(dep, shortName, NULL);
6675 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6676 vrockp->fullName = cm_ClientStrDup(matchName);
6677 vrockp->originalName = cm_FsStrDup(dep->name);
6678 return CM_ERROR_STOPNOW;
6681 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6682 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6683 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6684 vrockp->fullName = cm_ClientStrDup(matchName);
6685 vrockp->originalName = cm_FsStrDup(dep->name);
6686 return CM_ERROR_STOPNOW;
6691 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6692 clientchar_t **newPathp, fschar_t ** originalPathp,
6693 cm_user_t *userp, cm_req_t *reqp)
6695 struct smb_FullNameRock rock;
6698 memset(&rock, 0, sizeof(rock));
6702 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6703 if (code == CM_ERROR_STOPNOW) {
6704 *newPathp = rock.fullName;
6705 *originalPathp = rock.originalName;
6707 *newPathp = cm_ClientStrDup(pathp);
6708 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6712 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6713 afs_uint32 dosTime) {
6716 cm_scache_t *dscp = NULL;
6717 clientchar_t *pathp = NULL;
6718 cm_scache_t * scp = NULL;
6719 cm_scache_t *delscp = NULL;
6720 int nullcreator = 0;
6722 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6723 fidp, fidp->fid, scp, vcp);
6726 lock_ObtainMutex(&fidp->mx);
6727 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6729 lock_ReleaseMutex(&fidp->mx);
6730 osi_Log0(smb_logp, " No user specified. Not closing fid");
6731 return CM_ERROR_BADFD;
6734 userp = fidp->userp; /* no hold required since fidp is held
6735 throughout the function */
6736 lock_ReleaseMutex(&fidp->mx);
6741 lock_ObtainWrite(&smb_rctLock);
6742 if (fidp->deleteOk) {
6743 osi_Log0(smb_logp, " Fid already closed.");
6744 lock_ReleaseWrite(&smb_rctLock);
6745 return CM_ERROR_BADFD;
6748 lock_ReleaseWrite(&smb_rctLock);
6750 lock_ObtainMutex(&fidp->mx);
6751 if (fidp->NTopen_dscp) {
6752 dscp = fidp->NTopen_dscp;
6753 cm_HoldSCache(dscp);
6756 if (fidp->NTopen_pathp)
6757 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6764 /* Don't jump the gun on an async raw write */
6765 while (fidp->raw_writers) {
6766 lock_ReleaseMutex(&fidp->mx);
6767 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6768 lock_ObtainMutex(&fidp->mx);
6771 /* watch for ioctl closes, and read-only opens */
6773 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6774 == SMB_FID_OPENWRITE) {
6775 if (dosTime != 0 && dosTime != -1) {
6776 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6777 /* This fixes defect 10958 */
6778 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6779 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6781 if (smb_AsyncStore != 2) {
6782 lock_ReleaseMutex(&fidp->mx);
6783 code = cm_FSync(scp, userp, &req);
6784 lock_ObtainMutex(&fidp->mx);
6790 /* unlock any pending locks */
6791 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6792 scp->fileType == CM_SCACHETYPE_FILE) {
6796 lock_ReleaseMutex(&fidp->mx);
6798 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6800 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6801 lock_ObtainWrite(&scp->rw);
6803 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6804 CM_SCACHESYNC_NEEDCALLBACK
6805 | CM_SCACHESYNC_GETSTATUS
6806 | CM_SCACHESYNC_LOCK);
6810 "smb CoreClose SyncOp failure code 0x%x", tcode);
6811 goto post_syncopdone;
6814 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6816 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6820 lock_ReleaseWrite(&scp->rw);
6821 lock_ObtainMutex(&fidp->mx);
6824 if (fidp->flags & SMB_FID_DELONCLOSE) {
6825 clientchar_t *fullPathp = NULL;
6826 fschar_t *originalNamep = NULL;
6828 lock_ReleaseMutex(&fidp->mx);
6830 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6835 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6836 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6837 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6839 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6840 smb_NotifyChange(FILE_ACTION_REMOVED,
6841 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6842 dscp, fullPathp, NULL, TRUE);
6845 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6847 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6848 smb_NotifyChange(FILE_ACTION_REMOVED,
6849 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6850 dscp, fullPathp, NULL, TRUE);
6857 free(originalNamep);
6859 lock_ObtainMutex(&fidp->mx);
6860 fidp->flags &= ~SMB_FID_DELONCLOSE;
6863 /* if this was a newly created file, then clear the creator
6864 * in the stat cache entry. */
6865 if (fidp->flags & SMB_FID_CREATED) {
6867 fidp->flags &= ~SMB_FID_CREATED;
6870 if (fidp->flags & SMB_FID_NTOPEN) {
6871 cm_ReleaseSCache(fidp->NTopen_dscp);
6872 fidp->NTopen_dscp = NULL;
6873 free(fidp->NTopen_pathp);
6874 fidp->NTopen_pathp = NULL;
6875 fidp->flags &= ~SMB_FID_NTOPEN;
6877 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6878 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6881 if (fidp->NTopen_wholepathp) {
6882 free(fidp->NTopen_wholepathp);
6883 fidp->NTopen_wholepathp = NULL;
6887 cm_ReleaseSCache(fidp->scp);
6890 lock_ReleaseMutex(&fidp->mx);
6893 cm_ReleaseSCache(dscp);
6896 cm_ReleaseSCache(delscp);
6900 lock_ObtainWrite(&scp->rw);
6901 if (nullcreator && scp->creator == userp)
6902 scp->creator = NULL;
6903 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6904 lock_ReleaseWrite(&scp->rw);
6905 cm_ReleaseSCache(scp);
6915 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6923 fid = smb_GetSMBParm(inp, 0);
6924 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6926 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6928 fid = smb_ChainFID(fid, inp);
6929 fidp = smb_FindFID(vcp, fid, 0);
6931 return CM_ERROR_BADFD;
6934 userp = smb_GetUserFromVCP(vcp, inp);
6936 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6938 smb_ReleaseFID(fidp);
6939 cm_ReleaseUser(userp);
6944 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6946 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6947 cm_user_t *userp, long *readp)
6953 osi_hyper_t fileLength;
6955 osi_hyper_t lastByte;
6956 osi_hyper_t bufferOffset;
6960 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6963 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6964 fidp->fid, offsetp->LowPart, count);
6968 lock_ObtainMutex(&fidp->mx);
6969 /* make sure we have a readable FD */
6970 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6971 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6972 fidp->fid, fidp->flags);
6973 lock_ReleaseMutex(&fidp->mx);
6974 code = CM_ERROR_BADFDOP;
6979 lock_ReleaseMutex(&fidp->mx);
6980 code = CM_ERROR_BADFD;
6991 lock_ObtainWrite(&scp->rw);
6993 if (offset.HighPart == 0) {
6994 chunk = offset.LowPart >> cm_logChunkSize;
6995 if (chunk != fidp->curr_chunk) {
6996 fidp->prev_chunk = fidp->curr_chunk;
6997 fidp->curr_chunk = chunk;
6999 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7002 lock_ReleaseMutex(&fidp->mx);
7004 /* start by looking up the file's end */
7005 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7006 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7010 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7012 /* now we have the entry locked, look up the length */
7013 fileLength = scp->length;
7015 /* adjust count down so that it won't go past EOF */
7016 thyper.LowPart = count;
7017 thyper.HighPart = 0;
7018 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7020 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7021 /* we'd read past EOF, so just stop at fileLength bytes.
7022 * Start by computing how many bytes remain in the file.
7024 thyper = LargeIntegerSubtract(fileLength, offset);
7026 /* if we are past EOF, read 0 bytes */
7027 if (LargeIntegerLessThanZero(thyper))
7030 count = thyper.LowPart;
7035 /* now, copy the data one buffer at a time,
7036 * until we've filled the request packet
7039 /* if we've copied all the data requested, we're done */
7040 if (count <= 0) break;
7042 /* otherwise, load up a buffer of data */
7043 thyper.HighPart = offset.HighPart;
7044 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7045 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7048 buf_Release(bufferp);
7051 lock_ReleaseWrite(&scp->rw);
7053 code = buf_Get(scp, &thyper, &req, &bufferp);
7055 lock_ObtainWrite(&scp->rw);
7056 if (code) goto done;
7057 bufferOffset = thyper;
7059 /* now get the data in the cache */
7061 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7062 CM_SCACHESYNC_NEEDCALLBACK |
7063 CM_SCACHESYNC_READ);
7067 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7069 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7071 /* otherwise, load the buffer and try again */
7072 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7076 buf_Release(bufferp);
7080 } /* if (wrong buffer) ... */
7082 /* now we have the right buffer loaded. Copy out the
7083 * data from here to the user's buffer.
7085 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7087 /* and figure out how many bytes we want from this buffer */
7088 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7089 if (nbytes > count) nbytes = count; /* don't go past EOF */
7091 /* now copy the data */
7092 memcpy(op, bufferp->datap + bufIndex, nbytes);
7094 /* adjust counters, pointers, etc. */
7097 thyper.LowPart = nbytes;
7098 thyper.HighPart = 0;
7099 offset = LargeIntegerAdd(thyper, offset);
7103 lock_ReleaseWrite(&scp->rw);
7105 buf_Release(bufferp);
7107 if (code == 0 && sequential)
7108 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7110 cm_ReleaseSCache(scp);
7113 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7114 fidp->fid, code, *readp);
7119 * smb_WriteData -- common code for Write and Raw Write
7121 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7122 cm_user_t *userp, long *writtenp)
7124 osi_hyper_t offset = *offsetp;
7127 cm_scache_t *scp = NULL;
7128 osi_hyper_t fileLength; /* file's length at start of write */
7129 osi_hyper_t minLength; /* don't read past this */
7130 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7131 cm_buf_t *bufferp = NULL;
7132 osi_hyper_t thyper; /* hyper tmp variable */
7133 osi_hyper_t bufferOffset;
7134 afs_uint32 bufIndex; /* index in buffer where our data is */
7135 int doWriteBack = 0;
7136 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7140 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7141 fidp->fid, offsetp->LowPart, count);
7145 lock_ObtainMutex(&fidp->mx);
7146 /* make sure we have a writable FD */
7147 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7148 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7149 fidp->fid, fidp->flags);
7150 lock_ReleaseMutex(&fidp->mx);
7151 code = CM_ERROR_BADFDOP;
7159 lock_ReleaseMutex(&fidp->mx);
7161 lock_ObtainWrite(&scp->rw);
7162 /* start by looking up the file's end */
7163 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7164 CM_SCACHESYNC_NEEDCALLBACK
7165 | CM_SCACHESYNC_SETSTATUS
7166 | CM_SCACHESYNC_GETSTATUS);
7170 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7172 /* now we have the entry locked, look up the length */
7173 fileLength = scp->length;
7174 minLength = fileLength;
7175 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7176 minLength = scp->serverLength;
7178 /* adjust file length if we extend past EOF */
7179 thyper.LowPart = count;
7180 thyper.HighPart = 0;
7181 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7182 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7183 /* we'd write past EOF, so extend the file */
7184 scp->mask |= CM_SCACHEMASK_LENGTH;
7185 scp->length = thyper;
7186 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7188 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7190 /* now, if the new position (thyper) and the old (offset) are in
7191 * different storeback windows, remember to store back the previous
7192 * storeback window when we're done with the write.
7194 * the purpose of this logic is to slow down the CIFS client
7195 * in order to avoid the client disconnecting during the CLOSE
7196 * operation if there are too many dirty buffers left to write
7197 * than can be accomplished during 45 seconds. This used to be
7198 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7199 * so that we can read larger amounts of data at a time.
7201 if (smb_AsyncStore == 1 &&
7202 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7203 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7204 /* they're different */
7206 writeBackOffset.HighPart = offset.HighPart;
7207 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7212 /* now, copy the data one buffer at a time, until we've filled the
7215 /* if we've copied all the data requested, we're done */
7219 /* handle over quota or out of space */
7220 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7221 *writtenp = written;
7222 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7226 /* otherwise, load up a buffer of data */
7227 thyper.HighPart = offset.HighPart;
7228 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7229 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7232 lock_ReleaseMutex(&bufferp->mx);
7233 buf_Release(bufferp);
7236 lock_ReleaseWrite(&scp->rw);
7238 code = buf_Get(scp, &thyper, &req, &bufferp);
7240 lock_ObtainMutex(&bufferp->mx);
7241 lock_ObtainWrite(&scp->rw);
7242 if (code) goto done;
7244 bufferOffset = thyper;
7246 /* now get the data in the cache */
7248 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7249 CM_SCACHESYNC_NEEDCALLBACK
7250 | CM_SCACHESYNC_WRITE
7251 | CM_SCACHESYNC_BUFLOCKED);
7255 cm_SyncOpDone(scp, bufferp,
7256 CM_SCACHESYNC_NEEDCALLBACK
7257 | CM_SCACHESYNC_WRITE
7258 | CM_SCACHESYNC_BUFLOCKED);
7260 /* If we're overwriting the entire buffer, or
7261 * if we're writing at or past EOF, mark the
7262 * buffer as current so we don't call
7263 * cm_GetBuffer. This skips the fetch from the
7264 * server in those cases where we're going to
7265 * obliterate all the data in the buffer anyway,
7266 * or in those cases where there is no useful
7267 * data at the server to start with.
7269 * Use minLength instead of scp->length, since
7270 * the latter has already been updated by this
7273 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7274 || LargeIntegerEqualTo(offset, bufferp->offset)
7275 && (count >= cm_data.buf_blockSize
7276 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7277 ConvertLongToLargeInteger(count)),
7279 if (count < cm_data.buf_blockSize
7280 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7281 memset(bufferp->datap, 0,
7282 cm_data.buf_blockSize);
7283 bufferp->dataVersion = scp->dataVersion;
7286 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7288 /* otherwise, load the buffer and try again */
7289 lock_ReleaseMutex(&bufferp->mx);
7290 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7292 lock_ReleaseWrite(&scp->rw);
7293 lock_ObtainMutex(&bufferp->mx);
7294 lock_ObtainWrite(&scp->rw);
7298 lock_ReleaseMutex(&bufferp->mx);
7299 buf_Release(bufferp);
7303 } /* if (wrong buffer) ... */
7305 /* now we have the right buffer loaded. Copy out the
7306 * data from here to the user's buffer.
7308 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7310 /* and figure out how many bytes we want from this buffer */
7311 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7313 nbytes = count; /* don't go past end of request */
7315 /* now copy the data */
7316 memcpy(bufferp->datap + bufIndex, op, nbytes);
7317 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7319 /* adjust counters, pointers, etc. */
7323 thyper.LowPart = nbytes;
7324 thyper.HighPart = 0;
7325 offset = LargeIntegerAdd(thyper, offset);
7329 lock_ReleaseWrite(&scp->rw);
7332 lock_ReleaseMutex(&bufferp->mx);
7333 buf_Release(bufferp);
7336 lock_ObtainMutex(&fidp->mx);
7337 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7338 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7340 lock_ReleaseMutex(&fidp->mx);
7341 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7342 fidp->NTopen_dscp, fidp->NTopen_pathp,
7345 lock_ReleaseMutex(&fidp->mx);
7349 if (smb_AsyncStore > 0) {
7353 lock_ObtainWrite(&scp->rw);
7354 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7356 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7357 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7359 lock_ReleaseWrite(&scp->rw);
7360 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7361 writeBackOffset.HighPart,
7362 smb_AsyncStoreSize, 0, userp);
7363 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7366 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7370 cm_ReleaseSCache(scp);
7373 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7374 fidp->fid, code, *writtenp);
7379 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7382 unsigned short count;
7384 unsigned short hint;
7385 long written = 0, total_written = 0;
7388 smb_t* smbp = (smb_t*) inp;
7392 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7394 int inDataBlockCount;
7396 fd = smb_GetSMBParm(inp, 0);
7397 count = smb_GetSMBParm(inp, 1);
7398 offset.HighPart = 0; /* too bad */
7399 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7400 hint = smb_GetSMBParm(inp, 4);
7402 op = smb_GetSMBData(inp, NULL);
7403 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7405 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7406 fd, offset.LowPart, count);
7408 fd = smb_ChainFID(fd, inp);
7409 fidp = smb_FindFID(vcp, fd, 0);
7411 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
7412 return CM_ERROR_BADFD;
7415 lock_ObtainMutex(&fidp->mx);
7416 if (fidp->flags & SMB_FID_IOCTL) {
7417 lock_ReleaseMutex(&fidp->mx);
7418 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7419 smb_ReleaseFID(fidp);
7420 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7424 if (fidp->flags & SMB_FID_RPC) {
7425 lock_ReleaseMutex(&fidp->mx);
7426 code = smb_RPCWrite(fidp, vcp, inp, outp);
7427 smb_ReleaseFID(fidp);
7428 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7433 lock_ReleaseMutex(&fidp->mx);
7434 smb_ReleaseFID(fidp);
7435 return CM_ERROR_BADFD;
7438 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7439 lock_ReleaseMutex(&fidp->mx);
7440 smb_CloseFID(vcp, fidp, NULL, 0);
7441 smb_ReleaseFID(fidp);
7442 return CM_ERROR_NOSUCHFILE;
7447 lock_ReleaseMutex(&fidp->mx);
7448 userp = smb_GetUserFromVCP(vcp, inp);
7452 LARGE_INTEGER LOffset;
7453 LARGE_INTEGER LLength;
7456 key = cm_GenerateKey(vcp->vcID, pid, fd);
7458 LOffset.HighPart = offset.HighPart;
7459 LOffset.LowPart = offset.LowPart;
7460 LLength.HighPart = 0;
7461 LLength.LowPart = count;
7463 lock_ObtainWrite(&scp->rw);
7464 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7465 lock_ReleaseWrite(&scp->rw);
7468 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7473 /* special case: 0 bytes transferred means truncate to this position */
7477 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7481 truncAttr.mask = CM_ATTRMASK_LENGTH;
7482 truncAttr.length.LowPart = offset.LowPart;
7483 truncAttr.length.HighPart = 0;
7484 lock_ObtainMutex(&fidp->mx);
7485 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7486 fidp->flags |= SMB_FID_LENGTHSETDONE;
7487 lock_ReleaseMutex(&fidp->mx);
7488 smb_SetSMBParm(outp, 0, 0 /* count */);
7489 smb_SetSMBDataLength(outp, 0);
7494 * Work around bug in NT client
7496 * When copying a file, the NT client should first copy the data,
7497 * then copy the last write time. But sometimes the NT client does
7498 * these in the wrong order, so the data copies would inadvertently
7499 * cause the last write time to be overwritten. We try to detect this,
7500 * and don't set client mod time if we think that would go against the
7503 lock_ObtainMutex(&fidp->mx);
7504 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7505 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7506 fidp->scp->clientModTime = time(NULL);
7508 lock_ReleaseMutex(&fidp->mx);
7511 while ( code == 0 && count > 0 ) {
7512 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7513 if (code == 0 && written == 0)
7514 code = CM_ERROR_PARTIALWRITE;
7516 offset = LargeIntegerAdd(offset,
7517 ConvertLongToLargeInteger(written));
7518 count -= (unsigned short)written;
7519 total_written += written;
7523 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7524 total_written, code);
7526 /* set the packet data length to 3 bytes for the data block header,
7527 * plus the size of the data.
7529 smb_SetSMBParm(outp, 0, total_written);
7530 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7531 smb_SetSMBParm(outp, 3, hint);
7532 smb_SetSMBDataLength(outp, 0);
7535 smb_ReleaseFID(fidp);
7536 cm_ReleaseUser(userp);
7537 cm_ReleaseSCache(scp);
7542 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7543 NCB *ncbp, raw_write_cont_t *rwcp)
7552 fd = smb_GetSMBParm(inp, 0);
7553 fidp = smb_FindFID(vcp, fd, 0);
7555 lock_ObtainMutex(&fidp->mx);
7557 lock_ReleaseMutex(&fidp->mx);
7558 smb_ReleaseFID(fidp);
7562 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7563 lock_ReleaseMutex(&fidp->mx);
7564 smb_CloseFID(vcp, fidp, NULL, 0);
7565 smb_ReleaseFID(fidp);
7568 lock_ReleaseMutex(&fidp->mx);
7570 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7571 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7573 userp = smb_GetUserFromVCP(vcp, inp);
7576 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7578 if (rwcp->writeMode & 0x1) { /* synchronous */
7581 smb_FormatResponsePacket(vcp, inp, outp);
7582 op = (smb_t *) outp;
7583 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7584 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7585 smb_SetSMBDataLength(outp, 0);
7586 smb_SendPacket(vcp, outp);
7587 smb_FreePacket(outp);
7589 else { /* asynchronous */
7590 lock_ObtainMutex(&fidp->mx);
7591 fidp->raw_writers--;
7592 if (fidp->raw_writers == 0)
7593 thrd_SetEvent(fidp->raw_write_event);
7594 lock_ReleaseMutex(&fidp->mx);
7597 /* Give back raw buffer */
7598 lock_ObtainMutex(&smb_RawBufLock);
7599 *((char **)rawBuf) = smb_RawBufs;
7600 smb_RawBufs = rawBuf;
7601 lock_ReleaseMutex(&smb_RawBufLock);
7603 smb_ReleaseFID(fidp);
7604 cm_ReleaseUser(userp);
7607 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7612 /* SMB_COM_WRITE_RAW */
7613 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7616 long count, written = 0, total_written = 0;
7620 smb_t *smbp = (smb_t*) inp;
7625 unsigned short writeMode;
7627 fd = smb_GetSMBParm(inp, 0);
7628 totalCount = smb_GetSMBParm(inp, 1);
7629 count = smb_GetSMBParm(inp, 10);
7630 writeMode = smb_GetSMBParm(inp, 7);
7632 op = (char *) inp->data;
7633 op += smb_GetSMBParm(inp, 11);
7635 offset.HighPart = 0;
7636 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7638 if (*inp->wctp == 14) {
7639 /* we received a 64-bit file offset */
7640 #ifdef AFS_LARGEFILES
7641 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7643 if (LargeIntegerLessThanZero(offset)) {
7645 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7646 offset.HighPart, offset.LowPart);
7647 return CM_ERROR_BADSMB;
7650 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7652 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7653 return CM_ERROR_BADSMB;
7656 offset.HighPart = 0;
7659 offset.HighPart = 0; /* 32-bit file offset */
7663 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7664 fd, offset.HighPart, offset.LowPart, count);
7666 " WriteRaw WriteMode 0x%x",
7669 fd = smb_ChainFID(fd, inp);
7670 fidp = smb_FindFID(vcp, fd, 0);
7672 return CM_ERROR_BADFD;
7674 lock_ObtainMutex(&fidp->mx);
7676 lock_ReleaseMutex(&fidp->mx);
7677 smb_ReleaseFID(fidp);
7678 return CM_ERROR_BADFD;
7681 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7682 lock_ReleaseMutex(&fidp->mx);
7683 smb_CloseFID(vcp, fidp, NULL, 0);
7684 smb_ReleaseFID(fidp);
7685 return CM_ERROR_NOSUCHFILE;
7690 lock_ReleaseMutex(&fidp->mx);
7695 LARGE_INTEGER LOffset;
7696 LARGE_INTEGER LLength;
7699 key = cm_GenerateKey(vcp->vcID, pid, fd);
7701 LOffset.HighPart = offset.HighPart;
7702 LOffset.LowPart = offset.LowPart;
7703 LLength.HighPart = 0;
7704 LLength.LowPart = count;
7706 lock_ObtainWrite(&scp->rw);
7707 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7708 lock_ReleaseWrite(&scp->rw);
7711 cm_ReleaseSCache(scp);
7712 smb_ReleaseFID(fidp);
7717 userp = smb_GetUserFromVCP(vcp, inp);
7720 * Work around bug in NT client
7722 * When copying a file, the NT client should first copy the data,
7723 * then copy the last write time. But sometimes the NT client does
7724 * these in the wrong order, so the data copies would inadvertently
7725 * cause the last write time to be overwritten. We try to detect this,
7726 * and don't set client mod time if we think that would go against the
7729 lock_ObtainMutex(&fidp->mx);
7730 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7731 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7732 fidp->scp->clientModTime = time(NULL);
7734 lock_ReleaseMutex(&fidp->mx);
7737 while ( code == 0 && count > 0 ) {
7738 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7739 if (code == 0 && written == 0)
7740 code = CM_ERROR_PARTIALWRITE;
7742 offset = LargeIntegerAdd(offset,
7743 ConvertLongToLargeInteger(written));
7746 total_written += written;
7750 /* Get a raw buffer */
7753 lock_ObtainMutex(&smb_RawBufLock);
7755 /* Get a raw buf, from head of list */
7756 rawBuf = smb_RawBufs;
7757 smb_RawBufs = *(char **)smb_RawBufs;
7760 code = CM_ERROR_USESTD;
7762 lock_ReleaseMutex(&smb_RawBufLock);
7765 /* Don't allow a premature Close */
7766 if (code == 0 && (writeMode & 1) == 0) {
7767 lock_ObtainMutex(&fidp->mx);
7768 fidp->raw_writers++;
7769 thrd_ResetEvent(fidp->raw_write_event);
7770 lock_ReleaseMutex(&fidp->mx);
7773 smb_ReleaseFID(fidp);
7774 cm_ReleaseUser(userp);
7775 cm_ReleaseSCache(scp);
7778 smb_SetSMBParm(outp, 0, total_written);
7779 smb_SetSMBDataLength(outp, 0);
7780 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7785 offset = LargeIntegerAdd(offset,
7786 ConvertLongToLargeInteger(count));
7790 rwcp->offset.HighPart = offset.HighPart;
7791 rwcp->offset.LowPart = offset.LowPart;
7792 rwcp->count = totalCount - count;
7793 rwcp->writeMode = writeMode;
7794 rwcp->alreadyWritten = total_written;
7796 /* set the packet data length to 3 bytes for the data block header,
7797 * plus the size of the data.
7799 smb_SetSMBParm(outp, 0, 0xffff);
7800 smb_SetSMBDataLength(outp, 0);
7806 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7809 long count, finalCount;
7813 smb_t *smbp = (smb_t*) inp;
7819 fd = smb_GetSMBParm(inp, 0);
7820 count = smb_GetSMBParm(inp, 1);
7821 offset.HighPart = 0; /* too bad */
7822 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7824 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7825 fd, offset.LowPart, count);
7827 fd = smb_ChainFID(fd, inp);
7828 fidp = smb_FindFID(vcp, fd, 0);
7830 return CM_ERROR_BADFD;
7832 lock_ObtainMutex(&fidp->mx);
7833 if (fidp->flags & SMB_FID_IOCTL) {
7834 lock_ReleaseMutex(&fidp->mx);
7835 code = smb_IoctlRead(fidp, vcp, inp, outp);
7836 smb_ReleaseFID(fidp);
7840 if (fidp->flags & SMB_FID_RPC) {
7841 lock_ReleaseMutex(&fidp->mx);
7842 code = smb_RPCRead(fidp, vcp, inp, outp);
7843 smb_ReleaseFID(fidp);
7848 lock_ReleaseMutex(&fidp->mx);
7849 smb_ReleaseFID(fidp);
7850 return CM_ERROR_BADFD;
7853 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7854 lock_ReleaseMutex(&fidp->mx);
7855 smb_CloseFID(vcp, fidp, NULL, 0);
7856 smb_ReleaseFID(fidp);
7857 return CM_ERROR_NOSUCHFILE;
7862 lock_ReleaseMutex(&fidp->mx);
7865 LARGE_INTEGER LOffset, LLength;
7869 key = cm_GenerateKey(vcp->vcID, pid, fd);
7871 LOffset.HighPart = 0;
7872 LOffset.LowPart = offset.LowPart;
7873 LLength.HighPart = 0;
7874 LLength.LowPart = count;
7876 lock_ObtainWrite(&scp->rw);
7877 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7878 lock_ReleaseWrite(&scp->rw);
7881 cm_ReleaseSCache(scp);
7882 smb_ReleaseFID(fidp);
7886 userp = smb_GetUserFromVCP(vcp, inp);
7888 /* remember this for final results */
7889 smb_SetSMBParm(outp, 0, count);
7890 smb_SetSMBParm(outp, 1, 0);
7891 smb_SetSMBParm(outp, 2, 0);
7892 smb_SetSMBParm(outp, 3, 0);
7893 smb_SetSMBParm(outp, 4, 0);
7895 /* set the packet data length to 3 bytes for the data block header,
7896 * plus the size of the data.
7898 smb_SetSMBDataLength(outp, count+3);
7900 /* get op ptr after putting in the parms, since otherwise we don't
7901 * know where the data really is.
7903 op = smb_GetSMBData(outp, NULL);
7905 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7906 *op++ = 1; /* data block marker */
7907 *op++ = (unsigned char) (count & 0xff);
7908 *op++ = (unsigned char) ((count >> 8) & 0xff);
7910 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7912 /* fix some things up */
7913 smb_SetSMBParm(outp, 0, finalCount);
7914 smb_SetSMBDataLength(outp, finalCount+3);
7916 smb_ReleaseFID(fidp);
7918 cm_ReleaseUser(userp);
7919 cm_ReleaseSCache(scp);
7923 /* SMB_COM_CREATE_DIRECTORY */
7924 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7926 clientchar_t *pathp;
7931 cm_scache_t *dscp; /* dir we're dealing with */
7932 cm_scache_t *scp; /* file we're creating */
7934 int initialModeBits;
7935 clientchar_t *lastNamep;
7937 clientchar_t *tidPathp;
7944 /* compute initial mode bits based on read-only flag in attributes */
7945 initialModeBits = 0777;
7947 tp = smb_GetSMBData(inp, NULL);
7948 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7950 return CM_ERROR_BADSMB;
7952 spacep = inp->spacep;
7953 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7955 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7956 return CM_ERROR_EXISTS;
7958 userp = smb_GetUserFromVCP(vcp, inp);
7960 caseFold = CM_FLAG_CASEFOLD;
7962 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7964 cm_ReleaseUser(userp);
7965 return CM_ERROR_NOSUCHPATH;
7968 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7969 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7970 userp, tidPathp, &req, &dscp);
7973 cm_ReleaseUser(userp);
7978 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7979 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7980 cm_ReleaseSCache(dscp);
7981 cm_ReleaseUser(userp);
7982 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7983 return CM_ERROR_PATH_NOT_COVERED;
7985 return CM_ERROR_NOSUCHPATH;
7987 #endif /* DFS_SUPPORT */
7989 /* otherwise, scp points to the parent directory. Do a lookup, and
7990 * fail if we find it. Otherwise, we do the create.
7996 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7997 if (scp) cm_ReleaseSCache(scp);
7998 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7999 if (code == 0) code = CM_ERROR_EXISTS;
8000 cm_ReleaseSCache(dscp);
8001 cm_ReleaseUser(userp);
8005 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8006 setAttr.clientModTime = time(NULL);
8007 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8008 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8009 smb_NotifyChange(FILE_ACTION_ADDED,
8010 FILE_NOTIFY_CHANGE_DIR_NAME,
8011 dscp, lastNamep, NULL, TRUE);
8013 /* we don't need this any longer */
8014 cm_ReleaseSCache(dscp);
8017 /* something went wrong creating or truncating the file */
8018 cm_ReleaseUser(userp);
8022 /* otherwise we succeeded */
8023 smb_SetSMBDataLength(outp, 0);
8024 cm_ReleaseUser(userp);
8029 BOOL smb_IsLegalFilename(clientchar_t *filename)
8032 * Find the longest substring of filename that does not contain
8033 * any of the chars in illegalChars. If that substring is less
8034 * than the length of the whole string, then one or more of the
8035 * illegal chars is in filename.
8037 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8043 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8044 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8046 clientchar_t *pathp;
8052 cm_scache_t *dscp; /* dir we're dealing with */
8053 cm_scache_t *scp; /* file we're creating */
8055 int initialModeBits;
8058 clientchar_t *lastNamep;
8061 clientchar_t *tidPathp;
8063 int created = 0; /* the file was new */
8068 excl = (inp->inCom == 0x03)? 0 : 1;
8070 attributes = smb_GetSMBParm(inp, 0);
8071 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8073 /* compute initial mode bits based on read-only flag in attributes */
8074 initialModeBits = 0666;
8075 if (attributes & SMB_ATTR_READONLY)
8076 initialModeBits &= ~0222;
8078 tp = smb_GetSMBData(inp, NULL);
8079 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8081 return CM_ERROR_BADSMB;
8083 spacep = inp->spacep;
8084 /* smb_StripLastComponent will strip "::$DATA" if present */
8085 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8087 if (!cm_IsValidClientString(pathp)) {
8089 clientchar_t * hexp;
8091 hexp = cm_GetRawCharsAlloc(pathp, -1);
8092 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8093 osi_LogSaveClientString(smb_logp, hexp));
8097 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8099 return CM_ERROR_BADNTFILENAME;
8102 userp = smb_GetUserFromVCP(vcp, inp);
8104 caseFold = CM_FLAG_CASEFOLD;
8106 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8108 cm_ReleaseUser(userp);
8109 return CM_ERROR_NOSUCHPATH;
8111 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8112 userp, tidPathp, &req, &dscp);
8115 cm_ReleaseUser(userp);
8120 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8121 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8122 cm_ReleaseSCache(dscp);
8123 cm_ReleaseUser(userp);
8124 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8125 return CM_ERROR_PATH_NOT_COVERED;
8127 return CM_ERROR_NOSUCHPATH;
8129 #endif /* DFS_SUPPORT */
8131 /* otherwise, scp points to the parent directory. Do a lookup, and
8132 * truncate the file if we find it, otherwise we create the file.
8139 if (!smb_IsLegalFilename(lastNamep))
8140 return CM_ERROR_BADNTFILENAME;
8142 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8143 #ifdef DEBUG_VERBOSE
8146 hexp = osi_HexifyString( lastNamep );
8147 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8152 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8153 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8154 cm_ReleaseSCache(dscp);
8155 cm_ReleaseUser(userp);
8159 /* if we get here, if code is 0, the file exists and is represented by
8160 * scp. Otherwise, we have to create it.
8164 /* oops, file shouldn't be there */
8165 cm_ReleaseSCache(dscp);
8166 cm_ReleaseSCache(scp);
8167 cm_ReleaseUser(userp);
8168 return CM_ERROR_EXISTS;
8171 setAttr.mask = CM_ATTRMASK_LENGTH;
8172 setAttr.length.LowPart = 0;
8173 setAttr.length.HighPart = 0;
8174 code = cm_SetAttr(scp, &setAttr, userp, &req);
8177 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8178 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8179 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8183 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8184 smb_NotifyChange(FILE_ACTION_ADDED,
8185 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8186 dscp, lastNamep, NULL, TRUE);
8187 } else if (!excl && code == CM_ERROR_EXISTS) {
8188 /* not an exclusive create, and someone else tried
8189 * creating it already, then we open it anyway. We
8190 * don't bother retrying after this, since if this next
8191 * fails, that means that the file was deleted after
8192 * we started this call.
8194 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8197 setAttr.mask = CM_ATTRMASK_LENGTH;
8198 setAttr.length.LowPart = 0;
8199 setAttr.length.HighPart = 0;
8200 code = cm_SetAttr(scp, &setAttr, userp, &req);
8205 /* we don't need this any longer */
8206 cm_ReleaseSCache(dscp);
8209 /* something went wrong creating or truncating the file */
8210 if (scp) cm_ReleaseSCache(scp);
8211 cm_ReleaseUser(userp);
8215 /* make sure we only open files */
8216 if (scp->fileType != CM_SCACHETYPE_FILE) {
8217 cm_ReleaseSCache(scp);
8218 cm_ReleaseUser(userp);
8219 return CM_ERROR_ISDIR;
8222 /* now all we have to do is open the file itself */
8223 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8224 osi_assertx(fidp, "null smb_fid_t");
8228 lock_ObtainMutex(&fidp->mx);
8229 /* always create it open for read/write */
8230 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8232 /* remember that the file was newly created */
8234 fidp->flags |= SMB_FID_CREATED;
8236 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8238 /* save a pointer to the vnode */
8240 lock_ObtainWrite(&scp->rw);
8241 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8242 lock_ReleaseWrite(&scp->rw);
8245 fidp->userp = userp;
8246 lock_ReleaseMutex(&fidp->mx);
8248 smb_SetSMBParm(outp, 0, fidp->fid);
8249 smb_SetSMBDataLength(outp, 0);
8251 cm_Open(scp, 0, userp);
8253 smb_ReleaseFID(fidp);
8254 cm_ReleaseUser(userp);
8255 /* leave scp held since we put it in fidp->scp */
8260 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8263 osi_hyper_t new_offset;
8274 fd = smb_GetSMBParm(inp, 0);
8275 whence = smb_GetSMBParm(inp, 1);
8276 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8278 /* try to find the file descriptor */
8279 fd = smb_ChainFID(fd, inp);
8280 fidp = smb_FindFID(vcp, fd, 0);
8282 return CM_ERROR_BADFD;
8284 lock_ObtainMutex(&fidp->mx);
8285 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8286 lock_ReleaseMutex(&fidp->mx);
8287 smb_ReleaseFID(fidp);
8288 return CM_ERROR_BADFD;
8291 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8292 lock_ReleaseMutex(&fidp->mx);
8293 smb_CloseFID(vcp, fidp, NULL, 0);
8294 smb_ReleaseFID(fidp);
8295 return CM_ERROR_NOSUCHFILE;
8298 lock_ReleaseMutex(&fidp->mx);
8300 userp = smb_GetUserFromVCP(vcp, inp);
8302 lock_ObtainMutex(&fidp->mx);
8305 lock_ReleaseMutex(&fidp->mx);
8306 lock_ObtainWrite(&scp->rw);
8307 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8308 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8310 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8312 /* offset from current offset */
8313 new_offset = LargeIntegerAdd(fidp->offset,
8314 ConvertLongToLargeInteger(offset));
8316 else if (whence == 2) {
8317 /* offset from current EOF */
8318 new_offset = LargeIntegerAdd(scp->length,
8319 ConvertLongToLargeInteger(offset));
8321 new_offset = ConvertLongToLargeInteger(offset);
8324 fidp->offset = new_offset;
8325 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8326 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8327 smb_SetSMBDataLength(outp, 0);
8329 lock_ReleaseWrite(&scp->rw);
8330 smb_ReleaseFID(fidp);
8331 cm_ReleaseSCache(scp);
8332 cm_ReleaseUser(userp);
8336 /* dispatch all of the requests received in a packet. Due to chaining, this may
8337 * be more than one request.
8339 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8340 NCB *ncbp, raw_write_cont_t *rwcp)
8344 unsigned long code = 0;
8345 unsigned char *outWctp;
8346 int nparms; /* # of bytes of parameters */
8348 int nbytes; /* bytes of data, excluding count */
8351 unsigned short errCode;
8352 unsigned long NTStatus;
8354 unsigned char errClass;
8355 unsigned int oldGen;
8356 DWORD oldTime, newTime;
8358 /* get easy pointer to the data */
8359 smbp = (smb_t *) inp->data;
8361 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8362 /* setup the basic parms for the initial request in the packet */
8363 inp->inCom = smbp->com;
8364 inp->wctp = &smbp->wct;
8366 inp->ncb_length = ncbp->ncb_length;
8371 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8372 /* log it and discard it */
8373 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8374 __FILE__, __LINE__, ncbp->ncb_length);
8375 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8379 /* We are an ongoing op */
8380 thrd_Increment(&ongoingOps);
8382 /* set up response packet for receiving output */
8383 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8384 smb_FormatResponsePacket(vcp, inp, outp);
8385 outWctp = outp->wctp;
8387 /* Remember session generation number and time */
8388 oldGen = sessionGen;
8389 oldTime = GetTickCount();
8391 while (inp->inCom != 0xff) {
8392 dp = &smb_dispatchTable[inp->inCom];
8394 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8395 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8396 code = outp->resumeCode;
8400 /* process each request in the packet; inCom, wctp and inCount
8401 * are already set up.
8403 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8406 /* now do the dispatch */
8407 /* start by formatting the response record a little, as a default */
8408 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8410 outWctp[1] = 0xff; /* no operation */
8411 outWctp[2] = 0; /* padding */
8416 /* not a chained request, this is a more reasonable default */
8417 outWctp[0] = 0; /* wct of zero */
8418 outWctp[1] = 0; /* and bcc (word) of zero */
8422 /* once set, stays set. Doesn't matter, since we never chain
8423 * "no response" calls.
8425 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8429 /* we have a recognized operation */
8430 char * opName = myCrt_Dispatch(inp->inCom);
8433 smbp = (smb_t *) inp;
8435 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8436 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8437 if (inp->inCom == 0x1d) {
8439 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8441 code = (*(dp->procp)) (vcp, inp, outp);
8443 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8444 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8446 newTime = GetTickCount();
8447 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8448 opName, smbp->mid, newTime - oldTime);
8451 if ( code == CM_ERROR_BADSMB ||
8452 code == CM_ERROR_BADOP )
8454 #endif /* LOG_PACKET */
8456 /* ReceiveV3Tran2A handles its own logging */
8457 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8460 clientchar_t *treepath = NULL; /* do not free */
8461 clientchar_t *pathname = NULL;
8462 cm_fid_t afid = {0,0,0,0,0};
8464 uidp = smb_FindUID(vcp, smbp->uid, 0);
8465 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8466 fidp = smb_FindFID(vcp, inp->fid, 0);
8469 lock_ObtainMutex(&fidp->mx);
8470 if (fidp->NTopen_pathp)
8471 pathname = fidp->NTopen_pathp;
8473 afid = fidp->scp->fid;
8475 if (inp->stringsp->wdata)
8476 pathname = inp->stringsp->wdata;
8479 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)",
8480 opName, newTime - oldTime,
8481 smbp->uid, uidp ? uidp->unp->name : NULL,
8482 smbp->pid, smbp->mid, smbp->tid,
8485 afid.cell, afid.volume, afid.vnode, afid.unique);
8488 lock_ReleaseMutex(&fidp->mx);
8491 smb_ReleaseUID(uidp);
8493 smb_ReleaseFID(fidp);
8496 if (oldGen != sessionGen) {
8497 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8498 newTime - oldTime, ncbp->ncb_length);
8499 osi_Log3(smb_logp, "Request %s straddled session startup, "
8500 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8503 FreeSMBStrings(inp);
8505 /* bad opcode, fail the request, after displaying it */
8506 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8509 #endif /* LOG_PACKET */
8512 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8513 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8514 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8515 if (code == IDCANCEL)
8518 code = CM_ERROR_BADOP;
8521 /* catastrophic failure: log as much as possible */
8522 if (code == CM_ERROR_BADSMB) {
8523 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8527 #endif /* LOG_PACKET */
8528 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8531 code = CM_ERROR_INVAL;
8534 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8535 thrd_Decrement(&ongoingOps);
8540 /* now, if we failed, turn the current response into an empty
8541 * one, and fill in the response packet's error code.
8544 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8545 smb_MapNTError(code, &NTStatus);
8546 outWctp = outp->wctp;
8547 smbp = (smb_t *) &outp->data;
8548 if (code != CM_ERROR_PARTIALWRITE
8549 && code != CM_ERROR_BUFFERTOOSMALL
8550 && code != CM_ERROR_GSSCONTINUE) {
8551 /* nuke wct and bcc. For a partial
8552 * write or an in-process authentication handshake,
8553 * assume they're OK.
8559 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8560 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8561 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8562 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8563 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8567 smb_MapCoreError(code, vcp, &errCode, &errClass);
8568 outWctp = outp->wctp;
8569 smbp = (smb_t *) &outp->data;
8570 if (code != CM_ERROR_PARTIALWRITE) {
8571 /* nuke wct and bcc. For a partial
8572 * write, assume they're OK.
8578 smbp->errLow = (unsigned char) (errCode & 0xff);
8579 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8580 smbp->rcls = errClass;
8583 } /* error occurred */
8585 /* if we're here, we've finished one request. Look to see if
8586 * this is a chained opcode. If it is, setup things to process
8587 * the chained request, and setup the output buffer to hold the
8588 * chained response. Start by finding the next input record.
8590 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8591 break; /* not a chained req */
8592 tp = inp->wctp; /* points to start of last request */
8593 /* in a chained request, the first two
8594 * parm fields are required, and are
8595 * AndXCommand/AndXReserved and
8597 if (tp[0] < 2) break;
8598 if (tp[1] == 0xff) break; /* no more chained opcodes */
8600 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8603 /* and now append the next output request to the end of this
8604 * last request. Begin by finding out where the last response
8605 * ends, since that's where we'll put our new response.
8607 outWctp = outp->wctp; /* ptr to out parameters */
8608 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8609 nparms = outWctp[0] << 1;
8610 tp = outWctp + nparms + 1; /* now points to bcc field */
8611 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8612 tp += 2 /* for the count itself */ + nbytes;
8613 /* tp now points to the new output record; go back and patch the
8614 * second parameter (off2) to point to the new record.
8616 temp = (unsigned int)(tp - outp->data);
8617 outWctp[3] = (unsigned char) (temp & 0xff);
8618 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8619 outWctp[2] = 0; /* padding */
8620 outWctp[1] = inp->inCom; /* next opcode */
8622 /* finally, setup for the next iteration */
8625 } /* while loop over all requests in the packet */
8627 /* now send the output packet, and return */
8629 smb_SendPacket(vcp, outp);
8630 thrd_Decrement(&ongoingOps);
8635 /* Wait for Netbios() calls to return, and make the results available to server
8636 * threads. Note that server threads can't wait on the NCBevents array
8637 * themselves, because NCB events are manual-reset, and the servers would race
8638 * each other to reset them.
8640 void smb_ClientWaiter(void *parmp)
8645 while (smbShutdownFlag == 0) {
8646 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8648 if (code == WAIT_OBJECT_0)
8651 /* error checking */
8652 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8654 int abandonIdx = code - WAIT_ABANDONED_0;
8655 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8658 if (code == WAIT_IO_COMPLETION)
8660 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8664 if (code == WAIT_TIMEOUT)
8666 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8669 if (code == WAIT_FAILED)
8671 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8674 idx = code - WAIT_OBJECT_0;
8676 /* check idx range! */
8677 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8679 /* this is fatal - log as much as possible */
8680 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8681 osi_assertx(0, "invalid index");
8684 thrd_ResetEvent(NCBevents[idx]);
8685 thrd_SetEvent(NCBreturns[0][idx]);
8690 * Try to have one NCBRECV request waiting for every live session. Not more
8691 * than one, because if there is more than one, it's hard to handle Write Raw.
8693 void smb_ServerWaiter(void *parmp)
8696 int idx_session, idx_NCB;
8699 while (smbShutdownFlag == 0) {
8701 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8703 if (code == WAIT_OBJECT_0)
8706 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8708 int abandonIdx = code - WAIT_ABANDONED_0;
8709 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8712 if (code == WAIT_IO_COMPLETION)
8714 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8718 if (code == WAIT_TIMEOUT)
8720 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8723 if (code == WAIT_FAILED)
8725 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8728 idx_session = code - WAIT_OBJECT_0;
8730 /* check idx range! */
8731 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8733 /* this is fatal - log as much as possible */
8734 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8735 osi_assertx(0, "invalid index");
8740 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8742 if (code == WAIT_OBJECT_0) {
8743 if (smbShutdownFlag == 1)
8749 /* error checking */
8750 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8752 int abandonIdx = code - WAIT_ABANDONED_0;
8753 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8756 if (code == WAIT_IO_COMPLETION)
8758 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8762 if (code == WAIT_TIMEOUT)
8764 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8767 if (code == WAIT_FAILED)
8769 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8772 idx_NCB = code - WAIT_OBJECT_0;
8774 /* check idx range! */
8775 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8777 /* this is fatal - log as much as possible */
8778 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8779 osi_assertx(0, "invalid index");
8782 /* Link them together */
8783 NCBsessions[idx_NCB] = idx_session;
8786 ncbp = NCBs[idx_NCB];
8787 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8788 ncbp->ncb_command = NCBRECV | ASYNCH;
8789 ncbp->ncb_lana_num = lanas[idx_session];
8790 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8791 ncbp->ncb_event = NCBevents[idx_NCB];
8792 ncbp->ncb_length = SMB_PACKETSIZE;
8798 * The top level loop for handling SMB request messages. Each server thread
8799 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8800 * NCB and buffer for the incoming request are loaned to us.
8802 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8803 * to immediately send a request for the rest of the data. This must come
8804 * before any other traffic for that session, so we delay setting the session
8805 * event until that data has come in.
8807 void smb_Server(VOID *parmp)
8809 INT_PTR myIdx = (INT_PTR) parmp;
8813 smb_packet_t *outbufp;
8815 int idx_NCB, idx_session;
8817 smb_vc_t *vcp = NULL;
8819 extern void rx_StartClientThread(void);
8821 rx_StartClientThread();
8823 outncbp = smb_GetNCB();
8824 outbufp = smb_GetPacket();
8825 outbufp->ncbp = outncbp;
8833 cm_ResetServerPriority();
8835 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8838 /* terminate silently if shutdown flag is set */
8839 if (code == WAIT_OBJECT_0) {
8840 if (smbShutdownFlag == 1) {
8841 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8847 /* error checking */
8848 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8850 int abandonIdx = code - WAIT_ABANDONED_0;
8851 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8854 if (code == WAIT_IO_COMPLETION)
8856 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8860 if (code == WAIT_TIMEOUT)
8862 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8865 if (code == WAIT_FAILED)
8867 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8870 idx_NCB = code - WAIT_OBJECT_0;
8872 /* check idx range! */
8873 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8875 /* this is fatal - log as much as possible */
8876 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8877 osi_assertx(0, "invalid index");
8880 ncbp = NCBs[idx_NCB];
8881 idx_session = NCBsessions[idx_NCB];
8882 rc = ncbp->ncb_retcode;
8884 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8885 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8889 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8893 /* Can this happen? Or is it just my UNIX paranoia? */
8894 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8899 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8902 /* Client closed session */
8903 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8905 lock_ObtainMutex(&vcp->mx);
8906 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8907 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8909 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8910 lock_ReleaseMutex(&vcp->mx);
8911 lock_ObtainWrite(&smb_globalLock);
8912 dead_sessions[vcp->session] = TRUE;
8913 lock_ReleaseWrite(&smb_globalLock);
8915 lock_ReleaseMutex(&vcp->mx);
8917 smb_CleanupDeadVC(vcp);
8924 /* Treat as transient error */
8925 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8928 "dispatch smb recv failed, message incomplete, ncb_length %d",
8931 "SMB message incomplete, "
8932 "length %d", ncbp->ncb_length);
8935 * We used to discard the packet.
8936 * Instead, try handling it normally.
8940 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8944 /* A weird error code. Log it, sleep, and continue. */
8945 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8947 lock_ObtainMutex(&vcp->mx);
8948 if (vcp->errorCount++ > 3) {
8949 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8950 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8951 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8953 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8954 lock_ReleaseMutex(&vcp->mx);
8955 lock_ObtainWrite(&smb_globalLock);
8956 dead_sessions[vcp->session] = TRUE;
8957 lock_ReleaseWrite(&smb_globalLock);
8959 lock_ReleaseMutex(&vcp->mx);
8961 smb_CleanupDeadVC(vcp);
8967 lock_ReleaseMutex(&vcp->mx);
8971 thrd_SetEvent(SessionEvents[idx_session]);
8977 /* Success, so now dispatch on all the data in the packet */
8979 smb_concurrentCalls++;
8980 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8981 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8984 * If at this point vcp is NULL (implies that packet was invalid)
8985 * then we are in big trouble. This means either :
8986 * a) we have the wrong NCB.
8987 * b) Netbios screwed up the call.
8988 * c) The VC was already marked dead before we were able to
8990 * Obviously this implies that
8991 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8992 * lanas[idx_session] != ncbp->ncb_lana_num )
8993 * Either way, we can't do anything with this packet.
8994 * Log, sleep and resume.
8997 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9001 ncbp->ncb_lana_num);
9003 /* Also log in the trace log. */
9004 osi_Log4(smb_logp, "Server: VCP does not exist!"
9005 "LSNs[idx_session]=[%d],"
9006 "lanas[idx_session]=[%d],"
9007 "ncbp->ncb_lsn=[%d],"
9008 "ncbp->ncb_lana_num=[%d]",
9012 ncbp->ncb_lana_num);
9014 /* thrd_Sleep(1000); Don't bother sleeping */
9015 thrd_SetEvent(SessionEvents[idx_session]);
9016 smb_concurrentCalls--;
9020 cm_SetRequestStartTime();
9022 vcp->errorCount = 0;
9023 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9024 smbp = (smb_t *)bufp->data;
9031 if (smbp->com == 0x1d) {
9032 /* Special handling for Write Raw */
9033 raw_write_cont_t rwc;
9035 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9036 if (rwc.code == 0) {
9037 EVENT_HANDLE rwevent;
9038 char eventName[MAX_PATH];
9040 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9041 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9042 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9043 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9045 ncbp->ncb_command = NCBRECV | ASYNCH;
9046 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9047 ncbp->ncb_lana_num = vcp->lana;
9048 ncbp->ncb_buffer = rwc.buf;
9049 ncbp->ncb_length = 65535;
9050 ncbp->ncb_event = rwevent;
9052 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9053 thrd_CloseHandle(rwevent);
9055 thrd_SetEvent(SessionEvents[idx_session]);
9057 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9059 else if (smbp->com == 0xa0) {
9061 * Serialize the handling for NT Transact
9064 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9065 thrd_SetEvent(SessionEvents[idx_session]);
9067 thrd_SetEvent(SessionEvents[idx_session]);
9068 /* TODO: what else needs to be serialized? */
9069 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9073 __except( smb_ServerExceptionFilter() ) {
9077 smb_concurrentCalls--;
9080 thrd_SetEvent(NCBavails[idx_NCB]);
9085 smb_FreePacket(outbufp);
9087 smb_FreeNCB(outncbp);
9091 * Exception filter for the server threads. If an exception occurs in the
9092 * dispatch routines, which is where exceptions are most common, then do a
9093 * force trace and give control to upstream exception handlers. Useful for
9096 DWORD smb_ServerExceptionFilter(void) {
9097 /* While this is not the best time to do a trace, if it succeeds, then
9098 * we have a trace (assuming tracing was enabled). Otherwise, this should
9099 * throw a second exception.
9101 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9102 afsd_ForceTrace(TRUE);
9103 buf_ForceTrace(TRUE);
9104 return EXCEPTION_CONTINUE_SEARCH;
9108 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9109 * If the number of server threads is M, and the number of live sessions is
9110 * N, then the number of NCB's in use at any time either waiting for, or
9111 * holding, received messages is M + N, so that is how many NCB's get created.
9113 void InitNCBslot(int idx)
9115 struct smb_packet *bufp;
9116 EVENT_HANDLE retHandle;
9118 char eventName[MAX_PATH];
9120 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9122 NCBs[idx] = smb_GetNCB();
9123 sprintf(eventName,"NCBavails[%d]", idx);
9124 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9125 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9126 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9127 sprintf(eventName,"NCBevents[%d]", idx);
9128 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9129 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9130 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9131 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9132 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9133 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9134 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9135 for (i=0; i<smb_NumServerThreads; i++)
9136 NCBreturns[i][idx] = retHandle;
9137 bufp = smb_GetPacket();
9138 bufp->spacep = cm_GetSpace();
9142 /* listen for new connections */
9143 void smb_Listener(void *parmp)
9149 afs_uint32 session, thread;
9150 smb_vc_t *vcp = NULL;
9152 char rname[NCBNAMSZ+1];
9153 char cname[MAX_COMPUTERNAME_LENGTH+1];
9154 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9155 INT_PTR lana = (INT_PTR) parmp;
9156 char eventName[MAX_PATH];
9157 int bridgeCount = 0;
9158 int nowildCount = 0;
9160 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9161 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9162 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9163 thrd_ResetEvent(ListenerShutdown[lana]);
9165 ncbp = smb_GetNCB();
9167 /* retrieve computer name */
9168 GetComputerName(cname, &cnamelen);
9171 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9172 memset(ncbp, 0, sizeof(NCB));
9175 ncbp->ncb_command = NCBLISTEN;
9176 ncbp->ncb_rto = 0; /* No receive timeout */
9177 ncbp->ncb_sto = 0; /* No send timeout */
9179 /* pad out with spaces instead of null termination */
9180 len = (long)strlen(smb_localNamep);
9181 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9182 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9184 strcpy(ncbp->ncb_callname, "*");
9185 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9187 ncbp->ncb_lana_num = (UCHAR)lana;
9189 code = Netbios(ncbp);
9191 if (code == NRC_NAMERR) {
9192 /* An smb shutdown or Vista resume must have taken place */
9194 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9195 ncbp->ncb_lana_num);
9196 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9198 if (lock_TryMutex(&smb_StartedLock)) {
9199 lana_list.lana[i] = LANA_INVALID;
9200 lock_ReleaseMutex(&smb_StartedLock);
9203 } else if (code == NRC_BRIDGE || code != 0) {
9204 int lanaRemaining = 0;
9206 if (code == NRC_BRIDGE) {
9207 if (++bridgeCount <= 5) {
9208 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9211 } else if (code == NRC_NOWILD) {
9212 if (++nowildCount <= 5) {
9213 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9215 if (bridgeCount > 0) {
9216 memset(ncbp, 0, sizeof(*ncbp));
9217 ncbp->ncb_command = NCBADDNAME;
9218 ncbp->ncb_lana_num = (UCHAR)lana;
9219 /* pad out with spaces instead of null termination */
9220 len = (long)strlen(smb_localNamep);
9221 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9222 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9223 code = Netbios(ncbp);
9229 while (!lock_TryMutex(&smb_StartedLock)) {
9230 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9236 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9237 ncbp->ncb_lana_num, ncb_error_string(code));
9238 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9239 ncbp->ncb_lana_num, ncb_error_string(code));
9241 for (i = 0; i < lana_list.length; i++) {
9242 if (lana_list.lana[i] == lana) {
9243 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9244 lana_list.lana[i] = LANA_INVALID;
9246 if (lana_list.lana[i] != LANA_INVALID)
9250 if (lanaRemaining == 0) {
9251 cm_VolStatus_Network_Stopped(cm_NetbiosName
9256 smb_ListenerState = SMB_LISTENER_STOPPED;
9257 smb_LANadapter = LANA_INVALID;
9258 lana_list.length = 0;
9260 lock_ReleaseMutex(&smb_StartedLock);
9264 else if (code != 0) {
9265 char tbuffer[AFSPATHMAX];
9267 /* terminate silently if shutdown flag is set */
9268 while (!lock_TryMutex(&smb_StartedLock)) {
9269 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9275 "NCBLISTEN lana=%d failed with code %d [%s]",
9276 ncbp->ncb_lana_num, code, ncb_error_string(code));
9278 "Client exiting due to network failure. Please restart client.\n");
9281 "Client exiting due to network failure. Please restart client.\n"
9282 "NCBLISTEN lana=%d failed with code %d [%s]",
9283 ncbp->ncb_lana_num, code, ncb_error_string(code));
9285 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9286 MB_OK|MB_SERVICE_NOTIFICATION);
9287 osi_panic(tbuffer, __FILE__, __LINE__);
9289 lock_ReleaseMutex(&smb_StartedLock);
9294 /* a successful packet received. clear bridge error count */
9298 /* check for remote conns */
9299 /* first get remote name and insert null terminator */
9300 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9301 for (i=NCBNAMSZ; i>0; i--) {
9302 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9308 /* compare with local name */
9310 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9311 flags |= SMB_VCFLAG_REMOTECONN;
9314 lock_ObtainMutex(&smb_ListenerLock);
9316 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9317 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9319 /* now ncbp->ncb_lsn is the connection ID */
9320 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9321 if (vcp->session == 0) {
9322 /* New generation */
9323 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9326 /* Log session startup */
9328 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9329 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9330 #endif /* NOTSERVICE */
9331 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9332 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9334 if (reportSessionStartups) {
9335 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9338 lock_ObtainMutex(&vcp->mx);
9339 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9340 vcp->flags |= flags;
9341 lock_ReleaseMutex(&vcp->mx);
9343 /* Allocate slot in session arrays */
9344 /* Re-use dead session if possible, otherwise add one more */
9345 /* But don't look at session[0], it is reserved */
9346 lock_ObtainWrite(&smb_globalLock);
9347 for (session = 1; session < numSessions; session++) {
9348 if (dead_sessions[session]) {
9349 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9350 dead_sessions[session] = FALSE;
9354 lock_ReleaseWrite(&smb_globalLock);
9356 /* We are re-using an existing VC because the lsn and lana
9358 session = vcp->session;
9360 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9362 /* Log session startup */
9364 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9365 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9366 #endif /* NOTSERVICE */
9367 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9368 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9370 if (reportSessionStartups) {
9371 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9375 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9376 unsigned long code = CM_ERROR_ALLBUSY;
9377 smb_packet_t * outp = smb_GetPacket();
9378 unsigned char *outWctp;
9381 smb_FormatResponsePacket(vcp, NULL, outp);
9384 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9385 unsigned long NTStatus;
9386 smb_MapNTError(code, &NTStatus);
9387 outWctp = outp->wctp;
9388 smbp = (smb_t *) &outp->data;
9392 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9393 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9394 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9395 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9396 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9398 unsigned short errCode;
9399 unsigned char errClass;
9400 smb_MapCoreError(code, vcp, &errCode, &errClass);
9401 outWctp = outp->wctp;
9402 smbp = (smb_t *) &outp->data;
9406 smbp->errLow = (unsigned char) (errCode & 0xff);
9407 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9408 smbp->rcls = errClass;
9411 smb_SendPacket(vcp, outp);
9412 smb_FreePacket(outp);
9414 lock_ObtainMutex(&vcp->mx);
9415 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9416 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9418 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9419 lock_ReleaseMutex(&vcp->mx);
9420 lock_ObtainWrite(&smb_globalLock);
9421 dead_sessions[vcp->session] = TRUE;
9422 lock_ReleaseWrite(&smb_globalLock);
9423 smb_CleanupDeadVC(vcp);
9425 lock_ReleaseMutex(&vcp->mx);
9428 /* assert that we do not exceed the maximum number of sessions or NCBs.
9429 * we should probably want to wait for a session to be freed in case
9432 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9433 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9435 lock_ObtainMutex(&vcp->mx);
9436 vcp->session = session;
9437 lock_ReleaseMutex(&vcp->mx);
9438 lock_ObtainWrite(&smb_globalLock);
9439 LSNs[session] = ncbp->ncb_lsn;
9440 lanas[session] = ncbp->ncb_lana_num;
9441 lock_ReleaseWrite(&smb_globalLock);
9443 if (session == numSessions) {
9444 /* Add new NCB for new session */
9445 char eventName[MAX_PATH];
9447 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9449 InitNCBslot(numNCBs);
9450 lock_ObtainWrite(&smb_globalLock);
9452 lock_ReleaseWrite(&smb_globalLock);
9453 thrd_SetEvent(NCBavails[0]);
9454 thrd_SetEvent(NCBevents[0]);
9455 for (thread = 0; thread < smb_NumServerThreads; thread++)
9456 thrd_SetEvent(NCBreturns[thread][0]);
9457 /* Also add new session event */
9458 sprintf(eventName, "SessionEvents[%d]", session);
9459 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9460 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9461 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9462 lock_ObtainWrite(&smb_globalLock);
9464 lock_ReleaseWrite(&smb_globalLock);
9465 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9466 thrd_SetEvent(SessionEvents[0]);
9468 thrd_SetEvent(SessionEvents[session]);
9474 lock_ReleaseMutex(&smb_ListenerLock);
9475 } /* dispatch while loop */
9479 thrd_SetEvent(ListenerShutdown[lana]);
9484 configureBackConnectionHostNames(void)
9486 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9487 * there is a restriction on the use of SMB authentication on loopback connections.
9488 * There are two work arounds available:
9490 * (1) We can disable the check for matching host names. This does not
9492 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9493 * "DisableLoopbackCheck"=dword:00000001
9495 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9496 * does require a reboot:
9497 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9498 * "BackConnectionHostNames"=multi-sz
9500 * The algorithm will be:
9501 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9502 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9503 * (2b1) and check to see if DisableLoopbackCheck is set.
9504 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9505 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9506 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9507 * check for the UnsetDisableLoopbackCheck value.
9508 * If set, set the DisableLoopbackCheck flag to 0x0
9509 * and delete the UnsetDisableLoopbackCheck value
9511 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9512 * force Windows to use the loopback authentication mechanism for the specified
9515 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9516 * service session that set it.
9522 DWORD dwSize, dwAllocSize;
9524 PBYTE pHostNames = NULL, pName = NULL;
9525 BOOL bNameFound = FALSE;
9526 static BOOL bLoopbackCheckDisabled = FALSE;
9528 /* BackConnectionHostNames and DisableLoopbackCheck */
9529 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9530 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9533 &hkMSV10) == ERROR_SUCCESS )
9535 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9536 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9537 (dwType == REG_MULTI_SZ))
9539 dwAllocSize += 1 /* in case the source string is not nul terminated */
9540 + (DWORD)strlen(cm_NetbiosName) + 2;
9541 pHostNames = malloc(dwAllocSize);
9542 dwSize = dwAllocSize;
9543 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9544 pHostNames, &dwSize) == ERROR_SUCCESS)
9546 for (pName = pHostNames;
9547 (pName - pHostNames < (int) dwSize) && *pName ;
9548 pName += strlen(pName) + 1)
9550 if ( !stricmp(pName, cm_NetbiosName) ) {
9558 if ( !bNameFound ) {
9559 size_t size = strlen(cm_NetbiosName) + 2;
9560 if ( !pHostNames ) {
9561 pHostNames = malloc(size);
9564 StringCbCopyA(pName, size, cm_NetbiosName);
9566 *pName = '\0'; /* add a second nul terminator */
9568 dwType = REG_MULTI_SZ;
9569 dwSize = (DWORD)(pName - pHostNames + 1);
9570 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9572 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9573 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9576 &hkLsa) == ERROR_SUCCESS )
9578 dwSize = sizeof(DWORD);
9579 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9582 dwSize = sizeof(DWORD);
9584 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9586 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9587 AFSREG_CLT_OPENAFS_SUBKEY,
9590 REG_OPTION_NON_VOLATILE,
9594 NULL) == ERROR_SUCCESS) {
9597 dwSize = sizeof(DWORD);
9599 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9600 bLoopbackCheckDisabled = TRUE;
9601 RegCloseKey(hkClient);
9606 } else if (!bLoopbackCheckDisabled) {
9607 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9608 AFSREG_CLT_OPENAFS_SUBKEY,
9611 REG_OPTION_NON_VOLATILE,
9615 NULL) == ERROR_SUCCESS) {
9617 dwSize = sizeof(DWORD);
9618 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9620 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9621 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9624 &hkLsa) == ERROR_SUCCESS )
9626 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9630 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9631 RegCloseKey(hkClient);
9640 RegCloseKey(hkMSV10);
9646 configureExtendedSMBSessionTimeouts(void)
9649 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9650 * new functionality:
9652 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9653 * "ReconnectableServers" REG_MULTI_SZ
9654 * "ExtendedSessTimeout" REG_DWORD (seconds)
9655 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
9657 * These values can be used to prevent the smb redirector from timing out
9658 * smb connection to the afs smb server prematurely.
9662 DWORD dwSize, dwAllocSize;
9664 PBYTE pHostNames = NULL, pName = NULL;
9665 BOOL bNameFound = FALSE;
9667 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9668 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9671 &hkLanMan) == ERROR_SUCCESS )
9673 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
9674 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9675 (dwType == REG_MULTI_SZ))
9677 dwAllocSize += 1 /* in case the source string is not nul terminated */
9678 + (DWORD)strlen(cm_NetbiosName) + 2;
9679 pHostNames = malloc(dwAllocSize);
9680 dwSize = dwAllocSize;
9681 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
9682 pHostNames, &dwSize) == ERROR_SUCCESS)
9684 for (pName = pHostNames;
9685 (pName - pHostNames < (int) dwSize) && *pName ;
9686 pName += strlen(pName) + 1)
9688 if ( !stricmp(pName, cm_NetbiosName) ) {
9696 if ( !bNameFound ) {
9697 size_t size = strlen(cm_NetbiosName) + 2;
9698 if ( !pHostNames ) {
9699 pHostNames = malloc(size);
9702 StringCbCopyA(pName, size, cm_NetbiosName);
9704 *pName = '\0'; /* add a second nul terminator */
9706 dwType = REG_MULTI_SZ;
9707 dwSize = (DWORD)(pName - pHostNames + 1);
9708 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9716 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
9717 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9718 (dwType == REG_MULTI_SZ))
9720 dwAllocSize += 1 /* in case the source string is not nul terminated */
9721 + (DWORD)strlen(cm_NetbiosName) + 2;
9722 pHostNames = malloc(dwAllocSize);
9723 dwSize = dwAllocSize;
9724 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
9725 pHostNames, &dwSize) == ERROR_SUCCESS)
9727 for (pName = pHostNames;
9728 (pName - pHostNames < (int) dwSize) && *pName ;
9729 pName += strlen(pName) + 1)
9731 if ( !stricmp(pName, cm_NetbiosName) ) {
9739 if ( !bNameFound ) {
9740 size_t size = strlen(cm_NetbiosName) + 2;
9741 if ( !pHostNames ) {
9742 pHostNames = malloc(size);
9745 StringCbCopyA(pName, size, cm_NetbiosName);
9747 *pName = '\0'; /* add a second nul terminator */
9749 dwType = REG_MULTI_SZ;
9750 dwSize = (DWORD)(pName - pHostNames + 1);
9751 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9759 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
9760 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9761 (dwType != REG_DWORD))
9764 dwSize = sizeof(dwValue);
9765 dwValue = 300; /* 5 minutes */
9766 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9768 RegCloseKey(hkLanMan);
9773 smb_LanAdapterChangeThread(void *param)
9776 * Give the IPAddrDaemon thread a chance
9777 * to block before we trigger.
9780 smb_LanAdapterChange(0);
9783 void smb_SetLanAdapterChangeDetected(void)
9788 lock_ObtainMutex(&smb_StartedLock);
9790 if (!powerStateSuspended) {
9791 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9792 NULL, 0, &lpid, "smb_LanAdapterChange");
9793 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9794 thrd_CloseHandle(phandle);
9797 smb_LanAdapterChangeDetected = 1;
9798 lock_ReleaseMutex(&smb_StartedLock);
9801 void smb_LanAdapterChange(int locked) {
9802 lana_number_t lanaNum;
9804 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9806 LANA_ENUM temp_list;
9811 afsi_log("smb_LanAdapterChange");
9814 lock_ObtainMutex(&smb_StartedLock);
9816 smb_LanAdapterChangeDetected = 0;
9818 if (!powerStateSuspended &&
9819 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9820 LANA_NETBIOS_NAME_FULL)) &&
9821 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9822 if ( isGateway != bGateway ) {
9823 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9824 smb_LANadapter, lanaNum, isGateway, bGateway);
9826 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9827 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9828 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9831 NCB *ncbp = smb_GetNCB();
9832 ncbp->ncb_command = NCBENUM;
9833 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9834 ncbp->ncb_length = sizeof(temp_list);
9835 code = Netbios(ncbp);
9837 if (temp_list.length != lana_list.length) {
9838 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9839 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9842 for (i=0; i<lana_list.length; i++) {
9843 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9844 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9845 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9857 smb_StopListeners(1);
9858 smb_RestartListeners(1);
9861 lock_ReleaseMutex(&smb_StartedLock);
9864 /* initialize Netbios */
9865 int smb_NetbiosInit(int locked)
9868 int i, lana, code, l;
9870 int delname_tried=0;
9873 lana_number_t lanaNum;
9876 lock_ObtainMutex(&smb_StartedLock);
9878 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9879 smb_ListenerState != SMB_LISTENER_STOPPED) {
9882 lock_ReleaseMutex(&smb_StartedLock);
9885 /* setup the NCB system */
9886 ncbp = smb_GetNCB();
9888 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9889 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9890 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9892 if (smb_LANadapter != LANA_INVALID)
9893 afsi_log("LAN adapter number %d", smb_LANadapter);
9895 afsi_log("LAN adapter number not determined");
9898 afsi_log("Set for gateway service");
9900 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9902 /* something went horribly wrong. We can't proceed without a netbios name */
9904 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9905 osi_panic(buf, __FILE__, __LINE__);
9908 /* remember the name */
9909 len = (int)strlen(cm_NetbiosName);
9911 free(smb_localNamep);
9912 smb_localNamep = malloc(len+1);
9913 strcpy(smb_localNamep, cm_NetbiosName);
9914 afsi_log("smb_localNamep is >%s<", smb_localNamep);
9916 /* Also copy the value to the client character encoded string */
9917 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
9919 if (smb_LANadapter == LANA_INVALID) {
9920 ncbp->ncb_command = NCBENUM;
9921 ncbp->ncb_buffer = (PUCHAR)&lana_list;
9922 ncbp->ncb_length = sizeof(lana_list);
9923 code = Netbios(ncbp);
9925 afsi_log("Netbios NCBENUM error code %d", code);
9926 osi_panic(s, __FILE__, __LINE__);
9930 lana_list.length = 1;
9931 lana_list.lana[0] = smb_LANadapter;
9934 for (i = 0; i < lana_list.length; i++) {
9935 /* reset the adaptor: in Win32, this is required for every process, and
9936 * acts as an init call, not as a real hardware reset.
9938 ncbp->ncb_command = NCBRESET;
9939 ncbp->ncb_callname[0] = 100;
9940 ncbp->ncb_callname[2] = 100;
9941 ncbp->ncb_lana_num = lana_list.lana[i];
9942 code = Netbios(ncbp);
9944 code = ncbp->ncb_retcode;
9946 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
9947 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
9949 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
9953 /* and declare our name so we can receive connections */
9954 memset(ncbp, 0, sizeof(*ncbp));
9955 len=lstrlen(smb_localNamep);
9956 memset(smb_sharename,' ',NCBNAMSZ);
9957 memcpy(smb_sharename,smb_localNamep,len);
9958 afsi_log("lana_list.length %d", lana_list.length);
9960 /* Keep the name so we can unregister it later */
9961 for (l = 0; l < lana_list.length; l++) {
9962 lana = lana_list.lana[l];
9964 ncbp->ncb_command = NCBADDNAME;
9965 ncbp->ncb_lana_num = lana;
9966 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9967 code = Netbios(ncbp);
9969 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
9970 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9972 char name[NCBNAMSZ+1];
9974 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
9975 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
9979 code = ncbp->ncb_retcode;
9982 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
9985 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9986 if (code == NRC_BRIDGE) { /* invalid LANA num */
9987 lana_list.lana[l] = LANA_INVALID;
9990 else if (code == NRC_DUPNAME) {
9991 afsi_log("Name already exists; try to delete it");
9992 memset(ncbp, 0, sizeof(*ncbp));
9993 ncbp->ncb_command = NCBDELNAME;
9994 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9995 ncbp->ncb_lana_num = lana;
9996 code = Netbios(ncbp);
9998 code = ncbp->ncb_retcode;
10000 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10002 if (code != 0 || delname_tried) {
10003 lana_list.lana[l] = LANA_INVALID;
10005 else if (code == 0) {
10006 if (!delname_tried) {
10014 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10015 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10019 smb_LANadapter = lana;
10020 lana_found = 1; /* at least one worked */
10024 osi_assertx(lana_list.length >= 0, "empty lana list");
10026 afsi_log("No valid LANA numbers found!");
10027 lana_list.length = 0;
10028 smb_LANadapter = LANA_INVALID;
10029 smb_ListenerState = SMB_LISTENER_STOPPED;
10030 cm_VolStatus_Network_Stopped(cm_NetbiosName
10037 /* we're done with the NCB now */
10040 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10041 if (lana_list.length > 0)
10042 osi_assert(smb_LANadapter != LANA_INVALID);
10045 lock_ReleaseMutex(&smb_StartedLock);
10047 return (lana_list.length > 0 ? 1 : 0);
10050 void smb_StartListeners(int locked)
10057 lock_ObtainMutex(&smb_StartedLock);
10059 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10061 lock_ReleaseMutex(&smb_StartedLock);
10065 afsi_log("smb_StartListeners");
10066 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10067 configureBackConnectionHostNames();
10069 /* Configure Extended SMB Session Timeouts */
10070 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10071 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10072 configureExtendedSMBSessionTimeouts();
10075 smb_ListenerState = SMB_LISTENER_STARTED;
10076 cm_VolStatus_Network_Started(cm_NetbiosName
10082 for (i = 0; i < lana_list.length; i++) {
10083 if (lana_list.lana[i] == LANA_INVALID)
10085 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10086 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10087 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10088 thrd_CloseHandle(phandle);
10091 lock_ReleaseMutex(&smb_StartedLock);
10094 void smb_RestartListeners(int locked)
10097 lock_ObtainMutex(&smb_StartedLock);
10099 if (powerStateSuspended)
10100 afsi_log("smb_RestartListeners called while suspended");
10102 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10103 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10104 if (smb_NetbiosInit(1))
10105 smb_StartListeners(1);
10106 } else if (smb_LanAdapterChangeDetected) {
10107 smb_LanAdapterChange(1);
10111 lock_ReleaseMutex(&smb_StartedLock);
10114 void smb_StopListener(NCB *ncbp, int lana, int wait)
10118 memset(ncbp, 0, sizeof(*ncbp));
10119 ncbp->ncb_command = NCBDELNAME;
10120 ncbp->ncb_lana_num = lana;
10121 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10122 code = Netbios(ncbp);
10124 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10125 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10127 /* and then reset the LANA; this will cause the listener threads to exit */
10128 ncbp->ncb_command = NCBRESET;
10129 ncbp->ncb_callname[0] = 100;
10130 ncbp->ncb_callname[2] = 100;
10131 ncbp->ncb_lana_num = lana;
10132 code = Netbios(ncbp);
10134 code = ncbp->ncb_retcode;
10136 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10138 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10142 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10145 void smb_StopListeners(int locked)
10151 lock_ObtainMutex(&smb_StartedLock);
10153 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10155 lock_ReleaseMutex(&smb_StartedLock);
10159 afsi_log("smb_StopListeners");
10160 smb_ListenerState = SMB_LISTENER_STOPPED;
10161 cm_VolStatus_Network_Stopped(cm_NetbiosName
10167 ncbp = smb_GetNCB();
10169 /* Unregister the SMB name */
10170 for (l = 0; l < lana_list.length; l++) {
10171 lana = lana_list.lana[l];
10173 if (lana != LANA_INVALID) {
10174 smb_StopListener(ncbp, lana, TRUE);
10176 /* mark the adapter invalid */
10177 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10181 /* force a re-evaluation of the network adapters */
10182 lana_list.length = 0;
10183 smb_LANadapter = LANA_INVALID;
10186 lock_ReleaseMutex(&smb_StartedLock);
10189 void smb_Init(osi_log_t *logp, int useV3,
10199 EVENT_HANDLE retHandle;
10200 char eventName[MAX_PATH];
10201 int startListeners = 0;
10203 smb_MBfunc = aMBfunc;
10207 /* Initialize smb_localZero */
10208 myTime.tm_isdst = -1; /* compute whether on DST or not */
10209 myTime.tm_year = 70;
10211 myTime.tm_mday = 1;
10212 myTime.tm_hour = 0;
10215 smb_localZero = mktime(&myTime);
10217 #ifdef AFS_FREELANCE_CLIENT
10218 /* Make sure the root.afs volume has the correct time */
10219 cm_noteLocalMountPointChange();
10222 /* initialize the remote debugging log */
10225 /* and the global lock */
10226 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10227 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10229 /* Raw I/O data structures */
10230 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10232 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10233 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10235 /* 4 Raw I/O buffers */
10236 smb_RawBufs = calloc(65536,1);
10237 *((char **)smb_RawBufs) = NULL;
10238 for (i=0; i<3; i++) {
10239 char *rawBuf = calloc(65536,1);
10240 *((char **)rawBuf) = smb_RawBufs;
10241 smb_RawBufs = rawBuf;
10244 /* global free lists */
10245 smb_ncbFreeListp = NULL;
10246 smb_packetFreeListp = NULL;
10248 lock_ObtainMutex(&smb_StartedLock);
10249 startListeners = smb_NetbiosInit(1);
10251 /* Initialize listener and server structures */
10253 memset(dead_sessions, 0, sizeof(dead_sessions));
10254 sprintf(eventName, "SessionEvents[0]");
10255 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10256 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10257 afsi_log("Event Object Already Exists: %s", eventName);
10259 smb_NumServerThreads = nThreads;
10260 sprintf(eventName, "NCBavails[0]");
10261 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10262 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10263 afsi_log("Event Object Already Exists: %s", eventName);
10264 sprintf(eventName, "NCBevents[0]");
10265 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10266 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10267 afsi_log("Event Object Already Exists: %s", eventName);
10268 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10269 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10270 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10271 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10272 afsi_log("Event Object Already Exists: %s", eventName);
10273 for (i = 0; i < smb_NumServerThreads; i++) {
10274 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10275 NCBreturns[i][0] = retHandle;
10278 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10279 for (i = 0; i < smb_NumServerThreads; i++) {
10280 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10281 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10282 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10283 afsi_log("Event Object Already Exists: %s", eventName);
10284 InitNCBslot((int)(i+1));
10286 numNCBs = smb_NumServerThreads + 1;
10288 /* Initialize dispatch table */
10289 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10290 /* Prepare the table for unknown operations */
10291 for(i=0; i<= SMB_NOPCODES; i++) {
10292 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10294 /* Fill in the ones we do know */
10295 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10296 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10297 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10298 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10299 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10300 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10301 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10302 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10303 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10304 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10305 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10306 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10307 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10308 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10309 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10310 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10311 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10312 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10313 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10314 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10315 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10316 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10317 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10318 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10319 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10320 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10321 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10322 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10323 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10324 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10325 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10326 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10327 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10328 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10329 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10330 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10331 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10332 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10333 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10334 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10335 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10336 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10337 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10338 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10339 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10340 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10341 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10342 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10343 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10344 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10345 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10346 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10347 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10348 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10349 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10350 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10351 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10352 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10353 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10354 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10355 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10356 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10357 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10358 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10359 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10360 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10361 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10362 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10363 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10364 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10365 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10366 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10367 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10368 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10370 /* setup tran 2 dispatch table */
10371 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10372 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10373 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10374 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10375 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10376 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10377 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10378 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10379 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10380 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10381 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10382 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10383 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10384 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10385 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10386 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10387 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10388 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10390 /* setup the rap dispatch table */
10391 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10392 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10393 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10394 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10395 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10399 /* if we are doing SMB authentication we have register outselves as a logon process */
10400 if (smb_authType != SMB_AUTH_NONE) {
10401 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10402 LSA_STRING afsProcessName;
10403 LSA_OPERATIONAL_MODE dummy; /*junk*/
10405 afsProcessName.Buffer = "OpenAFSClientDaemon";
10406 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10407 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10409 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10411 if (nts == STATUS_SUCCESS) {
10412 LSA_STRING packageName;
10413 /* we are registered. Find out the security package id */
10414 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10415 packageName.Length = (USHORT)strlen(packageName.Buffer);
10416 packageName.MaximumLength = packageName.Length + 1;
10417 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10418 if (nts == STATUS_SUCCESS) {
10420 * This code forces Windows to authenticate against the Logon Cache
10421 * first instead of attempting to authenticate against the Domain
10422 * Controller. When the Windows logon cache is enabled this improves
10423 * performance by removing the network access and works around a bug
10424 * seen at sites which are using a MIT Kerberos principal to login
10425 * to machines joined to a non-root domain in a multi-domain forest.
10426 * MsV1_0SetProcessOption was added in Windows XP.
10428 PVOID pResponse = NULL;
10429 ULONG cbResponse = 0;
10430 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10432 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10433 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10434 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10435 OptionsRequest.DisableOptions = FALSE;
10437 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10440 sizeof(OptionsRequest),
10446 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10447 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10450 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10452 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10453 afsi_log("MsV1_0SetProcessOption success");
10455 /* END - code from Larry */
10457 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10458 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10459 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10461 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10463 /* something went wrong. We report the error and revert back to no authentication
10464 because we can't perform any auth requests without a successful lsa handle
10465 or sec package id. */
10466 afsi_log("Reverting to NO SMB AUTH");
10467 smb_authType = SMB_AUTH_NONE;
10470 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10472 /* something went wrong. We report the error and revert back to no authentication
10473 because we can't perform any auth requests without a successful lsa handle
10474 or sec package id. */
10475 afsi_log("Reverting to NO SMB AUTH");
10476 smb_authType = SMB_AUTH_NONE;
10480 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10481 * time prevents the failure of authentication when logged into Windows with an
10482 * external Kerberos principal mapped to a local account.
10484 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10485 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10486 * then the only option is NTLMSSP anyway; so just fallback.
10491 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10492 if (secBlobLength == 0) {
10493 smb_authType = SMB_AUTH_NTLM;
10494 afsi_log("Reverting to SMB AUTH NTLM");
10503 /* Now get ourselves a domain name. */
10504 /* For now we are using the local computer name as the domain name.
10505 * It is actually the domain for local logins, and we are acting as
10506 * a local SMB server.
10508 bufsize = lengthof(smb_ServerDomainName) - 1;
10509 GetComputerNameW(smb_ServerDomainName, &bufsize);
10510 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10511 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10514 /* Start listeners, waiters, servers, and daemons */
10515 if (startListeners)
10516 smb_StartListeners(1);
10518 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10519 NULL, 0, &lpid, "smb_ClientWaiter");
10520 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10521 thrd_CloseHandle(phandle);
10523 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10524 NULL, 0, &lpid, "smb_ServerWaiter");
10525 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10526 thrd_CloseHandle(phandle);
10528 for (i=0; i<smb_NumServerThreads; i++) {
10529 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10530 (void *) i, 0, &lpid, "smb_Server");
10531 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10532 thrd_CloseHandle(phandle);
10535 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10536 NULL, 0, &lpid, "smb_Daemon");
10537 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10538 thrd_CloseHandle(phandle);
10540 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10541 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10542 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10543 thrd_CloseHandle(phandle);
10545 lock_ReleaseMutex(&smb_StartedLock);
10549 void smb_Shutdown(void)
10556 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10558 /* setup the NCB system */
10559 ncbp = smb_GetNCB();
10561 /* Block new sessions by setting shutdown flag */
10562 smbShutdownFlag = 1;
10564 /* Hang up all sessions */
10565 memset((char *)ncbp, 0, sizeof(NCB));
10566 for (i = 1; i < numSessions; i++)
10568 if (dead_sessions[i])
10571 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10572 ncbp->ncb_command = NCBHANGUP;
10573 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10574 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10575 code = Netbios(ncbp);
10576 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10577 if (code == 0) code = ncbp->ncb_retcode;
10579 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10580 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10584 /* Trigger the shutdown of all SMB threads */
10585 for (i = 0; i < smb_NumServerThreads; i++)
10586 thrd_SetEvent(NCBreturns[i][0]);
10588 thrd_SetEvent(NCBevents[0]);
10589 thrd_SetEvent(SessionEvents[0]);
10590 thrd_SetEvent(NCBavails[0]);
10592 for (i = 0;i < smb_NumServerThreads; i++) {
10593 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10594 if (code == WAIT_OBJECT_0) {
10597 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10598 thrd_SetEvent(NCBreturns[i--][0]);
10602 /* Delete Netbios name */
10603 memset((char *)ncbp, 0, sizeof(NCB));
10604 for (i = 0; i < lana_list.length; i++) {
10605 if (lana_list.lana[i] == LANA_INVALID) continue;
10606 ncbp->ncb_command = NCBDELNAME;
10607 ncbp->ncb_lana_num = lana_list.lana[i];
10608 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10609 code = Netbios(ncbp);
10611 code = ncbp->ncb_retcode;
10613 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10614 ncbp->ncb_lana_num, code);
10619 /* Release the reference counts held by the VCs */
10620 lock_ObtainWrite(&smb_rctLock);
10621 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10626 if (vcp->magic != SMB_VC_MAGIC)
10627 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10628 __FILE__, __LINE__);
10630 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10632 if (fidp->scp != NULL) {
10635 lock_ReleaseWrite(&smb_rctLock);
10636 lock_ObtainMutex(&fidp->mx);
10637 if (fidp->scp != NULL) {
10640 lock_ObtainWrite(&scp->rw);
10641 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10642 lock_ReleaseWrite(&scp->rw);
10643 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10644 cm_ReleaseSCache(scp);
10646 lock_ReleaseMutex(&fidp->mx);
10647 lock_ObtainWrite(&smb_rctLock);
10651 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10653 smb_ReleaseVCNoLock(tidp->vcp);
10655 cm_user_t *userp = tidp->userp;
10656 tidp->userp = NULL;
10657 cm_ReleaseUser(userp);
10661 lock_ReleaseWrite(&smb_rctLock);
10665 /* Get the UNC \\<servername>\<sharename> prefix. */
10666 char *smb_GetSharename()
10671 /* Make sure we have been properly initialized. */
10672 if (smb_localNamep == NULL)
10675 /* Allocate space for \\<servername>\<sharename>, plus the
10678 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10679 name = malloc(len);
10680 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10686 void smb_LogPacket(smb_packet_t *packet)
10690 unsigned length, paramlen, datalen, i, j;
10692 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10694 if (!packet) return;
10696 osi_Log0(smb_logp, "*** SMB packet dump ***");
10698 smbp = (smb_t *) packet->data;
10699 vp = (BYTE *) packet->data;
10701 paramlen = smbp->wct * 2;
10702 datalen = *((WORD *) (smbp->vdata + paramlen));
10703 length = sizeof(*smbp) + paramlen + 1 + datalen;
10705 for (i=0;i < length; i+=16)
10707 memset( buf, ' ', 80 );
10710 itoa( i, buf, 16 );
10712 buf[strlen(buf)] = ' ';
10714 cp = (BYTE*) buf + 7;
10716 for (j=0;j < 16 && (i+j)<length; j++)
10718 *(cp++) = hex[vp[i+j] >> 4];
10719 *(cp++) = hex[vp[i+j] & 0xf];
10729 for (j=0;j < 16 && (i+j)<length;j++)
10731 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10742 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10745 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10747 #endif /* LOG_PACKET */
10750 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10756 smb_username_t *unp;
10757 smb_waitingLockRequest_t *wlrp;
10760 lock_ObtainRead(&smb_rctLock);
10762 sprintf(output, "begin dumping smb_username_t\r\n");
10763 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10764 for (unp = usernamesp; unp; unp=unp->nextp)
10766 cm_ucell_t *ucellp;
10768 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10769 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10770 unp->name ? unp->name : _C("NULL"),
10771 unp->machine ? unp->machine : _C("NULL"));
10772 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10774 sprintf(output, " begin dumping cm_ucell_t\r\n");
10775 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10777 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10778 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",
10779 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10780 ucellp->expirationTime, ucellp->gen,
10782 ucellp->cellp->name);
10783 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10786 sprintf(output, " done dumping cm_ucell_t\r\n");
10787 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10790 sprintf(output, "done dumping smb_username_t\r\n");
10791 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10794 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10795 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10798 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10799 smb_waitingLock_t *lockp;
10801 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10802 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10803 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10805 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10806 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10807 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10808 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10809 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10810 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10812 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10813 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10816 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10817 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10819 sprintf(output, "begin dumping smb_vc_t\r\n");
10820 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10822 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10828 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10829 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10830 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10832 sprintf(output, " begin dumping smb_user_t\r\n");
10833 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10834 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10835 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10836 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10837 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10839 sprintf(output, " done dumping smb_user_t\r\n");
10840 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10842 sprintf(output, " begin dumping smb_tid_t\r\n");
10843 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10844 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10845 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",
10846 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10847 tidp->pathname ? tidp->pathname : _C("NULL"));
10848 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10850 sprintf(output, " done dumping smb_tid_t\r\n");
10851 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10853 sprintf(output, " begin dumping smb_fid_t\r\n");
10854 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10856 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10858 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",
10859 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10860 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10861 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10862 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10865 sprintf(output, " done dumping smb_fid_t\r\n");
10866 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10869 sprintf(output, "done dumping smb_vc_t\r\n");
10870 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10872 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10873 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10875 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10881 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10882 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10883 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10885 sprintf(output, " begin dumping smb_user_t\r\n");
10886 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10887 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10888 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10889 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10890 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10892 sprintf(output, " done dumping smb_user_t\r\n");
10893 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10895 sprintf(output, " begin dumping smb_tid_t\r\n");
10896 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10897 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10898 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",
10899 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10900 tidp->pathname ? tidp->pathname : _C("NULL"));
10901 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10903 sprintf(output, " done dumping smb_tid_t\r\n");
10904 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10906 sprintf(output, " begin dumping smb_fid_t\r\n");
10907 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10909 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10911 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",
10912 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10913 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10914 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10915 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10918 sprintf(output, " done dumping smb_fid_t\r\n");
10919 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10922 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
10923 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10926 lock_ReleaseRead(&smb_rctLock);
10930 long smb_IsNetworkStarted(void)
10933 lock_ObtainWrite(&smb_globalLock);
10934 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
10935 lock_ReleaseWrite(&smb_globalLock);