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 <afsconfig.h>
11 #include <afs/param.h>
18 #pragma warning(disable: 4005)
32 #include <rx/rx_prototypes.h>
33 #include <WINNT\afsreg.h>
37 #include "lanahelper.h"
39 #define STRSAFE_NO_DEPRECATE
42 /* These characters are illegal in Windows filenames */
43 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
45 static int smbShutdownFlag = 0;
46 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
48 int smb_LogoffTokenTransfer;
49 time_t smb_LogoffTransferTimeout;
51 int smb_StoreAnsiFilenames = 0;
53 DWORD last_msg_time = 0;
57 unsigned int sessionGen = 0;
59 extern void afsi_log(char *pattern, ...);
60 extern HANDLE afsi_file;
61 extern int powerStateSuspended;
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t smb_ListenerLock;
70 osi_mutex_t smb_StartedLock;
72 unsigned char smb_LANadapter = LANA_INVALID;
73 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
74 int smb_LanAdapterChangeDetected = 0;
75 afs_uint32 smb_AsyncStore = 1;
76 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
78 BOOL isGateway = FALSE;
81 long smb_maxObsConcurrentCalls=0;
82 long smb_concurrentCalls=0;
84 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
86 smb_packet_t *smb_packetFreeListp;
87 smb_ncb_t *smb_ncbFreeListp;
89 afs_uint32 smb_NumServerThreads;
91 afs_uint32 numNCBs, numSessions, numVCs;
93 int smb_maxVCPerServer;
94 int smb_maxMpxRequests;
96 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
98 ULONG smb_lsaSecPackage;
99 LSA_STRING smb_lsaLogonOrigin;
101 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
102 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
103 EVENT_HANDLE **NCBreturns;
104 EVENT_HANDLE **NCBShutdown;
105 EVENT_HANDLE *smb_ServerShutdown;
106 EVENT_HANDLE ListenerShutdown[256];
107 DWORD NCBsessions[NCB_MAX];
109 struct smb_packet *bufs[NCB_MAX];
111 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
112 EVENT_HANDLE SessionEvents[SESSION_MAX];
113 unsigned short LSNs[SESSION_MAX];
114 int lanas[SESSION_MAX];
115 BOOL dead_sessions[SESSION_MAX];
118 osi_mutex_t smb_RawBufLock;
121 #define SMB_MASKFLAG_TILDE 1
122 #define SMB_MASKFLAG_CASEFOLD 2
124 #define RAWTIMEOUT INFINITE
127 typedef struct raw_write_cont {
136 /* dir search stuff */
137 long smb_dirSearchCounter = 1;
138 smb_dirSearch_t *smb_firstDirSearchp;
139 smb_dirSearch_t *smb_lastDirSearchp;
141 /* Initial mode bits for files and directories. Set to 0 to use
143 int smb_unixModeDefaultFile = 0666;
144 int smb_unixModeDefaultDir = 0777;
146 /* hide dot files? */
147 int smb_hideDotFiles;
149 /* Negotiate Unicode support? */
152 /* global state about V3 protocols */
153 int smb_useV3; /* try to negotiate V3 */
155 static int showErrors = 0;
156 /* MessageBox or something like it */
157 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
161 * Time in Unix format of midnight, 1/1/1970 local time.
162 * When added to dosUTime, gives Unix (AFS) time.
164 time_t smb_localZero = 0;
166 char *smb_localNamep = NULL;
168 smb_vc_t *smb_allVCsp;
169 smb_vc_t *smb_deadVCsp;
171 smb_username_t *usernamesp = NULL;
173 smb_waitingLockRequest_t *smb_allWaitingLocks;
176 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
177 NCB *ncbp, raw_write_cont_t *rwcp);
178 int smb_NetbiosInit(int);
181 void smb_LogPacket(smb_packet_t *packet);
182 #endif /* LOG_PACKET */
184 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
185 int smb_ServerDomainNameLength = 0;
186 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
187 int smb_ServerOSLength = lengthof(smb_ServerOS);
188 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
189 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
191 /* Faux server GUID. This is never checked. */
192 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
194 void smb_InitReq(cm_req_t *reqp)
197 reqp->flags |= CM_REQ_SOURCE_SMB;
200 const char * ncb_error_string(int code)
204 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
205 case 0x03: s = "NRC_ILLCMD illegal command"; break;
206 case 0x05: s = "NRC_CMDTMO command timed out"; break;
207 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
208 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
209 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
210 case 0x09: s = "NRC_NORES no resource available"; break;
211 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
212 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
213 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
214 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
215 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
216 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
217 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
218 case 0x13: s = "NRC_ILLNN illegal name number"; break;
219 case 0x14: s = "NRC_NOCALL no callname"; break;
220 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
221 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
222 case 0x17: s = "NRC_NAMERR name deleted"; break;
223 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
224 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
225 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
226 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
227 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
228 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
229 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
230 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
231 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
232 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
233 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
234 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
235 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
236 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
237 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
238 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
239 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
240 case 0x40: s = "NRC_SYSTEM system error"; break;
241 default: s = "unknown error";
247 char * myCrt_Dispatch(int i)
252 return "(00)ReceiveCoreMakeDir";
254 return "(01)ReceiveCoreRemoveDir";
256 return "(02)ReceiveCoreOpen";
258 return "(03)ReceiveCoreCreate";
260 return "(04)ReceiveCoreClose";
262 return "(05)ReceiveCoreFlush";
264 return "(06)ReceiveCoreUnlink";
266 return "(07)ReceiveCoreRename";
268 return "(08)ReceiveCoreGetFileAttributes";
270 return "(09)ReceiveCoreSetFileAttributes";
272 return "(0a)ReceiveCoreRead";
274 return "(0b)ReceiveCoreWrite";
276 return "(0c)ReceiveCoreLockRecord";
278 return "(0d)ReceiveCoreUnlockRecord";
280 return "(0e)SendCoreBadOp";
282 return "(0f)ReceiveCoreCreate";
284 return "(10)ReceiveCoreCheckPath";
286 return "(11)SendCoreBadOp";
288 return "(12)ReceiveCoreSeek";
290 return "(1a)ReceiveCoreReadRaw";
292 return "(1d)ReceiveCoreWriteRawDummy";
294 return "(22)ReceiveV3SetAttributes";
296 return "(23)ReceiveV3GetAttributes";
298 return "(24)ReceiveV3LockingX";
300 return "(25)ReceiveV3Trans";
302 return "(26)ReceiveV3Trans[aux]";
304 return "(29)SendCoreBadOp";
306 return "(2b)ReceiveCoreEcho";
308 return "(2d)ReceiveV3OpenX";
310 return "(2e)ReceiveV3ReadX";
312 return "(2f)ReceiveV3WriteX";
314 return "(32)ReceiveV3Tran2A";
316 return "(33)ReceiveV3Tran2A[aux]";
318 return "(34)ReceiveV3FindClose";
320 return "(35)ReceiveV3FindNotifyClose";
322 return "(70)ReceiveCoreTreeConnect";
324 return "(71)ReceiveCoreTreeDisconnect";
326 return "(72)ReceiveNegotiate";
328 return "(73)ReceiveV3SessionSetupX";
330 return "(74)ReceiveV3UserLogoffX";
332 return "(75)ReceiveV3TreeConnectX";
334 return "(80)ReceiveCoreGetDiskAttributes";
336 return "(81)ReceiveCoreSearchDir";
340 return "(83)FindUnique";
342 return "(84)FindClose";
344 return "(A0)ReceiveNTTransact";
346 return "(A2)ReceiveNTCreateX";
348 return "(A4)ReceiveNTCancel";
350 return "(A5)ReceiveNTRename";
352 return "(C0)OpenPrintFile";
354 return "(C1)WritePrintFile";
356 return "(C2)ClosePrintFile";
358 return "(C3)GetPrintQueue";
360 return "(D8)ReadBulk";
362 return "(D9)WriteBulk";
364 return "(DA)WriteBulkData";
366 return "unknown SMB op";
370 char * myCrt_2Dispatch(int i)
375 return "unknown SMB op-2";
377 return "S(00)CreateFile_ReceiveTran2Open";
379 return "S(01)FindFirst_ReceiveTran2SearchDir";
381 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
383 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
385 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
387 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
389 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
391 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
393 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
395 return "S(09)_ReceiveTran2FSCTL";
397 return "S(0a)_ReceiveTran2IOCTL";
399 return "S(0b)_ReceiveTran2FindNotifyFirst";
401 return "S(0c)_ReceiveTran2FindNotifyNext";
403 return "S(0d)_ReceiveTran2CreateDirectory";
405 return "S(0e)_ReceiveTran2SessionSetup";
407 return "S(0f)_QueryFileSystemInformationFid";
409 return "S(10)_ReceiveTran2GetDfsReferral";
411 return "S(11)_ReceiveTran2ReportDfsInconsistency";
415 char * myCrt_RapDispatch(int i)
420 return "unknown RAP OP";
422 return "RAP(0)NetShareEnum";
424 return "RAP(1)NetShareGetInfo";
426 return "RAP(13)NetServerGetInfo";
428 return "RAP(63)NetWkStaGetInfo";
432 char * myCrt_NmpipeDispatch(int i)
435 case SMB_TRANS_SET_NMPIPE_STATE:
436 return "SET NMPIPE STATE";
438 case SMB_TRANS_RAW_READ_NMPIPE:
439 return "RAW READ NMPIPE";
441 case SMB_TRANS_QUERY_NMPIPE_STATE:
442 return "QUERY NMPIPE STATE";
444 case SMB_TRANS_QUERY_NMPIPE_INFO:
445 return "QUERY NMPIPE INFO";
447 case SMB_TRANS_PEEK_NMPIPE:
448 return "PEEK NMPIPE";
450 case SMB_TRANS_TRANSACT_NMPIPE:
451 return "TRANSACT NMPIPE";
453 case SMB_TRANS_RAW_WRITE_NMPIPE:
454 return "WRITE NMPIPE";
456 case SMB_TRANS_READ_NMPIPE:
457 return "READ NMPIPE";
459 case SMB_TRANS_WRITE_NMPIPE:
460 return "WRITE NMPIPE";
462 case SMB_TRANS_WAIT_NMPIPE:
463 return "WAIT NMPIPE";
465 case SMB_TRANS_CALL_NMPIPE:
466 return "CALL NMPIPE";
471 /* scache must be locked */
472 unsigned int smb_Attributes(cm_scache_t *scp)
476 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
477 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
478 scp->fileType == CM_SCACHETYPE_INVALID)
480 attrs = SMB_ATTR_DIRECTORY;
481 #ifdef SPECIAL_FOLDERS
482 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
483 #endif /* SPECIAL_FOLDERS */
484 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
485 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
490 * We used to mark a file RO if it was in an RO volume, but that
491 * turns out to be impolitic in NT. See defect 10007.
494 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
495 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
497 if ((scp->unixModeBits & 0200) == 0)
498 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
504 void smb_SetInitialModeBitsForFile(int smb_attr, cm_attr_t * attr)
506 if (smb_unixModeDefaultFile != 0) {
507 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
508 attr->unixModeBits = smb_unixModeDefaultFile;
509 if (smb_attr & SMB_ATTR_READONLY)
510 attr->unixModeBits &= ~0222;
514 void smb_SetInitialModeBitsForDir(int smb_attr, cm_attr_t * attr)
516 if (smb_unixModeDefaultDir != 0) {
517 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
518 attr->unixModeBits = smb_unixModeDefaultDir;
522 /* Check if the named file/dir is a dotfile/dotdir */
523 /* String pointed to by lastComp can have leading slashes, but otherwise should have
524 no other patch components */
525 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
529 /* skip over slashes */
530 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
535 /* nulls, curdir and parent dir doesn't count */
541 if(*(s+1) == _C('.') && !*(s + 2))
548 static int ExtractBits(WORD bits, short start, short len)
555 num = bits << (16 - end);
556 num = num >> ((16 - end) + start);
561 void ShowUnixTime(char *FuncName, time_t unixTime)
566 cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
568 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
569 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
571 int day, month, year, sec, min, hour;
574 day = ExtractBits(wDate, 0, 5);
575 month = ExtractBits(wDate, 5, 4);
576 year = ExtractBits(wDate, 9, 7) + 1980;
578 sec = ExtractBits(wTime, 0, 5);
579 min = ExtractBits(wTime, 5, 6);
580 hour = ExtractBits(wTime, 11, 5);
582 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
583 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
587 /* Determine if we are observing daylight savings time */
588 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
590 TIME_ZONE_INFORMATION timeZoneInformation;
591 SYSTEMTIME utc, local, localDST;
593 /* Get the time zone info. NT uses this to calc if we are in DST. */
594 GetTimeZoneInformation(&timeZoneInformation);
596 /* Return the daylight bias */
597 *pDstBias = timeZoneInformation.DaylightBias;
599 /* Return the bias */
600 *pBias = timeZoneInformation.Bias;
602 /* Now determine if DST is being observed */
604 /* Get the UTC (GMT) time */
607 /* Convert UTC time to local time using the time zone info. If we are
608 observing DST, the calculated local time will include this.
610 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
612 /* Set the daylight bias to 0. The daylight bias is the amount of change
613 * in time that we use for daylight savings time. By setting this to 0
614 * we cause there to be no change in time during daylight savings time.
616 timeZoneInformation.DaylightBias = 0;
618 /* Convert the utc time to local time again, but this time without any
619 adjustment for daylight savings time.
621 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
623 /* If the two times are different, then it means that the localDST that
624 we calculated includes the daylight bias, and therefore we are
625 observing daylight savings time.
627 *pDST = localDST.wHour != local.wHour;
631 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
633 BOOL dst; /* Will be TRUE if observing DST */
634 LONG dstBias; /* Offset from local time if observing DST */
635 LONG bias; /* Offset from GMT for local time */
638 * This function will adjust the last write time to compensate
639 * for two bugs in the smb client:
641 * 1) During Daylight Savings Time, the LastWriteTime is ahead
642 * in time by the DaylightBias (ignoring the sign - the
643 * DaylightBias is always stored as a negative number). If
644 * the DaylightBias is -60, then the LastWriteTime will be
645 * ahead by 60 minutes.
647 * 2) If the local time zone is a positive offset from GMT, then
648 * the LastWriteTime will be the correct local time plus the
649 * Bias (ignoring the sign - a positive offset from GMT is
650 * always stored as a negative Bias). If the Bias is -120,
651 * then the LastWriteTime will be ahead by 120 minutes.
653 * These bugs can occur at the same time.
656 GetTimeZoneInfo(&dst, &dstBias, &bias);
658 /* First adjust for DST */
660 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
662 /* Now adjust for a positive offset from GMT (a negative bias). */
664 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
667 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
669 time_t diff_t = unixTime - smb_localZero;
670 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
671 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
673 *dosUTimep = (afs_uint32)diff_t;
676 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
678 *unixTimep = dosTime + smb_localZero;
681 void smb_MarkAllVCsDead(smb_vc_t * exclude)
684 smb_vc_t **vcp_to_cleanup = NULL;
685 int n_to_cleanup = 0;
688 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
690 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
691 lock_ObtainWrite(&smb_rctLock);
692 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
694 if (vcp->magic != SMB_VC_MAGIC)
695 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
701 lock_ObtainMutex(&vcp->mx);
702 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
703 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
704 lock_ReleaseMutex(&vcp->mx);
705 dead_sessions[vcp->session] = TRUE;
707 lock_ReleaseMutex(&vcp->mx);
712 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
714 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
718 vcp_to_cleanup[i++] = vcp;
719 smb_HoldVCNoLock(vcp);
722 osi_assert(i == n_to_cleanup);
724 lock_ReleaseWrite(&smb_rctLock);
725 lock_ReleaseWrite(&smb_globalLock);
727 for (i=0; i < n_to_cleanup; i++) {
728 smb_CleanupDeadVC(vcp_to_cleanup[i]);
729 smb_ReleaseVC(vcp_to_cleanup[i]);
730 vcp_to_cleanup[i] = 0;
733 free(vcp_to_cleanup);
736 #ifdef DEBUG_SMB_REFCOUNT
737 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
739 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
744 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
745 lock_ObtainWrite(&smb_rctLock);
746 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
747 if (vcp->magic != SMB_VC_MAGIC)
748 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
751 lock_ObtainMutex(&vcp->mx);
752 if (lsn == vcp->lsn && lana == vcp->lana &&
753 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
754 lock_ReleaseMutex(&vcp->mx);
755 smb_HoldVCNoLock(vcp);
758 lock_ReleaseMutex(&vcp->mx);
760 if (!vcp && (flags & SMB_FLAG_CREATE)) {
761 vcp = malloc(sizeof(*vcp));
762 memset(vcp, 0, sizeof(*vcp));
763 vcp->vcID = ++numVCs;
764 vcp->magic = SMB_VC_MAGIC;
765 vcp->refCount = 2; /* smb_allVCsp and caller */
768 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
769 vcp->nextp = smb_allVCsp;
771 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
776 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
777 /* We must obtain a challenge for extended auth
778 * in case the client negotiates smb v3
780 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
781 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
782 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
783 ULONG lsaRespSize = 0;
785 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
787 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
794 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
795 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
796 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
797 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
798 nts, ntsEx, lsaRespSize);
800 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
802 if (ntsEx == STATUS_SUCCESS) {
803 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
806 * This will cause the subsequent authentication to fail but
807 * that is better than us dereferencing a NULL pointer and
810 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
813 LsaFreeReturnBuffer(lsaResp);
816 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
818 if (numVCs >= CM_SESSION_RESERVED) {
820 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
823 #ifdef DEBUG_SMB_REFCOUNT
825 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
826 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
829 lock_ReleaseWrite(&smb_rctLock);
830 lock_ReleaseWrite(&smb_globalLock);
834 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
839 for(i=0; i<11; i++) {
841 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
847 static int smb_IsStarMask(clientchar_t *maskp)
853 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
859 #ifdef DEBUG_SMB_REFCOUNT
860 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
861 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
863 void smb_ReleaseVCInternal(smb_vc_t *vcp)
869 lock_AssertWrite(&smb_rctLock);
872 if (vcp->refCount == 0) {
873 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
874 #ifdef DEBUG_SMB_REFCOUNT
875 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
876 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
878 /* remove VCP from smb_deadVCsp */
879 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
885 lock_FinalizeMutex(&vcp->mx);
886 memset(vcp,0,sizeof(smb_vc_t));
889 #ifdef DEBUG_SMB_REFCOUNT
890 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
892 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
896 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
897 avcp?"":"not ",vcp, vcp->refCount);
899 /* This is a wrong. However, I suspect that there is an undercount
900 * and I don't want to release 1.4.1 in a state that will allow
901 * smb_vc_t objects to be deallocated while still in the
902 * smb_allVCsp list. The list is supposed to keep a reference
903 * to the smb_vc_t. Put it back.
907 #ifdef DEBUG_SMB_REFCOUNT
908 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
909 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
913 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
914 /* The reference count is non-zero but the VC is dead.
915 * This implies that some FIDs, TIDs, etc on the VC have yet to
916 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
917 * add a reference that will be dropped by
918 * smb_CleanupDeadVC() and try to cleanup the VC again.
919 * Eventually the refCount will drop to zero when all of the
920 * active threads working with the VC end their task.
922 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
923 vcp->refCount++; /* put the refCount back */
924 lock_ReleaseWrite(&smb_rctLock);
925 smb_CleanupDeadVC(vcp);
926 #ifdef DEBUG_SMB_REFCOUNT
927 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
928 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
930 lock_ObtainWrite(&smb_rctLock);
933 #ifdef DEBUG_SMB_REFCOUNT
934 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
935 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
940 #ifdef DEBUG_SMB_REFCOUNT
941 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
943 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
946 lock_AssertWrite(&smb_rctLock);
947 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
948 smb_ReleaseVCInternal(vcp);
951 #ifdef DEBUG_SMB_REFCOUNT
952 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
954 void smb_ReleaseVC(smb_vc_t *vcp)
957 lock_ObtainWrite(&smb_rctLock);
958 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
959 smb_ReleaseVCInternal(vcp);
960 lock_ReleaseWrite(&smb_rctLock);
963 #ifdef DEBUG_SMB_REFCOUNT
964 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
966 void smb_HoldVCNoLock(smb_vc_t *vcp)
969 lock_AssertWrite(&smb_rctLock);
971 #ifdef DEBUG_SMB_REFCOUNT
972 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
973 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
975 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
979 #ifdef DEBUG_SMB_REFCOUNT
980 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
982 void smb_HoldVC(smb_vc_t *vcp)
985 lock_ObtainWrite(&smb_rctLock);
987 #ifdef DEBUG_SMB_REFCOUNT
988 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
989 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
991 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
993 lock_ReleaseWrite(&smb_rctLock);
996 void smb_CleanupDeadVC(smb_vc_t *vcp)
1001 smb_tid_t *tidpIter;
1002 smb_tid_t *tidpNext;
1004 smb_user_t *uidpIter;
1005 smb_user_t *uidpNext;
1007 afs_uint32 refCount = 0;
1009 lock_ObtainMutex(&vcp->mx);
1010 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1011 lock_ReleaseMutex(&vcp->mx);
1012 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1015 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1016 lock_ReleaseMutex(&vcp->mx);
1017 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1019 lock_ObtainWrite(&smb_rctLock);
1020 /* remove VCP from smb_allVCsp */
1021 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1022 if ((*vcpp)->magic != SMB_VC_MAGIC)
1023 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1024 __FILE__, __LINE__);
1027 vcp->nextp = smb_deadVCsp;
1029 /* Hold onto the reference until we are done with this function */
1034 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1035 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1037 if (fidpIter->deleteOk)
1040 fid = fidpIter->fid;
1041 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1043 smb_HoldFIDNoLock(fidpIter);
1044 lock_ReleaseWrite(&smb_rctLock);
1046 smb_CloseFID(vcp, fidpIter, NULL, 0);
1047 smb_ReleaseFID(fidpIter);
1049 lock_ObtainWrite(&smb_rctLock);
1050 fidpNext = vcp->fidsp;
1053 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1054 tidpNext = tidpIter->nextp;
1055 if (tidpIter->deleteOk)
1057 tidpIter->deleteOk = 1;
1059 tid = tidpIter->tid;
1060 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1062 smb_HoldTIDNoLock(tidpIter);
1063 smb_ReleaseTID(tidpIter, TRUE);
1064 tidpNext = vcp->tidsp;
1067 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1068 uidpNext = uidpIter->nextp;
1069 if (uidpIter->deleteOk)
1071 uidpIter->deleteOk = 1;
1073 /* do not add an additional reference count for the smb_user_t
1074 * as the smb_vc_t already is holding a reference */
1075 lock_ReleaseWrite(&smb_rctLock);
1077 smb_ReleaseUID(uidpIter);
1079 lock_ObtainWrite(&smb_rctLock);
1080 uidpNext = vcp->usersp;
1083 /* The vcp is now on the deadVCsp list. We intentionally drop the
1084 * reference so that the refcount can reach 0 and we can delete it
1086 * If the refCount == 1 going into the ReleaseVCNoLock call
1087 * the object will be freed and it won't be safe to clear
1090 refCount = vcp->refCount;
1091 smb_ReleaseVCNoLock(vcp);
1093 lock_ObtainMutex(&vcp->mx);
1094 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1095 lock_ReleaseMutex(&vcp->mx);
1098 lock_ReleaseWrite(&smb_rctLock);
1099 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1102 #ifdef DEBUG_SMB_REFCOUNT
1103 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1105 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1110 lock_ObtainWrite(&smb_rctLock);
1112 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1113 if (tidp->refCount == 0 && tidp->deleteOk) {
1115 smb_ReleaseTID(tidp, TRUE);
1119 if (tid == tidp->tid) {
1124 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1125 tidp = malloc(sizeof(*tidp));
1126 memset(tidp, 0, sizeof(*tidp));
1127 tidp->nextp = vcp->tidsp;
1130 smb_HoldVCNoLock(vcp);
1132 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1135 #ifdef DEBUG_SMB_REFCOUNT
1137 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1138 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1141 lock_ReleaseWrite(&smb_rctLock);
1145 #ifdef DEBUG_SMB_REFCOUNT
1146 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1148 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1151 lock_AssertWrite(&smb_rctLock);
1153 #ifdef DEBUG_SMB_REFCOUNT
1154 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1155 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1159 #ifdef DEBUG_SMB_REFCOUNT
1160 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1162 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1167 cm_user_t *userp = NULL;
1168 smb_vc_t *vcp = NULL;
1171 lock_ObtainWrite(&smb_rctLock);
1173 lock_AssertWrite(&smb_rctLock);
1175 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1176 #ifdef DEBUG_SMB_REFCOUNT
1177 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1178 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1180 if (tidp->refCount == 0) {
1181 if (tidp->deleteOk) {
1182 ltpp = &tidp->vcp->tidsp;
1183 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1187 osi_assertx(tp != NULL, "null smb_tid_t");
1189 lock_FinalizeMutex(&tidp->mx);
1190 userp = tidp->userp; /* remember to drop ref later */
1198 smb_ReleaseVCNoLock(vcp);
1200 lock_ReleaseWrite(&smb_rctLock);
1202 cm_ReleaseUser(userp);
1205 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1207 smb_user_t *uidp = NULL;
1209 lock_ObtainWrite(&smb_rctLock);
1210 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1211 if (uid == uidp->userID) {
1213 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1215 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1219 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1220 uidp = malloc(sizeof(*uidp));
1221 memset(uidp, 0, sizeof(*uidp));
1222 uidp->nextp = vcp->usersp;
1223 uidp->refCount = 2; /* one for the vcp and one for the caller */
1225 smb_HoldVCNoLock(vcp);
1227 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1229 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1231 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1233 lock_ReleaseWrite(&smb_rctLock);
1237 afs_int32 smb_userIsLocalSystem(smb_user_t *uidp)
1240 DWORD dwSize1 = 0, dwSize2 = 0;
1241 wchar_t *pszRefDomain = NULL;
1242 SID_NAME_USE snu = SidTypeGroup;
1243 clientchar_t * secSidString = NULL;
1245 afs_int32 isSystem = 0;
1247 if (uidp->unp->flags & SMB_USERNAMEFLAG_SID) {
1248 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, uidp->unp->name);
1253 * The input name is not a SID for the user. See if we can
1254 * obtain the SID for the specified name. If we can, use
1255 * that instead of the name provided for the comparison.
1258 LookupAccountNameW( NULL /* System Name to begin Search */,
1263 gle = GetLastError();
1264 if (gle == ERROR_INSUFFICIENT_BUFFER) {
1265 pSid = malloc(dwSize1);
1267 * Although dwSize2 is supposed to include the terminating
1268 * NUL character, on Win7 it does not.
1270 pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
1273 if ( pSid && pszRefDomain ) {
1274 memset(pSid, 0, dwSize1);
1276 if (LookupAccountNameW( NULL /* System Name to begin Search */,
1279 pszRefDomain, &dwSize2,
1281 ConvertSidToStringSidW(pSid, &secSidString);
1285 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, secSidString);
1286 LocalFree(secSidString);
1297 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1300 smb_username_t *unp= NULL;
1302 lock_ObtainWrite(&smb_rctLock);
1303 for(unp = usernamesp; unp; unp = unp->nextp) {
1304 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1305 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1310 if (!unp && (flags & SMB_FLAG_CREATE)) {
1311 unp = malloc(sizeof(*unp));
1312 memset(unp, 0, sizeof(*unp));
1314 unp->nextp = usernamesp;
1315 unp->name = cm_ClientStrDup(usern);
1316 unp->machine = cm_ClientStrDup(machine);
1318 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1319 if (flags & SMB_FLAG_AFSLOGON)
1320 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1323 lock_ReleaseWrite(&smb_rctLock);
1327 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1329 smb_user_t *uidp= NULL;
1331 lock_ObtainWrite(&smb_rctLock);
1332 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1335 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1337 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1338 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1343 lock_ReleaseWrite(&smb_rctLock);
1347 void smb_ReleaseUsername(smb_username_t *unp)
1350 smb_username_t **lupp;
1351 cm_user_t *userp = NULL;
1352 time_t now = osi_Time();
1354 lock_ObtainWrite(&smb_rctLock);
1355 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1356 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1357 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1359 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1363 osi_assertx(up != NULL, "null smb_username_t");
1365 up->nextp = NULL; /* do not remove this */
1366 lock_FinalizeMutex(&unp->mx);
1372 lock_ReleaseWrite(&smb_rctLock);
1374 cm_ReleaseUser(userp);
1377 void smb_HoldUIDNoLock(smb_user_t *uidp)
1379 lock_AssertWrite(&smb_rctLock);
1383 void smb_ReleaseUID(smb_user_t *uidp)
1387 smb_username_t *unp = NULL;
1389 lock_ObtainWrite(&smb_rctLock);
1390 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1391 if (uidp->refCount == 0) {
1392 lupp = &uidp->vcp->usersp;
1393 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1397 osi_assertx(up != NULL, "null smb_user_t");
1399 lock_FinalizeMutex(&uidp->mx);
1401 smb_ReleaseVCNoLock(uidp->vcp);
1405 lock_ReleaseWrite(&smb_rctLock);
1409 cm_ReleaseUserVCRef(unp->userp);
1410 smb_ReleaseUsername(unp);
1414 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1416 cm_user_t *up = NULL;
1421 lock_ObtainMutex(&uidp->mx);
1423 up = uidp->unp->userp;
1426 lock_ReleaseMutex(&uidp->mx);
1432 /* retrieve a held reference to a user structure corresponding to an incoming
1434 * corresponding release function is cm_ReleaseUser.
1436 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1439 cm_user_t *up = NULL;
1442 smbp = (smb_t *) inp;
1443 uidp = smb_FindUID(vcp, smbp->uid, 0);
1447 up = smb_GetUserFromUID(uidp);
1449 smb_ReleaseUID(uidp);
1454 * Return a pointer to a pathname extracted from a TID structure. The
1455 * TID structure is not held; assume it won't go away.
1457 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1462 tidp = smb_FindTID(vcp, tid, 0);
1466 if (tidp->flags & SMB_TIDFLAG_IPC) {
1467 code = CM_ERROR_TIDIPC;
1468 /* tidp->pathname would be NULL, but that's fine */
1470 *treepath = tidp->pathname;
1471 smb_ReleaseTID(tidp, FALSE);
1476 /* check to see if we have a chained fid, that is, a fid that comes from an
1477 * OpenAndX message that ran earlier in this packet. In this case, the fid
1478 * field in a read, for example, request, isn't set, since the value is
1479 * supposed to be inherited from the openAndX call.
1481 int smb_ChainFID(int fid, smb_packet_t *inp)
1483 if (inp->fid == 0 || inp->inCount == 0)
1489 /* are we a priv'd user? What does this mean on NT? */
1490 int smb_SUser(cm_user_t *userp)
1495 /* find a file ID. If we pass in 0 we select an unused File ID.
1496 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1497 * smb_fid_t data structure if desired File ID cannot be found.
1499 #ifdef DEBUG_SMB_REFCOUNT
1500 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1502 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1509 if (!(flags & SMB_FLAG_CREATE))
1514 lock_ObtainWrite(&smb_rctLock);
1516 fid = vcp->fidCounter;
1519 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1520 if (fidp->refCount == 0 && fidp->deleteOk) {
1522 lock_ReleaseWrite(&smb_rctLock);
1523 smb_ReleaseFID(fidp);
1524 lock_ObtainWrite(&smb_rctLock);
1526 * We dropped the smb_rctLock so the fid value we are using
1527 * may now be used by another thread. Start over with the
1528 * current vcp->fidCounter.
1531 fid = vcp->fidCounter;
1534 if (fid == fidp->fid) {
1536 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1538 if (fid == 0xFFFF) {
1540 "New FID number wraps on vcp 0x%x", vcp);
1550 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1551 char eventName[MAX_PATH];
1555 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1557 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1559 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1560 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1561 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1562 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1563 thrd_CloseHandle(event);
1565 if (fid == 0xFFFF) {
1566 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1572 fidp = malloc(sizeof(*fidp));
1573 memset(fidp, 0, sizeof(*fidp));
1574 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1577 smb_HoldVCNoLock(vcp);
1578 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1580 fidp->curr_chunk = fidp->prev_chunk = -2;
1581 fidp->raw_write_event = event;
1583 vcp->fidCounter = fid+1;
1584 if (vcp->fidCounter == 0xFFFF) {
1585 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1587 vcp->fidCounter = 1;
1592 #ifdef DEBUG_SMB_REFCOUNT
1594 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1598 lock_ReleaseWrite(&smb_rctLock);
1603 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1604 #ifdef DEBUG_SMB_REFCOUNT
1605 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1607 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1610 smb_fid_t *fidp = NULL, *nextp = NULL;
1616 * If the fidp->scp changes out from under us then
1617 * we must not grab a refCount. It means the *fidp
1618 * was processed by smb_CloseFID() and the *fidp is
1619 * no longer valid for use.
1621 lock_ObtainWrite(&smb_rctLock);
1622 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1623 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1627 if (scp == fidp->scp) {
1628 lock_ReleaseWrite(&smb_rctLock);
1629 lock_ObtainMutex(&fidp->mx);
1630 lock_ObtainWrite(&smb_rctLock);
1631 if (scp == fidp->scp) {
1632 lock_ReleaseMutex(&fidp->mx);
1635 lock_ReleaseMutex(&fidp->mx);
1638 if (fidp->refCount > 1) {
1641 lock_ReleaseWrite(&smb_rctLock);
1642 smb_ReleaseFID(fidp);
1643 lock_ObtainWrite(&smb_rctLock);
1648 if (nextp->refCount > 1) {
1651 lock_ReleaseWrite(&smb_rctLock);
1652 smb_ReleaseFID(nextp);
1653 lock_ObtainWrite(&smb_rctLock);
1657 #ifdef DEBUG_SMB_REFCOUNT
1659 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1660 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1663 lock_ReleaseWrite(&smb_rctLock);
1667 #ifdef DEBUG_SMB_REFCOUNT
1668 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1670 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1673 lock_AssertWrite(&smb_rctLock);
1675 #ifdef DEBUG_SMB_REFCOUNT
1676 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1677 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1682 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1683 /* the smb_fid_t->mx and smb_rctLock must not be held */
1684 #ifdef DEBUG_SMB_REFCOUNT
1685 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1687 void smb_ReleaseFID(smb_fid_t *fidp)
1690 cm_scache_t *scp = NULL;
1691 cm_user_t *userp = NULL;
1692 smb_vc_t *vcp = NULL;
1693 smb_ioctl_t *ioctlp;
1695 lock_ObtainMutex(&fidp->mx);
1696 lock_ObtainWrite(&smb_rctLock);
1697 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1698 #ifdef DEBUG_SMB_REFCOUNT
1699 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1700 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1702 if (fidp->refCount == 0) {
1703 if (fidp->deleteOk) {
1706 scp = fidp->scp; /* release after lock is released */
1708 lock_ObtainWrite(&scp->rw);
1709 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1710 lock_ReleaseWrite(&scp->rw);
1711 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1714 userp = fidp->userp;
1718 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1719 thrd_CloseHandle(fidp->raw_write_event);
1721 /* and see if there is ioctl stuff to free */
1722 ioctlp = fidp->ioctlp;
1725 cm_FreeSpace(ioctlp->prefix);
1726 if (ioctlp->ioctl.inAllocp)
1727 free(ioctlp->ioctl.inAllocp);
1728 if (ioctlp->ioctl.outAllocp)
1729 free(ioctlp->ioctl.outAllocp);
1733 smb_CleanupRPCFid(fidp);
1735 lock_ReleaseMutex(&fidp->mx);
1736 lock_FinalizeMutex(&fidp->mx);
1741 smb_ReleaseVCNoLock(vcp);
1745 lock_ReleaseMutex(&fidp->mx);
1747 lock_ReleaseWrite(&smb_rctLock);
1749 /* now release the scache structure */
1751 cm_ReleaseSCache(scp);
1754 cm_ReleaseUser(userp);
1758 * Case-insensitive search for one string in another;
1759 * used to find variable names in submount pathnames.
1761 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1763 clientchar_t *cursor;
1765 for (cursor = str1; *cursor; cursor++)
1766 if (cm_ClientStrCmpI(cursor, str2) == 0)
1773 * Substitute a variable value for its name in a submount pathname. Variable
1774 * name has been identified by smb_stristr() and is in substr. Variable name
1775 * length (plus one) is in substr_size. Variable value is in newstr.
1777 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1778 unsigned int substr_size, clientchar_t *newstr)
1780 clientchar_t temp[1024];
1782 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1783 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1784 cm_ClientStrCat(str1, cchstr1, temp);
1787 clientchar_t VNUserName[] = _C("%USERNAME%");
1788 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1789 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1790 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1792 typedef struct smb_findShare_rock {
1793 clientchar_t * shareName;
1794 clientchar_t * match;
1796 } smb_findShare_rock_t;
1798 #define SMB_FINDSHARE_EXACT_MATCH 1
1799 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1801 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1805 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1806 normchar_t normName[MAX_PATH];
1808 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1809 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1810 osi_LogSaveString(smb_logp, dep->name));
1814 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1815 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1816 matchType = SMB_FINDSHARE_EXACT_MATCH;
1818 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1821 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1822 vrock->matchType = matchType;
1824 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1825 return CM_ERROR_STOPNOW;
1831 /* find a shareName in the table of submounts */
1832 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1833 clientchar_t *shareName,
1834 clientchar_t **pathNamep)
1838 clientchar_t pathName[1024];
1841 clientchar_t *p, *q;
1842 fschar_t *cellname = NULL;
1845 DWORD allSubmount = 1;
1847 /* if allSubmounts == 0, only return the //mountRoot/all share
1848 * if in fact it has been been created in the subMounts table.
1849 * This is to allow sites that want to restrict access to the
1852 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1853 0, KEY_QUERY_VALUE, &parmKey);
1854 if (code == ERROR_SUCCESS) {
1855 cblen = sizeof(allSubmount);
1856 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1857 (BYTE *) &allSubmount, &cblen);
1858 if (code != ERROR_SUCCESS) {
1861 RegCloseKey (parmKey);
1864 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1869 /* In case, the all share is disabled we need to still be able
1870 * to handle ioctl requests
1872 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1873 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1877 if (MSRPC_IsWellKnownService(shareName) ||
1878 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1879 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1885 /* Check for volume references
1887 * They look like <cell>{%,#}<volume>
1889 if (cm_ClientStrChr(shareName, '%') != NULL ||
1890 cm_ClientStrChr(shareName, '#') != NULL) {
1891 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1892 /* make room for '/@vol:' + mountchar + NULL terminator*/
1894 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1895 osi_LogSaveClientString(smb_logp, shareName));
1897 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1898 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1899 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1901 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1903 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1904 cm_ClientStrLwr(*pathNamep);
1905 osi_Log1(smb_logp, " returning pathname [%S]",
1906 osi_LogSaveClientString(smb_logp, *pathNamep));
1914 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1915 0, KEY_QUERY_VALUE, &parmKey);
1916 if (code == ERROR_SUCCESS) {
1917 cblen = sizeof(pathName);
1918 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1919 (BYTE *) pathName, &cblen);
1920 if (code != ERROR_SUCCESS)
1922 RegCloseKey (parmKey);
1926 cchlen = cblen / sizeof(clientchar_t);
1927 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1928 /* We can accept either unix or PC style AFS pathnames. Convert
1929 * Unix-style to PC style here for internal use.
1932 cchlen = lengthof(pathName);
1934 /* within this code block, we maintain, cchlen = writable
1935 buffer length of p */
1937 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1938 p += cm_mountRootCLen; /* skip mount path */
1939 cchlen -= (DWORD)(p - pathName);
1944 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1950 clientchar_t temp[1024];
1952 if (var = smb_stristr(p, VNUserName)) {
1953 if (uidp && uidp->unp)
1954 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1956 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1958 else if (var = smb_stristr(p, VNLCUserName))
1960 if (uidp && uidp->unp)
1961 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1963 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1964 cm_ClientStrLwr(temp);
1965 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1967 else if (var = smb_stristr(p, VNComputerName))
1969 sizeTemp = lengthof(temp);
1970 GetComputerNameW(temp, &sizeTemp);
1971 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1973 else if (var = smb_stristr(p, VNLCComputerName))
1975 sizeTemp = lengthof(temp);
1976 GetComputerName((LPTSTR)temp, &sizeTemp);
1977 cm_ClientStrLwr(temp);
1978 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1983 *pathNamep = cm_ClientStrDup(p);
1988 /* First lookup shareName in root.afs */
1990 smb_findShare_rock_t vrock;
1992 fschar_t ftemp[1024];
1993 clientchar_t * p = shareName;
1998 /* attempt to locate a partial match in root.afs. This is because
1999 when using the ANSI RAP calls, the share name is limited to 13 chars
2000 and hence is truncated. Of course we prefer exact matches. */
2002 thyper.HighPart = 0;
2005 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2006 if (vrock.shareName == NULL)
2009 vrock.matchType = 0;
2011 userp = (uidp? (uidp->unp ? uidp->unp->userp : cm_rootUserp) : cm_rootUserp);
2012 rscp = cm_RootSCachep(userp, &req);
2013 cm_HoldSCache(rscp);
2014 code = cm_ApplyDir(rscp, smb_FindShareProc, &vrock, &thyper,
2016 cm_ReleaseSCache(rscp);
2018 free(vrock.shareName);
2019 vrock.shareName = NULL;
2021 if (vrock.matchType) {
2022 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2023 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2028 /* if we get here, there was no match for the share in root.afs */
2029 /* so try to create \\<netbiosName>\<cellname> */
2034 /* Get the full name for this cell */
2035 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2036 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2037 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2038 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2039 if (code && cm_dnsEnabled) {
2041 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2046 /* construct the path */
2048 clientchar_t temp[1024];
2050 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2051 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2052 rw ? _C("/.%S/") : _C("/%S/"), temp);
2053 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2063 /* Client-side offline caching policy types */
2064 #define CSC_POLICY_MANUAL 0
2065 #define CSC_POLICY_DOCUMENTS 1
2066 #define CSC_POLICY_PROGRAMS 2
2067 #define CSC_POLICY_DISABLE 3
2069 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2072 clientchar_t policy[1024];
2075 int retval = CSC_POLICY_MANUAL;
2077 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2078 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2081 REG_OPTION_NON_VOLATILE,
2085 NULL ) != ERROR_SUCCESS)
2086 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2088 len = sizeof(policy);
2089 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2091 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2093 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2095 retval = CSC_POLICY_MANUAL;
2097 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2099 retval = CSC_POLICY_DOCUMENTS;
2101 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2103 retval = CSC_POLICY_PROGRAMS;
2105 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2107 retval = CSC_POLICY_DISABLE;
2110 RegCloseKey(hkCSCPolicy);
2114 /* find a dir search structure by cookie value, and return it held.
2115 * Must be called with smb_globalLock held.
2117 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2119 smb_dirSearch_t *dsp;
2121 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2122 if (dsp->cookie == cookie) {
2123 if (dsp != smb_firstDirSearchp) {
2124 /* move to head of LRU queue, too, if we're not already there */
2125 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2126 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2127 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2128 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2129 if (!smb_lastDirSearchp)
2130 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2138 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2139 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2140 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2146 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2148 lock_ObtainMutex(&dsp->mx);
2149 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2150 dsp->cookie, dsp, dsp->scp);
2151 dsp->flags |= SMB_DIRSEARCH_DELETE;
2152 if (dsp->scp != NULL) {
2153 lock_ObtainWrite(&dsp->scp->rw);
2154 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2155 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2156 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2157 dsp->scp->bulkStatProgress = hzero;
2159 lock_ReleaseWrite(&dsp->scp->rw);
2161 lock_ReleaseMutex(&dsp->mx);
2164 /* Must be called with the smb_globalLock held */
2165 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2167 cm_scache_t *scp = NULL;
2169 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2170 if (dsp->refCount == 0) {
2171 lock_ObtainMutex(&dsp->mx);
2172 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2173 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2174 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2175 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2176 lock_ReleaseMutex(&dsp->mx);
2177 lock_FinalizeMutex(&dsp->mx);
2179 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2180 dsp->cookie, dsp, scp);
2183 lock_ReleaseMutex(&dsp->mx);
2186 /* do this now to avoid spurious locking hierarchy creation */
2188 cm_ReleaseSCache(scp);
2191 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2193 lock_ObtainWrite(&smb_globalLock);
2194 smb_ReleaseDirSearchNoLock(dsp);
2195 lock_ReleaseWrite(&smb_globalLock);
2198 /* find a dir search structure by cookie value, and return it held */
2199 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2201 smb_dirSearch_t *dsp;
2203 lock_ObtainWrite(&smb_globalLock);
2204 dsp = smb_FindDirSearchNoLock(cookie);
2205 lock_ReleaseWrite(&smb_globalLock);
2209 /* GC some dir search entries, in the address space expected by the specific protocol.
2210 * Must be called with smb_globalLock held; release the lock temporarily.
2212 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2213 void smb_GCDirSearches(int isV3)
2215 smb_dirSearch_t *prevp;
2216 smb_dirSearch_t *dsp;
2217 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2221 victimCount = 0; /* how many have we got so far */
2222 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2223 /* we'll move tp from queue, so
2226 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2227 /* if no one is using this guy, and we're either in the new protocol,
2228 * or we're in the old one and this is a small enough ID to be useful
2229 * to the old protocol, GC this guy.
2231 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2232 /* hold and delete */
2233 lock_ObtainMutex(&dsp->mx);
2234 dsp->flags |= SMB_DIRSEARCH_DELETE;
2235 lock_ReleaseMutex(&dsp->mx);
2236 victimsp[victimCount++] = dsp;
2240 /* don't do more than this */
2241 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2245 /* now release them */
2246 for (i = 0; i < victimCount; i++) {
2247 smb_ReleaseDirSearchNoLock(victimsp[i]);
2251 /* function for allocating a dir search entry. We need these to remember enough context
2252 * since we don't get passed the path from call to call during a directory search.
2254 * Returns a held dir search structure, and bumps the reference count on the vnode,
2255 * since it saves a pointer to the vnode.
2257 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2259 smb_dirSearch_t *dsp;
2265 lock_ObtainWrite(&smb_globalLock);
2268 /* what's the biggest ID allowed in this version of the protocol */
2269 /* TODO: do we really want a non v3 dir search request to wrap
2270 smb_dirSearchCounter? */
2271 maxAllowed = isV3 ? 65535 : 255;
2272 if (smb_dirSearchCounter > maxAllowed)
2273 smb_dirSearchCounter = 1;
2275 start = smb_dirSearchCounter;
2278 /* twice so we have enough tries to find guys we GC after one pass;
2279 * 10 extra is just in case I mis-counted.
2281 if (++counter > 2*maxAllowed+10)
2282 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2284 if (smb_dirSearchCounter > maxAllowed) {
2285 smb_dirSearchCounter = 1;
2287 if (smb_dirSearchCounter == start) {
2289 smb_GCDirSearches(isV3);
2292 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2294 /* don't need to watch for refcount zero and deleted, since
2295 * we haven't dropped the global lock.
2298 ++smb_dirSearchCounter;
2302 dsp = malloc(sizeof(*dsp));
2303 memset(dsp, 0, sizeof(*dsp));
2304 dsp->cookie = smb_dirSearchCounter;
2305 ++smb_dirSearchCounter;
2307 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2308 dsp->lastTime = osi_Time();
2309 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2310 if (!smb_lastDirSearchp)
2311 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2313 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2317 lock_ReleaseWrite(&smb_globalLock);
2321 static smb_packet_t *smb_GetPacket(void)
2325 lock_ObtainWrite(&smb_globalLock);
2326 tbp = smb_packetFreeListp;
2328 smb_packetFreeListp = tbp->nextp;
2329 lock_ReleaseWrite(&smb_globalLock);
2331 tbp = calloc(sizeof(*tbp),1);
2332 tbp->magic = SMB_PACKETMAGIC;
2335 tbp->resumeCode = 0;
2341 tbp->ncb_length = 0;
2344 tbp->stringsp = NULL;
2346 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2351 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2354 tbp = smb_GetPacket();
2355 memcpy(tbp, pkt, sizeof(smb_packet_t));
2356 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2357 tbp->stringsp = NULL;
2359 smb_HoldVC(tbp->vcp);
2363 static NCB *smb_GetNCB(void)
2368 lock_ObtainWrite(&smb_globalLock);
2369 tbp = smb_ncbFreeListp;
2371 smb_ncbFreeListp = tbp->nextp;
2372 lock_ReleaseWrite(&smb_globalLock);
2374 tbp = calloc(sizeof(*tbp),1);
2375 tbp->magic = SMB_NCBMAGIC;
2378 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2380 memset(&tbp->ncb, 0, sizeof(NCB));
2385 static void FreeSMBStrings(smb_packet_t * pkt)
2390 for (s = pkt->stringsp; s; s = ns) {
2394 pkt->stringsp = NULL;
2397 void smb_FreePacket(smb_packet_t *tbp)
2399 smb_vc_t * vcp = NULL;
2400 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2402 lock_ObtainWrite(&smb_globalLock);
2403 tbp->nextp = smb_packetFreeListp;
2404 smb_packetFreeListp = tbp;
2405 tbp->magic = SMB_PACKETMAGIC;
2409 tbp->resumeCode = 0;
2415 tbp->ncb_length = 0;
2417 FreeSMBStrings(tbp);
2418 lock_ReleaseWrite(&smb_globalLock);
2424 static void smb_FreeNCB(NCB *bufferp)
2428 tbp = (smb_ncb_t *) bufferp;
2429 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2431 lock_ObtainWrite(&smb_globalLock);
2432 tbp->nextp = smb_ncbFreeListp;
2433 smb_ncbFreeListp = tbp;
2434 lock_ReleaseWrite(&smb_globalLock);
2437 /* get a ptr to the data part of a packet, and its count */
2438 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2442 unsigned char *afterParmsp;
2444 parmBytes = *smbp->wctp << 1;
2445 afterParmsp = smbp->wctp + parmBytes + 1;
2447 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2448 if (nbytesp) *nbytesp = dataBytes;
2450 /* don't forget to skip the data byte count, since it follows
2451 * the parameters; that's where the "2" comes from below.
2453 return (unsigned char *) (afterParmsp + 2);
2456 /* must set all the returned parameters before playing around with the
2457 * data region, since the data region is located past the end of the
2458 * variable number of parameters.
2460 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2462 unsigned char *afterParmsp;
2464 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2466 *afterParmsp++ = dsize & 0xff;
2467 *afterParmsp = (dsize>>8) & 0xff;
2470 /* return the parm'th parameter in the smbp packet */
2471 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2474 unsigned char *parmDatap;
2476 parmCount = *smbp->wctp;
2478 if (parm >= parmCount) {
2481 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2482 parm, parmCount, smbp->ncb_length);
2483 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2484 parm, parmCount, smbp->ncb_length);
2485 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2486 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2487 osi_panic(s, __FILE__, __LINE__);
2489 parmDatap = smbp->wctp + (2*parm) + 1;
2491 return parmDatap[0] + (parmDatap[1] << 8);
2494 /* return the parm'th parameter in the smbp packet */
2495 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2498 unsigned char *parmDatap;
2500 parmCount = *smbp->wctp;
2502 if (parm >= parmCount) {
2505 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2506 parm, parmCount, smbp->ncb_length);
2507 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2508 parm, parmCount, smbp->ncb_length);
2509 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2510 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2511 osi_panic(s, __FILE__, __LINE__);
2513 parmDatap = smbp->wctp + (2*parm) + 1;
2515 return parmDatap[0];
2518 /* return the parm'th parameter in the smbp packet */
2519 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2522 unsigned char *parmDatap;
2524 parmCount = *smbp->wctp;
2526 if (parm + 1 >= parmCount) {
2529 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2530 parm, parmCount, smbp->ncb_length);
2531 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2532 parm, parmCount, smbp->ncb_length);
2533 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2534 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2535 osi_panic(s, __FILE__, __LINE__);
2537 parmDatap = smbp->wctp + (2*parm) + 1;
2539 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2542 /* return the parm'th parameter in the smbp packet */
2543 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2546 unsigned char *parmDatap;
2548 parmCount = *smbp->wctp;
2550 if (parm * 2 + offset >= parmCount * 2) {
2553 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2554 parm, offset, parmCount, smbp->ncb_length);
2555 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2556 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2557 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2558 parm, offset, parmCount, smbp->ncb_length);
2559 osi_panic(s, __FILE__, __LINE__);
2561 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2563 return parmDatap[0] + (parmDatap[1] << 8);
2566 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2568 unsigned char *parmDatap;
2570 /* make sure we have enough slots */
2571 if (*smbp->wctp <= slot)
2572 *smbp->wctp = slot+1;
2574 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2575 *parmDatap++ = parmValue & 0xff;
2576 *parmDatap = (parmValue>>8) & 0xff;
2579 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2581 unsigned char *parmDatap;
2583 /* make sure we have enough slots */
2584 if (*smbp->wctp <= slot)
2585 *smbp->wctp = slot+2;
2587 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2588 *parmDatap++ = parmValue & 0xff;
2589 *parmDatap++ = (parmValue>>8) & 0xff;
2590 *parmDatap++ = (parmValue>>16) & 0xff;
2591 *parmDatap = (parmValue>>24) & 0xff;
2594 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2596 unsigned char *parmDatap;
2599 /* make sure we have enough slots */
2600 if (*smbp->wctp <= slot)
2601 *smbp->wctp = slot+4;
2603 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2605 *parmDatap++ = *parmValuep++;
2608 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2610 unsigned char *parmDatap;
2612 /* make sure we have enough slots */
2613 if (*smbp->wctp <= slot) {
2614 if (smbp->oddByte) {
2616 *smbp->wctp = slot+1;
2621 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2622 *parmDatap++ = parmValue & 0xff;
2627 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2628 clientchar_t *inPathp)
2630 clientchar_t *lastSlashp;
2631 clientchar_t *streamp = NULL;
2632 clientchar_t *typep = NULL;
2634 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2635 if (lastComponentp) {
2636 *lastComponentp = lastSlashp;
2640 * If the name contains a stream name and a type
2641 * and the stream name is the nul-string and the
2642 * type is $DATA, then strip "::$DATA" from the
2643 * last component string that is returned.
2645 * Otherwise, return the full path name and allow
2646 * the file name to be rejected because it contains
2649 typep = cm_ClientStrRChr(lastSlashp, L':');
2650 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2652 streamp = cm_ClientStrRChr(lastSlashp, L':');
2653 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2657 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2658 osi_LogSaveClientString(smb_logp,streamp),
2659 osi_LogSaveClientString(smb_logp,typep));
2663 if (inPathp == lastSlashp)
2665 *outPathp++ = *inPathp++;
2674 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2675 char **chainpp, int flags)
2678 afs_uint32 type = *inp++;
2681 * The first byte specifies the type of the input string.
2682 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2686 /* Length Counted */
2687 case 0x1: /* Data Block */
2688 case 0x5: /* Variable Block */
2689 cb = *inp++ << 16 | *inp++;
2692 /* Null-terminated string */
2693 case 0x4: /* ASCII */
2694 case 0x3: /* Pathname */
2695 case 0x2: /* Dialect */
2696 cb = sizeof(pktp->data) - (inp - pktp->data);
2697 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2698 #ifdef DEBUG_UNICODE
2701 cb = sizeof(pktp->data);
2706 return NULL; /* invalid input */
2710 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2711 flags |= SMB_STRF_FORCEASCII;
2714 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2717 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2718 char ** chainpp, int flags)
2723 if (!WANTS_UNICODE(pktp))
2724 flags |= SMB_STRF_FORCEASCII;
2727 cb = sizeof(pktp->data) - (inp - pktp->data);
2728 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2729 #ifdef DEBUG_UNICODE
2732 cb = sizeof(pktp->data);
2734 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2735 flags | SMB_STRF_SRCNULTERM);
2738 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2739 size_t cb, char ** chainpp, int flags)
2742 if (!WANTS_UNICODE(pktp))
2743 flags |= SMB_STRF_FORCEASCII;
2746 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2749 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2750 size_t cch, char ** chainpp, int flags)
2755 if (!WANTS_UNICODE(pktp))
2756 flags |= SMB_STRF_FORCEASCII;
2758 cb = cch * sizeof(wchar_t);
2761 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2765 smb_ParseStringBuf(const unsigned char * bufbase,
2766 cm_space_t ** stringspp,
2767 unsigned char *inp, size_t *pcb_max,
2768 char **chainpp, int flags)
2771 if (!(flags & SMB_STRF_FORCEASCII)) {
2773 cm_space_t * spacep;
2776 if (bufbase && ((inp - bufbase) % 2) != 0) {
2777 inp++; /* unicode strings are always word aligned */
2781 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2783 cch_src = *pcb_max / sizeof(wchar_t);
2787 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2794 spacep = cm_GetSpace();
2795 spacep->nextp = *stringspp;
2796 *stringspp = spacep;
2800 *chainpp = inp + sizeof(wchar_t);
2803 *(spacep->wdata) = 0;
2804 return spacep->wdata;
2807 StringCchCopyNW(spacep->wdata,
2808 lengthof(spacep->wdata),
2809 (const clientchar_t *) inp, cch_src);
2812 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2814 return spacep->wdata;
2818 cm_space_t * spacep;
2821 /* Not using Unicode */
2823 *chainpp = inp + strlen(inp) + 1;
2826 spacep = cm_GetSpace();
2827 spacep->nextp = *stringspp;
2828 *stringspp = spacep;
2830 cchdest = lengthof(spacep->wdata);
2831 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2832 spacep->wdata, cchdest);
2834 return spacep->wdata;
2840 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2842 size_t * plen, int flags)
2848 /* we are only calculating the required size */
2855 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2857 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2858 if (!(flags & SMB_STRF_IGNORENUL))
2859 *plen += sizeof(wchar_t);
2861 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2871 cch_str = cm_ClientStrLen(str);
2872 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2875 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2883 /* if outp != NULL ... */
2885 /* Number of bytes left in the buffer.
2887 If outp lies inside the packet data buffer, we assume that the
2888 buffer is the packet data buffer. Otherwise we assume that the
2889 buffer is sizeof(packet->data).
2892 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2893 align = (int)((outp - pktp->data) % 2);
2894 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2896 align = (int)(((size_t) outp) % 2);
2897 buffersize = (int)sizeof(pktp->data);
2902 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2908 if (*str == _C('\0')) {
2910 if (buffersize < sizeof(wchar_t))
2913 *((wchar_t *) outp) = L'\0';
2914 if (plen && !(flags & SMB_STRF_IGNORENUL))
2915 *plen += sizeof(wchar_t);
2916 return outp + sizeof(wchar_t);
2919 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2921 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2922 osi_LogSaveClientString(smb_logp, str),
2928 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2930 return outp + sizeof(wchar_t) * nchars;
2938 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2941 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2943 return outp + cch_dest;
2947 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2953 tlen = inp[0] + (inp[1]<<8);
2954 inp += 2; /* skip length field */
2957 *chainpp = inp + tlen;
2966 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2970 if (*inp++ != 0x1) return NULL;
2971 tlen = inp[0] + (inp[1]<<8);
2972 inp += 2; /* skip length field */
2975 *chainpp = inp + tlen;
2978 if (lengthp) *lengthp = tlen;
2983 /* format a packet as a response */
2984 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2989 outp = (smb_t *) op;
2991 /* zero the basic structure through the smb_wct field, and zero the data
2992 * size field, assuming that wct stays zero; otherwise, you have to
2993 * explicitly set the data size field, too.
2995 inSmbp = (smb_t *) inp;
2996 memset(outp, 0, sizeof(smb_t)+2);
3002 outp->com = inSmbp->com;
3003 outp->tid = inSmbp->tid;
3004 outp->pid = inSmbp->pid;
3005 outp->uid = inSmbp->uid;
3006 outp->mid = inSmbp->mid;
3007 outp->res[0] = inSmbp->res[0];
3008 outp->res[1] = inSmbp->res[1];
3009 op->inCom = inSmbp->com;
3011 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3012 #ifdef SEND_CANONICAL_PATHNAMES
3013 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3015 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3017 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3018 outp->flg2 |= SMB_FLAGS2_UNICODE;
3021 /* copy fields in generic packet area */
3022 op->wctp = &outp->wct;
3025 /* send a (probably response) packet; vcp tells us to whom to send it.
3026 * we compute the length by looking at wct and bcc fields.
3028 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3038 ncbp = smb_GetNCB();
3042 memset(ncbp, 0, sizeof(NCB));
3044 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3045 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3046 extra += tp[0] + (tp[1]<<8);
3047 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3048 extra += 3; /* wct and length fields */
3050 ncbp->ncb_length = extra; /* bytes to send */
3051 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3052 ncbp->ncb_lana_num = vcp->lana;
3053 ncbp->ncb_command = NCBSEND; /* op means send data */
3054 ncbp->ncb_buffer = (char *) inp;/* packet */
3055 code = Netbios(ncbp);
3058 const char * s = ncb_error_string(code);
3059 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3060 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3062 lock_ObtainMutex(&vcp->mx);
3063 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3064 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3066 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3067 lock_ReleaseMutex(&vcp->mx);
3068 lock_ObtainWrite(&smb_globalLock);
3069 dead_sessions[vcp->session] = TRUE;
3070 lock_ReleaseWrite(&smb_globalLock);
3071 smb_CleanupDeadVC(vcp);
3073 lock_ReleaseMutex(&vcp->mx);
3081 void smb_MapNTError(long code, unsigned long *NTStatusp)
3083 unsigned long NTStatus;
3085 /* map CM_ERROR_* errors to NT 32-bit status codes */
3086 /* NT Status codes are listed in ntstatus.h not winerror.h */
3090 else if (code == CM_ERROR_NOSUCHCELL) {
3091 NTStatus = 0xC0000034L; /* Name not found */
3093 else if (code == CM_ERROR_NOSUCHVOLUME) {
3094 NTStatus = 0xC0000034L; /* Name not found */
3096 else if (code == CM_ERROR_TIMEDOUT) {
3098 NTStatus = 0xC00000CFL; /* Sharing Paused */
3100 /* Do not send Timeout to the SMB redirector.
3101 * It causes the redirector to drop the connection */
3102 NTStatus = 0x00000102L; /* Timeout */
3103 /* do not send Retry to the SMB redirector.
3104 * It believes the error comes from the transport
3105 * layer not from the SMB server. */
3106 NTStatus = 0xC000022DL; /* Retry */
3108 NTStatus = 0xC00000B5L; /* I/O Timeout */
3111 else if (code == CM_ERROR_RETRY) {
3113 NTStatus = 0xC000022DL; /* Retry */
3115 NTStatus = 0xC00000B5L; /* I/O Timeout */
3118 else if (code == CM_ERROR_NOACCESS) {
3119 NTStatus = 0xC0000022L; /* Access denied */
3121 else if (code == CM_ERROR_READONLY) {
3122 NTStatus = 0xC00000A2L; /* Write protected */
3124 else if (code == CM_ERROR_NOSUCHFILE ||
3125 code == CM_ERROR_BPLUS_NOMATCH) {
3126 NTStatus = 0xC0000034L; /* Name not found */
3128 else if (code == CM_ERROR_NOSUCHPATH) {
3129 NTStatus = 0xC000003AL; /* Object path not found */
3131 else if (code == CM_ERROR_TOOBIG) {
3132 NTStatus = 0xC000007BL; /* Invalid image format */
3134 else if (code == CM_ERROR_INVAL) {
3135 NTStatus = 0xC000000DL; /* Invalid parameter */
3137 else if (code == CM_ERROR_BADFD) {
3138 NTStatus = 0xC0000008L; /* Invalid handle */
3140 else if (code == CM_ERROR_BADFDOP) {
3141 NTStatus = 0xC0000022L; /* Access denied */
3143 else if (code == CM_ERROR_UNKNOWN) {
3144 NTStatus = 0xC0000022L; /* Access denied */
3146 else if (code == CM_ERROR_EXISTS) {
3147 NTStatus = 0xC0000035L; /* Object name collision */
3149 else if (code == CM_ERROR_NOTEMPTY) {
3150 NTStatus = 0xC0000101L; /* Directory not empty */
3152 else if (code == CM_ERROR_CROSSDEVLINK) {
3153 NTStatus = 0xC00000D4L; /* Not same device */
3155 else if (code == CM_ERROR_NOTDIR) {
3156 NTStatus = 0xC0000103L; /* Not a directory */
3158 else if (code == CM_ERROR_ISDIR) {
3159 NTStatus = 0xC00000BAL; /* File is a directory */
3161 else if (code == CM_ERROR_BADOP) {
3163 /* I have no idea where this comes from */
3164 NTStatus = 0xC09820FFL; /* SMB no support */
3166 NTStatus = 0xC00000BBL; /* Not supported */
3167 #endif /* COMMENT */
3169 else if (code == CM_ERROR_BADSHARENAME) {
3170 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3172 else if (code == CM_ERROR_NOIPC) {
3174 NTStatus = 0xC0000022L; /* Access Denied */
3176 NTStatus = 0xC000013DL; /* Remote Resources */
3179 else if (code == CM_ERROR_CLOCKSKEW ||
3180 code == RXKADNOAUTH) {
3181 NTStatus = 0xC0000133L; /* Time difference at DC */
3183 else if (code == CM_ERROR_BADTID) {
3184 NTStatus = 0xC0982005L; /* SMB bad TID */
3186 else if (code == CM_ERROR_USESTD) {
3187 NTStatus = 0xC09820FBL; /* SMB use standard */
3189 else if (code == CM_ERROR_QUOTA) {
3190 NTStatus = 0xC0000044L; /* Quota exceeded */
3192 else if (code == CM_ERROR_SPACE) {
3193 NTStatus = 0xC000007FL; /* Disk full */
3195 else if (code == CM_ERROR_ATSYS) {
3196 NTStatus = 0xC0000033L; /* Object name invalid */
3198 else if (code == CM_ERROR_BADNTFILENAME) {
3199 NTStatus = 0xC0000033L; /* Object name invalid */
3201 else if (code == CM_ERROR_WOULDBLOCK) {
3202 NTStatus = 0xC00000D8L; /* Can't wait */
3204 else if (code == CM_ERROR_SHARING_VIOLATION) {
3205 NTStatus = 0xC0000043L; /* Sharing violation */
3207 else if (code == CM_ERROR_LOCK_CONFLICT) {
3208 NTStatus = 0xC0000054L; /* Lock conflict */
3210 else if (code == CM_ERROR_PARTIALWRITE) {
3211 NTStatus = 0xC000007FL; /* Disk full */
3213 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3214 NTStatus = 0xC0000023L; /* Buffer too small */
3216 else if (code == CM_ERROR_BUFFER_OVERFLOW) {
3217 NTStatus = 0x80000005L; /* Buffer overflow */
3219 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3220 NTStatus = 0xC0000035L; /* Object name collision */
3222 else if (code == CM_ERROR_BADPASSWORD) {
3223 NTStatus = 0xC000006DL; /* unknown username or bad password */
3225 else if (code == CM_ERROR_BADLOGONTYPE) {
3226 NTStatus = 0xC000015BL; /* logon type not granted */
3228 else if (code == CM_ERROR_GSSCONTINUE) {
3229 NTStatus = 0xC0000016L; /* more processing required */
3231 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3233 NTStatus = 0xC0000280L; /* reparse point not resolved */
3235 NTStatus = 0xC0000022L; /* Access Denied */
3238 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3239 NTStatus = 0xC0000257L; /* Path Not Covered */
3241 else if (code == CM_ERROR_ALLBUSY) {
3243 NTStatus = 0xC000022DL; /* Retry */
3245 NTStatus = 0xC0020018L; /* RPC_NT_SERVER_TOO_BUSY */
3248 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3250 NTStatus = 0xC000003AL; /* Path not found */
3252 NTStatus = 0xC0020017L; /* RPC_NT_SERVER_UNAVAILABLE */
3255 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3256 NTStatus = 0xC0000322L; /* No Kerberos key */
3258 else if (code == CM_ERROR_BAD_LEVEL) {
3259 NTStatus = 0xC0000148L; /* Invalid Level */
3261 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3262 NTStatus = 0xC000007EL; /* Range Not Locked */
3264 else if (code == CM_ERROR_NOSUCHDEVICE) {
3265 NTStatus = 0xC000000EL; /* No Such Device */
3267 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3268 NTStatus = 0xC0000055L; /* Lock Not Granted */
3270 else if (code == ENOMEM) {
3271 NTStatus = 0xC0000017L; /* Out of Memory */
3273 else if (code == CM_ERROR_RPC_MOREDATA) {
3274 NTStatus = 0x80000005L; /* Buffer overflow */
3277 NTStatus = 0xC0982001L; /* SMB non-specific error */
3280 *NTStatusp = NTStatus;
3281 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3285 * NTSTATUS <-> Win32 Error Translation
3286 * http://support.microsoft.com/kb/113996
3288 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3290 unsigned long Win32E;
3292 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3296 else if (code == CM_ERROR_NOSUCHCELL) {
3297 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3299 else if (code == CM_ERROR_NOSUCHVOLUME) {
3300 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3302 else if (code == CM_ERROR_TIMEDOUT) {
3304 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3306 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3309 else if (code == CM_ERROR_RETRY) {
3310 Win32E = ERROR_RETRY; /* Retry */
3312 else if (code == CM_ERROR_NOACCESS) {
3313 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3315 else if (code == CM_ERROR_READONLY) {
3316 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3318 else if (code == CM_ERROR_NOSUCHFILE ||
3319 code == CM_ERROR_BPLUS_NOMATCH) {
3320 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3322 else if (code == CM_ERROR_NOSUCHPATH) {
3323 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3325 else if (code == CM_ERROR_TOOBIG) {
3326 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3328 else if (code == CM_ERROR_INVAL) {
3329 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3331 else if (code == CM_ERROR_BADFD) {
3332 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3334 else if (code == CM_ERROR_BADFDOP) {
3335 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3337 else if (code == CM_ERROR_UNKNOWN) {
3338 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3340 else if (code == CM_ERROR_EXISTS) {
3341 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3343 else if (code == CM_ERROR_NOTEMPTY) {
3344 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3346 else if (code == CM_ERROR_CROSSDEVLINK) {
3347 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3349 else if (code == CM_ERROR_NOTDIR) {
3350 Win32E = ERROR_DIRECTORY; /* Not a directory */
3352 else if (code == CM_ERROR_ISDIR) {
3353 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3355 else if (code == CM_ERROR_BADOP) {
3356 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3358 else if (code == CM_ERROR_BADSHARENAME) {
3359 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3361 else if (code == CM_ERROR_NOIPC) {
3363 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3365 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3368 else if (code == CM_ERROR_CLOCKSKEW ||
3369 code == RXKADNOAUTH) {
3370 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3372 else if (code == CM_ERROR_BADTID) {
3373 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3375 else if (code == CM_ERROR_USESTD) {
3376 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3378 else if (code == CM_ERROR_QUOTA) {
3379 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3381 else if (code == CM_ERROR_SPACE) {
3382 Win32E = ERROR_DISK_FULL; /* Disk full */
3384 else if (code == CM_ERROR_ATSYS) {
3385 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3387 else if (code == CM_ERROR_BADNTFILENAME) {
3388 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3390 else if (code == CM_ERROR_WOULDBLOCK) {
3391 Win32E = WAIT_TIMEOUT; /* Can't wait */
3393 else if (code == CM_ERROR_SHARING_VIOLATION) {
3394 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3396 else if (code == CM_ERROR_LOCK_CONFLICT) {
3397 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3399 else if (code == CM_ERROR_PARTIALWRITE) {
3400 Win32E = ERROR_DISK_FULL; /* Disk full */
3402 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3403 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3405 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3406 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3408 else if (code == CM_ERROR_BADPASSWORD) {
3409 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3411 else if (code == CM_ERROR_BADLOGONTYPE) {
3412 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3414 else if (code == CM_ERROR_GSSCONTINUE) {
3415 Win32E = ERROR_MORE_DATA; /* more processing required */
3417 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3419 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3421 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3424 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3425 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3427 else if (code == CM_ERROR_ALLBUSY) {
3428 Win32E = ERROR_RETRY; /* Retry */
3430 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3431 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3433 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3434 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3436 else if (code == CM_ERROR_BAD_LEVEL) {
3437 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3439 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3440 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3442 else if (code == CM_ERROR_NOSUCHDEVICE) {
3443 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3445 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3446 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3448 else if (code == ENOMEM) {
3449 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3451 else if (code == CM_ERROR_RPC_MOREDATA) {
3452 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3455 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3459 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3462 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3463 unsigned char *classp)
3465 unsigned char class;
3466 unsigned short error;
3468 /* map CM_ERROR_* errors to SMB errors */
3469 if (code == CM_ERROR_NOSUCHCELL) {
3471 error = 3; /* bad path */
3473 else if (code == CM_ERROR_NOSUCHVOLUME) {
3475 error = 3; /* bad path */
3477 else if (code == CM_ERROR_TIMEDOUT) {
3479 error = 81; /* server is paused */
3481 else if (code == CM_ERROR_RETRY) {
3482 class = 2; /* shouldn't happen */
3485 else if (code == CM_ERROR_NOACCESS) {
3487 error = 4; /* bad access */
3489 else if (code == CM_ERROR_READONLY) {
3491 error = 19; /* read only */
3493 else if (code == CM_ERROR_NOSUCHFILE ||
3494 code == CM_ERROR_BPLUS_NOMATCH) {
3496 error = 2; /* ENOENT! */
3498 else if (code == CM_ERROR_NOSUCHPATH) {
3500 error = 3; /* Bad path */
3502 else if (code == CM_ERROR_TOOBIG) {
3504 error = 11; /* bad format */
3506 else if (code == CM_ERROR_INVAL) {
3507 class = 2; /* server non-specific error code */
3510 else if (code == CM_ERROR_BADFD) {
3512 error = 6; /* invalid file handle */
3514 else if (code == CM_ERROR_BADFDOP) {
3515 class = 1; /* invalid op on FD */
3518 else if (code == CM_ERROR_EXISTS) {
3520 error = 80; /* file already exists */
3522 else if (code == CM_ERROR_NOTEMPTY) {
3524 error = 5; /* delete directory not empty */
3526 else if (code == CM_ERROR_CROSSDEVLINK) {
3528 error = 17; /* EXDEV */
3530 else if (code == CM_ERROR_NOTDIR) {
3531 class = 1; /* bad path */
3534 else if (code == CM_ERROR_ISDIR) {
3535 class = 1; /* access denied; DOS doesn't have a good match */
3538 else if (code == CM_ERROR_BADOP) {
3542 else if (code == CM_ERROR_BADSHARENAME) {
3546 else if (code == CM_ERROR_NOIPC) {
3548 error = 4; /* bad access */
3550 else if (code == CM_ERROR_CLOCKSKEW) {
3551 class = 1; /* invalid function */
3554 else if (code == CM_ERROR_BADTID) {
3558 else if (code == CM_ERROR_USESTD) {
3562 else if (code == CM_ERROR_REMOTECONN) {
3566 else if (code == CM_ERROR_QUOTA) {
3567 if (vcp->flags & SMB_VCFLAG_USEV3) {
3569 error = 39; /* disk full */
3573 error = 5; /* access denied */
3576 else if (code == CM_ERROR_SPACE) {
3577 if (vcp->flags & SMB_VCFLAG_USEV3) {
3579 error = 39; /* disk full */
3583 error = 5; /* access denied */
3586 else if (code == CM_ERROR_PARTIALWRITE) {
3588 error = 39; /* disk full */
3590 else if (code == CM_ERROR_ATSYS) {
3592 error = 2; /* ENOENT */
3594 else if (code == CM_ERROR_WOULDBLOCK) {
3596 error = 33; /* lock conflict */
3598 else if (code == CM_ERROR_LOCK_CONFLICT) {
3600 error = 33; /* lock conflict */
3602 else if (code == CM_ERROR_SHARING_VIOLATION) {
3604 error = 33; /* lock conflict */
3606 else if (code == CM_ERROR_NOFILES) {
3608 error = 18; /* no files in search */
3610 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3612 error = 183; /* Samba uses this */
3614 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3615 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3617 error = 2; /* bad password */
3619 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3621 error = 3; /* bad path */
3630 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3633 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3635 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3636 return CM_ERROR_BADOP;
3640 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3642 unsigned short EchoCount, i;
3643 char *data, *outdata;
3646 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3648 for (i=1; i<=EchoCount; i++) {
3649 data = smb_GetSMBData(inp, &dataSize);
3650 smb_SetSMBParm(outp, 0, i);
3651 smb_SetSMBDataLength(outp, dataSize);
3652 outdata = smb_GetSMBData(outp, NULL);
3653 memcpy(outdata, data, dataSize);
3654 smb_SendPacket(vcp, outp);
3660 /* SMB_COM_READ_RAW */
3661 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3664 long count, minCount, finalCount;
3668 smb_t *smbp = (smb_t*) inp;
3670 cm_user_t *userp = NULL;
3673 char *rawBuf = NULL;
3678 fd = smb_GetSMBParm(inp, 0);
3679 count = smb_GetSMBParm(inp, 3);
3680 minCount = smb_GetSMBParm(inp, 4);
3681 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3683 if (*inp->wctp == 10) {
3684 /* we were sent a request with 64-bit file offsets */
3685 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3687 if (LargeIntegerLessThanZero(offset)) {
3688 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3692 /* we were sent a request with 32-bit file offsets */
3693 offset.HighPart = 0;
3696 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3697 fd, offset.HighPart, offset.LowPart, count);
3699 fidp = smb_FindFID(vcp, fd, 0);
3701 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3705 lock_ObtainMutex(&fidp->mx);
3707 lock_ReleaseMutex(&fidp->mx);
3708 smb_ReleaseFID(fidp);
3709 return CM_ERROR_BADFD;
3712 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3713 lock_ReleaseMutex(&fidp->mx);
3714 smb_CloseFID(vcp, fidp, NULL, 0);
3715 code = CM_ERROR_NOSUCHFILE;
3721 LARGE_INTEGER LOffset, LLength;
3724 key = cm_GenerateKey(vcp->vcID, pid, fd);
3726 LOffset.HighPart = offset.HighPart;
3727 LOffset.LowPart = offset.LowPart;
3728 LLength.HighPart = 0;
3729 LLength.LowPart = count;
3731 lock_ObtainWrite(&fidp->scp->rw);
3732 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3733 lock_ReleaseWrite(&fidp->scp->rw);
3736 lock_ReleaseMutex(&fidp->mx);
3740 lock_ObtainMutex(&smb_RawBufLock);
3742 /* Get a raw buf, from head of list */
3743 rawBuf = smb_RawBufs;
3744 smb_RawBufs = *(char **)smb_RawBufs;
3746 lock_ReleaseMutex(&smb_RawBufLock);
3748 lock_ReleaseMutex(&fidp->mx);
3752 if (fidp->flags & SMB_FID_IOCTL)
3754 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3756 /* Give back raw buffer */
3757 lock_ObtainMutex(&smb_RawBufLock);
3758 *((char **) rawBuf) = smb_RawBufs;
3760 smb_RawBufs = rawBuf;
3761 lock_ReleaseMutex(&smb_RawBufLock);
3764 lock_ReleaseMutex(&fidp->mx);
3765 smb_ReleaseFID(fidp);
3768 lock_ReleaseMutex(&fidp->mx);
3770 userp = smb_GetUserFromVCP(vcp, inp);
3772 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3778 cm_ReleaseUser(userp);
3781 smb_ReleaseFID(fidp);
3785 memset(ncbp, 0, sizeof(NCB));
3787 ncbp->ncb_length = (unsigned short) finalCount;
3788 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3789 ncbp->ncb_lana_num = vcp->lana;
3790 ncbp->ncb_command = NCBSEND;
3791 ncbp->ncb_buffer = rawBuf;
3793 code = Netbios(ncbp);
3795 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3798 /* Give back raw buffer */
3799 lock_ObtainMutex(&smb_RawBufLock);
3800 *((char **) rawBuf) = smb_RawBufs;
3802 smb_RawBufs = rawBuf;
3803 lock_ReleaseMutex(&smb_RawBufLock);
3809 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3811 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3816 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3818 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3823 /* SMB_COM_NEGOTIATE */
3824 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3831 int VistaProtoIndex;
3832 int protoIndex; /* index we're using */
3837 char protocol_array[10][1024]; /* protocol signature of the client */
3838 int caps; /* capabilities */
3841 TIME_ZONE_INFORMATION tzi;
3843 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3846 namep = smb_GetSMBData(inp, &dbytes);
3849 coreProtoIndex = -1; /* not found */
3852 VistaProtoIndex = -1;
3853 while(namex < dbytes) {
3854 osi_Log1(smb_logp, "Protocol %s",
3855 osi_LogSaveString(smb_logp, namep+1));
3856 strcpy(protocol_array[tcounter], namep+1);
3858 /* namep points at the first protocol, or really, a 0x02
3859 * byte preceding the null-terminated ASCII name.
3861 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3862 coreProtoIndex = tcounter;
3864 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3865 v3ProtoIndex = tcounter;
3867 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3868 NTProtoIndex = tcounter;
3870 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3871 VistaProtoIndex = tcounter;
3874 /* compute size of protocol entry */
3875 entryLength = (int)strlen(namep+1);
3876 entryLength += 2; /* 0x02 bytes and null termination */
3878 /* advance over this protocol entry */
3879 namex += entryLength;
3880 namep += entryLength;
3881 tcounter++; /* which proto entry we're looking at */
3884 lock_ObtainMutex(&vcp->mx);
3886 if (VistaProtoIndex != -1) {
3887 protoIndex = VistaProtoIndex;
3888 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3891 if (NTProtoIndex != -1) {
3892 protoIndex = NTProtoIndex;
3893 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3895 else if (v3ProtoIndex != -1) {
3896 protoIndex = v3ProtoIndex;
3897 vcp->flags |= SMB_VCFLAG_USEV3;
3899 else if (coreProtoIndex != -1) {
3900 protoIndex = coreProtoIndex;
3901 vcp->flags |= SMB_VCFLAG_USECORE;
3903 else protoIndex = -1;
3904 lock_ReleaseMutex(&vcp->mx);
3906 if (protoIndex == -1)
3907 return CM_ERROR_INVAL;
3908 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3909 smb_SetSMBParm(outp, 0, protoIndex);
3910 if (smb_authType != SMB_AUTH_NONE) {
3911 smb_SetSMBParmByte(outp, 1,
3912 NEGOTIATE_SECURITY_USER_LEVEL |
3913 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3915 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3917 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3918 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3919 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3920 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3921 /* The session key is not a well documented field however most clients
3922 * will echo back the session key to the server. Currently we are using
3923 * the same value for all sessions. We should generate a random value
3924 * and store it into the vcp
3926 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3927 smb_SetSMBParm(outp, 8, 1);
3929 * Tried changing the capabilities to support for W2K - defect 117695
3930 * Maybe something else needs to be changed here?
3934 smb_SetSMBParmLong(outp, 9, 0x43fd);
3936 smb_SetSMBParmLong(outp, 9, 0x251);
3939 * 32-bit error codes *
3945 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3947 NTNEGOTIATE_CAPABILITY_DFS |
3949 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3950 NTNEGOTIATE_CAPABILITY_NTFIND |
3951 NTNEGOTIATE_CAPABILITY_RAWMODE |
3952 NTNEGOTIATE_CAPABILITY_NTSMB;
3954 if ( smb_authType == SMB_AUTH_EXTENDED )
3955 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3958 if ( smb_UseUnicode ) {
3959 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3963 smb_SetSMBParmLong(outp, 9, caps);
3965 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3966 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3967 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3969 GetTimeZoneInformation(&tzi);
3970 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3972 if (smb_authType == SMB_AUTH_NTLM) {
3973 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3974 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3975 /* paste in encryption key */
3976 datap = smb_GetSMBData(outp, NULL);
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)));
3982 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3986 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3988 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3990 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3992 datap = smb_GetSMBData(outp, NULL);
3993 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3996 datap += sizeof(smb_ServerGUID);
3997 memcpy(datap, secBlob, secBlobLength);
4001 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
4002 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
4005 else if (v3ProtoIndex != -1) {
4006 smb_SetSMBParm(outp, 0, protoIndex);
4008 /* NOTE: Extended authentication cannot be negotiated with v3
4009 * therefore we fail over to NTLM
4011 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4012 smb_SetSMBParm(outp, 1,
4013 NEGOTIATE_SECURITY_USER_LEVEL |
4014 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
4016 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4018 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4019 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
4020 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
4021 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
4022 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
4023 smb_SetSMBParm(outp, 7, 1);
4025 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
4026 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
4027 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
4029 GetTimeZoneInformation(&tzi);
4030 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
4032 /* NOTE: Extended authentication cannot be negotiated with v3
4033 * therefore we fail over to NTLM
4035 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4036 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
4037 smb_SetSMBParm(outp, 12, 0); /* resvd */
4038 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
4039 datap = smb_GetSMBData(outp, NULL);
4040 /* paste in a new encryption key */
4041 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4042 /* and the faux domain name */
4043 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4044 datap + MSV1_0_CHALLENGE_LENGTH,
4045 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4047 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4048 smb_SetSMBParm(outp, 12, 0); /* resvd */
4049 smb_SetSMBDataLength(outp, 0);
4052 else if (coreProtoIndex != -1) { /* not really supported anymore */
4053 smb_SetSMBParm(outp, 0, protoIndex);
4054 smb_SetSMBDataLength(outp, 0);
4059 void smb_CheckVCs(void)
4061 smb_vc_t * vcp, *nextp;
4062 smb_packet_t * outp = smb_GetPacket();
4065 lock_ObtainWrite(&smb_rctLock);
4066 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4068 if (vcp->magic != SMB_VC_MAGIC)
4069 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4070 __FILE__, __LINE__);
4072 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4074 smb_HoldVCNoLock(vcp);
4077 * obtain a reference to 'nextp' now because we drop the
4078 * smb_rctLock later and the list contents could change
4079 * or 'vcp' could be destroyed when released.
4083 smb_HoldVCNoLock(nextp);
4085 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4086 smb_ReleaseVCNoLock(vcp);
4090 smb_FormatResponsePacket(vcp, NULL, outp);
4091 smbp = (smb_t *)outp;
4092 outp->inCom = smbp->com = 0x2b /* Echo */;
4100 smb_SetSMBParm(outp, 0, 0);
4101 smb_SetSMBDataLength(outp, 0);
4102 lock_ReleaseWrite(&smb_rctLock);
4104 smb_SendPacket(vcp, outp);
4106 lock_ObtainWrite(&smb_rctLock);
4107 smb_ReleaseVCNoLock(vcp);
4109 lock_ReleaseWrite(&smb_rctLock);
4110 smb_FreePacket(outp);
4113 void smb_Daemon(void *parmp)
4115 afs_uint32 count = 0;
4116 smb_username_t **unpp;
4119 while(smbShutdownFlag == 0) {
4123 if (smbShutdownFlag == 1)
4126 if ((count % 72) == 0) { /* every five minutes */
4128 time_t old_localZero = smb_localZero;
4130 /* Initialize smb_localZero */
4131 myTime.tm_isdst = -1; /* compute whether on DST or not */
4132 myTime.tm_year = 70;
4138 smb_localZero = mktime(&myTime);
4140 #ifdef AFS_FREELANCE
4141 if ( smb_localZero != old_localZero )
4142 cm_noteLocalMountPointChange(FALSE);
4148 /* GC smb_username_t objects that will no longer be used */
4150 lock_ObtainWrite(&smb_rctLock);
4151 for ( unpp=&usernamesp; *unpp; ) {
4153 smb_username_t *unp;
4155 lock_ObtainMutex(&(*unpp)->mx);
4156 if ( (*unpp)->refCount > 0 ||
4157 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4158 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4160 else if (!smb_LogoffTokenTransfer ||
4161 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4163 lock_ReleaseMutex(&(*unpp)->mx);
4171 lock_FinalizeMutex(&unp->mx);
4177 cm_ReleaseUser(userp);
4179 unpp = &(*unpp)->nextp;
4182 lock_ReleaseWrite(&smb_rctLock);
4184 /* XXX GC dir search entries */
4188 void smb_WaitingLocksDaemon()
4190 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4191 smb_waitingLock_t *wl, *wlNext;
4194 smb_packet_t *inp, *outp;
4198 while (smbShutdownFlag == 0) {
4199 lock_ObtainWrite(&smb_globalLock);
4200 nwlRequest = smb_allWaitingLocks;
4201 if (nwlRequest == NULL) {
4202 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4207 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4214 lock_ObtainWrite(&smb_globalLock);
4216 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4218 wlRequest = nwlRequest;
4219 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4220 lock_ReleaseWrite(&smb_globalLock);
4224 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4225 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4228 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4229 code = CM_ERROR_LOCK_NOT_GRANTED;
4233 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4235 /* wl->state is either _DONE or _WAITING. _ERROR
4236 would no longer be on the queue. */
4237 code = cm_RetryLock( wl->lockp,
4238 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4241 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4242 } else if (code != CM_ERROR_WOULDBLOCK) {
4243 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4248 if (code == CM_ERROR_WOULDBLOCK) {
4251 if (wlRequest->msTimeout != 0xffffffff
4252 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4264 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4267 scp = wlRequest->scp;
4268 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4272 lock_ObtainWrite(&scp->rw);
4274 for (wl = wlRequest->locks; wl; wl = wlNext) {
4275 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4277 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4278 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4279 wl->LLength, wl->key, 0, NULL, &req);
4281 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4286 lock_ReleaseWrite(&scp->rw);
4290 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4293 for (wl = wlRequest->locks; wl; wl = wlNext) {
4294 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4295 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4300 vcp = wlRequest->vcp;
4301 inp = wlRequest->inp;
4302 outp = wlRequest->outp;
4303 ncbp = smb_GetNCB();
4304 ncbp->ncb_length = inp->ncb_length;
4305 inp->spacep = cm_GetSpace();
4307 /* Remove waitingLock from list */
4308 lock_ObtainWrite(&smb_globalLock);
4309 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4311 lock_ReleaseWrite(&smb_globalLock);
4313 /* Resume packet processing */
4315 smb_SetSMBDataLength(outp, 0);
4316 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4317 outp->resumeCode = code;
4319 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4322 cm_FreeSpace(inp->spacep);
4323 smb_FreePacket(inp);
4324 smb_FreePacket(outp);
4326 cm_ReleaseSCache(wlRequest->scp);
4329 } while (nwlRequest && smbShutdownFlag == 0);
4334 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4336 osi_Log0(smb_logp, "SMB receive get disk attributes");
4338 smb_SetSMBParm(outp, 0, 32000);
4339 smb_SetSMBParm(outp, 1, 64);
4340 smb_SetSMBParm(outp, 2, 1024);
4341 smb_SetSMBParm(outp, 3, 30000);
4342 smb_SetSMBParm(outp, 4, 0);
4343 smb_SetSMBDataLength(outp, 0);
4347 /* SMB_COM_TREE_CONNECT */
4348 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4352 unsigned short newTid;
4353 clientchar_t shareName[AFSPATHMAX];
4354 clientchar_t *sharePath;
4357 clientchar_t *pathp;
4360 osi_Log0(smb_logp, "SMB receive tree connect");
4362 /* parse input parameters */
4365 tbp = smb_GetSMBData(inp, NULL);
4366 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4368 return CM_ERROR_BADSMB;
4370 tp = cm_ClientStrRChr(pathp, '\\');
4372 return CM_ERROR_BADSMB;
4373 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4375 lock_ObtainMutex(&vcp->mx);
4376 newTid = vcp->tidCounter++;
4377 lock_ReleaseMutex(&vcp->mx);
4379 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4380 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4382 return CM_ERROR_BADSMB;
4383 userp = smb_GetUserFromUID(uidp);
4384 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4385 smb_ReleaseUID(uidp);
4387 smb_ReleaseTID(tidp, FALSE);
4388 return CM_ERROR_BADSHARENAME;
4390 lock_ObtainMutex(&tidp->mx);
4391 tidp->userp = userp;
4392 tidp->pathname = sharePath;
4393 lock_ReleaseMutex(&tidp->mx);
4394 smb_ReleaseTID(tidp, FALSE);
4396 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4397 smb_SetSMBParm(rsp, 1, newTid);
4398 smb_SetSMBDataLength(rsp, 0);
4400 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4404 /* set maskp to the mask part of the incoming path.
4405 * Mask is 11 bytes long (8.3 with the dot elided).
4406 * Returns true if succeeds with a valid name, otherwise it does
4407 * its best, but returns false.
4409 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4417 /* starts off valid */
4420 /* mask starts out all blanks */
4421 memset(maskp, ' ', 11);
4424 /* find last backslash, or use whole thing if there is none */
4425 tp = cm_ClientStrRChr(pathp, '\\');
4429 tp++; /* skip slash */
4433 /* names starting with a dot are illegal */
4441 if (tc == '.' || tc == '"')
4449 /* if we get here, tp point after the dot */
4450 up = maskp+8; /* ext goes here */
4457 if (tc == '.' || tc == '"')
4460 /* copy extension if not too long */
4470 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4472 clientchar_t umask[11];
4480 /* XXX redo this, calling cm_MatchMask with a converted mask */
4482 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4486 /* otherwise, we have a valid 8.3 name; see if we have a match,
4487 * treating '?' as a wildcard in maskp (but not in the file name).
4489 tp1 = umask; /* real name, in mask format */
4490 tp2 = maskp; /* mask, in mask format */
4491 for(i=0; i<11; i++) {
4492 tc1 = *tp1++; /* clientchar_t from real name */
4493 tc2 = *tp2++; /* clientchar_t from mask */
4494 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4495 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4498 if (tc2 == '?' && tc1 != ' ')
4505 /* we got a match */
4509 clientchar_t *smb_FindMask(clientchar_t *pathp)
4513 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4516 return tp+1; /* skip the slash */
4518 return pathp; /* no slash, return the entire path */
4521 /* SMB_COM_SEARCH for a volume label
4523 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4524 dispatch function.) */
4525 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4527 clientchar_t *pathp;
4529 clientchar_t mask[12];
4530 unsigned char *statBlockp;
4531 unsigned char initStatBlock[21];
4534 osi_Log0(smb_logp, "SMB receive search volume");
4536 /* pull pathname and stat block out of request */
4537 tp = smb_GetSMBData(inp, NULL);
4538 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4539 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4541 return CM_ERROR_BADSMB;
4542 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4543 osi_assertx(statBlockp != NULL, "null statBlock");
4545 statBlockp = initStatBlock;
4549 /* for returning to caller */
4550 smb_Get8Dot3MaskFromPath(mask, pathp);
4552 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4553 tp = smb_GetSMBData(outp, NULL);
4555 *tp++ = 43; /* bytes in a dir entry */
4556 *tp++ = 0; /* high byte in counter */
4558 /* now marshall the dir entry, starting with the search status */
4559 *tp++ = statBlockp[0]; /* Reserved */
4560 memcpy(tp, mask, 11); tp += 11; /* FileName */
4562 /* now pass back server use info, with 1st byte non-zero */
4564 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4566 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4568 *tp++ = 0x8; /* attribute: volume */
4578 /* 4 byte file size */
4584 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4587 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4588 memset(tp, ' ', 13);
4591 /* set the length of the data part of the packet to 43 + 3, for the dir
4592 * entry plus the 5 and the length fields.
4594 smb_SetSMBDataLength(outp, 46);
4599 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4600 clientchar_t * tidPathp, clientchar_t * relPathp,
4601 cm_user_t *userp, cm_req_t *reqp)
4609 smb_dirListPatch_t *patchp;
4610 smb_dirListPatch_t *npatchp;
4611 clientchar_t path[AFSPATHMAX];
4613 afs_int32 mustFake = 0;
4615 code = cm_FindACLCache(dscp, userp, &rights);
4617 lock_ObtainWrite(&dscp->rw);
4618 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4619 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4620 lock_ReleaseWrite(&dscp->rw);
4621 if (code == CM_ERROR_NOACCESS) {
4629 if (!mustFake) { /* Bulk Stat */
4631 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4633 memset(bsp, 0, sizeof(cm_bulkStat_t));
4635 for (patchp = *dirPatchespp, count=0;
4637 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4638 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4642 if (lock_TryWrite(&tscp->rw)) {
4643 /* we have an entry that we can look at */
4644 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4645 /* we have a callback on it. Don't bother
4646 * fetching this stat entry, since we're happy
4647 * with the info we have.
4649 lock_ReleaseWrite(&tscp->rw);
4650 cm_ReleaseSCache(tscp);
4653 lock_ReleaseWrite(&tscp->rw);
4655 cm_ReleaseSCache(tscp);
4659 bsp->fids[i].Volume = patchp->fid.volume;
4660 bsp->fids[i].Vnode = patchp->fid.vnode;
4661 bsp->fids[i].Unique = patchp->fid.unique;
4663 if (bsp->counter == AFSCBMAX) {
4664 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4665 memset(bsp, 0, sizeof(cm_bulkStat_t));
4669 if (bsp->counter > 0)
4670 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4675 for (patchp = *dirPatchespp; patchp; patchp =
4676 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4678 dptr = patchp->dptr;
4680 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4681 relPathp ? relPathp : _C(""), patchp->dep->name);
4682 reqp->relPathp = path;
4683 reqp->tidPathp = tidPathp;
4685 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4686 reqp->relPathp = reqp->tidPathp = NULL;
4689 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4690 *dptr++ = SMB_ATTR_HIDDEN;
4693 lock_ObtainWrite(&scp->rw);
4694 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4695 lock_ReleaseWrite(&scp->rw);
4697 /* set the attribute */
4698 switch (scp->fileType) {
4699 case CM_SCACHETYPE_DIRECTORY:
4700 case CM_SCACHETYPE_MOUNTPOINT:
4701 case CM_SCACHETYPE_INVALID:
4702 attr = SMB_ATTR_DIRECTORY;
4704 case CM_SCACHETYPE_SYMLINK:
4705 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4706 attr = SMB_ATTR_DIRECTORY;
4708 attr = SMB_ATTR_NORMAL;
4711 /* if we get here we either have a normal file
4712 * or we have a file for which we have never
4713 * received status info. In this case, we can
4714 * check the even/odd value of the entry's vnode.
4715 * odd means it is to be treated as a directory
4716 * and even means it is to be treated as a file.
4718 if (mustFake && (scp->fid.vnode & 0x1))
4719 attr = SMB_ATTR_DIRECTORY;
4721 attr = SMB_ATTR_NORMAL;
4725 /* 1969-12-31 23:59:58 +00*/
4726 dosTime = 0xEBBFBF7D;
4729 shortTemp = (unsigned short) (dosTime & 0xffff);
4730 *((u_short *)dptr) = shortTemp;
4733 /* and copy out date */
4734 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4735 *((u_short *)dptr) = shortTemp;
4738 /* copy out file length */
4739 *((u_long *)dptr) = 0;
4742 lock_ConvertWToR(&scp->rw);
4743 attr = smb_Attributes(scp);
4744 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4745 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4746 attr |= SMB_ATTR_HIDDEN;
4750 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4753 shortTemp = (unsigned short) (dosTime & 0xffff);
4754 *((u_short *)dptr) = shortTemp;
4757 /* and copy out date */
4758 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4759 *((u_short *)dptr) = shortTemp;
4762 /* copy out file length */
4763 *((u_long *)dptr) = scp->length.LowPart;
4765 lock_ReleaseRead(&scp->rw);
4767 cm_ReleaseSCache(scp);
4770 /* now free the patches */
4771 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4772 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4776 /* and mark the list as empty */
4777 *dirPatchespp = NULL;
4783 /* SMB_COM_SEARCH */
4784 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4790 clientchar_t *pathp;
4791 cm_dirEntry_t *dep = 0;
4793 smb_dirListPatch_t *dirListPatchesp;
4794 smb_dirListPatch_t *curPatchp;
4798 osi_hyper_t dirLength;
4799 osi_hyper_t bufferOffset;
4800 osi_hyper_t curOffset;
4802 unsigned char *inCookiep;
4803 smb_dirSearch_t *dsp;
4807 unsigned long clientCookie;
4808 cm_pageHeader_t *pageHeaderp;
4809 cm_user_t *userp = NULL;
4811 clientchar_t mask[12];
4813 long nextEntryCookie;
4814 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4815 char resByte; /* reserved byte from the cookie */
4816 char *op; /* output data ptr */
4817 char *origOp; /* original value of op */
4818 cm_space_t *spacep; /* for pathname buffer */
4822 clientchar_t *tidPathp = 0;
4829 maxCount = smb_GetSMBParm(inp, 0);
4831 dirListPatchesp = NULL;
4833 caseFold = CM_FLAG_CASEFOLD;
4835 tp = smb_GetSMBData(inp, NULL);
4836 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4837 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4839 return CM_ERROR_BADSMB;
4841 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4843 return CM_ERROR_BADSMB;
4845 /* We can handle long names */
4846 if (vcp->flags & SMB_VCFLAG_USENT)
4847 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4849 /* make sure we got a whole search status */
4850 if (dataLength < 21) {
4851 nextCookie = 0; /* start at the beginning of the dir */
4854 attribute = smb_GetSMBParm(inp, 1);
4856 /* handle volume info in another function */
4857 if (attribute & 0x8)
4858 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4860 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4861 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4863 if (*pathp == 0) { /* null pathp, treat as root dir */
4864 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4865 return CM_ERROR_NOFILES;
4869 dsp = smb_NewDirSearch(0);
4870 dsp->attribute = attribute;
4871 smb_Get8Dot3MaskFromPath(mask, pathp);
4872 memcpy(dsp->mask, mask, 12);
4874 /* track if this is likely to match a lot of entries */
4875 if (smb_Is8Dot3StarMask(mask))
4880 /* pull the next cookie value out of the search status block */
4881 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4882 + (inCookiep[16]<<24);
4883 dsp = smb_FindDirSearch(inCookiep[12]);
4885 /* can't find dir search status; fatal error */
4886 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4887 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4888 return CM_ERROR_BADFD;
4890 attribute = dsp->attribute;
4891 resByte = inCookiep[0];
4893 /* copy out client cookie, in host byte order. Don't bother
4894 * interpreting it, since we're just passing it through, anyway.
4896 memcpy(&clientCookie, &inCookiep[17], 4);
4898 memcpy(mask, dsp->mask, 12);
4900 /* assume we're doing a star match if it has continued for more
4906 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4907 nextCookie, dsp->cookie, attribute);
4909 userp = smb_GetUserFromVCP(vcp, inp);
4911 /* try to get the vnode for the path name next */
4912 lock_ObtainMutex(&dsp->mx);
4915 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4919 spacep = inp->spacep;
4920 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4921 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4923 lock_ReleaseMutex(&dsp->mx);
4924 cm_ReleaseUser(userp);
4925 smb_DeleteDirSearch(dsp);
4926 smb_ReleaseDirSearch(dsp);
4927 return CM_ERROR_NOFILES;
4929 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4930 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4932 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
4933 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4936 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4939 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4940 cm_ReleaseSCache(scp);
4941 lock_ReleaseMutex(&dsp->mx);
4942 cm_ReleaseUser(userp);
4943 smb_DeleteDirSearch(dsp);
4944 smb_ReleaseDirSearch(dsp);
4945 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4946 return CM_ERROR_PATH_NOT_COVERED;
4948 return CM_ERROR_NOSUCHPATH;
4950 #endif /* DFS_SUPPORT */
4953 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4954 /* we need one hold for the entry we just stored into,
4955 * and one for our own processing. When we're done with this
4956 * function, we'll drop the one for our own processing.
4957 * We held it once from the namei call, and so we do another hold
4961 lock_ObtainWrite(&scp->rw);
4962 dsp->flags |= SMB_DIRSEARCH_BULKST;
4963 lock_ReleaseWrite(&scp->rw);
4966 lock_ReleaseMutex(&dsp->mx);
4968 cm_ReleaseUser(userp);
4969 smb_DeleteDirSearch(dsp);
4970 smb_ReleaseDirSearch(dsp);
4974 /* reserves space for parameter; we'll adjust it again later to the
4975 * real count of the # of entries we returned once we've actually
4976 * assembled the directory listing.
4978 smb_SetSMBParm(outp, 0, 0);
4980 /* get the directory size */
4981 lock_ObtainWrite(&scp->rw);
4982 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4983 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4985 lock_ReleaseWrite(&scp->rw);
4986 cm_ReleaseSCache(scp);
4987 cm_ReleaseUser(userp);
4988 smb_DeleteDirSearch(dsp);
4989 smb_ReleaseDirSearch(dsp);
4993 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4995 dirLength = scp->length;
4997 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4998 curOffset.HighPart = 0;
4999 curOffset.LowPart = nextCookie;
5000 origOp = op = smb_GetSMBData(outp, NULL);
5001 /* and write out the basic header */
5002 *op++ = 5; /* variable block */
5003 op += 2; /* skip vbl block length; we'll fill it in later */
5007 clientchar_t *actualName = NULL;
5008 int free_actualName = 0;
5009 clientchar_t shortName[13];
5010 clientchar_t *shortNameEnd;
5012 /* make sure that curOffset.LowPart doesn't point to the first
5013 * 32 bytes in the 2nd through last dir page, and that it doesn't
5014 * point at the first 13 32-byte chunks in the first dir page,
5015 * since those are dir and page headers, and don't contain useful
5018 temp = curOffset.LowPart & (2048-1);
5019 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5020 /* we're in the first page */
5021 if (temp < 13*32) temp = 13*32;
5024 /* we're in a later dir page */
5025 if (temp < 32) temp = 32;
5028 /* make sure the low order 5 bits are zero */
5031 /* now put temp bits back ito curOffset.LowPart */
5032 curOffset.LowPart &= ~(2048-1);
5033 curOffset.LowPart |= temp;
5035 /* check if we've returned all the names that will fit in the
5038 if (returnedNames >= maxCount) {
5039 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5040 returnedNames, maxCount);
5044 /* check if we've passed the dir's EOF */
5045 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5047 /* see if we can use the bufferp we have now; compute in which page
5048 * the current offset would be, and check whether that's the offset
5049 * of the buffer we have. If not, get the buffer.
5051 thyper.HighPart = curOffset.HighPart;
5052 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5053 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5056 buf_Release(bufferp);
5059 lock_ReleaseWrite(&scp->rw);
5060 code = buf_Get(scp, &thyper, &req, &bufferp);
5061 lock_ObtainMutex(&dsp->mx);
5063 /* now, if we're doing a star match, do bulk fetching of all of
5064 * the status info for files in the dir.
5067 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5069 lock_ObtainWrite(&scp->rw);
5070 lock_ReleaseMutex(&dsp->mx);
5072 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5076 bufferOffset = thyper;
5078 /* now get the data in the cache */
5080 code = cm_SyncOp(scp, bufferp, userp, &req,
5082 CM_SCACHESYNC_NEEDCALLBACK |
5083 CM_SCACHESYNC_READ);
5085 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5089 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5091 if (cm_HaveBuffer(scp, bufferp, 0)) {
5092 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5096 /* otherwise, load the buffer and try again */
5097 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5099 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5100 scp, bufferp, code);
5105 buf_Release(bufferp);
5109 } /* if (wrong buffer) ... */
5111 /* now we have the buffer containing the entry we're interested in; copy
5112 * it out if it represents a non-deleted entry.
5114 entryInDir = curOffset.LowPart & (2048-1);
5115 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5117 /* page header will help tell us which entries are free. Page header
5118 * can change more often than once per buffer, since AFS 3 dir page size
5119 * may be less than (but not more than a buffer package buffer.
5121 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5122 temp &= ~(2048 - 1); /* turn off intra-page bits */
5123 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5125 /* now determine which entry we're looking at in the page. If it is
5126 * free (there's a free bitmap at the start of the dir), we should
5127 * skip these 32 bytes.
5129 slotInPage = (entryInDir & 0x7e0) >> 5;
5130 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5131 /* this entry is free */
5132 numDirChunks = 1; /* only skip this guy */
5136 tp = bufferp->datap + entryInBuffer;
5137 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5139 /* while we're here, compute the next entry's location, too,
5140 * since we'll need it when writing out the cookie into the dir
5143 * XXXX Probably should do more sanity checking.
5145 numDirChunks = cm_NameEntries(dep->name, NULL);
5147 /* compute the offset of the cookie representing the next entry */
5148 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5150 /* Compute 8.3 name if necessary */
5151 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5152 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5155 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5156 actualName = shortName;
5157 free_actualName = 0;
5159 free_actualName = 1;
5162 if (actualName == NULL) {
5163 /* Couldn't convert the name for some reason */
5164 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5165 osi_LogSaveString(smb_logp, dep->name));
5169 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5170 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5171 osi_LogSaveClientString(smb_logp, actualName));
5173 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5174 /* this is one of the entries to use: it is not deleted
5175 * and it matches the star pattern we're looking for.
5178 /* Eliminate entries that don't match requested
5181 /* no hidden files */
5182 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5183 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5187 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5189 /* We have already done the cm_TryBulkStat above */
5190 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5191 fileType = cm_FindFileType(&fid);
5192 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5193 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5195 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5196 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5197 fileType == CM_SCACHETYPE_DFSLINK ||
5198 fileType == CM_SCACHETYPE_INVALID)
5199 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5204 memcpy(op, mask, 11); op += 11;
5205 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5206 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5207 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5208 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5209 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5210 memcpy(op, &clientCookie, 4); op += 4;
5212 /* now we emit the attribute. This is sort of tricky,
5213 * since we need to really stat the file to find out
5214 * what type of entry we've got. Right now, we're
5215 * copying out data from a buffer, while holding the
5216 * scp locked, so it isn't really convenient to stat
5217 * something now. We'll put in a place holder now,
5218 * and make a second pass before returning this to get
5219 * the real attributes. So, we just skip the data for
5220 * now, and adjust it later. We allocate a patch
5221 * record to make it easy to find this point later.
5222 * The replay will happen at a time when it is safe to
5223 * unlock the directory.
5225 curPatchp = malloc(sizeof(*curPatchp));
5226 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5227 curPatchp->dptr = op;
5228 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5230 /* do hidden attribute here since name won't be around when applying
5234 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5235 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5237 curPatchp->flags = 0;
5239 op += 9; /* skip attr, time, date and size */
5241 /* zero out name area. The spec says to pad with
5242 * spaces, but Samba doesn't, and neither do we.
5246 /* finally, we get to copy out the name; we know that
5247 * it fits in 8.3 or the pattern wouldn't match, but it
5248 * never hurts to be sure.
5250 cm_ClientStringToUtf8(actualName, -1, op, 13);
5251 if (smb_StoreAnsiFilenames)
5253 /* This is a UCHAR field, which is ASCII even if Unicode
5256 /* Uppercase if requested by client */
5257 if (!KNOWS_LONG_NAMES(inp))
5262 /* now, adjust the # of entries copied */
5264 } /* if we're including this name */
5267 if (free_actualName && actualName) {
5272 /* and adjust curOffset to be where the new cookie is */
5273 thyper.HighPart = 0;
5274 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5275 curOffset = LargeIntegerAdd(thyper, curOffset);
5276 } /* while copying data for dir listing */
5278 /* release the mutex */
5279 lock_ReleaseWrite(&scp->rw);
5281 buf_Release(bufferp);
5285 /* apply and free last set of patches; if not doing a star match, this
5286 * will be empty, but better safe (and freeing everything) than sorry.
5288 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5290 /* special return code for unsuccessful search */
5291 if (code == 0 && dataLength < 21 && returnedNames == 0)
5292 code = CM_ERROR_NOFILES;
5294 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5295 returnedNames, code);
5298 smb_DeleteDirSearch(dsp);
5299 smb_ReleaseDirSearch(dsp);
5300 cm_ReleaseSCache(scp);
5301 cm_ReleaseUser(userp);
5305 /* finalize the output buffer */
5306 smb_SetSMBParm(outp, 0, returnedNames);
5307 temp = (long) (op - origOp);
5308 smb_SetSMBDataLength(outp, temp);
5310 /* the data area is a variable block, which has a 5 (already there)
5311 * followed by the length of the # of data bytes. We now know this to
5312 * be "temp," although that includes the 3 bytes of vbl block header.
5313 * Deduct for them and fill in the length field.
5315 temp -= 3; /* deduct vbl block info */
5316 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5317 origOp[1] = (unsigned char)(temp & 0xff);
5318 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5319 if (returnedNames == 0)
5320 smb_DeleteDirSearch(dsp);
5321 smb_ReleaseDirSearch(dsp);
5322 cm_ReleaseSCache(scp);
5323 cm_ReleaseUser(userp);
5328 /* verify that this is a valid path to a directory. I don't know why they
5329 * don't use the get file attributes call.
5331 * SMB_COM_CHECK_DIRECTORY
5333 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5335 clientchar_t *pathp;
5337 cm_scache_t *rootScp;
5338 cm_scache_t *newScp;
5342 clientchar_t *tidPathp;
5348 pdata = smb_GetSMBData(inp, NULL);
5349 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5351 return CM_ERROR_BADSMB;
5352 osi_Log1(smb_logp, "SMB receive check path %S",
5353 osi_LogSaveClientString(smb_logp, pathp));
5355 userp = smb_GetUserFromVCP(vcp, inp);
5357 rootScp = cm_RootSCachep(userp, &req);
5359 caseFold = CM_FLAG_CASEFOLD;
5361 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5363 cm_ReleaseUser(userp);
5364 return CM_ERROR_NOSUCHPATH;
5366 code = cm_NameI(rootScp, pathp,
5367 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5368 userp, tidPathp, &req, &newScp);
5371 cm_ReleaseUser(userp);
5376 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5377 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5378 cm_ReleaseSCache(newScp);
5379 cm_ReleaseUser(userp);
5380 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5381 return CM_ERROR_PATH_NOT_COVERED;
5383 return CM_ERROR_NOSUCHPATH;
5385 #endif /* DFS_SUPPORT */
5387 /* now lock the vnode with a callback; returns with newScp locked */
5388 lock_ObtainWrite(&newScp->rw);
5389 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5390 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5392 if (code != CM_ERROR_NOACCESS) {
5393 lock_ReleaseWrite(&newScp->rw);
5394 cm_ReleaseSCache(newScp);
5395 cm_ReleaseUser(userp);
5399 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5402 attrs = smb_Attributes(newScp);
5404 if (!(attrs & SMB_ATTR_DIRECTORY))
5405 code = CM_ERROR_NOTDIR;
5407 lock_ReleaseWrite(&newScp->rw);
5409 cm_ReleaseSCache(newScp);
5410 cm_ReleaseUser(userp);
5414 /* SMB_COM_SET_INFORMATION */
5415 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5417 clientchar_t *pathp;
5419 cm_scache_t *rootScp;
5420 unsigned short attribute;
5422 cm_scache_t *newScp;
5426 clientchar_t *tidPathp;
5432 /* decode basic attributes we're passed */
5433 attribute = smb_GetSMBParm(inp, 0);
5434 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5436 datap = smb_GetSMBData(inp, NULL);
5437 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5439 return CM_ERROR_BADSMB;
5441 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5442 dosTime, attribute);
5444 userp = smb_GetUserFromVCP(vcp, inp);
5446 rootScp = cm_RootSCachep(userp, &req);
5448 caseFold = CM_FLAG_CASEFOLD;
5450 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5452 cm_ReleaseUser(userp);
5453 return CM_ERROR_NOSUCHFILE;
5455 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5456 tidPathp, &req, &newScp);
5459 cm_ReleaseUser(userp);
5464 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5465 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5466 cm_ReleaseSCache(newScp);
5467 cm_ReleaseUser(userp);
5468 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5469 return CM_ERROR_PATH_NOT_COVERED;
5471 return CM_ERROR_NOSUCHPATH;
5473 #endif /* DFS_SUPPORT */
5475 /* now lock the vnode with a callback; returns with newScp locked; we
5476 * need the current status to determine what the new status is, in some
5479 lock_ObtainWrite(&newScp->rw);
5480 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5481 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5483 lock_ReleaseWrite(&newScp->rw);
5484 cm_ReleaseSCache(newScp);
5485 cm_ReleaseUser(userp);
5489 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5491 /* Check for RO volume */
5492 if (newScp->flags & CM_SCACHEFLAG_RO) {
5493 lock_ReleaseWrite(&newScp->rw);
5494 cm_ReleaseSCache(newScp);
5495 cm_ReleaseUser(userp);
5496 return CM_ERROR_READONLY;
5499 /* prepare for setattr call */
5502 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5503 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5505 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5506 /* we're told to make a writable file read-only */
5507 attr.unixModeBits = newScp->unixModeBits & ~0222;
5508 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5510 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5511 /* we're told to make a read-only file writable */
5512 attr.unixModeBits = newScp->unixModeBits | 0222;
5513 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5515 lock_ReleaseWrite(&newScp->rw);
5517 /* now call setattr */
5519 code = cm_SetAttr(newScp, &attr, userp, &req);
5523 cm_ReleaseSCache(newScp);
5524 cm_ReleaseUser(userp);
5530 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5532 clientchar_t *pathp;
5534 cm_scache_t *rootScp;
5535 cm_scache_t *newScp, *dscp;
5540 clientchar_t *tidPathp;
5542 clientchar_t *lastComp;
5548 datap = smb_GetSMBData(inp, NULL);
5549 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5551 return CM_ERROR_BADSMB;
5553 if (*pathp == 0) /* null path */
5556 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5557 osi_LogSaveClientString(smb_logp, pathp));
5559 userp = smb_GetUserFromVCP(vcp, inp);
5561 rootScp = cm_RootSCachep(userp, &req);
5563 /* we shouldn't need this for V3 requests, but we seem to */
5564 caseFold = CM_FLAG_CASEFOLD;
5566 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5568 cm_ReleaseUser(userp);
5569 return CM_ERROR_NOSUCHFILE;
5573 * XXX Strange hack XXX
5575 * As of Patch 5 (16 July 97), we are having the following problem:
5576 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5577 * requests to look up "desktop.ini" in all the subdirectories.
5578 * This can cause zillions of timeouts looking up non-existent cells
5579 * and volumes, especially in the top-level directory.
5581 * We have not found any way to avoid this or work around it except
5582 * to explicitly ignore the requests for mount points that haven't
5583 * yet been evaluated and for directories that haven't yet been
5586 * We should modify this hack to provide a fake desktop.ini file
5587 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5589 spacep = inp->spacep;
5590 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5591 #ifndef SPECIAL_FOLDERS
5592 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5593 code = cm_NameI(rootScp, spacep->wdata,
5594 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5595 userp, tidPathp, &req, &dscp);
5598 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5599 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5601 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5602 return CM_ERROR_PATH_NOT_COVERED;
5604 return CM_ERROR_NOSUCHPATH;
5606 #endif /* DFS_SUPPORT */
5607 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5608 code = CM_ERROR_NOSUCHFILE;
5609 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5610 cm_buf_t *bp = buf_Find(dscp, &hzero);
5615 code = CM_ERROR_NOSUCHFILE;
5617 cm_ReleaseSCache(dscp);
5619 cm_ReleaseUser(userp);
5623 else if (code != CM_ERROR_NOSUCHFILE &&
5624 code != CM_ERROR_NOSUCHPATH &&
5625 code != CM_ERROR_BPLUS_NOMATCH)
5627 cm_ReleaseUser(userp);
5631 #endif /* SPECIAL_FOLDERS */
5633 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5634 tidPathp, &req, &newScp);
5636 cm_ReleaseUser(userp);
5641 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5642 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5643 cm_ReleaseSCache(newScp);
5644 cm_ReleaseUser(userp);
5645 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5646 return CM_ERROR_PATH_NOT_COVERED;
5648 return CM_ERROR_NOSUCHPATH;
5650 #endif /* DFS_SUPPORT */
5652 /* now lock the vnode with a callback; returns with newScp locked */
5653 lock_ObtainWrite(&newScp->rw);
5654 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5655 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5657 lock_ReleaseWrite(&newScp->rw);
5658 cm_ReleaseSCache(newScp);
5659 cm_ReleaseUser(userp);
5663 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5665 attrs = smb_Attributes(newScp);
5667 smb_SetSMBParm(outp, 0, attrs);
5669 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5670 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5671 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5672 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5673 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5674 smb_SetSMBParm(outp, 5, 0);
5675 smb_SetSMBParm(outp, 6, 0);
5676 smb_SetSMBParm(outp, 7, 0);
5677 smb_SetSMBParm(outp, 8, 0);
5678 smb_SetSMBParm(outp, 9, 0);
5679 smb_SetSMBDataLength(outp, 0);
5680 lock_ReleaseWrite(&newScp->rw);
5682 cm_ReleaseSCache(newScp);
5683 cm_ReleaseUser(userp);
5688 /* SMB_COM_TREE_DISCONNECT */
5689 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5693 osi_Log0(smb_logp, "SMB receive tree disconnect");
5695 /* find the tree and free it */
5696 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5698 lock_ObtainWrite(&smb_rctLock);
5700 smb_ReleaseTID(tidp, TRUE);
5701 lock_ReleaseWrite(&smb_rctLock);
5708 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5711 clientchar_t *pathp;
5712 clientchar_t *lastNamep;
5721 clientchar_t *tidPathp;
5727 datap = smb_GetSMBData(inp, NULL);
5728 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5730 return CM_ERROR_BADSMB;
5732 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5734 #ifdef DEBUG_VERBOSE
5738 hexpath = osi_HexifyString( pathp );
5739 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5744 share = smb_GetSMBParm(inp, 0);
5745 attribute = smb_GetSMBParm(inp, 1);
5747 spacep = inp->spacep;
5748 /* smb_StripLastComponent will strip "::$DATA" if present */
5749 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5751 if (!cm_IsValidClientString(pathp)) {
5753 clientchar_t * hexp;
5755 hexp = cm_GetRawCharsAlloc(pathp, -1);
5756 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5757 osi_LogSaveClientString(smb_logp, hexp));
5761 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5763 return CM_ERROR_BADNTFILENAME;
5766 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5767 /* special case magic file name for receiving IOCTL requests
5768 * (since IOCTL calls themselves aren't getting through).
5770 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5771 smb_SetupIoctlFid(fidp, spacep);
5772 smb_SetSMBParm(outp, 0, fidp->fid);
5773 smb_SetSMBParm(outp, 1, 0); /* attrs */
5774 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5775 smb_SetSMBParm(outp, 3, 0);
5776 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5777 smb_SetSMBParm(outp, 5, 0x7fff);
5778 /* pass the open mode back */
5779 smb_SetSMBParm(outp, 6, (share & 0xf));
5780 smb_SetSMBDataLength(outp, 0);
5781 smb_ReleaseFID(fidp);
5785 userp = smb_GetUserFromVCP(vcp, inp);
5787 caseFold = CM_FLAG_CASEFOLD;
5789 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5791 cm_ReleaseUser(userp);
5792 return CM_ERROR_NOSUCHPATH;
5794 code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
5795 tidPathp, &req, &scp);
5798 cm_ReleaseUser(userp);
5803 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5804 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5805 cm_ReleaseSCache(scp);
5806 cm_ReleaseUser(userp);
5807 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5808 return CM_ERROR_PATH_NOT_COVERED;
5810 return CM_ERROR_NOSUCHPATH;
5812 #endif /* DFS_SUPPORT */
5814 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5816 cm_ReleaseSCache(scp);
5817 cm_ReleaseUser(userp);
5821 /* don't need callback to check file type, since file types never
5822 * change, and namei and cm_Lookup all stat the object at least once on
5823 * a successful return.
5825 if (scp->fileType != CM_SCACHETYPE_FILE) {
5826 cm_ReleaseSCache(scp);
5827 cm_ReleaseUser(userp);
5828 return CM_ERROR_ISDIR;
5831 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5832 osi_assertx(fidp, "null smb_fid_t");
5834 lock_ObtainMutex(&fidp->mx);
5835 if ((share & 0xf) == 0)
5836 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5837 else if ((share & 0xf) == 1)
5838 fidp->flags |= SMB_FID_OPENWRITE;
5840 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5844 fidp->userp = userp;
5846 /* and a pointer to the vnode */
5848 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5849 lock_ObtainWrite(&scp->rw);
5850 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5852 smb_SetSMBParm(outp, 0, fidp->fid);
5853 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5854 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5855 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5856 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5857 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5858 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5859 /* pass the open mode back; XXXX add access checks */
5860 smb_SetSMBParm(outp, 6, (share & 0xf));
5861 smb_SetSMBDataLength(outp, 0);
5862 lock_ReleaseMutex(&fidp->mx);
5863 lock_ReleaseRead(&scp->rw);
5866 cm_Open(scp, 0, userp);
5868 /* send and free packet */
5869 smb_ReleaseFID(fidp);
5870 cm_ReleaseUser(userp);
5871 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5875 typedef struct smb_unlinkRock {
5880 clientchar_t *maskp; /* pointer to the star pattern */
5883 cm_dirEntryList_t * matches;
5886 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5889 smb_unlinkRock_t *rockp;
5892 normchar_t matchName[MAX_PATH];
5896 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5897 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5898 caseFold |= CM_FLAG_8DOT3;
5900 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5901 /* Can't convert name */
5902 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5903 osi_LogSaveString(smb_logp, dep->name));
5907 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5909 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5910 !cm_Is8Dot3(matchName)) {
5911 cm_Gen8Dot3Name(dep, matchName, NULL);
5912 /* 8.3 matches are always case insensitive */
5913 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5916 osi_Log1(smb_logp, "Found match %S",
5917 osi_LogSaveClientString(smb_logp, matchName));
5919 cm_DirEntryListAdd(dep->name, &rockp->matches);
5923 /* If we made a case sensitive exact match, we might as well quit now. */
5924 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5925 code = CM_ERROR_STOPNOW;
5934 /* SMB_COM_DELETE */
5935 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5939 clientchar_t *pathp;
5943 clientchar_t *lastNamep;
5944 smb_unlinkRock_t rock;
5948 clientchar_t *tidPathp;
5952 memset(&rock, 0, sizeof(rock));
5954 attribute = smb_GetSMBParm(inp, 0);
5956 tp = smb_GetSMBData(inp, NULL);
5957 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5959 return CM_ERROR_BADSMB;
5961 osi_Log1(smb_logp, "SMB receive unlink %S",
5962 osi_LogSaveClientString(smb_logp, pathp));
5964 spacep = inp->spacep;
5965 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5967 userp = smb_GetUserFromVCP(vcp, inp);
5969 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5971 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5973 cm_ReleaseUser(userp);
5974 return CM_ERROR_NOSUCHPATH;
5976 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
5979 cm_ReleaseUser(userp);
5984 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5985 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5986 cm_ReleaseSCache(dscp);
5987 cm_ReleaseUser(userp);
5988 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5989 return CM_ERROR_PATH_NOT_COVERED;
5991 return CM_ERROR_NOSUCHPATH;
5993 #endif /* DFS_SUPPORT */
5995 /* otherwise, scp points to the parent directory. */
6002 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
6004 code = CM_ERROR_NOSUCHFILE;
6007 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6010 thyper.HighPart = 0;
6015 rock.matches = NULL;
6017 /* Now, if we aren't dealing with a wildcard match, we first try an exact
6018 * match. If that fails, we do a case insensitve match.
6020 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6021 !smb_IsStarMask(rock.maskp)) {
6022 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6025 thyper.HighPart = 0;
6026 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6031 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6033 if (code == CM_ERROR_STOPNOW)
6036 if (code == 0 && rock.matches) {
6037 cm_dirEntryList_t * entry;
6039 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6040 normchar_t normalizedName[MAX_PATH];
6042 /* Note: entry->name is a non-normalized name */
6044 osi_Log1(smb_logp, "Unlinking %s",
6045 osi_LogSaveString(smb_logp, entry->name));
6047 /* We assume this works because entry->name was
6048 successfully converted in smb_UnlinkProc() once. */
6049 cm_FsStringToNormString(entry->name, -1,
6050 normalizedName, lengthof(normalizedName));
6052 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6054 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6055 smb_NotifyChange(FILE_ACTION_REMOVED,
6056 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6057 dscp, normalizedName, NULL, TRUE);
6061 cm_DirEntryListFree(&rock.matches);
6065 cm_ReleaseUser(userp);
6068 cm_ReleaseSCache(dscp);
6073 if (code == 0 && !rock.any)
6074 code = CM_ERROR_NOSUCHFILE;
6078 typedef struct smb_renameRock {
6079 cm_scache_t *odscp; /* old dir */
6080 cm_scache_t *ndscp; /* new dir */
6081 cm_user_t *userp; /* user */
6082 cm_req_t *reqp; /* request struct */
6083 smb_vc_t *vcp; /* virtual circuit */
6084 normchar_t *maskp; /* pointer to star pattern of old file name */
6085 int flags; /* tilde, casefold, etc */
6086 clientchar_t *newNamep; /* ptr to the new file's name */
6087 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6088 clientchar_t clOldName[MAX_PATH]; /* client name */
6092 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6095 smb_renameRock_t *rockp;
6098 normchar_t matchName[MAX_PATH];
6100 rockp = (smb_renameRock_t *) vrockp;
6102 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6103 /* Can't convert string */
6104 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6105 osi_LogSaveString(smb_logp, dep->name));
6109 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6110 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6111 caseFold |= CM_FLAG_8DOT3;
6113 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6115 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6116 !cm_Is8Dot3(matchName)) {
6117 cm_Gen8Dot3Name(dep, matchName, NULL);
6118 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6123 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6124 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6126 code = CM_ERROR_STOPNOW;
6136 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6139 cm_space_t *spacep = NULL;
6140 smb_renameRock_t rock;
6141 cm_scache_t *oldDscp = NULL;
6142 cm_scache_t *newDscp = NULL;
6143 cm_scache_t *tmpscp= NULL;
6144 cm_scache_t *tmpscp2 = NULL;
6145 clientchar_t *oldLastNamep;
6146 clientchar_t *newLastNamep;
6150 clientchar_t *tidPathp;
6154 userp = smb_GetUserFromVCP(vcp, inp);
6155 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6157 cm_ReleaseUser(userp);
6158 return CM_ERROR_NOSUCHPATH;
6162 memset(&rock, 0, sizeof(rock));
6164 spacep = inp->spacep;
6165 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6167 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6168 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6169 userp, tidPathp, &req, &oldDscp);
6171 cm_ReleaseUser(userp);
6176 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6177 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6178 cm_ReleaseSCache(oldDscp);
6179 cm_ReleaseUser(userp);
6180 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6181 return CM_ERROR_PATH_NOT_COVERED;
6183 return CM_ERROR_NOSUCHPATH;
6185 #endif /* DFS_SUPPORT */
6187 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6188 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6189 userp, tidPathp, &req, &newDscp);
6192 cm_ReleaseSCache(oldDscp);
6193 cm_ReleaseUser(userp);
6198 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6199 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6200 cm_ReleaseSCache(oldDscp);
6201 cm_ReleaseSCache(newDscp);
6202 cm_ReleaseUser(userp);
6203 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6204 return CM_ERROR_PATH_NOT_COVERED;
6206 return CM_ERROR_NOSUCHPATH;
6208 #endif /* DFS_SUPPORT */
6211 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6212 * next, get the component names, and lower case them.
6215 /* handle the old name first */
6217 oldLastNamep = oldPathp;
6221 /* and handle the new name, too */
6223 newLastNamep = newPathp;
6227 /* TODO: The old name could be a wildcard. The new name must not be */
6229 /* Check if the file already exists; if so return error */
6230 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6231 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6232 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6234 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6235 osi_LogSaveClientString(smb_logp, newLastNamep));
6237 /* Check if the old and the new names differ only in case. If so return
6238 * success, else return CM_ERROR_EXISTS
6240 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6242 /* This would be a success only if the old file is *as same as* the new file */
6243 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6245 if (tmpscp == tmpscp2)
6248 code = CM_ERROR_EXISTS;
6249 cm_ReleaseSCache(tmpscp2);
6252 code = CM_ERROR_NOSUCHFILE;
6255 /* file exist, do not rename, also fixes move */
6256 osi_Log0(smb_logp, "Can't rename. Target already exists");
6257 code = CM_ERROR_EXISTS;
6262 /* do the vnode call */
6263 rock.odscp = oldDscp;
6264 rock.ndscp = newDscp;
6268 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6270 code = CM_ERROR_NOSUCHFILE;
6273 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6274 rock.newNamep = newLastNamep;
6275 rock.fsOldName[0] = '\0';
6276 rock.clOldName[0] = '\0';
6279 /* Now search the directory for the pattern, and do the appropriate rename when found */
6280 thyper.LowPart = 0; /* search dir from here */
6281 thyper.HighPart = 0;
6283 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6284 if (code == 0 && !rock.any) {
6286 thyper.HighPart = 0;
6287 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6288 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6290 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6292 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6293 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6294 rock.ndscp, rock.newNamep, rock.userp,
6296 /* if the call worked, stop doing the search now, since we
6297 * really only want to rename one file.
6300 osi_Log0(smb_logp, "cm_Rename failure");
6301 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6302 } else if (code == 0) {
6303 code = CM_ERROR_NOSUCHFILE;
6306 /* Handle Change Notification */
6308 * Being lazy, not distinguishing between files and dirs in this
6309 * filter, since we'd have to do a lookup.
6312 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6313 if (oldDscp == newDscp) {
6314 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6315 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6316 filter, oldDscp, rock.clOldName,
6317 newLastNamep, TRUE);
6319 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6320 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6321 filter, oldDscp, rock.clOldName,
6323 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6324 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6325 filter, newDscp, newLastNamep,
6332 cm_ReleaseSCache(tmpscp);
6334 cm_ReleaseUser(userp);
6336 cm_ReleaseSCache(oldDscp);
6338 cm_ReleaseSCache(newDscp);
6346 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6349 cm_space_t *spacep = NULL;
6350 cm_scache_t *oldDscp = NULL;
6351 cm_scache_t *newDscp = NULL;
6352 cm_scache_t *tmpscp= NULL;
6353 cm_scache_t *tmpscp2 = NULL;
6354 cm_scache_t *sscp = NULL;
6355 clientchar_t *oldLastNamep;
6356 clientchar_t *newLastNamep;
6359 clientchar_t *tidPathp;
6363 userp = smb_GetUserFromVCP(vcp, inp);
6365 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6367 cm_ReleaseUser(userp);
6368 return CM_ERROR_NOSUCHPATH;
6373 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6375 spacep = inp->spacep;
6376 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6378 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6379 userp, tidPathp, &req, &oldDscp);
6381 cm_ReleaseUser(userp);
6386 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6387 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6388 cm_ReleaseSCache(oldDscp);
6389 cm_ReleaseUser(userp);
6390 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6391 return CM_ERROR_PATH_NOT_COVERED;
6393 return CM_ERROR_NOSUCHPATH;
6395 #endif /* DFS_SUPPORT */
6397 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6398 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6399 userp, tidPathp, &req, &newDscp);
6401 cm_ReleaseSCache(oldDscp);
6402 cm_ReleaseUser(userp);
6407 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6408 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6409 cm_ReleaseSCache(newDscp);
6410 cm_ReleaseSCache(oldDscp);
6411 cm_ReleaseUser(userp);
6412 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6413 return CM_ERROR_PATH_NOT_COVERED;
6415 return CM_ERROR_NOSUCHPATH;
6417 #endif /* DFS_SUPPORT */
6419 /* Now, although we did two lookups for the two directories (because the same
6420 * directory can be referenced through different paths), we only allow hard links
6421 * within the same directory. */
6422 if (oldDscp != newDscp) {
6423 cm_ReleaseSCache(oldDscp);
6424 cm_ReleaseSCache(newDscp);
6425 cm_ReleaseUser(userp);
6426 return CM_ERROR_CROSSDEVLINK;
6429 /* handle the old name first */
6431 oldLastNamep = oldPathp;
6435 /* and handle the new name, too */
6437 newLastNamep = newPathp;
6441 /* now lookup the old name */
6442 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6443 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6445 cm_ReleaseSCache(oldDscp);
6446 cm_ReleaseSCache(newDscp);
6447 cm_ReleaseUser(userp);
6451 /* Check if the file already exists; if so return error */
6452 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6453 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6454 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6456 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6457 osi_LogSaveClientString(smb_logp, newLastNamep));
6459 /* if the existing link is to the same file, then we return success */
6461 if(sscp == tmpscp) {
6464 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6465 code = CM_ERROR_EXISTS;
6470 cm_ReleaseSCache(tmpscp);
6471 cm_ReleaseSCache(sscp);
6472 cm_ReleaseSCache(newDscp);
6473 cm_ReleaseSCache(oldDscp);
6474 cm_ReleaseUser(userp);
6478 /* now create the hardlink */
6479 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6480 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6481 osi_Log1(smb_logp," Link returns 0x%x", code);
6483 /* Handle Change Notification */
6485 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6486 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6487 smb_NotifyChange(FILE_ACTION_ADDED,
6488 filter, newDscp, newLastNamep,
6493 cm_ReleaseSCache(tmpscp);
6494 cm_ReleaseUser(userp);
6495 cm_ReleaseSCache(sscp);
6496 cm_ReleaseSCache(oldDscp);
6497 cm_ReleaseSCache(newDscp);
6501 /* SMB_COM_RENAME */
6503 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6505 clientchar_t *oldPathp;
6506 clientchar_t *newPathp;
6510 tp = smb_GetSMBData(inp, NULL);
6511 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6513 return CM_ERROR_BADSMB;
6514 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6516 return CM_ERROR_BADSMB;
6518 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6519 osi_LogSaveClientString(smb_logp, oldPathp),
6520 osi_LogSaveClientString(smb_logp, newPathp));
6522 if (!cm_IsValidClientString(newPathp)) {
6524 clientchar_t * hexp;
6526 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6527 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6528 osi_LogSaveClientString(smb_logp, hexp));
6532 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6534 return CM_ERROR_BADNTFILENAME;
6537 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6539 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6545 typedef struct smb_rmdirRock {
6549 normchar_t *maskp; /* pointer to the star pattern */
6552 cm_dirEntryList_t * matches;
6555 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6558 smb_rmdirRock_t *rockp;
6560 normchar_t matchName[MAX_PATH];
6562 rockp = (smb_rmdirRock_t *) vrockp;
6564 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6565 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6566 osi_LogSaveString(smb_logp, dep->name));
6570 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6571 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6573 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6575 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6576 !cm_Is8Dot3(matchName)) {
6577 cm_Gen8Dot3Name(dep, matchName, NULL);
6578 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6583 cm_DirEntryListAdd(dep->name, &rockp->matches);
6590 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6593 clientchar_t *pathp;
6597 clientchar_t *lastNamep;
6598 smb_rmdirRock_t rock;
6602 clientchar_t *tidPathp;
6606 memset(&rock, 0, sizeof(rock));
6608 tp = smb_GetSMBData(inp, NULL);
6609 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6611 return CM_ERROR_BADSMB;
6613 spacep = inp->spacep;
6614 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6616 userp = smb_GetUserFromVCP(vcp, inp);
6618 caseFold = CM_FLAG_CASEFOLD;
6620 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6622 cm_ReleaseUser(userp);
6623 return CM_ERROR_NOSUCHPATH;
6625 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6626 userp, tidPathp, &req, &dscp);
6629 cm_ReleaseUser(userp);
6634 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6635 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6636 cm_ReleaseSCache(dscp);
6637 cm_ReleaseUser(userp);
6638 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6639 return CM_ERROR_PATH_NOT_COVERED;
6641 return CM_ERROR_NOSUCHPATH;
6643 #endif /* DFS_SUPPORT */
6645 /* otherwise, scp points to the parent directory. */
6652 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6654 code = CM_ERROR_NOSUCHFILE;
6657 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6660 thyper.HighPart = 0;
6664 rock.matches = NULL;
6666 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6667 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6668 if (code == 0 && !rock.any) {
6670 thyper.HighPart = 0;
6671 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6672 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6675 if (code == 0 && rock.matches) {
6676 cm_dirEntryList_t * entry;
6678 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6679 clientchar_t clientName[MAX_PATH];
6681 /* We assume this will succeed because smb_RmdirProc()
6682 successfully converted entry->name once above. */
6683 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6685 osi_Log1(smb_logp, "Removing directory %s",
6686 osi_LogSaveString(smb_logp, entry->name));
6688 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6690 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6691 smb_NotifyChange(FILE_ACTION_REMOVED,
6692 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6693 dscp, clientName, NULL, TRUE);
6699 cm_DirEntryListFree(&rock.matches);
6702 cm_ReleaseUser(userp);
6705 cm_ReleaseSCache(dscp);
6707 if (code == 0 && !rock.any)
6708 code = CM_ERROR_NOSUCHFILE;
6717 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6727 fid = smb_GetSMBParm(inp, 0);
6729 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6731 fid = smb_ChainFID(fid, inp);
6732 fidp = smb_FindFID(vcp, fid, 0);
6734 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6736 return CM_ERROR_BADFD;
6738 userp = smb_GetUserFromVCP(vcp, inp);
6740 lock_ObtainMutex(&fidp->mx);
6741 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6742 cm_ReleaseUser(userp);
6743 lock_ReleaseMutex(&fidp->mx);
6744 smb_ReleaseFID(fidp);
6745 return CM_ERROR_BADFD;
6748 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6749 lock_ReleaseMutex(&fidp->mx);
6750 cm_ReleaseUser(userp);
6751 smb_CloseFID(vcp, fidp, NULL, 0);
6752 smb_ReleaseFID(fidp);
6753 return CM_ERROR_NOSUCHFILE;
6756 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6757 cm_scache_t * scp = fidp->scp;
6759 lock_ReleaseMutex(&fidp->mx);
6760 code = cm_FSync(scp, userp, &req, FALSE);
6761 cm_ReleaseSCache(scp);
6763 lock_ReleaseMutex(&fidp->mx);
6767 cm_ReleaseUser(userp);
6768 smb_ReleaseFID(fidp);
6772 struct smb_FullNameRock {
6775 clientchar_t *fullName;
6776 fschar_t *originalName;
6779 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6782 normchar_t matchName[MAX_PATH];
6783 struct smb_FullNameRock *vrockp;
6785 vrockp = (struct smb_FullNameRock *)rockp;
6787 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6788 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6789 osi_LogSaveString(smb_logp, dep->name));
6793 if (!cm_Is8Dot3(matchName)) {
6794 clientchar_t shortName[13];
6796 cm_Gen8Dot3Name(dep, shortName, NULL);
6798 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6799 vrockp->fullName = cm_ClientStrDup(matchName);
6800 vrockp->originalName = cm_FsStrDup(dep->name);
6801 return CM_ERROR_STOPNOW;
6804 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6805 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6806 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6807 vrockp->fullName = cm_ClientStrDup(matchName);
6808 vrockp->originalName = cm_FsStrDup(dep->name);
6809 return CM_ERROR_STOPNOW;
6814 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6815 clientchar_t **newPathp, fschar_t ** originalPathp,
6816 cm_user_t *userp, cm_req_t *reqp)
6818 struct smb_FullNameRock rock;
6821 memset(&rock, 0, sizeof(rock));
6825 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6826 if (code == CM_ERROR_STOPNOW) {
6827 *newPathp = rock.fullName;
6828 *originalPathp = rock.originalName;
6830 *newPathp = cm_ClientStrDup(pathp);
6831 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6835 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6836 afs_uint32 dosTime) {
6839 cm_scache_t *dscp = NULL;
6840 clientchar_t *pathp = NULL;
6841 cm_scache_t * scp = NULL;
6842 cm_scache_t *delscp = NULL;
6843 int nullcreator = 0;
6845 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6846 fidp, fidp->fid, scp, vcp);
6849 lock_ObtainMutex(&fidp->mx);
6850 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6852 lock_ReleaseMutex(&fidp->mx);
6853 osi_Log0(smb_logp, " No user specified. Not closing fid");
6854 return CM_ERROR_BADFD;
6857 userp = fidp->userp; /* no hold required since fidp is held
6858 throughout the function */
6859 lock_ReleaseMutex(&fidp->mx);
6864 lock_ObtainWrite(&smb_rctLock);
6865 if (fidp->deleteOk) {
6866 osi_Log0(smb_logp, " Fid already closed.");
6867 lock_ReleaseWrite(&smb_rctLock);
6868 return CM_ERROR_BADFD;
6871 lock_ReleaseWrite(&smb_rctLock);
6873 lock_ObtainMutex(&fidp->mx);
6874 if (fidp->NTopen_dscp) {
6875 dscp = fidp->NTopen_dscp;
6876 cm_HoldSCache(dscp);
6879 if (fidp->NTopen_pathp)
6880 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6887 /* Don't jump the gun on an async raw write */
6888 while (fidp->raw_writers) {
6889 lock_ReleaseMutex(&fidp->mx);
6890 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6891 lock_ObtainMutex(&fidp->mx);
6894 /* watch for ioctl closes, and read-only opens */
6896 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6897 == SMB_FID_OPENWRITE) {
6898 if (dosTime != 0 && dosTime != -1) {
6899 lock_ObtainWrite(&fidp->scp->rw);
6900 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6901 /* This fixes defect 10958 */
6902 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6903 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6904 lock_ReleaseWrite(&fidp->scp->rw);
6906 if (smb_AsyncStore != 2) {
6907 lock_ReleaseMutex(&fidp->mx);
6908 code = cm_FSync(scp, userp, &req, FALSE);
6909 lock_ObtainMutex(&fidp->mx);
6915 /* unlock any pending locks */
6916 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6917 scp->fileType == CM_SCACHETYPE_FILE) {
6921 lock_ReleaseMutex(&fidp->mx);
6923 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6925 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6926 lock_ObtainWrite(&scp->rw);
6928 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6929 CM_SCACHESYNC_NEEDCALLBACK
6930 | CM_SCACHESYNC_GETSTATUS
6931 | CM_SCACHESYNC_LOCK);
6935 "smb CoreClose SyncOp failure code 0x%x", tcode);
6936 goto post_syncopdone;
6939 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6941 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6945 lock_ReleaseWrite(&scp->rw);
6946 lock_ObtainMutex(&fidp->mx);
6949 if (fidp->flags & SMB_FID_DELONCLOSE) {
6950 clientchar_t *fullPathp = NULL;
6951 fschar_t *originalNamep = NULL;
6953 lock_ReleaseMutex(&fidp->mx);
6955 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6960 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6961 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6962 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6964 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6965 smb_NotifyChange(FILE_ACTION_REMOVED,
6966 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6967 dscp, fullPathp, NULL, TRUE);
6970 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6972 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6973 smb_NotifyChange(FILE_ACTION_REMOVED,
6974 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6975 dscp, fullPathp, NULL, TRUE);
6982 free(originalNamep);
6984 lock_ObtainMutex(&fidp->mx);
6985 fidp->flags &= ~SMB_FID_DELONCLOSE;
6988 /* if this was a newly created file, then clear the creator
6989 * in the stat cache entry. */
6990 if (fidp->flags & SMB_FID_CREATED) {
6992 fidp->flags &= ~SMB_FID_CREATED;
6995 if (fidp->flags & SMB_FID_NTOPEN) {
6996 cm_ReleaseSCache(fidp->NTopen_dscp);
6997 fidp->NTopen_dscp = NULL;
6998 free(fidp->NTopen_pathp);
6999 fidp->NTopen_pathp = NULL;
7000 fidp->flags &= ~SMB_FID_NTOPEN;
7002 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
7003 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7006 if (fidp->NTopen_wholepathp) {
7007 free(fidp->NTopen_wholepathp);
7008 fidp->NTopen_wholepathp = NULL;
7012 cm_ReleaseSCache(fidp->scp);
7015 lock_ReleaseMutex(&fidp->mx);
7018 cm_ReleaseSCache(dscp);
7021 cm_ReleaseSCache(delscp);
7025 lock_ObtainWrite(&scp->rw);
7026 if (nullcreator && scp->creator == userp)
7027 scp->creator = NULL;
7028 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7029 lock_ReleaseWrite(&scp->rw);
7030 cm_ReleaseSCache(scp);
7040 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7048 fid = smb_GetSMBParm(inp, 0);
7049 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7051 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7053 fid = smb_ChainFID(fid, inp);
7054 fidp = smb_FindFID(vcp, fid, 0);
7056 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
7058 return CM_ERROR_BADFD;
7061 userp = smb_GetUserFromVCP(vcp, inp);
7063 code = smb_CloseFID(vcp, fidp, userp, dosTime);
7065 smb_ReleaseFID(fidp);
7066 cm_ReleaseUser(userp);
7071 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7073 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7074 cm_user_t *userp, long *readp)
7080 osi_hyper_t fileLength;
7082 osi_hyper_t lastByte;
7083 osi_hyper_t bufferOffset;
7087 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7090 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7091 fidp->fid, offsetp->LowPart, count);
7095 lock_ObtainMutex(&fidp->mx);
7096 /* make sure we have a readable FD */
7097 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7098 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7099 fidp->fid, fidp->flags);
7100 lock_ReleaseMutex(&fidp->mx);
7101 code = CM_ERROR_BADFDOP;
7106 lock_ReleaseMutex(&fidp->mx);
7107 code = CM_ERROR_BADFD;
7118 lock_ObtainWrite(&scp->rw);
7120 if (offset.HighPart == 0) {
7121 chunk = offset.LowPart >> cm_logChunkSize;
7122 if (chunk != fidp->curr_chunk) {
7123 fidp->prev_chunk = fidp->curr_chunk;
7124 fidp->curr_chunk = chunk;
7126 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7129 lock_ReleaseMutex(&fidp->mx);
7131 /* start by looking up the file's end */
7132 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7133 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7137 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7139 /* now we have the entry locked, look up the length */
7140 fileLength = scp->length;
7142 /* adjust count down so that it won't go past EOF */
7143 thyper.LowPart = count;
7144 thyper.HighPart = 0;
7145 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7147 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7148 /* we'd read past EOF, so just stop at fileLength bytes.
7149 * Start by computing how many bytes remain in the file.
7151 thyper = LargeIntegerSubtract(fileLength, offset);
7153 /* if we are past EOF, read 0 bytes */
7154 if (LargeIntegerLessThanZero(thyper))
7157 count = thyper.LowPart;
7162 /* now, copy the data one buffer at a time,
7163 * until we've filled the request packet
7166 /* if we've copied all the data requested, we're done */
7167 if (count <= 0) break;
7169 /* otherwise, load up a buffer of data */
7170 thyper.HighPart = offset.HighPart;
7171 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7172 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7175 buf_Release(bufferp);
7178 lock_ReleaseWrite(&scp->rw);
7180 code = buf_Get(scp, &thyper, &req, &bufferp);
7182 lock_ObtainWrite(&scp->rw);
7183 if (code) goto done;
7184 bufferOffset = thyper;
7186 /* now get the data in the cache */
7188 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7189 CM_SCACHESYNC_NEEDCALLBACK |
7190 CM_SCACHESYNC_READ);
7194 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7196 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7198 /* otherwise, load the buffer and try again */
7199 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7203 buf_Release(bufferp);
7207 } /* if (wrong buffer) ... */
7209 /* now we have the right buffer loaded. Copy out the
7210 * data from here to the user's buffer.
7212 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7214 /* and figure out how many bytes we want from this buffer */
7215 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7216 if (nbytes > count) nbytes = count; /* don't go past EOF */
7218 /* now copy the data */
7219 memcpy(op, bufferp->datap + bufIndex, nbytes);
7221 /* adjust counters, pointers, etc. */
7224 thyper.LowPart = nbytes;
7225 thyper.HighPart = 0;
7226 offset = LargeIntegerAdd(thyper, offset);
7230 lock_ReleaseWrite(&scp->rw);
7232 buf_Release(bufferp);
7234 if (code == 0 && sequential)
7235 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7237 cm_ReleaseSCache(scp);
7240 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7241 fidp->fid, code, *readp);
7246 * smb_WriteData -- common code for Write and Raw Write
7248 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7249 cm_user_t *userp, long *writtenp)
7251 osi_hyper_t offset = *offsetp;
7254 cm_scache_t *scp = NULL;
7255 osi_hyper_t fileLength; /* file's length at start of write */
7256 osi_hyper_t minLength; /* don't read past this */
7257 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7258 cm_buf_t *bufferp = NULL;
7259 osi_hyper_t thyper; /* hyper tmp variable */
7260 osi_hyper_t bufferOffset;
7261 afs_uint32 bufIndex; /* index in buffer where our data is */
7262 int doWriteBack = 0;
7263 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7266 int needSyncOpDone = 0;
7268 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7269 fidp->fid, offsetp->LowPart, count);
7273 lock_ObtainMutex(&fidp->mx);
7274 /* make sure we have a writable FD */
7275 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7276 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7277 fidp->fid, fidp->flags);
7278 lock_ReleaseMutex(&fidp->mx);
7279 code = CM_ERROR_BADFDOP;
7287 lock_ReleaseMutex(&fidp->mx);
7289 lock_ObtainWrite(&scp->rw);
7290 /* start by looking up the file's end */
7291 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7292 CM_SCACHESYNC_NEEDCALLBACK
7293 | CM_SCACHESYNC_SETSTATUS
7294 | CM_SCACHESYNC_GETSTATUS);
7298 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7300 /* now we have the entry locked, look up the length */
7301 fileLength = scp->length;
7302 minLength = fileLength;
7303 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7304 minLength = scp->serverLength;
7306 /* adjust file length if we extend past EOF */
7307 thyper.LowPart = count;
7308 thyper.HighPart = 0;
7309 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7310 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7311 /* we'd write past EOF, so extend the file */
7312 scp->mask |= CM_SCACHEMASK_LENGTH;
7313 scp->length = thyper;
7314 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7316 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7318 /* now, if the new position (thyper) and the old (offset) are in
7319 * different storeback windows, remember to store back the previous
7320 * storeback window when we're done with the write.
7322 * the purpose of this logic is to slow down the CIFS client
7323 * in order to avoid the client disconnecting during the CLOSE
7324 * operation if there are too many dirty buffers left to write
7325 * than can be accomplished during 45 seconds. This used to be
7326 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7327 * so that we can read larger amounts of data at a time.
7329 if (smb_AsyncStore == 1 &&
7330 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7331 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7332 /* they're different */
7334 writeBackOffset.HighPart = offset.HighPart;
7335 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7340 /* now, copy the data one buffer at a time, until we've filled the
7342 while (count != 0) {
7344 /* handle over quota or out of space */
7345 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7346 *writtenp = written;
7347 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7351 /* otherwise, load up a buffer of data */
7352 thyper.HighPart = offset.HighPart;
7353 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7354 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7357 if (needSyncOpDone) {
7358 cm_SyncOpDone(scp, bufferp,
7359 CM_SCACHESYNC_NEEDCALLBACK
7360 | CM_SCACHESYNC_WRITE
7361 | CM_SCACHESYNC_BUFLOCKED);
7364 lock_ReleaseMutex(&bufferp->mx);
7365 buf_Release(bufferp);
7368 lock_ReleaseWrite(&scp->rw);
7370 code = buf_Get(scp, &thyper, &req, &bufferp);
7372 lock_ObtainMutex(&bufferp->mx);
7373 lock_ObtainWrite(&scp->rw);
7374 if (code) goto done;
7376 bufferOffset = thyper;
7378 /* now get the data in the cache */
7380 if (!needSyncOpDone) {
7381 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7382 CM_SCACHESYNC_NEEDCALLBACK
7383 | CM_SCACHESYNC_WRITE
7384 | CM_SCACHESYNC_BUFLOCKED);
7391 /* If we're overwriting the entire buffer, or
7392 * if we're writing at or past EOF, mark the
7393 * buffer as current so we don't call
7394 * cm_GetBuffer. This skips the fetch from the
7395 * server in those cases where we're going to
7396 * obliterate all the data in the buffer anyway,
7397 * or in those cases where there is no useful
7398 * data at the server to start with.
7400 * Use minLength instead of scp->length, since
7401 * the latter has already been updated by this
7404 * The scp lock has been dropped multiple times
7405 * so the minLength must be refreshed before it
7409 minLength = scp->length;
7410 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7411 minLength = scp->serverLength;
7413 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7414 || LargeIntegerEqualTo(offset, bufferp->offset)
7415 && (count >= cm_data.buf_blockSize
7416 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7417 ConvertLongToLargeInteger(count)),
7419 if (count < cm_data.buf_blockSize
7420 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7421 memset(bufferp->datap, 0,
7422 cm_data.buf_blockSize);
7423 bufferp->dataVersion = scp->dataVersion;
7426 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7428 /* otherwise, load the buffer and try again */
7429 cm_SyncOpDone(scp, bufferp,
7430 CM_SCACHESYNC_NEEDCALLBACK
7431 | CM_SCACHESYNC_WRITE
7432 | CM_SCACHESYNC_BUFLOCKED);
7435 lock_ReleaseMutex(&bufferp->mx);
7436 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7438 lock_ReleaseWrite(&scp->rw);
7439 lock_ObtainMutex(&bufferp->mx);
7440 lock_ObtainWrite(&scp->rw);
7444 } /* if (wrong buffer) ... */
7446 /* now we have the right buffer loaded. Copy out the
7447 * data from here to the user's buffer.
7449 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7451 /* and figure out how many bytes we want from this buffer */
7452 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7454 nbytes = count; /* don't go past end of request */
7456 /* now copy the data */
7457 memcpy(bufferp->datap + bufIndex, op, nbytes);
7458 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7460 /* adjust counters, pointers, etc. */
7464 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7465 } /* while count != 0 */
7468 if (bufferp && needSyncOpDone) {
7469 cm_SyncOpDone(scp, bufferp,
7470 CM_SCACHESYNC_NEEDCALLBACK
7471 | CM_SCACHESYNC_WRITE
7472 | CM_SCACHESYNC_BUFLOCKED);
7475 lock_ReleaseWrite(&scp->rw);
7478 lock_ReleaseMutex(&bufferp->mx);
7479 buf_Release(bufferp);
7482 lock_ObtainMutex(&fidp->mx);
7483 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7484 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7486 lock_ReleaseMutex(&fidp->mx);
7487 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7488 fidp->NTopen_dscp, fidp->NTopen_pathp,
7491 lock_ReleaseMutex(&fidp->mx);
7495 if (smb_AsyncStore > 0) {
7499 lock_ObtainWrite(&scp->rw);
7500 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7502 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7503 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7505 lock_ReleaseWrite(&scp->rw);
7506 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7507 writeBackOffset.HighPart,
7508 smb_AsyncStoreSize, 0, userp);
7509 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7512 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7516 cm_ReleaseSCache(scp);
7519 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7520 fidp->fid, code, *writtenp);
7525 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7528 unsigned short count;
7530 unsigned short hint;
7531 long written = 0, total_written = 0;
7534 smb_t* smbp = (smb_t*) inp;
7538 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7540 int inDataBlockCount;
7542 fd = smb_GetSMBParm(inp, 0);
7543 count = smb_GetSMBParm(inp, 1);
7544 offset.HighPart = 0; /* too bad */
7545 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7546 hint = smb_GetSMBParm(inp, 4);
7548 op = smb_GetSMBData(inp, NULL);
7549 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7551 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7552 fd, offset.LowPart, count);
7554 fd = smb_ChainFID(fd, inp);
7555 fidp = smb_FindFID(vcp, fd, 0);
7557 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7559 return CM_ERROR_BADFD;
7562 lock_ObtainMutex(&fidp->mx);
7563 if (fidp->flags & SMB_FID_IOCTL) {
7564 lock_ReleaseMutex(&fidp->mx);
7565 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7566 smb_ReleaseFID(fidp);
7567 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7571 if (fidp->flags & SMB_FID_RPC) {
7572 lock_ReleaseMutex(&fidp->mx);
7573 code = smb_RPCWrite(fidp, vcp, inp, outp);
7574 smb_ReleaseFID(fidp);
7575 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7580 lock_ReleaseMutex(&fidp->mx);
7581 smb_ReleaseFID(fidp);
7582 return CM_ERROR_BADFD;
7585 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7586 lock_ReleaseMutex(&fidp->mx);
7587 smb_CloseFID(vcp, fidp, NULL, 0);
7588 smb_ReleaseFID(fidp);
7589 return CM_ERROR_NOSUCHFILE;
7594 lock_ReleaseMutex(&fidp->mx);
7595 userp = smb_GetUserFromVCP(vcp, inp);
7599 LARGE_INTEGER LOffset;
7600 LARGE_INTEGER LLength;
7603 key = cm_GenerateKey(vcp->vcID, pid, fd);
7605 LOffset.HighPart = offset.HighPart;
7606 LOffset.LowPart = offset.LowPart;
7607 LLength.HighPart = 0;
7608 LLength.LowPart = count;
7610 lock_ObtainWrite(&scp->rw);
7611 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7612 lock_ReleaseWrite(&scp->rw);
7615 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7620 /* special case: 0 bytes transferred means truncate to this position */
7624 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7628 truncAttr.mask = CM_ATTRMASK_LENGTH;
7629 truncAttr.length.LowPart = offset.LowPart;
7630 truncAttr.length.HighPart = 0;
7631 lock_ObtainMutex(&fidp->mx);
7632 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7633 fidp->flags |= SMB_FID_LENGTHSETDONE;
7634 lock_ReleaseMutex(&fidp->mx);
7635 smb_SetSMBParm(outp, 0, 0 /* count */);
7636 smb_SetSMBDataLength(outp, 0);
7641 * Work around bug in NT client
7643 * When copying a file, the NT client should first copy the data,
7644 * then copy the last write time. But sometimes the NT client does
7645 * these in the wrong order, so the data copies would inadvertently
7646 * cause the last write time to be overwritten. We try to detect this,
7647 * and don't set client mod time if we think that would go against the
7650 lock_ObtainMutex(&fidp->mx);
7651 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7652 lock_ObtainWrite(&fidp->scp->rw);
7653 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7654 fidp->scp->clientModTime = time(NULL);
7655 lock_ReleaseWrite(&fidp->scp->rw);
7657 lock_ReleaseMutex(&fidp->mx);
7660 while ( code == 0 && count > 0 ) {
7661 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7662 if (code == 0 && written == 0)
7663 code = CM_ERROR_PARTIALWRITE;
7665 offset = LargeIntegerAdd(offset,
7666 ConvertLongToLargeInteger(written));
7667 count -= (unsigned short)written;
7668 total_written += written;
7672 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7673 total_written, code);
7675 /* set the packet data length to 3 bytes for the data block header,
7676 * plus the size of the data.
7678 smb_SetSMBParm(outp, 0, total_written);
7679 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7680 smb_SetSMBParm(outp, 3, hint);
7681 smb_SetSMBDataLength(outp, 0);
7684 smb_ReleaseFID(fidp);
7685 cm_ReleaseUser(userp);
7686 cm_ReleaseSCache(scp);
7691 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7692 NCB *ncbp, raw_write_cont_t *rwcp)
7701 fd = smb_GetSMBParm(inp, 0);
7702 fidp = smb_FindFID(vcp, fd, 0);
7704 lock_ObtainMutex(&fidp->mx);
7706 lock_ReleaseMutex(&fidp->mx);
7707 smb_ReleaseFID(fidp);
7711 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7712 lock_ReleaseMutex(&fidp->mx);
7713 smb_CloseFID(vcp, fidp, NULL, 0);
7714 smb_ReleaseFID(fidp);
7717 lock_ReleaseMutex(&fidp->mx);
7719 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7720 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7722 userp = smb_GetUserFromVCP(vcp, inp);
7725 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7727 if (rwcp->writeMode & 0x1) { /* synchronous */
7730 smb_FormatResponsePacket(vcp, inp, outp);
7731 op = (smb_t *) outp;
7732 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7733 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7734 smb_SetSMBDataLength(outp, 0);
7735 smb_SendPacket(vcp, outp);
7736 smb_FreePacket(outp);
7738 else { /* asynchronous */
7739 lock_ObtainMutex(&fidp->mx);
7740 fidp->raw_writers--;
7741 if (fidp->raw_writers == 0)
7742 thrd_SetEvent(fidp->raw_write_event);
7743 lock_ReleaseMutex(&fidp->mx);
7746 /* Give back raw buffer */
7747 lock_ObtainMutex(&smb_RawBufLock);
7748 *((char **)rawBuf) = smb_RawBufs;
7749 smb_RawBufs = rawBuf;
7750 lock_ReleaseMutex(&smb_RawBufLock);
7752 smb_ReleaseFID(fidp);
7753 cm_ReleaseUser(userp);
7756 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7761 /* SMB_COM_WRITE_RAW */
7762 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7765 long count, written = 0, total_written = 0;
7769 smb_t *smbp = (smb_t*) inp;
7774 unsigned short writeMode;
7776 fd = smb_GetSMBParm(inp, 0);
7777 totalCount = smb_GetSMBParm(inp, 1);
7778 count = smb_GetSMBParm(inp, 10);
7779 writeMode = smb_GetSMBParm(inp, 7);
7781 op = (char *) inp->data;
7782 op += smb_GetSMBParm(inp, 11);
7784 offset.HighPart = 0;
7785 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7787 if (*inp->wctp == 14) {
7788 /* we received a 64-bit file offset */
7789 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7791 if (LargeIntegerLessThanZero(offset)) {
7793 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7794 offset.HighPart, offset.LowPart);
7795 return CM_ERROR_BADSMB;
7798 offset.HighPart = 0; /* 32-bit file offset */
7802 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7803 fd, offset.HighPart, offset.LowPart, count);
7805 " WriteRaw WriteMode 0x%x",
7808 fd = smb_ChainFID(fd, inp);
7809 fidp = smb_FindFID(vcp, fd, 0);
7811 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7813 return CM_ERROR_BADFD;
7815 lock_ObtainMutex(&fidp->mx);
7817 lock_ReleaseMutex(&fidp->mx);
7818 smb_ReleaseFID(fidp);
7819 return CM_ERROR_BADFD;
7822 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7823 lock_ReleaseMutex(&fidp->mx);
7824 smb_CloseFID(vcp, fidp, NULL, 0);
7825 smb_ReleaseFID(fidp);
7826 return CM_ERROR_NOSUCHFILE;
7831 lock_ReleaseMutex(&fidp->mx);
7836 LARGE_INTEGER LOffset;
7837 LARGE_INTEGER LLength;
7840 key = cm_GenerateKey(vcp->vcID, pid, fd);
7842 LOffset.HighPart = offset.HighPart;
7843 LOffset.LowPart = offset.LowPart;
7844 LLength.HighPart = 0;
7845 LLength.LowPart = count;
7847 lock_ObtainWrite(&scp->rw);
7848 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7849 lock_ReleaseWrite(&scp->rw);
7852 cm_ReleaseSCache(scp);
7853 smb_ReleaseFID(fidp);
7858 userp = smb_GetUserFromVCP(vcp, inp);
7861 * Work around bug in NT client
7863 * When copying a file, the NT client should first copy the data,
7864 * then copy the last write time. But sometimes the NT client does
7865 * these in the wrong order, so the data copies would inadvertently
7866 * cause the last write time to be overwritten. We try to detect this,
7867 * and don't set client mod time if we think that would go against the
7870 lock_ObtainMutex(&fidp->mx);
7871 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7872 lock_ObtainWrite(&fidp->scp->rw);
7873 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7874 fidp->scp->clientModTime = time(NULL);
7875 lock_ReleaseWrite(&fidp->scp->rw);
7877 lock_ReleaseMutex(&fidp->mx);
7880 while ( code == 0 && count > 0 ) {
7881 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7882 if (code == 0 && written == 0)
7883 code = CM_ERROR_PARTIALWRITE;
7885 offset = LargeIntegerAdd(offset,
7886 ConvertLongToLargeInteger(written));
7889 total_written += written;
7893 /* Get a raw buffer */
7896 lock_ObtainMutex(&smb_RawBufLock);
7898 /* Get a raw buf, from head of list */
7899 rawBuf = smb_RawBufs;
7900 smb_RawBufs = *(char **)smb_RawBufs;
7903 code = CM_ERROR_USESTD;
7905 lock_ReleaseMutex(&smb_RawBufLock);
7908 /* Don't allow a premature Close */
7909 if (code == 0 && (writeMode & 1) == 0) {
7910 lock_ObtainMutex(&fidp->mx);
7911 fidp->raw_writers++;
7912 thrd_ResetEvent(fidp->raw_write_event);
7913 lock_ReleaseMutex(&fidp->mx);
7916 smb_ReleaseFID(fidp);
7917 cm_ReleaseUser(userp);
7918 cm_ReleaseSCache(scp);
7921 smb_SetSMBParm(outp, 0, total_written);
7922 smb_SetSMBDataLength(outp, 0);
7923 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7928 offset = LargeIntegerAdd(offset,
7929 ConvertLongToLargeInteger(count));
7933 rwcp->offset.HighPart = offset.HighPart;
7934 rwcp->offset.LowPart = offset.LowPart;
7935 rwcp->count = totalCount - count;
7936 rwcp->writeMode = writeMode;
7937 rwcp->alreadyWritten = total_written;
7939 /* set the packet data length to 3 bytes for the data block header,
7940 * plus the size of the data.
7942 smb_SetSMBParm(outp, 0, 0xffff);
7943 smb_SetSMBDataLength(outp, 0);
7949 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7952 long count, finalCount;
7956 smb_t *smbp = (smb_t*) inp;
7962 fd = smb_GetSMBParm(inp, 0);
7963 count = smb_GetSMBParm(inp, 1);
7964 offset.HighPart = 0; /* too bad */
7965 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7967 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7968 fd, offset.LowPart, count);
7970 fd = smb_ChainFID(fd, inp);
7971 fidp = smb_FindFID(vcp, fd, 0);
7973 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7975 return CM_ERROR_BADFD;
7977 lock_ObtainMutex(&fidp->mx);
7978 if (fidp->flags & SMB_FID_IOCTL) {
7979 lock_ReleaseMutex(&fidp->mx);
7980 code = smb_IoctlRead(fidp, vcp, inp, outp);
7981 smb_ReleaseFID(fidp);
7985 if (fidp->flags & SMB_FID_RPC) {
7986 lock_ReleaseMutex(&fidp->mx);
7987 code = smb_RPCRead(fidp, vcp, inp, outp);
7988 smb_ReleaseFID(fidp);
7993 lock_ReleaseMutex(&fidp->mx);
7994 smb_ReleaseFID(fidp);
7995 return CM_ERROR_BADFD;
7998 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7999 lock_ReleaseMutex(&fidp->mx);
8000 smb_CloseFID(vcp, fidp, NULL, 0);
8001 smb_ReleaseFID(fidp);
8002 return CM_ERROR_NOSUCHFILE;
8007 lock_ReleaseMutex(&fidp->mx);
8010 LARGE_INTEGER LOffset, LLength;
8014 key = cm_GenerateKey(vcp->vcID, pid, fd);
8016 LOffset.HighPart = 0;
8017 LOffset.LowPart = offset.LowPart;
8018 LLength.HighPart = 0;
8019 LLength.LowPart = count;
8021 lock_ObtainWrite(&scp->rw);
8022 code = cm_LockCheckRead(scp, LOffset, LLength, key);
8023 lock_ReleaseWrite(&scp->rw);
8026 cm_ReleaseSCache(scp);
8027 smb_ReleaseFID(fidp);
8031 userp = smb_GetUserFromVCP(vcp, inp);
8033 /* remember this for final results */
8034 smb_SetSMBParm(outp, 0, count);
8035 smb_SetSMBParm(outp, 1, 0);
8036 smb_SetSMBParm(outp, 2, 0);
8037 smb_SetSMBParm(outp, 3, 0);
8038 smb_SetSMBParm(outp, 4, 0);
8040 /* set the packet data length to 3 bytes for the data block header,
8041 * plus the size of the data.
8043 smb_SetSMBDataLength(outp, count+3);
8045 /* get op ptr after putting in the parms, since otherwise we don't
8046 * know where the data really is.
8048 op = smb_GetSMBData(outp, NULL);
8050 /* now emit the data block header: 1 byte of type and 2 bytes of length */
8051 *op++ = 1; /* data block marker */
8052 *op++ = (unsigned char) (count & 0xff);
8053 *op++ = (unsigned char) ((count >> 8) & 0xff);
8055 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8057 /* fix some things up */
8058 smb_SetSMBParm(outp, 0, finalCount);
8059 smb_SetSMBDataLength(outp, finalCount+3);
8061 smb_ReleaseFID(fidp);
8063 cm_ReleaseUser(userp);
8064 cm_ReleaseSCache(scp);
8068 /* SMB_COM_CREATE_DIRECTORY */
8069 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8071 clientchar_t *pathp;
8076 cm_scache_t *dscp; /* dir we're dealing with */
8077 cm_scache_t *scp; /* file we're creating */
8079 int initialModeBits;
8080 clientchar_t *lastNamep;
8082 clientchar_t *tidPathp;
8089 /* compute initial mode bits based on read-only flag in attributes */
8090 initialModeBits = 0777;
8092 tp = smb_GetSMBData(inp, NULL);
8093 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8095 return CM_ERROR_BADSMB;
8097 spacep = inp->spacep;
8098 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8100 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8101 return CM_ERROR_EXISTS;
8103 userp = smb_GetUserFromVCP(vcp, inp);
8105 caseFold = CM_FLAG_CASEFOLD;
8107 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8109 cm_ReleaseUser(userp);
8110 return CM_ERROR_NOSUCHPATH;
8113 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
8114 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8115 userp, tidPathp, &req, &dscp);
8118 cm_ReleaseUser(userp);
8123 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8124 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8125 cm_ReleaseSCache(dscp);
8126 cm_ReleaseUser(userp);
8127 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8128 return CM_ERROR_PATH_NOT_COVERED;
8130 return CM_ERROR_NOSUCHPATH;
8132 #endif /* DFS_SUPPORT */
8134 /* otherwise, scp points to the parent directory. Do a lookup, and
8135 * fail if we find it. Otherwise, we do the create.
8141 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8142 if (scp) cm_ReleaseSCache(scp);
8143 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8144 if (code == 0) code = CM_ERROR_EXISTS;
8145 cm_ReleaseSCache(dscp);
8146 cm_ReleaseUser(userp);
8150 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8151 setAttr.clientModTime = time(NULL);
8152 smb_SetInitialModeBitsForDir(0, &setAttr);
8154 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8155 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8156 smb_NotifyChange(FILE_ACTION_ADDED,
8157 FILE_NOTIFY_CHANGE_DIR_NAME,
8158 dscp, lastNamep, NULL, TRUE);
8160 /* we don't need this any longer */
8161 cm_ReleaseSCache(dscp);
8164 /* something went wrong creating or truncating the file */
8165 cm_ReleaseUser(userp);
8169 /* otherwise we succeeded */
8170 smb_SetSMBDataLength(outp, 0);
8171 cm_ReleaseUser(userp);
8176 BOOL smb_IsLegalFilename(clientchar_t *filename)
8179 * Find the longest substring of filename that does not contain
8180 * any of the chars in illegalChars. If that substring is less
8181 * than the length of the whole string, then one or more of the
8182 * illegal chars is in filename.
8184 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8190 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8191 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8193 clientchar_t *pathp;
8199 cm_scache_t *dscp; /* dir we're dealing with */
8200 cm_scache_t *scp; /* file we're creating */
8204 clientchar_t *lastNamep;
8207 clientchar_t *tidPathp;
8209 int created = 0; /* the file was new */
8214 excl = (inp->inCom == 0x03)? 0 : 1;
8216 attributes = smb_GetSMBParm(inp, 0);
8217 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8219 tp = smb_GetSMBData(inp, NULL);
8220 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8222 return CM_ERROR_BADSMB;
8224 spacep = inp->spacep;
8225 /* smb_StripLastComponent will strip "::$DATA" if present */
8226 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8228 if (!cm_IsValidClientString(pathp)) {
8230 clientchar_t * hexp;
8232 hexp = cm_GetRawCharsAlloc(pathp, -1);
8233 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8234 osi_LogSaveClientString(smb_logp, hexp));
8238 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8240 return CM_ERROR_BADNTFILENAME;
8243 userp = smb_GetUserFromVCP(vcp, inp);
8245 caseFold = CM_FLAG_CASEFOLD;
8247 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8249 cm_ReleaseUser(userp);
8250 return CM_ERROR_NOSUCHPATH;
8252 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8253 userp, tidPathp, &req, &dscp);
8256 cm_ReleaseUser(userp);
8261 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8262 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8263 cm_ReleaseSCache(dscp);
8264 cm_ReleaseUser(userp);
8265 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8266 return CM_ERROR_PATH_NOT_COVERED;
8268 return CM_ERROR_NOSUCHPATH;
8270 #endif /* DFS_SUPPORT */
8272 /* otherwise, scp points to the parent directory. Do a lookup, and
8273 * truncate the file if we find it, otherwise we create the file.
8280 if (!smb_IsLegalFilename(lastNamep))
8281 return CM_ERROR_BADNTFILENAME;
8283 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8284 #ifdef DEBUG_VERBOSE
8287 hexp = osi_HexifyString( lastNamep );
8288 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8293 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8294 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8295 cm_ReleaseSCache(dscp);
8296 cm_ReleaseUser(userp);
8300 /* if we get here, if code is 0, the file exists and is represented by
8301 * scp. Otherwise, we have to create it.
8305 /* oops, file shouldn't be there */
8306 cm_ReleaseSCache(dscp);
8307 cm_ReleaseSCache(scp);
8308 cm_ReleaseUser(userp);
8309 return CM_ERROR_EXISTS;
8312 setAttr.mask = CM_ATTRMASK_LENGTH;
8313 setAttr.length.LowPart = 0;
8314 setAttr.length.HighPart = 0;
8315 code = cm_SetAttr(scp, &setAttr, userp, &req);
8318 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8319 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8320 smb_SetInitialModeBitsForFile(attributes, &setAttr);
8322 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8326 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8327 smb_NotifyChange(FILE_ACTION_ADDED,
8328 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8329 dscp, lastNamep, NULL, TRUE);
8330 } else if (!excl && code == CM_ERROR_EXISTS) {
8331 /* not an exclusive create, and someone else tried
8332 * creating it already, then we open it anyway. We
8333 * don't bother retrying after this, since if this next
8334 * fails, that means that the file was deleted after
8335 * we started this call.
8337 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8340 setAttr.mask = CM_ATTRMASK_LENGTH;
8341 setAttr.length.LowPart = 0;
8342 setAttr.length.HighPart = 0;
8343 code = cm_SetAttr(scp, &setAttr, userp, &req);
8348 /* we don't need this any longer */
8349 cm_ReleaseSCache(dscp);
8352 /* something went wrong creating or truncating the file */
8353 if (scp) cm_ReleaseSCache(scp);
8354 cm_ReleaseUser(userp);
8358 /* make sure we only open files */
8359 if (scp->fileType != CM_SCACHETYPE_FILE) {
8360 cm_ReleaseSCache(scp);
8361 cm_ReleaseUser(userp);
8362 return CM_ERROR_ISDIR;
8365 /* now all we have to do is open the file itself */
8366 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8367 osi_assertx(fidp, "null smb_fid_t");
8371 lock_ObtainMutex(&fidp->mx);
8372 /* always create it open for read/write */
8373 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8375 /* remember that the file was newly created */
8377 fidp->flags |= SMB_FID_CREATED;
8379 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8381 /* save a pointer to the vnode */
8383 lock_ObtainWrite(&scp->rw);
8384 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8385 lock_ReleaseWrite(&scp->rw);
8388 fidp->userp = userp;
8389 lock_ReleaseMutex(&fidp->mx);
8391 smb_SetSMBParm(outp, 0, fidp->fid);
8392 smb_SetSMBDataLength(outp, 0);
8394 cm_Open(scp, 0, userp);
8396 smb_ReleaseFID(fidp);
8397 cm_ReleaseUser(userp);
8398 /* leave scp held since we put it in fidp->scp */
8403 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8406 osi_hyper_t new_offset;
8417 fd = smb_GetSMBParm(inp, 0);
8418 whence = smb_GetSMBParm(inp, 1);
8419 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8421 /* try to find the file descriptor */
8422 fd = smb_ChainFID(fd, inp);
8423 fidp = smb_FindFID(vcp, fd, 0);
8425 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8427 return CM_ERROR_BADFD;
8429 lock_ObtainMutex(&fidp->mx);
8430 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8431 lock_ReleaseMutex(&fidp->mx);
8432 smb_ReleaseFID(fidp);
8433 return CM_ERROR_BADFD;
8436 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8437 lock_ReleaseMutex(&fidp->mx);
8438 smb_CloseFID(vcp, fidp, NULL, 0);
8439 smb_ReleaseFID(fidp);
8440 return CM_ERROR_NOSUCHFILE;
8443 lock_ReleaseMutex(&fidp->mx);
8445 userp = smb_GetUserFromVCP(vcp, inp);
8447 lock_ObtainMutex(&fidp->mx);
8450 lock_ReleaseMutex(&fidp->mx);
8451 lock_ObtainWrite(&scp->rw);
8452 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8453 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8455 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8457 /* offset from current offset */
8458 new_offset = LargeIntegerAdd(fidp->offset,
8459 ConvertLongToLargeInteger(offset));
8461 else if (whence == 2) {
8462 /* offset from current EOF */
8463 new_offset = LargeIntegerAdd(scp->length,
8464 ConvertLongToLargeInteger(offset));
8466 new_offset = ConvertLongToLargeInteger(offset);
8469 fidp->offset = new_offset;
8470 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8471 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8472 smb_SetSMBDataLength(outp, 0);
8474 lock_ReleaseWrite(&scp->rw);
8475 smb_ReleaseFID(fidp);
8476 cm_ReleaseSCache(scp);
8477 cm_ReleaseUser(userp);
8481 /* dispatch all of the requests received in a packet. Due to chaining, this may
8482 * be more than one request.
8484 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8485 NCB *ncbp, raw_write_cont_t *rwcp)
8489 unsigned long code = 0;
8490 unsigned char *outWctp;
8491 int nparms; /* # of bytes of parameters */
8493 int nbytes; /* bytes of data, excluding count */
8496 unsigned short errCode;
8497 unsigned long NTStatus;
8499 unsigned char errClass;
8500 unsigned int oldGen;
8501 DWORD oldTime, newTime;
8503 /* get easy pointer to the data */
8504 smbp = (smb_t *) inp->data;
8506 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8507 /* setup the basic parms for the initial request in the packet */
8508 inp->inCom = smbp->com;
8509 inp->wctp = &smbp->wct;
8511 inp->ncb_length = ncbp->ncb_length;
8516 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8517 /* log it and discard it */
8518 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8519 __FILE__, __LINE__, ncbp->ncb_length);
8520 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8524 /* We are an ongoing op */
8525 thrd_Increment(&ongoingOps);
8527 /* set up response packet for receiving output */
8528 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8529 smb_FormatResponsePacket(vcp, inp, outp);
8530 outWctp = outp->wctp;
8532 /* Remember session generation number and time */
8533 oldGen = sessionGen;
8534 oldTime = GetTickCount();
8536 while (inp->inCom != 0xff) {
8537 dp = &smb_dispatchTable[inp->inCom];
8539 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8540 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8541 code = outp->resumeCode;
8545 /* process each request in the packet; inCom, wctp and inCount
8546 * are already set up.
8548 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8551 /* now do the dispatch */
8552 /* start by formatting the response record a little, as a default */
8553 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8555 outWctp[1] = 0xff; /* no operation */
8556 outWctp[2] = 0; /* padding */
8561 /* not a chained request, this is a more reasonable default */
8562 outWctp[0] = 0; /* wct of zero */
8563 outWctp[1] = 0; /* and bcc (word) of zero */
8567 /* once set, stays set. Doesn't matter, since we never chain
8568 * "no response" calls.
8570 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8574 /* we have a recognized operation */
8575 char * opName = myCrt_Dispatch(inp->inCom);
8578 smbp = (smb_t *) inp;
8580 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8581 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8582 if (inp->inCom == 0x1d) {
8584 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8586 code = (*(dp->procp)) (vcp, inp, outp);
8588 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8589 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8591 newTime = GetTickCount();
8592 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8593 opName, smbp->mid, newTime - oldTime);
8596 if ( code == CM_ERROR_BADSMB ||
8597 code == CM_ERROR_BADOP )
8599 #endif /* LOG_PACKET */
8601 /* ReceiveV3Tran2A handles its own logging */
8602 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8605 clientchar_t *treepath = NULL; /* do not free */
8606 clientchar_t *pathname = NULL;
8607 cm_fid_t afid = {0,0,0,0,0};
8609 uidp = smb_FindUID(vcp, smbp->uid, 0);
8610 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8611 fidp = smb_FindFID(vcp, inp->fid, 0);
8614 lock_ObtainMutex(&fidp->mx);
8615 if (fidp->NTopen_pathp)
8616 pathname = fidp->NTopen_pathp;
8618 afid = fidp->scp->fid;
8620 if (inp->stringsp->wdata)
8621 pathname = inp->stringsp->wdata;
8624 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)",
8625 opName, newTime - oldTime,
8626 smbp->uid, uidp ? uidp->unp->name : NULL,
8627 smbp->pid, smbp->mid, smbp->tid,
8630 afid.cell, afid.volume, afid.vnode, afid.unique);
8633 lock_ReleaseMutex(&fidp->mx);
8636 smb_ReleaseUID(uidp);
8638 smb_ReleaseFID(fidp);
8641 if (oldGen != sessionGen) {
8642 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8643 newTime - oldTime, ncbp->ncb_length);
8644 osi_Log3(smb_logp, "Request %s straddled session startup, "
8645 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8648 FreeSMBStrings(inp);
8650 /* bad opcode, fail the request, after displaying it */
8651 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8654 #endif /* LOG_PACKET */
8657 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8658 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8659 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8660 if (code == IDCANCEL)
8663 code = CM_ERROR_BADOP;
8666 /* catastrophic failure: log as much as possible */
8667 if (code == CM_ERROR_BADSMB) {
8668 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8672 #endif /* LOG_PACKET */
8673 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8676 code = CM_ERROR_INVAL;
8679 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8680 thrd_Decrement(&ongoingOps);
8685 /* now, if we failed, turn the current response into an empty
8686 * one, and fill in the response packet's error code.
8689 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8690 smb_MapNTError(code, &NTStatus);
8691 outWctp = outp->wctp;
8692 smbp = (smb_t *) &outp->data;
8693 if (code != CM_ERROR_PARTIALWRITE
8694 && code != CM_ERROR_BUFFERTOOSMALL
8695 && code != CM_ERROR_GSSCONTINUE) {
8696 /* nuke wct and bcc. For a partial
8697 * write or an in-process authentication handshake,
8698 * assume they're OK.
8704 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8705 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8706 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8707 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8708 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8712 smb_MapCoreError(code, vcp, &errCode, &errClass);
8713 outWctp = outp->wctp;
8714 smbp = (smb_t *) &outp->data;
8715 if (code != CM_ERROR_PARTIALWRITE) {
8716 /* nuke wct and bcc. For a partial
8717 * write, assume they're OK.
8723 smbp->errLow = (unsigned char) (errCode & 0xff);
8724 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8725 smbp->rcls = errClass;
8728 } /* error occurred */
8730 /* if we're here, we've finished one request. Look to see if
8731 * this is a chained opcode. If it is, setup things to process
8732 * the chained request, and setup the output buffer to hold the
8733 * chained response. Start by finding the next input record.
8735 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8736 break; /* not a chained req */
8737 tp = inp->wctp; /* points to start of last request */
8738 /* in a chained request, the first two
8739 * parm fields are required, and are
8740 * AndXCommand/AndXReserved and
8742 if (tp[0] < 2) break;
8743 if (tp[1] == 0xff) break; /* no more chained opcodes */
8745 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8748 /* and now append the next output request to the end of this
8749 * last request. Begin by finding out where the last response
8750 * ends, since that's where we'll put our new response.
8752 outWctp = outp->wctp; /* ptr to out parameters */
8753 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8754 nparms = outWctp[0] << 1;
8755 tp = outWctp + nparms + 1; /* now points to bcc field */
8756 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8757 tp += 2 /* for the count itself */ + nbytes;
8758 /* tp now points to the new output record; go back and patch the
8759 * second parameter (off2) to point to the new record.
8761 temp = (unsigned int)(tp - outp->data);
8762 outWctp[3] = (unsigned char) (temp & 0xff);
8763 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8764 outWctp[2] = 0; /* padding */
8765 outWctp[1] = inp->inCom; /* next opcode */
8767 /* finally, setup for the next iteration */
8770 } /* while loop over all requests in the packet */
8772 /* now send the output packet, and return */
8774 smb_SendPacket(vcp, outp);
8775 thrd_Decrement(&ongoingOps);
8780 /* Wait for Netbios() calls to return, and make the results available to server
8781 * threads. Note that server threads can't wait on the NCBevents array
8782 * themselves, because NCB events are manual-reset, and the servers would race
8783 * each other to reset them.
8785 void smb_ClientWaiter(void *parmp)
8790 while (smbShutdownFlag == 0) {
8791 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8793 if (code == WAIT_OBJECT_0)
8796 /* error checking */
8797 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8799 int abandonIdx = code - WAIT_ABANDONED_0;
8800 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8803 if (code == WAIT_IO_COMPLETION)
8805 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8809 if (code == WAIT_TIMEOUT)
8811 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8814 if (code == WAIT_FAILED)
8816 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8819 idx = code - WAIT_OBJECT_0;
8821 /* check idx range! */
8822 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8824 /* this is fatal - log as much as possible */
8825 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8826 osi_assertx(0, "invalid index");
8829 thrd_ResetEvent(NCBevents[idx]);
8830 thrd_SetEvent(NCBreturns[0][idx]);
8835 * Try to have one NCBRECV request waiting for every live session. Not more
8836 * than one, because if there is more than one, it's hard to handle Write Raw.
8838 void smb_ServerWaiter(void *parmp)
8841 int idx_session, idx_NCB;
8844 while (smbShutdownFlag == 0) {
8846 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8848 if (code == WAIT_OBJECT_0)
8851 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8853 int abandonIdx = code - WAIT_ABANDONED_0;
8854 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8857 if (code == WAIT_IO_COMPLETION)
8859 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8863 if (code == WAIT_TIMEOUT)
8865 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8868 if (code == WAIT_FAILED)
8870 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8873 idx_session = code - WAIT_OBJECT_0;
8875 /* check idx range! */
8876 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8878 /* this is fatal - log as much as possible */
8879 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8880 osi_assertx(0, "invalid index");
8885 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8887 if (code == WAIT_OBJECT_0) {
8888 if (smbShutdownFlag == 1)
8894 /* error checking */
8895 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8897 int abandonIdx = code - WAIT_ABANDONED_0;
8898 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8901 if (code == WAIT_IO_COMPLETION)
8903 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8907 if (code == WAIT_TIMEOUT)
8909 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8912 if (code == WAIT_FAILED)
8914 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8917 idx_NCB = code - WAIT_OBJECT_0;
8919 /* check idx range! */
8920 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8922 /* this is fatal - log as much as possible */
8923 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8924 osi_assertx(0, "invalid index");
8927 /* Link them together */
8928 NCBsessions[idx_NCB] = idx_session;
8931 ncbp = NCBs[idx_NCB];
8932 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8933 ncbp->ncb_command = NCBRECV | ASYNCH;
8934 ncbp->ncb_lana_num = lanas[idx_session];
8935 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8936 ncbp->ncb_event = NCBevents[idx_NCB];
8937 ncbp->ncb_length = SMB_PACKETSIZE;
8942 typedef struct _monitored_task {
8945 LARGE_INTEGER start_time;
8947 BOOL trace_timer_hit;
8948 BOOL dump_timer_hit;
8951 typedef struct osi_queueHT {
8952 osi_queue_t * headp;
8953 osi_queue_t * tailp;
8956 static osi_queue_t *smb_monitored_tasks = NULL;
8957 static osi_queue_t *smb_free_monitored_tasks = NULL;
8959 static osi_mutex_t _monitor_mx;
8961 static HANDLE h_monitored_task_queue = NULL;
8962 static HANDLE h_monitored_task_shutdown = NULL;
8964 static time_t smb_last_dump_time = 0;
8966 DWORD smb_monitorReqs = 0;
8968 /* FILETIME comparison fuzz */
8969 #define MONITOR_FUZZ_TIMEOUT (1 * 10000000i64)
8971 /* Trace timeout is at 60 seconds */
8972 #define MONITOR_TRACE_TIMEOUT (60 * 10000000i64)
8974 /* Dump timeout is at 120 seconds */
8975 #define MONITOR_DUMP_TIMEOUT (120 * 10000000i64)
8977 /* Time before another dump is performed in seconds*/
8978 #define MONITOR_DUMP_RESET_TIMEOUT (600)
8980 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
8983 LARGE_INTEGER earliest;
8986 GetSystemTimeAsFileTime(&now);
8987 earliest.LowPart = now.dwLowDateTime;
8988 earliest.HighPart = now.dwHighDateTime;
8989 earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
8991 while ((t = (monitored_task *) taskmq->headp) != NULL &&
8993 (t->start_time.QuadPart < earliest.QuadPart ||
8995 t->dump_timer_hit)) {
8997 osi_QRemoveHT(&taskmq->headp,
9001 lock_ObtainMutex(&_monitor_mx);
9002 osi_QAdd(&smb_free_monitored_tasks, &t->q);
9003 lock_ReleaseMutex(&_monitor_mx);
9006 #ifdef INVARIANT_CHECK
9012 for (t = (monitored_task *) taskmq->headp;
9014 t = (monitored_task *) osi_QNext(&t->q)) {
9015 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9016 last.QuadPart = t->start_time.QuadPart;
9022 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
9024 monitored_task * task;
9025 monitored_task * tasks;
9027 lock_ObtainMutex(&_monitor_mx);
9028 tasks = (monitored_task *) smb_monitored_tasks;
9029 smb_monitored_tasks = NULL;
9030 lock_ReleaseMutex(&_monitor_mx);
9035 osi_QRemove((osi_queue_t **) &tasks, &task->q);
9037 if (task->started) {
9043 q.prevp = taskmq->tailp;
9045 /* Insertion sort by start_time. Earliest request is
9046 first. Since we are likely to receive new requests
9047 later, we start inserting from the back. */
9050 ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
9054 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
9055 else if (p->prevp == NULL)
9056 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
9058 osi_queue_t *o = p->prevp;
9060 osi_assert(o->nextp == p);
9064 p->prevp = &task->q;
9065 o->nextp = &task->q;
9069 /* Some task ending */
9073 for (p = taskmq->headp;
9077 monitored_task * mt = (monitored_task *) p;
9079 if (mt->task_id == task->task_id) {
9081 osi_QRemoveHT(&taskmq->headp,
9084 lock_ObtainMutex(&_monitor_mx);
9085 osi_QAdd(&smb_free_monitored_tasks, p);
9086 lock_ReleaseMutex(&_monitor_mx);
9092 lock_ObtainMutex(&_monitor_mx);
9093 osi_QAdd(&smb_free_monitored_tasks, &task->q);
9094 lock_ReleaseMutex(&_monitor_mx);
9098 #ifdef INVARIANT_CHECK
9105 for (t = (monitored_task *) taskmq->headp;
9107 t = (monitored_task *) osi_QNext(&t->q)) {
9108 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9109 last.QuadPart = t->start_time.QuadPart;
9115 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9117 if (!task->trace_timer_hit) {
9119 task->trace_timer_hit = TRUE;
9121 osi_LogEnable(afsd_logp);
9122 rx_DebugOnOff(TRUE);
9124 } else if (!task->dump_timer_hit) {
9129 if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9130 task->dump_timer_hit = TRUE;
9131 smb_last_dump_time = now;
9133 GenerateMiniDump(NULL);
9139 * Server request monitoring
9141 * The server monitor runs in a separate thread and monitors server
9142 * requests for potential timeouts. It examines notifcations queued
9143 * by smb_NotifyRequestEvent() and waits for potential timeout events:
9145 * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9146 * enables trace logging.
9148 * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9149 * out a dump file that will hopefully contain enough evidence to
9150 * figure out why the timeout event occurred.
9153 void smb_ServerMonitor(VOID * parmp)
9155 osi_queueHT_t in_progress = { NULL, NULL };
9156 HANDLE h_timer = NULL;
9160 h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9161 h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9162 h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9164 lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9166 h_all[0] = h_monitored_task_queue;
9168 h_all[2] = h_monitored_task_shutdown;
9173 rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9175 if (rv == WAIT_OBJECT_0) {
9177 smb_SlurpNewTaskMonitors(&in_progress);
9179 } else if (rv == WAIT_OBJECT_0 + 1) {
9181 smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9189 /* refresh timers */
9193 smb_PurgeOldTaskMonitors(&in_progress);
9194 t = (monitored_task *) in_progress.headp;
9196 if (t && !t->trace_timer_hit) {
9199 due = t->start_time;
9200 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9202 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9203 } else if (t && !t->dump_timer_hit) {
9207 due = t->start_time;
9208 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9210 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9212 CancelWaitableTimer(h_timer);
9214 /* CancelWaitableTimer() doesn't reset the timer if it
9215 was already signalled. */
9216 WaitForSingleObject(h_timer, 0);
9224 h = h_monitored_task_queue;
9225 h_monitored_task_queue = NULL;
9228 h = h_monitored_task_shutdown;
9229 h_monitored_task_shutdown = NULL;
9232 CloseHandle(h_timer);
9234 lock_FinalizeMutex(&_monitor_mx);
9238 monitored_task * task;
9240 while (in_progress.headp) {
9241 task = (monitored_task *) in_progress.headp;
9242 osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9246 for (task = (monitored_task *) smb_free_monitored_tasks;
9247 task; task = (monitored_task *) smb_free_monitored_tasks) {
9248 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9252 for (task = (monitored_task *) smb_monitored_tasks;
9253 task; task = (monitored_task *) smb_monitored_tasks) {
9254 osi_QRemove(&smb_monitored_tasks, &task->q);
9260 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9262 monitored_task * task;
9264 lock_ObtainMutex(&_monitor_mx);
9265 task = (monitored_task *) smb_free_monitored_tasks;
9267 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9268 lock_ReleaseMutex(&_monitor_mx);
9271 task = malloc(sizeof(monitored_task));
9272 memset(task, 0, sizeof(*task));
9274 task->task_id = task_id;
9275 task->started = started;
9280 GetSystemTimeAsFileTime(&now);
9281 task->start_time.HighPart = now.dwHighDateTime;
9282 task->start_time.LowPart = now.dwLowDateTime;
9285 lock_ObtainMutex(&_monitor_mx);
9286 osi_QAdd(&smb_monitored_tasks, &task->q);
9287 lock_ReleaseMutex(&_monitor_mx);
9289 SetEvent(h_monitored_task_queue);
9292 void smb_ShutdownMonitor()
9294 SetEvent(h_monitored_task_shutdown);
9298 * The top level loop for handling SMB request messages. Each server thread
9299 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9300 * NCB and buffer for the incoming request are loaned to us.
9302 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
9303 * to immediately send a request for the rest of the data. This must come
9304 * before any other traffic for that session, so we delay setting the session
9305 * event until that data has come in.
9307 void smb_Server(VOID *parmp)
9309 INT_PTR myIdx = (INT_PTR) parmp;
9313 smb_packet_t *outbufp;
9315 int idx_NCB, idx_session;
9317 smb_vc_t *vcp = NULL;
9320 rx_StartClientThread();
9322 outncbp = smb_GetNCB();
9323 outbufp = smb_GetPacket();
9324 outbufp->ncbp = outncbp;
9332 cm_ResetServerPriority();
9334 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9337 /* terminate silently if shutdown flag is set */
9338 if (code == WAIT_OBJECT_0) {
9339 if (smbShutdownFlag == 1) {
9340 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9346 /* error checking */
9347 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9349 int abandonIdx = code - WAIT_ABANDONED_0;
9350 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9353 if (code == WAIT_IO_COMPLETION)
9355 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9359 if (code == WAIT_TIMEOUT)
9361 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9364 if (code == WAIT_FAILED)
9366 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9369 idx_NCB = code - WAIT_OBJECT_0;
9371 /* check idx range! */
9372 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9374 /* this is fatal - log as much as possible */
9375 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9376 osi_assertx(0, "invalid index");
9379 ncbp = NCBs[idx_NCB];
9380 idx_session = NCBsessions[idx_NCB];
9381 rc = ncbp->ncb_retcode;
9383 if (rc != NRC_PENDING && rc != NRC_GOODRET)
9384 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9388 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9392 /* Can this happen? Or is it just my UNIX paranoia? */
9393 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9398 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9401 /* Client closed session */
9402 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9404 lock_ObtainMutex(&vcp->mx);
9405 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9406 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9408 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9409 lock_ReleaseMutex(&vcp->mx);
9410 lock_ObtainWrite(&smb_globalLock);
9411 dead_sessions[vcp->session] = TRUE;
9412 lock_ReleaseWrite(&smb_globalLock);
9414 lock_ReleaseMutex(&vcp->mx);
9416 smb_CleanupDeadVC(vcp);
9423 /* Treat as transient error */
9424 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9427 "dispatch smb recv failed, message incomplete, ncb_length %d",
9430 "SMB message incomplete, "
9431 "length %d", ncbp->ncb_length);
9434 * We used to discard the packet.
9435 * Instead, try handling it normally.
9439 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9443 /* A weird error code. Log it, sleep, and continue. */
9444 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9446 lock_ObtainMutex(&vcp->mx);
9447 if (vcp->errorCount++ > 3) {
9448 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9449 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9450 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9452 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9453 lock_ReleaseMutex(&vcp->mx);
9454 lock_ObtainWrite(&smb_globalLock);
9455 dead_sessions[vcp->session] = TRUE;
9456 lock_ReleaseWrite(&smb_globalLock);
9458 lock_ReleaseMutex(&vcp->mx);
9460 smb_CleanupDeadVC(vcp);
9466 lock_ReleaseMutex(&vcp->mx);
9470 thrd_SetEvent(SessionEvents[idx_session]);
9476 /* Success, so now dispatch on all the data in the packet */
9478 smb_concurrentCalls++;
9479 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9480 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9483 * If at this point vcp is NULL (implies that packet was invalid)
9484 * then we are in big trouble. This means either :
9485 * a) we have the wrong NCB.
9486 * b) Netbios screwed up the call.
9487 * c) The VC was already marked dead before we were able to
9489 * Obviously this implies that
9490 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9491 * lanas[idx_session] != ncbp->ncb_lana_num )
9492 * Either way, we can't do anything with this packet.
9493 * Log, sleep and resume.
9496 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9500 ncbp->ncb_lana_num);
9502 /* Also log in the trace log. */
9503 osi_Log4(smb_logp, "Server: VCP does not exist!"
9504 "LSNs[idx_session]=[%d],"
9505 "lanas[idx_session]=[%d],"
9506 "ncbp->ncb_lsn=[%d],"
9507 "ncbp->ncb_lana_num=[%d]",
9511 ncbp->ncb_lana_num);
9513 /* thrd_Sleep(1000); Don't bother sleeping */
9514 thrd_SetEvent(SessionEvents[idx_session]);
9515 smb_concurrentCalls--;
9519 cm_SetRequestStartTime();
9520 if (smb_monitorReqs) {
9521 smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9524 vcp->errorCount = 0;
9525 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9526 smbp = (smb_t *)bufp->data;
9533 if (smbp->com == 0x1d) {
9534 /* Special handling for Write Raw */
9535 raw_write_cont_t rwc;
9537 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9538 if (rwc.code == 0) {
9539 EVENT_HANDLE rwevent;
9540 char eventName[MAX_PATH];
9542 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9543 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9544 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9545 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9547 ncbp->ncb_command = NCBRECV | ASYNCH;
9548 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9549 ncbp->ncb_lana_num = vcp->lana;
9550 ncbp->ncb_buffer = rwc.buf;
9551 ncbp->ncb_length = 65535;
9552 ncbp->ncb_event = rwevent;
9554 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9555 thrd_CloseHandle(rwevent);
9557 thrd_SetEvent(SessionEvents[idx_session]);
9559 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9561 else if (smbp->com == 0xa0) {
9563 * Serialize the handling for NT Transact
9566 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9567 thrd_SetEvent(SessionEvents[idx_session]);
9569 thrd_SetEvent(SessionEvents[idx_session]);
9570 /* TODO: what else needs to be serialized? */
9571 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9575 __except( smb_ServerExceptionFilter() ) {
9579 if (smb_monitorReqs) {
9580 smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9582 smb_concurrentCalls--;
9585 thrd_SetEvent(NCBavails[idx_NCB]);
9590 smb_FreePacket(outbufp);
9592 smb_FreeNCB(outncbp);
9596 * Exception filter for the server threads. If an exception occurs in the
9597 * dispatch routines, which is where exceptions are most common, then do a
9598 * force trace and give control to upstream exception handlers. Useful for
9601 DWORD smb_ServerExceptionFilter(void) {
9602 /* While this is not the best time to do a trace, if it succeeds, then
9603 * we have a trace (assuming tracing was enabled). Otherwise, this should
9604 * throw a second exception.
9606 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9607 afsd_ForceTrace(TRUE);
9608 buf_ForceTrace(TRUE);
9609 return EXCEPTION_CONTINUE_SEARCH;
9613 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9614 * If the number of server threads is M, and the number of live sessions is
9615 * N, then the number of NCB's in use at any time either waiting for, or
9616 * holding, received messages is M + N, so that is how many NCB's get created.
9618 void InitNCBslot(int idx)
9620 struct smb_packet *bufp;
9621 EVENT_HANDLE retHandle;
9623 char eventName[MAX_PATH];
9625 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9627 NCBs[idx] = smb_GetNCB();
9628 sprintf(eventName,"NCBavails[%d]", idx);
9629 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9630 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9631 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9632 sprintf(eventName,"NCBevents[%d]", idx);
9633 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9634 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9635 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9636 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9637 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9638 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9639 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9640 for (i=0; i<smb_NumServerThreads; i++)
9641 NCBreturns[i][idx] = retHandle;
9642 bufp = smb_GetPacket();
9643 bufp->spacep = cm_GetSpace();
9647 /* listen for new connections */
9648 void smb_Listener(void *parmp)
9654 afs_uint32 session, thread;
9655 smb_vc_t *vcp = NULL;
9657 char rname[NCBNAMSZ+1];
9658 char cname[MAX_COMPUTERNAME_LENGTH+1];
9659 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9660 INT_PTR lana = (INT_PTR) parmp;
9661 char eventName[MAX_PATH];
9662 int bridgeCount = 0;
9663 int nowildCount = 0;
9665 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9666 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9667 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9668 thrd_ResetEvent(ListenerShutdown[lana]);
9670 ncbp = smb_GetNCB();
9672 /* retrieve computer name */
9673 GetComputerName(cname, &cnamelen);
9676 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9677 memset(ncbp, 0, sizeof(NCB));
9680 ncbp->ncb_command = NCBLISTEN;
9681 ncbp->ncb_rto = 0; /* No receive timeout */
9682 ncbp->ncb_sto = 0; /* No send timeout */
9684 /* pad out with spaces instead of null termination */
9685 len = (long)strlen(smb_localNamep);
9686 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9687 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9689 strcpy(ncbp->ncb_callname, "*");
9690 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9692 ncbp->ncb_lana_num = (UCHAR)lana;
9694 code = Netbios(ncbp);
9696 if (code == NRC_NAMERR) {
9697 /* An smb shutdown or Vista resume must have taken place */
9699 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9700 ncbp->ncb_lana_num);
9701 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9703 if (lock_TryMutex(&smb_StartedLock)) {
9704 lana_list.lana[i] = LANA_INVALID;
9705 lock_ReleaseMutex(&smb_StartedLock);
9708 } else if (code == NRC_BRIDGE || code != 0) {
9709 int lanaRemaining = 0;
9711 if (code == NRC_BRIDGE) {
9712 if (++bridgeCount <= 5) {
9713 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9716 } else if (code == NRC_NOWILD) {
9717 if (++nowildCount <= 5) {
9718 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9720 if (bridgeCount > 0) {
9721 memset(ncbp, 0, sizeof(*ncbp));
9722 ncbp->ncb_command = NCBADDNAME;
9723 ncbp->ncb_lana_num = (UCHAR)lana;
9724 /* pad out with spaces instead of null termination */
9725 len = (long)strlen(smb_localNamep);
9726 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9727 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9728 code = Netbios(ncbp);
9734 while (!lock_TryMutex(&smb_StartedLock)) {
9735 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9741 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9742 ncbp->ncb_lana_num, ncb_error_string(code));
9743 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9744 ncbp->ncb_lana_num, ncb_error_string(code));
9746 for (i = 0; i < lana_list.length; i++) {
9747 if (lana_list.lana[i] == lana) {
9748 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9749 lana_list.lana[i] = LANA_INVALID;
9751 if (lana_list.lana[i] != LANA_INVALID)
9755 if (lanaRemaining == 0) {
9756 cm_VolStatus_Network_Stopped(cm_NetbiosName
9761 smb_ListenerState = SMB_LISTENER_STOPPED;
9762 smb_LANadapter = LANA_INVALID;
9763 lana_list.length = 0;
9765 lock_ReleaseMutex(&smb_StartedLock);
9769 else if (code != 0) {
9770 char tbuffer[AFSPATHMAX];
9772 /* terminate silently if shutdown flag is set */
9773 while (!lock_TryMutex(&smb_StartedLock)) {
9774 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9780 "NCBLISTEN lana=%d failed with code %d [%s]",
9781 ncbp->ncb_lana_num, code, ncb_error_string(code));
9783 "Client exiting due to network failure. Please restart client.\n");
9786 "Client exiting due to network failure. Please restart client.\n"
9787 "NCBLISTEN lana=%d failed with code %d [%s]",
9788 ncbp->ncb_lana_num, code, ncb_error_string(code));
9790 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9791 MB_OK|MB_SERVICE_NOTIFICATION);
9792 osi_panic(tbuffer, __FILE__, __LINE__);
9794 lock_ReleaseMutex(&smb_StartedLock);
9799 /* a successful packet received. clear bridge error count */
9803 /* check for remote conns */
9804 /* first get remote name and insert null terminator */
9805 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9806 for (i=NCBNAMSZ; i>0; i--) {
9807 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9813 /* compare with local name */
9815 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9816 flags |= SMB_VCFLAG_REMOTECONN;
9819 lock_ObtainMutex(&smb_ListenerLock);
9821 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9822 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9824 /* now ncbp->ncb_lsn is the connection ID */
9825 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9826 if (vcp->session == 0) {
9827 /* New generation */
9828 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9831 /* Log session startup */
9833 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9834 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9835 #endif /* NOTSERVICE */
9836 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9837 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9839 if (reportSessionStartups) {
9840 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9843 lock_ObtainMutex(&vcp->mx);
9844 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9845 vcp->flags |= flags;
9846 lock_ReleaseMutex(&vcp->mx);
9848 /* Allocate slot in session arrays */
9849 /* Re-use dead session if possible, otherwise add one more */
9850 /* But don't look at session[0], it is reserved */
9851 lock_ObtainWrite(&smb_globalLock);
9852 for (session = 1; session < numSessions; session++) {
9853 if (dead_sessions[session]) {
9854 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9855 dead_sessions[session] = FALSE;
9859 lock_ReleaseWrite(&smb_globalLock);
9861 /* We are re-using an existing VC because the lsn and lana
9863 session = vcp->session;
9865 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9867 /* Log session startup */
9869 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9870 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9871 #endif /* NOTSERVICE */
9872 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9873 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9875 if (reportSessionStartups) {
9876 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9880 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9881 unsigned long code = CM_ERROR_ALLBUSY;
9882 smb_packet_t * outp = smb_GetPacket();
9883 unsigned char *outWctp;
9886 smb_FormatResponsePacket(vcp, NULL, outp);
9889 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9890 unsigned long NTStatus;
9891 smb_MapNTError(code, &NTStatus);
9892 outWctp = outp->wctp;
9893 smbp = (smb_t *) &outp->data;
9897 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9898 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9899 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9900 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9901 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9903 unsigned short errCode;
9904 unsigned char errClass;
9905 smb_MapCoreError(code, vcp, &errCode, &errClass);
9906 outWctp = outp->wctp;
9907 smbp = (smb_t *) &outp->data;
9911 smbp->errLow = (unsigned char) (errCode & 0xff);
9912 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9913 smbp->rcls = errClass;
9916 smb_SendPacket(vcp, outp);
9917 smb_FreePacket(outp);
9919 lock_ObtainMutex(&vcp->mx);
9920 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9921 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9923 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9924 lock_ReleaseMutex(&vcp->mx);
9925 lock_ObtainWrite(&smb_globalLock);
9926 dead_sessions[vcp->session] = TRUE;
9927 lock_ReleaseWrite(&smb_globalLock);
9928 smb_CleanupDeadVC(vcp);
9930 lock_ReleaseMutex(&vcp->mx);
9933 /* assert that we do not exceed the maximum number of sessions or NCBs.
9934 * we should probably want to wait for a session to be freed in case
9937 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9938 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9940 lock_ObtainMutex(&vcp->mx);
9941 vcp->session = session;
9942 lock_ReleaseMutex(&vcp->mx);
9943 lock_ObtainWrite(&smb_globalLock);
9944 LSNs[session] = ncbp->ncb_lsn;
9945 lanas[session] = ncbp->ncb_lana_num;
9946 lock_ReleaseWrite(&smb_globalLock);
9948 if (session == numSessions) {
9949 /* Add new NCB for new session */
9950 char eventName[MAX_PATH];
9952 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9954 InitNCBslot(numNCBs);
9955 lock_ObtainWrite(&smb_globalLock);
9957 lock_ReleaseWrite(&smb_globalLock);
9958 thrd_SetEvent(NCBavails[0]);
9959 thrd_SetEvent(NCBevents[0]);
9960 for (thread = 0; thread < smb_NumServerThreads; thread++)
9961 thrd_SetEvent(NCBreturns[thread][0]);
9962 /* Also add new session event */
9963 sprintf(eventName, "SessionEvents[%d]", session);
9964 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9965 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9966 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9967 lock_ObtainWrite(&smb_globalLock);
9969 lock_ReleaseWrite(&smb_globalLock);
9970 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9971 thrd_SetEvent(SessionEvents[0]);
9973 thrd_SetEvent(SessionEvents[session]);
9979 lock_ReleaseMutex(&smb_ListenerLock);
9980 } /* dispatch while loop */
9984 thrd_SetEvent(ListenerShutdown[lana]);
9989 configureBackConnectionHostNames(void)
9991 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9992 * there is a restriction on the use of SMB authentication on loopback connections.
9993 * There are two work arounds available:
9995 * (1) We can disable the check for matching host names. This does not
9997 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9998 * "DisableLoopbackCheck"=dword:00000001
10000 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
10001 * does require a reboot:
10002 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
10003 * "BackConnectionHostNames"=multi-sz
10005 * The algorithm will be:
10006 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
10007 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
10008 * (2b1) and check to see if DisableLoopbackCheck is set.
10009 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
10010 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
10011 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
10012 * check for the UnsetDisableLoopbackCheck value.
10013 * If set, set the DisableLoopbackCheck flag to 0x0
10014 * and delete the UnsetDisableLoopbackCheck value
10016 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
10017 * force Windows to use the loopback authentication mechanism for the specified
10020 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
10021 * service session that set it.
10027 DWORD dwSize, dwAllocSize;
10029 PBYTE pHostNames = NULL, pName = NULL;
10030 BOOL bNameFound = FALSE;
10031 static BOOL bLoopbackCheckDisabled = FALSE;
10033 /* BackConnectionHostNames and DisableLoopbackCheck */
10034 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10035 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
10037 KEY_READ|KEY_WRITE,
10038 &hkMSV10) == ERROR_SUCCESS )
10040 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
10041 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10042 (dwType == REG_MULTI_SZ))
10044 dwAllocSize += 1 /* in case the source string is not nul terminated */
10045 + (DWORD)strlen(cm_NetbiosName) + 2;
10046 pHostNames = malloc(dwAllocSize);
10047 dwSize = dwAllocSize;
10048 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
10049 pHostNames, &dwSize) == ERROR_SUCCESS)
10051 for (pName = pHostNames;
10052 (pName - pHostNames < (int) dwSize) && *pName ;
10053 pName += strlen(pName) + 1)
10055 if ( !stricmp(pName, cm_NetbiosName) ) {
10063 if ( !bNameFound ) {
10064 size_t size = strlen(cm_NetbiosName) + 2;
10065 if ( !pHostNames ) {
10066 pHostNames = malloc(size);
10067 pName = pHostNames;
10069 StringCbCopyA(pName, size, cm_NetbiosName);
10071 *pName = '\0'; /* add a second nul terminator */
10073 dwType = REG_MULTI_SZ;
10074 dwSize = (DWORD)(pName - pHostNames + 1);
10075 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10077 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10078 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10080 KEY_READ|KEY_WRITE,
10081 &hkLsa) == ERROR_SUCCESS )
10083 dwSize = sizeof(DWORD);
10084 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
10086 dwType = REG_DWORD;
10087 dwSize = sizeof(DWORD);
10089 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10091 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10092 AFSREG_CLT_OPENAFS_SUBKEY,
10095 REG_OPTION_NON_VOLATILE,
10096 KEY_READ|KEY_WRITE,
10099 NULL) == ERROR_SUCCESS) {
10101 dwType = REG_DWORD;
10102 dwSize = sizeof(DWORD);
10104 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10105 bLoopbackCheckDisabled = TRUE;
10106 RegCloseKey(hkClient);
10108 RegCloseKey(hkLsa);
10111 } else if (!bLoopbackCheckDisabled) {
10112 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10113 AFSREG_CLT_OPENAFS_SUBKEY,
10116 REG_OPTION_NON_VOLATILE,
10117 KEY_READ|KEY_WRITE,
10120 NULL) == ERROR_SUCCESS) {
10122 dwSize = sizeof(DWORD);
10123 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10125 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10126 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10128 KEY_READ|KEY_WRITE,
10129 &hkLsa) == ERROR_SUCCESS )
10131 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10132 RegCloseKey(hkLsa);
10135 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10136 RegCloseKey(hkClient);
10145 RegCloseKey(hkMSV10);
10151 configureExtendedSMBSessionTimeouts(void)
10154 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10155 * new functionality:
10157 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
10158 * "ReconnectableServers" REG_MULTI_SZ
10159 * "ExtendedSessTimeout" REG_DWORD (seconds)
10160 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
10162 * These values can be used to prevent the smb redirector from timing out
10163 * smb connection to the afs smb server prematurely.
10167 DWORD dwSize, dwAllocSize;
10169 PBYTE pHostNames = NULL, pName = NULL;
10170 BOOL bNameFound = FALSE;
10172 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10173 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
10175 KEY_READ|KEY_WRITE,
10176 &hkLanMan) == ERROR_SUCCESS )
10178 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
10179 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10180 (dwType == REG_MULTI_SZ))
10182 dwAllocSize += 1 /* in case the source string is not nul terminated */
10183 + (DWORD)strlen(cm_NetbiosName) + 2;
10184 pHostNames = malloc(dwAllocSize);
10185 dwSize = dwAllocSize;
10186 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
10187 pHostNames, &dwSize) == ERROR_SUCCESS)
10189 for (pName = pHostNames;
10190 (pName - pHostNames < (int) dwSize) && *pName ;
10191 pName += strlen(pName) + 1)
10193 if ( !stricmp(pName, cm_NetbiosName) ) {
10201 if ( !bNameFound ) {
10202 size_t size = strlen(cm_NetbiosName) + 2;
10203 if ( !pHostNames ) {
10204 pHostNames = malloc(size);
10205 pName = pHostNames;
10207 StringCbCopyA(pName, size, cm_NetbiosName);
10209 *pName = '\0'; /* add a second nul terminator */
10211 dwType = REG_MULTI_SZ;
10212 dwSize = (DWORD)(pName - pHostNames + 1);
10213 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10221 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
10222 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10223 (dwType == REG_MULTI_SZ))
10225 dwAllocSize += 1 /* in case the source string is not nul terminated */
10226 + (DWORD)strlen(cm_NetbiosName) + 2;
10227 pHostNames = malloc(dwAllocSize);
10228 dwSize = dwAllocSize;
10229 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
10230 pHostNames, &dwSize) == ERROR_SUCCESS)
10232 for (pName = pHostNames;
10233 (pName - pHostNames < (int) dwSize) && *pName ;
10234 pName += strlen(pName) + 1)
10236 if ( !stricmp(pName, cm_NetbiosName) ) {
10244 if ( !bNameFound ) {
10245 size_t size = strlen(cm_NetbiosName) + 2;
10246 if ( !pHostNames ) {
10247 pHostNames = malloc(size);
10248 pName = pHostNames;
10250 StringCbCopyA(pName, size, cm_NetbiosName);
10252 *pName = '\0'; /* add a second nul terminator */
10254 dwType = REG_MULTI_SZ;
10255 dwSize = (DWORD)(pName - pHostNames + 1);
10256 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10264 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
10265 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10266 (dwType != REG_DWORD))
10268 dwType = REG_DWORD;
10269 dwSize = sizeof(dwValue);
10270 dwValue = 300; /* 5 minutes */
10271 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10273 RegCloseKey(hkLanMan);
10278 smb_LanAdapterChangeThread(void *param)
10281 * Give the IPAddrDaemon thread a chance
10282 * to block before we trigger.
10285 smb_LanAdapterChange(0);
10288 void smb_SetLanAdapterChangeDetected(void)
10293 lock_ObtainMutex(&smb_StartedLock);
10295 if (!powerStateSuspended) {
10296 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10297 NULL, 0, &lpid, "smb_LanAdapterChange");
10298 if (phandle == NULL) {
10302 gle = GetLastError();
10303 StringCchPrintf( msg, sizeof(msg)/sizeof(msg[0]),
10304 "smb_LanAdapterChangeThread thread creation failure - gle 0x%x",
10306 osi_assertx(TRUE, msg);
10308 thrd_CloseHandle(phandle);
10311 smb_LanAdapterChangeDetected = 1;
10312 lock_ReleaseMutex(&smb_StartedLock);
10315 void smb_LanAdapterChange(int locked) {
10316 lana_number_t lanaNum;
10318 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
10320 LANA_ENUM temp_list;
10325 afsi_log("smb_LanAdapterChange");
10328 lock_ObtainMutex(&smb_StartedLock);
10330 smb_LanAdapterChangeDetected = 0;
10332 if (!powerStateSuspended &&
10333 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10334 LANA_NETBIOS_NAME_FULL | LANA_NETBIOS_NO_RESET)) &&
10335 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10336 if ( isGateway != bGateway ) {
10337 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10338 smb_LANadapter, lanaNum, isGateway, bGateway);
10340 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10341 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10342 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10345 NCB *ncbp = smb_GetNCB();
10346 ncbp->ncb_command = NCBENUM;
10347 ncbp->ncb_buffer = (PUCHAR)&temp_list;
10348 ncbp->ncb_length = sizeof(temp_list);
10349 code = Netbios(ncbp);
10351 if (temp_list.length != lana_list.length) {
10352 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10353 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10356 for (i=0; i<lana_list.length; i++) {
10357 if ( temp_list.lana[i] != lana_list.lana[i] ) {
10358 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10359 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10371 smb_StopListeners(1);
10372 smb_RestartListeners(1);
10375 lock_ReleaseMutex(&smb_StartedLock);
10378 /* initialize Netbios */
10379 int smb_NetbiosInit(int locked)
10382 int i, lana, code, l;
10384 int delname_tried=0;
10386 int lana_found = 0;
10387 lana_number_t lanaNum;
10390 lock_ObtainMutex(&smb_StartedLock);
10392 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10393 smb_ListenerState != SMB_LISTENER_STOPPED) {
10396 lock_ReleaseMutex(&smb_StartedLock);
10399 /* setup the NCB system */
10400 ncbp = smb_GetNCB();
10403 * Call lanahelper to get Netbios name, lan adapter number and gateway flag
10404 * This will reset all of the network adapter's netbios state.
10406 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10407 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10409 if (smb_LANadapter != LANA_INVALID)
10410 afsi_log("LAN adapter number %d", smb_LANadapter);
10412 afsi_log("LAN adapter number not determined");
10415 afsi_log("Set for gateway service");
10417 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10419 /* something went horribly wrong. We can't proceed without a netbios name */
10421 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10422 osi_panic(buf, __FILE__, __LINE__);
10425 /* remember the name */
10426 len = (int)strlen(cm_NetbiosName);
10427 if (smb_localNamep)
10428 free(smb_localNamep);
10429 smb_localNamep = malloc(len+1);
10430 strcpy(smb_localNamep, cm_NetbiosName);
10431 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10433 /* Also copy the value to the client character encoded string */
10434 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10436 if (smb_LANadapter == LANA_INVALID) {
10437 ncbp->ncb_command = NCBENUM;
10438 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10439 ncbp->ncb_length = sizeof(lana_list);
10440 code = Netbios(ncbp);
10442 afsi_log("Netbios NCBENUM error code %d", code);
10443 osi_panic(s, __FILE__, __LINE__);
10447 lana_list.length = 1;
10448 lana_list.lana[0] = smb_LANadapter;
10451 for (i = 0; i < lana_list.length; i++) {
10452 /* reset the adaptor: in Win32, this is required for every process, and
10453 * acts as an init call, not as a real hardware reset.
10455 ncbp->ncb_command = NCBRESET;
10456 ncbp->ncb_callname[0] = 100;
10457 ncbp->ncb_callname[2] = 100;
10458 ncbp->ncb_lana_num = lana_list.lana[i];
10459 code = Netbios(ncbp);
10461 code = ncbp->ncb_retcode;
10463 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10464 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10466 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10470 /* and declare our name so we can receive connections */
10471 memset(ncbp, 0, sizeof(*ncbp));
10472 len=lstrlen(smb_localNamep);
10473 memset(smb_sharename,' ',NCBNAMSZ);
10474 memcpy(smb_sharename,smb_localNamep,len);
10475 afsi_log("lana_list.length %d", lana_list.length);
10477 /* Keep the name so we can unregister it later */
10478 for (l = 0; l < lana_list.length; l++) {
10479 lana = lana_list.lana[l];
10481 ncbp->ncb_command = NCBADDNAME;
10482 ncbp->ncb_lana_num = lana;
10483 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10484 code = Netbios(ncbp);
10486 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10487 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10489 char name[NCBNAMSZ+1];
10491 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10492 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10496 code = ncbp->ncb_retcode;
10499 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10502 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10503 if (code == NRC_BRIDGE) { /* invalid LANA num */
10504 lana_list.lana[l] = LANA_INVALID;
10507 else if (code == NRC_DUPNAME) {
10508 afsi_log("Name already exists; try to delete it");
10509 memset(ncbp, 0, sizeof(*ncbp));
10510 ncbp->ncb_command = NCBDELNAME;
10511 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10512 ncbp->ncb_lana_num = lana;
10513 code = Netbios(ncbp);
10515 code = ncbp->ncb_retcode;
10517 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10519 if (code != 0 || delname_tried) {
10520 lana_list.lana[l] = LANA_INVALID;
10522 else if (code == 0) {
10523 if (!delname_tried) {
10531 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10532 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10536 smb_LANadapter = lana;
10537 lana_found = 1; /* at least one worked */
10541 osi_assertx(lana_list.length >= 0, "empty lana list");
10543 afsi_log("No valid LANA numbers found!");
10544 lana_list.length = 0;
10545 smb_LANadapter = LANA_INVALID;
10546 smb_ListenerState = SMB_LISTENER_STOPPED;
10547 cm_VolStatus_Network_Stopped(cm_NetbiosName
10554 /* we're done with the NCB now */
10557 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10558 if (lana_list.length > 0)
10559 osi_assert(smb_LANadapter != LANA_INVALID);
10562 lock_ReleaseMutex(&smb_StartedLock);
10564 return (lana_list.length > 0 ? 1 : 0);
10567 void smb_StartListeners(int locked)
10574 lock_ObtainMutex(&smb_StartedLock);
10576 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10578 lock_ReleaseMutex(&smb_StartedLock);
10582 afsi_log("smb_StartListeners");
10583 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10584 configureBackConnectionHostNames();
10586 /* Configure Extended SMB Session Timeouts */
10587 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10588 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10589 configureExtendedSMBSessionTimeouts();
10592 smb_ListenerState = SMB_LISTENER_STARTED;
10593 cm_VolStatus_Network_Started(cm_NetbiosName
10599 for (i = 0; i < lana_list.length; i++) {
10600 if (lana_list.lana[i] == LANA_INVALID)
10602 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10603 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10604 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10605 thrd_CloseHandle(phandle);
10608 lock_ReleaseMutex(&smb_StartedLock);
10611 void smb_RestartListeners(int locked)
10614 lock_ObtainMutex(&smb_StartedLock);
10616 if (powerStateSuspended)
10617 afsi_log("smb_RestartListeners called while suspended");
10619 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10620 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10621 if (smb_NetbiosInit(1))
10622 smb_StartListeners(1);
10623 } else if (smb_LanAdapterChangeDetected) {
10624 smb_LanAdapterChange(1);
10628 lock_ReleaseMutex(&smb_StartedLock);
10631 void smb_StopListener(NCB *ncbp, int lana, int wait)
10635 memset(ncbp, 0, sizeof(*ncbp));
10636 ncbp->ncb_command = NCBDELNAME;
10637 ncbp->ncb_lana_num = lana;
10638 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10639 code = Netbios(ncbp);
10641 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10642 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10644 /* and then reset the LANA; this will cause the listener threads to exit */
10645 ncbp->ncb_command = NCBRESET;
10646 ncbp->ncb_callname[0] = 100;
10647 ncbp->ncb_callname[2] = 100;
10648 ncbp->ncb_lana_num = lana;
10649 code = Netbios(ncbp);
10651 code = ncbp->ncb_retcode;
10653 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10655 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10659 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10662 void smb_StopListeners(int locked)
10668 lock_ObtainMutex(&smb_StartedLock);
10670 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10672 lock_ReleaseMutex(&smb_StartedLock);
10676 afsi_log("smb_StopListeners");
10677 smb_ListenerState = SMB_LISTENER_STOPPED;
10678 cm_VolStatus_Network_Stopped(cm_NetbiosName
10684 ncbp = smb_GetNCB();
10686 /* Unregister the SMB name */
10687 for (l = 0; l < lana_list.length; l++) {
10688 lana = lana_list.lana[l];
10690 if (lana != LANA_INVALID) {
10691 smb_StopListener(ncbp, lana, TRUE);
10693 /* mark the adapter invalid */
10694 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10698 /* force a re-evaluation of the network adapters */
10699 lana_list.length = 0;
10700 smb_LANadapter = LANA_INVALID;
10703 lock_ReleaseMutex(&smb_StartedLock);
10706 void smb_Init(osi_log_t *logp, int useV3,
10716 EVENT_HANDLE retHandle;
10717 char eventName[MAX_PATH];
10718 int startListeners = 0;
10720 smb_MBfunc = aMBfunc;
10724 /* Initialize smb_localZero */
10725 myTime.tm_isdst = -1; /* compute whether on DST or not */
10726 myTime.tm_year = 70;
10728 myTime.tm_mday = 1;
10729 myTime.tm_hour = 0;
10732 smb_localZero = mktime(&myTime);
10734 #ifdef AFS_FREELANCE_CLIENT
10735 /* Make sure the root.afs volume has the correct time */
10736 cm_noteLocalMountPointChange(FALSE);
10739 /* initialize the remote debugging log */
10742 /* and the global lock */
10743 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10744 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10746 /* Raw I/O data structures */
10747 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10749 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10750 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10752 /* 4 Raw I/O buffers */
10753 smb_RawBufs = calloc(65536,1);
10754 *((char **)smb_RawBufs) = NULL;
10755 for (i=0; i<3; i++) {
10756 char *rawBuf = calloc(65536,1);
10757 *((char **)rawBuf) = smb_RawBufs;
10758 smb_RawBufs = rawBuf;
10761 /* global free lists */
10762 smb_ncbFreeListp = NULL;
10763 smb_packetFreeListp = NULL;
10765 lock_ObtainMutex(&smb_StartedLock);
10766 startListeners = smb_NetbiosInit(1);
10768 /* Initialize listener and server structures */
10770 memset(dead_sessions, 0, sizeof(dead_sessions));
10771 sprintf(eventName, "SessionEvents[0]");
10772 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10773 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10774 afsi_log("Event Object Already Exists: %s", eventName);
10776 smb_NumServerThreads = nThreads;
10777 sprintf(eventName, "NCBavails[0]");
10778 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10779 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10780 afsi_log("Event Object Already Exists: %s", eventName);
10781 sprintf(eventName, "NCBevents[0]");
10782 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10783 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10784 afsi_log("Event Object Already Exists: %s", eventName);
10785 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10786 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10787 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10788 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10789 afsi_log("Event Object Already Exists: %s", eventName);
10790 for (i = 0; i < smb_NumServerThreads; i++) {
10791 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10792 NCBreturns[i][0] = retHandle;
10795 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10796 for (i = 0; i < smb_NumServerThreads; i++) {
10797 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10798 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10799 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10800 afsi_log("Event Object Already Exists: %s", eventName);
10801 InitNCBslot((int)(i+1));
10803 numNCBs = smb_NumServerThreads + 1;
10805 /* Initialize dispatch table */
10806 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10807 /* Prepare the table for unknown operations */
10808 for(i=0; i<= SMB_NOPCODES; i++) {
10809 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10811 /* Fill in the ones we do know */
10812 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10813 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10814 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10815 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10816 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10817 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10818 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10819 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10820 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10821 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10822 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10823 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10824 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10825 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10826 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10827 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10828 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10829 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10830 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10831 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10832 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10833 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10834 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10835 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10836 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10837 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10838 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10839 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10840 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10841 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10842 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10843 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10844 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10845 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10846 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10847 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10848 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10849 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10850 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10851 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10852 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10853 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10854 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10855 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10856 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10857 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10858 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10859 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10860 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10861 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10862 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10863 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10864 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10865 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10866 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10867 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10868 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10869 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10870 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10871 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10872 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10873 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10874 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10875 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10876 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10877 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10878 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10879 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10880 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10881 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10882 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10883 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10884 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10885 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10887 /* setup tran 2 dispatch table */
10888 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10889 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10890 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10891 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10892 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10893 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10894 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10895 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10896 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10897 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10898 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10899 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10900 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10901 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10902 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10903 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10904 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10905 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10907 /* setup the rap dispatch table */
10908 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10909 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10910 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10911 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10912 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10916 /* if we are doing SMB authentication we have register outselves as a logon process */
10917 if (smb_authType != SMB_AUTH_NONE) {
10918 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10919 LSA_STRING afsProcessName;
10920 LSA_OPERATIONAL_MODE dummy; /*junk*/
10922 afsProcessName.Buffer = "OpenAFSClientDaemon";
10923 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10924 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10926 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10928 if (nts == STATUS_SUCCESS) {
10929 LSA_STRING packageName;
10930 /* we are registered. Find out the security package id */
10931 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10932 packageName.Length = (USHORT)strlen(packageName.Buffer);
10933 packageName.MaximumLength = packageName.Length + 1;
10934 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10935 if (nts == STATUS_SUCCESS) {
10937 * This code forces Windows to authenticate against the Logon Cache
10938 * first instead of attempting to authenticate against the Domain
10939 * Controller. When the Windows logon cache is enabled this improves
10940 * performance by removing the network access and works around a bug
10941 * seen at sites which are using a MIT Kerberos principal to login
10942 * to machines joined to a non-root domain in a multi-domain forest.
10943 * MsV1_0SetProcessOption was added in Windows XP.
10945 PVOID pResponse = NULL;
10946 ULONG cbResponse = 0;
10947 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10949 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10950 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10951 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10952 OptionsRequest.DisableOptions = FALSE;
10954 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10957 sizeof(OptionsRequest),
10963 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10964 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10967 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10969 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10970 afsi_log("MsV1_0SetProcessOption success");
10972 /* END - code from Larry */
10974 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10975 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10976 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10978 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10980 /* something went wrong. We report the error and revert back to no authentication
10981 because we can't perform any auth requests without a successful lsa handle
10982 or sec package id. */
10983 afsi_log("Reverting to NO SMB AUTH");
10984 smb_authType = SMB_AUTH_NONE;
10987 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10989 /* something went wrong. We report the error and revert back to no authentication
10990 because we can't perform any auth requests without a successful lsa handle
10991 or sec package id. */
10992 afsi_log("Reverting to NO SMB AUTH");
10993 smb_authType = SMB_AUTH_NONE;
10997 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10998 * time prevents the failure of authentication when logged into Windows with an
10999 * external Kerberos principal mapped to a local account.
11001 else if ( smb_authType == SMB_AUTH_EXTENDED) {
11002 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
11003 * then the only option is NTLMSSP anyway; so just fallback.
11008 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
11009 if (secBlobLength == 0) {
11010 smb_authType = SMB_AUTH_NTLM;
11011 afsi_log("Reverting to SMB AUTH NTLM");
11020 /* Now get ourselves a domain name. */
11021 /* For now we are using the local computer name as the domain name.
11022 * It is actually the domain for local logins, and we are acting as
11023 * a local SMB server.
11025 bufsize = lengthof(smb_ServerDomainName) - 1;
11026 GetComputerNameW(smb_ServerDomainName, &bufsize);
11027 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
11028 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
11031 /* Start listeners, waiters, servers, and daemons */
11032 if (startListeners)
11033 smb_StartListeners(1);
11035 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
11036 NULL, 0, &lpid, "smb_ClientWaiter");
11037 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
11038 thrd_CloseHandle(phandle);
11040 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
11041 NULL, 0, &lpid, "smb_ServerWaiter");
11042 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
11043 thrd_CloseHandle(phandle);
11045 for (i=0; i<smb_NumServerThreads; i++) {
11046 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
11047 (void *) i, 0, &lpid, "smb_Server");
11048 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
11049 thrd_CloseHandle(phandle);
11052 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
11053 NULL, 0, &lpid, "smb_Daemon");
11054 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
11055 thrd_CloseHandle(phandle);
11057 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
11058 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
11059 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
11060 thrd_CloseHandle(phandle);
11062 if (smb_monitorReqs) {
11063 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
11064 NULL, 0, &lpid, "smb_ServerMonitor");
11065 osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
11066 thrd_CloseHandle(phandle);
11069 lock_ReleaseMutex(&smb_StartedLock);
11073 void smb_Shutdown(void)
11080 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11082 /* setup the NCB system */
11083 ncbp = smb_GetNCB();
11085 /* Block new sessions by setting shutdown flag */
11086 smbShutdownFlag = 1;
11088 /* Hang up all sessions */
11089 memset(ncbp, 0, sizeof(NCB));
11090 for (i = 1; i < numSessions; i++)
11092 if (dead_sessions[i])
11095 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11096 ncbp->ncb_command = NCBHANGUP;
11097 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
11098 ncbp->ncb_lsn = (UCHAR)LSNs[i];
11099 code = Netbios(ncbp);
11100 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11101 if (code == 0) code = ncbp->ncb_retcode;
11103 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11104 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11108 /* Trigger the shutdown of all SMB threads */
11109 for (i = 0; i < smb_NumServerThreads; i++)
11110 thrd_SetEvent(NCBreturns[i][0]);
11112 thrd_SetEvent(NCBevents[0]);
11113 thrd_SetEvent(SessionEvents[0]);
11114 thrd_SetEvent(NCBavails[0]);
11116 for (i = 0;i < smb_NumServerThreads; i++) {
11117 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11118 if (code == WAIT_OBJECT_0) {
11121 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11122 thrd_SetEvent(NCBreturns[i--][0]);
11126 /* Delete Netbios name */
11127 memset(ncbp, 0, sizeof(NCB));
11128 for (i = 0; i < lana_list.length; i++) {
11129 if (lana_list.lana[i] == LANA_INVALID) continue;
11130 ncbp->ncb_command = NCBDELNAME;
11131 ncbp->ncb_lana_num = lana_list.lana[i];
11132 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11133 code = Netbios(ncbp);
11135 code = ncbp->ncb_retcode;
11137 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11138 ncbp->ncb_lana_num, code);
11143 /* Release the reference counts held by the VCs */
11144 lock_ObtainWrite(&smb_rctLock);
11145 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11150 if (vcp->magic != SMB_VC_MAGIC)
11151 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11152 __FILE__, __LINE__);
11154 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11156 if (fidp->scp != NULL) {
11159 lock_ReleaseWrite(&smb_rctLock);
11160 lock_ObtainMutex(&fidp->mx);
11161 if (fidp->scp != NULL) {
11164 lock_ObtainWrite(&scp->rw);
11165 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11166 lock_ReleaseWrite(&scp->rw);
11167 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11168 cm_ReleaseSCache(scp);
11170 lock_ReleaseMutex(&fidp->mx);
11171 lock_ObtainWrite(&smb_rctLock);
11175 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11177 smb_ReleaseVCNoLock(tidp->vcp);
11179 cm_user_t *userp = tidp->userp;
11180 tidp->userp = NULL;
11181 cm_ReleaseUser(userp);
11185 lock_ReleaseWrite(&smb_rctLock);
11188 if (smb_monitorReqs) {
11189 smb_ShutdownMonitor();
11193 /* Get the UNC \\<servername>\<sharename> prefix. */
11194 char *smb_GetSharename()
11199 /* Make sure we have been properly initialized. */
11200 if (smb_localNamep == NULL)
11203 /* Allocate space for \\<servername>\<sharename>, plus the
11206 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11207 name = malloc(len);
11208 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11214 void smb_LogPacket(smb_packet_t *packet)
11218 unsigned length, paramlen, datalen, i, j;
11220 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11222 if (!packet) return;
11224 osi_Log0(smb_logp, "*** SMB packet dump ***");
11226 smbp = (smb_t *) packet->data;
11227 vp = (BYTE *) packet->data;
11229 paramlen = smbp->wct * 2;
11230 datalen = *((WORD *) (smbp->vdata + paramlen));
11231 length = sizeof(*smbp) + paramlen + 1 + datalen;
11233 for (i=0;i < length; i+=16)
11235 memset( buf, ' ', 80 );
11238 itoa( i, buf, 16 );
11240 buf[strlen(buf)] = ' ';
11242 cp = (BYTE*) buf + 7;
11244 for (j=0;j < 16 && (i+j)<length; j++)
11246 *(cp++) = hex[vp[i+j] >> 4];
11247 *(cp++) = hex[vp[i+j] & 0xf];
11257 for (j=0;j < 16 && (i+j)<length;j++)
11259 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11270 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11273 osi_Log0(smb_logp, "*** End SMB packet dump ***");
11275 #endif /* LOG_PACKET */
11278 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11284 smb_username_t *unp;
11285 smb_waitingLockRequest_t *wlrp;
11288 lock_ObtainRead(&smb_rctLock);
11290 sprintf(output, "begin dumping smb_username_t\r\n");
11291 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11292 for (unp = usernamesp; unp; unp=unp->nextp)
11294 cm_ucell_t *ucellp;
11296 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11297 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11298 unp->name ? unp->name : _C("NULL"),
11299 unp->machine ? unp->machine : _C("NULL"));
11300 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11302 sprintf(output, " begin dumping cm_ucell_t\r\n");
11303 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11305 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11306 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",
11307 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11308 ucellp->expirationTime, ucellp->gen,
11310 ucellp->cellp->name);
11311 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11314 sprintf(output, " done dumping cm_ucell_t\r\n");
11315 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11318 sprintf(output, "done dumping smb_username_t\r\n");
11319 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11322 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11323 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11326 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11327 smb_waitingLock_t *lockp;
11329 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11330 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11331 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11333 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
11334 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11335 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11336 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11337 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11338 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11340 sprintf(output, " done dumping smb_waitingLock_t\r\n");
11341 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11344 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11345 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11347 sprintf(output, "begin dumping smb_vc_t\r\n");
11348 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11350 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11356 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11357 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11358 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11360 sprintf(output, " begin dumping smb_user_t\r\n");
11361 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11362 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11363 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11364 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11365 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11367 sprintf(output, " done dumping smb_user_t\r\n");
11368 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11370 sprintf(output, " begin dumping smb_tid_t\r\n");
11371 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11372 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11373 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",
11374 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11375 tidp->pathname ? tidp->pathname : _C("NULL"));
11376 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11378 sprintf(output, " done dumping smb_tid_t\r\n");
11379 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11381 sprintf(output, " begin dumping smb_fid_t\r\n");
11382 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11384 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11386 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",
11387 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11388 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11389 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11390 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11393 sprintf(output, " done dumping smb_fid_t\r\n");
11394 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11397 sprintf(output, "done dumping smb_vc_t\r\n");
11398 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11400 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11401 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11403 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11409 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11410 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11411 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11413 sprintf(output, " begin dumping smb_user_t\r\n");
11414 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11415 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11416 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11417 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11418 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11420 sprintf(output, " done dumping smb_user_t\r\n");
11421 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11423 sprintf(output, " begin dumping smb_tid_t\r\n");
11424 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11425 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11426 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",
11427 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11428 tidp->pathname ? tidp->pathname : _C("NULL"));
11429 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11431 sprintf(output, " done dumping smb_tid_t\r\n");
11432 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11434 sprintf(output, " begin dumping smb_fid_t\r\n");
11435 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11437 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11439 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",
11440 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11441 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11442 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11443 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11446 sprintf(output, " done dumping smb_fid_t\r\n");
11447 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11450 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11451 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11454 lock_ReleaseRead(&smb_rctLock);
11458 long smb_IsNetworkStarted(void)
11461 lock_ObtainWrite(&smb_globalLock);
11462 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11463 lock_ReleaseWrite(&smb_globalLock);