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 /* Initial mode bits for files and directories. Set to 0 to use
139 int smb_unixModeDefaultFile = 0666;
140 int smb_unixModeDefaultDir = 0777;
142 /* hide dot files? */
143 int smb_hideDotFiles;
145 /* Negotiate Unicode support? */
148 /* global state about V3 protocols */
149 int smb_useV3; /* try to negotiate V3 */
151 static int showErrors = 0;
152 /* MessageBox or something like it */
153 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
157 * Time in Unix format of midnight, 1/1/1970 local time.
158 * When added to dosUTime, gives Unix (AFS) time.
160 time_t smb_localZero = 0;
162 char *smb_localNamep = NULL;
164 smb_vc_t *smb_allVCsp;
165 smb_vc_t *smb_deadVCsp;
167 smb_username_t *usernamesp = NULL;
169 smb_waitingLockRequest_t *smb_allWaitingLocks;
172 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
173 NCB *ncbp, raw_write_cont_t *rwcp);
174 int smb_NetbiosInit(int);
177 void smb_LogPacket(smb_packet_t *packet);
178 #endif /* LOG_PACKET */
180 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
181 int smb_ServerDomainNameLength = 0;
182 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
183 int smb_ServerOSLength = lengthof(smb_ServerOS);
184 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
185 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
187 /* Faux server GUID. This is never checked. */
188 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
190 void smb_InitReq(cm_req_t *reqp)
193 reqp->flags |= CM_REQ_SOURCE_SMB;
196 const char * ncb_error_string(int code)
200 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
201 case 0x03: s = "NRC_ILLCMD illegal command"; break;
202 case 0x05: s = "NRC_CMDTMO command timed out"; break;
203 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
204 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
205 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
206 case 0x09: s = "NRC_NORES no resource available"; break;
207 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
208 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
209 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
210 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
211 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
212 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
213 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
214 case 0x13: s = "NRC_ILLNN illegal name number"; break;
215 case 0x14: s = "NRC_NOCALL no callname"; break;
216 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
217 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
218 case 0x17: s = "NRC_NAMERR name deleted"; break;
219 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
220 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
221 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
222 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
223 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
224 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
225 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
226 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
227 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
228 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
229 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
230 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
231 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
232 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
233 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
234 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
235 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
236 case 0x40: s = "NRC_SYSTEM system error"; break;
237 default: s = "unknown error";
243 char * myCrt_Dispatch(int i)
248 return "(00)ReceiveCoreMakeDir";
250 return "(01)ReceiveCoreRemoveDir";
252 return "(02)ReceiveCoreOpen";
254 return "(03)ReceiveCoreCreate";
256 return "(04)ReceiveCoreClose";
258 return "(05)ReceiveCoreFlush";
260 return "(06)ReceiveCoreUnlink";
262 return "(07)ReceiveCoreRename";
264 return "(08)ReceiveCoreGetFileAttributes";
266 return "(09)ReceiveCoreSetFileAttributes";
268 return "(0a)ReceiveCoreRead";
270 return "(0b)ReceiveCoreWrite";
272 return "(0c)ReceiveCoreLockRecord";
274 return "(0d)ReceiveCoreUnlockRecord";
276 return "(0e)SendCoreBadOp";
278 return "(0f)ReceiveCoreCreate";
280 return "(10)ReceiveCoreCheckPath";
282 return "(11)SendCoreBadOp";
284 return "(12)ReceiveCoreSeek";
286 return "(1a)ReceiveCoreReadRaw";
288 return "(1d)ReceiveCoreWriteRawDummy";
290 return "(22)ReceiveV3SetAttributes";
292 return "(23)ReceiveV3GetAttributes";
294 return "(24)ReceiveV3LockingX";
296 return "(25)ReceiveV3Trans";
298 return "(26)ReceiveV3Trans[aux]";
300 return "(29)SendCoreBadOp";
302 return "(2b)ReceiveCoreEcho";
304 return "(2d)ReceiveV3OpenX";
306 return "(2e)ReceiveV3ReadX";
308 return "(2f)ReceiveV3WriteX";
310 return "(32)ReceiveV3Tran2A";
312 return "(33)ReceiveV3Tran2A[aux]";
314 return "(34)ReceiveV3FindClose";
316 return "(35)ReceiveV3FindNotifyClose";
318 return "(70)ReceiveCoreTreeConnect";
320 return "(71)ReceiveCoreTreeDisconnect";
322 return "(72)ReceiveNegotiate";
324 return "(73)ReceiveV3SessionSetupX";
326 return "(74)ReceiveV3UserLogoffX";
328 return "(75)ReceiveV3TreeConnectX";
330 return "(80)ReceiveCoreGetDiskAttributes";
332 return "(81)ReceiveCoreSearchDir";
336 return "(83)FindUnique";
338 return "(84)FindClose";
340 return "(A0)ReceiveNTTransact";
342 return "(A2)ReceiveNTCreateX";
344 return "(A4)ReceiveNTCancel";
346 return "(A5)ReceiveNTRename";
348 return "(C0)OpenPrintFile";
350 return "(C1)WritePrintFile";
352 return "(C2)ClosePrintFile";
354 return "(C3)GetPrintQueue";
356 return "(D8)ReadBulk";
358 return "(D9)WriteBulk";
360 return "(DA)WriteBulkData";
362 return "unknown SMB op";
366 char * myCrt_2Dispatch(int i)
371 return "unknown SMB op-2";
373 return "S(00)CreateFile_ReceiveTran2Open";
375 return "S(01)FindFirst_ReceiveTran2SearchDir";
377 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
379 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
381 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
383 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
385 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
387 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
389 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
391 return "S(09)_ReceiveTran2FSCTL";
393 return "S(0a)_ReceiveTran2IOCTL";
395 return "S(0b)_ReceiveTran2FindNotifyFirst";
397 return "S(0c)_ReceiveTran2FindNotifyNext";
399 return "S(0d)_ReceiveTran2CreateDirectory";
401 return "S(0e)_ReceiveTran2SessionSetup";
403 return "S(0f)_QueryFileSystemInformationFid";
405 return "S(10)_ReceiveTran2GetDfsReferral";
407 return "S(11)_ReceiveTran2ReportDfsInconsistency";
411 char * myCrt_RapDispatch(int i)
416 return "unknown RAP OP";
418 return "RAP(0)NetShareEnum";
420 return "RAP(1)NetShareGetInfo";
422 return "RAP(13)NetServerGetInfo";
424 return "RAP(63)NetWkStaGetInfo";
428 char * myCrt_NmpipeDispatch(int i)
431 case SMB_TRANS_SET_NMPIPE_STATE:
432 return "SET NMPIPE STATE";
434 case SMB_TRANS_RAW_READ_NMPIPE:
435 return "RAW READ NMPIPE";
437 case SMB_TRANS_QUERY_NMPIPE_STATE:
438 return "QUERY NMPIPE STATE";
440 case SMB_TRANS_QUERY_NMPIPE_INFO:
441 return "QUERY NMPIPE INFO";
443 case SMB_TRANS_PEEK_NMPIPE:
444 return "PEEK NMPIPE";
446 case SMB_TRANS_TRANSACT_NMPIPE:
447 return "TRANSACT NMPIPE";
449 case SMB_TRANS_RAW_WRITE_NMPIPE:
450 return "WRITE NMPIPE";
452 case SMB_TRANS_READ_NMPIPE:
453 return "READ NMPIPE";
455 case SMB_TRANS_WRITE_NMPIPE:
456 return "WRITE NMPIPE";
458 case SMB_TRANS_WAIT_NMPIPE:
459 return "WAIT NMPIPE";
461 case SMB_TRANS_CALL_NMPIPE:
462 return "CALL NMPIPE";
467 /* scache must be locked */
468 unsigned int smb_Attributes(cm_scache_t *scp)
472 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
473 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
474 scp->fileType == CM_SCACHETYPE_INVALID)
476 attrs = SMB_ATTR_DIRECTORY;
477 #ifdef SPECIAL_FOLDERS
478 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
479 #endif /* SPECIAL_FOLDERS */
480 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
481 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
486 * We used to mark a file RO if it was in an RO volume, but that
487 * turns out to be impolitic in NT. See defect 10007.
490 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
491 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
493 if ((scp->unixModeBits & 0200) == 0)
494 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
500 void smb_SetInitialModeBitsForFile(int smb_attr, cm_attr_t * attr)
502 if (smb_unixModeDefaultFile != 0) {
503 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
504 attr->unixModeBits = smb_unixModeDefaultFile;
505 if (smb_attr & SMB_ATTR_READONLY)
506 attr->unixModeBits &= ~0222;
510 void smb_SetInitialModeBitsForDir(int smb_attr, cm_attr_t * attr)
512 if (smb_unixModeDefaultDir != 0) {
513 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
514 attr->unixModeBits = smb_unixModeDefaultDir;
518 /* Check if the named file/dir is a dotfile/dotdir */
519 /* String pointed to by lastComp can have leading slashes, but otherwise should have
520 no other patch components */
521 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
525 /* skip over slashes */
526 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
531 /* nulls, curdir and parent dir doesn't count */
537 if(*(s+1) == _C('.') && !*(s + 2))
544 static int ExtractBits(WORD bits, short start, short len)
551 num = bits << (16 - end);
552 num = num >> ((16 - end) + start);
557 void ShowUnixTime(char *FuncName, time_t unixTime)
562 cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
564 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
565 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
567 int day, month, year, sec, min, hour;
570 day = ExtractBits(wDate, 0, 5);
571 month = ExtractBits(wDate, 5, 4);
572 year = ExtractBits(wDate, 9, 7) + 1980;
574 sec = ExtractBits(wTime, 0, 5);
575 min = ExtractBits(wTime, 5, 6);
576 hour = ExtractBits(wTime, 11, 5);
578 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
579 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
583 /* Determine if we are observing daylight savings time */
584 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
586 TIME_ZONE_INFORMATION timeZoneInformation;
587 SYSTEMTIME utc, local, localDST;
589 /* Get the time zone info. NT uses this to calc if we are in DST. */
590 GetTimeZoneInformation(&timeZoneInformation);
592 /* Return the daylight bias */
593 *pDstBias = timeZoneInformation.DaylightBias;
595 /* Return the bias */
596 *pBias = timeZoneInformation.Bias;
598 /* Now determine if DST is being observed */
600 /* Get the UTC (GMT) time */
603 /* Convert UTC time to local time using the time zone info. If we are
604 observing DST, the calculated local time will include this.
606 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
608 /* Set the daylight bias to 0. The daylight bias is the amount of change
609 * in time that we use for daylight savings time. By setting this to 0
610 * we cause there to be no change in time during daylight savings time.
612 timeZoneInformation.DaylightBias = 0;
614 /* Convert the utc time to local time again, but this time without any
615 adjustment for daylight savings time.
617 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
619 /* If the two times are different, then it means that the localDST that
620 we calculated includes the daylight bias, and therefore we are
621 observing daylight savings time.
623 *pDST = localDST.wHour != local.wHour;
627 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
629 BOOL dst; /* Will be TRUE if observing DST */
630 LONG dstBias; /* Offset from local time if observing DST */
631 LONG bias; /* Offset from GMT for local time */
634 * This function will adjust the last write time to compensate
635 * for two bugs in the smb client:
637 * 1) During Daylight Savings Time, the LastWriteTime is ahead
638 * in time by the DaylightBias (ignoring the sign - the
639 * DaylightBias is always stored as a negative number). If
640 * the DaylightBias is -60, then the LastWriteTime will be
641 * ahead by 60 minutes.
643 * 2) If the local time zone is a positive offset from GMT, then
644 * the LastWriteTime will be the correct local time plus the
645 * Bias (ignoring the sign - a positive offset from GMT is
646 * always stored as a negative Bias). If the Bias is -120,
647 * then the LastWriteTime will be ahead by 120 minutes.
649 * These bugs can occur at the same time.
652 GetTimeZoneInfo(&dst, &dstBias, &bias);
654 /* First adjust for DST */
656 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
658 /* Now adjust for a positive offset from GMT (a negative bias). */
660 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
663 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
665 time_t diff_t = unixTime - smb_localZero;
666 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
667 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
669 *dosUTimep = (afs_uint32)diff_t;
672 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
674 *unixTimep = dosTime + smb_localZero;
677 void smb_MarkAllVCsDead(smb_vc_t * exclude)
680 smb_vc_t **vcp_to_cleanup = NULL;
681 int n_to_cleanup = 0;
684 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
686 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
687 lock_ObtainWrite(&smb_rctLock);
688 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
690 if (vcp->magic != SMB_VC_MAGIC)
691 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
697 lock_ObtainMutex(&vcp->mx);
698 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
699 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
700 lock_ReleaseMutex(&vcp->mx);
701 dead_sessions[vcp->session] = TRUE;
703 lock_ReleaseMutex(&vcp->mx);
708 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
710 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
714 vcp_to_cleanup[i++] = vcp;
715 smb_HoldVCNoLock(vcp);
718 osi_assert(i == n_to_cleanup);
720 lock_ReleaseWrite(&smb_rctLock);
721 lock_ReleaseWrite(&smb_globalLock);
723 for (i=0; i < n_to_cleanup; i++) {
724 smb_CleanupDeadVC(vcp_to_cleanup[i]);
725 smb_ReleaseVC(vcp_to_cleanup[i]);
726 vcp_to_cleanup[i] = 0;
729 free(vcp_to_cleanup);
732 #ifdef DEBUG_SMB_REFCOUNT
733 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
735 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
740 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
741 lock_ObtainWrite(&smb_rctLock);
742 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
743 if (vcp->magic != SMB_VC_MAGIC)
744 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
747 lock_ObtainMutex(&vcp->mx);
748 if (lsn == vcp->lsn && lana == vcp->lana &&
749 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
750 lock_ReleaseMutex(&vcp->mx);
751 smb_HoldVCNoLock(vcp);
754 lock_ReleaseMutex(&vcp->mx);
756 if (!vcp && (flags & SMB_FLAG_CREATE)) {
757 vcp = malloc(sizeof(*vcp));
758 memset(vcp, 0, sizeof(*vcp));
759 vcp->vcID = ++numVCs;
760 vcp->magic = SMB_VC_MAGIC;
761 vcp->refCount = 2; /* smb_allVCsp and caller */
764 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
765 vcp->nextp = smb_allVCsp;
767 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
772 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
773 /* We must obtain a challenge for extended auth
774 * in case the client negotiates smb v3
776 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
777 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
778 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
779 ULONG lsaRespSize = 0;
781 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
783 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
790 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
791 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
792 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
793 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
794 nts, ntsEx, lsaRespSize);
796 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
798 if (ntsEx == STATUS_SUCCESS) {
799 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
802 * This will cause the subsequent authentication to fail but
803 * that is better than us dereferencing a NULL pointer and
806 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
809 LsaFreeReturnBuffer(lsaResp);
812 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
814 if (numVCs >= CM_SESSION_RESERVED) {
816 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
819 #ifdef DEBUG_SMB_REFCOUNT
821 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
822 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
825 lock_ReleaseWrite(&smb_rctLock);
826 lock_ReleaseWrite(&smb_globalLock);
830 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
835 for(i=0; i<11; i++) {
837 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
843 static int smb_IsStarMask(clientchar_t *maskp)
849 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
855 #ifdef DEBUG_SMB_REFCOUNT
856 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
857 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
859 void smb_ReleaseVCInternal(smb_vc_t *vcp)
865 lock_AssertWrite(&smb_rctLock);
868 if (vcp->refCount == 0) {
869 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
870 #ifdef DEBUG_SMB_REFCOUNT
871 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
872 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
874 /* remove VCP from smb_deadVCsp */
875 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
881 lock_FinalizeMutex(&vcp->mx);
882 memset(vcp,0,sizeof(smb_vc_t));
885 #ifdef DEBUG_SMB_REFCOUNT
886 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
888 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
892 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
893 avcp?"":"not ",vcp, vcp->refCount);
895 /* This is a wrong. However, I suspect that there is an undercount
896 * and I don't want to release 1.4.1 in a state that will allow
897 * smb_vc_t objects to be deallocated while still in the
898 * smb_allVCsp list. The list is supposed to keep a reference
899 * to the smb_vc_t. Put it back.
903 #ifdef DEBUG_SMB_REFCOUNT
904 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
905 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
909 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
910 /* The reference count is non-zero but the VC is dead.
911 * This implies that some FIDs, TIDs, etc on the VC have yet to
912 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
913 * add a reference that will be dropped by
914 * smb_CleanupDeadVC() and try to cleanup the VC again.
915 * Eventually the refCount will drop to zero when all of the
916 * active threads working with the VC end their task.
918 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
919 vcp->refCount++; /* put the refCount back */
920 lock_ReleaseWrite(&smb_rctLock);
921 smb_CleanupDeadVC(vcp);
922 #ifdef DEBUG_SMB_REFCOUNT
923 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
924 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
926 lock_ObtainWrite(&smb_rctLock);
929 #ifdef DEBUG_SMB_REFCOUNT
930 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
931 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
936 #ifdef DEBUG_SMB_REFCOUNT
937 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
939 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
942 lock_AssertWrite(&smb_rctLock);
943 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
944 smb_ReleaseVCInternal(vcp);
947 #ifdef DEBUG_SMB_REFCOUNT
948 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
950 void smb_ReleaseVC(smb_vc_t *vcp)
953 lock_ObtainWrite(&smb_rctLock);
954 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
955 smb_ReleaseVCInternal(vcp);
956 lock_ReleaseWrite(&smb_rctLock);
959 #ifdef DEBUG_SMB_REFCOUNT
960 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
962 void smb_HoldVCNoLock(smb_vc_t *vcp)
965 lock_AssertWrite(&smb_rctLock);
967 #ifdef DEBUG_SMB_REFCOUNT
968 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
969 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
971 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
975 #ifdef DEBUG_SMB_REFCOUNT
976 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
978 void smb_HoldVC(smb_vc_t *vcp)
981 lock_ObtainWrite(&smb_rctLock);
983 #ifdef DEBUG_SMB_REFCOUNT
984 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
985 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
987 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
989 lock_ReleaseWrite(&smb_rctLock);
992 void smb_CleanupDeadVC(smb_vc_t *vcp)
1000 smb_user_t *uidpIter;
1001 smb_user_t *uidpNext;
1003 afs_uint32 refCount = 0;
1005 lock_ObtainMutex(&vcp->mx);
1006 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1007 lock_ReleaseMutex(&vcp->mx);
1008 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1011 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1012 lock_ReleaseMutex(&vcp->mx);
1013 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1015 lock_ObtainWrite(&smb_rctLock);
1016 /* remove VCP from smb_allVCsp */
1017 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1018 if ((*vcpp)->magic != SMB_VC_MAGIC)
1019 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1020 __FILE__, __LINE__);
1023 vcp->nextp = smb_deadVCsp;
1025 /* Hold onto the reference until we are done with this function */
1030 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1031 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1033 if (fidpIter->deleteOk)
1036 fid = fidpIter->fid;
1037 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1039 smb_HoldFIDNoLock(fidpIter);
1040 lock_ReleaseWrite(&smb_rctLock);
1042 smb_CloseFID(vcp, fidpIter, NULL, 0);
1043 smb_ReleaseFID(fidpIter);
1045 lock_ObtainWrite(&smb_rctLock);
1046 fidpNext = vcp->fidsp;
1049 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1050 tidpNext = tidpIter->nextp;
1051 if (tidpIter->deleteOk)
1053 tidpIter->deleteOk = 1;
1055 tid = tidpIter->tid;
1056 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1058 smb_HoldTIDNoLock(tidpIter);
1059 smb_ReleaseTID(tidpIter, TRUE);
1060 tidpNext = vcp->tidsp;
1063 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1064 uidpNext = uidpIter->nextp;
1065 if (uidpIter->deleteOk)
1067 uidpIter->deleteOk = 1;
1069 /* do not add an additional reference count for the smb_user_t
1070 * as the smb_vc_t already is holding a reference */
1071 lock_ReleaseWrite(&smb_rctLock);
1073 smb_ReleaseUID(uidpIter);
1075 lock_ObtainWrite(&smb_rctLock);
1076 uidpNext = vcp->usersp;
1079 /* The vcp is now on the deadVCsp list. We intentionally drop the
1080 * reference so that the refcount can reach 0 and we can delete it
1082 * If the refCount == 1 going into the ReleaseVCNoLock call
1083 * the object will be freed and it won't be safe to clear
1086 refCount = vcp->refCount;
1087 smb_ReleaseVCNoLock(vcp);
1089 lock_ObtainMutex(&vcp->mx);
1090 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1091 lock_ReleaseMutex(&vcp->mx);
1094 lock_ReleaseWrite(&smb_rctLock);
1095 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1098 #ifdef DEBUG_SMB_REFCOUNT
1099 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1101 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1106 lock_ObtainWrite(&smb_rctLock);
1108 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1109 if (tidp->refCount == 0 && tidp->deleteOk) {
1111 smb_ReleaseTID(tidp, TRUE);
1115 if (tid == tidp->tid) {
1120 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1121 tidp = malloc(sizeof(*tidp));
1122 memset(tidp, 0, sizeof(*tidp));
1123 tidp->nextp = vcp->tidsp;
1126 smb_HoldVCNoLock(vcp);
1128 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1131 #ifdef DEBUG_SMB_REFCOUNT
1133 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1134 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1137 lock_ReleaseWrite(&smb_rctLock);
1141 #ifdef DEBUG_SMB_REFCOUNT
1142 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1144 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1147 lock_AssertWrite(&smb_rctLock);
1149 #ifdef DEBUG_SMB_REFCOUNT
1150 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1151 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1155 #ifdef DEBUG_SMB_REFCOUNT
1156 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1158 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1163 cm_user_t *userp = NULL;
1164 smb_vc_t *vcp = NULL;
1167 lock_ObtainWrite(&smb_rctLock);
1169 lock_AssertWrite(&smb_rctLock);
1171 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1172 #ifdef DEBUG_SMB_REFCOUNT
1173 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1174 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1176 if (tidp->refCount == 0) {
1177 if (tidp->deleteOk) {
1178 ltpp = &tidp->vcp->tidsp;
1179 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1183 osi_assertx(tp != NULL, "null smb_tid_t");
1185 lock_FinalizeMutex(&tidp->mx);
1186 userp = tidp->userp; /* remember to drop ref later */
1194 smb_ReleaseVCNoLock(vcp);
1196 lock_ReleaseWrite(&smb_rctLock);
1198 cm_ReleaseUser(userp);
1201 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1203 smb_user_t *uidp = NULL;
1205 lock_ObtainWrite(&smb_rctLock);
1206 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1207 if (uid == uidp->userID) {
1209 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1211 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1215 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1216 uidp = malloc(sizeof(*uidp));
1217 memset(uidp, 0, sizeof(*uidp));
1218 uidp->nextp = vcp->usersp;
1219 uidp->refCount = 2; /* one for the vcp and one for the caller */
1221 smb_HoldVCNoLock(vcp);
1223 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1225 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1227 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1229 lock_ReleaseWrite(&smb_rctLock);
1233 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1236 smb_username_t *unp= NULL;
1238 lock_ObtainWrite(&smb_rctLock);
1239 for(unp = usernamesp; unp; unp = unp->nextp) {
1240 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1241 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1246 if (!unp && (flags & SMB_FLAG_CREATE)) {
1247 unp = malloc(sizeof(*unp));
1248 memset(unp, 0, sizeof(*unp));
1250 unp->nextp = usernamesp;
1251 unp->name = cm_ClientStrDup(usern);
1252 unp->machine = cm_ClientStrDup(machine);
1254 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1255 if (flags & SMB_FLAG_AFSLOGON)
1256 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1259 lock_ReleaseWrite(&smb_rctLock);
1263 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1265 smb_user_t *uidp= NULL;
1267 lock_ObtainWrite(&smb_rctLock);
1268 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1271 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1273 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1274 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1279 lock_ReleaseWrite(&smb_rctLock);
1283 void smb_ReleaseUsername(smb_username_t *unp)
1286 smb_username_t **lupp;
1287 cm_user_t *userp = NULL;
1288 time_t now = osi_Time();
1290 lock_ObtainWrite(&smb_rctLock);
1291 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1292 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1293 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1295 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1299 osi_assertx(up != NULL, "null smb_username_t");
1301 up->nextp = NULL; /* do not remove this */
1302 lock_FinalizeMutex(&unp->mx);
1308 lock_ReleaseWrite(&smb_rctLock);
1310 cm_ReleaseUser(userp);
1313 void smb_HoldUIDNoLock(smb_user_t *uidp)
1315 lock_AssertWrite(&smb_rctLock);
1319 void smb_ReleaseUID(smb_user_t *uidp)
1323 smb_username_t *unp = NULL;
1325 lock_ObtainWrite(&smb_rctLock);
1326 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1327 if (uidp->refCount == 0) {
1328 lupp = &uidp->vcp->usersp;
1329 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1333 osi_assertx(up != NULL, "null smb_user_t");
1335 lock_FinalizeMutex(&uidp->mx);
1337 smb_ReleaseVCNoLock(uidp->vcp);
1341 lock_ReleaseWrite(&smb_rctLock);
1345 cm_ReleaseUserVCRef(unp->userp);
1346 smb_ReleaseUsername(unp);
1350 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1352 cm_user_t *up = NULL;
1357 lock_ObtainMutex(&uidp->mx);
1359 up = uidp->unp->userp;
1362 lock_ReleaseMutex(&uidp->mx);
1368 /* retrieve a held reference to a user structure corresponding to an incoming
1370 * corresponding release function is cm_ReleaseUser.
1372 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1375 cm_user_t *up = NULL;
1378 smbp = (smb_t *) inp;
1379 uidp = smb_FindUID(vcp, smbp->uid, 0);
1383 up = smb_GetUserFromUID(uidp);
1385 smb_ReleaseUID(uidp);
1390 * Return a pointer to a pathname extracted from a TID structure. The
1391 * TID structure is not held; assume it won't go away.
1393 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1398 tidp = smb_FindTID(vcp, tid, 0);
1402 if (tidp->flags & SMB_TIDFLAG_IPC) {
1403 code = CM_ERROR_TIDIPC;
1404 /* tidp->pathname would be NULL, but that's fine */
1406 *treepath = tidp->pathname;
1407 smb_ReleaseTID(tidp, FALSE);
1412 /* check to see if we have a chained fid, that is, a fid that comes from an
1413 * OpenAndX message that ran earlier in this packet. In this case, the fid
1414 * field in a read, for example, request, isn't set, since the value is
1415 * supposed to be inherited from the openAndX call.
1417 int smb_ChainFID(int fid, smb_packet_t *inp)
1419 if (inp->fid == 0 || inp->inCount == 0)
1425 /* are we a priv'd user? What does this mean on NT? */
1426 int smb_SUser(cm_user_t *userp)
1431 /* find a file ID. If we pass in 0 we select an unused File ID.
1432 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1433 * smb_fid_t data structure if desired File ID cannot be found.
1435 #ifdef DEBUG_SMB_REFCOUNT
1436 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1438 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1445 if (!(flags & SMB_FLAG_CREATE))
1450 lock_ObtainWrite(&smb_rctLock);
1452 fid = vcp->fidCounter;
1455 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1456 if (fidp->refCount == 0 && fidp->deleteOk) {
1458 lock_ReleaseWrite(&smb_rctLock);
1459 smb_ReleaseFID(fidp);
1460 lock_ObtainWrite(&smb_rctLock);
1462 * We dropped the smb_rctLock so the fid value we are using
1463 * may now be used by another thread. Start over with the
1464 * current vcp->fidCounter.
1467 fid = vcp->fidCounter;
1470 if (fid == fidp->fid) {
1472 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1474 if (fid == 0xFFFF) {
1476 "New FID number wraps on vcp 0x%x", vcp);
1486 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1487 char eventName[MAX_PATH];
1491 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1493 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1495 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1496 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1497 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1498 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1499 thrd_CloseHandle(event);
1501 if (fid == 0xFFFF) {
1502 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1508 fidp = malloc(sizeof(*fidp));
1509 memset(fidp, 0, sizeof(*fidp));
1510 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1513 smb_HoldVCNoLock(vcp);
1514 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1516 fidp->curr_chunk = fidp->prev_chunk = -2;
1517 fidp->raw_write_event = event;
1519 vcp->fidCounter = fid+1;
1520 if (vcp->fidCounter == 0xFFFF) {
1521 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1523 vcp->fidCounter = 1;
1528 #ifdef DEBUG_SMB_REFCOUNT
1530 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1531 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1534 lock_ReleaseWrite(&smb_rctLock);
1539 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1540 #ifdef DEBUG_SMB_REFCOUNT
1541 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1543 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1546 smb_fid_t *fidp = NULL, *nextp = NULL;
1552 * If the fidp->scp changes out from under us then
1553 * we must not grab a refCount. It means the *fidp
1554 * was processed by smb_CloseFID() and the *fidp is
1555 * no longer valid for use.
1557 lock_ObtainWrite(&smb_rctLock);
1558 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1559 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1563 if (scp == fidp->scp) {
1564 lock_ReleaseWrite(&smb_rctLock);
1565 lock_ObtainMutex(&fidp->mx);
1566 lock_ObtainWrite(&smb_rctLock);
1567 if (scp == fidp->scp) {
1568 lock_ReleaseMutex(&fidp->mx);
1571 lock_ReleaseMutex(&fidp->mx);
1574 if (fidp->refCount > 1) {
1577 lock_ReleaseWrite(&smb_rctLock);
1578 smb_ReleaseFID(fidp);
1579 lock_ObtainWrite(&smb_rctLock);
1584 if (nextp->refCount > 1) {
1587 lock_ReleaseWrite(&smb_rctLock);
1588 smb_ReleaseFID(nextp);
1589 lock_ObtainWrite(&smb_rctLock);
1593 #ifdef DEBUG_SMB_REFCOUNT
1595 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1596 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1599 lock_ReleaseWrite(&smb_rctLock);
1603 #ifdef DEBUG_SMB_REFCOUNT
1604 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1606 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1609 lock_AssertWrite(&smb_rctLock);
1611 #ifdef DEBUG_SMB_REFCOUNT
1612 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1613 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1618 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1619 /* the smb_fid_t->mx and smb_rctLock must not be held */
1620 #ifdef DEBUG_SMB_REFCOUNT
1621 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1623 void smb_ReleaseFID(smb_fid_t *fidp)
1626 cm_scache_t *scp = NULL;
1627 cm_user_t *userp = NULL;
1628 smb_vc_t *vcp = NULL;
1629 smb_ioctl_t *ioctlp;
1631 lock_ObtainMutex(&fidp->mx);
1632 lock_ObtainWrite(&smb_rctLock);
1633 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1634 #ifdef DEBUG_SMB_REFCOUNT
1635 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1636 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1638 if (fidp->refCount == 0) {
1639 if (fidp->deleteOk) {
1642 scp = fidp->scp; /* release after lock is released */
1644 lock_ObtainWrite(&scp->rw);
1645 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1646 lock_ReleaseWrite(&scp->rw);
1647 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1650 userp = fidp->userp;
1654 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1655 thrd_CloseHandle(fidp->raw_write_event);
1657 /* and see if there is ioctl stuff to free */
1658 ioctlp = fidp->ioctlp;
1661 cm_FreeSpace(ioctlp->prefix);
1662 if (ioctlp->ioctl.inAllocp)
1663 free(ioctlp->ioctl.inAllocp);
1664 if (ioctlp->ioctl.outAllocp)
1665 free(ioctlp->ioctl.outAllocp);
1669 smb_CleanupRPCFid(fidp);
1671 lock_ReleaseMutex(&fidp->mx);
1672 lock_FinalizeMutex(&fidp->mx);
1677 smb_ReleaseVCNoLock(vcp);
1681 lock_ReleaseMutex(&fidp->mx);
1683 lock_ReleaseWrite(&smb_rctLock);
1685 /* now release the scache structure */
1687 cm_ReleaseSCache(scp);
1690 cm_ReleaseUser(userp);
1694 * Case-insensitive search for one string in another;
1695 * used to find variable names in submount pathnames.
1697 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1699 clientchar_t *cursor;
1701 for (cursor = str1; *cursor; cursor++)
1702 if (cm_ClientStrCmpI(cursor, str2) == 0)
1709 * Substitute a variable value for its name in a submount pathname. Variable
1710 * name has been identified by smb_stristr() and is in substr. Variable name
1711 * length (plus one) is in substr_size. Variable value is in newstr.
1713 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1714 unsigned int substr_size, clientchar_t *newstr)
1716 clientchar_t temp[1024];
1718 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1719 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1720 cm_ClientStrCat(str1, cchstr1, temp);
1723 clientchar_t VNUserName[] = _C("%USERNAME%");
1724 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1725 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1726 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1728 typedef struct smb_findShare_rock {
1729 clientchar_t * shareName;
1730 clientchar_t * match;
1732 } smb_findShare_rock_t;
1734 #define SMB_FINDSHARE_EXACT_MATCH 1
1735 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1737 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1741 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1742 normchar_t normName[MAX_PATH];
1744 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1745 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1746 osi_LogSaveString(smb_logp, dep->name));
1750 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1751 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1752 matchType = SMB_FINDSHARE_EXACT_MATCH;
1754 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1757 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1758 vrock->matchType = matchType;
1760 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1761 return CM_ERROR_STOPNOW;
1767 /* find a shareName in the table of submounts */
1768 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1769 clientchar_t *shareName,
1770 clientchar_t **pathNamep)
1774 clientchar_t pathName[1024];
1777 clientchar_t *p, *q;
1778 fschar_t *cellname = NULL;
1781 DWORD allSubmount = 1;
1783 /* if allSubmounts == 0, only return the //mountRoot/all share
1784 * if in fact it has been been created in the subMounts table.
1785 * This is to allow sites that want to restrict access to the
1788 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1789 0, KEY_QUERY_VALUE, &parmKey);
1790 if (code == ERROR_SUCCESS) {
1791 cblen = sizeof(allSubmount);
1792 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1793 (BYTE *) &allSubmount, &cblen);
1794 if (code != ERROR_SUCCESS) {
1797 RegCloseKey (parmKey);
1800 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1805 /* In case, the all share is disabled we need to still be able
1806 * to handle ioctl requests
1808 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1809 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1813 if (MSRPC_IsWellKnownService(shareName) ||
1814 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1815 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1821 /* Check for volume references
1823 * They look like <cell>{%,#}<volume>
1825 if (cm_ClientStrChr(shareName, '%') != NULL ||
1826 cm_ClientStrChr(shareName, '#') != NULL) {
1827 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1828 /* make room for '/@vol:' + mountchar + NULL terminator*/
1830 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1831 osi_LogSaveClientString(smb_logp, shareName));
1833 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1834 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1835 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1837 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1839 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1840 cm_ClientStrLwr(*pathNamep);
1841 osi_Log1(smb_logp, " returning pathname [%S]",
1842 osi_LogSaveClientString(smb_logp, *pathNamep));
1850 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1851 0, KEY_QUERY_VALUE, &parmKey);
1852 if (code == ERROR_SUCCESS) {
1853 cblen = sizeof(pathName);
1854 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1855 (BYTE *) pathName, &cblen);
1856 if (code != ERROR_SUCCESS)
1858 RegCloseKey (parmKey);
1862 cchlen = cblen / sizeof(clientchar_t);
1863 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1864 /* We can accept either unix or PC style AFS pathnames. Convert
1865 * Unix-style to PC style here for internal use.
1868 cchlen = lengthof(pathName);
1870 /* within this code block, we maintain, cchlen = writeable
1871 buffer length of p */
1873 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1874 p += cm_mountRootCLen; /* skip mount path */
1875 cchlen -= (DWORD)(p - pathName);
1880 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1886 clientchar_t temp[1024];
1888 if (var = smb_stristr(p, VNUserName)) {
1889 if (uidp && uidp->unp)
1890 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1892 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1894 else if (var = smb_stristr(p, VNLCUserName))
1896 if (uidp && uidp->unp)
1897 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1899 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1900 cm_ClientStrLwr(temp);
1901 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1903 else if (var = smb_stristr(p, VNComputerName))
1905 sizeTemp = lengthof(temp);
1906 GetComputerNameW(temp, &sizeTemp);
1907 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1909 else if (var = smb_stristr(p, VNLCComputerName))
1911 sizeTemp = lengthof(temp);
1912 GetComputerName((LPTSTR)temp, &sizeTemp);
1913 cm_ClientStrLwr(temp);
1914 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1919 *pathNamep = cm_ClientStrDup(p);
1924 /* First lookup shareName in root.afs */
1926 smb_findShare_rock_t vrock;
1928 fschar_t ftemp[1024];
1929 clientchar_t * p = shareName;
1932 /* attempt to locate a partial match in root.afs. This is because
1933 when using the ANSI RAP calls, the share name is limited to 13 chars
1934 and hence is truncated. Of course we prefer exact matches. */
1936 thyper.HighPart = 0;
1939 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1940 if (vrock.shareName == NULL)
1943 vrock.matchType = 0;
1945 cm_HoldSCache(cm_data.rootSCachep);
1946 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1947 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1948 cm_ReleaseSCache(cm_data.rootSCachep);
1950 free(vrock.shareName);
1951 vrock.shareName = NULL;
1953 if (vrock.matchType) {
1954 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1955 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1960 /* if we get here, there was no match for the share in root.afs */
1961 /* so try to create \\<netbiosName>\<cellname> */
1966 /* Get the full name for this cell */
1967 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1968 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
1969 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
1970 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1971 if (code && cm_dnsEnabled) {
1973 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1978 /* construct the path */
1980 clientchar_t temp[1024];
1982 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
1983 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
1984 rw ? _C("/.%S/") : _C("/%S/"), temp);
1985 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1995 /* Client-side offline caching policy types */
1996 #define CSC_POLICY_MANUAL 0
1997 #define CSC_POLICY_DOCUMENTS 1
1998 #define CSC_POLICY_PROGRAMS 2
1999 #define CSC_POLICY_DISABLE 3
2001 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2004 clientchar_t policy[1024];
2007 int retval = CSC_POLICY_MANUAL;
2009 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2010 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2013 REG_OPTION_NON_VOLATILE,
2017 NULL ) != ERROR_SUCCESS)
2018 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2020 len = sizeof(policy);
2021 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2023 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2025 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2027 retval = CSC_POLICY_MANUAL;
2029 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2031 retval = CSC_POLICY_DOCUMENTS;
2033 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2035 retval = CSC_POLICY_PROGRAMS;
2037 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2039 retval = CSC_POLICY_DISABLE;
2042 RegCloseKey(hkCSCPolicy);
2046 /* find a dir search structure by cookie value, and return it held.
2047 * Must be called with smb_globalLock held.
2049 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2051 smb_dirSearch_t *dsp;
2053 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2054 if (dsp->cookie == cookie) {
2055 if (dsp != smb_firstDirSearchp) {
2056 /* move to head of LRU queue, too, if we're not already there */
2057 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2058 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2059 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2060 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2061 if (!smb_lastDirSearchp)
2062 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2070 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2071 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2072 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2078 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2080 lock_ObtainMutex(&dsp->mx);
2081 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2082 dsp->cookie, dsp, dsp->scp);
2083 dsp->flags |= SMB_DIRSEARCH_DELETE;
2084 if (dsp->scp != NULL) {
2085 lock_ObtainWrite(&dsp->scp->rw);
2086 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2087 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2088 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2089 dsp->scp->bulkStatProgress = hzero;
2091 lock_ReleaseWrite(&dsp->scp->rw);
2093 lock_ReleaseMutex(&dsp->mx);
2096 /* Must be called with the smb_globalLock held */
2097 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2099 cm_scache_t *scp = NULL;
2101 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2102 if (dsp->refCount == 0) {
2103 lock_ObtainMutex(&dsp->mx);
2104 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2105 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2106 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2107 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2108 lock_ReleaseMutex(&dsp->mx);
2109 lock_FinalizeMutex(&dsp->mx);
2111 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2112 dsp->cookie, dsp, scp);
2115 lock_ReleaseMutex(&dsp->mx);
2118 /* do this now to avoid spurious locking hierarchy creation */
2120 cm_ReleaseSCache(scp);
2123 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2125 lock_ObtainWrite(&smb_globalLock);
2126 smb_ReleaseDirSearchNoLock(dsp);
2127 lock_ReleaseWrite(&smb_globalLock);
2130 /* find a dir search structure by cookie value, and return it held */
2131 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2133 smb_dirSearch_t *dsp;
2135 lock_ObtainWrite(&smb_globalLock);
2136 dsp = smb_FindDirSearchNoLock(cookie);
2137 lock_ReleaseWrite(&smb_globalLock);
2141 /* GC some dir search entries, in the address space expected by the specific protocol.
2142 * Must be called with smb_globalLock held; release the lock temporarily.
2144 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2145 void smb_GCDirSearches(int isV3)
2147 smb_dirSearch_t *prevp;
2148 smb_dirSearch_t *dsp;
2149 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2153 victimCount = 0; /* how many have we got so far */
2154 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2155 /* we'll move tp from queue, so
2158 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2159 /* if no one is using this guy, and we're either in the new protocol,
2160 * or we're in the old one and this is a small enough ID to be useful
2161 * to the old protocol, GC this guy.
2163 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2164 /* hold and delete */
2165 lock_ObtainMutex(&dsp->mx);
2166 dsp->flags |= SMB_DIRSEARCH_DELETE;
2167 lock_ReleaseMutex(&dsp->mx);
2168 victimsp[victimCount++] = dsp;
2172 /* don't do more than this */
2173 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2177 /* now release them */
2178 for (i = 0; i < victimCount; i++) {
2179 smb_ReleaseDirSearchNoLock(victimsp[i]);
2183 /* function for allocating a dir search entry. We need these to remember enough context
2184 * since we don't get passed the path from call to call during a directory search.
2186 * Returns a held dir search structure, and bumps the reference count on the vnode,
2187 * since it saves a pointer to the vnode.
2189 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2191 smb_dirSearch_t *dsp;
2197 lock_ObtainWrite(&smb_globalLock);
2200 /* what's the biggest ID allowed in this version of the protocol */
2201 /* TODO: do we really want a non v3 dir search request to wrap
2202 smb_dirSearchCounter? */
2203 maxAllowed = isV3 ? 65535 : 255;
2204 if (smb_dirSearchCounter > maxAllowed)
2205 smb_dirSearchCounter = 1;
2207 start = smb_dirSearchCounter;
2210 /* twice so we have enough tries to find guys we GC after one pass;
2211 * 10 extra is just in case I mis-counted.
2213 if (++counter > 2*maxAllowed+10)
2214 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2216 if (smb_dirSearchCounter > maxAllowed) {
2217 smb_dirSearchCounter = 1;
2219 if (smb_dirSearchCounter == start) {
2221 smb_GCDirSearches(isV3);
2224 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2226 /* don't need to watch for refcount zero and deleted, since
2227 * we haven't dropped the global lock.
2230 ++smb_dirSearchCounter;
2234 dsp = malloc(sizeof(*dsp));
2235 memset(dsp, 0, sizeof(*dsp));
2236 dsp->cookie = smb_dirSearchCounter;
2237 ++smb_dirSearchCounter;
2239 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2240 dsp->lastTime = osi_Time();
2241 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2242 if (!smb_lastDirSearchp)
2243 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2245 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2249 lock_ReleaseWrite(&smb_globalLock);
2253 static smb_packet_t *smb_GetPacket(void)
2257 lock_ObtainWrite(&smb_globalLock);
2258 tbp = smb_packetFreeListp;
2260 smb_packetFreeListp = tbp->nextp;
2261 lock_ReleaseWrite(&smb_globalLock);
2263 tbp = calloc(sizeof(*tbp),1);
2264 tbp->magic = SMB_PACKETMAGIC;
2267 tbp->resumeCode = 0;
2273 tbp->ncb_length = 0;
2276 tbp->stringsp = NULL;
2278 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2283 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2286 tbp = smb_GetPacket();
2287 memcpy(tbp, pkt, sizeof(smb_packet_t));
2288 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2289 tbp->stringsp = NULL;
2291 smb_HoldVC(tbp->vcp);
2295 static NCB *smb_GetNCB(void)
2300 lock_ObtainWrite(&smb_globalLock);
2301 tbp = smb_ncbFreeListp;
2303 smb_ncbFreeListp = tbp->nextp;
2304 lock_ReleaseWrite(&smb_globalLock);
2306 tbp = calloc(sizeof(*tbp),1);
2307 tbp->magic = SMB_NCBMAGIC;
2310 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2312 memset(&tbp->ncb, 0, sizeof(NCB));
2317 static void FreeSMBStrings(smb_packet_t * pkt)
2322 for (s = pkt->stringsp; s; s = ns) {
2326 pkt->stringsp = NULL;
2329 void smb_FreePacket(smb_packet_t *tbp)
2331 smb_vc_t * vcp = NULL;
2332 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2334 lock_ObtainWrite(&smb_globalLock);
2335 tbp->nextp = smb_packetFreeListp;
2336 smb_packetFreeListp = tbp;
2337 tbp->magic = SMB_PACKETMAGIC;
2341 tbp->resumeCode = 0;
2347 tbp->ncb_length = 0;
2349 FreeSMBStrings(tbp);
2350 lock_ReleaseWrite(&smb_globalLock);
2356 static void smb_FreeNCB(NCB *bufferp)
2360 tbp = (smb_ncb_t *) bufferp;
2361 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2363 lock_ObtainWrite(&smb_globalLock);
2364 tbp->nextp = smb_ncbFreeListp;
2365 smb_ncbFreeListp = tbp;
2366 lock_ReleaseWrite(&smb_globalLock);
2369 /* get a ptr to the data part of a packet, and its count */
2370 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2374 unsigned char *afterParmsp;
2376 parmBytes = *smbp->wctp << 1;
2377 afterParmsp = smbp->wctp + parmBytes + 1;
2379 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2380 if (nbytesp) *nbytesp = dataBytes;
2382 /* don't forget to skip the data byte count, since it follows
2383 * the parameters; that's where the "2" comes from below.
2385 return (unsigned char *) (afterParmsp + 2);
2388 /* must set all the returned parameters before playing around with the
2389 * data region, since the data region is located past the end of the
2390 * variable number of parameters.
2392 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2394 unsigned char *afterParmsp;
2396 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2398 *afterParmsp++ = dsize & 0xff;
2399 *afterParmsp = (dsize>>8) & 0xff;
2402 /* return the parm'th parameter in the smbp packet */
2403 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2406 unsigned char *parmDatap;
2408 parmCount = *smbp->wctp;
2410 if (parm >= parmCount) {
2413 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2414 parm, parmCount, smbp->ncb_length);
2415 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2416 parm, parmCount, smbp->ncb_length);
2417 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2418 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2419 osi_panic(s, __FILE__, __LINE__);
2421 parmDatap = smbp->wctp + (2*parm) + 1;
2423 return parmDatap[0] + (parmDatap[1] << 8);
2426 /* return the parm'th parameter in the smbp packet */
2427 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2430 unsigned char *parmDatap;
2432 parmCount = *smbp->wctp;
2434 if (parm >= parmCount) {
2437 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2438 parm, parmCount, smbp->ncb_length);
2439 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2440 parm, parmCount, smbp->ncb_length);
2441 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2442 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2443 osi_panic(s, __FILE__, __LINE__);
2445 parmDatap = smbp->wctp + (2*parm) + 1;
2447 return parmDatap[0];
2450 /* return the parm'th parameter in the smbp packet */
2451 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2454 unsigned char *parmDatap;
2456 parmCount = *smbp->wctp;
2458 if (parm + 1 >= parmCount) {
2461 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2462 parm, parmCount, smbp->ncb_length);
2463 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2464 parm, parmCount, smbp->ncb_length);
2465 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2466 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2467 osi_panic(s, __FILE__, __LINE__);
2469 parmDatap = smbp->wctp + (2*parm) + 1;
2471 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2474 /* return the parm'th parameter in the smbp packet */
2475 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2478 unsigned char *parmDatap;
2480 parmCount = *smbp->wctp;
2482 if (parm * 2 + offset >= parmCount * 2) {
2485 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2486 parm, offset, parmCount, smbp->ncb_length);
2487 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2488 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2489 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2490 parm, offset, parmCount, smbp->ncb_length);
2491 osi_panic(s, __FILE__, __LINE__);
2493 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2495 return parmDatap[0] + (parmDatap[1] << 8);
2498 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2500 unsigned char *parmDatap;
2502 /* make sure we have enough slots */
2503 if (*smbp->wctp <= slot)
2504 *smbp->wctp = slot+1;
2506 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2507 *parmDatap++ = parmValue & 0xff;
2508 *parmDatap = (parmValue>>8) & 0xff;
2511 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2513 unsigned char *parmDatap;
2515 /* make sure we have enough slots */
2516 if (*smbp->wctp <= slot)
2517 *smbp->wctp = slot+2;
2519 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2520 *parmDatap++ = parmValue & 0xff;
2521 *parmDatap++ = (parmValue>>8) & 0xff;
2522 *parmDatap++ = (parmValue>>16) & 0xff;
2523 *parmDatap = (parmValue>>24) & 0xff;
2526 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2528 unsigned char *parmDatap;
2531 /* make sure we have enough slots */
2532 if (*smbp->wctp <= slot)
2533 *smbp->wctp = slot+4;
2535 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2537 *parmDatap++ = *parmValuep++;
2540 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2542 unsigned char *parmDatap;
2544 /* make sure we have enough slots */
2545 if (*smbp->wctp <= slot) {
2546 if (smbp->oddByte) {
2548 *smbp->wctp = slot+1;
2553 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2554 *parmDatap++ = parmValue & 0xff;
2559 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2560 clientchar_t *inPathp)
2562 clientchar_t *lastSlashp;
2563 clientchar_t *streamp = NULL;
2564 clientchar_t *typep = NULL;
2566 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2567 if (lastComponentp) {
2568 *lastComponentp = lastSlashp;
2572 * If the name contains a stream name and a type
2573 * and the stream name is the nul-string and the
2574 * type is $DATA, then strip "::$DATA" from the
2575 * last component string that is returned.
2577 * Otherwise, return the full path name and allow
2578 * the file name to be rejected because it contains
2581 typep = cm_ClientStrRChr(lastSlashp, L':');
2582 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2584 streamp = cm_ClientStrRChr(lastSlashp, L':');
2585 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2589 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2590 osi_LogSaveClientString(smb_logp,streamp),
2591 osi_LogSaveClientString(smb_logp,typep));
2595 if (inPathp == lastSlashp)
2597 *outPathp++ = *inPathp++;
2606 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2607 char **chainpp, int flags)
2610 afs_uint32 type = *inp++;
2613 * The first byte specifies the type of the input string.
2614 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2618 /* Length Counted */
2619 case 0x1: /* Data Block */
2620 case 0x5: /* Variable Block */
2621 cb = *inp++ << 16 | *inp++;
2624 /* Null-terminated string */
2625 case 0x4: /* ASCII */
2626 case 0x3: /* Pathname */
2627 case 0x2: /* Dialect */
2628 cb = sizeof(pktp->data) - (inp - pktp->data);
2629 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2630 #ifdef DEBUG_UNICODE
2633 cb = sizeof(pktp->data);
2638 return NULL; /* invalid input */
2642 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2643 flags |= SMB_STRF_FORCEASCII;
2646 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2649 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2650 char ** chainpp, int flags)
2655 if (!WANTS_UNICODE(pktp))
2656 flags |= SMB_STRF_FORCEASCII;
2659 cb = sizeof(pktp->data) - (inp - pktp->data);
2660 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2661 #ifdef DEBUG_UNICODE
2664 cb = sizeof(pktp->data);
2666 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2667 flags | SMB_STRF_SRCNULTERM);
2670 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2671 size_t cb, char ** chainpp, int flags)
2674 if (!WANTS_UNICODE(pktp))
2675 flags |= SMB_STRF_FORCEASCII;
2678 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2681 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2682 size_t cch, char ** chainpp, int flags)
2687 if (!WANTS_UNICODE(pktp))
2688 flags |= SMB_STRF_FORCEASCII;
2690 cb = cch * sizeof(wchar_t);
2693 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2697 smb_ParseStringBuf(const unsigned char * bufbase,
2698 cm_space_t ** stringspp,
2699 unsigned char *inp, size_t *pcb_max,
2700 char **chainpp, int flags)
2703 if (!(flags & SMB_STRF_FORCEASCII)) {
2705 cm_space_t * spacep;
2708 if (bufbase && ((inp - bufbase) % 2) != 0) {
2709 inp++; /* unicode strings are always word aligned */
2713 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2715 cch_src = *pcb_max / sizeof(wchar_t);
2719 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2726 spacep = cm_GetSpace();
2727 spacep->nextp = *stringspp;
2728 *stringspp = spacep;
2732 *chainpp = inp + sizeof(wchar_t);
2735 *(spacep->wdata) = 0;
2736 return spacep->wdata;
2739 StringCchCopyNW(spacep->wdata,
2740 lengthof(spacep->wdata),
2741 (const clientchar_t *) inp, cch_src);
2744 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2746 return spacep->wdata;
2750 cm_space_t * spacep;
2753 /* Not using Unicode */
2755 *chainpp = inp + strlen(inp) + 1;
2758 spacep = cm_GetSpace();
2759 spacep->nextp = *stringspp;
2760 *stringspp = spacep;
2762 cchdest = lengthof(spacep->wdata);
2763 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2764 spacep->wdata, cchdest);
2766 return spacep->wdata;
2772 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2774 size_t * plen, int flags)
2780 /* we are only calculating the required size */
2787 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2789 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2790 if (!(flags & SMB_STRF_IGNORENUL))
2791 *plen += sizeof(wchar_t);
2793 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2803 cch_str = cm_ClientStrLen(str);
2804 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2807 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2815 /* if outp != NULL ... */
2817 /* Number of bytes left in the buffer.
2819 If outp lies inside the packet data buffer, we assume that the
2820 buffer is the packet data buffer. Otherwise we assume that the
2821 buffer is sizeof(packet->data).
2824 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2825 align = (int)((outp - pktp->data) % 2);
2826 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2828 align = (int)(((size_t) outp) % 2);
2829 buffersize = (int)sizeof(pktp->data);
2834 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2840 if (*str == _C('\0')) {
2842 if (buffersize < sizeof(wchar_t))
2845 *((wchar_t *) outp) = L'\0';
2846 if (plen && !(flags & SMB_STRF_IGNORENUL))
2847 *plen += sizeof(wchar_t);
2848 return outp + sizeof(wchar_t);
2851 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2853 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2854 osi_LogSaveClientString(smb_logp, str),
2860 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2862 return outp + sizeof(wchar_t) * nchars;
2870 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2873 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2875 return outp + cch_dest;
2879 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2885 tlen = inp[0] + (inp[1]<<8);
2886 inp += 2; /* skip length field */
2889 *chainpp = inp + tlen;
2898 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2902 if (*inp++ != 0x1) return NULL;
2903 tlen = inp[0] + (inp[1]<<8);
2904 inp += 2; /* skip length field */
2907 *chainpp = inp + tlen;
2910 if (lengthp) *lengthp = tlen;
2915 /* format a packet as a response */
2916 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2921 outp = (smb_t *) op;
2923 /* zero the basic structure through the smb_wct field, and zero the data
2924 * size field, assuming that wct stays zero; otherwise, you have to
2925 * explicitly set the data size field, too.
2927 inSmbp = (smb_t *) inp;
2928 memset(outp, 0, sizeof(smb_t)+2);
2934 outp->com = inSmbp->com;
2935 outp->tid = inSmbp->tid;
2936 outp->pid = inSmbp->pid;
2937 outp->uid = inSmbp->uid;
2938 outp->mid = inSmbp->mid;
2939 outp->res[0] = inSmbp->res[0];
2940 outp->res[1] = inSmbp->res[1];
2941 op->inCom = inSmbp->com;
2943 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2944 #ifdef SEND_CANONICAL_PATHNAMES
2945 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2947 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2949 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2950 outp->flg2 |= SMB_FLAGS2_UNICODE;
2953 /* copy fields in generic packet area */
2954 op->wctp = &outp->wct;
2957 /* send a (probably response) packet; vcp tells us to whom to send it.
2958 * we compute the length by looking at wct and bcc fields.
2960 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2970 ncbp = smb_GetNCB();
2974 memset(ncbp, 0, sizeof(NCB));
2976 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2977 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2978 extra += tp[0] + (tp[1]<<8);
2979 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2980 extra += 3; /* wct and length fields */
2982 ncbp->ncb_length = extra; /* bytes to send */
2983 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2984 ncbp->ncb_lana_num = vcp->lana;
2985 ncbp->ncb_command = NCBSEND; /* op means send data */
2986 ncbp->ncb_buffer = (char *) inp;/* packet */
2987 code = Netbios(ncbp);
2990 const char * s = ncb_error_string(code);
2991 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2992 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2994 lock_ObtainMutex(&vcp->mx);
2995 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2996 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2998 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2999 lock_ReleaseMutex(&vcp->mx);
3000 lock_ObtainWrite(&smb_globalLock);
3001 dead_sessions[vcp->session] = TRUE;
3002 lock_ReleaseWrite(&smb_globalLock);
3003 smb_CleanupDeadVC(vcp);
3005 lock_ReleaseMutex(&vcp->mx);
3013 void smb_MapNTError(long code, unsigned long *NTStatusp)
3015 unsigned long NTStatus;
3017 /* map CM_ERROR_* errors to NT 32-bit status codes */
3018 /* NT Status codes are listed in ntstatus.h not winerror.h */
3022 else if (code == CM_ERROR_NOSUCHCELL) {
3023 NTStatus = 0xC0000034L; /* Name not found */
3025 else if (code == CM_ERROR_NOSUCHVOLUME) {
3026 NTStatus = 0xC0000034L; /* Name not found */
3028 else if (code == CM_ERROR_TIMEDOUT) {
3030 NTStatus = 0xC00000CFL; /* Sharing Paused */
3032 /* Do not send Timeout to the SMB redirector.
3033 * It causes the redirector to drop the connection */
3034 NTStatus = 0x00000102L; /* Timeout */
3035 /* do not send Retry to the SMB redirector.
3036 * It believes the error comes from the transport
3037 * layer not from the SMB server. */
3038 NTStatus = 0xC000022DL; /* Retry */
3040 NTStatus = 0xC00000B5L; /* I/O Timeout */
3043 else if (code == CM_ERROR_RETRY) {
3045 NTStatus = 0xC000022DL; /* Retry */
3047 NTStatus = 0xC00000B5L; /* I/O Timeout */
3050 else if (code == CM_ERROR_NOACCESS) {
3051 NTStatus = 0xC0000022L; /* Access denied */
3053 else if (code == CM_ERROR_READONLY) {
3054 NTStatus = 0xC00000A2L; /* Write protected */
3056 else if (code == CM_ERROR_NOSUCHFILE ||
3057 code == CM_ERROR_BPLUS_NOMATCH) {
3058 NTStatus = 0xC0000034L; /* Name not found */
3060 else if (code == CM_ERROR_NOSUCHPATH) {
3061 NTStatus = 0xC000003AL; /* Object path not found */
3063 else if (code == CM_ERROR_TOOBIG) {
3064 NTStatus = 0xC000007BL; /* Invalid image format */
3066 else if (code == CM_ERROR_INVAL) {
3067 NTStatus = 0xC000000DL; /* Invalid parameter */
3069 else if (code == CM_ERROR_BADFD) {
3070 NTStatus = 0xC0000008L; /* Invalid handle */
3072 else if (code == CM_ERROR_BADFDOP) {
3073 NTStatus = 0xC0000022L; /* Access denied */
3075 else if (code == CM_ERROR_UNKNOWN) {
3076 NTStatus = 0xC0000022L; /* Access denied */
3078 else if (code == CM_ERROR_EXISTS) {
3079 NTStatus = 0xC0000035L; /* Object name collision */
3081 else if (code == CM_ERROR_NOTEMPTY) {
3082 NTStatus = 0xC0000101L; /* Directory not empty */
3084 else if (code == CM_ERROR_CROSSDEVLINK) {
3085 NTStatus = 0xC00000D4L; /* Not same device */
3087 else if (code == CM_ERROR_NOTDIR) {
3088 NTStatus = 0xC0000103L; /* Not a directory */
3090 else if (code == CM_ERROR_ISDIR) {
3091 NTStatus = 0xC00000BAL; /* File is a directory */
3093 else if (code == CM_ERROR_BADOP) {
3095 /* I have no idea where this comes from */
3096 NTStatus = 0xC09820FFL; /* SMB no support */
3098 NTStatus = 0xC00000BBL; /* Not supported */
3099 #endif /* COMMENT */
3101 else if (code == CM_ERROR_BADSHARENAME) {
3102 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3104 else if (code == CM_ERROR_NOIPC) {
3106 NTStatus = 0xC0000022L; /* Access Denied */
3108 NTStatus = 0xC000013DL; /* Remote Resources */
3111 else if (code == CM_ERROR_CLOCKSKEW ||
3112 code == RXKADNOAUTH) {
3113 NTStatus = 0xC0000133L; /* Time difference at DC */
3115 else if (code == CM_ERROR_BADTID) {
3116 NTStatus = 0xC0982005L; /* SMB bad TID */
3118 else if (code == CM_ERROR_USESTD) {
3119 NTStatus = 0xC09820FBL; /* SMB use standard */
3121 else if (code == CM_ERROR_QUOTA) {
3122 NTStatus = 0xC0000044L; /* Quota exceeded */
3124 else if (code == CM_ERROR_SPACE) {
3125 NTStatus = 0xC000007FL; /* Disk full */
3127 else if (code == CM_ERROR_ATSYS) {
3128 NTStatus = 0xC0000033L; /* Object name invalid */
3130 else if (code == CM_ERROR_BADNTFILENAME) {
3131 NTStatus = 0xC0000033L; /* Object name invalid */
3133 else if (code == CM_ERROR_WOULDBLOCK) {
3134 NTStatus = 0xC00000D8L; /* Can't wait */
3136 else if (code == CM_ERROR_SHARING_VIOLATION) {
3137 NTStatus = 0xC0000043L; /* Sharing violation */
3139 else if (code == CM_ERROR_LOCK_CONFLICT) {
3140 NTStatus = 0xC0000054L; /* Lock conflict */
3142 else if (code == CM_ERROR_PARTIALWRITE) {
3143 NTStatus = 0xC000007FL; /* Disk full */
3145 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3146 NTStatus = 0xC0000023L; /* Buffer too small */
3148 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3149 NTStatus = 0xC0000035L; /* Object name collision */
3151 else if (code == CM_ERROR_BADPASSWORD) {
3152 NTStatus = 0xC000006DL; /* unknown username or bad password */
3154 else if (code == CM_ERROR_BADLOGONTYPE) {
3155 NTStatus = 0xC000015BL; /* logon type not granted */
3157 else if (code == CM_ERROR_GSSCONTINUE) {
3158 NTStatus = 0xC0000016L; /* more processing required */
3160 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3162 NTStatus = 0xC0000280L; /* reparse point not resolved */
3164 NTStatus = 0xC0000022L; /* Access Denied */
3167 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3168 NTStatus = 0xC0000257L; /* Path Not Covered */
3170 else if (code == CM_ERROR_ALLBUSY) {
3172 NTStatus = 0xC000022DL; /* Retry */
3174 NTStatus = 0xC00000B5L; /* I/O Timeout */
3177 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3178 NTStatus = 0xC000003AL; /* Path not found */
3180 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3181 NTStatus = 0xC0000322L; /* No Kerberos key */
3183 else if (code == CM_ERROR_BAD_LEVEL) {
3184 NTStatus = 0xC0000148L; /* Invalid Level */
3186 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3187 NTStatus = 0xC000007EL; /* Range Not Locked */
3189 else if (code == CM_ERROR_NOSUCHDEVICE) {
3190 NTStatus = 0xC000000EL; /* No Such Device */
3192 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3193 NTStatus = 0xC0000055L; /* Lock Not Granted */
3195 else if (code == ENOMEM) {
3196 NTStatus = 0xC0000017L; /* Out of Memory */
3198 else if (code == CM_ERROR_RPC_MOREDATA) {
3199 NTStatus = 0x80000005L; /* Buffer overflow */
3202 NTStatus = 0xC0982001L; /* SMB non-specific error */
3205 *NTStatusp = NTStatus;
3206 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3210 * NTSTATUS <-> Win32 Error Translation
3211 * http://support.microsoft.com/kb/113996
3213 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3215 unsigned long Win32E;
3217 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3221 else if (code == CM_ERROR_NOSUCHCELL) {
3222 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3224 else if (code == CM_ERROR_NOSUCHVOLUME) {
3225 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3227 else if (code == CM_ERROR_TIMEDOUT) {
3229 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3231 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3234 else if (code == CM_ERROR_RETRY) {
3235 Win32E = ERROR_RETRY; /* Retry */
3237 else if (code == CM_ERROR_NOACCESS) {
3238 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3240 else if (code == CM_ERROR_READONLY) {
3241 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3243 else if (code == CM_ERROR_NOSUCHFILE ||
3244 code == CM_ERROR_BPLUS_NOMATCH) {
3245 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3247 else if (code == CM_ERROR_NOSUCHPATH) {
3248 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3250 else if (code == CM_ERROR_TOOBIG) {
3251 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3253 else if (code == CM_ERROR_INVAL) {
3254 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3256 else if (code == CM_ERROR_BADFD) {
3257 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3259 else if (code == CM_ERROR_BADFDOP) {
3260 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3262 else if (code == CM_ERROR_UNKNOWN) {
3263 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3265 else if (code == CM_ERROR_EXISTS) {
3266 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3268 else if (code == CM_ERROR_NOTEMPTY) {
3269 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3271 else if (code == CM_ERROR_CROSSDEVLINK) {
3272 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3274 else if (code == CM_ERROR_NOTDIR) {
3275 Win32E = ERROR_DIRECTORY; /* Not a directory */
3277 else if (code == CM_ERROR_ISDIR) {
3278 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3280 else if (code == CM_ERROR_BADOP) {
3281 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3283 else if (code == CM_ERROR_BADSHARENAME) {
3284 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3286 else if (code == CM_ERROR_NOIPC) {
3288 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3290 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3293 else if (code == CM_ERROR_CLOCKSKEW ||
3294 code == RXKADNOAUTH) {
3295 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3297 else if (code == CM_ERROR_BADTID) {
3298 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3300 else if (code == CM_ERROR_USESTD) {
3301 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3303 else if (code == CM_ERROR_QUOTA) {
3304 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3306 else if (code == CM_ERROR_SPACE) {
3307 Win32E = ERROR_DISK_FULL; /* Disk full */
3309 else if (code == CM_ERROR_ATSYS) {
3310 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3312 else if (code == CM_ERROR_BADNTFILENAME) {
3313 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3315 else if (code == CM_ERROR_WOULDBLOCK) {
3316 Win32E = WAIT_TIMEOUT; /* Can't wait */
3318 else if (code == CM_ERROR_SHARING_VIOLATION) {
3319 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3321 else if (code == CM_ERROR_LOCK_CONFLICT) {
3322 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3324 else if (code == CM_ERROR_PARTIALWRITE) {
3325 Win32E = ERROR_DISK_FULL; /* Disk full */
3327 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3328 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3330 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3331 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3333 else if (code == CM_ERROR_BADPASSWORD) {
3334 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3336 else if (code == CM_ERROR_BADLOGONTYPE) {
3337 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3339 else if (code == CM_ERROR_GSSCONTINUE) {
3340 Win32E = ERROR_MORE_DATA; /* more processing required */
3342 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3344 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3346 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3349 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3350 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3352 else if (code == CM_ERROR_ALLBUSY) {
3353 Win32E = ERROR_RETRY; /* Retry */
3355 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3356 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3358 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3359 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3361 else if (code == CM_ERROR_BAD_LEVEL) {
3362 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3364 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3365 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3367 else if (code == CM_ERROR_NOSUCHDEVICE) {
3368 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3370 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3371 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3373 else if (code == ENOMEM) {
3374 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3376 else if (code == CM_ERROR_RPC_MOREDATA) {
3377 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3380 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3384 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3387 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3388 unsigned char *classp)
3390 unsigned char class;
3391 unsigned short error;
3393 /* map CM_ERROR_* errors to SMB errors */
3394 if (code == CM_ERROR_NOSUCHCELL) {
3396 error = 3; /* bad path */
3398 else if (code == CM_ERROR_NOSUCHVOLUME) {
3400 error = 3; /* bad path */
3402 else if (code == CM_ERROR_TIMEDOUT) {
3404 error = 81; /* server is paused */
3406 else if (code == CM_ERROR_RETRY) {
3407 class = 2; /* shouldn't happen */
3410 else if (code == CM_ERROR_NOACCESS) {
3412 error = 4; /* bad access */
3414 else if (code == CM_ERROR_READONLY) {
3416 error = 19; /* read only */
3418 else if (code == CM_ERROR_NOSUCHFILE ||
3419 code == CM_ERROR_BPLUS_NOMATCH) {
3421 error = 2; /* ENOENT! */
3423 else if (code == CM_ERROR_NOSUCHPATH) {
3425 error = 3; /* Bad path */
3427 else if (code == CM_ERROR_TOOBIG) {
3429 error = 11; /* bad format */
3431 else if (code == CM_ERROR_INVAL) {
3432 class = 2; /* server non-specific error code */
3435 else if (code == CM_ERROR_BADFD) {
3437 error = 6; /* invalid file handle */
3439 else if (code == CM_ERROR_BADFDOP) {
3440 class = 1; /* invalid op on FD */
3443 else if (code == CM_ERROR_EXISTS) {
3445 error = 80; /* file already exists */
3447 else if (code == CM_ERROR_NOTEMPTY) {
3449 error = 5; /* delete directory not empty */
3451 else if (code == CM_ERROR_CROSSDEVLINK) {
3453 error = 17; /* EXDEV */
3455 else if (code == CM_ERROR_NOTDIR) {
3456 class = 1; /* bad path */
3459 else if (code == CM_ERROR_ISDIR) {
3460 class = 1; /* access denied; DOS doesn't have a good match */
3463 else if (code == CM_ERROR_BADOP) {
3467 else if (code == CM_ERROR_BADSHARENAME) {
3471 else if (code == CM_ERROR_NOIPC) {
3473 error = 4; /* bad access */
3475 else if (code == CM_ERROR_CLOCKSKEW) {
3476 class = 1; /* invalid function */
3479 else if (code == CM_ERROR_BADTID) {
3483 else if (code == CM_ERROR_USESTD) {
3487 else if (code == CM_ERROR_REMOTECONN) {
3491 else if (code == CM_ERROR_QUOTA) {
3492 if (vcp->flags & SMB_VCFLAG_USEV3) {
3494 error = 39; /* disk full */
3498 error = 5; /* access denied */
3501 else if (code == CM_ERROR_SPACE) {
3502 if (vcp->flags & SMB_VCFLAG_USEV3) {
3504 error = 39; /* disk full */
3508 error = 5; /* access denied */
3511 else if (code == CM_ERROR_PARTIALWRITE) {
3513 error = 39; /* disk full */
3515 else if (code == CM_ERROR_ATSYS) {
3517 error = 2; /* ENOENT */
3519 else if (code == CM_ERROR_WOULDBLOCK) {
3521 error = 33; /* lock conflict */
3523 else if (code == CM_ERROR_LOCK_CONFLICT) {
3525 error = 33; /* lock conflict */
3527 else if (code == CM_ERROR_SHARING_VIOLATION) {
3529 error = 33; /* lock conflict */
3531 else if (code == CM_ERROR_NOFILES) {
3533 error = 18; /* no files in search */
3535 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3537 error = 183; /* Samba uses this */
3539 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3540 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3542 error = 2; /* bad password */
3544 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3546 error = 3; /* bad path */
3555 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3558 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3560 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3561 return CM_ERROR_BADOP;
3565 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3567 unsigned short EchoCount, i;
3568 char *data, *outdata;
3571 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3573 for (i=1; i<=EchoCount; i++) {
3574 data = smb_GetSMBData(inp, &dataSize);
3575 smb_SetSMBParm(outp, 0, i);
3576 smb_SetSMBDataLength(outp, dataSize);
3577 outdata = smb_GetSMBData(outp, NULL);
3578 memcpy(outdata, data, dataSize);
3579 smb_SendPacket(vcp, outp);
3585 /* SMB_COM_READ_RAW */
3586 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3589 long count, minCount, finalCount;
3593 smb_t *smbp = (smb_t*) inp;
3595 cm_user_t *userp = NULL;
3598 char *rawBuf = NULL;
3603 fd = smb_GetSMBParm(inp, 0);
3604 count = smb_GetSMBParm(inp, 3);
3605 minCount = smb_GetSMBParm(inp, 4);
3606 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3608 if (*inp->wctp == 10) {
3609 /* we were sent a request with 64-bit file offsets */
3610 #ifdef AFS_LARGEFILES
3611 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3613 if (LargeIntegerLessThanZero(offset)) {
3614 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3618 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3619 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3622 offset.HighPart = 0;
3626 /* we were sent a request with 32-bit file offsets */
3627 offset.HighPart = 0;
3630 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3631 fd, offset.HighPart, offset.LowPart, count);
3633 fidp = smb_FindFID(vcp, fd, 0);
3635 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3639 lock_ObtainMutex(&fidp->mx);
3641 lock_ReleaseMutex(&fidp->mx);
3642 smb_ReleaseFID(fidp);
3643 return CM_ERROR_BADFD;
3646 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3647 lock_ReleaseMutex(&fidp->mx);
3648 smb_CloseFID(vcp, fidp, NULL, 0);
3649 code = CM_ERROR_NOSUCHFILE;
3655 LARGE_INTEGER LOffset, LLength;
3658 key = cm_GenerateKey(vcp->vcID, pid, fd);
3660 LOffset.HighPart = offset.HighPart;
3661 LOffset.LowPart = offset.LowPart;
3662 LLength.HighPart = 0;
3663 LLength.LowPart = count;
3665 lock_ObtainWrite(&fidp->scp->rw);
3666 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3667 lock_ReleaseWrite(&fidp->scp->rw);
3670 lock_ReleaseMutex(&fidp->mx);
3674 lock_ObtainMutex(&smb_RawBufLock);
3676 /* Get a raw buf, from head of list */
3677 rawBuf = smb_RawBufs;
3678 smb_RawBufs = *(char **)smb_RawBufs;
3680 lock_ReleaseMutex(&smb_RawBufLock);
3682 lock_ReleaseMutex(&fidp->mx);
3686 if (fidp->flags & SMB_FID_IOCTL)
3688 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3690 /* Give back raw buffer */
3691 lock_ObtainMutex(&smb_RawBufLock);
3692 *((char **) rawBuf) = smb_RawBufs;
3694 smb_RawBufs = rawBuf;
3695 lock_ReleaseMutex(&smb_RawBufLock);
3698 lock_ReleaseMutex(&fidp->mx);
3699 smb_ReleaseFID(fidp);
3702 lock_ReleaseMutex(&fidp->mx);
3704 userp = smb_GetUserFromVCP(vcp, inp);
3706 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3712 cm_ReleaseUser(userp);
3715 smb_ReleaseFID(fidp);
3719 memset(ncbp, 0, sizeof(NCB));
3721 ncbp->ncb_length = (unsigned short) finalCount;
3722 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3723 ncbp->ncb_lana_num = vcp->lana;
3724 ncbp->ncb_command = NCBSEND;
3725 ncbp->ncb_buffer = rawBuf;
3727 code = Netbios(ncbp);
3729 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3732 /* Give back raw buffer */
3733 lock_ObtainMutex(&smb_RawBufLock);
3734 *((char **) rawBuf) = smb_RawBufs;
3736 smb_RawBufs = rawBuf;
3737 lock_ReleaseMutex(&smb_RawBufLock);
3743 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3745 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3750 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3752 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3757 /* SMB_COM_NEGOTIATE */
3758 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3765 int VistaProtoIndex;
3766 int protoIndex; /* index we're using */
3771 char protocol_array[10][1024]; /* protocol signature of the client */
3772 int caps; /* capabilities */
3775 TIME_ZONE_INFORMATION tzi;
3777 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3780 namep = smb_GetSMBData(inp, &dbytes);
3783 coreProtoIndex = -1; /* not found */
3786 VistaProtoIndex = -1;
3787 while(namex < dbytes) {
3788 osi_Log1(smb_logp, "Protocol %s",
3789 osi_LogSaveString(smb_logp, namep+1));
3790 strcpy(protocol_array[tcounter], namep+1);
3792 /* namep points at the first protocol, or really, a 0x02
3793 * byte preceding the null-terminated ASCII name.
3795 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3796 coreProtoIndex = tcounter;
3798 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3799 v3ProtoIndex = tcounter;
3801 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3802 NTProtoIndex = tcounter;
3804 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3805 VistaProtoIndex = tcounter;
3808 /* compute size of protocol entry */
3809 entryLength = (int)strlen(namep+1);
3810 entryLength += 2; /* 0x02 bytes and null termination */
3812 /* advance over this protocol entry */
3813 namex += entryLength;
3814 namep += entryLength;
3815 tcounter++; /* which proto entry we're looking at */
3818 lock_ObtainMutex(&vcp->mx);
3820 if (VistaProtoIndex != -1) {
3821 protoIndex = VistaProtoIndex;
3822 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3825 if (NTProtoIndex != -1) {
3826 protoIndex = NTProtoIndex;
3827 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3829 else if (v3ProtoIndex != -1) {
3830 protoIndex = v3ProtoIndex;
3831 vcp->flags |= SMB_VCFLAG_USEV3;
3833 else if (coreProtoIndex != -1) {
3834 protoIndex = coreProtoIndex;
3835 vcp->flags |= SMB_VCFLAG_USECORE;
3837 else protoIndex = -1;
3838 lock_ReleaseMutex(&vcp->mx);
3840 if (protoIndex == -1)
3841 return CM_ERROR_INVAL;
3842 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3843 smb_SetSMBParm(outp, 0, protoIndex);
3844 if (smb_authType != SMB_AUTH_NONE) {
3845 smb_SetSMBParmByte(outp, 1,
3846 NEGOTIATE_SECURITY_USER_LEVEL |
3847 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3849 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3851 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3852 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3853 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3854 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3855 /* The session key is not a well documented field however most clients
3856 * will echo back the session key to the server. Currently we are using
3857 * the same value for all sessions. We should generate a random value
3858 * and store it into the vcp
3860 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3861 smb_SetSMBParm(outp, 8, 1);
3863 * Tried changing the capabilities to support for W2K - defect 117695
3864 * Maybe something else needs to be changed here?
3868 smb_SetSMBParmLong(outp, 9, 0x43fd);
3870 smb_SetSMBParmLong(outp, 9, 0x251);
3873 * 32-bit error codes *
3879 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3881 NTNEGOTIATE_CAPABILITY_DFS |
3883 #ifdef AFS_LARGEFILES
3884 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3886 NTNEGOTIATE_CAPABILITY_NTFIND |
3887 NTNEGOTIATE_CAPABILITY_RAWMODE |
3888 NTNEGOTIATE_CAPABILITY_NTSMB;
3890 if ( smb_authType == SMB_AUTH_EXTENDED )
3891 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3894 if ( smb_UseUnicode ) {
3895 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3899 smb_SetSMBParmLong(outp, 9, caps);
3901 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3902 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3903 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3905 GetTimeZoneInformation(&tzi);
3906 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3908 if (smb_authType == SMB_AUTH_NTLM) {
3909 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3910 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3911 /* paste in encryption key */
3912 datap = smb_GetSMBData(outp, NULL);
3913 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3914 /* and the faux domain name */
3915 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3916 datap + MSV1_0_CHALLENGE_LENGTH,
3917 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3918 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3922 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3924 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3926 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3928 datap = smb_GetSMBData(outp, NULL);
3929 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3932 datap += sizeof(smb_ServerGUID);
3933 memcpy(datap, secBlob, secBlobLength);
3937 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3938 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3941 else if (v3ProtoIndex != -1) {
3942 smb_SetSMBParm(outp, 0, protoIndex);
3944 /* NOTE: Extended authentication cannot be negotiated with v3
3945 * therefore we fail over to NTLM
3947 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3948 smb_SetSMBParm(outp, 1,
3949 NEGOTIATE_SECURITY_USER_LEVEL |
3950 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3952 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3954 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3955 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3956 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3957 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3958 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3959 smb_SetSMBParm(outp, 7, 1);
3961 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3962 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3963 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3965 GetTimeZoneInformation(&tzi);
3966 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3968 /* NOTE: Extended authentication cannot be negotiated with v3
3969 * therefore we fail over to NTLM
3971 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3972 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3973 smb_SetSMBParm(outp, 12, 0); /* resvd */
3974 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3975 datap = smb_GetSMBData(outp, NULL);
3976 /* paste in a new encryption key */
3977 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3978 /* and the faux domain name */
3979 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3980 datap + MSV1_0_CHALLENGE_LENGTH,
3981 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3983 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3984 smb_SetSMBParm(outp, 12, 0); /* resvd */
3985 smb_SetSMBDataLength(outp, 0);
3988 else if (coreProtoIndex != -1) { /* not really supported anymore */
3989 smb_SetSMBParm(outp, 0, protoIndex);
3990 smb_SetSMBDataLength(outp, 0);
3995 void smb_CheckVCs(void)
3997 smb_vc_t * vcp, *nextp;
3998 smb_packet_t * outp = smb_GetPacket();
4001 lock_ObtainWrite(&smb_rctLock);
4002 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4004 if (vcp->magic != SMB_VC_MAGIC)
4005 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4006 __FILE__, __LINE__);
4008 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4010 smb_HoldVCNoLock(vcp);
4013 * obtain a reference to 'nextp' now because we drop the
4014 * smb_rctLock later and the list contents could change
4015 * or 'vcp' could be destroyed when released.
4019 smb_HoldVCNoLock(nextp);
4021 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4022 smb_ReleaseVCNoLock(vcp);
4026 smb_FormatResponsePacket(vcp, NULL, outp);
4027 smbp = (smb_t *)outp;
4028 outp->inCom = smbp->com = 0x2b /* Echo */;
4036 smb_SetSMBParm(outp, 0, 0);
4037 smb_SetSMBDataLength(outp, 0);
4038 lock_ReleaseWrite(&smb_rctLock);
4040 smb_SendPacket(vcp, outp);
4042 lock_ObtainWrite(&smb_rctLock);
4043 smb_ReleaseVCNoLock(vcp);
4045 lock_ReleaseWrite(&smb_rctLock);
4046 smb_FreePacket(outp);
4049 void smb_Daemon(void *parmp)
4051 afs_uint32 count = 0;
4052 smb_username_t **unpp;
4055 while(smbShutdownFlag == 0) {
4059 if (smbShutdownFlag == 1)
4062 if ((count % 72) == 0) { /* every five minutes */
4064 time_t old_localZero = smb_localZero;
4066 /* Initialize smb_localZero */
4067 myTime.tm_isdst = -1; /* compute whether on DST or not */
4068 myTime.tm_year = 70;
4074 smb_localZero = mktime(&myTime);
4076 #ifdef AFS_FREELANCE
4077 if ( smb_localZero != old_localZero )
4078 cm_noteLocalMountPointChange();
4084 /* GC smb_username_t objects that will no longer be used */
4086 lock_ObtainWrite(&smb_rctLock);
4087 for ( unpp=&usernamesp; *unpp; ) {
4089 smb_username_t *unp;
4091 lock_ObtainMutex(&(*unpp)->mx);
4092 if ( (*unpp)->refCount > 0 ||
4093 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4094 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4096 else if (!smb_LogoffTokenTransfer ||
4097 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4099 lock_ReleaseMutex(&(*unpp)->mx);
4107 lock_FinalizeMutex(&unp->mx);
4113 cm_ReleaseUser(userp);
4115 unpp = &(*unpp)->nextp;
4118 lock_ReleaseWrite(&smb_rctLock);
4120 /* XXX GC dir search entries */
4124 void smb_WaitingLocksDaemon()
4126 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4127 smb_waitingLock_t *wl, *wlNext;
4130 smb_packet_t *inp, *outp;
4134 while (smbShutdownFlag == 0) {
4135 lock_ObtainWrite(&smb_globalLock);
4136 nwlRequest = smb_allWaitingLocks;
4137 if (nwlRequest == NULL) {
4138 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4143 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4150 lock_ObtainWrite(&smb_globalLock);
4152 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4154 wlRequest = nwlRequest;
4155 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4156 lock_ReleaseWrite(&smb_globalLock);
4160 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4161 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4164 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4165 code = CM_ERROR_LOCK_NOT_GRANTED;
4169 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4171 /* wl->state is either _DONE or _WAITING. _ERROR
4172 would no longer be on the queue. */
4173 code = cm_RetryLock( wl->lockp,
4174 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4177 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4178 } else if (code != CM_ERROR_WOULDBLOCK) {
4179 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4184 if (code == CM_ERROR_WOULDBLOCK) {
4187 if (wlRequest->msTimeout != 0xffffffff
4188 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4200 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4203 scp = wlRequest->scp;
4204 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4208 lock_ObtainWrite(&scp->rw);
4210 for (wl = wlRequest->locks; wl; wl = wlNext) {
4211 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4213 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4214 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4215 wl->LLength, wl->key, 0, NULL, &req);
4217 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4222 lock_ReleaseWrite(&scp->rw);
4226 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4229 for (wl = wlRequest->locks; wl; wl = wlNext) {
4230 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4231 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4236 vcp = wlRequest->vcp;
4237 inp = wlRequest->inp;
4238 outp = wlRequest->outp;
4239 ncbp = smb_GetNCB();
4240 ncbp->ncb_length = inp->ncb_length;
4241 inp->spacep = cm_GetSpace();
4243 /* Remove waitingLock from list */
4244 lock_ObtainWrite(&smb_globalLock);
4245 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4247 lock_ReleaseWrite(&smb_globalLock);
4249 /* Resume packet processing */
4251 smb_SetSMBDataLength(outp, 0);
4252 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4253 outp->resumeCode = code;
4255 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4258 cm_FreeSpace(inp->spacep);
4259 smb_FreePacket(inp);
4260 smb_FreePacket(outp);
4262 cm_ReleaseSCache(wlRequest->scp);
4265 } while (nwlRequest && smbShutdownFlag == 0);
4270 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4272 osi_Log0(smb_logp, "SMB receive get disk attributes");
4274 smb_SetSMBParm(outp, 0, 32000);
4275 smb_SetSMBParm(outp, 1, 64);
4276 smb_SetSMBParm(outp, 2, 1024);
4277 smb_SetSMBParm(outp, 3, 30000);
4278 smb_SetSMBParm(outp, 4, 0);
4279 smb_SetSMBDataLength(outp, 0);
4283 /* SMB_COM_TREE_CONNECT */
4284 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4288 unsigned short newTid;
4289 clientchar_t shareName[AFSPATHMAX];
4290 clientchar_t *sharePath;
4293 clientchar_t *pathp;
4296 osi_Log0(smb_logp, "SMB receive tree connect");
4298 /* parse input parameters */
4301 tbp = smb_GetSMBData(inp, NULL);
4302 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4304 return CM_ERROR_BADSMB;
4306 tp = cm_ClientStrRChr(pathp, '\\');
4308 return CM_ERROR_BADSMB;
4309 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4311 lock_ObtainMutex(&vcp->mx);
4312 newTid = vcp->tidCounter++;
4313 lock_ReleaseMutex(&vcp->mx);
4315 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4316 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4318 return CM_ERROR_BADSMB;
4319 userp = smb_GetUserFromUID(uidp);
4320 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4321 smb_ReleaseUID(uidp);
4323 smb_ReleaseTID(tidp, FALSE);
4324 return CM_ERROR_BADSHARENAME;
4326 lock_ObtainMutex(&tidp->mx);
4327 tidp->userp = userp;
4328 tidp->pathname = sharePath;
4329 lock_ReleaseMutex(&tidp->mx);
4330 smb_ReleaseTID(tidp, FALSE);
4332 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4333 smb_SetSMBParm(rsp, 1, newTid);
4334 smb_SetSMBDataLength(rsp, 0);
4336 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4340 /* set maskp to the mask part of the incoming path.
4341 * Mask is 11 bytes long (8.3 with the dot elided).
4342 * Returns true if succeeds with a valid name, otherwise it does
4343 * its best, but returns false.
4345 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4353 /* starts off valid */
4356 /* mask starts out all blanks */
4357 memset(maskp, ' ', 11);
4360 /* find last backslash, or use whole thing if there is none */
4361 tp = cm_ClientStrRChr(pathp, '\\');
4365 tp++; /* skip slash */
4369 /* names starting with a dot are illegal */
4377 if (tc == '.' || tc == '"')
4385 /* if we get here, tp point after the dot */
4386 up = maskp+8; /* ext goes here */
4393 if (tc == '.' || tc == '"')
4396 /* copy extension if not too long */
4406 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4408 clientchar_t umask[11];
4416 /* XXX redo this, calling cm_MatchMask with a converted mask */
4418 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4422 /* otherwise, we have a valid 8.3 name; see if we have a match,
4423 * treating '?' as a wildcard in maskp (but not in the file name).
4425 tp1 = umask; /* real name, in mask format */
4426 tp2 = maskp; /* mask, in mask format */
4427 for(i=0; i<11; i++) {
4428 tc1 = *tp1++; /* clientchar_t from real name */
4429 tc2 = *tp2++; /* clientchar_t from mask */
4430 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4431 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4434 if (tc2 == '?' && tc1 != ' ')
4441 /* we got a match */
4445 clientchar_t *smb_FindMask(clientchar_t *pathp)
4449 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4452 return tp+1; /* skip the slash */
4454 return pathp; /* no slash, return the entire path */
4457 /* SMB_COM_SEARCH for a volume label
4459 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4460 dispatch function.) */
4461 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4463 clientchar_t *pathp;
4465 clientchar_t mask[12];
4466 unsigned char *statBlockp;
4467 unsigned char initStatBlock[21];
4470 osi_Log0(smb_logp, "SMB receive search volume");
4472 /* pull pathname and stat block out of request */
4473 tp = smb_GetSMBData(inp, NULL);
4474 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4475 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4477 return CM_ERROR_BADSMB;
4478 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4479 osi_assertx(statBlockp != NULL, "null statBlock");
4481 statBlockp = initStatBlock;
4485 /* for returning to caller */
4486 smb_Get8Dot3MaskFromPath(mask, pathp);
4488 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4489 tp = smb_GetSMBData(outp, NULL);
4491 *tp++ = 43; /* bytes in a dir entry */
4492 *tp++ = 0; /* high byte in counter */
4494 /* now marshall the dir entry, starting with the search status */
4495 *tp++ = statBlockp[0]; /* Reserved */
4496 memcpy(tp, mask, 11); tp += 11; /* FileName */
4498 /* now pass back server use info, with 1st byte non-zero */
4500 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4502 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4504 *tp++ = 0x8; /* attribute: volume */
4514 /* 4 byte file size */
4520 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4523 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4524 memset(tp, ' ', 13);
4527 /* set the length of the data part of the packet to 43 + 3, for the dir
4528 * entry plus the 5 and the length fields.
4530 smb_SetSMBDataLength(outp, 46);
4535 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4536 clientchar_t * tidPathp, clientchar_t * relPathp,
4537 cm_user_t *userp, cm_req_t *reqp)
4545 smb_dirListPatch_t *patchp;
4546 smb_dirListPatch_t *npatchp;
4547 clientchar_t path[AFSPATHMAX];
4549 afs_int32 mustFake = 0;
4551 code = cm_FindACLCache(dscp, userp, &rights);
4553 lock_ObtainWrite(&dscp->rw);
4554 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4555 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4556 lock_ReleaseWrite(&dscp->rw);
4557 if (code == CM_ERROR_NOACCESS) {
4565 if (!mustFake) { /* Bulk Stat */
4567 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4569 memset(bsp, 0, sizeof(cm_bulkStat_t));
4571 for (patchp = *dirPatchespp, count=0;
4573 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4574 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4578 if (lock_TryWrite(&tscp->rw)) {
4579 /* we have an entry that we can look at */
4580 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4581 /* we have a callback on it. Don't bother
4582 * fetching this stat entry, since we're happy
4583 * with the info we have.
4585 lock_ReleaseWrite(&tscp->rw);
4586 cm_ReleaseSCache(tscp);
4589 lock_ReleaseWrite(&tscp->rw);
4591 cm_ReleaseSCache(tscp);
4595 bsp->fids[i].Volume = patchp->fid.volume;
4596 bsp->fids[i].Vnode = patchp->fid.vnode;
4597 bsp->fids[i].Unique = patchp->fid.unique;
4599 if (bsp->counter == AFSCBMAX) {
4600 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4601 memset(bsp, 0, sizeof(cm_bulkStat_t));
4605 if (bsp->counter > 0)
4606 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4611 for (patchp = *dirPatchespp; patchp; patchp =
4612 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4614 dptr = patchp->dptr;
4616 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4617 relPathp ? relPathp : _C(""), patchp->dep->name);
4618 reqp->relPathp = path;
4619 reqp->tidPathp = tidPathp;
4621 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4622 reqp->relPathp = reqp->tidPathp = NULL;
4625 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4626 *dptr++ = SMB_ATTR_HIDDEN;
4629 lock_ObtainWrite(&scp->rw);
4630 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4631 lock_ReleaseWrite(&scp->rw);
4633 /* set the attribute */
4634 switch (scp->fileType) {
4635 case CM_SCACHETYPE_DIRECTORY:
4636 case CM_SCACHETYPE_MOUNTPOINT:
4637 case CM_SCACHETYPE_INVALID:
4638 attr = SMB_ATTR_DIRECTORY;
4640 case CM_SCACHETYPE_SYMLINK:
4641 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4642 attr = SMB_ATTR_DIRECTORY;
4644 attr = SMB_ATTR_NORMAL;
4647 /* if we get here we either have a normal file
4648 * or we have a file for which we have never
4649 * received status info. In this case, we can
4650 * check the even/odd value of the entry's vnode.
4651 * odd means it is to be treated as a directory
4652 * and even means it is to be treated as a file.
4654 if (mustFake && (scp->fid.vnode & 0x1))
4655 attr = SMB_ATTR_DIRECTORY;
4657 attr = SMB_ATTR_NORMAL;
4661 /* 1969-12-31 23:59:58 +00*/
4662 dosTime = 0xEBBFBF7D;
4665 shortTemp = (unsigned short) (dosTime & 0xffff);
4666 *((u_short *)dptr) = shortTemp;
4669 /* and copy out date */
4670 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4671 *((u_short *)dptr) = shortTemp;
4674 /* copy out file length */
4675 *((u_long *)dptr) = 0;
4678 lock_ConvertWToR(&scp->rw);
4679 attr = smb_Attributes(scp);
4680 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4681 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4682 attr |= SMB_ATTR_HIDDEN;
4686 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4689 shortTemp = (unsigned short) (dosTime & 0xffff);
4690 *((u_short *)dptr) = shortTemp;
4693 /* and copy out date */
4694 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4695 *((u_short *)dptr) = shortTemp;
4698 /* copy out file length */
4699 *((u_long *)dptr) = scp->length.LowPart;
4701 lock_ReleaseRead(&scp->rw);
4703 cm_ReleaseSCache(scp);
4706 /* now free the patches */
4707 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4708 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4712 /* and mark the list as empty */
4713 *dirPatchespp = NULL;
4719 /* SMB_COM_SEARCH */
4720 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4726 clientchar_t *pathp;
4727 cm_dirEntry_t *dep = 0;
4729 smb_dirListPatch_t *dirListPatchesp;
4730 smb_dirListPatch_t *curPatchp;
4734 osi_hyper_t dirLength;
4735 osi_hyper_t bufferOffset;
4736 osi_hyper_t curOffset;
4738 unsigned char *inCookiep;
4739 smb_dirSearch_t *dsp;
4743 unsigned long clientCookie;
4744 cm_pageHeader_t *pageHeaderp;
4745 cm_user_t *userp = NULL;
4747 clientchar_t mask[12];
4749 long nextEntryCookie;
4750 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4751 char resByte; /* reserved byte from the cookie */
4752 char *op; /* output data ptr */
4753 char *origOp; /* original value of op */
4754 cm_space_t *spacep; /* for pathname buffer */
4758 clientchar_t *tidPathp = 0;
4765 maxCount = smb_GetSMBParm(inp, 0);
4767 dirListPatchesp = NULL;
4769 caseFold = CM_FLAG_CASEFOLD;
4771 tp = smb_GetSMBData(inp, NULL);
4772 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4773 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4775 return CM_ERROR_BADSMB;
4777 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4779 return CM_ERROR_BADSMB;
4781 /* We can handle long names */
4782 if (vcp->flags & SMB_VCFLAG_USENT)
4783 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4785 /* make sure we got a whole search status */
4786 if (dataLength < 21) {
4787 nextCookie = 0; /* start at the beginning of the dir */
4790 attribute = smb_GetSMBParm(inp, 1);
4792 /* handle volume info in another function */
4793 if (attribute & 0x8)
4794 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4796 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4797 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4799 if (*pathp == 0) { /* null pathp, treat as root dir */
4800 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4801 return CM_ERROR_NOFILES;
4805 dsp = smb_NewDirSearch(0);
4806 dsp->attribute = attribute;
4807 smb_Get8Dot3MaskFromPath(mask, pathp);
4808 memcpy(dsp->mask, mask, 12);
4810 /* track if this is likely to match a lot of entries */
4811 if (smb_Is8Dot3StarMask(mask))
4816 /* pull the next cookie value out of the search status block */
4817 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4818 + (inCookiep[16]<<24);
4819 dsp = smb_FindDirSearch(inCookiep[12]);
4821 /* can't find dir search status; fatal error */
4822 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4823 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4824 return CM_ERROR_BADFD;
4826 attribute = dsp->attribute;
4827 resByte = inCookiep[0];
4829 /* copy out client cookie, in host byte order. Don't bother
4830 * interpreting it, since we're just passing it through, anyway.
4832 memcpy(&clientCookie, &inCookiep[17], 4);
4834 memcpy(mask, dsp->mask, 12);
4836 /* assume we're doing a star match if it has continued for more
4842 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4843 nextCookie, dsp->cookie, attribute);
4845 userp = smb_GetUserFromVCP(vcp, inp);
4847 /* try to get the vnode for the path name next */
4848 lock_ObtainMutex(&dsp->mx);
4851 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4855 spacep = inp->spacep;
4856 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4857 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4859 lock_ReleaseMutex(&dsp->mx);
4860 cm_ReleaseUser(userp);
4861 smb_DeleteDirSearch(dsp);
4862 smb_ReleaseDirSearch(dsp);
4863 return CM_ERROR_NOFILES;
4865 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4866 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4868 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4869 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4872 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4875 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4876 cm_ReleaseSCache(scp);
4877 lock_ReleaseMutex(&dsp->mx);
4878 cm_ReleaseUser(userp);
4879 smb_DeleteDirSearch(dsp);
4880 smb_ReleaseDirSearch(dsp);
4881 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4882 return CM_ERROR_PATH_NOT_COVERED;
4884 return CM_ERROR_NOSUCHPATH;
4886 #endif /* DFS_SUPPORT */
4889 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4890 /* we need one hold for the entry we just stored into,
4891 * and one for our own processing. When we're done with this
4892 * function, we'll drop the one for our own processing.
4893 * We held it once from the namei call, and so we do another hold
4897 lock_ObtainWrite(&scp->rw);
4898 dsp->flags |= SMB_DIRSEARCH_BULKST;
4899 lock_ReleaseWrite(&scp->rw);
4902 lock_ReleaseMutex(&dsp->mx);
4904 cm_ReleaseUser(userp);
4905 smb_DeleteDirSearch(dsp);
4906 smb_ReleaseDirSearch(dsp);
4910 /* reserves space for parameter; we'll adjust it again later to the
4911 * real count of the # of entries we returned once we've actually
4912 * assembled the directory listing.
4914 smb_SetSMBParm(outp, 0, 0);
4916 /* get the directory size */
4917 lock_ObtainWrite(&scp->rw);
4918 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4919 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4921 lock_ReleaseWrite(&scp->rw);
4922 cm_ReleaseSCache(scp);
4923 cm_ReleaseUser(userp);
4924 smb_DeleteDirSearch(dsp);
4925 smb_ReleaseDirSearch(dsp);
4929 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4931 dirLength = scp->length;
4933 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4934 curOffset.HighPart = 0;
4935 curOffset.LowPart = nextCookie;
4936 origOp = op = smb_GetSMBData(outp, NULL);
4937 /* and write out the basic header */
4938 *op++ = 5; /* variable block */
4939 op += 2; /* skip vbl block length; we'll fill it in later */
4943 clientchar_t *actualName = NULL;
4944 int free_actualName = 0;
4945 clientchar_t shortName[13];
4946 clientchar_t *shortNameEnd;
4948 /* make sure that curOffset.LowPart doesn't point to the first
4949 * 32 bytes in the 2nd through last dir page, and that it doesn't
4950 * point at the first 13 32-byte chunks in the first dir page,
4951 * since those are dir and page headers, and don't contain useful
4954 temp = curOffset.LowPart & (2048-1);
4955 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4956 /* we're in the first page */
4957 if (temp < 13*32) temp = 13*32;
4960 /* we're in a later dir page */
4961 if (temp < 32) temp = 32;
4964 /* make sure the low order 5 bits are zero */
4967 /* now put temp bits back ito curOffset.LowPart */
4968 curOffset.LowPart &= ~(2048-1);
4969 curOffset.LowPart |= temp;
4971 /* check if we've returned all the names that will fit in the
4974 if (returnedNames >= maxCount) {
4975 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4976 returnedNames, maxCount);
4980 /* check if we've passed the dir's EOF */
4981 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4983 /* see if we can use the bufferp we have now; compute in which page
4984 * the current offset would be, and check whether that's the offset
4985 * of the buffer we have. If not, get the buffer.
4987 thyper.HighPart = curOffset.HighPart;
4988 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4989 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4992 buf_Release(bufferp);
4995 lock_ReleaseWrite(&scp->rw);
4996 code = buf_Get(scp, &thyper, &req, &bufferp);
4997 lock_ObtainMutex(&dsp->mx);
4999 /* now, if we're doing a star match, do bulk fetching of all of
5000 * the status info for files in the dir.
5003 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5005 lock_ObtainWrite(&scp->rw);
5006 lock_ReleaseMutex(&dsp->mx);
5008 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5012 bufferOffset = thyper;
5014 /* now get the data in the cache */
5016 code = cm_SyncOp(scp, bufferp, userp, &req,
5018 CM_SCACHESYNC_NEEDCALLBACK |
5019 CM_SCACHESYNC_READ);
5021 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5025 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5027 if (cm_HaveBuffer(scp, bufferp, 0)) {
5028 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5032 /* otherwise, load the buffer and try again */
5033 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5035 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5036 scp, bufferp, code);
5041 buf_Release(bufferp);
5045 } /* if (wrong buffer) ... */
5047 /* now we have the buffer containing the entry we're interested in; copy
5048 * it out if it represents a non-deleted entry.
5050 entryInDir = curOffset.LowPart & (2048-1);
5051 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5053 /* page header will help tell us which entries are free. Page header
5054 * can change more often than once per buffer, since AFS 3 dir page size
5055 * may be less than (but not more than a buffer package buffer.
5057 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5058 temp &= ~(2048 - 1); /* turn off intra-page bits */
5059 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5061 /* now determine which entry we're looking at in the page. If it is
5062 * free (there's a free bitmap at the start of the dir), we should
5063 * skip these 32 bytes.
5065 slotInPage = (entryInDir & 0x7e0) >> 5;
5066 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5067 /* this entry is free */
5068 numDirChunks = 1; /* only skip this guy */
5072 tp = bufferp->datap + entryInBuffer;
5073 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5075 /* while we're here, compute the next entry's location, too,
5076 * since we'll need it when writing out the cookie into the dir
5079 * XXXX Probably should do more sanity checking.
5081 numDirChunks = cm_NameEntries(dep->name, NULL);
5083 /* compute the offset of the cookie representing the next entry */
5084 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5086 /* Compute 8.3 name if necessary */
5087 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5088 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5091 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5092 actualName = shortName;
5093 free_actualName = 0;
5095 free_actualName = 1;
5098 if (actualName == NULL) {
5099 /* Couldn't convert the name for some reason */
5100 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5101 osi_LogSaveString(smb_logp, dep->name));
5105 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5106 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5107 osi_LogSaveClientString(smb_logp, actualName));
5109 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5110 /* this is one of the entries to use: it is not deleted
5111 * and it matches the star pattern we're looking for.
5114 /* Eliminate entries that don't match requested
5117 /* no hidden files */
5118 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5119 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5123 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5125 /* We have already done the cm_TryBulkStat above */
5126 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5127 fileType = cm_FindFileType(&fid);
5128 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5129 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5131 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5132 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5133 fileType == CM_SCACHETYPE_DFSLINK ||
5134 fileType == CM_SCACHETYPE_INVALID)
5135 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5140 memcpy(op, mask, 11); op += 11;
5141 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5142 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5143 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5144 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5145 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5146 memcpy(op, &clientCookie, 4); op += 4;
5148 /* now we emit the attribute. This is sort of tricky,
5149 * since we need to really stat the file to find out
5150 * what type of entry we've got. Right now, we're
5151 * copying out data from a buffer, while holding the
5152 * scp locked, so it isn't really convenient to stat
5153 * something now. We'll put in a place holder now,
5154 * and make a second pass before returning this to get
5155 * the real attributes. So, we just skip the data for
5156 * now, and adjust it later. We allocate a patch
5157 * record to make it easy to find this point later.
5158 * The replay will happen at a time when it is safe to
5159 * unlock the directory.
5161 curPatchp = malloc(sizeof(*curPatchp));
5162 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5163 curPatchp->dptr = op;
5164 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5166 /* do hidden attribute here since name won't be around when applying
5170 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5171 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5173 curPatchp->flags = 0;
5175 op += 9; /* skip attr, time, date and size */
5177 /* zero out name area. The spec says to pad with
5178 * spaces, but Samba doesn't, and neither do we.
5182 /* finally, we get to copy out the name; we know that
5183 * it fits in 8.3 or the pattern wouldn't match, but it
5184 * never hurts to be sure.
5186 cm_ClientStringToUtf8(actualName, -1, op, 13);
5187 if (smb_StoreAnsiFilenames)
5189 /* This is a UCHAR field, which is ASCII even if Unicode
5192 /* Uppercase if requested by client */
5193 if (!KNOWS_LONG_NAMES(inp))
5198 /* now, adjust the # of entries copied */
5200 } /* if we're including this name */
5203 if (free_actualName && actualName) {
5208 /* and adjust curOffset to be where the new cookie is */
5209 thyper.HighPart = 0;
5210 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5211 curOffset = LargeIntegerAdd(thyper, curOffset);
5212 } /* while copying data for dir listing */
5214 /* release the mutex */
5215 lock_ReleaseWrite(&scp->rw);
5217 buf_Release(bufferp);
5221 /* apply and free last set of patches; if not doing a star match, this
5222 * will be empty, but better safe (and freeing everything) than sorry.
5224 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5226 /* special return code for unsuccessful search */
5227 if (code == 0 && dataLength < 21 && returnedNames == 0)
5228 code = CM_ERROR_NOFILES;
5230 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5231 returnedNames, code);
5234 smb_DeleteDirSearch(dsp);
5235 smb_ReleaseDirSearch(dsp);
5236 cm_ReleaseSCache(scp);
5237 cm_ReleaseUser(userp);
5241 /* finalize the output buffer */
5242 smb_SetSMBParm(outp, 0, returnedNames);
5243 temp = (long) (op - origOp);
5244 smb_SetSMBDataLength(outp, temp);
5246 /* the data area is a variable block, which has a 5 (already there)
5247 * followed by the length of the # of data bytes. We now know this to
5248 * be "temp," although that includes the 3 bytes of vbl block header.
5249 * Deduct for them and fill in the length field.
5251 temp -= 3; /* deduct vbl block info */
5252 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5253 origOp[1] = (unsigned char)(temp & 0xff);
5254 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5255 if (returnedNames == 0)
5256 smb_DeleteDirSearch(dsp);
5257 smb_ReleaseDirSearch(dsp);
5258 cm_ReleaseSCache(scp);
5259 cm_ReleaseUser(userp);
5264 /* verify that this is a valid path to a directory. I don't know why they
5265 * don't use the get file attributes call.
5267 * SMB_COM_CHECK_DIRECTORY
5269 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5271 clientchar_t *pathp;
5273 cm_scache_t *rootScp;
5274 cm_scache_t *newScp;
5278 clientchar_t *tidPathp;
5284 pdata = smb_GetSMBData(inp, NULL);
5285 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5287 return CM_ERROR_BADSMB;
5288 osi_Log1(smb_logp, "SMB receive check path %S",
5289 osi_LogSaveClientString(smb_logp, pathp));
5291 rootScp = cm_data.rootSCachep;
5293 userp = smb_GetUserFromVCP(vcp, inp);
5295 caseFold = CM_FLAG_CASEFOLD;
5297 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5299 cm_ReleaseUser(userp);
5300 return CM_ERROR_NOSUCHPATH;
5302 code = cm_NameI(rootScp, pathp,
5303 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5304 userp, tidPathp, &req, &newScp);
5307 cm_ReleaseUser(userp);
5312 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5313 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5314 cm_ReleaseSCache(newScp);
5315 cm_ReleaseUser(userp);
5316 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5317 return CM_ERROR_PATH_NOT_COVERED;
5319 return CM_ERROR_NOSUCHPATH;
5321 #endif /* DFS_SUPPORT */
5323 /* now lock the vnode with a callback; returns with newScp locked */
5324 lock_ObtainWrite(&newScp->rw);
5325 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5326 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5328 if (code != CM_ERROR_NOACCESS) {
5329 lock_ReleaseWrite(&newScp->rw);
5330 cm_ReleaseSCache(newScp);
5331 cm_ReleaseUser(userp);
5335 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5338 attrs = smb_Attributes(newScp);
5340 if (!(attrs & SMB_ATTR_DIRECTORY))
5341 code = CM_ERROR_NOTDIR;
5343 lock_ReleaseWrite(&newScp->rw);
5345 cm_ReleaseSCache(newScp);
5346 cm_ReleaseUser(userp);
5350 /* SMB_COM_SET_INFORMATION */
5351 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5353 clientchar_t *pathp;
5355 cm_scache_t *rootScp;
5356 unsigned short attribute;
5358 cm_scache_t *newScp;
5362 clientchar_t *tidPathp;
5368 /* decode basic attributes we're passed */
5369 attribute = smb_GetSMBParm(inp, 0);
5370 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5372 datap = smb_GetSMBData(inp, NULL);
5373 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5375 return CM_ERROR_BADSMB;
5377 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5378 dosTime, attribute);
5380 rootScp = cm_data.rootSCachep;
5382 userp = smb_GetUserFromVCP(vcp, inp);
5384 caseFold = CM_FLAG_CASEFOLD;
5386 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5388 cm_ReleaseUser(userp);
5389 return CM_ERROR_NOSUCHFILE;
5391 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5392 tidPathp, &req, &newScp);
5395 cm_ReleaseUser(userp);
5400 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5401 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5402 cm_ReleaseSCache(newScp);
5403 cm_ReleaseUser(userp);
5404 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5405 return CM_ERROR_PATH_NOT_COVERED;
5407 return CM_ERROR_NOSUCHPATH;
5409 #endif /* DFS_SUPPORT */
5411 /* now lock the vnode with a callback; returns with newScp locked; we
5412 * need the current status to determine what the new status is, in some
5415 lock_ObtainWrite(&newScp->rw);
5416 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5417 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5419 lock_ReleaseWrite(&newScp->rw);
5420 cm_ReleaseSCache(newScp);
5421 cm_ReleaseUser(userp);
5425 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5427 /* Check for RO volume */
5428 if (newScp->flags & CM_SCACHEFLAG_RO) {
5429 lock_ReleaseWrite(&newScp->rw);
5430 cm_ReleaseSCache(newScp);
5431 cm_ReleaseUser(userp);
5432 return CM_ERROR_READONLY;
5435 /* prepare for setattr call */
5438 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5439 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5441 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5442 /* we're told to make a writable file read-only */
5443 attr.unixModeBits = newScp->unixModeBits & ~0222;
5444 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5446 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5447 /* we're told to make a read-only file writable */
5448 attr.unixModeBits = newScp->unixModeBits | 0222;
5449 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5451 lock_ReleaseWrite(&newScp->rw);
5453 /* now call setattr */
5455 code = cm_SetAttr(newScp, &attr, userp, &req);
5459 cm_ReleaseSCache(newScp);
5460 cm_ReleaseUser(userp);
5466 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5468 clientchar_t *pathp;
5470 cm_scache_t *rootScp;
5471 cm_scache_t *newScp, *dscp;
5476 clientchar_t *tidPathp;
5478 clientchar_t *lastComp;
5484 datap = smb_GetSMBData(inp, NULL);
5485 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5487 return CM_ERROR_BADSMB;
5489 if (*pathp == 0) /* null path */
5492 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5493 osi_LogSaveClientString(smb_logp, pathp));
5495 rootScp = cm_data.rootSCachep;
5497 userp = smb_GetUserFromVCP(vcp, inp);
5499 /* we shouldn't need this for V3 requests, but we seem to */
5500 caseFold = CM_FLAG_CASEFOLD;
5502 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5504 cm_ReleaseUser(userp);
5505 return CM_ERROR_NOSUCHFILE;
5509 * XXX Strange hack XXX
5511 * As of Patch 5 (16 July 97), we are having the following problem:
5512 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5513 * requests to look up "desktop.ini" in all the subdirectories.
5514 * This can cause zillions of timeouts looking up non-existent cells
5515 * and volumes, especially in the top-level directory.
5517 * We have not found any way to avoid this or work around it except
5518 * to explicitly ignore the requests for mount points that haven't
5519 * yet been evaluated and for directories that haven't yet been
5522 * We should modify this hack to provide a fake desktop.ini file
5523 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5525 spacep = inp->spacep;
5526 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5527 #ifndef SPECIAL_FOLDERS
5528 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5529 code = cm_NameI(rootScp, spacep->wdata,
5530 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5531 userp, tidPathp, &req, &dscp);
5534 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5535 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5537 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5538 return CM_ERROR_PATH_NOT_COVERED;
5540 return CM_ERROR_NOSUCHPATH;
5542 #endif /* DFS_SUPPORT */
5543 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5544 code = CM_ERROR_NOSUCHFILE;
5545 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5546 cm_buf_t *bp = buf_Find(dscp, &hzero);
5551 code = CM_ERROR_NOSUCHFILE;
5553 cm_ReleaseSCache(dscp);
5555 cm_ReleaseUser(userp);
5560 #endif /* SPECIAL_FOLDERS */
5562 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5563 tidPathp, &req, &newScp);
5565 cm_ReleaseUser(userp);
5570 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5571 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5572 cm_ReleaseSCache(newScp);
5573 cm_ReleaseUser(userp);
5574 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5575 return CM_ERROR_PATH_NOT_COVERED;
5577 return CM_ERROR_NOSUCHPATH;
5579 #endif /* DFS_SUPPORT */
5581 /* now lock the vnode with a callback; returns with newScp locked */
5582 lock_ObtainWrite(&newScp->rw);
5583 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5584 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5586 lock_ReleaseWrite(&newScp->rw);
5587 cm_ReleaseSCache(newScp);
5588 cm_ReleaseUser(userp);
5592 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5594 attrs = smb_Attributes(newScp);
5596 smb_SetSMBParm(outp, 0, attrs);
5598 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5599 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5600 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5601 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5602 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5603 smb_SetSMBParm(outp, 5, 0);
5604 smb_SetSMBParm(outp, 6, 0);
5605 smb_SetSMBParm(outp, 7, 0);
5606 smb_SetSMBParm(outp, 8, 0);
5607 smb_SetSMBParm(outp, 9, 0);
5608 smb_SetSMBDataLength(outp, 0);
5609 lock_ReleaseWrite(&newScp->rw);
5611 cm_ReleaseSCache(newScp);
5612 cm_ReleaseUser(userp);
5617 /* SMB_COM_TREE_DISCONNECT */
5618 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5622 osi_Log0(smb_logp, "SMB receive tree disconnect");
5624 /* find the tree and free it */
5625 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5627 lock_ObtainWrite(&smb_rctLock);
5629 smb_ReleaseTID(tidp, TRUE);
5630 lock_ReleaseWrite(&smb_rctLock);
5637 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5640 clientchar_t *pathp;
5641 clientchar_t *lastNamep;
5650 clientchar_t *tidPathp;
5656 datap = smb_GetSMBData(inp, NULL);
5657 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5659 return CM_ERROR_BADSMB;
5661 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5663 #ifdef DEBUG_VERBOSE
5667 hexpath = osi_HexifyString( pathp );
5668 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5673 share = smb_GetSMBParm(inp, 0);
5674 attribute = smb_GetSMBParm(inp, 1);
5676 spacep = inp->spacep;
5677 /* smb_StripLastComponent will strip "::$DATA" if present */
5678 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5680 if (!cm_IsValidClientString(pathp)) {
5682 clientchar_t * hexp;
5684 hexp = cm_GetRawCharsAlloc(pathp, -1);
5685 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5686 osi_LogSaveClientString(smb_logp, hexp));
5690 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5692 return CM_ERROR_BADNTFILENAME;
5695 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5696 /* special case magic file name for receiving IOCTL requests
5697 * (since IOCTL calls themselves aren't getting through).
5699 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5700 smb_SetupIoctlFid(fidp, spacep);
5701 smb_SetSMBParm(outp, 0, fidp->fid);
5702 smb_SetSMBParm(outp, 1, 0); /* attrs */
5703 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5704 smb_SetSMBParm(outp, 3, 0);
5705 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5706 smb_SetSMBParm(outp, 5, 0x7fff);
5707 /* pass the open mode back */
5708 smb_SetSMBParm(outp, 6, (share & 0xf));
5709 smb_SetSMBDataLength(outp, 0);
5710 smb_ReleaseFID(fidp);
5714 userp = smb_GetUserFromVCP(vcp, inp);
5716 caseFold = CM_FLAG_CASEFOLD;
5718 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5720 cm_ReleaseUser(userp);
5721 return CM_ERROR_NOSUCHPATH;
5723 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5724 tidPathp, &req, &scp);
5727 cm_ReleaseUser(userp);
5732 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5733 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5734 cm_ReleaseSCache(scp);
5735 cm_ReleaseUser(userp);
5736 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5737 return CM_ERROR_PATH_NOT_COVERED;
5739 return CM_ERROR_NOSUCHPATH;
5741 #endif /* DFS_SUPPORT */
5743 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5745 cm_ReleaseSCache(scp);
5746 cm_ReleaseUser(userp);
5750 /* don't need callback to check file type, since file types never
5751 * change, and namei and cm_Lookup all stat the object at least once on
5752 * a successful return.
5754 if (scp->fileType != CM_SCACHETYPE_FILE) {
5755 cm_ReleaseSCache(scp);
5756 cm_ReleaseUser(userp);
5757 return CM_ERROR_ISDIR;
5760 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5761 osi_assertx(fidp, "null smb_fid_t");
5763 lock_ObtainMutex(&fidp->mx);
5764 if ((share & 0xf) == 0)
5765 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5766 else if ((share & 0xf) == 1)
5767 fidp->flags |= SMB_FID_OPENWRITE;
5769 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5773 fidp->userp = userp;
5775 /* and a pointer to the vnode */
5777 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5778 lock_ObtainWrite(&scp->rw);
5779 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5781 smb_SetSMBParm(outp, 0, fidp->fid);
5782 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5783 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5784 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5785 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5786 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5787 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5788 /* pass the open mode back; XXXX add access checks */
5789 smb_SetSMBParm(outp, 6, (share & 0xf));
5790 smb_SetSMBDataLength(outp, 0);
5791 lock_ReleaseMutex(&fidp->mx);
5792 lock_ReleaseRead(&scp->rw);
5795 cm_Open(scp, 0, userp);
5797 /* send and free packet */
5798 smb_ReleaseFID(fidp);
5799 cm_ReleaseUser(userp);
5800 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5804 typedef struct smb_unlinkRock {
5809 clientchar_t *maskp; /* pointer to the star pattern */
5812 cm_dirEntryList_t * matches;
5815 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5818 smb_unlinkRock_t *rockp;
5821 normchar_t matchName[MAX_PATH];
5825 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5826 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5827 caseFold |= CM_FLAG_8DOT3;
5829 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5830 /* Can't convert name */
5831 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5832 osi_LogSaveString(smb_logp, dep->name));
5836 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5838 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5839 !cm_Is8Dot3(matchName)) {
5840 cm_Gen8Dot3Name(dep, matchName, NULL);
5841 /* 8.3 matches are always case insensitive */
5842 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5845 osi_Log1(smb_logp, "Found match %S",
5846 osi_LogSaveClientString(smb_logp, matchName));
5848 cm_DirEntryListAdd(dep->name, &rockp->matches);
5852 /* If we made a case sensitive exact match, we might as well quit now. */
5853 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5854 code = CM_ERROR_STOPNOW;
5863 /* SMB_COM_DELETE */
5864 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5868 clientchar_t *pathp;
5872 clientchar_t *lastNamep;
5873 smb_unlinkRock_t rock;
5877 clientchar_t *tidPathp;
5881 memset(&rock, 0, sizeof(rock));
5883 attribute = smb_GetSMBParm(inp, 0);
5885 tp = smb_GetSMBData(inp, NULL);
5886 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5888 return CM_ERROR_BADSMB;
5890 osi_Log1(smb_logp, "SMB receive unlink %S",
5891 osi_LogSaveClientString(smb_logp, pathp));
5893 spacep = inp->spacep;
5894 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5896 userp = smb_GetUserFromVCP(vcp, inp);
5898 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5900 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5902 cm_ReleaseUser(userp);
5903 return CM_ERROR_NOSUCHPATH;
5905 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5908 cm_ReleaseUser(userp);
5913 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5914 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5915 cm_ReleaseSCache(dscp);
5916 cm_ReleaseUser(userp);
5917 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5918 return CM_ERROR_PATH_NOT_COVERED;
5920 return CM_ERROR_NOSUCHPATH;
5922 #endif /* DFS_SUPPORT */
5924 /* otherwise, scp points to the parent directory. */
5931 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5933 code = CM_ERROR_NOSUCHFILE;
5936 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5939 thyper.HighPart = 0;
5944 rock.matches = NULL;
5946 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5947 * match. If that fails, we do a case insensitve match.
5949 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5950 !smb_IsStarMask(rock.maskp)) {
5951 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5954 thyper.HighPart = 0;
5955 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5960 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5962 if (code == CM_ERROR_STOPNOW)
5965 if (code == 0 && rock.matches) {
5966 cm_dirEntryList_t * entry;
5968 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5969 normchar_t normalizedName[MAX_PATH];
5971 /* Note: entry->name is a non-normalized name */
5973 osi_Log1(smb_logp, "Unlinking %s",
5974 osi_LogSaveString(smb_logp, entry->name));
5976 /* We assume this works because entry->name was
5977 successfully converted in smb_UnlinkProc() once. */
5978 cm_FsStringToNormString(entry->name, -1,
5979 normalizedName, lengthof(normalizedName));
5981 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5983 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5984 smb_NotifyChange(FILE_ACTION_REMOVED,
5985 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5986 dscp, normalizedName, NULL, TRUE);
5990 cm_DirEntryListFree(&rock.matches);
5994 cm_ReleaseUser(userp);
5997 cm_ReleaseSCache(dscp);
6002 if (code == 0 && !rock.any)
6003 code = CM_ERROR_NOSUCHFILE;
6007 typedef struct smb_renameRock {
6008 cm_scache_t *odscp; /* old dir */
6009 cm_scache_t *ndscp; /* new dir */
6010 cm_user_t *userp; /* user */
6011 cm_req_t *reqp; /* request struct */
6012 smb_vc_t *vcp; /* virtual circuit */
6013 normchar_t *maskp; /* pointer to star pattern of old file name */
6014 int flags; /* tilde, casefold, etc */
6015 clientchar_t *newNamep; /* ptr to the new file's name */
6016 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6017 clientchar_t clOldName[MAX_PATH]; /* client name */
6021 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6024 smb_renameRock_t *rockp;
6027 normchar_t matchName[MAX_PATH];
6029 rockp = (smb_renameRock_t *) vrockp;
6031 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6032 /* Can't convert string */
6033 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6034 osi_LogSaveString(smb_logp, dep->name));
6038 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6039 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6040 caseFold |= CM_FLAG_8DOT3;
6042 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6044 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6045 !cm_Is8Dot3(matchName)) {
6046 cm_Gen8Dot3Name(dep, matchName, NULL);
6047 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6052 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6053 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6055 code = CM_ERROR_STOPNOW;
6065 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6068 cm_space_t *spacep = NULL;
6069 smb_renameRock_t rock;
6070 cm_scache_t *oldDscp = NULL;
6071 cm_scache_t *newDscp = NULL;
6072 cm_scache_t *tmpscp= NULL;
6073 cm_scache_t *tmpscp2 = NULL;
6074 clientchar_t *oldLastNamep;
6075 clientchar_t *newLastNamep;
6079 clientchar_t *tidPathp;
6083 userp = smb_GetUserFromVCP(vcp, inp);
6084 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6086 cm_ReleaseUser(userp);
6087 return CM_ERROR_NOSUCHPATH;
6091 memset(&rock, 0, sizeof(rock));
6093 spacep = inp->spacep;
6094 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6096 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6097 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6098 userp, tidPathp, &req, &oldDscp);
6100 cm_ReleaseUser(userp);
6105 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6106 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6107 cm_ReleaseSCache(oldDscp);
6108 cm_ReleaseUser(userp);
6109 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6110 return CM_ERROR_PATH_NOT_COVERED;
6112 return CM_ERROR_NOSUCHPATH;
6114 #endif /* DFS_SUPPORT */
6116 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6117 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6118 userp, tidPathp, &req, &newDscp);
6121 cm_ReleaseSCache(oldDscp);
6122 cm_ReleaseUser(userp);
6127 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6128 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6129 cm_ReleaseSCache(oldDscp);
6130 cm_ReleaseSCache(newDscp);
6131 cm_ReleaseUser(userp);
6132 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6133 return CM_ERROR_PATH_NOT_COVERED;
6135 return CM_ERROR_NOSUCHPATH;
6137 #endif /* DFS_SUPPORT */
6140 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6141 * next, get the component names, and lower case them.
6144 /* handle the old name first */
6146 oldLastNamep = oldPathp;
6150 /* and handle the new name, too */
6152 newLastNamep = newPathp;
6156 /* TODO: The old name could be a wildcard. The new name must not be */
6158 /* Check if the file already exists; if so return error */
6159 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6160 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6161 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6163 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6164 osi_LogSaveClientString(smb_logp, newLastNamep));
6166 /* Check if the old and the new names differ only in case. If so return
6167 * success, else return CM_ERROR_EXISTS
6169 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6171 /* This would be a success only if the old file is *as same as* the new file */
6172 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6174 if (tmpscp == tmpscp2)
6177 code = CM_ERROR_EXISTS;
6178 cm_ReleaseSCache(tmpscp2);
6181 code = CM_ERROR_NOSUCHFILE;
6184 /* file exist, do not rename, also fixes move */
6185 osi_Log0(smb_logp, "Can't rename. Target already exists");
6186 code = CM_ERROR_EXISTS;
6191 /* do the vnode call */
6192 rock.odscp = oldDscp;
6193 rock.ndscp = newDscp;
6197 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6199 code = CM_ERROR_NOSUCHFILE;
6202 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6203 rock.newNamep = newLastNamep;
6204 rock.fsOldName[0] = '\0';
6205 rock.clOldName[0] = '\0';
6208 /* Now search the directory for the pattern, and do the appropriate rename when found */
6209 thyper.LowPart = 0; /* search dir from here */
6210 thyper.HighPart = 0;
6212 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6213 if (code == 0 && !rock.any) {
6215 thyper.HighPart = 0;
6216 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6217 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6219 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6221 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6222 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6223 rock.ndscp, rock.newNamep, rock.userp,
6225 /* if the call worked, stop doing the search now, since we
6226 * really only want to rename one file.
6229 osi_Log0(smb_logp, "cm_Rename failure");
6230 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6231 } else if (code == 0) {
6232 code = CM_ERROR_NOSUCHFILE;
6235 /* Handle Change Notification */
6237 * Being lazy, not distinguishing between files and dirs in this
6238 * filter, since we'd have to do a lookup.
6241 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6242 if (oldDscp == newDscp) {
6243 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6244 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6245 filter, oldDscp, rock.clOldName,
6246 newLastNamep, TRUE);
6248 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6249 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6250 filter, oldDscp, rock.clOldName,
6252 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6253 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6254 filter, newDscp, newLastNamep,
6261 cm_ReleaseSCache(tmpscp);
6263 cm_ReleaseUser(userp);
6265 cm_ReleaseSCache(oldDscp);
6267 cm_ReleaseSCache(newDscp);
6275 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6278 cm_space_t *spacep = NULL;
6279 cm_scache_t *oldDscp = NULL;
6280 cm_scache_t *newDscp = NULL;
6281 cm_scache_t *tmpscp= NULL;
6282 cm_scache_t *tmpscp2 = NULL;
6283 cm_scache_t *sscp = NULL;
6284 clientchar_t *oldLastNamep;
6285 clientchar_t *newLastNamep;
6288 clientchar_t *tidPathp;
6292 userp = smb_GetUserFromVCP(vcp, inp);
6294 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6296 cm_ReleaseUser(userp);
6297 return CM_ERROR_NOSUCHPATH;
6302 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6304 spacep = inp->spacep;
6305 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6307 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6308 userp, tidPathp, &req, &oldDscp);
6310 cm_ReleaseUser(userp);
6315 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6316 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6317 cm_ReleaseSCache(oldDscp);
6318 cm_ReleaseUser(userp);
6319 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6320 return CM_ERROR_PATH_NOT_COVERED;
6322 return CM_ERROR_NOSUCHPATH;
6324 #endif /* DFS_SUPPORT */
6326 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6327 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6328 userp, tidPathp, &req, &newDscp);
6330 cm_ReleaseSCache(oldDscp);
6331 cm_ReleaseUser(userp);
6336 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6337 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6338 cm_ReleaseSCache(newDscp);
6339 cm_ReleaseSCache(oldDscp);
6340 cm_ReleaseUser(userp);
6341 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6342 return CM_ERROR_PATH_NOT_COVERED;
6344 return CM_ERROR_NOSUCHPATH;
6346 #endif /* DFS_SUPPORT */
6348 /* Now, although we did two lookups for the two directories (because the same
6349 * directory can be referenced through different paths), we only allow hard links
6350 * within the same directory. */
6351 if (oldDscp != newDscp) {
6352 cm_ReleaseSCache(oldDscp);
6353 cm_ReleaseSCache(newDscp);
6354 cm_ReleaseUser(userp);
6355 return CM_ERROR_CROSSDEVLINK;
6358 /* handle the old name first */
6360 oldLastNamep = oldPathp;
6364 /* and handle the new name, too */
6366 newLastNamep = newPathp;
6370 /* now lookup the old name */
6371 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6372 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6374 cm_ReleaseSCache(oldDscp);
6375 cm_ReleaseSCache(newDscp);
6376 cm_ReleaseUser(userp);
6380 /* Check if the file already exists; if so return error */
6381 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6382 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6383 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6385 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6386 osi_LogSaveClientString(smb_logp, newLastNamep));
6388 /* if the existing link is to the same file, then we return success */
6390 if(sscp == tmpscp) {
6393 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6394 code = CM_ERROR_EXISTS;
6399 cm_ReleaseSCache(tmpscp);
6400 cm_ReleaseSCache(sscp);
6401 cm_ReleaseSCache(newDscp);
6402 cm_ReleaseSCache(oldDscp);
6403 cm_ReleaseUser(userp);
6407 /* now create the hardlink */
6408 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6409 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6410 osi_Log1(smb_logp," Link returns 0x%x", code);
6412 /* Handle Change Notification */
6414 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6415 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6416 smb_NotifyChange(FILE_ACTION_ADDED,
6417 filter, newDscp, newLastNamep,
6422 cm_ReleaseSCache(tmpscp);
6423 cm_ReleaseUser(userp);
6424 cm_ReleaseSCache(sscp);
6425 cm_ReleaseSCache(oldDscp);
6426 cm_ReleaseSCache(newDscp);
6430 /* SMB_COM_RENAME */
6432 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6434 clientchar_t *oldPathp;
6435 clientchar_t *newPathp;
6439 tp = smb_GetSMBData(inp, NULL);
6440 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6442 return CM_ERROR_BADSMB;
6443 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6445 return CM_ERROR_BADSMB;
6447 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6448 osi_LogSaveClientString(smb_logp, oldPathp),
6449 osi_LogSaveClientString(smb_logp, newPathp));
6451 if (!cm_IsValidClientString(newPathp)) {
6453 clientchar_t * hexp;
6455 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6456 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6457 osi_LogSaveClientString(smb_logp, hexp));
6461 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6463 return CM_ERROR_BADNTFILENAME;
6466 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6468 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6474 typedef struct smb_rmdirRock {
6478 normchar_t *maskp; /* pointer to the star pattern */
6481 cm_dirEntryList_t * matches;
6484 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6487 smb_rmdirRock_t *rockp;
6489 normchar_t matchName[MAX_PATH];
6491 rockp = (smb_rmdirRock_t *) vrockp;
6493 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6494 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6495 osi_LogSaveString(smb_logp, dep->name));
6499 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6500 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6502 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6504 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6505 !cm_Is8Dot3(matchName)) {
6506 cm_Gen8Dot3Name(dep, matchName, NULL);
6507 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6512 cm_DirEntryListAdd(dep->name, &rockp->matches);
6519 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6522 clientchar_t *pathp;
6526 clientchar_t *lastNamep;
6527 smb_rmdirRock_t rock;
6531 clientchar_t *tidPathp;
6535 memset(&rock, 0, sizeof(rock));
6537 tp = smb_GetSMBData(inp, NULL);
6538 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6540 return CM_ERROR_BADSMB;
6542 spacep = inp->spacep;
6543 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6545 userp = smb_GetUserFromVCP(vcp, inp);
6547 caseFold = CM_FLAG_CASEFOLD;
6549 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6551 cm_ReleaseUser(userp);
6552 return CM_ERROR_NOSUCHPATH;
6554 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6555 userp, tidPathp, &req, &dscp);
6558 cm_ReleaseUser(userp);
6563 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6564 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6565 cm_ReleaseSCache(dscp);
6566 cm_ReleaseUser(userp);
6567 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6568 return CM_ERROR_PATH_NOT_COVERED;
6570 return CM_ERROR_NOSUCHPATH;
6572 #endif /* DFS_SUPPORT */
6574 /* otherwise, scp points to the parent directory. */
6581 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6583 code = CM_ERROR_NOSUCHFILE;
6586 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6589 thyper.HighPart = 0;
6593 rock.matches = NULL;
6595 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6596 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6597 if (code == 0 && !rock.any) {
6599 thyper.HighPart = 0;
6600 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6601 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6604 if (code == 0 && rock.matches) {
6605 cm_dirEntryList_t * entry;
6607 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6608 clientchar_t clientName[MAX_PATH];
6610 /* We assume this will succeed because smb_RmdirProc()
6611 successfully converted entry->name once above. */
6612 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6614 osi_Log1(smb_logp, "Removing directory %s",
6615 osi_LogSaveString(smb_logp, entry->name));
6617 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6619 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6620 smb_NotifyChange(FILE_ACTION_REMOVED,
6621 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6622 dscp, clientName, NULL, TRUE);
6628 cm_DirEntryListFree(&rock.matches);
6631 cm_ReleaseUser(userp);
6634 cm_ReleaseSCache(dscp);
6636 if (code == 0 && !rock.any)
6637 code = CM_ERROR_NOSUCHFILE;
6646 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6656 fid = smb_GetSMBParm(inp, 0);
6658 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6660 fid = smb_ChainFID(fid, inp);
6661 fidp = smb_FindFID(vcp, fid, 0);
6663 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6665 return CM_ERROR_BADFD;
6667 userp = smb_GetUserFromVCP(vcp, inp);
6669 lock_ObtainMutex(&fidp->mx);
6670 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6671 cm_ReleaseUser(userp);
6672 lock_ReleaseMutex(&fidp->mx);
6673 smb_ReleaseFID(fidp);
6674 return CM_ERROR_BADFD;
6677 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6678 lock_ReleaseMutex(&fidp->mx);
6679 cm_ReleaseUser(userp);
6680 smb_CloseFID(vcp, fidp, NULL, 0);
6681 smb_ReleaseFID(fidp);
6682 return CM_ERROR_NOSUCHFILE;
6685 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6686 cm_scache_t * scp = fidp->scp;
6688 lock_ReleaseMutex(&fidp->mx);
6689 code = cm_FSync(scp, userp, &req, FALSE);
6690 cm_ReleaseSCache(scp);
6692 lock_ReleaseMutex(&fidp->mx);
6696 cm_ReleaseUser(userp);
6697 smb_ReleaseFID(fidp);
6701 struct smb_FullNameRock {
6704 clientchar_t *fullName;
6705 fschar_t *originalName;
6708 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6711 normchar_t matchName[MAX_PATH];
6712 struct smb_FullNameRock *vrockp;
6714 vrockp = (struct smb_FullNameRock *)rockp;
6716 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6717 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6718 osi_LogSaveString(smb_logp, dep->name));
6722 if (!cm_Is8Dot3(matchName)) {
6723 clientchar_t shortName[13];
6725 cm_Gen8Dot3Name(dep, shortName, NULL);
6727 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6728 vrockp->fullName = cm_ClientStrDup(matchName);
6729 vrockp->originalName = cm_FsStrDup(dep->name);
6730 return CM_ERROR_STOPNOW;
6733 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6734 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6735 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6736 vrockp->fullName = cm_ClientStrDup(matchName);
6737 vrockp->originalName = cm_FsStrDup(dep->name);
6738 return CM_ERROR_STOPNOW;
6743 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6744 clientchar_t **newPathp, fschar_t ** originalPathp,
6745 cm_user_t *userp, cm_req_t *reqp)
6747 struct smb_FullNameRock rock;
6750 memset(&rock, 0, sizeof(rock));
6754 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6755 if (code == CM_ERROR_STOPNOW) {
6756 *newPathp = rock.fullName;
6757 *originalPathp = rock.originalName;
6759 *newPathp = cm_ClientStrDup(pathp);
6760 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6764 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6765 afs_uint32 dosTime) {
6768 cm_scache_t *dscp = NULL;
6769 clientchar_t *pathp = NULL;
6770 cm_scache_t * scp = NULL;
6771 cm_scache_t *delscp = NULL;
6772 int nullcreator = 0;
6774 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6775 fidp, fidp->fid, scp, vcp);
6778 lock_ObtainMutex(&fidp->mx);
6779 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6781 lock_ReleaseMutex(&fidp->mx);
6782 osi_Log0(smb_logp, " No user specified. Not closing fid");
6783 return CM_ERROR_BADFD;
6786 userp = fidp->userp; /* no hold required since fidp is held
6787 throughout the function */
6788 lock_ReleaseMutex(&fidp->mx);
6793 lock_ObtainWrite(&smb_rctLock);
6794 if (fidp->deleteOk) {
6795 osi_Log0(smb_logp, " Fid already closed.");
6796 lock_ReleaseWrite(&smb_rctLock);
6797 return CM_ERROR_BADFD;
6800 lock_ReleaseWrite(&smb_rctLock);
6802 lock_ObtainMutex(&fidp->mx);
6803 if (fidp->NTopen_dscp) {
6804 dscp = fidp->NTopen_dscp;
6805 cm_HoldSCache(dscp);
6808 if (fidp->NTopen_pathp)
6809 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6816 /* Don't jump the gun on an async raw write */
6817 while (fidp->raw_writers) {
6818 lock_ReleaseMutex(&fidp->mx);
6819 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6820 lock_ObtainMutex(&fidp->mx);
6823 /* watch for ioctl closes, and read-only opens */
6825 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6826 == SMB_FID_OPENWRITE) {
6827 if (dosTime != 0 && dosTime != -1) {
6828 lock_ObtainWrite(&fidp->scp->rw);
6829 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6830 /* This fixes defect 10958 */
6831 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6832 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6833 lock_ReleaseWrite(&fidp->scp->rw);
6835 if (smb_AsyncStore != 2) {
6836 lock_ReleaseMutex(&fidp->mx);
6837 code = cm_FSync(scp, userp, &req, FALSE);
6838 lock_ObtainMutex(&fidp->mx);
6844 /* unlock any pending locks */
6845 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6846 scp->fileType == CM_SCACHETYPE_FILE) {
6850 lock_ReleaseMutex(&fidp->mx);
6852 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6854 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6855 lock_ObtainWrite(&scp->rw);
6857 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6858 CM_SCACHESYNC_NEEDCALLBACK
6859 | CM_SCACHESYNC_GETSTATUS
6860 | CM_SCACHESYNC_LOCK);
6864 "smb CoreClose SyncOp failure code 0x%x", tcode);
6865 goto post_syncopdone;
6868 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6870 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6874 lock_ReleaseWrite(&scp->rw);
6875 lock_ObtainMutex(&fidp->mx);
6878 if (fidp->flags & SMB_FID_DELONCLOSE) {
6879 clientchar_t *fullPathp = NULL;
6880 fschar_t *originalNamep = NULL;
6882 lock_ReleaseMutex(&fidp->mx);
6884 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6889 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6890 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6891 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6893 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6894 smb_NotifyChange(FILE_ACTION_REMOVED,
6895 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6896 dscp, fullPathp, NULL, TRUE);
6899 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6901 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6902 smb_NotifyChange(FILE_ACTION_REMOVED,
6903 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6904 dscp, fullPathp, NULL, TRUE);
6911 free(originalNamep);
6913 lock_ObtainMutex(&fidp->mx);
6914 fidp->flags &= ~SMB_FID_DELONCLOSE;
6917 /* if this was a newly created file, then clear the creator
6918 * in the stat cache entry. */
6919 if (fidp->flags & SMB_FID_CREATED) {
6921 fidp->flags &= ~SMB_FID_CREATED;
6924 if (fidp->flags & SMB_FID_NTOPEN) {
6925 cm_ReleaseSCache(fidp->NTopen_dscp);
6926 fidp->NTopen_dscp = NULL;
6927 free(fidp->NTopen_pathp);
6928 fidp->NTopen_pathp = NULL;
6929 fidp->flags &= ~SMB_FID_NTOPEN;
6931 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6932 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6935 if (fidp->NTopen_wholepathp) {
6936 free(fidp->NTopen_wholepathp);
6937 fidp->NTopen_wholepathp = NULL;
6941 cm_ReleaseSCache(fidp->scp);
6944 lock_ReleaseMutex(&fidp->mx);
6947 cm_ReleaseSCache(dscp);
6950 cm_ReleaseSCache(delscp);
6954 lock_ObtainWrite(&scp->rw);
6955 if (nullcreator && scp->creator == userp)
6956 scp->creator = NULL;
6957 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6958 lock_ReleaseWrite(&scp->rw);
6959 cm_ReleaseSCache(scp);
6969 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6977 fid = smb_GetSMBParm(inp, 0);
6978 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6980 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6982 fid = smb_ChainFID(fid, inp);
6983 fidp = smb_FindFID(vcp, fid, 0);
6985 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
6987 return CM_ERROR_BADFD;
6990 userp = smb_GetUserFromVCP(vcp, inp);
6992 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6994 smb_ReleaseFID(fidp);
6995 cm_ReleaseUser(userp);
7000 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7002 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7003 cm_user_t *userp, long *readp)
7009 osi_hyper_t fileLength;
7011 osi_hyper_t lastByte;
7012 osi_hyper_t bufferOffset;
7016 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7019 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7020 fidp->fid, offsetp->LowPart, count);
7024 lock_ObtainMutex(&fidp->mx);
7025 /* make sure we have a readable FD */
7026 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7027 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7028 fidp->fid, fidp->flags);
7029 lock_ReleaseMutex(&fidp->mx);
7030 code = CM_ERROR_BADFDOP;
7035 lock_ReleaseMutex(&fidp->mx);
7036 code = CM_ERROR_BADFD;
7047 lock_ObtainWrite(&scp->rw);
7049 if (offset.HighPart == 0) {
7050 chunk = offset.LowPart >> cm_logChunkSize;
7051 if (chunk != fidp->curr_chunk) {
7052 fidp->prev_chunk = fidp->curr_chunk;
7053 fidp->curr_chunk = chunk;
7055 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7058 lock_ReleaseMutex(&fidp->mx);
7060 /* start by looking up the file's end */
7061 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7062 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7066 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7068 /* now we have the entry locked, look up the length */
7069 fileLength = scp->length;
7071 /* adjust count down so that it won't go past EOF */
7072 thyper.LowPart = count;
7073 thyper.HighPart = 0;
7074 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7076 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7077 /* we'd read past EOF, so just stop at fileLength bytes.
7078 * Start by computing how many bytes remain in the file.
7080 thyper = LargeIntegerSubtract(fileLength, offset);
7082 /* if we are past EOF, read 0 bytes */
7083 if (LargeIntegerLessThanZero(thyper))
7086 count = thyper.LowPart;
7091 /* now, copy the data one buffer at a time,
7092 * until we've filled the request packet
7095 /* if we've copied all the data requested, we're done */
7096 if (count <= 0) break;
7098 /* otherwise, load up a buffer of data */
7099 thyper.HighPart = offset.HighPart;
7100 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7101 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7104 buf_Release(bufferp);
7107 lock_ReleaseWrite(&scp->rw);
7109 code = buf_Get(scp, &thyper, &req, &bufferp);
7111 lock_ObtainWrite(&scp->rw);
7112 if (code) goto done;
7113 bufferOffset = thyper;
7115 /* now get the data in the cache */
7117 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7118 CM_SCACHESYNC_NEEDCALLBACK |
7119 CM_SCACHESYNC_READ);
7123 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7125 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7127 /* otherwise, load the buffer and try again */
7128 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7132 buf_Release(bufferp);
7136 } /* if (wrong buffer) ... */
7138 /* now we have the right buffer loaded. Copy out the
7139 * data from here to the user's buffer.
7141 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7143 /* and figure out how many bytes we want from this buffer */
7144 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7145 if (nbytes > count) nbytes = count; /* don't go past EOF */
7147 /* now copy the data */
7148 memcpy(op, bufferp->datap + bufIndex, nbytes);
7150 /* adjust counters, pointers, etc. */
7153 thyper.LowPart = nbytes;
7154 thyper.HighPart = 0;
7155 offset = LargeIntegerAdd(thyper, offset);
7159 lock_ReleaseWrite(&scp->rw);
7161 buf_Release(bufferp);
7163 if (code == 0 && sequential)
7164 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7166 cm_ReleaseSCache(scp);
7169 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7170 fidp->fid, code, *readp);
7175 * smb_WriteData -- common code for Write and Raw Write
7177 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7178 cm_user_t *userp, long *writtenp)
7180 osi_hyper_t offset = *offsetp;
7183 cm_scache_t *scp = NULL;
7184 osi_hyper_t fileLength; /* file's length at start of write */
7185 osi_hyper_t minLength; /* don't read past this */
7186 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7187 cm_buf_t *bufferp = NULL;
7188 osi_hyper_t thyper; /* hyper tmp variable */
7189 osi_hyper_t bufferOffset;
7190 afs_uint32 bufIndex; /* index in buffer where our data is */
7191 int doWriteBack = 0;
7192 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7195 int needSyncOpDone = 0;
7197 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7198 fidp->fid, offsetp->LowPart, count);
7202 lock_ObtainMutex(&fidp->mx);
7203 /* make sure we have a writable FD */
7204 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7205 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7206 fidp->fid, fidp->flags);
7207 lock_ReleaseMutex(&fidp->mx);
7208 code = CM_ERROR_BADFDOP;
7216 lock_ReleaseMutex(&fidp->mx);
7218 lock_ObtainWrite(&scp->rw);
7219 /* start by looking up the file's end */
7220 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7221 CM_SCACHESYNC_NEEDCALLBACK
7222 | CM_SCACHESYNC_SETSTATUS
7223 | CM_SCACHESYNC_GETSTATUS);
7227 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7229 /* now we have the entry locked, look up the length */
7230 fileLength = scp->length;
7231 minLength = fileLength;
7232 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7233 minLength = scp->serverLength;
7235 /* adjust file length if we extend past EOF */
7236 thyper.LowPart = count;
7237 thyper.HighPart = 0;
7238 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7239 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7240 /* we'd write past EOF, so extend the file */
7241 scp->mask |= CM_SCACHEMASK_LENGTH;
7242 scp->length = thyper;
7243 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7245 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7247 /* now, if the new position (thyper) and the old (offset) are in
7248 * different storeback windows, remember to store back the previous
7249 * storeback window when we're done with the write.
7251 * the purpose of this logic is to slow down the CIFS client
7252 * in order to avoid the client disconnecting during the CLOSE
7253 * operation if there are too many dirty buffers left to write
7254 * than can be accomplished during 45 seconds. This used to be
7255 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7256 * so that we can read larger amounts of data at a time.
7258 if (smb_AsyncStore == 1 &&
7259 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7260 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7261 /* they're different */
7263 writeBackOffset.HighPart = offset.HighPart;
7264 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7269 /* now, copy the data one buffer at a time, until we've filled the
7271 while (count != 0) {
7273 /* handle over quota or out of space */
7274 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7275 *writtenp = written;
7276 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7280 /* otherwise, load up a buffer of data */
7281 thyper.HighPart = offset.HighPart;
7282 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7283 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7286 if (needSyncOpDone) {
7287 cm_SyncOpDone(scp, bufferp,
7288 CM_SCACHESYNC_NEEDCALLBACK
7289 | CM_SCACHESYNC_WRITE
7290 | CM_SCACHESYNC_BUFLOCKED);
7293 lock_ReleaseMutex(&bufferp->mx);
7294 buf_Release(bufferp);
7297 lock_ReleaseWrite(&scp->rw);
7299 code = buf_Get(scp, &thyper, &req, &bufferp);
7301 lock_ObtainMutex(&bufferp->mx);
7302 lock_ObtainWrite(&scp->rw);
7303 if (code) goto done;
7305 bufferOffset = thyper;
7307 /* now get the data in the cache */
7309 if (!needSyncOpDone) {
7310 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7311 CM_SCACHESYNC_NEEDCALLBACK
7312 | CM_SCACHESYNC_WRITE
7313 | CM_SCACHESYNC_BUFLOCKED);
7320 /* If we're overwriting the entire buffer, or
7321 * if we're writing at or past EOF, mark the
7322 * buffer as current so we don't call
7323 * cm_GetBuffer. This skips the fetch from the
7324 * server in those cases where we're going to
7325 * obliterate all the data in the buffer anyway,
7326 * or in those cases where there is no useful
7327 * data at the server to start with.
7329 * Use minLength instead of scp->length, since
7330 * the latter has already been updated by this
7333 * The scp lock has been dropped multiple times
7334 * so the minLength must be refreshed before it
7338 minLength = scp->length;
7339 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7340 minLength = scp->serverLength;
7342 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7343 || LargeIntegerEqualTo(offset, bufferp->offset)
7344 && (count >= cm_data.buf_blockSize
7345 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7346 ConvertLongToLargeInteger(count)),
7348 if (count < cm_data.buf_blockSize
7349 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7350 memset(bufferp->datap, 0,
7351 cm_data.buf_blockSize);
7352 bufferp->dataVersion = scp->dataVersion;
7355 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7357 /* otherwise, load the buffer and try again */
7358 cm_SyncOpDone(scp, bufferp,
7359 CM_SCACHESYNC_NEEDCALLBACK
7360 | CM_SCACHESYNC_WRITE
7361 | CM_SCACHESYNC_BUFLOCKED);
7364 lock_ReleaseMutex(&bufferp->mx);
7365 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7367 lock_ReleaseWrite(&scp->rw);
7368 lock_ObtainMutex(&bufferp->mx);
7369 lock_ObtainWrite(&scp->rw);
7373 } /* if (wrong buffer) ... */
7375 /* now we have the right buffer loaded. Copy out the
7376 * data from here to the user's buffer.
7378 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7380 /* and figure out how many bytes we want from this buffer */
7381 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7383 nbytes = count; /* don't go past end of request */
7385 /* now copy the data */
7386 memcpy(bufferp->datap + bufIndex, op, nbytes);
7387 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7389 /* adjust counters, pointers, etc. */
7393 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7394 } /* while count != 0 */
7397 if (bufferp && needSyncOpDone) {
7398 cm_SyncOpDone(scp, bufferp,
7399 CM_SCACHESYNC_NEEDCALLBACK
7400 | CM_SCACHESYNC_WRITE
7401 | CM_SCACHESYNC_BUFLOCKED);
7404 lock_ReleaseWrite(&scp->rw);
7407 lock_ReleaseMutex(&bufferp->mx);
7408 buf_Release(bufferp);
7411 lock_ObtainMutex(&fidp->mx);
7412 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7413 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7415 lock_ReleaseMutex(&fidp->mx);
7416 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7417 fidp->NTopen_dscp, fidp->NTopen_pathp,
7420 lock_ReleaseMutex(&fidp->mx);
7424 if (smb_AsyncStore > 0) {
7428 lock_ObtainWrite(&scp->rw);
7429 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7431 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7432 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7434 lock_ReleaseWrite(&scp->rw);
7435 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7436 writeBackOffset.HighPart,
7437 smb_AsyncStoreSize, 0, userp);
7438 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7441 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7445 cm_ReleaseSCache(scp);
7448 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7449 fidp->fid, code, *writtenp);
7454 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7457 unsigned short count;
7459 unsigned short hint;
7460 long written = 0, total_written = 0;
7463 smb_t* smbp = (smb_t*) inp;
7467 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7469 int inDataBlockCount;
7471 fd = smb_GetSMBParm(inp, 0);
7472 count = smb_GetSMBParm(inp, 1);
7473 offset.HighPart = 0; /* too bad */
7474 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7475 hint = smb_GetSMBParm(inp, 4);
7477 op = smb_GetSMBData(inp, NULL);
7478 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7480 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7481 fd, offset.LowPart, count);
7483 fd = smb_ChainFID(fd, inp);
7484 fidp = smb_FindFID(vcp, fd, 0);
7486 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7488 return CM_ERROR_BADFD;
7491 lock_ObtainMutex(&fidp->mx);
7492 if (fidp->flags & SMB_FID_IOCTL) {
7493 lock_ReleaseMutex(&fidp->mx);
7494 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7495 smb_ReleaseFID(fidp);
7496 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7500 if (fidp->flags & SMB_FID_RPC) {
7501 lock_ReleaseMutex(&fidp->mx);
7502 code = smb_RPCWrite(fidp, vcp, inp, outp);
7503 smb_ReleaseFID(fidp);
7504 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7509 lock_ReleaseMutex(&fidp->mx);
7510 smb_ReleaseFID(fidp);
7511 return CM_ERROR_BADFD;
7514 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7515 lock_ReleaseMutex(&fidp->mx);
7516 smb_CloseFID(vcp, fidp, NULL, 0);
7517 smb_ReleaseFID(fidp);
7518 return CM_ERROR_NOSUCHFILE;
7523 lock_ReleaseMutex(&fidp->mx);
7524 userp = smb_GetUserFromVCP(vcp, inp);
7528 LARGE_INTEGER LOffset;
7529 LARGE_INTEGER LLength;
7532 key = cm_GenerateKey(vcp->vcID, pid, fd);
7534 LOffset.HighPart = offset.HighPart;
7535 LOffset.LowPart = offset.LowPart;
7536 LLength.HighPart = 0;
7537 LLength.LowPart = count;
7539 lock_ObtainWrite(&scp->rw);
7540 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7541 lock_ReleaseWrite(&scp->rw);
7544 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7549 /* special case: 0 bytes transferred means truncate to this position */
7553 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7557 truncAttr.mask = CM_ATTRMASK_LENGTH;
7558 truncAttr.length.LowPart = offset.LowPart;
7559 truncAttr.length.HighPart = 0;
7560 lock_ObtainMutex(&fidp->mx);
7561 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7562 fidp->flags |= SMB_FID_LENGTHSETDONE;
7563 lock_ReleaseMutex(&fidp->mx);
7564 smb_SetSMBParm(outp, 0, 0 /* count */);
7565 smb_SetSMBDataLength(outp, 0);
7570 * Work around bug in NT client
7572 * When copying a file, the NT client should first copy the data,
7573 * then copy the last write time. But sometimes the NT client does
7574 * these in the wrong order, so the data copies would inadvertently
7575 * cause the last write time to be overwritten. We try to detect this,
7576 * and don't set client mod time if we think that would go against the
7579 lock_ObtainMutex(&fidp->mx);
7580 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7581 lock_ObtainWrite(&fidp->scp->rw);
7582 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7583 fidp->scp->clientModTime = time(NULL);
7584 lock_ReleaseWrite(&fidp->scp->rw);
7586 lock_ReleaseMutex(&fidp->mx);
7589 while ( code == 0 && count > 0 ) {
7590 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7591 if (code == 0 && written == 0)
7592 code = CM_ERROR_PARTIALWRITE;
7594 offset = LargeIntegerAdd(offset,
7595 ConvertLongToLargeInteger(written));
7596 count -= (unsigned short)written;
7597 total_written += written;
7601 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7602 total_written, code);
7604 /* set the packet data length to 3 bytes for the data block header,
7605 * plus the size of the data.
7607 smb_SetSMBParm(outp, 0, total_written);
7608 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7609 smb_SetSMBParm(outp, 3, hint);
7610 smb_SetSMBDataLength(outp, 0);
7613 smb_ReleaseFID(fidp);
7614 cm_ReleaseUser(userp);
7615 cm_ReleaseSCache(scp);
7620 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7621 NCB *ncbp, raw_write_cont_t *rwcp)
7630 fd = smb_GetSMBParm(inp, 0);
7631 fidp = smb_FindFID(vcp, fd, 0);
7633 lock_ObtainMutex(&fidp->mx);
7635 lock_ReleaseMutex(&fidp->mx);
7636 smb_ReleaseFID(fidp);
7640 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7641 lock_ReleaseMutex(&fidp->mx);
7642 smb_CloseFID(vcp, fidp, NULL, 0);
7643 smb_ReleaseFID(fidp);
7646 lock_ReleaseMutex(&fidp->mx);
7648 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7649 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7651 userp = smb_GetUserFromVCP(vcp, inp);
7654 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7656 if (rwcp->writeMode & 0x1) { /* synchronous */
7659 smb_FormatResponsePacket(vcp, inp, outp);
7660 op = (smb_t *) outp;
7661 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7662 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7663 smb_SetSMBDataLength(outp, 0);
7664 smb_SendPacket(vcp, outp);
7665 smb_FreePacket(outp);
7667 else { /* asynchronous */
7668 lock_ObtainMutex(&fidp->mx);
7669 fidp->raw_writers--;
7670 if (fidp->raw_writers == 0)
7671 thrd_SetEvent(fidp->raw_write_event);
7672 lock_ReleaseMutex(&fidp->mx);
7675 /* Give back raw buffer */
7676 lock_ObtainMutex(&smb_RawBufLock);
7677 *((char **)rawBuf) = smb_RawBufs;
7678 smb_RawBufs = rawBuf;
7679 lock_ReleaseMutex(&smb_RawBufLock);
7681 smb_ReleaseFID(fidp);
7682 cm_ReleaseUser(userp);
7685 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7690 /* SMB_COM_WRITE_RAW */
7691 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7694 long count, written = 0, total_written = 0;
7698 smb_t *smbp = (smb_t*) inp;
7703 unsigned short writeMode;
7705 fd = smb_GetSMBParm(inp, 0);
7706 totalCount = smb_GetSMBParm(inp, 1);
7707 count = smb_GetSMBParm(inp, 10);
7708 writeMode = smb_GetSMBParm(inp, 7);
7710 op = (char *) inp->data;
7711 op += smb_GetSMBParm(inp, 11);
7713 offset.HighPart = 0;
7714 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7716 if (*inp->wctp == 14) {
7717 /* we received a 64-bit file offset */
7718 #ifdef AFS_LARGEFILES
7719 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7721 if (LargeIntegerLessThanZero(offset)) {
7723 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7724 offset.HighPart, offset.LowPart);
7725 return CM_ERROR_BADSMB;
7728 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7730 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7731 return CM_ERROR_BADSMB;
7734 offset.HighPart = 0;
7737 offset.HighPart = 0; /* 32-bit file offset */
7741 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7742 fd, offset.HighPart, offset.LowPart, count);
7744 " WriteRaw WriteMode 0x%x",
7747 fd = smb_ChainFID(fd, inp);
7748 fidp = smb_FindFID(vcp, fd, 0);
7750 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7752 return CM_ERROR_BADFD;
7754 lock_ObtainMutex(&fidp->mx);
7756 lock_ReleaseMutex(&fidp->mx);
7757 smb_ReleaseFID(fidp);
7758 return CM_ERROR_BADFD;
7761 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7762 lock_ReleaseMutex(&fidp->mx);
7763 smb_CloseFID(vcp, fidp, NULL, 0);
7764 smb_ReleaseFID(fidp);
7765 return CM_ERROR_NOSUCHFILE;
7770 lock_ReleaseMutex(&fidp->mx);
7775 LARGE_INTEGER LOffset;
7776 LARGE_INTEGER LLength;
7779 key = cm_GenerateKey(vcp->vcID, pid, fd);
7781 LOffset.HighPart = offset.HighPart;
7782 LOffset.LowPart = offset.LowPart;
7783 LLength.HighPart = 0;
7784 LLength.LowPart = count;
7786 lock_ObtainWrite(&scp->rw);
7787 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7788 lock_ReleaseWrite(&scp->rw);
7791 cm_ReleaseSCache(scp);
7792 smb_ReleaseFID(fidp);
7797 userp = smb_GetUserFromVCP(vcp, inp);
7800 * Work around bug in NT client
7802 * When copying a file, the NT client should first copy the data,
7803 * then copy the last write time. But sometimes the NT client does
7804 * these in the wrong order, so the data copies would inadvertently
7805 * cause the last write time to be overwritten. We try to detect this,
7806 * and don't set client mod time if we think that would go against the
7809 lock_ObtainMutex(&fidp->mx);
7810 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7811 lock_ObtainWrite(&fidp->scp->rw);
7812 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7813 fidp->scp->clientModTime = time(NULL);
7814 lock_ReleaseWrite(&fidp->scp->rw);
7816 lock_ReleaseMutex(&fidp->mx);
7819 while ( code == 0 && count > 0 ) {
7820 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7821 if (code == 0 && written == 0)
7822 code = CM_ERROR_PARTIALWRITE;
7824 offset = LargeIntegerAdd(offset,
7825 ConvertLongToLargeInteger(written));
7828 total_written += written;
7832 /* Get a raw buffer */
7835 lock_ObtainMutex(&smb_RawBufLock);
7837 /* Get a raw buf, from head of list */
7838 rawBuf = smb_RawBufs;
7839 smb_RawBufs = *(char **)smb_RawBufs;
7842 code = CM_ERROR_USESTD;
7844 lock_ReleaseMutex(&smb_RawBufLock);
7847 /* Don't allow a premature Close */
7848 if (code == 0 && (writeMode & 1) == 0) {
7849 lock_ObtainMutex(&fidp->mx);
7850 fidp->raw_writers++;
7851 thrd_ResetEvent(fidp->raw_write_event);
7852 lock_ReleaseMutex(&fidp->mx);
7855 smb_ReleaseFID(fidp);
7856 cm_ReleaseUser(userp);
7857 cm_ReleaseSCache(scp);
7860 smb_SetSMBParm(outp, 0, total_written);
7861 smb_SetSMBDataLength(outp, 0);
7862 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7867 offset = LargeIntegerAdd(offset,
7868 ConvertLongToLargeInteger(count));
7872 rwcp->offset.HighPart = offset.HighPart;
7873 rwcp->offset.LowPart = offset.LowPart;
7874 rwcp->count = totalCount - count;
7875 rwcp->writeMode = writeMode;
7876 rwcp->alreadyWritten = total_written;
7878 /* set the packet data length to 3 bytes for the data block header,
7879 * plus the size of the data.
7881 smb_SetSMBParm(outp, 0, 0xffff);
7882 smb_SetSMBDataLength(outp, 0);
7888 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7891 long count, finalCount;
7895 smb_t *smbp = (smb_t*) inp;
7901 fd = smb_GetSMBParm(inp, 0);
7902 count = smb_GetSMBParm(inp, 1);
7903 offset.HighPart = 0; /* too bad */
7904 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7906 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7907 fd, offset.LowPart, count);
7909 fd = smb_ChainFID(fd, inp);
7910 fidp = smb_FindFID(vcp, fd, 0);
7912 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7914 return CM_ERROR_BADFD;
7916 lock_ObtainMutex(&fidp->mx);
7917 if (fidp->flags & SMB_FID_IOCTL) {
7918 lock_ReleaseMutex(&fidp->mx);
7919 code = smb_IoctlRead(fidp, vcp, inp, outp);
7920 smb_ReleaseFID(fidp);
7924 if (fidp->flags & SMB_FID_RPC) {
7925 lock_ReleaseMutex(&fidp->mx);
7926 code = smb_RPCRead(fidp, vcp, inp, outp);
7927 smb_ReleaseFID(fidp);
7932 lock_ReleaseMutex(&fidp->mx);
7933 smb_ReleaseFID(fidp);
7934 return CM_ERROR_BADFD;
7937 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7938 lock_ReleaseMutex(&fidp->mx);
7939 smb_CloseFID(vcp, fidp, NULL, 0);
7940 smb_ReleaseFID(fidp);
7941 return CM_ERROR_NOSUCHFILE;
7946 lock_ReleaseMutex(&fidp->mx);
7949 LARGE_INTEGER LOffset, LLength;
7953 key = cm_GenerateKey(vcp->vcID, pid, fd);
7955 LOffset.HighPart = 0;
7956 LOffset.LowPart = offset.LowPart;
7957 LLength.HighPart = 0;
7958 LLength.LowPart = count;
7960 lock_ObtainWrite(&scp->rw);
7961 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7962 lock_ReleaseWrite(&scp->rw);
7965 cm_ReleaseSCache(scp);
7966 smb_ReleaseFID(fidp);
7970 userp = smb_GetUserFromVCP(vcp, inp);
7972 /* remember this for final results */
7973 smb_SetSMBParm(outp, 0, count);
7974 smb_SetSMBParm(outp, 1, 0);
7975 smb_SetSMBParm(outp, 2, 0);
7976 smb_SetSMBParm(outp, 3, 0);
7977 smb_SetSMBParm(outp, 4, 0);
7979 /* set the packet data length to 3 bytes for the data block header,
7980 * plus the size of the data.
7982 smb_SetSMBDataLength(outp, count+3);
7984 /* get op ptr after putting in the parms, since otherwise we don't
7985 * know where the data really is.
7987 op = smb_GetSMBData(outp, NULL);
7989 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7990 *op++ = 1; /* data block marker */
7991 *op++ = (unsigned char) (count & 0xff);
7992 *op++ = (unsigned char) ((count >> 8) & 0xff);
7994 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7996 /* fix some things up */
7997 smb_SetSMBParm(outp, 0, finalCount);
7998 smb_SetSMBDataLength(outp, finalCount+3);
8000 smb_ReleaseFID(fidp);
8002 cm_ReleaseUser(userp);
8003 cm_ReleaseSCache(scp);
8007 /* SMB_COM_CREATE_DIRECTORY */
8008 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8010 clientchar_t *pathp;
8015 cm_scache_t *dscp; /* dir we're dealing with */
8016 cm_scache_t *scp; /* file we're creating */
8018 int initialModeBits;
8019 clientchar_t *lastNamep;
8021 clientchar_t *tidPathp;
8028 /* compute initial mode bits based on read-only flag in attributes */
8029 initialModeBits = 0777;
8031 tp = smb_GetSMBData(inp, NULL);
8032 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8034 return CM_ERROR_BADSMB;
8036 spacep = inp->spacep;
8037 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8039 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8040 return CM_ERROR_EXISTS;
8042 userp = smb_GetUserFromVCP(vcp, inp);
8044 caseFold = CM_FLAG_CASEFOLD;
8046 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8048 cm_ReleaseUser(userp);
8049 return CM_ERROR_NOSUCHPATH;
8052 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
8053 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8054 userp, tidPathp, &req, &dscp);
8057 cm_ReleaseUser(userp);
8062 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8063 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8064 cm_ReleaseSCache(dscp);
8065 cm_ReleaseUser(userp);
8066 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8067 return CM_ERROR_PATH_NOT_COVERED;
8069 return CM_ERROR_NOSUCHPATH;
8071 #endif /* DFS_SUPPORT */
8073 /* otherwise, scp points to the parent directory. Do a lookup, and
8074 * fail if we find it. Otherwise, we do the create.
8080 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8081 if (scp) cm_ReleaseSCache(scp);
8082 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8083 if (code == 0) code = CM_ERROR_EXISTS;
8084 cm_ReleaseSCache(dscp);
8085 cm_ReleaseUser(userp);
8089 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8090 setAttr.clientModTime = time(NULL);
8091 smb_SetInitialModeBitsForDir(0, &setAttr);
8093 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8094 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8095 smb_NotifyChange(FILE_ACTION_ADDED,
8096 FILE_NOTIFY_CHANGE_DIR_NAME,
8097 dscp, lastNamep, NULL, TRUE);
8099 /* we don't need this any longer */
8100 cm_ReleaseSCache(dscp);
8103 /* something went wrong creating or truncating the file */
8104 cm_ReleaseUser(userp);
8108 /* otherwise we succeeded */
8109 smb_SetSMBDataLength(outp, 0);
8110 cm_ReleaseUser(userp);
8115 BOOL smb_IsLegalFilename(clientchar_t *filename)
8118 * Find the longest substring of filename that does not contain
8119 * any of the chars in illegalChars. If that substring is less
8120 * than the length of the whole string, then one or more of the
8121 * illegal chars is in filename.
8123 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8129 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8130 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8132 clientchar_t *pathp;
8138 cm_scache_t *dscp; /* dir we're dealing with */
8139 cm_scache_t *scp; /* file we're creating */
8143 clientchar_t *lastNamep;
8146 clientchar_t *tidPathp;
8148 int created = 0; /* the file was new */
8153 excl = (inp->inCom == 0x03)? 0 : 1;
8155 attributes = smb_GetSMBParm(inp, 0);
8156 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8158 tp = smb_GetSMBData(inp, NULL);
8159 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8161 return CM_ERROR_BADSMB;
8163 spacep = inp->spacep;
8164 /* smb_StripLastComponent will strip "::$DATA" if present */
8165 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8167 if (!cm_IsValidClientString(pathp)) {
8169 clientchar_t * hexp;
8171 hexp = cm_GetRawCharsAlloc(pathp, -1);
8172 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8173 osi_LogSaveClientString(smb_logp, hexp));
8177 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8179 return CM_ERROR_BADNTFILENAME;
8182 userp = smb_GetUserFromVCP(vcp, inp);
8184 caseFold = CM_FLAG_CASEFOLD;
8186 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8188 cm_ReleaseUser(userp);
8189 return CM_ERROR_NOSUCHPATH;
8191 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8192 userp, tidPathp, &req, &dscp);
8195 cm_ReleaseUser(userp);
8200 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8201 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8202 cm_ReleaseSCache(dscp);
8203 cm_ReleaseUser(userp);
8204 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8205 return CM_ERROR_PATH_NOT_COVERED;
8207 return CM_ERROR_NOSUCHPATH;
8209 #endif /* DFS_SUPPORT */
8211 /* otherwise, scp points to the parent directory. Do a lookup, and
8212 * truncate the file if we find it, otherwise we create the file.
8219 if (!smb_IsLegalFilename(lastNamep))
8220 return CM_ERROR_BADNTFILENAME;
8222 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8223 #ifdef DEBUG_VERBOSE
8226 hexp = osi_HexifyString( lastNamep );
8227 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8232 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8233 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8234 cm_ReleaseSCache(dscp);
8235 cm_ReleaseUser(userp);
8239 /* if we get here, if code is 0, the file exists and is represented by
8240 * scp. Otherwise, we have to create it.
8244 /* oops, file shouldn't be there */
8245 cm_ReleaseSCache(dscp);
8246 cm_ReleaseSCache(scp);
8247 cm_ReleaseUser(userp);
8248 return CM_ERROR_EXISTS;
8251 setAttr.mask = CM_ATTRMASK_LENGTH;
8252 setAttr.length.LowPart = 0;
8253 setAttr.length.HighPart = 0;
8254 code = cm_SetAttr(scp, &setAttr, userp, &req);
8257 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8258 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8259 smb_SetInitialModeBitsForFile(attributes, &setAttr);
8261 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8265 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8266 smb_NotifyChange(FILE_ACTION_ADDED,
8267 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8268 dscp, lastNamep, NULL, TRUE);
8269 } else if (!excl && code == CM_ERROR_EXISTS) {
8270 /* not an exclusive create, and someone else tried
8271 * creating it already, then we open it anyway. We
8272 * don't bother retrying after this, since if this next
8273 * fails, that means that the file was deleted after
8274 * we started this call.
8276 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8279 setAttr.mask = CM_ATTRMASK_LENGTH;
8280 setAttr.length.LowPart = 0;
8281 setAttr.length.HighPart = 0;
8282 code = cm_SetAttr(scp, &setAttr, userp, &req);
8287 /* we don't need this any longer */
8288 cm_ReleaseSCache(dscp);
8291 /* something went wrong creating or truncating the file */
8292 if (scp) cm_ReleaseSCache(scp);
8293 cm_ReleaseUser(userp);
8297 /* make sure we only open files */
8298 if (scp->fileType != CM_SCACHETYPE_FILE) {
8299 cm_ReleaseSCache(scp);
8300 cm_ReleaseUser(userp);
8301 return CM_ERROR_ISDIR;
8304 /* now all we have to do is open the file itself */
8305 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8306 osi_assertx(fidp, "null smb_fid_t");
8310 lock_ObtainMutex(&fidp->mx);
8311 /* always create it open for read/write */
8312 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8314 /* remember that the file was newly created */
8316 fidp->flags |= SMB_FID_CREATED;
8318 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8320 /* save a pointer to the vnode */
8322 lock_ObtainWrite(&scp->rw);
8323 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8324 lock_ReleaseWrite(&scp->rw);
8327 fidp->userp = userp;
8328 lock_ReleaseMutex(&fidp->mx);
8330 smb_SetSMBParm(outp, 0, fidp->fid);
8331 smb_SetSMBDataLength(outp, 0);
8333 cm_Open(scp, 0, userp);
8335 smb_ReleaseFID(fidp);
8336 cm_ReleaseUser(userp);
8337 /* leave scp held since we put it in fidp->scp */
8342 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8345 osi_hyper_t new_offset;
8356 fd = smb_GetSMBParm(inp, 0);
8357 whence = smb_GetSMBParm(inp, 1);
8358 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8360 /* try to find the file descriptor */
8361 fd = smb_ChainFID(fd, inp);
8362 fidp = smb_FindFID(vcp, fd, 0);
8364 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8366 return CM_ERROR_BADFD;
8368 lock_ObtainMutex(&fidp->mx);
8369 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8370 lock_ReleaseMutex(&fidp->mx);
8371 smb_ReleaseFID(fidp);
8372 return CM_ERROR_BADFD;
8375 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8376 lock_ReleaseMutex(&fidp->mx);
8377 smb_CloseFID(vcp, fidp, NULL, 0);
8378 smb_ReleaseFID(fidp);
8379 return CM_ERROR_NOSUCHFILE;
8382 lock_ReleaseMutex(&fidp->mx);
8384 userp = smb_GetUserFromVCP(vcp, inp);
8386 lock_ObtainMutex(&fidp->mx);
8389 lock_ReleaseMutex(&fidp->mx);
8390 lock_ObtainWrite(&scp->rw);
8391 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8392 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8394 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8396 /* offset from current offset */
8397 new_offset = LargeIntegerAdd(fidp->offset,
8398 ConvertLongToLargeInteger(offset));
8400 else if (whence == 2) {
8401 /* offset from current EOF */
8402 new_offset = LargeIntegerAdd(scp->length,
8403 ConvertLongToLargeInteger(offset));
8405 new_offset = ConvertLongToLargeInteger(offset);
8408 fidp->offset = new_offset;
8409 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8410 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8411 smb_SetSMBDataLength(outp, 0);
8413 lock_ReleaseWrite(&scp->rw);
8414 smb_ReleaseFID(fidp);
8415 cm_ReleaseSCache(scp);
8416 cm_ReleaseUser(userp);
8420 /* dispatch all of the requests received in a packet. Due to chaining, this may
8421 * be more than one request.
8423 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8424 NCB *ncbp, raw_write_cont_t *rwcp)
8428 unsigned long code = 0;
8429 unsigned char *outWctp;
8430 int nparms; /* # of bytes of parameters */
8432 int nbytes; /* bytes of data, excluding count */
8435 unsigned short errCode;
8436 unsigned long NTStatus;
8438 unsigned char errClass;
8439 unsigned int oldGen;
8440 DWORD oldTime, newTime;
8442 /* get easy pointer to the data */
8443 smbp = (smb_t *) inp->data;
8445 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8446 /* setup the basic parms for the initial request in the packet */
8447 inp->inCom = smbp->com;
8448 inp->wctp = &smbp->wct;
8450 inp->ncb_length = ncbp->ncb_length;
8455 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8456 /* log it and discard it */
8457 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8458 __FILE__, __LINE__, ncbp->ncb_length);
8459 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8463 /* We are an ongoing op */
8464 thrd_Increment(&ongoingOps);
8466 /* set up response packet for receiving output */
8467 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8468 smb_FormatResponsePacket(vcp, inp, outp);
8469 outWctp = outp->wctp;
8471 /* Remember session generation number and time */
8472 oldGen = sessionGen;
8473 oldTime = GetTickCount();
8475 while (inp->inCom != 0xff) {
8476 dp = &smb_dispatchTable[inp->inCom];
8478 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8479 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8480 code = outp->resumeCode;
8484 /* process each request in the packet; inCom, wctp and inCount
8485 * are already set up.
8487 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8490 /* now do the dispatch */
8491 /* start by formatting the response record a little, as a default */
8492 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8494 outWctp[1] = 0xff; /* no operation */
8495 outWctp[2] = 0; /* padding */
8500 /* not a chained request, this is a more reasonable default */
8501 outWctp[0] = 0; /* wct of zero */
8502 outWctp[1] = 0; /* and bcc (word) of zero */
8506 /* once set, stays set. Doesn't matter, since we never chain
8507 * "no response" calls.
8509 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8513 /* we have a recognized operation */
8514 char * opName = myCrt_Dispatch(inp->inCom);
8517 smbp = (smb_t *) inp;
8519 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8520 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8521 if (inp->inCom == 0x1d) {
8523 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8525 code = (*(dp->procp)) (vcp, inp, outp);
8527 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8528 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8530 newTime = GetTickCount();
8531 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8532 opName, smbp->mid, newTime - oldTime);
8535 if ( code == CM_ERROR_BADSMB ||
8536 code == CM_ERROR_BADOP )
8538 #endif /* LOG_PACKET */
8540 /* ReceiveV3Tran2A handles its own logging */
8541 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8544 clientchar_t *treepath = NULL; /* do not free */
8545 clientchar_t *pathname = NULL;
8546 cm_fid_t afid = {0,0,0,0,0};
8548 uidp = smb_FindUID(vcp, smbp->uid, 0);
8549 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8550 fidp = smb_FindFID(vcp, inp->fid, 0);
8553 lock_ObtainMutex(&fidp->mx);
8554 if (fidp->NTopen_pathp)
8555 pathname = fidp->NTopen_pathp;
8557 afid = fidp->scp->fid;
8559 if (inp->stringsp->wdata)
8560 pathname = inp->stringsp->wdata;
8563 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)",
8564 opName, newTime - oldTime,
8565 smbp->uid, uidp ? uidp->unp->name : NULL,
8566 smbp->pid, smbp->mid, smbp->tid,
8569 afid.cell, afid.volume, afid.vnode, afid.unique);
8572 lock_ReleaseMutex(&fidp->mx);
8575 smb_ReleaseUID(uidp);
8577 smb_ReleaseFID(fidp);
8580 if (oldGen != sessionGen) {
8581 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8582 newTime - oldTime, ncbp->ncb_length);
8583 osi_Log3(smb_logp, "Request %s straddled session startup, "
8584 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8587 FreeSMBStrings(inp);
8589 /* bad opcode, fail the request, after displaying it */
8590 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8593 #endif /* LOG_PACKET */
8596 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8597 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8598 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8599 if (code == IDCANCEL)
8602 code = CM_ERROR_BADOP;
8605 /* catastrophic failure: log as much as possible */
8606 if (code == CM_ERROR_BADSMB) {
8607 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8611 #endif /* LOG_PACKET */
8612 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8615 code = CM_ERROR_INVAL;
8618 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8619 thrd_Decrement(&ongoingOps);
8624 /* now, if we failed, turn the current response into an empty
8625 * one, and fill in the response packet's error code.
8628 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8629 smb_MapNTError(code, &NTStatus);
8630 outWctp = outp->wctp;
8631 smbp = (smb_t *) &outp->data;
8632 if (code != CM_ERROR_PARTIALWRITE
8633 && code != CM_ERROR_BUFFERTOOSMALL
8634 && code != CM_ERROR_GSSCONTINUE) {
8635 /* nuke wct and bcc. For a partial
8636 * write or an in-process authentication handshake,
8637 * assume they're OK.
8643 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8644 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8645 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8646 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8647 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8651 smb_MapCoreError(code, vcp, &errCode, &errClass);
8652 outWctp = outp->wctp;
8653 smbp = (smb_t *) &outp->data;
8654 if (code != CM_ERROR_PARTIALWRITE) {
8655 /* nuke wct and bcc. For a partial
8656 * write, assume they're OK.
8662 smbp->errLow = (unsigned char) (errCode & 0xff);
8663 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8664 smbp->rcls = errClass;
8667 } /* error occurred */
8669 /* if we're here, we've finished one request. Look to see if
8670 * this is a chained opcode. If it is, setup things to process
8671 * the chained request, and setup the output buffer to hold the
8672 * chained response. Start by finding the next input record.
8674 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8675 break; /* not a chained req */
8676 tp = inp->wctp; /* points to start of last request */
8677 /* in a chained request, the first two
8678 * parm fields are required, and are
8679 * AndXCommand/AndXReserved and
8681 if (tp[0] < 2) break;
8682 if (tp[1] == 0xff) break; /* no more chained opcodes */
8684 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8687 /* and now append the next output request to the end of this
8688 * last request. Begin by finding out where the last response
8689 * ends, since that's where we'll put our new response.
8691 outWctp = outp->wctp; /* ptr to out parameters */
8692 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8693 nparms = outWctp[0] << 1;
8694 tp = outWctp + nparms + 1; /* now points to bcc field */
8695 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8696 tp += 2 /* for the count itself */ + nbytes;
8697 /* tp now points to the new output record; go back and patch the
8698 * second parameter (off2) to point to the new record.
8700 temp = (unsigned int)(tp - outp->data);
8701 outWctp[3] = (unsigned char) (temp & 0xff);
8702 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8703 outWctp[2] = 0; /* padding */
8704 outWctp[1] = inp->inCom; /* next opcode */
8706 /* finally, setup for the next iteration */
8709 } /* while loop over all requests in the packet */
8711 /* now send the output packet, and return */
8713 smb_SendPacket(vcp, outp);
8714 thrd_Decrement(&ongoingOps);
8719 /* Wait for Netbios() calls to return, and make the results available to server
8720 * threads. Note that server threads can't wait on the NCBevents array
8721 * themselves, because NCB events are manual-reset, and the servers would race
8722 * each other to reset them.
8724 void smb_ClientWaiter(void *parmp)
8729 while (smbShutdownFlag == 0) {
8730 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8732 if (code == WAIT_OBJECT_0)
8735 /* error checking */
8736 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8738 int abandonIdx = code - WAIT_ABANDONED_0;
8739 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8742 if (code == WAIT_IO_COMPLETION)
8744 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8748 if (code == WAIT_TIMEOUT)
8750 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8753 if (code == WAIT_FAILED)
8755 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8758 idx = code - WAIT_OBJECT_0;
8760 /* check idx range! */
8761 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8763 /* this is fatal - log as much as possible */
8764 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8765 osi_assertx(0, "invalid index");
8768 thrd_ResetEvent(NCBevents[idx]);
8769 thrd_SetEvent(NCBreturns[0][idx]);
8774 * Try to have one NCBRECV request waiting for every live session. Not more
8775 * than one, because if there is more than one, it's hard to handle Write Raw.
8777 void smb_ServerWaiter(void *parmp)
8780 int idx_session, idx_NCB;
8783 while (smbShutdownFlag == 0) {
8785 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8787 if (code == WAIT_OBJECT_0)
8790 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8792 int abandonIdx = code - WAIT_ABANDONED_0;
8793 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8796 if (code == WAIT_IO_COMPLETION)
8798 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8802 if (code == WAIT_TIMEOUT)
8804 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8807 if (code == WAIT_FAILED)
8809 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8812 idx_session = code - WAIT_OBJECT_0;
8814 /* check idx range! */
8815 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8817 /* this is fatal - log as much as possible */
8818 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8819 osi_assertx(0, "invalid index");
8824 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8826 if (code == WAIT_OBJECT_0) {
8827 if (smbShutdownFlag == 1)
8833 /* error checking */
8834 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8836 int abandonIdx = code - WAIT_ABANDONED_0;
8837 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8840 if (code == WAIT_IO_COMPLETION)
8842 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8846 if (code == WAIT_TIMEOUT)
8848 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8851 if (code == WAIT_FAILED)
8853 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8856 idx_NCB = code - WAIT_OBJECT_0;
8858 /* check idx range! */
8859 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8861 /* this is fatal - log as much as possible */
8862 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8863 osi_assertx(0, "invalid index");
8866 /* Link them together */
8867 NCBsessions[idx_NCB] = idx_session;
8870 ncbp = NCBs[idx_NCB];
8871 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8872 ncbp->ncb_command = NCBRECV | ASYNCH;
8873 ncbp->ncb_lana_num = lanas[idx_session];
8874 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8875 ncbp->ncb_event = NCBevents[idx_NCB];
8876 ncbp->ncb_length = SMB_PACKETSIZE;
8881 typedef struct _monitored_task {
8884 LARGE_INTEGER start_time;
8886 BOOL trace_timer_hit;
8887 BOOL dump_timer_hit;
8890 typedef struct osi_queueHT {
8891 osi_queue_t * headp;
8892 osi_queue_t * tailp;
8895 static osi_queue_t *smb_monitored_tasks = NULL;
8896 static osi_queue_t *smb_free_monitored_tasks = NULL;
8898 static osi_mutex_t _monitor_mx;
8900 static HANDLE h_monitored_task_queue = NULL;
8901 static HANDLE h_monitored_task_shutdown = NULL;
8903 static time_t smb_last_dump_time = 0;
8905 DWORD smb_monitorReqs = 0;
8907 /* FILETIME comparison fuzz */
8908 #define MONITOR_FUZZ_TIMEOUT (1 * 10000000i64)
8910 /* Trace timeout is at 60 seconds */
8911 #define MONITOR_TRACE_TIMEOUT (60 * 10000000i64)
8913 /* Dump timeout is at 120 seconds */
8914 #define MONITOR_DUMP_TIMEOUT (120 * 10000000i64)
8916 /* Time before another dump is performed in seconds*/
8917 #define MONITOR_DUMP_RESET_TIMEOUT (600)
8919 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
8922 LARGE_INTEGER earliest;
8925 GetSystemTimeAsFileTime(&now);
8926 earliest.LowPart = now.dwLowDateTime;
8927 earliest.HighPart = now.dwHighDateTime;
8928 earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
8930 while ((t = (monitored_task *) taskmq->headp) != NULL &&
8932 (t->start_time.QuadPart < earliest.QuadPart ||
8934 t->dump_timer_hit)) {
8936 osi_QRemoveHT(&taskmq->headp,
8940 lock_ObtainMutex(&_monitor_mx);
8941 osi_QAdd(&smb_free_monitored_tasks, &t->q);
8942 lock_ReleaseMutex(&_monitor_mx);
8945 #ifdef INVARIANT_CHECK
8951 for (t = (monitored_task *) taskmq->headp;
8953 t = (monitored_task *) osi_QNext(&t->q)) {
8954 osi_assert(last.QuadPart <= t->start_time.QuadPart);
8955 last.QuadPart = t->start_time.QuadPart;
8961 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
8963 monitored_task * task;
8964 monitored_task * tasks;
8966 lock_ObtainMutex(&_monitor_mx);
8967 tasks = (monitored_task *) smb_monitored_tasks;
8968 smb_monitored_tasks = NULL;
8969 lock_ReleaseMutex(&_monitor_mx);
8974 osi_QRemove((osi_queue_t **) &tasks, &task->q);
8976 if (task->started) {
8982 q.prevp = taskmq->tailp;
8984 /* Insertion sort by start_time. Earliest request is
8985 first. Since we are likely to receive new requests
8986 later, we start inserting from the back. */
8989 ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
8993 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
8994 else if (p->prevp == NULL)
8995 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
8997 osi_queue_t *o = p->prevp;
8999 osi_assert(o->nextp == p);
9003 p->prevp = &task->q;
9004 o->nextp = &task->q;
9008 /* Some task ending */
9012 for (p = taskmq->headp;
9016 monitored_task * mt = (monitored_task *) p;
9018 if (mt->task_id == task->task_id) {
9020 osi_QRemoveHT(&taskmq->headp,
9023 lock_ObtainMutex(&_monitor_mx);
9024 osi_QAdd(&smb_free_monitored_tasks, p);
9025 lock_ReleaseMutex(&_monitor_mx);
9031 lock_ObtainMutex(&_monitor_mx);
9032 osi_QAdd(&smb_free_monitored_tasks, &task->q);
9033 lock_ReleaseMutex(&_monitor_mx);
9037 #ifdef INVARIANT_CHECK
9044 for (t = (monitored_task *) taskmq->headp;
9046 t = (monitored_task *) osi_QNext(&t->q)) {
9047 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9048 last.QuadPart = t->start_time.QuadPart;
9054 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9056 if (!task->trace_timer_hit) {
9058 task->trace_timer_hit = TRUE;
9060 osi_LogEnable(afsd_logp);
9061 rx_DebugOnOff(TRUE);
9063 } else if (!task->dump_timer_hit) {
9068 if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9069 task->dump_timer_hit = TRUE;
9070 smb_last_dump_time = now;
9072 GenerateMiniDump(NULL);
9078 * Server request monitoring
9080 * The server monitor runs in a separate thread and monitors server
9081 * requests for potential timeouts. It examines notifcations queued
9082 * by smb_NotifyRequestEvent() and waits for potential timeout events:
9084 * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9085 * enables trace logging.
9087 * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9088 * out a dump file that will hopefully contain enough evidence to
9089 * figure out why the timeout event occurred.
9092 void smb_ServerMonitor(VOID * parmp)
9094 osi_queueHT_t in_progress = { NULL, NULL };
9095 HANDLE h_timer = NULL;
9099 h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9100 h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9101 h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9103 lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9105 h_all[0] = h_monitored_task_queue;
9107 h_all[2] = h_monitored_task_shutdown;
9112 rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9114 if (rv == WAIT_OBJECT_0) {
9116 smb_SlurpNewTaskMonitors(&in_progress);
9118 } else if (rv == WAIT_OBJECT_0 + 1) {
9120 smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9128 /* refresh timers */
9132 smb_PurgeOldTaskMonitors(&in_progress);
9133 t = (monitored_task *) in_progress.headp;
9135 if (t && !t->trace_timer_hit) {
9138 due = t->start_time;
9139 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9141 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9142 } else if (t && !t->dump_timer_hit) {
9146 due = t->start_time;
9147 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9149 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9151 CancelWaitableTimer(h_timer);
9153 /* CancelWaitableTimer() doesn't reset the timer if it
9154 was already signalled. */
9155 WaitForSingleObject(h_timer, 0);
9163 h = h_monitored_task_queue;
9164 h_monitored_task_queue = NULL;
9167 h = h_monitored_task_shutdown;
9168 h_monitored_task_shutdown = NULL;
9171 CloseHandle(h_timer);
9173 lock_FinalizeMutex(&_monitor_mx);
9177 monitored_task * task;
9179 while (in_progress.headp) {
9180 task = (monitored_task *) in_progress.headp;
9181 osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9185 for (task = (monitored_task *) smb_free_monitored_tasks;
9186 task; task = (monitored_task *) smb_free_monitored_tasks) {
9187 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9191 for (task = (monitored_task *) smb_monitored_tasks;
9192 task; task = (monitored_task *) smb_monitored_tasks) {
9193 osi_QRemove(&smb_monitored_tasks, &task->q);
9199 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9201 monitored_task * task;
9203 lock_ObtainMutex(&_monitor_mx);
9204 task = (monitored_task *) smb_free_monitored_tasks;
9206 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9207 lock_ReleaseMutex(&_monitor_mx);
9210 task = malloc(sizeof(monitored_task));
9211 memset(task, 0, sizeof(*task));
9213 task->task_id = task_id;
9214 task->started = started;
9219 GetSystemTimeAsFileTime(&now);
9220 task->start_time.HighPart = now.dwHighDateTime;
9221 task->start_time.LowPart = now.dwLowDateTime;
9224 lock_ObtainMutex(&_monitor_mx);
9225 osi_QAdd(&smb_monitored_tasks, &task->q);
9226 lock_ReleaseMutex(&_monitor_mx);
9228 SetEvent(h_monitored_task_queue);
9231 void smb_ShutdownMonitor()
9233 SetEvent(h_monitored_task_shutdown);
9237 * The top level loop for handling SMB request messages. Each server thread
9238 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9239 * NCB and buffer for the incoming request are loaned to us.
9241 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
9242 * to immediately send a request for the rest of the data. This must come
9243 * before any other traffic for that session, so we delay setting the session
9244 * event until that data has come in.
9246 void smb_Server(VOID *parmp)
9248 INT_PTR myIdx = (INT_PTR) parmp;
9252 smb_packet_t *outbufp;
9254 int idx_NCB, idx_session;
9256 smb_vc_t *vcp = NULL;
9258 extern void rx_StartClientThread(void);
9260 rx_StartClientThread();
9262 outncbp = smb_GetNCB();
9263 outbufp = smb_GetPacket();
9264 outbufp->ncbp = outncbp;
9272 cm_ResetServerPriority();
9274 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9277 /* terminate silently if shutdown flag is set */
9278 if (code == WAIT_OBJECT_0) {
9279 if (smbShutdownFlag == 1) {
9280 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9286 /* error checking */
9287 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9289 int abandonIdx = code - WAIT_ABANDONED_0;
9290 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9293 if (code == WAIT_IO_COMPLETION)
9295 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9299 if (code == WAIT_TIMEOUT)
9301 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9304 if (code == WAIT_FAILED)
9306 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9309 idx_NCB = code - WAIT_OBJECT_0;
9311 /* check idx range! */
9312 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9314 /* this is fatal - log as much as possible */
9315 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9316 osi_assertx(0, "invalid index");
9319 ncbp = NCBs[idx_NCB];
9320 idx_session = NCBsessions[idx_NCB];
9321 rc = ncbp->ncb_retcode;
9323 if (rc != NRC_PENDING && rc != NRC_GOODRET)
9324 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9328 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9332 /* Can this happen? Or is it just my UNIX paranoia? */
9333 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9338 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9341 /* Client closed session */
9342 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9344 lock_ObtainMutex(&vcp->mx);
9345 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9346 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9348 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9349 lock_ReleaseMutex(&vcp->mx);
9350 lock_ObtainWrite(&smb_globalLock);
9351 dead_sessions[vcp->session] = TRUE;
9352 lock_ReleaseWrite(&smb_globalLock);
9354 lock_ReleaseMutex(&vcp->mx);
9356 smb_CleanupDeadVC(vcp);
9363 /* Treat as transient error */
9364 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9367 "dispatch smb recv failed, message incomplete, ncb_length %d",
9370 "SMB message incomplete, "
9371 "length %d", ncbp->ncb_length);
9374 * We used to discard the packet.
9375 * Instead, try handling it normally.
9379 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9383 /* A weird error code. Log it, sleep, and continue. */
9384 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9386 lock_ObtainMutex(&vcp->mx);
9387 if (vcp->errorCount++ > 3) {
9388 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9389 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9390 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9392 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9393 lock_ReleaseMutex(&vcp->mx);
9394 lock_ObtainWrite(&smb_globalLock);
9395 dead_sessions[vcp->session] = TRUE;
9396 lock_ReleaseWrite(&smb_globalLock);
9398 lock_ReleaseMutex(&vcp->mx);
9400 smb_CleanupDeadVC(vcp);
9406 lock_ReleaseMutex(&vcp->mx);
9410 thrd_SetEvent(SessionEvents[idx_session]);
9416 /* Success, so now dispatch on all the data in the packet */
9418 smb_concurrentCalls++;
9419 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9420 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9423 * If at this point vcp is NULL (implies that packet was invalid)
9424 * then we are in big trouble. This means either :
9425 * a) we have the wrong NCB.
9426 * b) Netbios screwed up the call.
9427 * c) The VC was already marked dead before we were able to
9429 * Obviously this implies that
9430 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9431 * lanas[idx_session] != ncbp->ncb_lana_num )
9432 * Either way, we can't do anything with this packet.
9433 * Log, sleep and resume.
9436 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9440 ncbp->ncb_lana_num);
9442 /* Also log in the trace log. */
9443 osi_Log4(smb_logp, "Server: VCP does not exist!"
9444 "LSNs[idx_session]=[%d],"
9445 "lanas[idx_session]=[%d],"
9446 "ncbp->ncb_lsn=[%d],"
9447 "ncbp->ncb_lana_num=[%d]",
9451 ncbp->ncb_lana_num);
9453 /* thrd_Sleep(1000); Don't bother sleeping */
9454 thrd_SetEvent(SessionEvents[idx_session]);
9455 smb_concurrentCalls--;
9459 cm_SetRequestStartTime();
9460 if (smb_monitorReqs) {
9461 smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9464 vcp->errorCount = 0;
9465 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9466 smbp = (smb_t *)bufp->data;
9473 if (smbp->com == 0x1d) {
9474 /* Special handling for Write Raw */
9475 raw_write_cont_t rwc;
9477 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9478 if (rwc.code == 0) {
9479 EVENT_HANDLE rwevent;
9480 char eventName[MAX_PATH];
9482 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9483 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9484 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9485 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9487 ncbp->ncb_command = NCBRECV | ASYNCH;
9488 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9489 ncbp->ncb_lana_num = vcp->lana;
9490 ncbp->ncb_buffer = rwc.buf;
9491 ncbp->ncb_length = 65535;
9492 ncbp->ncb_event = rwevent;
9494 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9495 thrd_CloseHandle(rwevent);
9497 thrd_SetEvent(SessionEvents[idx_session]);
9499 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9501 else if (smbp->com == 0xa0) {
9503 * Serialize the handling for NT Transact
9506 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9507 thrd_SetEvent(SessionEvents[idx_session]);
9509 thrd_SetEvent(SessionEvents[idx_session]);
9510 /* TODO: what else needs to be serialized? */
9511 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9515 __except( smb_ServerExceptionFilter() ) {
9519 if (smb_monitorReqs) {
9520 smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9522 smb_concurrentCalls--;
9525 thrd_SetEvent(NCBavails[idx_NCB]);
9530 smb_FreePacket(outbufp);
9532 smb_FreeNCB(outncbp);
9536 * Exception filter for the server threads. If an exception occurs in the
9537 * dispatch routines, which is where exceptions are most common, then do a
9538 * force trace and give control to upstream exception handlers. Useful for
9541 DWORD smb_ServerExceptionFilter(void) {
9542 /* While this is not the best time to do a trace, if it succeeds, then
9543 * we have a trace (assuming tracing was enabled). Otherwise, this should
9544 * throw a second exception.
9546 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9547 afsd_ForceTrace(TRUE);
9548 buf_ForceTrace(TRUE);
9549 return EXCEPTION_CONTINUE_SEARCH;
9553 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9554 * If the number of server threads is M, and the number of live sessions is
9555 * N, then the number of NCB's in use at any time either waiting for, or
9556 * holding, received messages is M + N, so that is how many NCB's get created.
9558 void InitNCBslot(int idx)
9560 struct smb_packet *bufp;
9561 EVENT_HANDLE retHandle;
9563 char eventName[MAX_PATH];
9565 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9567 NCBs[idx] = smb_GetNCB();
9568 sprintf(eventName,"NCBavails[%d]", idx);
9569 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9570 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9571 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9572 sprintf(eventName,"NCBevents[%d]", idx);
9573 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9574 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9575 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9576 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9577 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9578 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9579 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9580 for (i=0; i<smb_NumServerThreads; i++)
9581 NCBreturns[i][idx] = retHandle;
9582 bufp = smb_GetPacket();
9583 bufp->spacep = cm_GetSpace();
9587 /* listen for new connections */
9588 void smb_Listener(void *parmp)
9594 afs_uint32 session, thread;
9595 smb_vc_t *vcp = NULL;
9597 char rname[NCBNAMSZ+1];
9598 char cname[MAX_COMPUTERNAME_LENGTH+1];
9599 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9600 INT_PTR lana = (INT_PTR) parmp;
9601 char eventName[MAX_PATH];
9602 int bridgeCount = 0;
9603 int nowildCount = 0;
9605 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9606 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9607 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9608 thrd_ResetEvent(ListenerShutdown[lana]);
9610 ncbp = smb_GetNCB();
9612 /* retrieve computer name */
9613 GetComputerName(cname, &cnamelen);
9616 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9617 memset(ncbp, 0, sizeof(NCB));
9620 ncbp->ncb_command = NCBLISTEN;
9621 ncbp->ncb_rto = 0; /* No receive timeout */
9622 ncbp->ncb_sto = 0; /* No send timeout */
9624 /* pad out with spaces instead of null termination */
9625 len = (long)strlen(smb_localNamep);
9626 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9627 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9629 strcpy(ncbp->ncb_callname, "*");
9630 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9632 ncbp->ncb_lana_num = (UCHAR)lana;
9634 code = Netbios(ncbp);
9636 if (code == NRC_NAMERR) {
9637 /* An smb shutdown or Vista resume must have taken place */
9639 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9640 ncbp->ncb_lana_num);
9641 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9643 if (lock_TryMutex(&smb_StartedLock)) {
9644 lana_list.lana[i] = LANA_INVALID;
9645 lock_ReleaseMutex(&smb_StartedLock);
9648 } else if (code == NRC_BRIDGE || code != 0) {
9649 int lanaRemaining = 0;
9651 if (code == NRC_BRIDGE) {
9652 if (++bridgeCount <= 5) {
9653 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9656 } else if (code == NRC_NOWILD) {
9657 if (++nowildCount <= 5) {
9658 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9660 if (bridgeCount > 0) {
9661 memset(ncbp, 0, sizeof(*ncbp));
9662 ncbp->ncb_command = NCBADDNAME;
9663 ncbp->ncb_lana_num = (UCHAR)lana;
9664 /* pad out with spaces instead of null termination */
9665 len = (long)strlen(smb_localNamep);
9666 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9667 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9668 code = Netbios(ncbp);
9674 while (!lock_TryMutex(&smb_StartedLock)) {
9675 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9681 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9682 ncbp->ncb_lana_num, ncb_error_string(code));
9683 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9684 ncbp->ncb_lana_num, ncb_error_string(code));
9686 for (i = 0; i < lana_list.length; i++) {
9687 if (lana_list.lana[i] == lana) {
9688 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9689 lana_list.lana[i] = LANA_INVALID;
9691 if (lana_list.lana[i] != LANA_INVALID)
9695 if (lanaRemaining == 0) {
9696 cm_VolStatus_Network_Stopped(cm_NetbiosName
9701 smb_ListenerState = SMB_LISTENER_STOPPED;
9702 smb_LANadapter = LANA_INVALID;
9703 lana_list.length = 0;
9705 lock_ReleaseMutex(&smb_StartedLock);
9709 else if (code != 0) {
9710 char tbuffer[AFSPATHMAX];
9712 /* terminate silently if shutdown flag is set */
9713 while (!lock_TryMutex(&smb_StartedLock)) {
9714 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9720 "NCBLISTEN lana=%d failed with code %d [%s]",
9721 ncbp->ncb_lana_num, code, ncb_error_string(code));
9723 "Client exiting due to network failure. Please restart client.\n");
9726 "Client exiting due to network failure. Please restart client.\n"
9727 "NCBLISTEN lana=%d failed with code %d [%s]",
9728 ncbp->ncb_lana_num, code, ncb_error_string(code));
9730 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9731 MB_OK|MB_SERVICE_NOTIFICATION);
9732 osi_panic(tbuffer, __FILE__, __LINE__);
9734 lock_ReleaseMutex(&smb_StartedLock);
9739 /* a successful packet received. clear bridge error count */
9743 /* check for remote conns */
9744 /* first get remote name and insert null terminator */
9745 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9746 for (i=NCBNAMSZ; i>0; i--) {
9747 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9753 /* compare with local name */
9755 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9756 flags |= SMB_VCFLAG_REMOTECONN;
9759 lock_ObtainMutex(&smb_ListenerLock);
9761 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9762 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9764 /* now ncbp->ncb_lsn is the connection ID */
9765 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9766 if (vcp->session == 0) {
9767 /* New generation */
9768 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9771 /* Log session startup */
9773 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9774 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9775 #endif /* NOTSERVICE */
9776 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9777 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9779 if (reportSessionStartups) {
9780 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9783 lock_ObtainMutex(&vcp->mx);
9784 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9785 vcp->flags |= flags;
9786 lock_ReleaseMutex(&vcp->mx);
9788 /* Allocate slot in session arrays */
9789 /* Re-use dead session if possible, otherwise add one more */
9790 /* But don't look at session[0], it is reserved */
9791 lock_ObtainWrite(&smb_globalLock);
9792 for (session = 1; session < numSessions; session++) {
9793 if (dead_sessions[session]) {
9794 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9795 dead_sessions[session] = FALSE;
9799 lock_ReleaseWrite(&smb_globalLock);
9801 /* We are re-using an existing VC because the lsn and lana
9803 session = vcp->session;
9805 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9807 /* Log session startup */
9809 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9810 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9811 #endif /* NOTSERVICE */
9812 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9813 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9815 if (reportSessionStartups) {
9816 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9820 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9821 unsigned long code = CM_ERROR_ALLBUSY;
9822 smb_packet_t * outp = smb_GetPacket();
9823 unsigned char *outWctp;
9826 smb_FormatResponsePacket(vcp, NULL, outp);
9829 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9830 unsigned long NTStatus;
9831 smb_MapNTError(code, &NTStatus);
9832 outWctp = outp->wctp;
9833 smbp = (smb_t *) &outp->data;
9837 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9838 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9839 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9840 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9841 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9843 unsigned short errCode;
9844 unsigned char errClass;
9845 smb_MapCoreError(code, vcp, &errCode, &errClass);
9846 outWctp = outp->wctp;
9847 smbp = (smb_t *) &outp->data;
9851 smbp->errLow = (unsigned char) (errCode & 0xff);
9852 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9853 smbp->rcls = errClass;
9856 smb_SendPacket(vcp, outp);
9857 smb_FreePacket(outp);
9859 lock_ObtainMutex(&vcp->mx);
9860 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9861 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9863 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9864 lock_ReleaseMutex(&vcp->mx);
9865 lock_ObtainWrite(&smb_globalLock);
9866 dead_sessions[vcp->session] = TRUE;
9867 lock_ReleaseWrite(&smb_globalLock);
9868 smb_CleanupDeadVC(vcp);
9870 lock_ReleaseMutex(&vcp->mx);
9873 /* assert that we do not exceed the maximum number of sessions or NCBs.
9874 * we should probably want to wait for a session to be freed in case
9877 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9878 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9880 lock_ObtainMutex(&vcp->mx);
9881 vcp->session = session;
9882 lock_ReleaseMutex(&vcp->mx);
9883 lock_ObtainWrite(&smb_globalLock);
9884 LSNs[session] = ncbp->ncb_lsn;
9885 lanas[session] = ncbp->ncb_lana_num;
9886 lock_ReleaseWrite(&smb_globalLock);
9888 if (session == numSessions) {
9889 /* Add new NCB for new session */
9890 char eventName[MAX_PATH];
9892 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9894 InitNCBslot(numNCBs);
9895 lock_ObtainWrite(&smb_globalLock);
9897 lock_ReleaseWrite(&smb_globalLock);
9898 thrd_SetEvent(NCBavails[0]);
9899 thrd_SetEvent(NCBevents[0]);
9900 for (thread = 0; thread < smb_NumServerThreads; thread++)
9901 thrd_SetEvent(NCBreturns[thread][0]);
9902 /* Also add new session event */
9903 sprintf(eventName, "SessionEvents[%d]", session);
9904 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9905 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9906 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9907 lock_ObtainWrite(&smb_globalLock);
9909 lock_ReleaseWrite(&smb_globalLock);
9910 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9911 thrd_SetEvent(SessionEvents[0]);
9913 thrd_SetEvent(SessionEvents[session]);
9919 lock_ReleaseMutex(&smb_ListenerLock);
9920 } /* dispatch while loop */
9924 thrd_SetEvent(ListenerShutdown[lana]);
9929 configureBackConnectionHostNames(void)
9931 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9932 * there is a restriction on the use of SMB authentication on loopback connections.
9933 * There are two work arounds available:
9935 * (1) We can disable the check for matching host names. This does not
9937 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9938 * "DisableLoopbackCheck"=dword:00000001
9940 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9941 * does require a reboot:
9942 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9943 * "BackConnectionHostNames"=multi-sz
9945 * The algorithm will be:
9946 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9947 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9948 * (2b1) and check to see if DisableLoopbackCheck is set.
9949 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9950 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9951 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9952 * check for the UnsetDisableLoopbackCheck value.
9953 * If set, set the DisableLoopbackCheck flag to 0x0
9954 * and delete the UnsetDisableLoopbackCheck value
9956 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9957 * force Windows to use the loopback authentication mechanism for the specified
9960 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9961 * service session that set it.
9967 DWORD dwSize, dwAllocSize;
9969 PBYTE pHostNames = NULL, pName = NULL;
9970 BOOL bNameFound = FALSE;
9971 static BOOL bLoopbackCheckDisabled = FALSE;
9973 /* BackConnectionHostNames and DisableLoopbackCheck */
9974 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9975 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9978 &hkMSV10) == ERROR_SUCCESS )
9980 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9981 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9982 (dwType == REG_MULTI_SZ))
9984 dwAllocSize += 1 /* in case the source string is not nul terminated */
9985 + (DWORD)strlen(cm_NetbiosName) + 2;
9986 pHostNames = malloc(dwAllocSize);
9987 dwSize = dwAllocSize;
9988 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9989 pHostNames, &dwSize) == ERROR_SUCCESS)
9991 for (pName = pHostNames;
9992 (pName - pHostNames < (int) dwSize) && *pName ;
9993 pName += strlen(pName) + 1)
9995 if ( !stricmp(pName, cm_NetbiosName) ) {
10003 if ( !bNameFound ) {
10004 size_t size = strlen(cm_NetbiosName) + 2;
10005 if ( !pHostNames ) {
10006 pHostNames = malloc(size);
10007 pName = pHostNames;
10009 StringCbCopyA(pName, size, cm_NetbiosName);
10011 *pName = '\0'; /* add a second nul terminator */
10013 dwType = REG_MULTI_SZ;
10014 dwSize = (DWORD)(pName - pHostNames + 1);
10015 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10017 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10018 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10020 KEY_READ|KEY_WRITE,
10021 &hkLsa) == ERROR_SUCCESS )
10023 dwSize = sizeof(DWORD);
10024 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
10026 dwType = REG_DWORD;
10027 dwSize = sizeof(DWORD);
10029 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10031 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10032 AFSREG_CLT_OPENAFS_SUBKEY,
10035 REG_OPTION_NON_VOLATILE,
10036 KEY_READ|KEY_WRITE,
10039 NULL) == ERROR_SUCCESS) {
10041 dwType = REG_DWORD;
10042 dwSize = sizeof(DWORD);
10044 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10045 bLoopbackCheckDisabled = TRUE;
10046 RegCloseKey(hkClient);
10048 RegCloseKey(hkLsa);
10051 } else if (!bLoopbackCheckDisabled) {
10052 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10053 AFSREG_CLT_OPENAFS_SUBKEY,
10056 REG_OPTION_NON_VOLATILE,
10057 KEY_READ|KEY_WRITE,
10060 NULL) == ERROR_SUCCESS) {
10062 dwSize = sizeof(DWORD);
10063 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10065 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10066 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10068 KEY_READ|KEY_WRITE,
10069 &hkLsa) == ERROR_SUCCESS )
10071 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10072 RegCloseKey(hkLsa);
10075 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10076 RegCloseKey(hkClient);
10085 RegCloseKey(hkMSV10);
10091 configureExtendedSMBSessionTimeouts(void)
10094 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10095 * new functionality:
10097 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
10098 * "ReconnectableServers" REG_MULTI_SZ
10099 * "ExtendedSessTimeout" REG_DWORD (seconds)
10100 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
10102 * These values can be used to prevent the smb redirector from timing out
10103 * smb connection to the afs smb server prematurely.
10107 DWORD dwSize, dwAllocSize;
10109 PBYTE pHostNames = NULL, pName = NULL;
10110 BOOL bNameFound = FALSE;
10112 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10113 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
10115 KEY_READ|KEY_WRITE,
10116 &hkLanMan) == ERROR_SUCCESS )
10118 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
10119 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10120 (dwType == REG_MULTI_SZ))
10122 dwAllocSize += 1 /* in case the source string is not nul terminated */
10123 + (DWORD)strlen(cm_NetbiosName) + 2;
10124 pHostNames = malloc(dwAllocSize);
10125 dwSize = dwAllocSize;
10126 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
10127 pHostNames, &dwSize) == ERROR_SUCCESS)
10129 for (pName = pHostNames;
10130 (pName - pHostNames < (int) dwSize) && *pName ;
10131 pName += strlen(pName) + 1)
10133 if ( !stricmp(pName, cm_NetbiosName) ) {
10141 if ( !bNameFound ) {
10142 size_t size = strlen(cm_NetbiosName) + 2;
10143 if ( !pHostNames ) {
10144 pHostNames = malloc(size);
10145 pName = pHostNames;
10147 StringCbCopyA(pName, size, cm_NetbiosName);
10149 *pName = '\0'; /* add a second nul terminator */
10151 dwType = REG_MULTI_SZ;
10152 dwSize = (DWORD)(pName - pHostNames + 1);
10153 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10161 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
10162 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10163 (dwType == REG_MULTI_SZ))
10165 dwAllocSize += 1 /* in case the source string is not nul terminated */
10166 + (DWORD)strlen(cm_NetbiosName) + 2;
10167 pHostNames = malloc(dwAllocSize);
10168 dwSize = dwAllocSize;
10169 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
10170 pHostNames, &dwSize) == ERROR_SUCCESS)
10172 for (pName = pHostNames;
10173 (pName - pHostNames < (int) dwSize) && *pName ;
10174 pName += strlen(pName) + 1)
10176 if ( !stricmp(pName, cm_NetbiosName) ) {
10184 if ( !bNameFound ) {
10185 size_t size = strlen(cm_NetbiosName) + 2;
10186 if ( !pHostNames ) {
10187 pHostNames = malloc(size);
10188 pName = pHostNames;
10190 StringCbCopyA(pName, size, cm_NetbiosName);
10192 *pName = '\0'; /* add a second nul terminator */
10194 dwType = REG_MULTI_SZ;
10195 dwSize = (DWORD)(pName - pHostNames + 1);
10196 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10204 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
10205 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10206 (dwType != REG_DWORD))
10208 dwType = REG_DWORD;
10209 dwSize = sizeof(dwValue);
10210 dwValue = 300; /* 5 minutes */
10211 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10213 RegCloseKey(hkLanMan);
10218 smb_LanAdapterChangeThread(void *param)
10221 * Give the IPAddrDaemon thread a chance
10222 * to block before we trigger.
10225 smb_LanAdapterChange(0);
10228 void smb_SetLanAdapterChangeDetected(void)
10233 lock_ObtainMutex(&smb_StartedLock);
10235 if (!powerStateSuspended) {
10236 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10237 NULL, 0, &lpid, "smb_LanAdapterChange");
10238 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
10239 thrd_CloseHandle(phandle);
10242 smb_LanAdapterChangeDetected = 1;
10243 lock_ReleaseMutex(&smb_StartedLock);
10246 void smb_LanAdapterChange(int locked) {
10247 lana_number_t lanaNum;
10249 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
10251 LANA_ENUM temp_list;
10256 afsi_log("smb_LanAdapterChange");
10259 lock_ObtainMutex(&smb_StartedLock);
10261 smb_LanAdapterChangeDetected = 0;
10263 if (!powerStateSuspended &&
10264 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10265 LANA_NETBIOS_NAME_FULL)) &&
10266 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10267 if ( isGateway != bGateway ) {
10268 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10269 smb_LANadapter, lanaNum, isGateway, bGateway);
10271 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10272 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10273 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10276 NCB *ncbp = smb_GetNCB();
10277 ncbp->ncb_command = NCBENUM;
10278 ncbp->ncb_buffer = (PUCHAR)&temp_list;
10279 ncbp->ncb_length = sizeof(temp_list);
10280 code = Netbios(ncbp);
10282 if (temp_list.length != lana_list.length) {
10283 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10284 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10287 for (i=0; i<lana_list.length; i++) {
10288 if ( temp_list.lana[i] != lana_list.lana[i] ) {
10289 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10290 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10302 smb_StopListeners(1);
10303 smb_RestartListeners(1);
10306 lock_ReleaseMutex(&smb_StartedLock);
10309 /* initialize Netbios */
10310 int smb_NetbiosInit(int locked)
10313 int i, lana, code, l;
10315 int delname_tried=0;
10317 int lana_found = 0;
10318 lana_number_t lanaNum;
10321 lock_ObtainMutex(&smb_StartedLock);
10323 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10324 smb_ListenerState != SMB_LISTENER_STOPPED) {
10327 lock_ReleaseMutex(&smb_StartedLock);
10330 /* setup the NCB system */
10331 ncbp = smb_GetNCB();
10333 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
10334 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10335 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10337 if (smb_LANadapter != LANA_INVALID)
10338 afsi_log("LAN adapter number %d", smb_LANadapter);
10340 afsi_log("LAN adapter number not determined");
10343 afsi_log("Set for gateway service");
10345 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10347 /* something went horribly wrong. We can't proceed without a netbios name */
10349 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10350 osi_panic(buf, __FILE__, __LINE__);
10353 /* remember the name */
10354 len = (int)strlen(cm_NetbiosName);
10355 if (smb_localNamep)
10356 free(smb_localNamep);
10357 smb_localNamep = malloc(len+1);
10358 strcpy(smb_localNamep, cm_NetbiosName);
10359 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10361 /* Also copy the value to the client character encoded string */
10362 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10364 if (smb_LANadapter == LANA_INVALID) {
10365 ncbp->ncb_command = NCBENUM;
10366 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10367 ncbp->ncb_length = sizeof(lana_list);
10368 code = Netbios(ncbp);
10370 afsi_log("Netbios NCBENUM error code %d", code);
10371 osi_panic(s, __FILE__, __LINE__);
10375 lana_list.length = 1;
10376 lana_list.lana[0] = smb_LANadapter;
10379 for (i = 0; i < lana_list.length; i++) {
10380 /* reset the adaptor: in Win32, this is required for every process, and
10381 * acts as an init call, not as a real hardware reset.
10383 ncbp->ncb_command = NCBRESET;
10384 ncbp->ncb_callname[0] = 100;
10385 ncbp->ncb_callname[2] = 100;
10386 ncbp->ncb_lana_num = lana_list.lana[i];
10387 code = Netbios(ncbp);
10389 code = ncbp->ncb_retcode;
10391 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10392 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10394 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10398 /* and declare our name so we can receive connections */
10399 memset(ncbp, 0, sizeof(*ncbp));
10400 len=lstrlen(smb_localNamep);
10401 memset(smb_sharename,' ',NCBNAMSZ);
10402 memcpy(smb_sharename,smb_localNamep,len);
10403 afsi_log("lana_list.length %d", lana_list.length);
10405 /* Keep the name so we can unregister it later */
10406 for (l = 0; l < lana_list.length; l++) {
10407 lana = lana_list.lana[l];
10409 ncbp->ncb_command = NCBADDNAME;
10410 ncbp->ncb_lana_num = lana;
10411 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10412 code = Netbios(ncbp);
10414 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10415 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10417 char name[NCBNAMSZ+1];
10419 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10420 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10424 code = ncbp->ncb_retcode;
10427 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10430 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10431 if (code == NRC_BRIDGE) { /* invalid LANA num */
10432 lana_list.lana[l] = LANA_INVALID;
10435 else if (code == NRC_DUPNAME) {
10436 afsi_log("Name already exists; try to delete it");
10437 memset(ncbp, 0, sizeof(*ncbp));
10438 ncbp->ncb_command = NCBDELNAME;
10439 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10440 ncbp->ncb_lana_num = lana;
10441 code = Netbios(ncbp);
10443 code = ncbp->ncb_retcode;
10445 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10447 if (code != 0 || delname_tried) {
10448 lana_list.lana[l] = LANA_INVALID;
10450 else if (code == 0) {
10451 if (!delname_tried) {
10459 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10460 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10464 smb_LANadapter = lana;
10465 lana_found = 1; /* at least one worked */
10469 osi_assertx(lana_list.length >= 0, "empty lana list");
10471 afsi_log("No valid LANA numbers found!");
10472 lana_list.length = 0;
10473 smb_LANadapter = LANA_INVALID;
10474 smb_ListenerState = SMB_LISTENER_STOPPED;
10475 cm_VolStatus_Network_Stopped(cm_NetbiosName
10482 /* we're done with the NCB now */
10485 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10486 if (lana_list.length > 0)
10487 osi_assert(smb_LANadapter != LANA_INVALID);
10490 lock_ReleaseMutex(&smb_StartedLock);
10492 return (lana_list.length > 0 ? 1 : 0);
10495 void smb_StartListeners(int locked)
10502 lock_ObtainMutex(&smb_StartedLock);
10504 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10506 lock_ReleaseMutex(&smb_StartedLock);
10510 afsi_log("smb_StartListeners");
10511 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10512 configureBackConnectionHostNames();
10514 /* Configure Extended SMB Session Timeouts */
10515 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10516 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10517 configureExtendedSMBSessionTimeouts();
10520 smb_ListenerState = SMB_LISTENER_STARTED;
10521 cm_VolStatus_Network_Started(cm_NetbiosName
10527 for (i = 0; i < lana_list.length; i++) {
10528 if (lana_list.lana[i] == LANA_INVALID)
10530 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10531 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10532 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10533 thrd_CloseHandle(phandle);
10536 lock_ReleaseMutex(&smb_StartedLock);
10539 void smb_RestartListeners(int locked)
10542 lock_ObtainMutex(&smb_StartedLock);
10544 if (powerStateSuspended)
10545 afsi_log("smb_RestartListeners called while suspended");
10547 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10548 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10549 if (smb_NetbiosInit(1))
10550 smb_StartListeners(1);
10551 } else if (smb_LanAdapterChangeDetected) {
10552 smb_LanAdapterChange(1);
10556 lock_ReleaseMutex(&smb_StartedLock);
10559 void smb_StopListener(NCB *ncbp, int lana, int wait)
10563 memset(ncbp, 0, sizeof(*ncbp));
10564 ncbp->ncb_command = NCBDELNAME;
10565 ncbp->ncb_lana_num = lana;
10566 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10567 code = Netbios(ncbp);
10569 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10570 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10572 /* and then reset the LANA; this will cause the listener threads to exit */
10573 ncbp->ncb_command = NCBRESET;
10574 ncbp->ncb_callname[0] = 100;
10575 ncbp->ncb_callname[2] = 100;
10576 ncbp->ncb_lana_num = lana;
10577 code = Netbios(ncbp);
10579 code = ncbp->ncb_retcode;
10581 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10583 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10587 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10590 void smb_StopListeners(int locked)
10596 lock_ObtainMutex(&smb_StartedLock);
10598 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10600 lock_ReleaseMutex(&smb_StartedLock);
10604 afsi_log("smb_StopListeners");
10605 smb_ListenerState = SMB_LISTENER_STOPPED;
10606 cm_VolStatus_Network_Stopped(cm_NetbiosName
10612 ncbp = smb_GetNCB();
10614 /* Unregister the SMB name */
10615 for (l = 0; l < lana_list.length; l++) {
10616 lana = lana_list.lana[l];
10618 if (lana != LANA_INVALID) {
10619 smb_StopListener(ncbp, lana, TRUE);
10621 /* mark the adapter invalid */
10622 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10626 /* force a re-evaluation of the network adapters */
10627 lana_list.length = 0;
10628 smb_LANadapter = LANA_INVALID;
10631 lock_ReleaseMutex(&smb_StartedLock);
10634 void smb_Init(osi_log_t *logp, int useV3,
10644 EVENT_HANDLE retHandle;
10645 char eventName[MAX_PATH];
10646 int startListeners = 0;
10648 smb_MBfunc = aMBfunc;
10652 /* Initialize smb_localZero */
10653 myTime.tm_isdst = -1; /* compute whether on DST or not */
10654 myTime.tm_year = 70;
10656 myTime.tm_mday = 1;
10657 myTime.tm_hour = 0;
10660 smb_localZero = mktime(&myTime);
10662 #ifdef AFS_FREELANCE_CLIENT
10663 /* Make sure the root.afs volume has the correct time */
10664 cm_noteLocalMountPointChange();
10667 /* initialize the remote debugging log */
10670 /* and the global lock */
10671 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10672 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10674 /* Raw I/O data structures */
10675 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10677 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10678 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10680 /* 4 Raw I/O buffers */
10681 smb_RawBufs = calloc(65536,1);
10682 *((char **)smb_RawBufs) = NULL;
10683 for (i=0; i<3; i++) {
10684 char *rawBuf = calloc(65536,1);
10685 *((char **)rawBuf) = smb_RawBufs;
10686 smb_RawBufs = rawBuf;
10689 /* global free lists */
10690 smb_ncbFreeListp = NULL;
10691 smb_packetFreeListp = NULL;
10693 lock_ObtainMutex(&smb_StartedLock);
10694 startListeners = smb_NetbiosInit(1);
10696 /* Initialize listener and server structures */
10698 memset(dead_sessions, 0, sizeof(dead_sessions));
10699 sprintf(eventName, "SessionEvents[0]");
10700 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10701 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10702 afsi_log("Event Object Already Exists: %s", eventName);
10704 smb_NumServerThreads = nThreads;
10705 sprintf(eventName, "NCBavails[0]");
10706 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10707 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10708 afsi_log("Event Object Already Exists: %s", eventName);
10709 sprintf(eventName, "NCBevents[0]");
10710 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10711 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10712 afsi_log("Event Object Already Exists: %s", eventName);
10713 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10714 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10715 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10716 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10717 afsi_log("Event Object Already Exists: %s", eventName);
10718 for (i = 0; i < smb_NumServerThreads; i++) {
10719 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10720 NCBreturns[i][0] = retHandle;
10723 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10724 for (i = 0; i < smb_NumServerThreads; i++) {
10725 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10726 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10727 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10728 afsi_log("Event Object Already Exists: %s", eventName);
10729 InitNCBslot((int)(i+1));
10731 numNCBs = smb_NumServerThreads + 1;
10733 /* Initialize dispatch table */
10734 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10735 /* Prepare the table for unknown operations */
10736 for(i=0; i<= SMB_NOPCODES; i++) {
10737 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10739 /* Fill in the ones we do know */
10740 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10741 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10742 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10743 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10744 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10745 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10746 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10747 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10748 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10749 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10750 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10751 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10752 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10753 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10754 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10755 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10756 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10757 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10758 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10759 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10760 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10761 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10762 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10763 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10764 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10765 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10766 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10767 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10768 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10769 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10770 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10771 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10772 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10773 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10774 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10775 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10776 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10777 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10778 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10779 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10780 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10781 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10782 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10783 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10784 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10785 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10786 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10787 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10788 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10789 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10790 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10791 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10792 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10793 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10794 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10795 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10796 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10797 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10798 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10799 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10800 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10801 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10802 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10803 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10804 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10805 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10806 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10807 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10808 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10809 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10810 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10811 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10812 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10813 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10815 /* setup tran 2 dispatch table */
10816 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10817 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10818 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10819 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10820 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10821 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10822 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10823 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10824 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10825 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10826 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10827 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10828 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10829 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10830 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10831 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10832 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10833 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10835 /* setup the rap dispatch table */
10836 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10837 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10838 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10839 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10840 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10844 /* if we are doing SMB authentication we have register outselves as a logon process */
10845 if (smb_authType != SMB_AUTH_NONE) {
10846 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10847 LSA_STRING afsProcessName;
10848 LSA_OPERATIONAL_MODE dummy; /*junk*/
10850 afsProcessName.Buffer = "OpenAFSClientDaemon";
10851 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10852 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10854 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10856 if (nts == STATUS_SUCCESS) {
10857 LSA_STRING packageName;
10858 /* we are registered. Find out the security package id */
10859 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10860 packageName.Length = (USHORT)strlen(packageName.Buffer);
10861 packageName.MaximumLength = packageName.Length + 1;
10862 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10863 if (nts == STATUS_SUCCESS) {
10865 * This code forces Windows to authenticate against the Logon Cache
10866 * first instead of attempting to authenticate against the Domain
10867 * Controller. When the Windows logon cache is enabled this improves
10868 * performance by removing the network access and works around a bug
10869 * seen at sites which are using a MIT Kerberos principal to login
10870 * to machines joined to a non-root domain in a multi-domain forest.
10871 * MsV1_0SetProcessOption was added in Windows XP.
10873 PVOID pResponse = NULL;
10874 ULONG cbResponse = 0;
10875 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10877 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10878 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10879 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10880 OptionsRequest.DisableOptions = FALSE;
10882 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10885 sizeof(OptionsRequest),
10891 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10892 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10895 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10897 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10898 afsi_log("MsV1_0SetProcessOption success");
10900 /* END - code from Larry */
10902 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10903 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10904 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10906 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10908 /* something went wrong. We report the error and revert back to no authentication
10909 because we can't perform any auth requests without a successful lsa handle
10910 or sec package id. */
10911 afsi_log("Reverting to NO SMB AUTH");
10912 smb_authType = SMB_AUTH_NONE;
10915 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10917 /* something went wrong. We report the error and revert back to no authentication
10918 because we can't perform any auth requests without a successful lsa handle
10919 or sec package id. */
10920 afsi_log("Reverting to NO SMB AUTH");
10921 smb_authType = SMB_AUTH_NONE;
10925 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10926 * time prevents the failure of authentication when logged into Windows with an
10927 * external Kerberos principal mapped to a local account.
10929 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10930 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10931 * then the only option is NTLMSSP anyway; so just fallback.
10936 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10937 if (secBlobLength == 0) {
10938 smb_authType = SMB_AUTH_NTLM;
10939 afsi_log("Reverting to SMB AUTH NTLM");
10948 /* Now get ourselves a domain name. */
10949 /* For now we are using the local computer name as the domain name.
10950 * It is actually the domain for local logins, and we are acting as
10951 * a local SMB server.
10953 bufsize = lengthof(smb_ServerDomainName) - 1;
10954 GetComputerNameW(smb_ServerDomainName, &bufsize);
10955 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10956 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10959 /* Start listeners, waiters, servers, and daemons */
10960 if (startListeners)
10961 smb_StartListeners(1);
10963 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10964 NULL, 0, &lpid, "smb_ClientWaiter");
10965 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10966 thrd_CloseHandle(phandle);
10968 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10969 NULL, 0, &lpid, "smb_ServerWaiter");
10970 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10971 thrd_CloseHandle(phandle);
10973 for (i=0; i<smb_NumServerThreads; i++) {
10974 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10975 (void *) i, 0, &lpid, "smb_Server");
10976 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10977 thrd_CloseHandle(phandle);
10980 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10981 NULL, 0, &lpid, "smb_Daemon");
10982 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10983 thrd_CloseHandle(phandle);
10985 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10986 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10987 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10988 thrd_CloseHandle(phandle);
10990 if (smb_monitorReqs) {
10991 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
10992 NULL, 0, &lpid, "smb_ServerMonitor");
10993 osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
10994 thrd_CloseHandle(phandle);
10997 lock_ReleaseMutex(&smb_StartedLock);
11001 void smb_Shutdown(void)
11008 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11010 /* setup the NCB system */
11011 ncbp = smb_GetNCB();
11013 /* Block new sessions by setting shutdown flag */
11014 smbShutdownFlag = 1;
11016 /* Hang up all sessions */
11017 memset(ncbp, 0, sizeof(NCB));
11018 for (i = 1; i < numSessions; i++)
11020 if (dead_sessions[i])
11023 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11024 ncbp->ncb_command = NCBHANGUP;
11025 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
11026 ncbp->ncb_lsn = (UCHAR)LSNs[i];
11027 code = Netbios(ncbp);
11028 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11029 if (code == 0) code = ncbp->ncb_retcode;
11031 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11032 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11036 /* Trigger the shutdown of all SMB threads */
11037 for (i = 0; i < smb_NumServerThreads; i++)
11038 thrd_SetEvent(NCBreturns[i][0]);
11040 thrd_SetEvent(NCBevents[0]);
11041 thrd_SetEvent(SessionEvents[0]);
11042 thrd_SetEvent(NCBavails[0]);
11044 for (i = 0;i < smb_NumServerThreads; i++) {
11045 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11046 if (code == WAIT_OBJECT_0) {
11049 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11050 thrd_SetEvent(NCBreturns[i--][0]);
11054 /* Delete Netbios name */
11055 memset(ncbp, 0, sizeof(NCB));
11056 for (i = 0; i < lana_list.length; i++) {
11057 if (lana_list.lana[i] == LANA_INVALID) continue;
11058 ncbp->ncb_command = NCBDELNAME;
11059 ncbp->ncb_lana_num = lana_list.lana[i];
11060 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11061 code = Netbios(ncbp);
11063 code = ncbp->ncb_retcode;
11065 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11066 ncbp->ncb_lana_num, code);
11071 /* Release the reference counts held by the VCs */
11072 lock_ObtainWrite(&smb_rctLock);
11073 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11078 if (vcp->magic != SMB_VC_MAGIC)
11079 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11080 __FILE__, __LINE__);
11082 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11084 if (fidp->scp != NULL) {
11087 lock_ReleaseWrite(&smb_rctLock);
11088 lock_ObtainMutex(&fidp->mx);
11089 if (fidp->scp != NULL) {
11092 lock_ObtainWrite(&scp->rw);
11093 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11094 lock_ReleaseWrite(&scp->rw);
11095 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11096 cm_ReleaseSCache(scp);
11098 lock_ReleaseMutex(&fidp->mx);
11099 lock_ObtainWrite(&smb_rctLock);
11103 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11105 smb_ReleaseVCNoLock(tidp->vcp);
11107 cm_user_t *userp = tidp->userp;
11108 tidp->userp = NULL;
11109 cm_ReleaseUser(userp);
11113 lock_ReleaseWrite(&smb_rctLock);
11116 if (smb_monitorReqs) {
11117 smb_ShutdownMonitor();
11121 /* Get the UNC \\<servername>\<sharename> prefix. */
11122 char *smb_GetSharename()
11127 /* Make sure we have been properly initialized. */
11128 if (smb_localNamep == NULL)
11131 /* Allocate space for \\<servername>\<sharename>, plus the
11134 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11135 name = malloc(len);
11136 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11142 void smb_LogPacket(smb_packet_t *packet)
11146 unsigned length, paramlen, datalen, i, j;
11148 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11150 if (!packet) return;
11152 osi_Log0(smb_logp, "*** SMB packet dump ***");
11154 smbp = (smb_t *) packet->data;
11155 vp = (BYTE *) packet->data;
11157 paramlen = smbp->wct * 2;
11158 datalen = *((WORD *) (smbp->vdata + paramlen));
11159 length = sizeof(*smbp) + paramlen + 1 + datalen;
11161 for (i=0;i < length; i+=16)
11163 memset( buf, ' ', 80 );
11166 itoa( i, buf, 16 );
11168 buf[strlen(buf)] = ' ';
11170 cp = (BYTE*) buf + 7;
11172 for (j=0;j < 16 && (i+j)<length; j++)
11174 *(cp++) = hex[vp[i+j] >> 4];
11175 *(cp++) = hex[vp[i+j] & 0xf];
11185 for (j=0;j < 16 && (i+j)<length;j++)
11187 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11198 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11201 osi_Log0(smb_logp, "*** End SMB packet dump ***");
11203 #endif /* LOG_PACKET */
11206 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11212 smb_username_t *unp;
11213 smb_waitingLockRequest_t *wlrp;
11216 lock_ObtainRead(&smb_rctLock);
11218 sprintf(output, "begin dumping smb_username_t\r\n");
11219 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11220 for (unp = usernamesp; unp; unp=unp->nextp)
11222 cm_ucell_t *ucellp;
11224 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11225 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11226 unp->name ? unp->name : _C("NULL"),
11227 unp->machine ? unp->machine : _C("NULL"));
11228 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11230 sprintf(output, " begin dumping cm_ucell_t\r\n");
11231 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11233 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11234 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",
11235 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11236 ucellp->expirationTime, ucellp->gen,
11238 ucellp->cellp->name);
11239 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11242 sprintf(output, " done dumping cm_ucell_t\r\n");
11243 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11246 sprintf(output, "done dumping smb_username_t\r\n");
11247 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11250 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11251 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11254 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11255 smb_waitingLock_t *lockp;
11257 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11258 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11259 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11261 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
11262 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11263 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11264 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11265 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11266 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11268 sprintf(output, " done dumping smb_waitingLock_t\r\n");
11269 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11272 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11273 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11275 sprintf(output, "begin dumping smb_vc_t\r\n");
11276 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11278 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11284 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11285 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11286 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11288 sprintf(output, " begin dumping smb_user_t\r\n");
11289 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11290 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11291 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11292 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11293 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11295 sprintf(output, " done dumping smb_user_t\r\n");
11296 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11298 sprintf(output, " begin dumping smb_tid_t\r\n");
11299 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11300 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11301 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",
11302 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11303 tidp->pathname ? tidp->pathname : _C("NULL"));
11304 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11306 sprintf(output, " done dumping smb_tid_t\r\n");
11307 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11309 sprintf(output, " begin dumping smb_fid_t\r\n");
11310 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11312 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11314 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",
11315 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11316 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11317 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11318 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11321 sprintf(output, " done dumping smb_fid_t\r\n");
11322 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11325 sprintf(output, "done dumping smb_vc_t\r\n");
11326 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11328 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11329 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11331 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11337 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11338 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11339 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11341 sprintf(output, " begin dumping smb_user_t\r\n");
11342 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11343 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11344 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11345 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11346 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11348 sprintf(output, " done dumping smb_user_t\r\n");
11349 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11351 sprintf(output, " begin dumping smb_tid_t\r\n");
11352 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11353 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11354 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",
11355 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11356 tidp->pathname ? tidp->pathname : _C("NULL"));
11357 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11359 sprintf(output, " done dumping smb_tid_t\r\n");
11360 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11362 sprintf(output, " begin dumping smb_fid_t\r\n");
11363 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11365 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11367 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",
11368 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11369 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11370 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11371 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11374 sprintf(output, " done dumping smb_fid_t\r\n");
11375 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11378 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11379 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11382 lock_ReleaseRead(&smb_rctLock);
11386 long smb_IsNetworkStarted(void)
11389 lock_ObtainWrite(&smb_globalLock);
11390 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11391 lock_ReleaseWrite(&smb_globalLock);