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, afs_uint32 redir)
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 = 0xC0020052L; /* RPC_NT_COMM_FAILURE */
3101 NTStatus = 0xC00000CFL; /* Sharing Paused */
3103 /* Do not send Timeout to the SMB redirector.
3104 * It causes the redirector to drop the connection */
3105 NTStatus = 0x00000102L; /* Timeout */
3106 /* do not send Retry to the SMB redirector.
3107 * It believes the error comes from the transport
3108 * layer not from the SMB server. */
3109 NTStatus = 0xC000022DL; /* Retry */
3111 NTStatus = 0xC00000B5L; /* I/O Timeout */
3115 else if (code == CM_ERROR_RETRY) {
3117 NTStatus = 0xC000022DL; /* Retry */
3120 NTStatus = 0xC000022DL; /* Retry */
3122 NTStatus = 0xC00000B5L; /* I/O Timeout */
3126 else if (code == CM_ERROR_NOACCESS) {
3127 NTStatus = 0xC0000022L; /* Access denied */
3129 else if (code == CM_ERROR_READONLY) {
3130 NTStatus = 0xC00000A2L; /* Write protected */
3132 else if (code == CM_ERROR_NOSUCHFILE ||
3133 code == CM_ERROR_BPLUS_NOMATCH) {
3134 NTStatus = 0xC0000034L; /* Name not found */
3136 else if (code == CM_ERROR_NOSUCHPATH) {
3137 NTStatus = 0xC000003AL; /* Object path not found */
3139 else if (code == CM_ERROR_TOOBIG) {
3140 NTStatus = 0xC000007BL; /* Invalid image format */
3142 else if (code == CM_ERROR_INVAL) {
3143 NTStatus = 0xC000000DL; /* Invalid parameter */
3145 else if (code == CM_ERROR_BADFD) {
3146 NTStatus = 0xC0000008L; /* Invalid handle */
3148 else if (code == CM_ERROR_BADFDOP) {
3149 NTStatus = 0xC0000022L; /* Access denied */
3151 else if (code == CM_ERROR_UNKNOWN) {
3152 NTStatus = 0xC0000022L; /* Access denied */
3154 else if (code == CM_ERROR_EXISTS) {
3155 NTStatus = 0xC0000035L; /* Object name collision */
3157 else if (code == CM_ERROR_NOTEMPTY) {
3158 NTStatus = 0xC0000101L; /* Directory not empty */
3160 else if (code == CM_ERROR_CROSSDEVLINK) {
3161 NTStatus = 0xC00000D4L; /* Not same device */
3163 else if (code == CM_ERROR_NOTDIR) {
3164 NTStatus = 0xC0000103L; /* Not a directory */
3166 else if (code == CM_ERROR_ISDIR) {
3167 NTStatus = 0xC00000BAL; /* File is a directory */
3169 else if (code == CM_ERROR_BADOP) {
3171 /* I have no idea where this comes from */
3172 NTStatus = 0xC09820FFL; /* SMB no support */
3174 NTStatus = 0xC00000BBL; /* Not supported */
3175 #endif /* COMMENT */
3177 else if (code == CM_ERROR_BADSHARENAME) {
3178 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3180 else if (code == CM_ERROR_NOIPC) {
3182 NTStatus = 0xC0000022L; /* Access Denied */
3184 NTStatus = 0xC000013DL; /* Remote Resources */
3187 else if (code == CM_ERROR_CLOCKSKEW ||
3188 code == RXKADNOAUTH) {
3189 NTStatus = 0xC0000133L; /* Time difference at DC */
3191 else if (code == CM_ERROR_BADTID) {
3192 NTStatus = 0xC0982005L; /* SMB bad TID */
3194 else if (code == CM_ERROR_USESTD) {
3195 NTStatus = 0xC09820FBL; /* SMB use standard */
3197 else if (code == CM_ERROR_QUOTA) {
3198 NTStatus = 0xC0000044L; /* Quota exceeded */
3200 else if (code == CM_ERROR_SPACE) {
3201 NTStatus = 0xC000007FL; /* Disk full */
3203 else if (code == CM_ERROR_ATSYS) {
3204 NTStatus = 0xC0000033L; /* Object name invalid */
3206 else if (code == CM_ERROR_BADNTFILENAME) {
3207 NTStatus = 0xC0000033L; /* Object name invalid */
3209 else if (code == CM_ERROR_WOULDBLOCK) {
3210 NTStatus = 0xC00000D8L; /* Can't wait */
3212 else if (code == CM_ERROR_SHARING_VIOLATION) {
3213 NTStatus = 0xC0000043L; /* Sharing violation */
3215 else if (code == CM_ERROR_LOCK_CONFLICT) {
3216 NTStatus = 0xC0000054L; /* Lock conflict */
3218 else if (code == CM_ERROR_PARTIALWRITE) {
3219 NTStatus = 0xC000007FL; /* Disk full */
3221 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3222 NTStatus = 0xC0000023L; /* Buffer too small */
3224 else if (code == CM_ERROR_BUFFER_OVERFLOW) {
3225 NTStatus = 0x80000005L; /* Buffer overflow */
3227 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3228 NTStatus = 0xC0000035L; /* Object name collision */
3230 else if (code == CM_ERROR_BADPASSWORD) {
3231 NTStatus = 0xC000006DL; /* unknown username or bad password */
3233 else if (code == CM_ERROR_BADLOGONTYPE) {
3234 NTStatus = 0xC000015BL; /* logon type not granted */
3236 else if (code == CM_ERROR_GSSCONTINUE) {
3237 NTStatus = 0xC0000016L; /* more processing required */
3239 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3241 NTStatus = 0xC0000280L; /* reparse point not resolved */
3243 NTStatus = 0xC0000022L; /* Access Denied */
3246 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3247 NTStatus = 0xC0000257L; /* Path Not Covered */
3249 else if (code == CM_ERROR_ALLBUSY) {
3251 NTStatus = 0xC000022DL; /* Retry */
3253 NTStatus = 0xC0020018L; /* RPC_NT_SERVER_TOO_BUSY */
3256 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3258 NTStatus = 0xC000003AL; /* Path not found */
3260 NTStatus = 0xC0020017L; /* RPC_NT_SERVER_UNAVAILABLE */
3263 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3264 NTStatus = 0xC0000322L; /* No Kerberos key */
3266 else if (code == CM_ERROR_BAD_LEVEL) {
3267 NTStatus = 0xC0000148L; /* Invalid Level */
3269 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3270 NTStatus = 0xC000007EL; /* Range Not Locked */
3272 else if (code == CM_ERROR_NOSUCHDEVICE) {
3273 NTStatus = 0xC000000EL; /* No Such Device */
3275 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3276 NTStatus = 0xC0000055L; /* Lock Not Granted */
3278 else if (code == ENOMEM) {
3279 NTStatus = 0xC0000017L; /* Out of Memory */
3281 else if (code == CM_ERROR_RPC_MOREDATA) {
3282 NTStatus = 0x80000005L; /* Buffer overflow */
3285 NTStatus = 0xC0982001L; /* SMB non-specific error */
3288 *NTStatusp = NTStatus;
3289 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3293 * NTSTATUS <-> Win32 Error Translation
3294 * http://support.microsoft.com/kb/113996
3296 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3298 unsigned long Win32E;
3300 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3304 else if (code == CM_ERROR_NOSUCHCELL) {
3305 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3307 else if (code == CM_ERROR_NOSUCHVOLUME) {
3308 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3310 else if (code == CM_ERROR_TIMEDOUT) {
3312 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3314 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3317 else if (code == CM_ERROR_RETRY) {
3318 Win32E = ERROR_RETRY; /* Retry */
3320 else if (code == CM_ERROR_NOACCESS) {
3321 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3323 else if (code == CM_ERROR_READONLY) {
3324 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3326 else if (code == CM_ERROR_NOSUCHFILE ||
3327 code == CM_ERROR_BPLUS_NOMATCH) {
3328 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3330 else if (code == CM_ERROR_NOSUCHPATH) {
3331 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3333 else if (code == CM_ERROR_TOOBIG) {
3334 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3336 else if (code == CM_ERROR_INVAL) {
3337 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3339 else if (code == CM_ERROR_BADFD) {
3340 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3342 else if (code == CM_ERROR_BADFDOP) {
3343 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3345 else if (code == CM_ERROR_UNKNOWN) {
3346 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3348 else if (code == CM_ERROR_EXISTS) {
3349 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3351 else if (code == CM_ERROR_NOTEMPTY) {
3352 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3354 else if (code == CM_ERROR_CROSSDEVLINK) {
3355 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3357 else if (code == CM_ERROR_NOTDIR) {
3358 Win32E = ERROR_DIRECTORY; /* Not a directory */
3360 else if (code == CM_ERROR_ISDIR) {
3361 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3363 else if (code == CM_ERROR_BADOP) {
3364 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3366 else if (code == CM_ERROR_BADSHARENAME) {
3367 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3369 else if (code == CM_ERROR_NOIPC) {
3371 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3373 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3376 else if (code == CM_ERROR_CLOCKSKEW ||
3377 code == RXKADNOAUTH) {
3378 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3380 else if (code == CM_ERROR_BADTID) {
3381 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3383 else if (code == CM_ERROR_USESTD) {
3384 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3386 else if (code == CM_ERROR_QUOTA) {
3387 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3389 else if (code == CM_ERROR_SPACE) {
3390 Win32E = ERROR_DISK_FULL; /* Disk full */
3392 else if (code == CM_ERROR_ATSYS) {
3393 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3395 else if (code == CM_ERROR_BADNTFILENAME) {
3396 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3398 else if (code == CM_ERROR_WOULDBLOCK) {
3399 Win32E = WAIT_TIMEOUT; /* Can't wait */
3401 else if (code == CM_ERROR_SHARING_VIOLATION) {
3402 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3404 else if (code == CM_ERROR_LOCK_CONFLICT) {
3405 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3407 else if (code == CM_ERROR_PARTIALWRITE) {
3408 Win32E = ERROR_DISK_FULL; /* Disk full */
3410 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3411 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3413 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3414 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3416 else if (code == CM_ERROR_BADPASSWORD) {
3417 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3419 else if (code == CM_ERROR_BADLOGONTYPE) {
3420 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3422 else if (code == CM_ERROR_GSSCONTINUE) {
3423 Win32E = ERROR_MORE_DATA; /* more processing required */
3425 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3427 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3429 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3432 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3433 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3435 else if (code == CM_ERROR_ALLBUSY) {
3436 Win32E = ERROR_RETRY; /* Retry */
3438 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3439 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3441 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3442 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3444 else if (code == CM_ERROR_BAD_LEVEL) {
3445 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3447 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3448 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3450 else if (code == CM_ERROR_NOSUCHDEVICE) {
3451 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3453 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3454 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3456 else if (code == ENOMEM) {
3457 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3459 else if (code == CM_ERROR_RPC_MOREDATA) {
3460 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3463 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3467 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3470 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3471 unsigned char *classp)
3473 unsigned char class;
3474 unsigned short error;
3476 /* map CM_ERROR_* errors to SMB errors */
3477 if (code == CM_ERROR_NOSUCHCELL) {
3479 error = 3; /* bad path */
3481 else if (code == CM_ERROR_NOSUCHVOLUME) {
3483 error = 3; /* bad path */
3485 else if (code == CM_ERROR_TIMEDOUT) {
3487 error = 81; /* server is paused */
3489 else if (code == CM_ERROR_RETRY) {
3490 class = 2; /* shouldn't happen */
3493 else if (code == CM_ERROR_NOACCESS) {
3495 error = 4; /* bad access */
3497 else if (code == CM_ERROR_READONLY) {
3499 error = 19; /* read only */
3501 else if (code == CM_ERROR_NOSUCHFILE ||
3502 code == CM_ERROR_BPLUS_NOMATCH) {
3504 error = 2; /* ENOENT! */
3506 else if (code == CM_ERROR_NOSUCHPATH) {
3508 error = 3; /* Bad path */
3510 else if (code == CM_ERROR_TOOBIG) {
3512 error = 11; /* bad format */
3514 else if (code == CM_ERROR_INVAL) {
3515 class = 2; /* server non-specific error code */
3518 else if (code == CM_ERROR_BADFD) {
3520 error = 6; /* invalid file handle */
3522 else if (code == CM_ERROR_BADFDOP) {
3523 class = 1; /* invalid op on FD */
3526 else if (code == CM_ERROR_EXISTS) {
3528 error = 80; /* file already exists */
3530 else if (code == CM_ERROR_NOTEMPTY) {
3532 error = 5; /* delete directory not empty */
3534 else if (code == CM_ERROR_CROSSDEVLINK) {
3536 error = 17; /* EXDEV */
3538 else if (code == CM_ERROR_NOTDIR) {
3539 class = 1; /* bad path */
3542 else if (code == CM_ERROR_ISDIR) {
3543 class = 1; /* access denied; DOS doesn't have a good match */
3546 else if (code == CM_ERROR_BADOP) {
3550 else if (code == CM_ERROR_BADSHARENAME) {
3554 else if (code == CM_ERROR_NOIPC) {
3556 error = 4; /* bad access */
3558 else if (code == CM_ERROR_CLOCKSKEW) {
3559 class = 1; /* invalid function */
3562 else if (code == CM_ERROR_BADTID) {
3566 else if (code == CM_ERROR_USESTD) {
3570 else if (code == CM_ERROR_REMOTECONN) {
3574 else if (code == CM_ERROR_QUOTA) {
3575 if (vcp->flags & SMB_VCFLAG_USEV3) {
3577 error = 39; /* disk full */
3581 error = 5; /* access denied */
3584 else if (code == CM_ERROR_SPACE) {
3585 if (vcp->flags & SMB_VCFLAG_USEV3) {
3587 error = 39; /* disk full */
3591 error = 5; /* access denied */
3594 else if (code == CM_ERROR_PARTIALWRITE) {
3596 error = 39; /* disk full */
3598 else if (code == CM_ERROR_ATSYS) {
3600 error = 2; /* ENOENT */
3602 else if (code == CM_ERROR_WOULDBLOCK) {
3604 error = 33; /* lock conflict */
3606 else if (code == CM_ERROR_LOCK_CONFLICT) {
3608 error = 33; /* lock conflict */
3610 else if (code == CM_ERROR_SHARING_VIOLATION) {
3612 error = 33; /* lock conflict */
3614 else if (code == CM_ERROR_NOFILES) {
3616 error = 18; /* no files in search */
3618 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3620 error = 183; /* Samba uses this */
3622 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3623 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3625 error = 2; /* bad password */
3627 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3629 error = 3; /* bad path */
3638 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3641 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3643 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3644 return CM_ERROR_BADOP;
3648 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3650 unsigned short EchoCount, i;
3651 char *data, *outdata;
3654 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3656 for (i=1; i<=EchoCount; i++) {
3657 data = smb_GetSMBData(inp, &dataSize);
3658 smb_SetSMBParm(outp, 0, i);
3659 smb_SetSMBDataLength(outp, dataSize);
3660 outdata = smb_GetSMBData(outp, NULL);
3661 memcpy(outdata, data, dataSize);
3662 smb_SendPacket(vcp, outp);
3668 /* SMB_COM_READ_RAW */
3669 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3672 long count, minCount, finalCount;
3676 smb_t *smbp = (smb_t*) inp;
3678 cm_user_t *userp = NULL;
3681 char *rawBuf = NULL;
3686 fd = smb_GetSMBParm(inp, 0);
3687 count = smb_GetSMBParm(inp, 3);
3688 minCount = smb_GetSMBParm(inp, 4);
3689 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3691 if (*inp->wctp == 10) {
3692 /* we were sent a request with 64-bit file offsets */
3693 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3695 if (LargeIntegerLessThanZero(offset)) {
3696 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3700 /* we were sent a request with 32-bit file offsets */
3701 offset.HighPart = 0;
3704 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3705 fd, offset.HighPart, offset.LowPart, count);
3707 fidp = smb_FindFID(vcp, fd, 0);
3709 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3713 lock_ObtainMutex(&fidp->mx);
3715 lock_ReleaseMutex(&fidp->mx);
3716 smb_ReleaseFID(fidp);
3717 return CM_ERROR_BADFD;
3720 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3721 lock_ReleaseMutex(&fidp->mx);
3722 smb_CloseFID(vcp, fidp, NULL, 0);
3723 code = CM_ERROR_NOSUCHFILE;
3729 LARGE_INTEGER LOffset, LLength;
3732 key = cm_GenerateKey(vcp->vcID, pid, fd);
3734 LOffset.HighPart = offset.HighPart;
3735 LOffset.LowPart = offset.LowPart;
3736 LLength.HighPart = 0;
3737 LLength.LowPart = count;
3739 lock_ObtainWrite(&fidp->scp->rw);
3740 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3741 lock_ReleaseWrite(&fidp->scp->rw);
3744 lock_ReleaseMutex(&fidp->mx);
3748 lock_ObtainMutex(&smb_RawBufLock);
3750 /* Get a raw buf, from head of list */
3751 rawBuf = smb_RawBufs;
3752 smb_RawBufs = *(char **)smb_RawBufs;
3754 lock_ReleaseMutex(&smb_RawBufLock);
3756 lock_ReleaseMutex(&fidp->mx);
3760 if (fidp->flags & SMB_FID_IOCTL)
3762 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3764 /* Give back raw buffer */
3765 lock_ObtainMutex(&smb_RawBufLock);
3766 *((char **) rawBuf) = smb_RawBufs;
3768 smb_RawBufs = rawBuf;
3769 lock_ReleaseMutex(&smb_RawBufLock);
3772 lock_ReleaseMutex(&fidp->mx);
3773 smb_ReleaseFID(fidp);
3776 lock_ReleaseMutex(&fidp->mx);
3778 userp = smb_GetUserFromVCP(vcp, inp);
3780 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3786 cm_ReleaseUser(userp);
3789 smb_ReleaseFID(fidp);
3793 memset(ncbp, 0, sizeof(NCB));
3795 ncbp->ncb_length = (unsigned short) finalCount;
3796 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3797 ncbp->ncb_lana_num = vcp->lana;
3798 ncbp->ncb_command = NCBSEND;
3799 ncbp->ncb_buffer = rawBuf;
3801 code = Netbios(ncbp);
3803 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3806 /* Give back raw buffer */
3807 lock_ObtainMutex(&smb_RawBufLock);
3808 *((char **) rawBuf) = smb_RawBufs;
3810 smb_RawBufs = rawBuf;
3811 lock_ReleaseMutex(&smb_RawBufLock);
3817 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3819 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3824 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3826 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3831 /* SMB_COM_NEGOTIATE */
3832 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3839 int VistaProtoIndex;
3840 int protoIndex; /* index we're using */
3845 char protocol_array[10][1024]; /* protocol signature of the client */
3846 int caps; /* capabilities */
3849 TIME_ZONE_INFORMATION tzi;
3851 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3854 namep = smb_GetSMBData(inp, &dbytes);
3857 coreProtoIndex = -1; /* not found */
3860 VistaProtoIndex = -1;
3861 while(namex < dbytes) {
3862 osi_Log1(smb_logp, "Protocol %s",
3863 osi_LogSaveString(smb_logp, namep+1));
3864 strcpy(protocol_array[tcounter], namep+1);
3866 /* namep points at the first protocol, or really, a 0x02
3867 * byte preceding the null-terminated ASCII name.
3869 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3870 coreProtoIndex = tcounter;
3872 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3873 v3ProtoIndex = tcounter;
3875 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3876 NTProtoIndex = tcounter;
3878 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3879 VistaProtoIndex = tcounter;
3882 /* compute size of protocol entry */
3883 entryLength = (int)strlen(namep+1);
3884 entryLength += 2; /* 0x02 bytes and null termination */
3886 /* advance over this protocol entry */
3887 namex += entryLength;
3888 namep += entryLength;
3889 tcounter++; /* which proto entry we're looking at */
3892 lock_ObtainMutex(&vcp->mx);
3894 if (VistaProtoIndex != -1) {
3895 protoIndex = VistaProtoIndex;
3896 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3899 if (NTProtoIndex != -1) {
3900 protoIndex = NTProtoIndex;
3901 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3903 else if (v3ProtoIndex != -1) {
3904 protoIndex = v3ProtoIndex;
3905 vcp->flags |= SMB_VCFLAG_USEV3;
3907 else if (coreProtoIndex != -1) {
3908 protoIndex = coreProtoIndex;
3909 vcp->flags |= SMB_VCFLAG_USECORE;
3911 else protoIndex = -1;
3912 lock_ReleaseMutex(&vcp->mx);
3914 if (protoIndex == -1)
3915 return CM_ERROR_INVAL;
3916 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3917 smb_SetSMBParm(outp, 0, protoIndex);
3918 if (smb_authType != SMB_AUTH_NONE) {
3919 smb_SetSMBParmByte(outp, 1,
3920 NEGOTIATE_SECURITY_USER_LEVEL |
3921 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3923 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3925 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3926 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3927 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3928 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3929 /* The session key is not a well documented field however most clients
3930 * will echo back the session key to the server. Currently we are using
3931 * the same value for all sessions. We should generate a random value
3932 * and store it into the vcp
3934 smb_SetSMBParmLong(outp, 7, 0x1a2b3c4d); /* session key */
3936 * Tried changing the capabilities to support for W2K - defect 117695
3937 * Maybe something else needs to be changed here?
3941 smb_SetSMBParmLong(outp, 9, 0x43fd);
3943 smb_SetSMBParmLong(outp, 9, 0x251);
3946 * 32-bit error codes *
3952 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3954 NTNEGOTIATE_CAPABILITY_DFS |
3956 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3957 NTNEGOTIATE_CAPABILITY_NTFIND |
3958 NTNEGOTIATE_CAPABILITY_RAWMODE |
3959 NTNEGOTIATE_CAPABILITY_NTSMB;
3961 if ( smb_authType == SMB_AUTH_EXTENDED )
3962 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3965 if ( smb_UseUnicode ) {
3966 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3970 smb_SetSMBParmLong(outp, 9, caps);
3972 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3973 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3974 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3976 GetTimeZoneInformation(&tzi);
3977 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3979 if (smb_authType == SMB_AUTH_NTLM) {
3980 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3981 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3982 /* paste in encryption key */
3983 datap = smb_GetSMBData(outp, NULL);
3984 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3985 /* and the faux domain name */
3986 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3987 datap + MSV1_0_CHALLENGE_LENGTH,
3988 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3989 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3993 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3995 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3997 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3999 datap = smb_GetSMBData(outp, NULL);
4000 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
4003 datap += sizeof(smb_ServerGUID);
4004 memcpy(datap, secBlob, secBlobLength);
4008 smb_SetSMBParmByte(outp, 16, 0);/* Challenge length */
4009 smb_SetSMBDataLength(outp, smb_ServerDomainNameLength);
4010 datap = smb_GetSMBData(outp, NULL);
4011 /* the faux domain name */
4012 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4014 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4017 else if (v3ProtoIndex != -1) {
4018 smb_SetSMBParm(outp, 0, protoIndex);
4020 /* NOTE: Extended authentication cannot be negotiated with v3
4021 * therefore we fail over to NTLM
4023 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4024 smb_SetSMBParm(outp, 1,
4025 NEGOTIATE_SECURITY_USER_LEVEL |
4026 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
4028 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4030 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4031 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
4032 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
4033 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
4034 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
4035 smb_SetSMBParm(outp, 7, 1);
4037 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
4038 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
4039 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
4041 GetTimeZoneInformation(&tzi);
4042 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
4044 /* NOTE: Extended authentication cannot be negotiated with v3
4045 * therefore we fail over to NTLM
4047 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4048 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
4049 smb_SetSMBParm(outp, 12, 0); /* resvd */
4050 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
4051 datap = smb_GetSMBData(outp, NULL);
4052 /* paste in a new encryption key */
4053 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4054 /* and the faux domain name */
4055 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4056 datap + MSV1_0_CHALLENGE_LENGTH,
4057 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4059 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4060 smb_SetSMBParm(outp, 12, 0); /* resvd */
4061 smb_SetSMBDataLength(outp, 0);
4064 else if (coreProtoIndex != -1) { /* not really supported anymore */
4065 smb_SetSMBParm(outp, 0, protoIndex);
4066 smb_SetSMBDataLength(outp, 0);
4071 void smb_CheckVCs(void)
4073 smb_vc_t * vcp, *nextp;
4074 smb_packet_t * outp = smb_GetPacket();
4077 lock_ObtainWrite(&smb_rctLock);
4078 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4080 if (vcp->magic != SMB_VC_MAGIC)
4081 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4082 __FILE__, __LINE__);
4084 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4086 smb_HoldVCNoLock(vcp);
4089 * obtain a reference to 'nextp' now because we drop the
4090 * smb_rctLock later and the list contents could change
4091 * or 'vcp' could be destroyed when released.
4095 smb_HoldVCNoLock(nextp);
4097 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4098 smb_ReleaseVCNoLock(vcp);
4102 smb_FormatResponsePacket(vcp, NULL, outp);
4103 smbp = (smb_t *)outp;
4104 outp->inCom = smbp->com = 0x2b /* Echo */;
4112 smb_SetSMBParm(outp, 0, 0);
4113 smb_SetSMBDataLength(outp, 0);
4114 lock_ReleaseWrite(&smb_rctLock);
4116 smb_SendPacket(vcp, outp);
4118 lock_ObtainWrite(&smb_rctLock);
4119 smb_ReleaseVCNoLock(vcp);
4121 lock_ReleaseWrite(&smb_rctLock);
4122 smb_FreePacket(outp);
4125 void smb_Daemon(void *parmp)
4127 afs_uint32 count = 0;
4128 smb_username_t **unpp;
4131 while(smbShutdownFlag == 0) {
4135 if (smbShutdownFlag == 1)
4138 if ((count % 72) == 0) { /* every five minutes */
4140 time_t old_localZero = smb_localZero;
4142 /* Initialize smb_localZero */
4143 myTime.tm_isdst = -1; /* compute whether on DST or not */
4144 myTime.tm_year = 70;
4150 smb_localZero = mktime(&myTime);
4152 #ifdef AFS_FREELANCE
4153 if ( smb_localZero != old_localZero )
4154 cm_noteLocalMountPointChange(FALSE);
4160 /* GC smb_username_t objects that will no longer be used */
4162 lock_ObtainWrite(&smb_rctLock);
4163 for ( unpp=&usernamesp; *unpp; ) {
4165 smb_username_t *unp;
4167 lock_ObtainMutex(&(*unpp)->mx);
4168 if ( (*unpp)->refCount > 0 ||
4169 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4170 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4172 else if (!smb_LogoffTokenTransfer ||
4173 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4175 lock_ReleaseMutex(&(*unpp)->mx);
4183 lock_FinalizeMutex(&unp->mx);
4189 cm_ReleaseUser(userp);
4191 unpp = &(*unpp)->nextp;
4194 lock_ReleaseWrite(&smb_rctLock);
4196 /* XXX GC dir search entries */
4200 void smb_WaitingLocksDaemon()
4202 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4203 smb_waitingLock_t *wl, *wlNext;
4206 smb_packet_t *inp, *outp;
4210 while (smbShutdownFlag == 0) {
4211 lock_ObtainWrite(&smb_globalLock);
4212 nwlRequest = smb_allWaitingLocks;
4213 if (nwlRequest == NULL) {
4214 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4219 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4226 lock_ObtainWrite(&smb_globalLock);
4228 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4230 wlRequest = nwlRequest;
4231 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4232 lock_ReleaseWrite(&smb_globalLock);
4236 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4237 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4240 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4241 code = CM_ERROR_LOCK_NOT_GRANTED;
4245 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4247 /* wl->state is either _DONE or _WAITING. _ERROR
4248 would no longer be on the queue. */
4249 code = cm_RetryLock( wl->lockp,
4250 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4253 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4254 } else if (code != CM_ERROR_WOULDBLOCK) {
4255 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4260 if (code == CM_ERROR_WOULDBLOCK) {
4263 if (wlRequest->msTimeout != 0xffffffff
4264 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4276 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4279 scp = wlRequest->scp;
4280 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4284 lock_ObtainWrite(&scp->rw);
4286 for (wl = wlRequest->locks; wl; wl = wlNext) {
4287 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4289 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4290 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4291 wl->LLength, wl->key, 0, NULL, &req);
4293 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4298 lock_ReleaseWrite(&scp->rw);
4302 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4305 for (wl = wlRequest->locks; wl; wl = wlNext) {
4306 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4307 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4312 vcp = wlRequest->vcp;
4313 inp = wlRequest->inp;
4314 outp = wlRequest->outp;
4315 ncbp = smb_GetNCB();
4316 ncbp->ncb_length = inp->ncb_length;
4317 inp->spacep = cm_GetSpace();
4319 /* Remove waitingLock from list */
4320 lock_ObtainWrite(&smb_globalLock);
4321 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4323 lock_ReleaseWrite(&smb_globalLock);
4325 /* Resume packet processing */
4327 smb_SetSMBDataLength(outp, 0);
4328 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4329 outp->resumeCode = code;
4331 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4334 cm_FreeSpace(inp->spacep);
4335 smb_FreePacket(inp);
4336 smb_FreePacket(outp);
4338 cm_ReleaseSCache(wlRequest->scp);
4341 } while (nwlRequest && smbShutdownFlag == 0);
4346 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4348 osi_Log0(smb_logp, "SMB receive get disk attributes");
4350 smb_SetSMBParm(outp, 0, 32000);
4351 smb_SetSMBParm(outp, 1, 64);
4352 smb_SetSMBParm(outp, 2, 1024);
4353 smb_SetSMBParm(outp, 3, 30000);
4354 smb_SetSMBParm(outp, 4, 0);
4355 smb_SetSMBDataLength(outp, 0);
4359 /* SMB_COM_TREE_CONNECT */
4360 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4364 unsigned short newTid;
4365 clientchar_t shareName[AFSPATHMAX];
4366 clientchar_t *sharePath;
4369 clientchar_t *pathp;
4372 osi_Log0(smb_logp, "SMB receive tree connect");
4374 /* parse input parameters */
4377 tbp = smb_GetSMBData(inp, NULL);
4378 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4380 return CM_ERROR_BADSMB;
4382 tp = cm_ClientStrRChr(pathp, '\\');
4384 return CM_ERROR_BADSMB;
4385 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4387 lock_ObtainMutex(&vcp->mx);
4388 newTid = vcp->tidCounter++;
4389 lock_ReleaseMutex(&vcp->mx);
4391 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4392 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4394 return CM_ERROR_BADSMB;
4395 userp = smb_GetUserFromUID(uidp);
4396 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4397 smb_ReleaseUID(uidp);
4399 smb_ReleaseTID(tidp, FALSE);
4400 return CM_ERROR_BADSHARENAME;
4402 lock_ObtainMutex(&tidp->mx);
4403 tidp->userp = userp;
4404 tidp->pathname = sharePath;
4405 lock_ReleaseMutex(&tidp->mx);
4406 smb_ReleaseTID(tidp, FALSE);
4408 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4409 smb_SetSMBParm(rsp, 1, newTid);
4410 smb_SetSMBDataLength(rsp, 0);
4412 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4416 /* set maskp to the mask part of the incoming path.
4417 * Mask is 11 bytes long (8.3 with the dot elided).
4418 * Returns true if succeeds with a valid name, otherwise it does
4419 * its best, but returns false.
4421 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4429 /* starts off valid */
4432 /* mask starts out all blanks */
4433 memset(maskp, ' ', 11);
4436 /* find last backslash, or use whole thing if there is none */
4437 tp = cm_ClientStrRChr(pathp, '\\');
4441 tp++; /* skip slash */
4445 /* names starting with a dot are illegal */
4453 if (tc == '.' || tc == '"')
4461 /* if we get here, tp point after the dot */
4462 up = maskp+8; /* ext goes here */
4469 if (tc == '.' || tc == '"')
4472 /* copy extension if not too long */
4482 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4484 clientchar_t umask[11];
4492 /* XXX redo this, calling cm_MatchMask with a converted mask */
4494 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4498 /* otherwise, we have a valid 8.3 name; see if we have a match,
4499 * treating '?' as a wildcard in maskp (but not in the file name).
4501 tp1 = umask; /* real name, in mask format */
4502 tp2 = maskp; /* mask, in mask format */
4503 for(i=0; i<11; i++) {
4504 tc1 = *tp1++; /* clientchar_t from real name */
4505 tc2 = *tp2++; /* clientchar_t from mask */
4506 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4507 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4510 if (tc2 == '?' && tc1 != ' ')
4517 /* we got a match */
4521 clientchar_t *smb_FindMask(clientchar_t *pathp)
4525 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4528 return tp+1; /* skip the slash */
4530 return pathp; /* no slash, return the entire path */
4533 /* SMB_COM_SEARCH for a volume label
4535 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4536 dispatch function.) */
4537 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4539 clientchar_t *pathp;
4541 clientchar_t mask[12];
4542 unsigned char *statBlockp;
4543 unsigned char initStatBlock[21];
4546 osi_Log0(smb_logp, "SMB receive search volume");
4548 /* pull pathname and stat block out of request */
4549 tp = smb_GetSMBData(inp, NULL);
4550 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4551 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4553 return CM_ERROR_BADSMB;
4554 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4555 osi_assertx(statBlockp != NULL, "null statBlock");
4557 statBlockp = initStatBlock;
4561 /* for returning to caller */
4562 smb_Get8Dot3MaskFromPath(mask, pathp);
4564 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4565 tp = smb_GetSMBData(outp, NULL);
4567 *tp++ = 43; /* bytes in a dir entry */
4568 *tp++ = 0; /* high byte in counter */
4570 /* now marshall the dir entry, starting with the search status */
4571 *tp++ = statBlockp[0]; /* Reserved */
4572 memcpy(tp, mask, 11); tp += 11; /* FileName */
4574 /* now pass back server use info, with 1st byte non-zero */
4576 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4578 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4580 *tp++ = 0x8; /* attribute: volume */
4590 /* 4 byte file size */
4596 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4599 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4600 memset(tp, ' ', 13);
4603 /* set the length of the data part of the packet to 43 + 3, for the dir
4604 * entry plus the 5 and the length fields.
4606 smb_SetSMBDataLength(outp, 46);
4611 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4612 clientchar_t * tidPathp, clientchar_t * relPathp,
4613 cm_user_t *userp, cm_req_t *reqp)
4621 smb_dirListPatch_t *patchp;
4622 smb_dirListPatch_t *npatchp;
4623 clientchar_t path[AFSPATHMAX];
4625 afs_int32 mustFake = 0;
4627 code = cm_FindACLCache(dscp, userp, &rights);
4629 lock_ObtainWrite(&dscp->rw);
4630 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4631 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4632 lock_ReleaseWrite(&dscp->rw);
4633 if (code == CM_ERROR_NOACCESS) {
4641 if (!mustFake) { /* Bulk Stat */
4643 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4645 memset(bsp, 0, sizeof(cm_bulkStat_t));
4647 for (patchp = *dirPatchespp, count=0;
4649 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4650 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4654 if (lock_TryWrite(&tscp->rw)) {
4655 /* we have an entry that we can look at */
4656 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4657 /* we have a callback on it. Don't bother
4658 * fetching this stat entry, since we're happy
4659 * with the info we have.
4661 lock_ReleaseWrite(&tscp->rw);
4662 cm_ReleaseSCache(tscp);
4665 lock_ReleaseWrite(&tscp->rw);
4667 cm_ReleaseSCache(tscp);
4671 bsp->fids[i].Volume = patchp->fid.volume;
4672 bsp->fids[i].Vnode = patchp->fid.vnode;
4673 bsp->fids[i].Unique = patchp->fid.unique;
4675 if (bsp->counter == AFSCBMAX) {
4676 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4677 memset(bsp, 0, sizeof(cm_bulkStat_t));
4681 if (bsp->counter > 0)
4682 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4687 for (patchp = *dirPatchespp; patchp; patchp =
4688 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4690 dptr = patchp->dptr;
4692 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4693 relPathp ? relPathp : _C(""), patchp->dep->name);
4694 reqp->relPathp = path;
4695 reqp->tidPathp = tidPathp;
4697 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4698 reqp->relPathp = reqp->tidPathp = NULL;
4701 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4702 *dptr++ = SMB_ATTR_HIDDEN;
4705 lock_ObtainWrite(&scp->rw);
4706 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4707 lock_ReleaseWrite(&scp->rw);
4709 /* set the attribute */
4710 switch (scp->fileType) {
4711 case CM_SCACHETYPE_DIRECTORY:
4712 case CM_SCACHETYPE_MOUNTPOINT:
4713 case CM_SCACHETYPE_INVALID:
4714 attr = SMB_ATTR_DIRECTORY;
4716 case CM_SCACHETYPE_SYMLINK:
4717 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4718 attr = SMB_ATTR_DIRECTORY;
4720 attr = SMB_ATTR_NORMAL;
4723 /* if we get here we either have a normal file
4724 * or we have a file for which we have never
4725 * received status info. In this case, we can
4726 * check the even/odd value of the entry's vnode.
4727 * odd means it is to be treated as a directory
4728 * and even means it is to be treated as a file.
4730 if (mustFake && (scp->fid.vnode & 0x1))
4731 attr = SMB_ATTR_DIRECTORY;
4733 attr = SMB_ATTR_NORMAL;
4737 /* 1969-12-31 23:59:58 +00*/
4738 dosTime = 0xEBBFBF7D;
4741 shortTemp = (unsigned short) (dosTime & 0xffff);
4742 *((u_short *)dptr) = shortTemp;
4745 /* and copy out date */
4746 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4747 *((u_short *)dptr) = shortTemp;
4750 /* copy out file length */
4751 *((u_long *)dptr) = 0;
4754 lock_ConvertWToR(&scp->rw);
4755 attr = smb_Attributes(scp);
4756 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4757 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4758 attr |= SMB_ATTR_HIDDEN;
4762 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4765 shortTemp = (unsigned short) (dosTime & 0xffff);
4766 *((u_short *)dptr) = shortTemp;
4769 /* and copy out date */
4770 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4771 *((u_short *)dptr) = shortTemp;
4774 /* copy out file length */
4775 *((u_long *)dptr) = scp->length.LowPart;
4777 lock_ReleaseRead(&scp->rw);
4779 cm_ReleaseSCache(scp);
4782 /* now free the patches */
4783 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4784 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4788 /* and mark the list as empty */
4789 *dirPatchespp = NULL;
4795 /* SMB_COM_SEARCH */
4796 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4802 clientchar_t *pathp;
4803 cm_dirEntry_t *dep = 0;
4805 smb_dirListPatch_t *dirListPatchesp;
4806 smb_dirListPatch_t *curPatchp;
4810 osi_hyper_t dirLength;
4811 osi_hyper_t bufferOffset;
4812 osi_hyper_t curOffset;
4814 unsigned char *inCookiep;
4815 smb_dirSearch_t *dsp;
4819 unsigned long clientCookie;
4820 cm_pageHeader_t *pageHeaderp;
4821 cm_user_t *userp = NULL;
4823 clientchar_t mask[12];
4825 long nextEntryCookie;
4826 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4827 char resByte; /* reserved byte from the cookie */
4828 char *op; /* output data ptr */
4829 char *origOp; /* original value of op */
4830 cm_space_t *spacep; /* for pathname buffer */
4834 clientchar_t *tidPathp = 0;
4841 maxCount = smb_GetSMBParm(inp, 0);
4843 dirListPatchesp = NULL;
4845 caseFold = CM_FLAG_CASEFOLD;
4847 tp = smb_GetSMBData(inp, NULL);
4848 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4849 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4851 return CM_ERROR_BADSMB;
4853 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4855 return CM_ERROR_BADSMB;
4857 /* We can handle long names */
4858 if (vcp->flags & SMB_VCFLAG_USENT)
4859 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4861 /* make sure we got a whole search status */
4862 if (dataLength < 21) {
4863 nextCookie = 0; /* start at the beginning of the dir */
4866 attribute = smb_GetSMBParm(inp, 1);
4868 /* handle volume info in another function */
4869 if (attribute & 0x8)
4870 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4872 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4873 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4875 if (*pathp == 0) { /* null pathp, treat as root dir */
4876 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4877 return CM_ERROR_NOFILES;
4881 dsp = smb_NewDirSearch(0);
4882 dsp->attribute = attribute;
4883 smb_Get8Dot3MaskFromPath(mask, pathp);
4884 memcpy(dsp->mask, mask, 12);
4886 /* track if this is likely to match a lot of entries */
4887 if (smb_Is8Dot3StarMask(mask))
4892 /* pull the next cookie value out of the search status block */
4893 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4894 + (inCookiep[16]<<24);
4895 dsp = smb_FindDirSearch(inCookiep[12]);
4897 /* can't find dir search status; fatal error */
4898 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4899 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4900 return CM_ERROR_BADFD;
4902 attribute = dsp->attribute;
4903 resByte = inCookiep[0];
4905 /* copy out client cookie, in host byte order. Don't bother
4906 * interpreting it, since we're just passing it through, anyway.
4908 memcpy(&clientCookie, &inCookiep[17], 4);
4910 memcpy(mask, dsp->mask, 12);
4912 /* assume we're doing a star match if it has continued for more
4918 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4919 nextCookie, dsp->cookie, attribute);
4921 userp = smb_GetUserFromVCP(vcp, inp);
4923 /* try to get the vnode for the path name next */
4924 lock_ObtainMutex(&dsp->mx);
4927 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4931 spacep = inp->spacep;
4932 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4933 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4935 lock_ReleaseMutex(&dsp->mx);
4936 cm_ReleaseUser(userp);
4937 smb_DeleteDirSearch(dsp);
4938 smb_ReleaseDirSearch(dsp);
4939 return CM_ERROR_NOFILES;
4941 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4942 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4944 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
4945 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4948 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4951 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4952 cm_ReleaseSCache(scp);
4953 lock_ReleaseMutex(&dsp->mx);
4954 cm_ReleaseUser(userp);
4955 smb_DeleteDirSearch(dsp);
4956 smb_ReleaseDirSearch(dsp);
4957 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4958 return CM_ERROR_PATH_NOT_COVERED;
4960 return CM_ERROR_NOSUCHPATH;
4962 #endif /* DFS_SUPPORT */
4965 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4966 /* we need one hold for the entry we just stored into,
4967 * and one for our own processing. When we're done with this
4968 * function, we'll drop the one for our own processing.
4969 * We held it once from the namei call, and so we do another hold
4973 lock_ObtainWrite(&scp->rw);
4974 dsp->flags |= SMB_DIRSEARCH_BULKST;
4975 lock_ReleaseWrite(&scp->rw);
4978 lock_ReleaseMutex(&dsp->mx);
4980 cm_ReleaseUser(userp);
4981 smb_DeleteDirSearch(dsp);
4982 smb_ReleaseDirSearch(dsp);
4986 /* reserves space for parameter; we'll adjust it again later to the
4987 * real count of the # of entries we returned once we've actually
4988 * assembled the directory listing.
4990 smb_SetSMBParm(outp, 0, 0);
4992 /* get the directory size */
4993 lock_ObtainWrite(&scp->rw);
4994 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4995 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4997 lock_ReleaseWrite(&scp->rw);
4998 cm_ReleaseSCache(scp);
4999 cm_ReleaseUser(userp);
5000 smb_DeleteDirSearch(dsp);
5001 smb_ReleaseDirSearch(dsp);
5005 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5007 dirLength = scp->length;
5009 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5010 curOffset.HighPart = 0;
5011 curOffset.LowPart = nextCookie;
5012 origOp = op = smb_GetSMBData(outp, NULL);
5013 /* and write out the basic header */
5014 *op++ = 5; /* variable block */
5015 op += 2; /* skip vbl block length; we'll fill it in later */
5019 clientchar_t *actualName = NULL;
5020 int free_actualName = 0;
5021 clientchar_t shortName[13];
5022 clientchar_t *shortNameEnd;
5024 /* make sure that curOffset.LowPart doesn't point to the first
5025 * 32 bytes in the 2nd through last dir page, and that it doesn't
5026 * point at the first 13 32-byte chunks in the first dir page,
5027 * since those are dir and page headers, and don't contain useful
5030 temp = curOffset.LowPart & (2048-1);
5031 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5032 /* we're in the first page */
5033 if (temp < 13*32) temp = 13*32;
5036 /* we're in a later dir page */
5037 if (temp < 32) temp = 32;
5040 /* make sure the low order 5 bits are zero */
5043 /* now put temp bits back ito curOffset.LowPart */
5044 curOffset.LowPart &= ~(2048-1);
5045 curOffset.LowPart |= temp;
5047 /* check if we've returned all the names that will fit in the
5050 if (returnedNames >= maxCount) {
5051 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5052 returnedNames, maxCount);
5056 /* check if we've passed the dir's EOF */
5057 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5059 /* see if we can use the bufferp we have now; compute in which page
5060 * the current offset would be, and check whether that's the offset
5061 * of the buffer we have. If not, get the buffer.
5063 thyper.HighPart = curOffset.HighPart;
5064 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5065 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5068 buf_Release(bufferp);
5071 lock_ReleaseWrite(&scp->rw);
5072 code = buf_Get(scp, &thyper, &req, &bufferp);
5073 lock_ObtainMutex(&dsp->mx);
5075 /* now, if we're doing a star match, do bulk fetching of all of
5076 * the status info for files in the dir.
5079 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5081 lock_ObtainWrite(&scp->rw);
5082 lock_ReleaseMutex(&dsp->mx);
5084 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5088 bufferOffset = thyper;
5090 /* now get the data in the cache */
5092 code = cm_SyncOp(scp, bufferp, userp, &req,
5094 CM_SCACHESYNC_NEEDCALLBACK |
5095 CM_SCACHESYNC_READ);
5097 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5101 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5103 if (cm_HaveBuffer(scp, bufferp, 0)) {
5104 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5108 /* otherwise, load the buffer and try again */
5109 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5111 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5112 scp, bufferp, code);
5117 buf_Release(bufferp);
5121 } /* if (wrong buffer) ... */
5123 /* now we have the buffer containing the entry we're interested in; copy
5124 * it out if it represents a non-deleted entry.
5126 entryInDir = curOffset.LowPart & (2048-1);
5127 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5129 /* page header will help tell us which entries are free. Page header
5130 * can change more often than once per buffer, since AFS 3 dir page size
5131 * may be less than (but not more than a buffer package buffer.
5133 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5134 temp &= ~(2048 - 1); /* turn off intra-page bits */
5135 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5137 /* now determine which entry we're looking at in the page. If it is
5138 * free (there's a free bitmap at the start of the dir), we should
5139 * skip these 32 bytes.
5141 slotInPage = (entryInDir & 0x7e0) >> 5;
5142 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5143 /* this entry is free */
5144 numDirChunks = 1; /* only skip this guy */
5148 tp = bufferp->datap + entryInBuffer;
5149 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5151 /* while we're here, compute the next entry's location, too,
5152 * since we'll need it when writing out the cookie into the dir
5155 * XXXX Probably should do more sanity checking.
5157 numDirChunks = cm_NameEntries(dep->name, NULL);
5159 /* compute the offset of the cookie representing the next entry */
5160 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5162 /* Compute 8.3 name if necessary */
5163 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5164 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5167 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5168 actualName = shortName;
5169 free_actualName = 0;
5171 free_actualName = 1;
5174 if (actualName == NULL) {
5175 /* Couldn't convert the name for some reason */
5176 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5177 osi_LogSaveString(smb_logp, dep->name));
5181 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5182 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5183 osi_LogSaveClientString(smb_logp, actualName));
5185 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5186 /* this is one of the entries to use: it is not deleted
5187 * and it matches the star pattern we're looking for.
5190 /* Eliminate entries that don't match requested
5193 /* no hidden files */
5194 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5195 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5199 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5201 /* We have already done the cm_TryBulkStat above */
5202 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5203 fileType = cm_FindFileType(&fid);
5204 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5205 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5207 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5208 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5209 fileType == CM_SCACHETYPE_DFSLINK ||
5210 fileType == CM_SCACHETYPE_INVALID)
5211 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5216 memcpy(op, mask, 11); op += 11;
5217 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5218 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5219 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5220 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5221 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5222 memcpy(op, &clientCookie, 4); op += 4;
5224 /* now we emit the attribute. This is sort of tricky,
5225 * since we need to really stat the file to find out
5226 * what type of entry we've got. Right now, we're
5227 * copying out data from a buffer, while holding the
5228 * scp locked, so it isn't really convenient to stat
5229 * something now. We'll put in a place holder now,
5230 * and make a second pass before returning this to get
5231 * the real attributes. So, we just skip the data for
5232 * now, and adjust it later. We allocate a patch
5233 * record to make it easy to find this point later.
5234 * The replay will happen at a time when it is safe to
5235 * unlock the directory.
5237 curPatchp = malloc(sizeof(*curPatchp));
5238 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5239 curPatchp->dptr = op;
5240 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5242 /* do hidden attribute here since name won't be around when applying
5246 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5247 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5249 curPatchp->flags = 0;
5251 op += 9; /* skip attr, time, date and size */
5253 /* zero out name area. The spec says to pad with
5254 * spaces, but Samba doesn't, and neither do we.
5258 /* finally, we get to copy out the name; we know that
5259 * it fits in 8.3 or the pattern wouldn't match, but it
5260 * never hurts to be sure.
5262 cm_ClientStringToUtf8(actualName, -1, op, 13);
5263 if (smb_StoreAnsiFilenames)
5265 /* This is a UCHAR field, which is ASCII even if Unicode
5268 /* Uppercase if requested by client */
5269 if (!KNOWS_LONG_NAMES(inp))
5274 /* now, adjust the # of entries copied */
5276 } /* if we're including this name */
5279 if (free_actualName && actualName) {
5284 /* and adjust curOffset to be where the new cookie is */
5285 thyper.HighPart = 0;
5286 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5287 curOffset = LargeIntegerAdd(thyper, curOffset);
5288 } /* while copying data for dir listing */
5290 /* release the mutex */
5291 lock_ReleaseWrite(&scp->rw);
5293 buf_Release(bufferp);
5297 /* apply and free last set of patches; if not doing a star match, this
5298 * will be empty, but better safe (and freeing everything) than sorry.
5300 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5302 /* special return code for unsuccessful search */
5303 if (code == 0 && dataLength < 21 && returnedNames == 0)
5304 code = CM_ERROR_NOFILES;
5306 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5307 returnedNames, code);
5310 smb_DeleteDirSearch(dsp);
5311 smb_ReleaseDirSearch(dsp);
5312 cm_ReleaseSCache(scp);
5313 cm_ReleaseUser(userp);
5317 /* finalize the output buffer */
5318 smb_SetSMBParm(outp, 0, returnedNames);
5319 temp = (long) (op - origOp);
5320 smb_SetSMBDataLength(outp, temp);
5322 /* the data area is a variable block, which has a 5 (already there)
5323 * followed by the length of the # of data bytes. We now know this to
5324 * be "temp," although that includes the 3 bytes of vbl block header.
5325 * Deduct for them and fill in the length field.
5327 temp -= 3; /* deduct vbl block info */
5328 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5329 origOp[1] = (unsigned char)(temp & 0xff);
5330 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5331 if (returnedNames == 0)
5332 smb_DeleteDirSearch(dsp);
5333 smb_ReleaseDirSearch(dsp);
5334 cm_ReleaseSCache(scp);
5335 cm_ReleaseUser(userp);
5340 /* verify that this is a valid path to a directory. I don't know why they
5341 * don't use the get file attributes call.
5343 * SMB_COM_CHECK_DIRECTORY
5345 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5347 clientchar_t *pathp;
5349 cm_scache_t *rootScp;
5350 cm_scache_t *newScp;
5354 clientchar_t *tidPathp;
5360 pdata = smb_GetSMBData(inp, NULL);
5361 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5363 return CM_ERROR_BADSMB;
5364 osi_Log1(smb_logp, "SMB receive check path %S",
5365 osi_LogSaveClientString(smb_logp, pathp));
5367 userp = smb_GetUserFromVCP(vcp, inp);
5369 rootScp = cm_RootSCachep(userp, &req);
5371 caseFold = CM_FLAG_CASEFOLD;
5373 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5375 cm_ReleaseUser(userp);
5376 return CM_ERROR_NOSUCHPATH;
5378 code = cm_NameI(rootScp, pathp,
5379 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5380 userp, tidPathp, &req, &newScp);
5383 cm_ReleaseUser(userp);
5388 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5389 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5390 cm_ReleaseSCache(newScp);
5391 cm_ReleaseUser(userp);
5392 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5393 return CM_ERROR_PATH_NOT_COVERED;
5395 return CM_ERROR_NOSUCHPATH;
5397 #endif /* DFS_SUPPORT */
5399 /* now lock the vnode with a callback; returns with newScp locked */
5400 lock_ObtainWrite(&newScp->rw);
5401 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5402 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5404 if (code != CM_ERROR_NOACCESS) {
5405 lock_ReleaseWrite(&newScp->rw);
5406 cm_ReleaseSCache(newScp);
5407 cm_ReleaseUser(userp);
5411 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5414 attrs = smb_Attributes(newScp);
5416 if (!(attrs & SMB_ATTR_DIRECTORY))
5417 code = CM_ERROR_NOTDIR;
5419 lock_ReleaseWrite(&newScp->rw);
5421 cm_ReleaseSCache(newScp);
5422 cm_ReleaseUser(userp);
5426 /* SMB_COM_SET_INFORMATION */
5427 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5429 clientchar_t *pathp;
5431 cm_scache_t *rootScp;
5432 unsigned short attribute;
5434 cm_scache_t *newScp;
5438 clientchar_t *tidPathp;
5444 /* decode basic attributes we're passed */
5445 attribute = smb_GetSMBParm(inp, 0);
5446 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5448 datap = smb_GetSMBData(inp, NULL);
5449 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5451 return CM_ERROR_BADSMB;
5453 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5454 dosTime, attribute);
5456 userp = smb_GetUserFromVCP(vcp, inp);
5458 rootScp = cm_RootSCachep(userp, &req);
5460 caseFold = CM_FLAG_CASEFOLD;
5462 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5464 cm_ReleaseUser(userp);
5465 return CM_ERROR_NOSUCHFILE;
5467 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5468 tidPathp, &req, &newScp);
5471 cm_ReleaseUser(userp);
5476 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5477 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5478 cm_ReleaseSCache(newScp);
5479 cm_ReleaseUser(userp);
5480 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5481 return CM_ERROR_PATH_NOT_COVERED;
5483 return CM_ERROR_NOSUCHPATH;
5485 #endif /* DFS_SUPPORT */
5487 /* now lock the vnode with a callback; returns with newScp locked; we
5488 * need the current status to determine what the new status is, in some
5491 lock_ObtainWrite(&newScp->rw);
5492 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5493 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5495 lock_ReleaseWrite(&newScp->rw);
5496 cm_ReleaseSCache(newScp);
5497 cm_ReleaseUser(userp);
5501 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5503 /* Check for RO volume */
5504 if (newScp->flags & CM_SCACHEFLAG_RO) {
5505 lock_ReleaseWrite(&newScp->rw);
5506 cm_ReleaseSCache(newScp);
5507 cm_ReleaseUser(userp);
5508 return CM_ERROR_READONLY;
5511 /* prepare for setattr call */
5514 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5515 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5517 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5518 /* we're told to make a writable file read-only */
5519 attr.unixModeBits = newScp->unixModeBits & ~0222;
5520 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5522 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5523 /* we're told to make a read-only file writable */
5524 attr.unixModeBits = newScp->unixModeBits | 0222;
5525 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5527 lock_ReleaseWrite(&newScp->rw);
5529 /* now call setattr */
5531 code = cm_SetAttr(newScp, &attr, userp, &req);
5535 cm_ReleaseSCache(newScp);
5536 cm_ReleaseUser(userp);
5542 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5544 clientchar_t *pathp;
5546 cm_scache_t *rootScp;
5547 cm_scache_t *newScp, *dscp;
5552 clientchar_t *tidPathp;
5554 clientchar_t *lastComp;
5560 datap = smb_GetSMBData(inp, NULL);
5561 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5563 return CM_ERROR_BADSMB;
5565 if (*pathp == 0) /* null path */
5568 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5569 osi_LogSaveClientString(smb_logp, pathp));
5571 userp = smb_GetUserFromVCP(vcp, inp);
5573 rootScp = cm_RootSCachep(userp, &req);
5575 /* we shouldn't need this for V3 requests, but we seem to */
5576 caseFold = CM_FLAG_CASEFOLD;
5578 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5580 cm_ReleaseUser(userp);
5581 return CM_ERROR_NOSUCHFILE;
5585 * XXX Strange hack XXX
5587 * As of Patch 5 (16 July 97), we are having the following problem:
5588 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5589 * requests to look up "desktop.ini" in all the subdirectories.
5590 * This can cause zillions of timeouts looking up non-existent cells
5591 * and volumes, especially in the top-level directory.
5593 * We have not found any way to avoid this or work around it except
5594 * to explicitly ignore the requests for mount points that haven't
5595 * yet been evaluated and for directories that haven't yet been
5598 * We should modify this hack to provide a fake desktop.ini file
5599 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5601 spacep = inp->spacep;
5602 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5603 #ifndef SPECIAL_FOLDERS
5604 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5605 code = cm_NameI(rootScp, spacep->wdata,
5606 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5607 userp, tidPathp, &req, &dscp);
5610 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5611 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5613 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5614 return CM_ERROR_PATH_NOT_COVERED;
5616 return CM_ERROR_NOSUCHPATH;
5618 #endif /* DFS_SUPPORT */
5619 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5620 code = CM_ERROR_NOSUCHFILE;
5621 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5622 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
5627 code = CM_ERROR_NOSUCHFILE;
5629 cm_ReleaseSCache(dscp);
5631 cm_ReleaseUser(userp);
5635 else if (code != CM_ERROR_NOSUCHFILE &&
5636 code != CM_ERROR_NOSUCHPATH &&
5637 code != CM_ERROR_BPLUS_NOMATCH)
5639 cm_ReleaseUser(userp);
5643 #endif /* SPECIAL_FOLDERS */
5645 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5646 tidPathp, &req, &newScp);
5648 cm_ReleaseUser(userp);
5653 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5654 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5655 cm_ReleaseSCache(newScp);
5656 cm_ReleaseUser(userp);
5657 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5658 return CM_ERROR_PATH_NOT_COVERED;
5660 return CM_ERROR_NOSUCHPATH;
5662 #endif /* DFS_SUPPORT */
5664 /* now lock the vnode with a callback; returns with newScp locked */
5665 lock_ObtainWrite(&newScp->rw);
5666 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5667 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5669 lock_ReleaseWrite(&newScp->rw);
5670 cm_ReleaseSCache(newScp);
5671 cm_ReleaseUser(userp);
5675 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5677 attrs = smb_Attributes(newScp);
5679 smb_SetSMBParm(outp, 0, attrs);
5681 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5682 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5683 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5684 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5685 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5686 smb_SetSMBParm(outp, 5, 0);
5687 smb_SetSMBParm(outp, 6, 0);
5688 smb_SetSMBParm(outp, 7, 0);
5689 smb_SetSMBParm(outp, 8, 0);
5690 smb_SetSMBParm(outp, 9, 0);
5691 smb_SetSMBDataLength(outp, 0);
5692 lock_ReleaseWrite(&newScp->rw);
5694 cm_ReleaseSCache(newScp);
5695 cm_ReleaseUser(userp);
5700 /* SMB_COM_TREE_DISCONNECT */
5701 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5705 osi_Log0(smb_logp, "SMB receive tree disconnect");
5707 /* find the tree and free it */
5708 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5710 lock_ObtainWrite(&smb_rctLock);
5712 smb_ReleaseTID(tidp, TRUE);
5713 lock_ReleaseWrite(&smb_rctLock);
5720 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5723 clientchar_t *pathp;
5724 clientchar_t *lastNamep;
5733 clientchar_t *tidPathp;
5739 datap = smb_GetSMBData(inp, NULL);
5740 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5742 return CM_ERROR_BADSMB;
5744 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5746 #ifdef DEBUG_VERBOSE
5750 hexpath = osi_HexifyString( pathp );
5751 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5756 share = smb_GetSMBParm(inp, 0);
5757 attribute = smb_GetSMBParm(inp, 1);
5759 spacep = inp->spacep;
5760 /* smb_StripLastComponent will strip "::$DATA" if present */
5761 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5763 if (!cm_IsValidClientString(pathp)) {
5765 clientchar_t * hexp;
5767 hexp = cm_GetRawCharsAlloc(pathp, -1);
5768 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5769 osi_LogSaveClientString(smb_logp, hexp));
5773 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5775 return CM_ERROR_BADNTFILENAME;
5778 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5779 /* special case magic file name for receiving IOCTL requests
5780 * (since IOCTL calls themselves aren't getting through).
5782 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5783 smb_SetupIoctlFid(fidp, spacep);
5784 smb_SetSMBParm(outp, 0, fidp->fid);
5785 smb_SetSMBParm(outp, 1, 0); /* attrs */
5786 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5787 smb_SetSMBParm(outp, 3, 0);
5788 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5789 smb_SetSMBParm(outp, 5, 0x7fff);
5790 /* pass the open mode back */
5791 smb_SetSMBParm(outp, 6, (share & 0xf));
5792 smb_SetSMBDataLength(outp, 0);
5793 smb_ReleaseFID(fidp);
5797 userp = smb_GetUserFromVCP(vcp, inp);
5799 caseFold = CM_FLAG_CASEFOLD;
5801 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5803 cm_ReleaseUser(userp);
5804 return CM_ERROR_NOSUCHPATH;
5806 code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
5807 tidPathp, &req, &scp);
5810 cm_ReleaseUser(userp);
5815 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5816 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5817 cm_ReleaseSCache(scp);
5818 cm_ReleaseUser(userp);
5819 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5820 return CM_ERROR_PATH_NOT_COVERED;
5822 return CM_ERROR_NOSUCHPATH;
5824 #endif /* DFS_SUPPORT */
5826 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5828 cm_ReleaseSCache(scp);
5829 cm_ReleaseUser(userp);
5833 /* don't need callback to check file type, since file types never
5834 * change, and namei and cm_Lookup all stat the object at least once on
5835 * a successful return.
5837 if (scp->fileType != CM_SCACHETYPE_FILE) {
5838 cm_ReleaseSCache(scp);
5839 cm_ReleaseUser(userp);
5840 return CM_ERROR_ISDIR;
5843 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5844 osi_assertx(fidp, "null smb_fid_t");
5846 lock_ObtainMutex(&fidp->mx);
5847 if ((share & 0xf) == 0)
5848 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5849 else if ((share & 0xf) == 1)
5850 fidp->flags |= SMB_FID_OPENWRITE;
5852 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5856 fidp->userp = userp;
5858 /* and a pointer to the vnode */
5860 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5861 lock_ObtainWrite(&scp->rw);
5862 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5864 smb_SetSMBParm(outp, 0, fidp->fid);
5865 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5866 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5867 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5868 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5869 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5870 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5871 /* pass the open mode back; XXXX add access checks */
5872 smb_SetSMBParm(outp, 6, (share & 0xf));
5873 smb_SetSMBDataLength(outp, 0);
5874 lock_ReleaseMutex(&fidp->mx);
5875 lock_ReleaseRead(&scp->rw);
5878 cm_Open(scp, 0, userp);
5880 /* send and free packet */
5881 smb_ReleaseFID(fidp);
5882 cm_ReleaseUser(userp);
5883 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5887 typedef struct smb_unlinkRock {
5892 clientchar_t *maskp; /* pointer to the star pattern */
5895 cm_dirEntryList_t * matches;
5898 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5901 smb_unlinkRock_t *rockp;
5904 normchar_t matchName[MAX_PATH];
5908 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5909 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5910 caseFold |= CM_FLAG_8DOT3;
5912 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5913 /* Can't convert name */
5914 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5915 osi_LogSaveString(smb_logp, dep->name));
5919 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5921 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5922 !cm_Is8Dot3(matchName)) {
5923 cm_Gen8Dot3Name(dep, matchName, NULL);
5924 /* 8.3 matches are always case insensitive */
5925 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5928 osi_Log1(smb_logp, "Found match %S",
5929 osi_LogSaveClientString(smb_logp, matchName));
5931 cm_DirEntryListAdd(dep->name, &rockp->matches);
5935 /* If we made a case sensitive exact match, we might as well quit now. */
5936 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5937 code = CM_ERROR_STOPNOW;
5946 /* SMB_COM_DELETE */
5947 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5951 clientchar_t *pathp;
5955 clientchar_t *lastNamep;
5956 smb_unlinkRock_t rock;
5960 clientchar_t *tidPathp;
5964 memset(&rock, 0, sizeof(rock));
5966 attribute = smb_GetSMBParm(inp, 0);
5968 tp = smb_GetSMBData(inp, NULL);
5969 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5971 return CM_ERROR_BADSMB;
5973 osi_Log1(smb_logp, "SMB receive unlink %S",
5974 osi_LogSaveClientString(smb_logp, pathp));
5976 spacep = inp->spacep;
5977 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5979 userp = smb_GetUserFromVCP(vcp, inp);
5981 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5983 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5985 cm_ReleaseUser(userp);
5986 return CM_ERROR_NOSUCHPATH;
5988 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
5991 cm_ReleaseUser(userp);
5996 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5997 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5998 cm_ReleaseSCache(dscp);
5999 cm_ReleaseUser(userp);
6000 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6001 return CM_ERROR_PATH_NOT_COVERED;
6003 return CM_ERROR_NOSUCHPATH;
6005 #endif /* DFS_SUPPORT */
6007 /* otherwise, scp points to the parent directory. */
6014 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
6016 code = CM_ERROR_NOSUCHFILE;
6019 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6022 thyper.HighPart = 0;
6027 rock.matches = NULL;
6029 /* Now, if we aren't dealing with a wildcard match, we first try an exact
6030 * match. If that fails, we do a case insensitve match.
6032 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6033 !smb_IsStarMask(rock.maskp)) {
6034 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6037 thyper.HighPart = 0;
6038 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6043 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6045 if (code == CM_ERROR_STOPNOW)
6048 if (code == 0 && rock.matches) {
6049 cm_dirEntryList_t * entry;
6051 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6052 normchar_t normalizedName[MAX_PATH];
6054 /* Note: entry->name is a non-normalized name */
6056 osi_Log1(smb_logp, "Unlinking %s",
6057 osi_LogSaveString(smb_logp, entry->name));
6059 /* We assume this works because entry->name was
6060 successfully converted in smb_UnlinkProc() once. */
6061 cm_FsStringToNormString(entry->name, -1,
6062 normalizedName, lengthof(normalizedName));
6064 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6066 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6067 smb_NotifyChange(FILE_ACTION_REMOVED,
6068 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6069 dscp, normalizedName, NULL, TRUE);
6073 cm_DirEntryListFree(&rock.matches);
6077 cm_ReleaseUser(userp);
6080 cm_ReleaseSCache(dscp);
6085 if (code == 0 && !rock.any)
6086 code = CM_ERROR_NOSUCHFILE;
6090 typedef struct smb_renameRock {
6091 cm_scache_t *odscp; /* old dir */
6092 cm_scache_t *ndscp; /* new dir */
6093 cm_user_t *userp; /* user */
6094 cm_req_t *reqp; /* request struct */
6095 smb_vc_t *vcp; /* virtual circuit */
6096 normchar_t *maskp; /* pointer to star pattern of old file name */
6097 int flags; /* tilde, casefold, etc */
6098 clientchar_t *newNamep; /* ptr to the new file's name */
6099 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6100 clientchar_t clOldName[MAX_PATH]; /* client name */
6104 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6107 smb_renameRock_t *rockp;
6110 normchar_t matchName[MAX_PATH];
6112 rockp = (smb_renameRock_t *) vrockp;
6114 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6115 /* Can't convert string */
6116 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6117 osi_LogSaveString(smb_logp, dep->name));
6121 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6122 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6123 caseFold |= CM_FLAG_8DOT3;
6125 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6127 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6128 !cm_Is8Dot3(matchName)) {
6129 cm_Gen8Dot3Name(dep, matchName, NULL);
6130 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6135 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6136 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6138 code = CM_ERROR_STOPNOW;
6148 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6151 cm_space_t *spacep = NULL;
6152 smb_renameRock_t rock;
6153 cm_scache_t *oldDscp = NULL;
6154 cm_scache_t *newDscp = NULL;
6155 cm_scache_t *tmpscp= NULL;
6156 cm_scache_t *tmpscp2 = NULL;
6157 clientchar_t *oldLastNamep;
6158 clientchar_t *newLastNamep;
6162 clientchar_t *tidPathp;
6166 userp = smb_GetUserFromVCP(vcp, inp);
6167 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6169 cm_ReleaseUser(userp);
6170 return CM_ERROR_NOSUCHPATH;
6174 memset(&rock, 0, sizeof(rock));
6176 spacep = inp->spacep;
6177 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6179 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6180 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6181 userp, tidPathp, &req, &oldDscp);
6183 cm_ReleaseUser(userp);
6188 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6189 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6190 cm_ReleaseSCache(oldDscp);
6191 cm_ReleaseUser(userp);
6192 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6193 return CM_ERROR_PATH_NOT_COVERED;
6195 return CM_ERROR_NOSUCHPATH;
6197 #endif /* DFS_SUPPORT */
6199 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6200 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6201 userp, tidPathp, &req, &newDscp);
6204 cm_ReleaseSCache(oldDscp);
6205 cm_ReleaseUser(userp);
6210 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6211 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6212 cm_ReleaseSCache(oldDscp);
6213 cm_ReleaseSCache(newDscp);
6214 cm_ReleaseUser(userp);
6215 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6216 return CM_ERROR_PATH_NOT_COVERED;
6218 return CM_ERROR_NOSUCHPATH;
6220 #endif /* DFS_SUPPORT */
6223 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6224 * next, get the component names, and lower case them.
6227 /* handle the old name first */
6229 oldLastNamep = oldPathp;
6233 /* and handle the new name, too */
6235 newLastNamep = newPathp;
6239 /* TODO: The old name could be a wildcard. The new name must not be */
6241 /* Check if the file already exists; if so return error */
6242 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6243 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6244 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6246 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6247 osi_LogSaveClientString(smb_logp, newLastNamep));
6249 /* Check if the old and the new names differ only in case. If so return
6250 * success, else return CM_ERROR_EXISTS
6252 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6254 /* This would be a success only if the old file is *as same as* the new file */
6255 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6257 if (tmpscp == tmpscp2)
6260 code = CM_ERROR_EXISTS;
6261 cm_ReleaseSCache(tmpscp2);
6264 code = CM_ERROR_NOSUCHFILE;
6267 /* file exist, do not rename, also fixes move */
6268 osi_Log0(smb_logp, "Can't rename. Target already exists");
6269 code = CM_ERROR_EXISTS;
6274 /* do the vnode call */
6275 rock.odscp = oldDscp;
6276 rock.ndscp = newDscp;
6280 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6282 code = CM_ERROR_NOSUCHFILE;
6285 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6286 rock.newNamep = newLastNamep;
6287 rock.fsOldName[0] = '\0';
6288 rock.clOldName[0] = '\0';
6291 /* Now search the directory for the pattern, and do the appropriate rename when found */
6292 thyper.LowPart = 0; /* search dir from here */
6293 thyper.HighPart = 0;
6295 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6296 if (code == 0 && !rock.any) {
6298 thyper.HighPart = 0;
6299 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6300 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6302 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6304 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6305 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6306 rock.ndscp, rock.newNamep, rock.userp,
6308 /* if the call worked, stop doing the search now, since we
6309 * really only want to rename one file.
6312 osi_Log0(smb_logp, "cm_Rename failure");
6313 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6314 } else if (code == 0) {
6315 code = CM_ERROR_NOSUCHFILE;
6318 /* Handle Change Notification */
6320 * Being lazy, not distinguishing between files and dirs in this
6321 * filter, since we'd have to do a lookup.
6324 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6325 if (oldDscp == newDscp) {
6326 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6327 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6328 filter, oldDscp, rock.clOldName,
6329 newLastNamep, TRUE);
6331 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6332 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6333 filter, oldDscp, rock.clOldName,
6335 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6336 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6337 filter, newDscp, newLastNamep,
6344 cm_ReleaseSCache(tmpscp);
6346 cm_ReleaseUser(userp);
6348 cm_ReleaseSCache(oldDscp);
6350 cm_ReleaseSCache(newDscp);
6358 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6361 cm_space_t *spacep = NULL;
6362 cm_scache_t *oldDscp = NULL;
6363 cm_scache_t *newDscp = NULL;
6364 cm_scache_t *tmpscp= NULL;
6365 cm_scache_t *tmpscp2 = NULL;
6366 cm_scache_t *sscp = NULL;
6367 clientchar_t *oldLastNamep;
6368 clientchar_t *newLastNamep;
6371 clientchar_t *tidPathp;
6375 userp = smb_GetUserFromVCP(vcp, inp);
6377 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6379 cm_ReleaseUser(userp);
6380 return CM_ERROR_NOSUCHPATH;
6385 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6387 spacep = inp->spacep;
6388 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6390 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6391 userp, tidPathp, &req, &oldDscp);
6393 cm_ReleaseUser(userp);
6398 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6399 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6400 cm_ReleaseSCache(oldDscp);
6401 cm_ReleaseUser(userp);
6402 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6403 return CM_ERROR_PATH_NOT_COVERED;
6405 return CM_ERROR_NOSUCHPATH;
6407 #endif /* DFS_SUPPORT */
6409 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6410 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6411 userp, tidPathp, &req, &newDscp);
6413 cm_ReleaseSCache(oldDscp);
6414 cm_ReleaseUser(userp);
6419 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6420 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6421 cm_ReleaseSCache(newDscp);
6422 cm_ReleaseSCache(oldDscp);
6423 cm_ReleaseUser(userp);
6424 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6425 return CM_ERROR_PATH_NOT_COVERED;
6427 return CM_ERROR_NOSUCHPATH;
6429 #endif /* DFS_SUPPORT */
6431 /* Now, although we did two lookups for the two directories (because the same
6432 * directory can be referenced through different paths), we only allow hard links
6433 * within the same directory. */
6434 if (oldDscp != newDscp) {
6435 cm_ReleaseSCache(oldDscp);
6436 cm_ReleaseSCache(newDscp);
6437 cm_ReleaseUser(userp);
6438 return CM_ERROR_CROSSDEVLINK;
6441 /* handle the old name first */
6443 oldLastNamep = oldPathp;
6447 /* and handle the new name, too */
6449 newLastNamep = newPathp;
6453 /* now lookup the old name */
6454 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6455 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6457 cm_ReleaseSCache(oldDscp);
6458 cm_ReleaseSCache(newDscp);
6459 cm_ReleaseUser(userp);
6463 /* Check if the file already exists; if so return error */
6464 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6465 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6466 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6468 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6469 osi_LogSaveClientString(smb_logp, newLastNamep));
6471 /* if the existing link is to the same file, then we return success */
6473 if(sscp == tmpscp) {
6476 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6477 code = CM_ERROR_EXISTS;
6482 cm_ReleaseSCache(tmpscp);
6483 cm_ReleaseSCache(sscp);
6484 cm_ReleaseSCache(newDscp);
6485 cm_ReleaseSCache(oldDscp);
6486 cm_ReleaseUser(userp);
6490 /* now create the hardlink */
6491 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6492 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6493 osi_Log1(smb_logp," Link returns 0x%x", code);
6495 /* Handle Change Notification */
6497 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6498 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6499 smb_NotifyChange(FILE_ACTION_ADDED,
6500 filter, newDscp, newLastNamep,
6505 cm_ReleaseSCache(tmpscp);
6506 cm_ReleaseUser(userp);
6507 cm_ReleaseSCache(sscp);
6508 cm_ReleaseSCache(oldDscp);
6509 cm_ReleaseSCache(newDscp);
6513 /* SMB_COM_RENAME */
6515 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6517 clientchar_t *oldPathp;
6518 clientchar_t *newPathp;
6522 tp = smb_GetSMBData(inp, NULL);
6523 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6525 return CM_ERROR_BADSMB;
6526 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6528 return CM_ERROR_BADSMB;
6530 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6531 osi_LogSaveClientString(smb_logp, oldPathp),
6532 osi_LogSaveClientString(smb_logp, newPathp));
6534 if (!cm_IsValidClientString(newPathp)) {
6536 clientchar_t * hexp;
6538 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6539 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6540 osi_LogSaveClientString(smb_logp, hexp));
6544 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6546 return CM_ERROR_BADNTFILENAME;
6549 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6551 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6557 typedef struct smb_rmdirRock {
6561 normchar_t *maskp; /* pointer to the star pattern */
6564 cm_dirEntryList_t * matches;
6567 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6570 smb_rmdirRock_t *rockp;
6572 normchar_t matchName[MAX_PATH];
6574 rockp = (smb_rmdirRock_t *) vrockp;
6576 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6577 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6578 osi_LogSaveString(smb_logp, dep->name));
6582 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6583 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6585 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6587 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6588 !cm_Is8Dot3(matchName)) {
6589 cm_Gen8Dot3Name(dep, matchName, NULL);
6590 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6595 cm_DirEntryListAdd(dep->name, &rockp->matches);
6602 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6605 clientchar_t *pathp;
6609 clientchar_t *lastNamep;
6610 smb_rmdirRock_t rock;
6614 clientchar_t *tidPathp;
6618 memset(&rock, 0, sizeof(rock));
6620 tp = smb_GetSMBData(inp, NULL);
6621 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6623 return CM_ERROR_BADSMB;
6625 spacep = inp->spacep;
6626 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6628 userp = smb_GetUserFromVCP(vcp, inp);
6630 caseFold = CM_FLAG_CASEFOLD;
6632 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6634 cm_ReleaseUser(userp);
6635 return CM_ERROR_NOSUCHPATH;
6637 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6638 userp, tidPathp, &req, &dscp);
6641 cm_ReleaseUser(userp);
6646 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6647 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6648 cm_ReleaseSCache(dscp);
6649 cm_ReleaseUser(userp);
6650 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6651 return CM_ERROR_PATH_NOT_COVERED;
6653 return CM_ERROR_NOSUCHPATH;
6655 #endif /* DFS_SUPPORT */
6657 /* otherwise, scp points to the parent directory. */
6664 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6666 code = CM_ERROR_NOSUCHFILE;
6669 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6672 thyper.HighPart = 0;
6676 rock.matches = NULL;
6678 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6679 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6680 if (code == 0 && !rock.any) {
6682 thyper.HighPart = 0;
6683 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6684 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6687 if (code == 0 && rock.matches) {
6688 cm_dirEntryList_t * entry;
6690 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6691 clientchar_t clientName[MAX_PATH];
6693 /* We assume this will succeed because smb_RmdirProc()
6694 successfully converted entry->name once above. */
6695 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6697 osi_Log1(smb_logp, "Removing directory %s",
6698 osi_LogSaveString(smb_logp, entry->name));
6700 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6702 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6703 smb_NotifyChange(FILE_ACTION_REMOVED,
6704 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6705 dscp, clientName, NULL, TRUE);
6711 cm_DirEntryListFree(&rock.matches);
6714 cm_ReleaseUser(userp);
6717 cm_ReleaseSCache(dscp);
6719 if (code == 0 && !rock.any)
6720 code = CM_ERROR_NOSUCHFILE;
6729 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6739 fid = smb_GetSMBParm(inp, 0);
6741 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6743 fid = smb_ChainFID(fid, inp);
6744 fidp = smb_FindFID(vcp, fid, 0);
6746 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6748 return CM_ERROR_BADFD;
6750 userp = smb_GetUserFromVCP(vcp, inp);
6752 lock_ObtainMutex(&fidp->mx);
6753 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6754 cm_ReleaseUser(userp);
6755 lock_ReleaseMutex(&fidp->mx);
6756 smb_ReleaseFID(fidp);
6757 return CM_ERROR_BADFD;
6760 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6761 lock_ReleaseMutex(&fidp->mx);
6762 cm_ReleaseUser(userp);
6763 smb_CloseFID(vcp, fidp, NULL, 0);
6764 smb_ReleaseFID(fidp);
6765 return CM_ERROR_NOSUCHFILE;
6768 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6769 cm_scache_t * scp = fidp->scp;
6771 lock_ReleaseMutex(&fidp->mx);
6772 code = cm_FSync(scp, userp, &req, FALSE);
6773 cm_ReleaseSCache(scp);
6775 lock_ReleaseMutex(&fidp->mx);
6779 cm_ReleaseUser(userp);
6780 smb_ReleaseFID(fidp);
6784 struct smb_FullNameRock {
6787 clientchar_t *fullName;
6788 fschar_t *originalName;
6791 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6794 normchar_t matchName[MAX_PATH];
6795 struct smb_FullNameRock *vrockp;
6797 vrockp = (struct smb_FullNameRock *)rockp;
6799 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6800 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6801 osi_LogSaveString(smb_logp, dep->name));
6805 if (!cm_Is8Dot3(matchName)) {
6806 clientchar_t shortName[13];
6808 cm_Gen8Dot3Name(dep, shortName, NULL);
6810 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6811 vrockp->fullName = cm_ClientStrDup(matchName);
6812 vrockp->originalName = cm_FsStrDup(dep->name);
6813 return CM_ERROR_STOPNOW;
6816 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6817 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6818 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6819 vrockp->fullName = cm_ClientStrDup(matchName);
6820 vrockp->originalName = cm_FsStrDup(dep->name);
6821 return CM_ERROR_STOPNOW;
6826 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6827 clientchar_t **newPathp, fschar_t ** originalPathp,
6828 cm_user_t *userp, cm_req_t *reqp)
6830 struct smb_FullNameRock rock;
6833 memset(&rock, 0, sizeof(rock));
6837 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6838 if (code == CM_ERROR_STOPNOW) {
6839 *newPathp = rock.fullName;
6840 *originalPathp = rock.originalName;
6842 *newPathp = cm_ClientStrDup(pathp);
6843 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6847 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6848 afs_uint32 dosTime) {
6851 cm_scache_t *dscp = NULL;
6852 clientchar_t *pathp = NULL;
6853 cm_scache_t * scp = NULL;
6854 cm_scache_t *delscp = NULL;
6855 int nullcreator = 0;
6857 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6858 fidp, fidp->fid, scp, vcp);
6861 lock_ObtainMutex(&fidp->mx);
6862 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6864 lock_ReleaseMutex(&fidp->mx);
6865 osi_Log0(smb_logp, " No user specified. Not closing fid");
6866 return CM_ERROR_BADFD;
6869 userp = fidp->userp; /* no hold required since fidp is held
6870 throughout the function */
6871 lock_ReleaseMutex(&fidp->mx);
6876 lock_ObtainWrite(&smb_rctLock);
6877 if (fidp->deleteOk) {
6878 osi_Log0(smb_logp, " Fid already closed.");
6879 lock_ReleaseWrite(&smb_rctLock);
6880 return CM_ERROR_BADFD;
6883 lock_ReleaseWrite(&smb_rctLock);
6885 lock_ObtainMutex(&fidp->mx);
6886 if (fidp->NTopen_dscp) {
6887 dscp = fidp->NTopen_dscp;
6888 cm_HoldSCache(dscp);
6891 if (fidp->NTopen_pathp)
6892 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6899 /* Don't jump the gun on an async raw write */
6900 while (fidp->raw_writers) {
6901 lock_ReleaseMutex(&fidp->mx);
6902 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6903 lock_ObtainMutex(&fidp->mx);
6906 /* watch for ioctl closes, and read-only opens */
6908 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6909 == SMB_FID_OPENWRITE) {
6910 if (dosTime != 0 && dosTime != -1) {
6911 lock_ObtainWrite(&fidp->scp->rw);
6912 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6913 /* This fixes defect 10958 */
6914 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6915 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6916 lock_ReleaseWrite(&fidp->scp->rw);
6918 if (smb_AsyncStore != 2) {
6919 lock_ReleaseMutex(&fidp->mx);
6920 code = cm_FSync(scp, userp, &req, FALSE);
6921 lock_ObtainMutex(&fidp->mx);
6927 /* unlock any pending locks */
6928 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6929 scp->fileType == CM_SCACHETYPE_FILE) {
6933 lock_ReleaseMutex(&fidp->mx);
6935 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6937 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6938 lock_ObtainWrite(&scp->rw);
6940 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6941 CM_SCACHESYNC_NEEDCALLBACK
6942 | CM_SCACHESYNC_GETSTATUS
6943 | CM_SCACHESYNC_LOCK);
6947 "smb CoreClose SyncOp failure code 0x%x", tcode);
6948 goto post_syncopdone;
6951 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6953 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6957 lock_ReleaseWrite(&scp->rw);
6958 lock_ObtainMutex(&fidp->mx);
6961 if (fidp->flags & SMB_FID_DELONCLOSE) {
6962 clientchar_t *fullPathp = NULL;
6963 fschar_t *originalNamep = NULL;
6965 lock_ReleaseMutex(&fidp->mx);
6967 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6972 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6973 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6974 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6976 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6977 smb_NotifyChange(FILE_ACTION_REMOVED,
6978 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6979 dscp, fullPathp, NULL, TRUE);
6982 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6984 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6985 smb_NotifyChange(FILE_ACTION_REMOVED,
6986 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6987 dscp, fullPathp, NULL, TRUE);
6994 free(originalNamep);
6996 lock_ObtainMutex(&fidp->mx);
6997 fidp->flags &= ~SMB_FID_DELONCLOSE;
7000 /* if this was a newly created file, then clear the creator
7001 * in the stat cache entry. */
7002 if (fidp->flags & SMB_FID_CREATED) {
7004 fidp->flags &= ~SMB_FID_CREATED;
7007 if (fidp->flags & SMB_FID_NTOPEN) {
7008 cm_ReleaseSCache(fidp->NTopen_dscp);
7009 fidp->NTopen_dscp = NULL;
7010 free(fidp->NTopen_pathp);
7011 fidp->NTopen_pathp = NULL;
7012 fidp->flags &= ~SMB_FID_NTOPEN;
7014 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
7015 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7018 if (fidp->NTopen_wholepathp) {
7019 free(fidp->NTopen_wholepathp);
7020 fidp->NTopen_wholepathp = NULL;
7024 cm_ReleaseSCache(fidp->scp);
7027 lock_ReleaseMutex(&fidp->mx);
7030 cm_ReleaseSCache(dscp);
7033 cm_ReleaseSCache(delscp);
7037 lock_ObtainWrite(&scp->rw);
7038 if (nullcreator && scp->creator == userp)
7039 scp->creator = NULL;
7040 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7041 lock_ReleaseWrite(&scp->rw);
7042 cm_ReleaseSCache(scp);
7052 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7060 fid = smb_GetSMBParm(inp, 0);
7061 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7063 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7065 fid = smb_ChainFID(fid, inp);
7066 fidp = smb_FindFID(vcp, fid, 0);
7068 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
7070 return CM_ERROR_BADFD;
7073 userp = smb_GetUserFromVCP(vcp, inp);
7075 code = smb_CloseFID(vcp, fidp, userp, dosTime);
7077 smb_ReleaseFID(fidp);
7078 cm_ReleaseUser(userp);
7083 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7085 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7086 cm_user_t *userp, long *readp)
7092 osi_hyper_t fileLength;
7094 osi_hyper_t lastByte;
7095 osi_hyper_t bufferOffset;
7099 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7102 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7103 fidp->fid, offsetp->LowPart, count);
7107 lock_ObtainMutex(&fidp->mx);
7108 /* make sure we have a readable FD */
7109 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7110 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7111 fidp->fid, fidp->flags);
7112 lock_ReleaseMutex(&fidp->mx);
7113 code = CM_ERROR_BADFDOP;
7118 lock_ReleaseMutex(&fidp->mx);
7119 code = CM_ERROR_BADFD;
7130 lock_ObtainWrite(&scp->rw);
7132 if (offset.HighPart == 0) {
7133 chunk = offset.LowPart >> cm_logChunkSize;
7134 if (chunk != fidp->curr_chunk) {
7135 fidp->prev_chunk = fidp->curr_chunk;
7136 fidp->curr_chunk = chunk;
7138 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7141 lock_ReleaseMutex(&fidp->mx);
7143 /* start by looking up the file's end */
7144 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7145 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7149 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7151 /* now we have the entry locked, look up the length */
7152 fileLength = scp->length;
7154 /* adjust count down so that it won't go past EOF */
7155 thyper.LowPart = count;
7156 thyper.HighPart = 0;
7157 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7159 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7160 /* we'd read past EOF, so just stop at fileLength bytes.
7161 * Start by computing how many bytes remain in the file.
7163 thyper = LargeIntegerSubtract(fileLength, offset);
7165 /* if we are past EOF, read 0 bytes */
7166 if (LargeIntegerLessThanZero(thyper))
7169 count = thyper.LowPart;
7174 /* now, copy the data one buffer at a time,
7175 * until we've filled the request packet
7178 /* if we've copied all the data requested, we're done */
7179 if (count <= 0) break;
7181 /* otherwise, load up a buffer of data */
7182 thyper.HighPart = offset.HighPart;
7183 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7184 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7187 buf_Release(bufferp);
7190 lock_ReleaseWrite(&scp->rw);
7192 code = buf_Get(scp, &thyper, &req, &bufferp);
7194 lock_ObtainWrite(&scp->rw);
7195 if (code) goto done;
7196 bufferOffset = thyper;
7198 /* now get the data in the cache */
7200 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7201 CM_SCACHESYNC_NEEDCALLBACK |
7202 CM_SCACHESYNC_READ);
7206 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7208 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7210 /* otherwise, load the buffer and try again */
7211 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7215 buf_Release(bufferp);
7219 } /* if (wrong buffer) ... */
7221 /* now we have the right buffer loaded. Copy out the
7222 * data from here to the user's buffer.
7224 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7226 /* and figure out how many bytes we want from this buffer */
7227 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7228 if (nbytes > count) nbytes = count; /* don't go past EOF */
7230 /* now copy the data */
7231 memcpy(op, bufferp->datap + bufIndex, nbytes);
7233 /* adjust counters, pointers, etc. */
7236 thyper.LowPart = nbytes;
7237 thyper.HighPart = 0;
7238 offset = LargeIntegerAdd(thyper, offset);
7242 lock_ReleaseWrite(&scp->rw);
7244 buf_Release(bufferp);
7246 if (code == 0 && sequential)
7247 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7249 cm_ReleaseSCache(scp);
7252 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7253 fidp->fid, code, *readp);
7258 * smb_WriteData -- common code for Write and Raw Write
7260 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7261 cm_user_t *userp, long *writtenp)
7263 osi_hyper_t offset = *offsetp;
7266 cm_scache_t *scp = NULL;
7267 osi_hyper_t fileLength; /* file's length at start of write */
7268 osi_hyper_t minLength; /* don't read past this */
7269 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7270 cm_buf_t *bufferp = NULL;
7271 osi_hyper_t thyper; /* hyper tmp variable */
7272 osi_hyper_t bufferOffset;
7273 afs_uint32 bufIndex; /* index in buffer where our data is */
7274 int doWriteBack = 0;
7275 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7278 int needSyncOpDone = 0;
7280 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7281 fidp->fid, offsetp->LowPart, count);
7285 lock_ObtainMutex(&fidp->mx);
7286 /* make sure we have a writable FD */
7287 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7288 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7289 fidp->fid, fidp->flags);
7290 lock_ReleaseMutex(&fidp->mx);
7291 code = CM_ERROR_BADFDOP;
7299 lock_ReleaseMutex(&fidp->mx);
7301 lock_ObtainWrite(&scp->rw);
7302 /* start by looking up the file's end */
7303 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7304 CM_SCACHESYNC_NEEDCALLBACK
7305 | CM_SCACHESYNC_SETSTATUS
7306 | CM_SCACHESYNC_GETSTATUS);
7310 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7312 /* now we have the entry locked, look up the length */
7313 fileLength = scp->length;
7314 minLength = fileLength;
7315 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7316 minLength = scp->serverLength;
7318 /* adjust file length if we extend past EOF */
7319 thyper.LowPart = count;
7320 thyper.HighPart = 0;
7321 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7322 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7323 /* we'd write past EOF, so extend the file */
7324 scp->mask |= CM_SCACHEMASK_LENGTH;
7325 scp->length = thyper;
7326 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7328 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7330 /* now, if the new position (thyper) and the old (offset) are in
7331 * different storeback windows, remember to store back the previous
7332 * storeback window when we're done with the write.
7334 * the purpose of this logic is to slow down the CIFS client
7335 * in order to avoid the client disconnecting during the CLOSE
7336 * operation if there are too many dirty buffers left to write
7337 * than can be accomplished during 45 seconds. This used to be
7338 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7339 * so that we can read larger amounts of data at a time.
7341 if (smb_AsyncStore == 1 &&
7342 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7343 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7344 /* they're different */
7346 writeBackOffset.HighPart = offset.HighPart;
7347 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7352 /* now, copy the data one buffer at a time, until we've filled the
7354 while (count != 0) {
7356 /* handle over quota or out of space */
7357 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7358 *writtenp = written;
7359 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7363 /* otherwise, load up a buffer of data */
7364 thyper.HighPart = offset.HighPart;
7365 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7366 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7369 if (needSyncOpDone) {
7370 cm_SyncOpDone(scp, bufferp,
7371 CM_SCACHESYNC_NEEDCALLBACK
7372 | CM_SCACHESYNC_WRITE
7373 | CM_SCACHESYNC_BUFLOCKED);
7376 lock_ReleaseMutex(&bufferp->mx);
7377 buf_Release(bufferp);
7380 lock_ReleaseWrite(&scp->rw);
7382 code = buf_Get(scp, &thyper, &req, &bufferp);
7384 lock_ObtainMutex(&bufferp->mx);
7385 lock_ObtainWrite(&scp->rw);
7386 if (code) goto done;
7388 bufferOffset = thyper;
7390 /* now get the data in the cache */
7392 if (!needSyncOpDone) {
7393 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7394 CM_SCACHESYNC_NEEDCALLBACK
7395 | CM_SCACHESYNC_WRITE
7396 | CM_SCACHESYNC_BUFLOCKED);
7403 /* If we're overwriting the entire buffer, or
7404 * if we're writing at or past EOF, mark the
7405 * buffer as current so we don't call
7406 * cm_GetBuffer. This skips the fetch from the
7407 * server in those cases where we're going to
7408 * obliterate all the data in the buffer anyway,
7409 * or in those cases where there is no useful
7410 * data at the server to start with.
7412 * Use minLength instead of scp->length, since
7413 * the latter has already been updated by this
7416 * The scp lock has been dropped multiple times
7417 * so the minLength must be refreshed before it
7421 minLength = scp->length;
7422 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7423 minLength = scp->serverLength;
7425 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7426 || LargeIntegerEqualTo(offset, bufferp->offset)
7427 && (count >= cm_data.buf_blockSize
7428 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7429 ConvertLongToLargeInteger(count)),
7431 if (count < cm_data.buf_blockSize
7432 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7433 memset(bufferp->datap, 0,
7434 cm_data.buf_blockSize);
7435 bufferp->dataVersion = scp->dataVersion;
7438 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7440 /* otherwise, load the buffer and try again */
7441 cm_SyncOpDone(scp, bufferp,
7442 CM_SCACHESYNC_NEEDCALLBACK
7443 | CM_SCACHESYNC_WRITE
7444 | CM_SCACHESYNC_BUFLOCKED);
7447 lock_ReleaseMutex(&bufferp->mx);
7448 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7450 lock_ReleaseWrite(&scp->rw);
7451 lock_ObtainMutex(&bufferp->mx);
7452 lock_ObtainWrite(&scp->rw);
7456 } /* if (wrong buffer) ... */
7458 /* now we have the right buffer loaded. Copy out the
7459 * data from here to the user's buffer.
7461 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7463 /* and figure out how many bytes we want from this buffer */
7464 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7466 nbytes = count; /* don't go past end of request */
7468 /* now copy the data */
7469 memcpy(bufferp->datap + bufIndex, op, nbytes);
7470 buf_SetDirty(bufferp, &req, bufIndex, nbytes, userp);
7472 /* adjust counters, pointers, etc. */
7476 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7477 } /* while count != 0 */
7480 if (bufferp && needSyncOpDone) {
7481 cm_SyncOpDone(scp, bufferp,
7482 CM_SCACHESYNC_NEEDCALLBACK
7483 | CM_SCACHESYNC_WRITE
7484 | CM_SCACHESYNC_BUFLOCKED);
7487 lock_ReleaseWrite(&scp->rw);
7490 lock_ReleaseMutex(&bufferp->mx);
7491 buf_Release(bufferp);
7494 lock_ObtainMutex(&fidp->mx);
7495 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7496 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7498 lock_ReleaseMutex(&fidp->mx);
7499 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7500 fidp->NTopen_dscp, fidp->NTopen_pathp,
7503 lock_ReleaseMutex(&fidp->mx);
7507 if (smb_AsyncStore > 0) {
7511 lock_ObtainWrite(&scp->rw);
7512 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7514 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7515 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7517 lock_ReleaseWrite(&scp->rw);
7518 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7519 writeBackOffset.HighPart,
7520 smb_AsyncStoreSize, 0, userp, &req);
7521 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7524 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7528 cm_ReleaseSCache(scp);
7531 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7532 fidp->fid, code, *writtenp);
7537 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7540 unsigned short count;
7542 unsigned short hint;
7543 long written = 0, total_written = 0;
7546 smb_t* smbp = (smb_t*) inp;
7550 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7552 int inDataBlockCount;
7554 fd = smb_GetSMBParm(inp, 0);
7555 count = smb_GetSMBParm(inp, 1);
7556 offset.HighPart = 0; /* too bad */
7557 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7558 hint = smb_GetSMBParm(inp, 4);
7560 op = smb_GetSMBData(inp, NULL);
7561 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7563 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7564 fd, offset.LowPart, count);
7566 fd = smb_ChainFID(fd, inp);
7567 fidp = smb_FindFID(vcp, fd, 0);
7569 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7571 return CM_ERROR_BADFD;
7574 lock_ObtainMutex(&fidp->mx);
7575 if (fidp->flags & SMB_FID_IOCTL) {
7576 lock_ReleaseMutex(&fidp->mx);
7577 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7578 smb_ReleaseFID(fidp);
7579 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7583 if (fidp->flags & SMB_FID_RPC) {
7584 lock_ReleaseMutex(&fidp->mx);
7585 code = smb_RPCWrite(fidp, vcp, inp, outp);
7586 smb_ReleaseFID(fidp);
7587 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7592 lock_ReleaseMutex(&fidp->mx);
7593 smb_ReleaseFID(fidp);
7594 return CM_ERROR_BADFD;
7597 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7598 lock_ReleaseMutex(&fidp->mx);
7599 smb_CloseFID(vcp, fidp, NULL, 0);
7600 smb_ReleaseFID(fidp);
7601 return CM_ERROR_NOSUCHFILE;
7606 lock_ReleaseMutex(&fidp->mx);
7607 userp = smb_GetUserFromVCP(vcp, inp);
7611 LARGE_INTEGER LOffset;
7612 LARGE_INTEGER LLength;
7615 key = cm_GenerateKey(vcp->vcID, pid, fd);
7617 LOffset.HighPart = offset.HighPart;
7618 LOffset.LowPart = offset.LowPart;
7619 LLength.HighPart = 0;
7620 LLength.LowPart = count;
7622 lock_ObtainWrite(&scp->rw);
7623 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7624 lock_ReleaseWrite(&scp->rw);
7627 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7632 /* special case: 0 bytes transferred means truncate to this position */
7636 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7640 truncAttr.mask = CM_ATTRMASK_LENGTH;
7641 truncAttr.length.LowPart = offset.LowPart;
7642 truncAttr.length.HighPart = 0;
7643 lock_ObtainMutex(&fidp->mx);
7644 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7645 fidp->flags |= SMB_FID_LENGTHSETDONE;
7646 lock_ReleaseMutex(&fidp->mx);
7647 smb_SetSMBParm(outp, 0, 0 /* count */);
7648 smb_SetSMBDataLength(outp, 0);
7653 * Work around bug in NT client
7655 * When copying a file, the NT client should first copy the data,
7656 * then copy the last write time. But sometimes the NT client does
7657 * these in the wrong order, so the data copies would inadvertently
7658 * cause the last write time to be overwritten. We try to detect this,
7659 * and don't set client mod time if we think that would go against the
7662 lock_ObtainMutex(&fidp->mx);
7663 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7664 lock_ObtainWrite(&fidp->scp->rw);
7665 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7666 fidp->scp->clientModTime = time(NULL);
7667 lock_ReleaseWrite(&fidp->scp->rw);
7669 lock_ReleaseMutex(&fidp->mx);
7672 while ( code == 0 && count > 0 ) {
7673 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7674 if (code == 0 && written == 0)
7675 code = CM_ERROR_PARTIALWRITE;
7677 offset = LargeIntegerAdd(offset,
7678 ConvertLongToLargeInteger(written));
7679 count -= (unsigned short)written;
7680 total_written += written;
7684 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7685 total_written, code);
7687 /* set the packet data length to 3 bytes for the data block header,
7688 * plus the size of the data.
7690 smb_SetSMBParm(outp, 0, total_written);
7691 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7692 smb_SetSMBParm(outp, 3, hint);
7693 smb_SetSMBDataLength(outp, 0);
7696 smb_ReleaseFID(fidp);
7697 cm_ReleaseUser(userp);
7698 cm_ReleaseSCache(scp);
7703 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7704 NCB *ncbp, raw_write_cont_t *rwcp)
7713 fd = smb_GetSMBParm(inp, 0);
7714 fidp = smb_FindFID(vcp, fd, 0);
7716 lock_ObtainMutex(&fidp->mx);
7718 lock_ReleaseMutex(&fidp->mx);
7719 smb_ReleaseFID(fidp);
7723 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7724 lock_ReleaseMutex(&fidp->mx);
7725 smb_CloseFID(vcp, fidp, NULL, 0);
7726 smb_ReleaseFID(fidp);
7729 lock_ReleaseMutex(&fidp->mx);
7731 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7732 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7734 userp = smb_GetUserFromVCP(vcp, inp);
7737 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7739 if (rwcp->writeMode & 0x1) { /* synchronous */
7742 smb_FormatResponsePacket(vcp, inp, outp);
7743 op = (smb_t *) outp;
7744 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7745 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7746 smb_SetSMBDataLength(outp, 0);
7747 smb_SendPacket(vcp, outp);
7748 smb_FreePacket(outp);
7750 else { /* asynchronous */
7751 lock_ObtainMutex(&fidp->mx);
7752 fidp->raw_writers--;
7753 if (fidp->raw_writers == 0)
7754 thrd_SetEvent(fidp->raw_write_event);
7755 lock_ReleaseMutex(&fidp->mx);
7758 /* Give back raw buffer */
7759 lock_ObtainMutex(&smb_RawBufLock);
7760 *((char **)rawBuf) = smb_RawBufs;
7761 smb_RawBufs = rawBuf;
7762 lock_ReleaseMutex(&smb_RawBufLock);
7764 smb_ReleaseFID(fidp);
7765 cm_ReleaseUser(userp);
7768 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7773 /* SMB_COM_WRITE_RAW */
7774 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7777 long count, written = 0, total_written = 0;
7781 smb_t *smbp = (smb_t*) inp;
7786 unsigned short writeMode;
7788 fd = smb_GetSMBParm(inp, 0);
7789 totalCount = smb_GetSMBParm(inp, 1);
7790 count = smb_GetSMBParm(inp, 10);
7791 writeMode = smb_GetSMBParm(inp, 7);
7793 op = (char *) inp->data;
7794 op += smb_GetSMBParm(inp, 11);
7796 offset.HighPart = 0;
7797 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7799 if (*inp->wctp == 14) {
7800 /* we received a 64-bit file offset */
7801 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7803 if (LargeIntegerLessThanZero(offset)) {
7805 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7806 offset.HighPart, offset.LowPart);
7807 return CM_ERROR_BADSMB;
7810 offset.HighPart = 0; /* 32-bit file offset */
7814 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7815 fd, offset.HighPart, offset.LowPart, count);
7817 " WriteRaw WriteMode 0x%x",
7820 fd = smb_ChainFID(fd, inp);
7821 fidp = smb_FindFID(vcp, fd, 0);
7823 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7825 return CM_ERROR_BADFD;
7827 lock_ObtainMutex(&fidp->mx);
7829 lock_ReleaseMutex(&fidp->mx);
7830 smb_ReleaseFID(fidp);
7831 return CM_ERROR_BADFD;
7834 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7835 lock_ReleaseMutex(&fidp->mx);
7836 smb_CloseFID(vcp, fidp, NULL, 0);
7837 smb_ReleaseFID(fidp);
7838 return CM_ERROR_NOSUCHFILE;
7843 lock_ReleaseMutex(&fidp->mx);
7848 LARGE_INTEGER LOffset;
7849 LARGE_INTEGER LLength;
7852 key = cm_GenerateKey(vcp->vcID, pid, fd);
7854 LOffset.HighPart = offset.HighPart;
7855 LOffset.LowPart = offset.LowPart;
7856 LLength.HighPart = 0;
7857 LLength.LowPart = count;
7859 lock_ObtainWrite(&scp->rw);
7860 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7861 lock_ReleaseWrite(&scp->rw);
7864 cm_ReleaseSCache(scp);
7865 smb_ReleaseFID(fidp);
7870 userp = smb_GetUserFromVCP(vcp, inp);
7873 * Work around bug in NT client
7875 * When copying a file, the NT client should first copy the data,
7876 * then copy the last write time. But sometimes the NT client does
7877 * these in the wrong order, so the data copies would inadvertently
7878 * cause the last write time to be overwritten. We try to detect this,
7879 * and don't set client mod time if we think that would go against the
7882 lock_ObtainMutex(&fidp->mx);
7883 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7884 lock_ObtainWrite(&fidp->scp->rw);
7885 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7886 fidp->scp->clientModTime = time(NULL);
7887 lock_ReleaseWrite(&fidp->scp->rw);
7889 lock_ReleaseMutex(&fidp->mx);
7892 while ( code == 0 && count > 0 ) {
7893 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7894 if (code == 0 && written == 0)
7895 code = CM_ERROR_PARTIALWRITE;
7897 offset = LargeIntegerAdd(offset,
7898 ConvertLongToLargeInteger(written));
7901 total_written += written;
7905 /* Get a raw buffer */
7908 lock_ObtainMutex(&smb_RawBufLock);
7910 /* Get a raw buf, from head of list */
7911 rawBuf = smb_RawBufs;
7912 smb_RawBufs = *(char **)smb_RawBufs;
7915 code = CM_ERROR_USESTD;
7917 lock_ReleaseMutex(&smb_RawBufLock);
7920 /* Don't allow a premature Close */
7921 if (code == 0 && (writeMode & 1) == 0) {
7922 lock_ObtainMutex(&fidp->mx);
7923 fidp->raw_writers++;
7924 thrd_ResetEvent(fidp->raw_write_event);
7925 lock_ReleaseMutex(&fidp->mx);
7928 smb_ReleaseFID(fidp);
7929 cm_ReleaseUser(userp);
7930 cm_ReleaseSCache(scp);
7933 smb_SetSMBParm(outp, 0, total_written);
7934 smb_SetSMBDataLength(outp, 0);
7935 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7940 offset = LargeIntegerAdd(offset,
7941 ConvertLongToLargeInteger(count));
7945 rwcp->offset.HighPart = offset.HighPart;
7946 rwcp->offset.LowPart = offset.LowPart;
7947 rwcp->count = totalCount - count;
7948 rwcp->writeMode = writeMode;
7949 rwcp->alreadyWritten = total_written;
7951 /* set the packet data length to 3 bytes for the data block header,
7952 * plus the size of the data.
7954 smb_SetSMBParm(outp, 0, 0xffff);
7955 smb_SetSMBDataLength(outp, 0);
7961 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7964 long count, finalCount;
7968 smb_t *smbp = (smb_t*) inp;
7974 fd = smb_GetSMBParm(inp, 0);
7975 count = smb_GetSMBParm(inp, 1);
7976 offset.HighPart = 0; /* too bad */
7977 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7979 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7980 fd, offset.LowPart, count);
7982 fd = smb_ChainFID(fd, inp);
7983 fidp = smb_FindFID(vcp, fd, 0);
7985 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7987 return CM_ERROR_BADFD;
7989 lock_ObtainMutex(&fidp->mx);
7990 if (fidp->flags & SMB_FID_IOCTL) {
7991 lock_ReleaseMutex(&fidp->mx);
7992 code = smb_IoctlRead(fidp, vcp, inp, outp);
7993 smb_ReleaseFID(fidp);
7997 if (fidp->flags & SMB_FID_RPC) {
7998 lock_ReleaseMutex(&fidp->mx);
7999 code = smb_RPCRead(fidp, vcp, inp, outp);
8000 smb_ReleaseFID(fidp);
8005 lock_ReleaseMutex(&fidp->mx);
8006 smb_ReleaseFID(fidp);
8007 return CM_ERROR_BADFD;
8010 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8011 lock_ReleaseMutex(&fidp->mx);
8012 smb_CloseFID(vcp, fidp, NULL, 0);
8013 smb_ReleaseFID(fidp);
8014 return CM_ERROR_NOSUCHFILE;
8019 lock_ReleaseMutex(&fidp->mx);
8022 LARGE_INTEGER LOffset, LLength;
8026 key = cm_GenerateKey(vcp->vcID, pid, fd);
8028 LOffset.HighPart = 0;
8029 LOffset.LowPart = offset.LowPart;
8030 LLength.HighPart = 0;
8031 LLength.LowPart = count;
8033 lock_ObtainWrite(&scp->rw);
8034 code = cm_LockCheckRead(scp, LOffset, LLength, key);
8035 lock_ReleaseWrite(&scp->rw);
8038 cm_ReleaseSCache(scp);
8039 smb_ReleaseFID(fidp);
8043 userp = smb_GetUserFromVCP(vcp, inp);
8045 /* remember this for final results */
8046 smb_SetSMBParm(outp, 0, count);
8047 smb_SetSMBParm(outp, 1, 0);
8048 smb_SetSMBParm(outp, 2, 0);
8049 smb_SetSMBParm(outp, 3, 0);
8050 smb_SetSMBParm(outp, 4, 0);
8052 /* set the packet data length to 3 bytes for the data block header,
8053 * plus the size of the data.
8055 smb_SetSMBDataLength(outp, count+3);
8057 /* get op ptr after putting in the parms, since otherwise we don't
8058 * know where the data really is.
8060 op = smb_GetSMBData(outp, NULL);
8062 /* now emit the data block header: 1 byte of type and 2 bytes of length */
8063 *op++ = 1; /* data block marker */
8064 *op++ = (unsigned char) (count & 0xff);
8065 *op++ = (unsigned char) ((count >> 8) & 0xff);
8067 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8069 /* fix some things up */
8070 smb_SetSMBParm(outp, 0, finalCount);
8071 smb_SetSMBDataLength(outp, finalCount+3);
8073 smb_ReleaseFID(fidp);
8075 cm_ReleaseUser(userp);
8076 cm_ReleaseSCache(scp);
8080 /* SMB_COM_CREATE_DIRECTORY */
8081 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8083 clientchar_t *pathp;
8088 cm_scache_t *dscp; /* dir we're dealing with */
8089 cm_scache_t *scp; /* file we're creating */
8091 int initialModeBits;
8092 clientchar_t *lastNamep;
8094 clientchar_t *tidPathp;
8101 /* compute initial mode bits based on read-only flag in attributes */
8102 initialModeBits = 0777;
8104 tp = smb_GetSMBData(inp, NULL);
8105 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8107 return CM_ERROR_BADSMB;
8109 spacep = inp->spacep;
8110 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8112 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8113 return CM_ERROR_EXISTS;
8115 userp = smb_GetUserFromVCP(vcp, inp);
8117 caseFold = CM_FLAG_CASEFOLD;
8119 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8121 cm_ReleaseUser(userp);
8122 return CM_ERROR_NOSUCHPATH;
8125 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
8126 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8127 userp, tidPathp, &req, &dscp);
8130 cm_ReleaseUser(userp);
8135 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8136 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8137 cm_ReleaseSCache(dscp);
8138 cm_ReleaseUser(userp);
8139 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8140 return CM_ERROR_PATH_NOT_COVERED;
8142 return CM_ERROR_NOSUCHPATH;
8144 #endif /* DFS_SUPPORT */
8146 /* otherwise, scp points to the parent directory. Do a lookup, and
8147 * fail if we find it. Otherwise, we do the create.
8153 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8154 if (scp) cm_ReleaseSCache(scp);
8155 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8156 if (code == 0) code = CM_ERROR_EXISTS;
8157 cm_ReleaseSCache(dscp);
8158 cm_ReleaseUser(userp);
8162 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8163 setAttr.clientModTime = time(NULL);
8164 smb_SetInitialModeBitsForDir(0, &setAttr);
8166 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8167 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8168 smb_NotifyChange(FILE_ACTION_ADDED,
8169 FILE_NOTIFY_CHANGE_DIR_NAME,
8170 dscp, lastNamep, NULL, TRUE);
8172 /* we don't need this any longer */
8173 cm_ReleaseSCache(dscp);
8176 /* something went wrong creating or truncating the file */
8177 cm_ReleaseUser(userp);
8181 /* otherwise we succeeded */
8182 smb_SetSMBDataLength(outp, 0);
8183 cm_ReleaseUser(userp);
8188 BOOL smb_IsLegalFilename(clientchar_t *filename)
8191 * Find the longest substring of filename that does not contain
8192 * any of the chars in illegalChars. If that substring is less
8193 * than the length of the whole string, then one or more of the
8194 * illegal chars is in filename.
8196 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8202 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8203 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8205 clientchar_t *pathp;
8211 cm_scache_t *dscp; /* dir we're dealing with */
8212 cm_scache_t *scp; /* file we're creating */
8216 clientchar_t *lastNamep;
8219 clientchar_t *tidPathp;
8221 int created = 0; /* the file was new */
8226 excl = (inp->inCom == 0x03)? 0 : 1;
8228 attributes = smb_GetSMBParm(inp, 0);
8229 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8231 tp = smb_GetSMBData(inp, NULL);
8232 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8234 return CM_ERROR_BADSMB;
8236 spacep = inp->spacep;
8237 /* smb_StripLastComponent will strip "::$DATA" if present */
8238 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8240 if (!cm_IsValidClientString(pathp)) {
8242 clientchar_t * hexp;
8244 hexp = cm_GetRawCharsAlloc(pathp, -1);
8245 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8246 osi_LogSaveClientString(smb_logp, hexp));
8250 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8252 return CM_ERROR_BADNTFILENAME;
8255 userp = smb_GetUserFromVCP(vcp, inp);
8257 caseFold = CM_FLAG_CASEFOLD;
8259 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8261 cm_ReleaseUser(userp);
8262 return CM_ERROR_NOSUCHPATH;
8264 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8265 userp, tidPathp, &req, &dscp);
8268 cm_ReleaseUser(userp);
8273 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8274 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8275 cm_ReleaseSCache(dscp);
8276 cm_ReleaseUser(userp);
8277 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8278 return CM_ERROR_PATH_NOT_COVERED;
8280 return CM_ERROR_NOSUCHPATH;
8282 #endif /* DFS_SUPPORT */
8284 /* otherwise, scp points to the parent directory. Do a lookup, and
8285 * truncate the file if we find it, otherwise we create the file.
8292 if (!smb_IsLegalFilename(lastNamep))
8293 return CM_ERROR_BADNTFILENAME;
8295 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8296 #ifdef DEBUG_VERBOSE
8299 hexp = osi_HexifyString( lastNamep );
8300 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8305 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8306 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8307 cm_ReleaseSCache(dscp);
8308 cm_ReleaseUser(userp);
8312 /* if we get here, if code is 0, the file exists and is represented by
8313 * scp. Otherwise, we have to create it.
8317 /* oops, file shouldn't be there */
8318 cm_ReleaseSCache(dscp);
8319 cm_ReleaseSCache(scp);
8320 cm_ReleaseUser(userp);
8321 return CM_ERROR_EXISTS;
8324 setAttr.mask = CM_ATTRMASK_LENGTH;
8325 setAttr.length.LowPart = 0;
8326 setAttr.length.HighPart = 0;
8327 code = cm_SetAttr(scp, &setAttr, userp, &req);
8330 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8331 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8332 smb_SetInitialModeBitsForFile(attributes, &setAttr);
8334 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8338 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8339 smb_NotifyChange(FILE_ACTION_ADDED,
8340 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8341 dscp, lastNamep, NULL, TRUE);
8342 } else if (!excl && code == CM_ERROR_EXISTS) {
8343 /* not an exclusive create, and someone else tried
8344 * creating it already, then we open it anyway. We
8345 * don't bother retrying after this, since if this next
8346 * fails, that means that the file was deleted after
8347 * we started this call.
8349 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8352 setAttr.mask = CM_ATTRMASK_LENGTH;
8353 setAttr.length.LowPart = 0;
8354 setAttr.length.HighPart = 0;
8355 code = cm_SetAttr(scp, &setAttr, userp, &req);
8360 /* we don't need this any longer */
8361 cm_ReleaseSCache(dscp);
8364 /* something went wrong creating or truncating the file */
8365 if (scp) cm_ReleaseSCache(scp);
8366 cm_ReleaseUser(userp);
8370 /* make sure we only open files */
8371 if (scp->fileType != CM_SCACHETYPE_FILE) {
8372 cm_ReleaseSCache(scp);
8373 cm_ReleaseUser(userp);
8374 return CM_ERROR_ISDIR;
8377 /* now all we have to do is open the file itself */
8378 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8379 osi_assertx(fidp, "null smb_fid_t");
8383 lock_ObtainMutex(&fidp->mx);
8384 /* always create it open for read/write */
8385 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8387 /* remember that the file was newly created */
8389 fidp->flags |= SMB_FID_CREATED;
8391 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8393 /* save a pointer to the vnode */
8395 lock_ObtainWrite(&scp->rw);
8396 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8397 lock_ReleaseWrite(&scp->rw);
8400 fidp->userp = userp;
8401 lock_ReleaseMutex(&fidp->mx);
8403 smb_SetSMBParm(outp, 0, fidp->fid);
8404 smb_SetSMBDataLength(outp, 0);
8406 cm_Open(scp, 0, userp);
8408 smb_ReleaseFID(fidp);
8409 cm_ReleaseUser(userp);
8410 /* leave scp held since we put it in fidp->scp */
8415 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8418 osi_hyper_t new_offset;
8429 fd = smb_GetSMBParm(inp, 0);
8430 whence = smb_GetSMBParm(inp, 1);
8431 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8433 /* try to find the file descriptor */
8434 fd = smb_ChainFID(fd, inp);
8435 fidp = smb_FindFID(vcp, fd, 0);
8437 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8439 return CM_ERROR_BADFD;
8441 lock_ObtainMutex(&fidp->mx);
8442 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8443 lock_ReleaseMutex(&fidp->mx);
8444 smb_ReleaseFID(fidp);
8445 return CM_ERROR_BADFD;
8448 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8449 lock_ReleaseMutex(&fidp->mx);
8450 smb_CloseFID(vcp, fidp, NULL, 0);
8451 smb_ReleaseFID(fidp);
8452 return CM_ERROR_NOSUCHFILE;
8455 lock_ReleaseMutex(&fidp->mx);
8457 userp = smb_GetUserFromVCP(vcp, inp);
8459 lock_ObtainMutex(&fidp->mx);
8462 lock_ReleaseMutex(&fidp->mx);
8463 lock_ObtainWrite(&scp->rw);
8464 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8465 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8467 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8469 /* offset from current offset */
8470 new_offset = LargeIntegerAdd(fidp->offset,
8471 ConvertLongToLargeInteger(offset));
8473 else if (whence == 2) {
8474 /* offset from current EOF */
8475 new_offset = LargeIntegerAdd(scp->length,
8476 ConvertLongToLargeInteger(offset));
8478 new_offset = ConvertLongToLargeInteger(offset);
8481 fidp->offset = new_offset;
8482 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8483 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8484 smb_SetSMBDataLength(outp, 0);
8486 lock_ReleaseWrite(&scp->rw);
8487 smb_ReleaseFID(fidp);
8488 cm_ReleaseSCache(scp);
8489 cm_ReleaseUser(userp);
8493 /* dispatch all of the requests received in a packet. Due to chaining, this may
8494 * be more than one request.
8496 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8497 NCB *ncbp, raw_write_cont_t *rwcp)
8501 unsigned long code = 0;
8502 unsigned char *outWctp;
8503 int nparms; /* # of bytes of parameters */
8505 int nbytes; /* bytes of data, excluding count */
8508 unsigned short errCode;
8509 unsigned long NTStatus;
8511 unsigned char errClass;
8512 unsigned int oldGen;
8513 DWORD oldTime, newTime;
8515 /* get easy pointer to the data */
8516 smbp = (smb_t *) inp->data;
8518 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8519 /* setup the basic parms for the initial request in the packet */
8520 inp->inCom = smbp->com;
8521 inp->wctp = &smbp->wct;
8523 inp->ncb_length = ncbp->ncb_length;
8528 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8529 /* log it and discard it */
8530 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8531 __FILE__, __LINE__, ncbp->ncb_length);
8532 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8536 /* We are an ongoing op */
8537 thrd_Increment(&ongoingOps);
8539 /* set up response packet for receiving output */
8540 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8541 smb_FormatResponsePacket(vcp, inp, outp);
8542 outWctp = outp->wctp;
8544 /* Remember session generation number and time */
8545 oldGen = sessionGen;
8546 oldTime = GetTickCount();
8548 while (inp->inCom != 0xff) {
8549 dp = &smb_dispatchTable[inp->inCom];
8551 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8552 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8553 code = outp->resumeCode;
8557 /* process each request in the packet; inCom, wctp and inCount
8558 * are already set up.
8560 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8563 /* now do the dispatch */
8564 /* start by formatting the response record a little, as a default */
8565 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8567 outWctp[1] = 0xff; /* no operation */
8568 outWctp[2] = 0; /* padding */
8573 /* not a chained request, this is a more reasonable default */
8574 outWctp[0] = 0; /* wct of zero */
8575 outWctp[1] = 0; /* and bcc (word) of zero */
8579 /* once set, stays set. Doesn't matter, since we never chain
8580 * "no response" calls.
8582 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8586 /* we have a recognized operation */
8587 char * opName = myCrt_Dispatch(inp->inCom);
8590 smbp = (smb_t *) inp;
8592 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8593 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8594 if (inp->inCom == 0x1d) {
8596 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8598 code = (*(dp->procp)) (vcp, inp, outp);
8600 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8601 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8603 newTime = GetTickCount();
8604 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8605 opName, smbp->mid, newTime - oldTime);
8608 if ( code == CM_ERROR_BADSMB ||
8609 code == CM_ERROR_BADOP )
8611 #endif /* LOG_PACKET */
8613 /* ReceiveV3Tran2A handles its own logging */
8614 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8617 clientchar_t *treepath = NULL; /* do not free */
8618 clientchar_t *pathname = NULL;
8619 cm_fid_t afid = {0,0,0,0,0};
8621 uidp = smb_FindUID(vcp, smbp->uid, 0);
8622 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8623 fidp = smb_FindFID(vcp, inp->fid, 0);
8626 lock_ObtainMutex(&fidp->mx);
8627 if (fidp->NTopen_pathp)
8628 pathname = fidp->NTopen_pathp;
8630 afid = fidp->scp->fid;
8632 if (inp->stringsp->wdata)
8633 pathname = inp->stringsp->wdata;
8636 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)",
8637 opName, newTime - oldTime,
8638 smbp->uid, uidp ? uidp->unp->name : NULL,
8639 smbp->pid, smbp->mid, smbp->tid,
8642 afid.cell, afid.volume, afid.vnode, afid.unique);
8645 lock_ReleaseMutex(&fidp->mx);
8648 smb_ReleaseUID(uidp);
8650 smb_ReleaseFID(fidp);
8653 if (oldGen != sessionGen) {
8654 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8655 newTime - oldTime, ncbp->ncb_length);
8656 osi_Log3(smb_logp, "Request %s straddled session startup, "
8657 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8660 FreeSMBStrings(inp);
8662 /* bad opcode, fail the request, after displaying it */
8663 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8666 #endif /* LOG_PACKET */
8669 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8670 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8671 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8672 if (code == IDCANCEL)
8675 code = CM_ERROR_BADOP;
8678 /* catastrophic failure: log as much as possible */
8679 if (code == CM_ERROR_BADSMB) {
8680 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8684 #endif /* LOG_PACKET */
8685 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8688 code = CM_ERROR_INVAL;
8691 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8692 thrd_Decrement(&ongoingOps);
8697 /* now, if we failed, turn the current response into an empty
8698 * one, and fill in the response packet's error code.
8701 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8702 smb_MapNTError(code, &NTStatus, FALSE);
8703 outWctp = outp->wctp;
8704 smbp = (smb_t *) &outp->data;
8705 if (code != CM_ERROR_PARTIALWRITE
8706 && code != CM_ERROR_BUFFERTOOSMALL
8707 && code != CM_ERROR_GSSCONTINUE) {
8708 /* nuke wct and bcc. For a partial
8709 * write or an in-process authentication handshake,
8710 * assume they're OK.
8716 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8717 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8718 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8719 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8720 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8724 smb_MapCoreError(code, vcp, &errCode, &errClass);
8725 outWctp = outp->wctp;
8726 smbp = (smb_t *) &outp->data;
8727 if (code != CM_ERROR_PARTIALWRITE) {
8728 /* nuke wct and bcc. For a partial
8729 * write, assume they're OK.
8735 smbp->errLow = (unsigned char) (errCode & 0xff);
8736 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8737 smbp->rcls = errClass;
8740 } /* error occurred */
8742 /* if we're here, we've finished one request. Look to see if
8743 * this is a chained opcode. If it is, setup things to process
8744 * the chained request, and setup the output buffer to hold the
8745 * chained response. Start by finding the next input record.
8747 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8748 break; /* not a chained req */
8749 tp = inp->wctp; /* points to start of last request */
8750 /* in a chained request, the first two
8751 * parm fields are required, and are
8752 * AndXCommand/AndXReserved and
8754 if (tp[0] < 2) break;
8755 if (tp[1] == 0xff) break; /* no more chained opcodes */
8757 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8760 /* and now append the next output request to the end of this
8761 * last request. Begin by finding out where the last response
8762 * ends, since that's where we'll put our new response.
8764 outWctp = outp->wctp; /* ptr to out parameters */
8765 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8766 nparms = outWctp[0] << 1;
8767 tp = outWctp + nparms + 1; /* now points to bcc field */
8768 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8769 tp += 2 /* for the count itself */ + nbytes;
8770 /* tp now points to the new output record; go back and patch the
8771 * second parameter (off2) to point to the new record.
8773 temp = (unsigned int)(tp - outp->data);
8774 outWctp[3] = (unsigned char) (temp & 0xff);
8775 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8776 outWctp[2] = 0; /* padding */
8777 outWctp[1] = inp->inCom; /* next opcode */
8779 /* finally, setup for the next iteration */
8782 } /* while loop over all requests in the packet */
8784 /* now send the output packet, and return */
8786 smb_SendPacket(vcp, outp);
8787 thrd_Decrement(&ongoingOps);
8792 /* Wait for Netbios() calls to return, and make the results available to server
8793 * threads. Note that server threads can't wait on the NCBevents array
8794 * themselves, because NCB events are manual-reset, and the servers would race
8795 * each other to reset them.
8797 void smb_ClientWaiter(void *parmp)
8802 while (smbShutdownFlag == 0) {
8803 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8805 if (code == WAIT_OBJECT_0)
8808 /* error checking */
8809 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8811 int abandonIdx = code - WAIT_ABANDONED_0;
8812 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8815 if (code == WAIT_IO_COMPLETION)
8817 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8821 if (code == WAIT_TIMEOUT)
8823 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8826 if (code == WAIT_FAILED)
8828 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8831 idx = code - WAIT_OBJECT_0;
8833 /* check idx range! */
8834 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8836 /* this is fatal - log as much as possible */
8837 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8838 osi_assertx(0, "invalid index");
8841 thrd_ResetEvent(NCBevents[idx]);
8842 thrd_SetEvent(NCBreturns[0][idx]);
8847 * Try to have one NCBRECV request waiting for every live session. Not more
8848 * than one, because if there is more than one, it's hard to handle Write Raw.
8850 void smb_ServerWaiter(void *parmp)
8853 int idx_session, idx_NCB;
8856 while (smbShutdownFlag == 0) {
8858 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8860 if (code == WAIT_OBJECT_0)
8863 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8865 int abandonIdx = code - WAIT_ABANDONED_0;
8866 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8869 if (code == WAIT_IO_COMPLETION)
8871 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8875 if (code == WAIT_TIMEOUT)
8877 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8880 if (code == WAIT_FAILED)
8882 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8885 idx_session = code - WAIT_OBJECT_0;
8887 /* check idx range! */
8888 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8890 /* this is fatal - log as much as possible */
8891 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8892 osi_assertx(0, "invalid index");
8897 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8899 if (code == WAIT_OBJECT_0) {
8900 if (smbShutdownFlag == 1)
8906 /* error checking */
8907 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8909 int abandonIdx = code - WAIT_ABANDONED_0;
8910 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8913 if (code == WAIT_IO_COMPLETION)
8915 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8919 if (code == WAIT_TIMEOUT)
8921 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8924 if (code == WAIT_FAILED)
8926 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8929 idx_NCB = code - WAIT_OBJECT_0;
8931 /* check idx range! */
8932 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8934 /* this is fatal - log as much as possible */
8935 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8936 osi_assertx(0, "invalid index");
8939 /* Link them together */
8940 NCBsessions[idx_NCB] = idx_session;
8943 ncbp = NCBs[idx_NCB];
8944 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8945 ncbp->ncb_command = NCBRECV | ASYNCH;
8946 ncbp->ncb_lana_num = lanas[idx_session];
8947 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8948 ncbp->ncb_event = NCBevents[idx_NCB];
8949 ncbp->ncb_length = SMB_PACKETSIZE;
8954 typedef struct _monitored_task {
8957 LARGE_INTEGER start_time;
8959 BOOL trace_timer_hit;
8960 BOOL dump_timer_hit;
8963 typedef struct osi_queueHT {
8964 osi_queue_t * headp;
8965 osi_queue_t * tailp;
8968 static osi_queue_t *smb_monitored_tasks = NULL;
8969 static osi_queue_t *smb_free_monitored_tasks = NULL;
8971 static osi_mutex_t _monitor_mx;
8973 static HANDLE h_monitored_task_queue = NULL;
8974 static HANDLE h_monitored_task_shutdown = NULL;
8976 static time_t smb_last_dump_time = 0;
8978 DWORD smb_monitorReqs = 0;
8980 /* FILETIME comparison fuzz */
8981 #define MONITOR_FUZZ_TIMEOUT (1 * 10000000i64)
8983 /* Trace timeout is at 60 seconds */
8984 #define MONITOR_TRACE_TIMEOUT (60 * 10000000i64)
8986 /* Dump timeout is at 120 seconds */
8987 #define MONITOR_DUMP_TIMEOUT (120 * 10000000i64)
8989 /* Time before another dump is performed in seconds*/
8990 #define MONITOR_DUMP_RESET_TIMEOUT (600)
8992 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
8995 LARGE_INTEGER earliest;
8998 GetSystemTimeAsFileTime(&now);
8999 earliest.LowPart = now.dwLowDateTime;
9000 earliest.HighPart = now.dwHighDateTime;
9001 earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
9003 while ((t = (monitored_task *) taskmq->headp) != NULL &&
9005 (t->start_time.QuadPart < earliest.QuadPart ||
9007 t->dump_timer_hit)) {
9009 osi_QRemoveHT(&taskmq->headp,
9013 lock_ObtainMutex(&_monitor_mx);
9014 osi_QAdd(&smb_free_monitored_tasks, &t->q);
9015 lock_ReleaseMutex(&_monitor_mx);
9018 #ifdef INVARIANT_CHECK
9024 for (t = (monitored_task *) taskmq->headp;
9026 t = (monitored_task *) osi_QNext(&t->q)) {
9027 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9028 last.QuadPart = t->start_time.QuadPart;
9034 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
9036 monitored_task * task;
9037 monitored_task * tasks;
9039 lock_ObtainMutex(&_monitor_mx);
9040 tasks = (monitored_task *) smb_monitored_tasks;
9041 smb_monitored_tasks = NULL;
9042 lock_ReleaseMutex(&_monitor_mx);
9047 osi_QRemove((osi_queue_t **) &tasks, &task->q);
9049 if (task->started) {
9055 q.prevp = taskmq->tailp;
9057 /* Insertion sort by start_time. Earliest request is
9058 first. Since we are likely to receive new requests
9059 later, we start inserting from the back. */
9062 ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
9066 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
9067 else if (p->prevp == NULL)
9068 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
9070 osi_queue_t *o = p->prevp;
9072 osi_assert(o->nextp == p);
9076 p->prevp = &task->q;
9077 o->nextp = &task->q;
9081 /* Some task ending */
9085 for (p = taskmq->headp;
9089 monitored_task * mt = (monitored_task *) p;
9091 if (mt->task_id == task->task_id) {
9093 osi_QRemoveHT(&taskmq->headp,
9096 lock_ObtainMutex(&_monitor_mx);
9097 osi_QAdd(&smb_free_monitored_tasks, p);
9098 lock_ReleaseMutex(&_monitor_mx);
9104 lock_ObtainMutex(&_monitor_mx);
9105 osi_QAdd(&smb_free_monitored_tasks, &task->q);
9106 lock_ReleaseMutex(&_monitor_mx);
9110 #ifdef INVARIANT_CHECK
9117 for (t = (monitored_task *) taskmq->headp;
9119 t = (monitored_task *) osi_QNext(&t->q)) {
9120 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9121 last.QuadPart = t->start_time.QuadPart;
9127 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9129 if (!task->trace_timer_hit) {
9131 task->trace_timer_hit = TRUE;
9133 osi_LogEnable(afsd_logp);
9134 rx_DebugOnOff(TRUE);
9136 } else if (!task->dump_timer_hit) {
9141 if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9142 task->dump_timer_hit = TRUE;
9143 smb_last_dump_time = now;
9145 GenerateMiniDump(NULL);
9151 * Server request monitoring
9153 * The server monitor runs in a separate thread and monitors server
9154 * requests for potential timeouts. It examines notifcations queued
9155 * by smb_NotifyRequestEvent() and waits for potential timeout events:
9157 * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9158 * enables trace logging.
9160 * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9161 * out a dump file that will hopefully contain enough evidence to
9162 * figure out why the timeout event occurred.
9165 void smb_ServerMonitor(VOID * parmp)
9167 osi_queueHT_t in_progress = { NULL, NULL };
9168 HANDLE h_timer = NULL;
9172 h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9173 h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9174 h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9176 lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9178 h_all[0] = h_monitored_task_queue;
9180 h_all[2] = h_monitored_task_shutdown;
9185 rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9187 if (rv == WAIT_OBJECT_0) {
9189 smb_SlurpNewTaskMonitors(&in_progress);
9191 } else if (rv == WAIT_OBJECT_0 + 1) {
9193 smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9201 /* refresh timers */
9205 smb_PurgeOldTaskMonitors(&in_progress);
9206 t = (monitored_task *) in_progress.headp;
9208 if (t && !t->trace_timer_hit) {
9211 due = t->start_time;
9212 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9214 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9215 } else if (t && !t->dump_timer_hit) {
9219 due = t->start_time;
9220 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9222 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9224 CancelWaitableTimer(h_timer);
9226 /* CancelWaitableTimer() doesn't reset the timer if it
9227 was already signalled. */
9228 WaitForSingleObject(h_timer, 0);
9236 h = h_monitored_task_queue;
9237 h_monitored_task_queue = NULL;
9240 h = h_monitored_task_shutdown;
9241 h_monitored_task_shutdown = NULL;
9244 CloseHandle(h_timer);
9246 lock_FinalizeMutex(&_monitor_mx);
9250 monitored_task * task;
9252 while (in_progress.headp) {
9253 task = (monitored_task *) in_progress.headp;
9254 osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9258 for (task = (monitored_task *) smb_free_monitored_tasks;
9259 task; task = (monitored_task *) smb_free_monitored_tasks) {
9260 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9264 for (task = (monitored_task *) smb_monitored_tasks;
9265 task; task = (monitored_task *) smb_monitored_tasks) {
9266 osi_QRemove(&smb_monitored_tasks, &task->q);
9272 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9274 monitored_task * task;
9276 lock_ObtainMutex(&_monitor_mx);
9277 task = (monitored_task *) smb_free_monitored_tasks;
9279 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9280 lock_ReleaseMutex(&_monitor_mx);
9283 task = malloc(sizeof(monitored_task));
9284 memset(task, 0, sizeof(*task));
9286 task->task_id = task_id;
9287 task->started = started;
9292 GetSystemTimeAsFileTime(&now);
9293 task->start_time.HighPart = now.dwHighDateTime;
9294 task->start_time.LowPart = now.dwLowDateTime;
9297 lock_ObtainMutex(&_monitor_mx);
9298 osi_QAdd(&smb_monitored_tasks, &task->q);
9299 lock_ReleaseMutex(&_monitor_mx);
9301 SetEvent(h_monitored_task_queue);
9304 void smb_ShutdownMonitor()
9306 SetEvent(h_monitored_task_shutdown);
9310 * The top level loop for handling SMB request messages. Each server thread
9311 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9312 * NCB and buffer for the incoming request are loaned to us.
9314 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
9315 * to immediately send a request for the rest of the data. This must come
9316 * before any other traffic for that session, so we delay setting the session
9317 * event until that data has come in.
9319 void smb_Server(VOID *parmp)
9321 INT_PTR myIdx = (INT_PTR) parmp;
9325 smb_packet_t *outbufp;
9327 int idx_NCB, idx_session;
9329 smb_vc_t *vcp = NULL;
9332 rx_StartClientThread();
9334 outncbp = smb_GetNCB();
9335 outbufp = smb_GetPacket();
9336 outbufp->ncbp = outncbp;
9344 cm_ResetServerPriority();
9346 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9349 /* terminate silently if shutdown flag is set */
9350 if (code == WAIT_OBJECT_0) {
9351 if (smbShutdownFlag == 1) {
9352 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9358 /* error checking */
9359 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9361 int abandonIdx = code - WAIT_ABANDONED_0;
9362 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9365 if (code == WAIT_IO_COMPLETION)
9367 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9371 if (code == WAIT_TIMEOUT)
9373 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9376 if (code == WAIT_FAILED)
9378 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9381 idx_NCB = code - WAIT_OBJECT_0;
9383 /* check idx range! */
9384 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9386 /* this is fatal - log as much as possible */
9387 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9388 osi_assertx(0, "invalid index");
9391 ncbp = NCBs[idx_NCB];
9392 idx_session = NCBsessions[idx_NCB];
9393 rc = ncbp->ncb_retcode;
9395 if (rc != NRC_PENDING && rc != NRC_GOODRET)
9396 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9400 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9404 /* Can this happen? Or is it just my UNIX paranoia? */
9405 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9410 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9413 /* Client closed session */
9414 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9416 lock_ObtainMutex(&vcp->mx);
9417 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9418 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9420 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9421 lock_ReleaseMutex(&vcp->mx);
9422 lock_ObtainWrite(&smb_globalLock);
9423 dead_sessions[vcp->session] = TRUE;
9424 lock_ReleaseWrite(&smb_globalLock);
9426 lock_ReleaseMutex(&vcp->mx);
9428 smb_CleanupDeadVC(vcp);
9435 /* Treat as transient error */
9436 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9439 "dispatch smb recv failed, message incomplete, ncb_length %d",
9442 "SMB message incomplete, "
9443 "length %d", ncbp->ncb_length);
9446 * We used to discard the packet.
9447 * Instead, try handling it normally.
9451 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9455 /* A weird error code. Log it, sleep, and continue. */
9456 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9458 lock_ObtainMutex(&vcp->mx);
9459 if (vcp->errorCount++ > 3) {
9460 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9461 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9462 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9464 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9465 lock_ReleaseMutex(&vcp->mx);
9466 lock_ObtainWrite(&smb_globalLock);
9467 dead_sessions[vcp->session] = TRUE;
9468 lock_ReleaseWrite(&smb_globalLock);
9470 lock_ReleaseMutex(&vcp->mx);
9472 smb_CleanupDeadVC(vcp);
9478 lock_ReleaseMutex(&vcp->mx);
9482 thrd_SetEvent(SessionEvents[idx_session]);
9488 /* Success, so now dispatch on all the data in the packet */
9490 smb_concurrentCalls++;
9491 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9492 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9495 * If at this point vcp is NULL (implies that packet was invalid)
9496 * then we are in big trouble. This means either :
9497 * a) we have the wrong NCB.
9498 * b) Netbios screwed up the call.
9499 * c) The VC was already marked dead before we were able to
9501 * Obviously this implies that
9502 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9503 * lanas[idx_session] != ncbp->ncb_lana_num )
9504 * Either way, we can't do anything with this packet.
9505 * Log, sleep and resume.
9508 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9512 ncbp->ncb_lana_num);
9514 /* Also log in the trace log. */
9515 osi_Log4(smb_logp, "Server: VCP does not exist!"
9516 "LSNs[idx_session]=[%d],"
9517 "lanas[idx_session]=[%d],"
9518 "ncbp->ncb_lsn=[%d],"
9519 "ncbp->ncb_lana_num=[%d]",
9523 ncbp->ncb_lana_num);
9525 /* thrd_Sleep(1000); Don't bother sleeping */
9526 thrd_SetEvent(SessionEvents[idx_session]);
9527 smb_concurrentCalls--;
9531 cm_SetRequestStartTime();
9532 if (smb_monitorReqs) {
9533 smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9536 vcp->errorCount = 0;
9537 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9538 smbp = (smb_t *)bufp->data;
9545 if (smbp->com == 0x1d) {
9546 /* Special handling for Write Raw */
9547 raw_write_cont_t rwc;
9549 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9550 if (rwc.code == 0) {
9551 EVENT_HANDLE rwevent;
9552 char eventName[MAX_PATH];
9554 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9555 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9556 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9557 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9559 ncbp->ncb_command = NCBRECV | ASYNCH;
9560 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9561 ncbp->ncb_lana_num = vcp->lana;
9562 ncbp->ncb_buffer = rwc.buf;
9563 ncbp->ncb_length = 65535;
9564 ncbp->ncb_event = rwevent;
9566 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9567 thrd_CloseHandle(rwevent);
9569 thrd_SetEvent(SessionEvents[idx_session]);
9571 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9573 else if (smbp->com == 0xa0) {
9575 * Serialize the handling for NT Transact
9578 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9579 thrd_SetEvent(SessionEvents[idx_session]);
9581 thrd_SetEvent(SessionEvents[idx_session]);
9582 /* TODO: what else needs to be serialized? */
9583 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9587 __except( smb_ServerExceptionFilter() ) {
9591 if (smb_monitorReqs) {
9592 smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9594 smb_concurrentCalls--;
9597 thrd_SetEvent(NCBavails[idx_NCB]);
9602 smb_FreePacket(outbufp);
9604 smb_FreeNCB(outncbp);
9608 * Exception filter for the server threads. If an exception occurs in the
9609 * dispatch routines, which is where exceptions are most common, then do a
9610 * force trace and give control to upstream exception handlers. Useful for
9613 DWORD smb_ServerExceptionFilter(void) {
9614 /* While this is not the best time to do a trace, if it succeeds, then
9615 * we have a trace (assuming tracing was enabled). Otherwise, this should
9616 * throw a second exception.
9618 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9619 afsd_ForceTrace(TRUE);
9620 buf_ForceTrace(TRUE);
9621 return EXCEPTION_CONTINUE_SEARCH;
9625 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9626 * If the number of server threads is M, and the number of live sessions is
9627 * N, then the number of NCB's in use at any time either waiting for, or
9628 * holding, received messages is M + N, so that is how many NCB's get created.
9630 void InitNCBslot(int idx)
9632 struct smb_packet *bufp;
9633 EVENT_HANDLE retHandle;
9635 char eventName[MAX_PATH];
9637 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9639 NCBs[idx] = smb_GetNCB();
9640 sprintf(eventName,"NCBavails[%d]", idx);
9641 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9642 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9643 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9644 sprintf(eventName,"NCBevents[%d]", idx);
9645 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9646 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9647 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9648 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9649 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9650 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9651 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9652 for (i=0; i<smb_NumServerThreads; i++)
9653 NCBreturns[i][idx] = retHandle;
9654 bufp = smb_GetPacket();
9655 bufp->spacep = cm_GetSpace();
9659 /* listen for new connections */
9660 void smb_Listener(void *parmp)
9666 afs_uint32 session, thread;
9667 smb_vc_t *vcp = NULL;
9669 char rname[NCBNAMSZ+1];
9670 char cname[MAX_COMPUTERNAME_LENGTH+1];
9671 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9672 INT_PTR lana = (INT_PTR) parmp;
9673 char eventName[MAX_PATH];
9674 int bridgeCount = 0;
9675 int nowildCount = 0;
9677 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9678 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9679 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9680 thrd_ResetEvent(ListenerShutdown[lana]);
9682 ncbp = smb_GetNCB();
9684 /* retrieve computer name */
9685 GetComputerName(cname, &cnamelen);
9688 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9689 memset(ncbp, 0, sizeof(NCB));
9692 ncbp->ncb_command = NCBLISTEN;
9693 ncbp->ncb_rto = 0; /* No receive timeout */
9694 ncbp->ncb_sto = 0; /* No send timeout */
9696 /* pad out with spaces instead of null termination */
9697 len = (long)strlen(smb_localNamep);
9698 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9699 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9701 strcpy(ncbp->ncb_callname, "*");
9702 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9704 ncbp->ncb_lana_num = (UCHAR)lana;
9706 code = Netbios(ncbp);
9708 if (code == NRC_NAMERR) {
9709 /* An smb shutdown or Vista resume must have taken place */
9711 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9712 ncbp->ncb_lana_num);
9713 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9715 if (lock_TryMutex(&smb_StartedLock)) {
9716 lana_list.lana[i] = LANA_INVALID;
9717 lock_ReleaseMutex(&smb_StartedLock);
9720 } else if (code == NRC_BRIDGE || code != 0) {
9721 int lanaRemaining = 0;
9723 if (code == NRC_BRIDGE) {
9724 if (++bridgeCount <= 5) {
9725 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9728 } else if (code == NRC_NOWILD) {
9729 if (++nowildCount <= 5) {
9730 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9732 if (bridgeCount > 0) {
9733 memset(ncbp, 0, sizeof(*ncbp));
9734 ncbp->ncb_command = NCBADDNAME;
9735 ncbp->ncb_lana_num = (UCHAR)lana;
9736 /* pad out with spaces instead of null termination */
9737 len = (long)strlen(smb_localNamep);
9738 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9739 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9740 code = Netbios(ncbp);
9746 while (!lock_TryMutex(&smb_StartedLock)) {
9747 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9753 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9754 ncbp->ncb_lana_num, ncb_error_string(code));
9755 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9756 ncbp->ncb_lana_num, ncb_error_string(code));
9758 for (i = 0; i < lana_list.length; i++) {
9759 if (lana_list.lana[i] == lana) {
9760 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9761 lana_list.lana[i] = LANA_INVALID;
9763 if (lana_list.lana[i] != LANA_INVALID)
9767 if (lanaRemaining == 0) {
9768 cm_VolStatus_Network_Stopped(cm_NetbiosName
9773 smb_ListenerState = SMB_LISTENER_STOPPED;
9774 smb_LANadapter = LANA_INVALID;
9775 lana_list.length = 0;
9777 lock_ReleaseMutex(&smb_StartedLock);
9781 else if (code != 0) {
9782 char tbuffer[AFSPATHMAX];
9784 /* terminate silently if shutdown flag is set */
9785 while (!lock_TryMutex(&smb_StartedLock)) {
9786 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9792 "NCBLISTEN lana=%d failed with code %d [%s]",
9793 ncbp->ncb_lana_num, code, ncb_error_string(code));
9795 "Client exiting due to network failure. Please restart client.\n");
9798 "Client exiting due to network failure. Please restart client.\n"
9799 "NCBLISTEN lana=%d failed with code %d [%s]",
9800 ncbp->ncb_lana_num, code, ncb_error_string(code));
9802 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9803 MB_OK|MB_SERVICE_NOTIFICATION);
9804 osi_panic(tbuffer, __FILE__, __LINE__);
9806 lock_ReleaseMutex(&smb_StartedLock);
9811 /* a successful packet received. clear bridge error count */
9815 /* check for remote conns */
9816 /* first get remote name and insert null terminator */
9817 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9818 for (i=NCBNAMSZ; i>0; i--) {
9819 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9825 /* compare with local name */
9827 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9828 flags |= SMB_VCFLAG_REMOTECONN;
9831 lock_ObtainMutex(&smb_ListenerLock);
9833 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9834 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9836 /* now ncbp->ncb_lsn is the connection ID */
9837 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9838 if (vcp->session == 0) {
9839 /* New generation */
9840 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9843 /* Log session startup */
9845 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9846 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9847 #endif /* NOTSERVICE */
9848 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9849 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9851 if (reportSessionStartups) {
9852 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9855 lock_ObtainMutex(&vcp->mx);
9856 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9857 vcp->flags |= flags;
9858 lock_ReleaseMutex(&vcp->mx);
9860 /* Allocate slot in session arrays */
9861 /* Re-use dead session if possible, otherwise add one more */
9862 /* But don't look at session[0], it is reserved */
9863 lock_ObtainWrite(&smb_globalLock);
9864 for (session = 1; session < numSessions; session++) {
9865 if (dead_sessions[session]) {
9866 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9867 dead_sessions[session] = FALSE;
9871 lock_ReleaseWrite(&smb_globalLock);
9873 /* We are re-using an existing VC because the lsn and lana
9875 session = vcp->session;
9877 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9879 /* Log session startup */
9881 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9882 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9883 #endif /* NOTSERVICE */
9884 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9885 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9887 if (reportSessionStartups) {
9888 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9892 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9893 unsigned long code = CM_ERROR_ALLBUSY;
9894 smb_packet_t * outp = smb_GetPacket();
9895 unsigned char *outWctp;
9898 smb_FormatResponsePacket(vcp, NULL, outp);
9901 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9902 unsigned long NTStatus;
9903 smb_MapNTError(code, &NTStatus, FALSE);
9904 outWctp = outp->wctp;
9905 smbp = (smb_t *) &outp->data;
9909 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9910 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9911 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9912 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9913 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9915 unsigned short errCode;
9916 unsigned char errClass;
9917 smb_MapCoreError(code, vcp, &errCode, &errClass);
9918 outWctp = outp->wctp;
9919 smbp = (smb_t *) &outp->data;
9923 smbp->errLow = (unsigned char) (errCode & 0xff);
9924 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9925 smbp->rcls = errClass;
9928 smb_SendPacket(vcp, outp);
9929 smb_FreePacket(outp);
9931 lock_ObtainMutex(&vcp->mx);
9932 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9933 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9935 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9936 lock_ReleaseMutex(&vcp->mx);
9937 lock_ObtainWrite(&smb_globalLock);
9938 dead_sessions[vcp->session] = TRUE;
9939 lock_ReleaseWrite(&smb_globalLock);
9940 smb_CleanupDeadVC(vcp);
9942 lock_ReleaseMutex(&vcp->mx);
9945 /* assert that we do not exceed the maximum number of sessions or NCBs.
9946 * we should probably want to wait for a session to be freed in case
9949 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9950 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9952 lock_ObtainMutex(&vcp->mx);
9953 vcp->session = session;
9954 lock_ReleaseMutex(&vcp->mx);
9955 lock_ObtainWrite(&smb_globalLock);
9956 LSNs[session] = ncbp->ncb_lsn;
9957 lanas[session] = ncbp->ncb_lana_num;
9958 lock_ReleaseWrite(&smb_globalLock);
9960 if (session == numSessions) {
9961 /* Add new NCB for new session */
9962 char eventName[MAX_PATH];
9964 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9966 InitNCBslot(numNCBs);
9967 lock_ObtainWrite(&smb_globalLock);
9969 lock_ReleaseWrite(&smb_globalLock);
9970 thrd_SetEvent(NCBavails[0]);
9971 thrd_SetEvent(NCBevents[0]);
9972 for (thread = 0; thread < smb_NumServerThreads; thread++)
9973 thrd_SetEvent(NCBreturns[thread][0]);
9974 /* Also add new session event */
9975 sprintf(eventName, "SessionEvents[%d]", session);
9976 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9977 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9978 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9979 lock_ObtainWrite(&smb_globalLock);
9981 lock_ReleaseWrite(&smb_globalLock);
9982 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9983 thrd_SetEvent(SessionEvents[0]);
9985 thrd_SetEvent(SessionEvents[session]);
9991 lock_ReleaseMutex(&smb_ListenerLock);
9992 } /* dispatch while loop */
9996 thrd_SetEvent(ListenerShutdown[lana]);
10001 configureBackConnectionHostNames(void)
10003 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
10004 * there is a restriction on the use of SMB authentication on loopback connections.
10005 * There are two work arounds available:
10007 * (1) We can disable the check for matching host names. This does not
10008 * require a reboot:
10009 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
10010 * "DisableLoopbackCheck"=dword:00000001
10012 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
10013 * does require a reboot:
10014 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
10015 * "BackConnectionHostNames"=multi-sz
10017 * The algorithm will be:
10018 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
10019 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
10020 * (2b1) and check to see if DisableLoopbackCheck is set.
10021 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
10022 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
10023 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
10024 * check for the UnsetDisableLoopbackCheck value.
10025 * If set, set the DisableLoopbackCheck flag to 0x0
10026 * and delete the UnsetDisableLoopbackCheck value
10028 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
10029 * force Windows to use the loopback authentication mechanism for the specified
10032 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
10033 * service session that set it.
10039 DWORD dwSize, dwAllocSize;
10041 PBYTE pHostNames = NULL, pName = NULL;
10042 BOOL bNameFound = FALSE;
10043 static BOOL bLoopbackCheckDisabled = FALSE;
10045 /* BackConnectionHostNames and DisableLoopbackCheck */
10046 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10047 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
10049 KEY_READ|KEY_WRITE,
10050 &hkMSV10) == ERROR_SUCCESS )
10052 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
10053 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10054 (dwType == REG_MULTI_SZ))
10056 dwAllocSize += 1 /* in case the source string is not nul terminated */
10057 + (DWORD)strlen(cm_NetbiosName) + 2;
10058 pHostNames = malloc(dwAllocSize);
10059 dwSize = dwAllocSize;
10060 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
10061 pHostNames, &dwSize) == ERROR_SUCCESS)
10063 for (pName = pHostNames;
10064 (pName - pHostNames < (int) dwSize) && *pName ;
10065 pName += strlen(pName) + 1)
10067 if ( !stricmp(pName, cm_NetbiosName) ) {
10075 if ( !bNameFound ) {
10076 size_t size = strlen(cm_NetbiosName) + 2;
10077 if ( !pHostNames ) {
10078 pHostNames = malloc(size);
10079 pName = pHostNames;
10081 StringCbCopyA(pName, size, cm_NetbiosName);
10083 *pName = '\0'; /* add a second nul terminator */
10085 dwType = REG_MULTI_SZ;
10086 dwSize = (DWORD)(pName - pHostNames + 1);
10087 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10089 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10090 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10092 KEY_READ|KEY_WRITE,
10093 &hkLsa) == ERROR_SUCCESS )
10095 dwSize = sizeof(DWORD);
10096 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
10098 dwType = REG_DWORD;
10099 dwSize = sizeof(DWORD);
10101 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10103 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10104 AFSREG_CLT_OPENAFS_SUBKEY,
10107 REG_OPTION_NON_VOLATILE,
10108 KEY_READ|KEY_WRITE,
10111 NULL) == ERROR_SUCCESS) {
10113 dwType = REG_DWORD;
10114 dwSize = sizeof(DWORD);
10116 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10117 bLoopbackCheckDisabled = TRUE;
10118 RegCloseKey(hkClient);
10120 RegCloseKey(hkLsa);
10123 } else if (!bLoopbackCheckDisabled) {
10124 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10125 AFSREG_CLT_OPENAFS_SUBKEY,
10128 REG_OPTION_NON_VOLATILE,
10129 KEY_READ|KEY_WRITE,
10132 NULL) == ERROR_SUCCESS) {
10134 dwSize = sizeof(DWORD);
10135 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10137 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10138 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10140 KEY_READ|KEY_WRITE,
10141 &hkLsa) == ERROR_SUCCESS )
10143 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10144 RegCloseKey(hkLsa);
10147 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10148 RegCloseKey(hkClient);
10157 RegCloseKey(hkMSV10);
10163 configureExtendedSMBSessionTimeouts(void)
10166 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10167 * new functionality:
10169 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
10170 * "ReconnectableServers" REG_MULTI_SZ
10171 * "ExtendedSessTimeout" REG_DWORD (seconds)
10172 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
10174 * These values can be used to prevent the smb redirector from timing out
10175 * smb connection to the afs smb server prematurely.
10179 DWORD dwSize, dwAllocSize;
10181 PBYTE pHostNames = NULL, pName = NULL;
10182 BOOL bNameFound = FALSE;
10184 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10185 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
10187 KEY_READ|KEY_WRITE,
10188 &hkLanMan) == ERROR_SUCCESS )
10190 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
10191 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10192 (dwType == REG_MULTI_SZ))
10194 dwAllocSize += 1 /* in case the source string is not nul terminated */
10195 + (DWORD)strlen(cm_NetbiosName) + 2;
10196 pHostNames = malloc(dwAllocSize);
10197 dwSize = dwAllocSize;
10198 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
10199 pHostNames, &dwSize) == ERROR_SUCCESS)
10201 for (pName = pHostNames;
10202 (pName - pHostNames < (int) dwSize) && *pName ;
10203 pName += strlen(pName) + 1)
10205 if ( !stricmp(pName, cm_NetbiosName) ) {
10213 if ( !bNameFound ) {
10214 size_t size = strlen(cm_NetbiosName) + 2;
10215 if ( !pHostNames ) {
10216 pHostNames = malloc(size);
10217 pName = pHostNames;
10219 StringCbCopyA(pName, size, cm_NetbiosName);
10221 *pName = '\0'; /* add a second nul terminator */
10223 dwType = REG_MULTI_SZ;
10224 dwSize = (DWORD)(pName - pHostNames + 1);
10225 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10233 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
10234 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10235 (dwType == REG_MULTI_SZ))
10237 dwAllocSize += 1 /* in case the source string is not nul terminated */
10238 + (DWORD)strlen(cm_NetbiosName) + 2;
10239 pHostNames = malloc(dwAllocSize);
10240 dwSize = dwAllocSize;
10241 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
10242 pHostNames, &dwSize) == ERROR_SUCCESS)
10244 for (pName = pHostNames;
10245 (pName - pHostNames < (int) dwSize) && *pName ;
10246 pName += strlen(pName) + 1)
10248 if ( !stricmp(pName, cm_NetbiosName) ) {
10256 if ( !bNameFound ) {
10257 size_t size = strlen(cm_NetbiosName) + 2;
10258 if ( !pHostNames ) {
10259 pHostNames = malloc(size);
10260 pName = pHostNames;
10262 StringCbCopyA(pName, size, cm_NetbiosName);
10264 *pName = '\0'; /* add a second nul terminator */
10266 dwType = REG_MULTI_SZ;
10267 dwSize = (DWORD)(pName - pHostNames + 1);
10268 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10276 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
10277 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10278 (dwType != REG_DWORD))
10280 dwType = REG_DWORD;
10281 dwSize = sizeof(dwValue);
10282 dwValue = 300; /* 5 minutes */
10283 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10285 RegCloseKey(hkLanMan);
10290 smb_LanAdapterChangeThread(void *param)
10293 * Give the IPAddrDaemon thread a chance
10294 * to block before we trigger.
10297 smb_LanAdapterChange(0);
10300 void smb_SetLanAdapterChangeDetected(void)
10305 lock_ObtainMutex(&smb_StartedLock);
10307 if (!powerStateSuspended) {
10308 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10309 NULL, 0, &lpid, "smb_LanAdapterChange");
10310 if (phandle == NULL) {
10314 gle = GetLastError();
10315 StringCchPrintf( msg, sizeof(msg)/sizeof(msg[0]),
10316 "smb_LanAdapterChangeThread thread creation failure - gle 0x%x",
10318 osi_assertx(TRUE, msg);
10320 thrd_CloseHandle(phandle);
10323 smb_LanAdapterChangeDetected = 1;
10324 lock_ReleaseMutex(&smb_StartedLock);
10327 void smb_LanAdapterChange(int locked) {
10328 lana_number_t lanaNum;
10330 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
10332 LANA_ENUM temp_list;
10337 afsi_log("smb_LanAdapterChange");
10340 lock_ObtainMutex(&smb_StartedLock);
10342 smb_LanAdapterChangeDetected = 0;
10344 if (!powerStateSuspended &&
10345 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10346 LANA_NETBIOS_NAME_FULL | LANA_NETBIOS_NO_RESET)) &&
10347 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10348 if ( isGateway != bGateway ) {
10349 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10350 smb_LANadapter, lanaNum, isGateway, bGateway);
10352 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10353 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10354 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10357 NCB *ncbp = smb_GetNCB();
10358 ncbp->ncb_command = NCBENUM;
10359 ncbp->ncb_buffer = (PUCHAR)&temp_list;
10360 ncbp->ncb_length = sizeof(temp_list);
10361 code = Netbios(ncbp);
10363 if (temp_list.length != lana_list.length) {
10364 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10365 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10368 for (i=0; i<lana_list.length; i++) {
10369 if ( temp_list.lana[i] != lana_list.lana[i] ) {
10370 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10371 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10383 smb_StopListeners(1);
10384 smb_RestartListeners(1);
10387 lock_ReleaseMutex(&smb_StartedLock);
10390 /* initialize Netbios */
10391 int smb_NetbiosInit(int locked)
10394 int i, lana, code, l;
10396 int delname_tried=0;
10398 int lana_found = 0;
10399 lana_number_t lanaNum;
10405 lock_ObtainMutex(&smb_StartedLock);
10407 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10408 smb_ListenerState != SMB_LISTENER_STOPPED) {
10411 lock_ReleaseMutex(&smb_StartedLock);
10414 /* setup the NCB system */
10415 ncbp = smb_GetNCB();
10418 * Call lanahelper to get Netbios name, lan adapter number and gateway flag
10419 * This will reset all of the network adapter's netbios state.
10421 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10422 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10424 if (smb_LANadapter != LANA_INVALID)
10425 afsi_log("LAN adapter number %d", smb_LANadapter);
10427 afsi_log("LAN adapter number not determined");
10430 afsi_log("Set for gateway service");
10432 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10434 /* something went horribly wrong. We can't proceed without a netbios name */
10436 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10437 osi_panic(buf, __FILE__, __LINE__);
10440 /* remember the name */
10441 len = (int)strlen(cm_NetbiosName);
10442 if (smb_localNamep)
10443 free(smb_localNamep);
10444 smb_localNamep = malloc(len+1);
10445 strcpy(smb_localNamep, cm_NetbiosName);
10446 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10448 /* Also copy the value to the client character encoded string */
10449 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10451 if (smb_LANadapter == LANA_INVALID) {
10452 ncbp->ncb_command = NCBENUM;
10453 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10454 ncbp->ncb_length = sizeof(lana_list);
10455 code = Netbios(ncbp);
10457 afsi_log("Netbios NCBENUM error code %d", code);
10458 osi_panic(s, __FILE__, __LINE__);
10462 lana_list.length = 1;
10463 lana_list.lana[0] = smb_LANadapter;
10466 for (i = 0; i < lana_list.length; i++) {
10467 /* reset the adaptor: in Win32, this is required for every process, and
10468 * acts as an init call, not as a real hardware reset.
10470 ncbp->ncb_command = NCBRESET;
10471 ncbp->ncb_callname[0] = 100;
10472 ncbp->ncb_callname[2] = 100;
10473 ncbp->ncb_lana_num = lana_list.lana[i];
10474 code = Netbios(ncbp);
10476 code = ncbp->ncb_retcode;
10478 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10479 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10481 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10485 /* and declare our name so we can receive connections */
10486 memset(ncbp, 0, sizeof(*ncbp));
10487 len=lstrlen(smb_localNamep);
10488 memset(smb_sharename,' ',NCBNAMSZ);
10489 memcpy(smb_sharename,smb_localNamep,len);
10490 afsi_log("lana_list.length %d", lana_list.length);
10492 /* Keep the name so we can unregister it later */
10493 for (l = 0; l < lana_list.length; l++) {
10494 lana = lana_list.lana[l];
10496 ncbp->ncb_command = NCBADDNAME;
10497 ncbp->ncb_lana_num = lana;
10498 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10499 code = Netbios(ncbp);
10501 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10502 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10504 char name[NCBNAMSZ+1];
10506 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10507 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10511 code = ncbp->ncb_retcode;
10514 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10517 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10518 if (code == NRC_BRIDGE) { /* invalid LANA num */
10519 lana_list.lana[l] = LANA_INVALID;
10522 else if (code == NRC_DUPNAME) {
10523 afsi_log("Name already exists; try to delete it");
10524 memset(ncbp, 0, sizeof(*ncbp));
10525 ncbp->ncb_command = NCBDELNAME;
10526 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10527 ncbp->ncb_lana_num = lana;
10528 code = Netbios(ncbp);
10530 code = ncbp->ncb_retcode;
10532 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10534 if (code != 0 || delname_tried) {
10535 lana_list.lana[l] = LANA_INVALID;
10537 else if (code == 0) {
10538 if (!delname_tried) {
10546 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10547 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10551 smb_LANadapter = lana;
10552 lana_found = 1; /* at least one worked */
10556 osi_assertx(lana_list.length >= 0, "empty lana list");
10558 afsi_log("No valid LANA numbers found!");
10559 lana_list.length = 0;
10560 smb_LANadapter = LANA_INVALID;
10561 smb_ListenerState = SMB_LISTENER_STOPPED;
10562 cm_VolStatus_Network_Stopped(cm_NetbiosName
10569 /* we're done with the NCB now */
10572 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10573 if (lana_list.length > 0)
10574 osi_assert(smb_LANadapter != LANA_INVALID);
10577 lock_ReleaseMutex(&smb_StartedLock);
10579 return (lana_list.length > 0 ? 1 : 0);
10582 void smb_StartListeners(int locked)
10592 lock_ObtainMutex(&smb_StartedLock);
10594 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10596 lock_ReleaseMutex(&smb_StartedLock);
10600 afsi_log("smb_StartListeners");
10601 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10602 configureBackConnectionHostNames();
10604 /* Configure Extended SMB Session Timeouts */
10605 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10606 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10607 configureExtendedSMBSessionTimeouts();
10610 smb_ListenerState = SMB_LISTENER_STARTED;
10611 cm_VolStatus_Network_Started(cm_NetbiosName
10617 for (i = 0; i < lana_list.length; i++) {
10618 if (lana_list.lana[i] == LANA_INVALID)
10620 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10621 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10622 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10623 thrd_CloseHandle(phandle);
10626 lock_ReleaseMutex(&smb_StartedLock);
10629 void smb_RestartListeners(int locked)
10635 lock_ObtainMutex(&smb_StartedLock);
10637 if (powerStateSuspended)
10638 afsi_log("smb_RestartListeners called while suspended");
10640 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10641 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10642 if (smb_NetbiosInit(1))
10643 smb_StartListeners(1);
10644 } else if (smb_LanAdapterChangeDetected) {
10645 smb_LanAdapterChange(1);
10649 lock_ReleaseMutex(&smb_StartedLock);
10652 void smb_StopListener(NCB *ncbp, int lana, int wait)
10656 memset(ncbp, 0, sizeof(*ncbp));
10657 ncbp->ncb_command = NCBDELNAME;
10658 ncbp->ncb_lana_num = lana;
10659 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10660 code = Netbios(ncbp);
10662 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10663 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10665 /* and then reset the LANA; this will cause the listener threads to exit */
10666 ncbp->ncb_command = NCBRESET;
10667 ncbp->ncb_callname[0] = 100;
10668 ncbp->ncb_callname[2] = 100;
10669 ncbp->ncb_lana_num = lana;
10670 code = Netbios(ncbp);
10672 code = ncbp->ncb_retcode;
10674 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10676 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10680 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10683 void smb_StopListeners(int locked)
10692 lock_ObtainMutex(&smb_StartedLock);
10694 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10696 lock_ReleaseMutex(&smb_StartedLock);
10700 afsi_log("smb_StopListeners");
10701 smb_ListenerState = SMB_LISTENER_STOPPED;
10702 cm_VolStatus_Network_Stopped(cm_NetbiosName
10708 ncbp = smb_GetNCB();
10710 /* Unregister the SMB name */
10711 for (l = 0; l < lana_list.length; l++) {
10712 lana = lana_list.lana[l];
10714 if (lana != LANA_INVALID) {
10715 smb_StopListener(ncbp, lana, TRUE);
10717 /* mark the adapter invalid */
10718 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10722 /* force a re-evaluation of the network adapters */
10723 lana_list.length = 0;
10724 smb_LANadapter = LANA_INVALID;
10727 lock_ReleaseMutex(&smb_StartedLock);
10730 void smb_Init(osi_log_t *logp, int useV3,
10740 EVENT_HANDLE retHandle;
10741 char eventName[MAX_PATH];
10742 int startListeners = 0;
10747 smb_MBfunc = aMBfunc;
10751 /* Initialize smb_localZero */
10752 myTime.tm_isdst = -1; /* compute whether on DST or not */
10753 myTime.tm_year = 70;
10755 myTime.tm_mday = 1;
10756 myTime.tm_hour = 0;
10759 smb_localZero = mktime(&myTime);
10761 #ifdef AFS_FREELANCE_CLIENT
10762 /* Make sure the root.afs volume has the correct time */
10763 cm_noteLocalMountPointChange(FALSE);
10766 /* initialize the remote debugging log */
10769 /* and the global lock */
10770 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10771 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10773 /* Raw I/O data structures */
10774 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10776 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10777 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10779 /* 4 Raw I/O buffers */
10780 smb_RawBufs = calloc(65536,1);
10781 *((char **)smb_RawBufs) = NULL;
10782 for (i=0; i<3; i++) {
10783 char *rawBuf = calloc(65536,1);
10784 *((char **)rawBuf) = smb_RawBufs;
10785 smb_RawBufs = rawBuf;
10788 /* global free lists */
10789 smb_ncbFreeListp = NULL;
10790 smb_packetFreeListp = NULL;
10792 lock_ObtainMutex(&smb_StartedLock);
10793 startListeners = smb_NetbiosInit(1);
10795 /* Initialize listener and server structures */
10797 memset(dead_sessions, 0, sizeof(dead_sessions));
10798 sprintf(eventName, "SessionEvents[0]");
10799 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10800 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10801 afsi_log("Event Object Already Exists: %s", eventName);
10803 smb_NumServerThreads = nThreads;
10804 sprintf(eventName, "NCBavails[0]");
10805 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10806 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10807 afsi_log("Event Object Already Exists: %s", eventName);
10808 sprintf(eventName, "NCBevents[0]");
10809 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10810 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10811 afsi_log("Event Object Already Exists: %s", eventName);
10812 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10813 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10814 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10815 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10816 afsi_log("Event Object Already Exists: %s", eventName);
10817 for (i = 0; i < smb_NumServerThreads; i++) {
10818 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10819 NCBreturns[i][0] = retHandle;
10822 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10823 for (i = 0; i < smb_NumServerThreads; i++) {
10824 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10825 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10826 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10827 afsi_log("Event Object Already Exists: %s", eventName);
10828 InitNCBslot((int)(i+1));
10830 numNCBs = smb_NumServerThreads + 1;
10832 /* Initialize dispatch table */
10833 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10834 /* Prepare the table for unknown operations */
10835 for(i=0; i<= SMB_NOPCODES; i++) {
10836 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10838 /* Fill in the ones we do know */
10839 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10840 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10841 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10842 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10843 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10844 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10845 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10846 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10847 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10848 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10849 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10850 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10851 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10852 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10853 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10854 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10855 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10856 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10857 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10858 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10859 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10860 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10861 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10862 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10863 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10864 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10865 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10866 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10867 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10868 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10869 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10870 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10871 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10872 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10873 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10874 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10875 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10876 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10877 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10878 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10879 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10880 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10881 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10882 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10883 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10884 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10885 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10886 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10887 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10888 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10889 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10890 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10891 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10892 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10893 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10894 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10895 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10896 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10897 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10898 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10899 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10900 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10901 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10902 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10903 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10904 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10905 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10906 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10907 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10908 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10909 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10910 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10911 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10912 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10914 /* setup tran 2 dispatch table */
10915 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10916 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10917 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10918 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10919 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10920 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10921 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10922 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10923 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10924 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10925 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10926 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10927 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10928 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10929 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10930 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10931 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10932 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10934 /* setup the rap dispatch table */
10935 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10936 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10937 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10938 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10939 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10943 /* if we are doing SMB authentication we have register outselves as a logon process */
10944 if (smb_authType != SMB_AUTH_NONE) {
10945 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10946 LSA_STRING afsProcessName;
10947 LSA_OPERATIONAL_MODE dummy; /*junk*/
10949 afsProcessName.Buffer = "OpenAFSClientDaemon";
10950 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10951 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10953 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10955 if (nts == STATUS_SUCCESS) {
10956 LSA_STRING packageName;
10957 /* we are registered. Find out the security package id */
10958 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10959 packageName.Length = (USHORT)strlen(packageName.Buffer);
10960 packageName.MaximumLength = packageName.Length + 1;
10961 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10962 if (nts == STATUS_SUCCESS) {
10964 * This code forces Windows to authenticate against the Logon Cache
10965 * first instead of attempting to authenticate against the Domain
10966 * Controller. When the Windows logon cache is enabled this improves
10967 * performance by removing the network access and works around a bug
10968 * seen at sites which are using a MIT Kerberos principal to login
10969 * to machines joined to a non-root domain in a multi-domain forest.
10970 * MsV1_0SetProcessOption was added in Windows XP.
10972 PVOID pResponse = NULL;
10973 ULONG cbResponse = 0;
10974 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10976 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10977 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10978 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10979 OptionsRequest.DisableOptions = FALSE;
10981 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10984 sizeof(OptionsRequest),
10990 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10991 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10994 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10996 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10997 afsi_log("MsV1_0SetProcessOption success");
10999 /* END - code from Larry */
11001 smb_lsaLogonOrigin.Buffer = "OpenAFS";
11002 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
11003 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
11005 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
11007 /* something went wrong. We report the error and revert back to no authentication
11008 because we can't perform any auth requests without a successful lsa handle
11009 or sec package id. */
11010 afsi_log("Reverting to NO SMB AUTH");
11011 smb_authType = SMB_AUTH_NONE;
11014 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
11016 /* something went wrong. We report the error and revert back to no authentication
11017 because we can't perform any auth requests without a successful lsa handle
11018 or sec package id. */
11019 afsi_log("Reverting to NO SMB AUTH");
11020 smb_authType = SMB_AUTH_NONE;
11024 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
11025 * time prevents the failure of authentication when logged into Windows with an
11026 * external Kerberos principal mapped to a local account.
11028 else if ( smb_authType == SMB_AUTH_EXTENDED) {
11029 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
11030 * then the only option is NTLMSSP anyway; so just fallback.
11035 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
11036 if (secBlobLength == 0) {
11037 smb_authType = SMB_AUTH_NTLM;
11038 afsi_log("Reverting to SMB AUTH NTLM");
11047 /* Now get ourselves a domain name. */
11048 /* For now we are using the local computer name as the domain name.
11049 * It is actually the domain for local logins, and we are acting as
11050 * a local SMB server.
11052 bufsize = lengthof(smb_ServerDomainName) - 1;
11053 GetComputerNameW(smb_ServerDomainName, &bufsize);
11054 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
11055 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
11058 /* Start listeners, waiters, servers, and daemons */
11059 if (startListeners)
11060 smb_StartListeners(1);
11062 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
11063 NULL, 0, &lpid, "smb_ClientWaiter");
11064 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
11065 thrd_CloseHandle(phandle);
11067 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
11068 NULL, 0, &lpid, "smb_ServerWaiter");
11069 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
11070 thrd_CloseHandle(phandle);
11072 for (i=0; i<smb_NumServerThreads; i++) {
11073 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
11074 (void *) i, 0, &lpid, "smb_Server");
11075 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
11076 thrd_CloseHandle(phandle);
11079 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
11080 NULL, 0, &lpid, "smb_Daemon");
11081 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
11082 thrd_CloseHandle(phandle);
11084 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
11085 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
11086 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
11087 thrd_CloseHandle(phandle);
11089 if (smb_monitorReqs) {
11090 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
11091 NULL, 0, &lpid, "smb_ServerMonitor");
11092 osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
11093 thrd_CloseHandle(phandle);
11096 lock_ReleaseMutex(&smb_StartedLock);
11100 void smb_Shutdown(void)
11110 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11112 /* setup the NCB system */
11113 ncbp = smb_GetNCB();
11115 /* Block new sessions by setting shutdown flag */
11116 smbShutdownFlag = 1;
11118 /* Hang up all sessions */
11119 memset(ncbp, 0, sizeof(NCB));
11120 for (i = 1; i < numSessions; i++)
11122 if (dead_sessions[i])
11125 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11126 ncbp->ncb_command = NCBHANGUP;
11127 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
11128 ncbp->ncb_lsn = (UCHAR)LSNs[i];
11129 code = Netbios(ncbp);
11130 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11131 if (code == 0) code = ncbp->ncb_retcode;
11133 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11134 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11138 /* Trigger the shutdown of all SMB threads */
11139 for (i = 0; i < smb_NumServerThreads; i++)
11140 thrd_SetEvent(NCBreturns[i][0]);
11142 thrd_SetEvent(NCBevents[0]);
11143 thrd_SetEvent(SessionEvents[0]);
11144 thrd_SetEvent(NCBavails[0]);
11146 for (i = 0;i < smb_NumServerThreads; i++) {
11147 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11148 if (code == WAIT_OBJECT_0) {
11151 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11152 thrd_SetEvent(NCBreturns[i--][0]);
11156 /* Delete Netbios name */
11157 memset(ncbp, 0, sizeof(NCB));
11158 for (i = 0; i < lana_list.length; i++) {
11159 if (lana_list.lana[i] == LANA_INVALID) continue;
11160 ncbp->ncb_command = NCBDELNAME;
11161 ncbp->ncb_lana_num = lana_list.lana[i];
11162 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11163 code = Netbios(ncbp);
11165 code = ncbp->ncb_retcode;
11167 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11168 ncbp->ncb_lana_num, code);
11173 /* Release the reference counts held by the VCs */
11174 lock_ObtainWrite(&smb_rctLock);
11175 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11180 if (vcp->magic != SMB_VC_MAGIC)
11181 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11182 __FILE__, __LINE__);
11184 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11186 if (fidp->scp != NULL) {
11189 lock_ReleaseWrite(&smb_rctLock);
11190 lock_ObtainMutex(&fidp->mx);
11191 if (fidp->scp != NULL) {
11194 lock_ObtainWrite(&scp->rw);
11195 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11196 lock_ReleaseWrite(&scp->rw);
11197 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11198 cm_ReleaseSCache(scp);
11200 lock_ReleaseMutex(&fidp->mx);
11201 lock_ObtainWrite(&smb_rctLock);
11205 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11207 smb_ReleaseVCNoLock(tidp->vcp);
11209 cm_user_t *userp = tidp->userp;
11210 tidp->userp = NULL;
11211 cm_ReleaseUser(userp);
11215 lock_ReleaseWrite(&smb_rctLock);
11218 if (smb_monitorReqs) {
11219 smb_ShutdownMonitor();
11223 /* Get the UNC \\<servername>\<sharename> prefix. */
11224 char *smb_GetSharename()
11229 /* Make sure we have been properly initialized. */
11230 if (smb_localNamep == NULL)
11233 /* Allocate space for \\<servername>\<sharename>, plus the
11236 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11237 name = malloc(len);
11238 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11244 void smb_LogPacket(smb_packet_t *packet)
11248 unsigned length, paramlen, datalen, i, j;
11250 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11252 if (!packet) return;
11254 osi_Log0(smb_logp, "*** SMB packet dump ***");
11256 smbp = (smb_t *) packet->data;
11257 vp = (BYTE *) packet->data;
11259 paramlen = smbp->wct * 2;
11260 datalen = *((WORD *) (smbp->vdata + paramlen));
11261 length = sizeof(*smbp) + paramlen + 1 + datalen;
11263 for (i=0;i < length; i+=16)
11265 memset( buf, ' ', 80 );
11268 itoa( i, buf, 16 );
11270 buf[strlen(buf)] = ' ';
11272 cp = (BYTE*) buf + 7;
11274 for (j=0;j < 16 && (i+j)<length; j++)
11276 *(cp++) = hex[vp[i+j] >> 4];
11277 *(cp++) = hex[vp[i+j] & 0xf];
11287 for (j=0;j < 16 && (i+j)<length;j++)
11289 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11300 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11303 osi_Log0(smb_logp, "*** End SMB packet dump ***");
11305 #endif /* LOG_PACKET */
11308 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11314 smb_username_t *unp;
11315 smb_waitingLockRequest_t *wlrp;
11318 lock_ObtainRead(&smb_rctLock);
11320 sprintf(output, "begin dumping smb_username_t\r\n");
11321 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11322 for (unp = usernamesp; unp; unp=unp->nextp)
11324 cm_ucell_t *ucellp;
11326 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11327 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11328 unp->name ? unp->name : _C("NULL"),
11329 unp->machine ? unp->machine : _C("NULL"));
11330 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11332 sprintf(output, " begin dumping cm_ucell_t\r\n");
11333 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11335 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11336 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",
11337 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11338 ucellp->expirationTime, ucellp->gen,
11340 ucellp->cellp->name);
11341 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11344 sprintf(output, " done dumping cm_ucell_t\r\n");
11345 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11348 sprintf(output, "done dumping smb_username_t\r\n");
11349 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11355 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11356 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11358 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11359 smb_waitingLock_t *lockp;
11361 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11362 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11363 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11365 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
11366 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11367 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11368 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11369 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11370 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11372 sprintf(output, " done dumping smb_waitingLock_t\r\n");
11373 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11376 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11377 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11379 sprintf(output, "begin dumping smb_vc_t\r\n");
11380 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11382 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11388 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11389 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11390 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11392 sprintf(output, " begin dumping smb_user_t\r\n");
11393 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11394 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11395 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11396 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11397 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11399 sprintf(output, " done dumping smb_user_t\r\n");
11400 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11402 sprintf(output, " begin dumping smb_tid_t\r\n");
11403 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11404 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11405 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",
11406 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11407 tidp->pathname ? tidp->pathname : _C("NULL"));
11408 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11410 sprintf(output, " done dumping smb_tid_t\r\n");
11411 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11413 sprintf(output, " begin dumping smb_fid_t\r\n");
11414 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11416 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11418 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",
11419 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11420 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11421 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11422 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11425 sprintf(output, " done dumping smb_fid_t\r\n");
11426 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11429 sprintf(output, "done dumping smb_vc_t\r\n");
11430 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11432 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11433 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11435 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11441 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11442 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11443 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11445 sprintf(output, " begin dumping smb_user_t\r\n");
11446 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11447 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11448 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11449 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11450 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11452 sprintf(output, " done dumping smb_user_t\r\n");
11453 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11455 sprintf(output, " begin dumping smb_tid_t\r\n");
11456 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11457 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11458 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",
11459 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11460 tidp->pathname ? tidp->pathname : _C("NULL"));
11461 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11463 sprintf(output, " done dumping smb_tid_t\r\n");
11464 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11466 sprintf(output, " begin dumping smb_fid_t\r\n");
11467 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11469 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11471 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",
11472 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11473 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11474 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11475 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11478 sprintf(output, " done dumping smb_fid_t\r\n");
11479 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11482 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11483 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11487 lock_ReleaseRead(&smb_rctLock);
11491 long smb_IsNetworkStarted(void)
11498 lock_ObtainWrite(&smb_globalLock);
11499 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11500 lock_ReleaseWrite(&smb_globalLock);