2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 #pragma warning(disable: 4005)
32 #include <rx/rx_prototypes.h>
33 #include <WINNT\afsreg.h>
37 #include "lanahelper.h"
39 #define STRSAFE_NO_DEPRECATE
42 /* These characters are illegal in Windows filenames */
43 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
45 static int smbShutdownFlag = 0;
46 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
48 int smb_LogoffTokenTransfer;
49 time_t smb_LogoffTransferTimeout;
51 int smb_StoreAnsiFilenames = 0;
53 DWORD last_msg_time = 0;
57 unsigned int sessionGen = 0;
59 extern void afsi_log(char *pattern, ...);
60 extern HANDLE afsi_file;
61 extern int powerStateSuspended;
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t smb_ListenerLock;
70 osi_mutex_t smb_StartedLock;
72 unsigned char smb_LANadapter = LANA_INVALID;
73 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
74 int smb_LanAdapterChangeDetected = 0;
75 afs_uint32 smb_AsyncStore = 1;
76 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
78 BOOL isGateway = FALSE;
81 long smb_maxObsConcurrentCalls=0;
82 long smb_concurrentCalls=0;
84 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
86 smb_packet_t *smb_packetFreeListp;
87 smb_ncb_t *smb_ncbFreeListp;
89 afs_uint32 smb_NumServerThreads;
91 afs_uint32 numNCBs, numSessions, numVCs;
93 int smb_maxVCPerServer;
94 int smb_maxMpxRequests;
96 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
98 ULONG smb_lsaSecPackage;
99 LSA_STRING smb_lsaLogonOrigin;
101 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
102 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
103 EVENT_HANDLE **NCBreturns;
104 EVENT_HANDLE **NCBShutdown;
105 EVENT_HANDLE *smb_ServerShutdown;
106 EVENT_HANDLE ListenerShutdown[256];
107 DWORD NCBsessions[NCB_MAX];
109 struct smb_packet *bufs[NCB_MAX];
111 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
112 EVENT_HANDLE SessionEvents[SESSION_MAX];
113 unsigned short LSNs[SESSION_MAX];
114 int lanas[SESSION_MAX];
115 BOOL dead_sessions[SESSION_MAX];
118 osi_mutex_t smb_RawBufLock;
121 #define SMB_MASKFLAG_TILDE 1
122 #define SMB_MASKFLAG_CASEFOLD 2
124 #define RAWTIMEOUT INFINITE
127 typedef struct raw_write_cont {
136 /* dir search stuff */
137 long smb_dirSearchCounter = 1;
138 smb_dirSearch_t *smb_firstDirSearchp;
139 smb_dirSearch_t *smb_lastDirSearchp;
141 /* Initial mode bits for files and directories. Set to 0 to use
143 int smb_unixModeDefaultFile = 0666;
144 int smb_unixModeDefaultDir = 0777;
146 /* hide dot files? */
147 int smb_hideDotFiles;
149 /* Negotiate Unicode support? */
152 /* global state about V3 protocols */
153 int smb_useV3; /* try to negotiate V3 */
155 static int showErrors = 0;
156 /* MessageBox or something like it */
157 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
161 * Time in Unix format of midnight, 1/1/1970 local time.
162 * When added to dosUTime, gives Unix (AFS) time.
164 time_t smb_localZero = 0;
166 char *smb_localNamep = NULL;
168 smb_vc_t *smb_allVCsp;
169 smb_vc_t *smb_deadVCsp;
171 smb_username_t *usernamesp = NULL;
173 smb_waitingLockRequest_t *smb_allWaitingLocks;
176 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
177 NCB *ncbp, raw_write_cont_t *rwcp);
178 int smb_NetbiosInit(int);
181 void smb_LogPacket(smb_packet_t *packet);
182 #endif /* LOG_PACKET */
184 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
185 int smb_ServerDomainNameLength = 0;
186 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
187 int smb_ServerOSLength = lengthof(smb_ServerOS);
188 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
189 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
191 /* Faux server GUID. This is never checked. */
192 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
194 void smb_InitReq(cm_req_t *reqp)
197 reqp->flags |= CM_REQ_SOURCE_SMB;
200 const char * ncb_error_string(int code)
204 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
205 case 0x03: s = "NRC_ILLCMD illegal command"; break;
206 case 0x05: s = "NRC_CMDTMO command timed out"; break;
207 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
208 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
209 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
210 case 0x09: s = "NRC_NORES no resource available"; break;
211 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
212 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
213 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
214 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
215 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
216 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
217 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
218 case 0x13: s = "NRC_ILLNN illegal name number"; break;
219 case 0x14: s = "NRC_NOCALL no callname"; break;
220 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
221 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
222 case 0x17: s = "NRC_NAMERR name deleted"; break;
223 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
224 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
225 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
226 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
227 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
228 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
229 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
230 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
231 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
232 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
233 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
234 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
235 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
236 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
237 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
238 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
239 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
240 case 0x40: s = "NRC_SYSTEM system error"; break;
241 default: s = "unknown error";
247 char * myCrt_Dispatch(int i)
252 return "(00)ReceiveCoreMakeDir";
254 return "(01)ReceiveCoreRemoveDir";
256 return "(02)ReceiveCoreOpen";
258 return "(03)ReceiveCoreCreate";
260 return "(04)ReceiveCoreClose";
262 return "(05)ReceiveCoreFlush";
264 return "(06)ReceiveCoreUnlink";
266 return "(07)ReceiveCoreRename";
268 return "(08)ReceiveCoreGetFileAttributes";
270 return "(09)ReceiveCoreSetFileAttributes";
272 return "(0a)ReceiveCoreRead";
274 return "(0b)ReceiveCoreWrite";
276 return "(0c)ReceiveCoreLockRecord";
278 return "(0d)ReceiveCoreUnlockRecord";
280 return "(0e)SendCoreBadOp";
282 return "(0f)ReceiveCoreCreate";
284 return "(10)ReceiveCoreCheckPath";
286 return "(11)SendCoreBadOp";
288 return "(12)ReceiveCoreSeek";
290 return "(1a)ReceiveCoreReadRaw";
292 return "(1d)ReceiveCoreWriteRawDummy";
294 return "(22)ReceiveV3SetAttributes";
296 return "(23)ReceiveV3GetAttributes";
298 return "(24)ReceiveV3LockingX";
300 return "(25)ReceiveV3Trans";
302 return "(26)ReceiveV3Trans[aux]";
304 return "(29)SendCoreBadOp";
306 return "(2b)ReceiveCoreEcho";
308 return "(2d)ReceiveV3OpenX";
310 return "(2e)ReceiveV3ReadX";
312 return "(2f)ReceiveV3WriteX";
314 return "(32)ReceiveV3Tran2A";
316 return "(33)ReceiveV3Tran2A[aux]";
318 return "(34)ReceiveV3FindClose";
320 return "(35)ReceiveV3FindNotifyClose";
322 return "(70)ReceiveCoreTreeConnect";
324 return "(71)ReceiveCoreTreeDisconnect";
326 return "(72)ReceiveNegotiate";
328 return "(73)ReceiveV3SessionSetupX";
330 return "(74)ReceiveV3UserLogoffX";
332 return "(75)ReceiveV3TreeConnectX";
334 return "(80)ReceiveCoreGetDiskAttributes";
336 return "(81)ReceiveCoreSearchDir";
340 return "(83)FindUnique";
342 return "(84)FindClose";
344 return "(A0)ReceiveNTTransact";
346 return "(A2)ReceiveNTCreateX";
348 return "(A4)ReceiveNTCancel";
350 return "(A5)ReceiveNTRename";
352 return "(C0)OpenPrintFile";
354 return "(C1)WritePrintFile";
356 return "(C2)ClosePrintFile";
358 return "(C3)GetPrintQueue";
360 return "(D8)ReadBulk";
362 return "(D9)WriteBulk";
364 return "(DA)WriteBulkData";
366 return "unknown SMB op";
370 char * myCrt_2Dispatch(int i)
375 return "unknown SMB op-2";
377 return "S(00)CreateFile_ReceiveTran2Open";
379 return "S(01)FindFirst_ReceiveTran2SearchDir";
381 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
383 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
385 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
387 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
389 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
391 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
393 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
395 return "S(09)_ReceiveTran2FSCTL";
397 return "S(0a)_ReceiveTran2IOCTL";
399 return "S(0b)_ReceiveTran2FindNotifyFirst";
401 return "S(0c)_ReceiveTran2FindNotifyNext";
403 return "S(0d)_ReceiveTran2CreateDirectory";
405 return "S(0e)_ReceiveTran2SessionSetup";
407 return "S(0f)_QueryFileSystemInformationFid";
409 return "S(10)_ReceiveTran2GetDfsReferral";
411 return "S(11)_ReceiveTran2ReportDfsInconsistency";
415 char * myCrt_RapDispatch(int i)
420 return "unknown RAP OP";
422 return "RAP(0)NetShareEnum";
424 return "RAP(1)NetShareGetInfo";
426 return "RAP(13)NetServerGetInfo";
428 return "RAP(63)NetWkStaGetInfo";
432 char * myCrt_NmpipeDispatch(int i)
435 case SMB_TRANS_SET_NMPIPE_STATE:
436 return "SET NMPIPE STATE";
438 case SMB_TRANS_RAW_READ_NMPIPE:
439 return "RAW READ NMPIPE";
441 case SMB_TRANS_QUERY_NMPIPE_STATE:
442 return "QUERY NMPIPE STATE";
444 case SMB_TRANS_QUERY_NMPIPE_INFO:
445 return "QUERY NMPIPE INFO";
447 case SMB_TRANS_PEEK_NMPIPE:
448 return "PEEK NMPIPE";
450 case SMB_TRANS_TRANSACT_NMPIPE:
451 return "TRANSACT NMPIPE";
453 case SMB_TRANS_RAW_WRITE_NMPIPE:
454 return "WRITE NMPIPE";
456 case SMB_TRANS_READ_NMPIPE:
457 return "READ NMPIPE";
459 case SMB_TRANS_WRITE_NMPIPE:
460 return "WRITE NMPIPE";
462 case SMB_TRANS_WAIT_NMPIPE:
463 return "WAIT NMPIPE";
465 case SMB_TRANS_CALL_NMPIPE:
466 return "CALL NMPIPE";
471 /* scache must be locked */
472 unsigned int smb_Attributes(cm_scache_t *scp)
476 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
477 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
478 scp->fileType == CM_SCACHETYPE_INVALID)
480 attrs = SMB_ATTR_DIRECTORY;
481 #ifdef SPECIAL_FOLDERS
482 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
483 #endif /* SPECIAL_FOLDERS */
484 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
485 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
490 * We used to mark a file RO if it was in an RO volume, but that
491 * turns out to be impolitic in NT. See defect 10007.
494 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
495 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
497 if ((scp->unixModeBits & 0200) == 0)
498 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
504 void smb_SetInitialModeBitsForFile(int smb_attr, cm_attr_t * attr)
506 if (smb_unixModeDefaultFile != 0) {
507 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
508 attr->unixModeBits = smb_unixModeDefaultFile;
509 if (smb_attr & SMB_ATTR_READONLY)
510 attr->unixModeBits &= ~0222;
514 void smb_SetInitialModeBitsForDir(int smb_attr, cm_attr_t * attr)
516 if (smb_unixModeDefaultDir != 0) {
517 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
518 attr->unixModeBits = smb_unixModeDefaultDir;
522 /* Check if the named file/dir is a dotfile/dotdir */
523 /* String pointed to by lastComp can have leading slashes, but otherwise should have
524 no other patch components */
525 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
529 /* skip over slashes */
530 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
535 /* nulls, curdir and parent dir doesn't count */
541 if(*(s+1) == _C('.') && !*(s + 2))
548 static int ExtractBits(WORD bits, short start, short len)
555 num = bits << (16 - end);
556 num = num >> ((16 - end) + start);
561 void ShowUnixTime(char *FuncName, time_t unixTime)
566 cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
568 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
569 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
571 int day, month, year, sec, min, hour;
574 day = ExtractBits(wDate, 0, 5);
575 month = ExtractBits(wDate, 5, 4);
576 year = ExtractBits(wDate, 9, 7) + 1980;
578 sec = ExtractBits(wTime, 0, 5);
579 min = ExtractBits(wTime, 5, 6);
580 hour = ExtractBits(wTime, 11, 5);
582 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
583 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
587 /* Determine if we are observing daylight savings time */
588 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
590 TIME_ZONE_INFORMATION timeZoneInformation;
591 SYSTEMTIME utc, local, localDST;
593 /* Get the time zone info. NT uses this to calc if we are in DST. */
594 GetTimeZoneInformation(&timeZoneInformation);
596 /* Return the daylight bias */
597 *pDstBias = timeZoneInformation.DaylightBias;
599 /* Return the bias */
600 *pBias = timeZoneInformation.Bias;
602 /* Now determine if DST is being observed */
604 /* Get the UTC (GMT) time */
607 /* Convert UTC time to local time using the time zone info. If we are
608 observing DST, the calculated local time will include this.
610 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
612 /* Set the daylight bias to 0. The daylight bias is the amount of change
613 * in time that we use for daylight savings time. By setting this to 0
614 * we cause there to be no change in time during daylight savings time.
616 timeZoneInformation.DaylightBias = 0;
618 /* Convert the utc time to local time again, but this time without any
619 adjustment for daylight savings time.
621 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
623 /* If the two times are different, then it means that the localDST that
624 we calculated includes the daylight bias, and therefore we are
625 observing daylight savings time.
627 *pDST = localDST.wHour != local.wHour;
631 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
633 BOOL dst; /* Will be TRUE if observing DST */
634 LONG dstBias; /* Offset from local time if observing DST */
635 LONG bias; /* Offset from GMT for local time */
638 * This function will adjust the last write time to compensate
639 * for two bugs in the smb client:
641 * 1) During Daylight Savings Time, the LastWriteTime is ahead
642 * in time by the DaylightBias (ignoring the sign - the
643 * DaylightBias is always stored as a negative number). If
644 * the DaylightBias is -60, then the LastWriteTime will be
645 * ahead by 60 minutes.
647 * 2) If the local time zone is a positive offset from GMT, then
648 * the LastWriteTime will be the correct local time plus the
649 * Bias (ignoring the sign - a positive offset from GMT is
650 * always stored as a negative Bias). If the Bias is -120,
651 * then the LastWriteTime will be ahead by 120 minutes.
653 * These bugs can occur at the same time.
656 GetTimeZoneInfo(&dst, &dstBias, &bias);
658 /* First adjust for DST */
660 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
662 /* Now adjust for a positive offset from GMT (a negative bias). */
664 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
667 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
669 time_t diff_t = unixTime - smb_localZero;
670 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
671 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
673 *dosUTimep = (afs_uint32)diff_t;
676 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
678 *unixTimep = dosTime + smb_localZero;
681 void smb_MarkAllVCsDead(smb_vc_t * exclude)
684 smb_vc_t **vcp_to_cleanup = NULL;
685 int n_to_cleanup = 0;
688 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
690 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
691 lock_ObtainWrite(&smb_rctLock);
692 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
694 if (vcp->magic != SMB_VC_MAGIC)
695 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
701 lock_ObtainMutex(&vcp->mx);
702 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
703 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
704 lock_ReleaseMutex(&vcp->mx);
705 dead_sessions[vcp->session] = TRUE;
707 lock_ReleaseMutex(&vcp->mx);
712 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
714 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
718 vcp_to_cleanup[i++] = vcp;
719 smb_HoldVCNoLock(vcp);
722 osi_assert(i == n_to_cleanup);
724 lock_ReleaseWrite(&smb_rctLock);
725 lock_ReleaseWrite(&smb_globalLock);
727 for (i=0; i < n_to_cleanup; i++) {
728 smb_CleanupDeadVC(vcp_to_cleanup[i]);
729 smb_ReleaseVC(vcp_to_cleanup[i]);
730 vcp_to_cleanup[i] = 0;
733 free(vcp_to_cleanup);
736 #ifdef DEBUG_SMB_REFCOUNT
737 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
739 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
744 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
745 lock_ObtainWrite(&smb_rctLock);
746 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
747 if (vcp->magic != SMB_VC_MAGIC)
748 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
751 lock_ObtainMutex(&vcp->mx);
752 if (lsn == vcp->lsn && lana == vcp->lana &&
753 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
754 lock_ReleaseMutex(&vcp->mx);
755 smb_HoldVCNoLock(vcp);
758 lock_ReleaseMutex(&vcp->mx);
760 if (!vcp && (flags & SMB_FLAG_CREATE)) {
761 vcp = malloc(sizeof(*vcp));
762 memset(vcp, 0, sizeof(*vcp));
763 vcp->vcID = ++numVCs;
764 vcp->magic = SMB_VC_MAGIC;
765 vcp->refCount = 2; /* smb_allVCsp and caller */
768 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
769 vcp->nextp = smb_allVCsp;
771 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
776 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
777 /* We must obtain a challenge for extended auth
778 * in case the client negotiates smb v3
780 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
781 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
782 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
783 ULONG lsaRespSize = 0;
785 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
787 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
794 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
795 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
796 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
797 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
798 nts, ntsEx, lsaRespSize);
800 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
802 if (ntsEx == STATUS_SUCCESS) {
803 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
806 * This will cause the subsequent authentication to fail but
807 * that is better than us dereferencing a NULL pointer and
810 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
813 LsaFreeReturnBuffer(lsaResp);
816 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
818 if (numVCs >= CM_SESSION_RESERVED) {
820 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
823 #ifdef DEBUG_SMB_REFCOUNT
825 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
826 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
829 lock_ReleaseWrite(&smb_rctLock);
830 lock_ReleaseWrite(&smb_globalLock);
834 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
839 for(i=0; i<11; i++) {
841 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
847 static int smb_IsStarMask(clientchar_t *maskp)
853 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
859 #ifdef DEBUG_SMB_REFCOUNT
860 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
861 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
863 void smb_ReleaseVCInternal(smb_vc_t *vcp)
869 lock_AssertWrite(&smb_rctLock);
872 if (vcp->refCount == 0) {
873 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
874 #ifdef DEBUG_SMB_REFCOUNT
875 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
876 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
878 /* remove VCP from smb_deadVCsp */
879 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
885 lock_FinalizeMutex(&vcp->mx);
886 memset(vcp,0,sizeof(smb_vc_t));
889 #ifdef DEBUG_SMB_REFCOUNT
890 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
892 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
896 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
897 avcp?"":"not ",vcp, vcp->refCount);
899 /* This is a wrong. However, I suspect that there is an undercount
900 * and I don't want to release 1.4.1 in a state that will allow
901 * smb_vc_t objects to be deallocated while still in the
902 * smb_allVCsp list. The list is supposed to keep a reference
903 * to the smb_vc_t. Put it back.
907 #ifdef DEBUG_SMB_REFCOUNT
908 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
909 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
913 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
914 /* The reference count is non-zero but the VC is dead.
915 * This implies that some FIDs, TIDs, etc on the VC have yet to
916 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
917 * add a reference that will be dropped by
918 * smb_CleanupDeadVC() and try to cleanup the VC again.
919 * Eventually the refCount will drop to zero when all of the
920 * active threads working with the VC end their task.
922 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
923 vcp->refCount++; /* put the refCount back */
924 lock_ReleaseWrite(&smb_rctLock);
925 smb_CleanupDeadVC(vcp);
926 #ifdef DEBUG_SMB_REFCOUNT
927 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
928 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
930 lock_ObtainWrite(&smb_rctLock);
933 #ifdef DEBUG_SMB_REFCOUNT
934 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
935 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
940 #ifdef DEBUG_SMB_REFCOUNT
941 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
943 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
946 lock_AssertWrite(&smb_rctLock);
947 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
948 smb_ReleaseVCInternal(vcp);
951 #ifdef DEBUG_SMB_REFCOUNT
952 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
954 void smb_ReleaseVC(smb_vc_t *vcp)
957 lock_ObtainWrite(&smb_rctLock);
958 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
959 smb_ReleaseVCInternal(vcp);
960 lock_ReleaseWrite(&smb_rctLock);
963 #ifdef DEBUG_SMB_REFCOUNT
964 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
966 void smb_HoldVCNoLock(smb_vc_t *vcp)
969 lock_AssertWrite(&smb_rctLock);
971 #ifdef DEBUG_SMB_REFCOUNT
972 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
973 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
975 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
979 #ifdef DEBUG_SMB_REFCOUNT
980 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
982 void smb_HoldVC(smb_vc_t *vcp)
985 lock_ObtainWrite(&smb_rctLock);
987 #ifdef DEBUG_SMB_REFCOUNT
988 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
989 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
991 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
993 lock_ReleaseWrite(&smb_rctLock);
996 void smb_CleanupDeadVC(smb_vc_t *vcp)
1001 smb_tid_t *tidpIter;
1002 smb_tid_t *tidpNext;
1004 smb_user_t *uidpIter;
1005 smb_user_t *uidpNext;
1007 afs_uint32 refCount = 0;
1009 lock_ObtainMutex(&vcp->mx);
1010 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1011 lock_ReleaseMutex(&vcp->mx);
1012 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1015 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1016 lock_ReleaseMutex(&vcp->mx);
1017 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1019 lock_ObtainWrite(&smb_rctLock);
1020 /* remove VCP from smb_allVCsp */
1021 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1022 if ((*vcpp)->magic != SMB_VC_MAGIC)
1023 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1024 __FILE__, __LINE__);
1027 vcp->nextp = smb_deadVCsp;
1029 /* Hold onto the reference until we are done with this function */
1034 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1035 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1037 if (fidpIter->deleteOk)
1040 fid = fidpIter->fid;
1041 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1043 smb_HoldFIDNoLock(fidpIter);
1044 lock_ReleaseWrite(&smb_rctLock);
1046 smb_CloseFID(vcp, fidpIter, NULL, 0);
1047 smb_ReleaseFID(fidpIter);
1049 lock_ObtainWrite(&smb_rctLock);
1050 fidpNext = vcp->fidsp;
1053 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1054 tidpNext = tidpIter->nextp;
1055 if (tidpIter->deleteOk)
1057 tidpIter->deleteOk = 1;
1059 tid = tidpIter->tid;
1060 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1062 smb_HoldTIDNoLock(tidpIter);
1063 smb_ReleaseTID(tidpIter, TRUE);
1064 tidpNext = vcp->tidsp;
1067 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1068 uidpNext = uidpIter->nextp;
1069 if (uidpIter->deleteOk)
1071 uidpIter->deleteOk = 1;
1073 /* do not add an additional reference count for the smb_user_t
1074 * as the smb_vc_t already is holding a reference */
1075 lock_ReleaseWrite(&smb_rctLock);
1077 smb_ReleaseUID(uidpIter);
1079 lock_ObtainWrite(&smb_rctLock);
1080 uidpNext = vcp->usersp;
1083 /* The vcp is now on the deadVCsp list. We intentionally drop the
1084 * reference so that the refcount can reach 0 and we can delete it
1086 * If the refCount == 1 going into the ReleaseVCNoLock call
1087 * the object will be freed and it won't be safe to clear
1090 refCount = vcp->refCount;
1091 smb_ReleaseVCNoLock(vcp);
1093 lock_ObtainMutex(&vcp->mx);
1094 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1095 lock_ReleaseMutex(&vcp->mx);
1098 lock_ReleaseWrite(&smb_rctLock);
1099 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1102 #ifdef DEBUG_SMB_REFCOUNT
1103 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1105 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1110 lock_ObtainWrite(&smb_rctLock);
1112 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1113 if (tidp->refCount == 0 && tidp->deleteOk) {
1115 smb_ReleaseTID(tidp, TRUE);
1119 if (tid == tidp->tid) {
1124 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1125 tidp = malloc(sizeof(*tidp));
1126 memset(tidp, 0, sizeof(*tidp));
1127 tidp->nextp = vcp->tidsp;
1130 smb_HoldVCNoLock(vcp);
1132 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1135 #ifdef DEBUG_SMB_REFCOUNT
1137 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1138 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1141 lock_ReleaseWrite(&smb_rctLock);
1145 #ifdef DEBUG_SMB_REFCOUNT
1146 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1148 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1151 lock_AssertWrite(&smb_rctLock);
1153 #ifdef DEBUG_SMB_REFCOUNT
1154 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1155 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1159 #ifdef DEBUG_SMB_REFCOUNT
1160 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1162 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1167 cm_user_t *userp = NULL;
1168 smb_vc_t *vcp = NULL;
1171 lock_ObtainWrite(&smb_rctLock);
1173 lock_AssertWrite(&smb_rctLock);
1175 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1176 #ifdef DEBUG_SMB_REFCOUNT
1177 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1178 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1180 if (tidp->refCount == 0) {
1181 if (tidp->deleteOk) {
1182 ltpp = &tidp->vcp->tidsp;
1183 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1187 osi_assertx(tp != NULL, "null smb_tid_t");
1189 lock_FinalizeMutex(&tidp->mx);
1190 userp = tidp->userp; /* remember to drop ref later */
1198 smb_ReleaseVCNoLock(vcp);
1200 lock_ReleaseWrite(&smb_rctLock);
1202 cm_ReleaseUser(userp);
1205 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1207 smb_user_t *uidp = NULL;
1209 lock_ObtainWrite(&smb_rctLock);
1210 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1211 if (uid == uidp->userID) {
1213 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1215 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1219 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1220 uidp = malloc(sizeof(*uidp));
1221 memset(uidp, 0, sizeof(*uidp));
1222 uidp->nextp = vcp->usersp;
1223 uidp->refCount = 2; /* one for the vcp and one for the caller */
1225 smb_HoldVCNoLock(vcp);
1227 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1229 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1231 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1233 lock_ReleaseWrite(&smb_rctLock);
1237 afs_int32 smb_userIsLocalSystem(smb_user_t *uidp)
1240 DWORD dwSize1 = 0, dwSize2 = 0;
1241 wchar_t *pszRefDomain = NULL;
1242 SID_NAME_USE snu = SidTypeGroup;
1243 clientchar_t * secSidString = NULL;
1245 afs_int32 isSystem = 0;
1247 if (uidp->unp->flags & SMB_USERNAMEFLAG_SID) {
1248 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, uidp->unp->name);
1253 * The input name is not a SID for the user. See if we can
1254 * obtain the SID for the specified name. If we can, use
1255 * that instead of the name provided for the comparison.
1258 LookupAccountNameW( NULL /* System Name to begin Search */,
1263 gle = GetLastError();
1264 if (gle == ERROR_INSUFFICIENT_BUFFER) {
1265 pSid = malloc(dwSize1);
1267 * Although dwSize2 is supposed to include the terminating
1268 * NUL character, on Win7 it does not.
1270 pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
1273 if ( pSid && pszRefDomain ) {
1274 memset(pSid, 0, dwSize1);
1276 if (LookupAccountNameW( NULL /* System Name to begin Search */,
1279 pszRefDomain, &dwSize2,
1281 ConvertSidToStringSidW(pSid, &secSidString);
1285 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, secSidString);
1286 LocalFree(secSidString);
1297 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1300 smb_username_t *unp= NULL;
1302 lock_ObtainWrite(&smb_rctLock);
1303 for(unp = usernamesp; unp; unp = unp->nextp) {
1304 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1305 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1310 if (!unp && (flags & SMB_FLAG_CREATE)) {
1311 unp = malloc(sizeof(*unp));
1312 memset(unp, 0, sizeof(*unp));
1314 unp->nextp = usernamesp;
1315 unp->name = cm_ClientStrDup(usern);
1316 unp->machine = cm_ClientStrDup(machine);
1318 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1319 if (flags & SMB_FLAG_AFSLOGON)
1320 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1323 lock_ReleaseWrite(&smb_rctLock);
1327 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1329 smb_user_t *uidp= NULL;
1331 lock_ObtainWrite(&smb_rctLock);
1332 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1335 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1337 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1338 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1343 lock_ReleaseWrite(&smb_rctLock);
1347 void smb_ReleaseUsername(smb_username_t *unp)
1350 smb_username_t **lupp;
1351 cm_user_t *userp = NULL;
1352 time_t now = osi_Time();
1354 lock_ObtainWrite(&smb_rctLock);
1355 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1356 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1357 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1359 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1363 osi_assertx(up != NULL, "null smb_username_t");
1365 up->nextp = NULL; /* do not remove this */
1366 lock_FinalizeMutex(&unp->mx);
1372 lock_ReleaseWrite(&smb_rctLock);
1374 cm_ReleaseUser(userp);
1377 void smb_HoldUIDNoLock(smb_user_t *uidp)
1379 lock_AssertWrite(&smb_rctLock);
1383 void smb_ReleaseUID(smb_user_t *uidp)
1387 smb_username_t *unp = NULL;
1389 lock_ObtainWrite(&smb_rctLock);
1390 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1391 if (uidp->refCount == 0) {
1392 lupp = &uidp->vcp->usersp;
1393 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1397 osi_assertx(up != NULL, "null smb_user_t");
1399 lock_FinalizeMutex(&uidp->mx);
1401 smb_ReleaseVCNoLock(uidp->vcp);
1405 lock_ReleaseWrite(&smb_rctLock);
1409 cm_ReleaseUserVCRef(unp->userp);
1410 smb_ReleaseUsername(unp);
1414 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1416 cm_user_t *up = NULL;
1421 lock_ObtainMutex(&uidp->mx);
1423 up = uidp->unp->userp;
1426 lock_ReleaseMutex(&uidp->mx);
1432 /* retrieve a held reference to a user structure corresponding to an incoming
1434 * corresponding release function is cm_ReleaseUser.
1436 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1439 cm_user_t *up = NULL;
1442 smbp = (smb_t *) inp;
1443 uidp = smb_FindUID(vcp, smbp->uid, 0);
1447 up = smb_GetUserFromUID(uidp);
1449 smb_ReleaseUID(uidp);
1454 * Return a pointer to a pathname extracted from a TID structure. The
1455 * TID structure is not held; assume it won't go away.
1457 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1462 tidp = smb_FindTID(vcp, tid, 0);
1466 if (tidp->flags & SMB_TIDFLAG_IPC) {
1467 code = CM_ERROR_TIDIPC;
1468 /* tidp->pathname would be NULL, but that's fine */
1470 *treepath = tidp->pathname;
1471 smb_ReleaseTID(tidp, FALSE);
1476 /* check to see if we have a chained fid, that is, a fid that comes from an
1477 * OpenAndX message that ran earlier in this packet. In this case, the fid
1478 * field in a read, for example, request, isn't set, since the value is
1479 * supposed to be inherited from the openAndX call.
1481 int smb_ChainFID(int fid, smb_packet_t *inp)
1483 if (inp->fid == 0 || inp->inCount == 0)
1489 /* are we a priv'd user? What does this mean on NT? */
1490 int smb_SUser(cm_user_t *userp)
1495 /* find a file ID. If we pass in 0 we select an unused File ID.
1496 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1497 * smb_fid_t data structure if desired File ID cannot be found.
1499 #ifdef DEBUG_SMB_REFCOUNT
1500 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1502 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1509 if (!(flags & SMB_FLAG_CREATE))
1514 lock_ObtainWrite(&smb_rctLock);
1516 fid = vcp->fidCounter;
1519 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1520 if (fidp->refCount == 0 && fidp->deleteOk) {
1522 lock_ReleaseWrite(&smb_rctLock);
1523 smb_ReleaseFID(fidp);
1524 lock_ObtainWrite(&smb_rctLock);
1526 * We dropped the smb_rctLock so the fid value we are using
1527 * may now be used by another thread. Start over with the
1528 * current vcp->fidCounter.
1531 fid = vcp->fidCounter;
1534 if (fid == fidp->fid) {
1536 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1538 if (fid == 0xFFFF) {
1540 "New FID number wraps on vcp 0x%x", vcp);
1550 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1551 char eventName[MAX_PATH];
1555 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1557 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1559 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1560 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1561 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1562 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1563 thrd_CloseHandle(event);
1565 if (fid == 0xFFFF) {
1566 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1572 fidp = malloc(sizeof(*fidp));
1573 memset(fidp, 0, sizeof(*fidp));
1574 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1577 smb_HoldVCNoLock(vcp);
1578 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1580 fidp->curr_chunk = fidp->prev_chunk = -2;
1581 fidp->raw_write_event = event;
1583 vcp->fidCounter = fid+1;
1584 if (vcp->fidCounter == 0xFFFF) {
1585 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1587 vcp->fidCounter = 1;
1592 #ifdef DEBUG_SMB_REFCOUNT
1594 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1598 lock_ReleaseWrite(&smb_rctLock);
1603 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1604 #ifdef DEBUG_SMB_REFCOUNT
1605 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1607 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1610 smb_fid_t *fidp = NULL, *nextp = NULL;
1616 * If the fidp->scp changes out from under us then
1617 * we must not grab a refCount. It means the *fidp
1618 * was processed by smb_CloseFID() and the *fidp is
1619 * no longer valid for use.
1621 lock_ObtainWrite(&smb_rctLock);
1622 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1623 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1627 if (scp == fidp->scp) {
1628 lock_ReleaseWrite(&smb_rctLock);
1629 lock_ObtainMutex(&fidp->mx);
1630 lock_ObtainWrite(&smb_rctLock);
1631 if (scp == fidp->scp) {
1632 lock_ReleaseMutex(&fidp->mx);
1635 lock_ReleaseMutex(&fidp->mx);
1638 if (fidp->refCount > 1) {
1641 lock_ReleaseWrite(&smb_rctLock);
1642 smb_ReleaseFID(fidp);
1643 lock_ObtainWrite(&smb_rctLock);
1648 if (nextp->refCount > 1) {
1651 lock_ReleaseWrite(&smb_rctLock);
1652 smb_ReleaseFID(nextp);
1653 lock_ObtainWrite(&smb_rctLock);
1657 #ifdef DEBUG_SMB_REFCOUNT
1659 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1660 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1663 lock_ReleaseWrite(&smb_rctLock);
1667 #ifdef DEBUG_SMB_REFCOUNT
1668 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1670 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1673 lock_AssertWrite(&smb_rctLock);
1675 #ifdef DEBUG_SMB_REFCOUNT
1676 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1677 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1682 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1683 /* the smb_fid_t->mx and smb_rctLock must not be held */
1684 #ifdef DEBUG_SMB_REFCOUNT
1685 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1687 void smb_ReleaseFID(smb_fid_t *fidp)
1690 cm_scache_t *scp = NULL;
1691 cm_user_t *userp = NULL;
1692 smb_vc_t *vcp = NULL;
1693 smb_ioctl_t *ioctlp;
1695 lock_ObtainMutex(&fidp->mx);
1696 lock_ObtainWrite(&smb_rctLock);
1697 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1698 #ifdef DEBUG_SMB_REFCOUNT
1699 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1700 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1702 if (fidp->refCount == 0) {
1703 if (fidp->deleteOk) {
1706 scp = fidp->scp; /* release after lock is released */
1708 lock_ObtainWrite(&scp->rw);
1709 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1710 lock_ReleaseWrite(&scp->rw);
1711 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1714 userp = fidp->userp;
1718 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1719 thrd_CloseHandle(fidp->raw_write_event);
1721 /* and see if there is ioctl stuff to free */
1722 ioctlp = fidp->ioctlp;
1725 cm_FreeSpace(ioctlp->prefix);
1726 if (ioctlp->ioctl.inAllocp)
1727 free(ioctlp->ioctl.inAllocp);
1728 if (ioctlp->ioctl.outAllocp)
1729 free(ioctlp->ioctl.outAllocp);
1733 smb_CleanupRPCFid(fidp);
1735 lock_ReleaseMutex(&fidp->mx);
1736 lock_FinalizeMutex(&fidp->mx);
1741 smb_ReleaseVCNoLock(vcp);
1745 lock_ReleaseMutex(&fidp->mx);
1747 lock_ReleaseWrite(&smb_rctLock);
1749 /* now release the scache structure */
1751 cm_ReleaseSCache(scp);
1754 cm_ReleaseUser(userp);
1758 * Case-insensitive search for one string in another;
1759 * used to find variable names in submount pathnames.
1761 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1763 clientchar_t *cursor;
1765 for (cursor = str1; *cursor; cursor++)
1766 if (cm_ClientStrCmpI(cursor, str2) == 0)
1773 * Substitute a variable value for its name in a submount pathname. Variable
1774 * name has been identified by smb_stristr() and is in substr. Variable name
1775 * length (plus one) is in substr_size. Variable value is in newstr.
1777 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1778 unsigned int substr_size, clientchar_t *newstr)
1780 clientchar_t temp[1024];
1782 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1783 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1784 cm_ClientStrCat(str1, cchstr1, temp);
1787 clientchar_t VNUserName[] = _C("%USERNAME%");
1788 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1789 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1790 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1792 typedef struct smb_findShare_rock {
1793 clientchar_t * shareName;
1794 clientchar_t * match;
1796 } smb_findShare_rock_t;
1798 #define SMB_FINDSHARE_EXACT_MATCH 1
1799 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1801 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1805 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1806 normchar_t normName[MAX_PATH];
1808 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1809 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1810 osi_LogSaveString(smb_logp, dep->name));
1814 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1815 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1816 matchType = SMB_FINDSHARE_EXACT_MATCH;
1818 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1821 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1822 vrock->matchType = matchType;
1824 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1825 return CM_ERROR_STOPNOW;
1831 /* find a shareName in the table of submounts */
1832 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1833 clientchar_t *shareName,
1834 clientchar_t **pathNamep)
1838 clientchar_t pathName[1024];
1841 clientchar_t *p, *q;
1842 fschar_t *cellname = NULL;
1845 DWORD allSubmount = 1;
1847 /* if allSubmounts == 0, only return the //mountRoot/all share
1848 * if in fact it has been been created in the subMounts table.
1849 * This is to allow sites that want to restrict access to the
1852 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1853 0, KEY_QUERY_VALUE, &parmKey);
1854 if (code == ERROR_SUCCESS) {
1855 cblen = sizeof(allSubmount);
1856 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1857 (BYTE *) &allSubmount, &cblen);
1858 if (code != ERROR_SUCCESS) {
1861 RegCloseKey (parmKey);
1864 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1869 /* In case, the all share is disabled we need to still be able
1870 * to handle ioctl requests
1872 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1873 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1877 if (MSRPC_IsWellKnownService(shareName) ||
1878 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1879 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1885 /* Check for volume references
1887 * They look like <cell>{%,#}<volume>
1889 if (cm_ClientStrChr(shareName, '%') != NULL ||
1890 cm_ClientStrChr(shareName, '#') != NULL) {
1891 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1892 /* make room for '/@vol:' + mountchar + NULL terminator*/
1894 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1895 osi_LogSaveClientString(smb_logp, shareName));
1897 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1898 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1899 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1901 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1903 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1904 cm_ClientStrLwr(*pathNamep);
1905 osi_Log1(smb_logp, " returning pathname [%S]",
1906 osi_LogSaveClientString(smb_logp, *pathNamep));
1914 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1915 0, KEY_QUERY_VALUE, &parmKey);
1916 if (code == ERROR_SUCCESS) {
1917 cblen = sizeof(pathName);
1918 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1919 (BYTE *) pathName, &cblen);
1920 if (code != ERROR_SUCCESS)
1922 RegCloseKey (parmKey);
1926 cchlen = cblen / sizeof(clientchar_t);
1927 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1928 /* We can accept either unix or PC style AFS pathnames. Convert
1929 * Unix-style to PC style here for internal use.
1932 cchlen = lengthof(pathName);
1934 /* within this code block, we maintain, cchlen = writable
1935 buffer length of p */
1937 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1938 p += cm_mountRootCLen; /* skip mount path */
1939 cchlen -= (DWORD)(p - pathName);
1944 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1950 clientchar_t temp[1024];
1952 if (var = smb_stristr(p, VNUserName)) {
1953 if (uidp && uidp->unp)
1954 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1956 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1958 else if (var = smb_stristr(p, VNLCUserName))
1960 if (uidp && uidp->unp)
1961 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1963 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1964 cm_ClientStrLwr(temp);
1965 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1967 else if (var = smb_stristr(p, VNComputerName))
1969 sizeTemp = lengthof(temp);
1970 GetComputerNameW(temp, &sizeTemp);
1971 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1973 else if (var = smb_stristr(p, VNLCComputerName))
1975 sizeTemp = lengthof(temp);
1976 GetComputerName((LPTSTR)temp, &sizeTemp);
1977 cm_ClientStrLwr(temp);
1978 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1983 *pathNamep = cm_ClientStrDup(p);
1988 /* First lookup shareName in root.afs */
1990 smb_findShare_rock_t vrock;
1992 fschar_t ftemp[1024];
1993 clientchar_t * p = shareName;
1998 /* attempt to locate a partial match in root.afs. This is because
1999 when using the ANSI RAP calls, the share name is limited to 13 chars
2000 and hence is truncated. Of course we prefer exact matches. */
2002 thyper.HighPart = 0;
2005 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2006 if (vrock.shareName == NULL)
2009 vrock.matchType = 0;
2011 userp = (uidp? (uidp->unp ? uidp->unp->userp : cm_rootUserp) : cm_rootUserp);
2012 rscp = cm_RootSCachep(userp, &req);
2013 cm_HoldSCache(rscp);
2014 code = cm_ApplyDir(rscp, smb_FindShareProc, &vrock, &thyper,
2016 cm_ReleaseSCache(rscp);
2018 free(vrock.shareName);
2019 vrock.shareName = NULL;
2021 if (vrock.matchType) {
2022 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2023 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2028 /* if we get here, there was no match for the share in root.afs */
2029 /* so try to create \\<netbiosName>\<cellname> */
2034 /* Get the full name for this cell */
2035 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2036 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2037 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2038 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2039 if (code && cm_dnsEnabled) {
2041 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2046 /* construct the path */
2048 clientchar_t temp[1024];
2050 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2051 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2052 rw ? _C("/.%S/") : _C("/%S/"), temp);
2053 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2063 /* Client-side offline caching policy types */
2064 #define CSC_POLICY_MANUAL 0
2065 #define CSC_POLICY_DOCUMENTS 1
2066 #define CSC_POLICY_PROGRAMS 2
2067 #define CSC_POLICY_DISABLE 3
2069 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2072 clientchar_t policy[1024];
2075 int retval = CSC_POLICY_MANUAL;
2077 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2078 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2081 REG_OPTION_NON_VOLATILE,
2085 NULL ) != ERROR_SUCCESS)
2086 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2088 len = sizeof(policy);
2089 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2091 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2093 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2095 retval = CSC_POLICY_MANUAL;
2097 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2099 retval = CSC_POLICY_DOCUMENTS;
2101 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2103 retval = CSC_POLICY_PROGRAMS;
2105 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2107 retval = CSC_POLICY_DISABLE;
2110 RegCloseKey(hkCSCPolicy);
2114 /* find a dir search structure by cookie value, and return it held.
2115 * Must be called with smb_globalLock held.
2117 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2119 smb_dirSearch_t *dsp;
2121 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2122 if (dsp->cookie == cookie) {
2123 if (dsp != smb_firstDirSearchp) {
2124 /* move to head of LRU queue, too, if we're not already there */
2125 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2126 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2127 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2128 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2129 if (!smb_lastDirSearchp)
2130 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2138 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2139 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2140 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2146 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2148 lock_ObtainMutex(&dsp->mx);
2149 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2150 dsp->cookie, dsp, dsp->scp);
2151 dsp->flags |= SMB_DIRSEARCH_DELETE;
2152 if (dsp->scp != NULL) {
2153 lock_ObtainWrite(&dsp->scp->rw);
2154 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2155 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2156 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2157 dsp->scp->bulkStatProgress = hzero;
2159 lock_ReleaseWrite(&dsp->scp->rw);
2161 lock_ReleaseMutex(&dsp->mx);
2164 /* Must be called with the smb_globalLock held */
2165 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2167 cm_scache_t *scp = NULL;
2169 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2170 if (dsp->refCount == 0) {
2171 lock_ObtainMutex(&dsp->mx);
2172 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2173 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2174 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2175 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2176 lock_ReleaseMutex(&dsp->mx);
2177 lock_FinalizeMutex(&dsp->mx);
2179 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2180 dsp->cookie, dsp, scp);
2183 lock_ReleaseMutex(&dsp->mx);
2186 /* do this now to avoid spurious locking hierarchy creation */
2188 cm_ReleaseSCache(scp);
2191 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2193 lock_ObtainWrite(&smb_globalLock);
2194 smb_ReleaseDirSearchNoLock(dsp);
2195 lock_ReleaseWrite(&smb_globalLock);
2198 /* find a dir search structure by cookie value, and return it held */
2199 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2201 smb_dirSearch_t *dsp;
2203 lock_ObtainWrite(&smb_globalLock);
2204 dsp = smb_FindDirSearchNoLock(cookie);
2205 lock_ReleaseWrite(&smb_globalLock);
2209 /* GC some dir search entries, in the address space expected by the specific protocol.
2210 * Must be called with smb_globalLock held; release the lock temporarily.
2212 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2213 void smb_GCDirSearches(int isV3)
2215 smb_dirSearch_t *prevp;
2216 smb_dirSearch_t *dsp;
2217 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2221 victimCount = 0; /* how many have we got so far */
2222 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2223 /* we'll move tp from queue, so
2226 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2227 /* if no one is using this guy, and we're either in the new protocol,
2228 * or we're in the old one and this is a small enough ID to be useful
2229 * to the old protocol, GC this guy.
2231 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2232 /* hold and delete */
2233 lock_ObtainMutex(&dsp->mx);
2234 dsp->flags |= SMB_DIRSEARCH_DELETE;
2235 lock_ReleaseMutex(&dsp->mx);
2236 victimsp[victimCount++] = dsp;
2240 /* don't do more than this */
2241 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2245 /* now release them */
2246 for (i = 0; i < victimCount; i++) {
2247 smb_ReleaseDirSearchNoLock(victimsp[i]);
2251 /* function for allocating a dir search entry. We need these to remember enough context
2252 * since we don't get passed the path from call to call during a directory search.
2254 * Returns a held dir search structure, and bumps the reference count on the vnode,
2255 * since it saves a pointer to the vnode.
2257 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2259 smb_dirSearch_t *dsp;
2265 lock_ObtainWrite(&smb_globalLock);
2268 /* what's the biggest ID allowed in this version of the protocol */
2269 /* TODO: do we really want a non v3 dir search request to wrap
2270 smb_dirSearchCounter? */
2271 maxAllowed = isV3 ? 65535 : 255;
2272 if (smb_dirSearchCounter > maxAllowed)
2273 smb_dirSearchCounter = 1;
2275 start = smb_dirSearchCounter;
2278 /* twice so we have enough tries to find guys we GC after one pass;
2279 * 10 extra is just in case I mis-counted.
2281 if (++counter > 2*maxAllowed+10)
2282 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2284 if (smb_dirSearchCounter > maxAllowed) {
2285 smb_dirSearchCounter = 1;
2287 if (smb_dirSearchCounter == start) {
2289 smb_GCDirSearches(isV3);
2292 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2294 /* don't need to watch for refcount zero and deleted, since
2295 * we haven't dropped the global lock.
2298 ++smb_dirSearchCounter;
2302 dsp = malloc(sizeof(*dsp));
2303 memset(dsp, 0, sizeof(*dsp));
2304 dsp->cookie = smb_dirSearchCounter;
2305 ++smb_dirSearchCounter;
2307 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2308 dsp->lastTime = osi_Time();
2309 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2310 if (!smb_lastDirSearchp)
2311 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2313 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2317 lock_ReleaseWrite(&smb_globalLock);
2321 static smb_packet_t *smb_GetPacket(void)
2325 lock_ObtainWrite(&smb_globalLock);
2326 tbp = smb_packetFreeListp;
2328 smb_packetFreeListp = tbp->nextp;
2329 lock_ReleaseWrite(&smb_globalLock);
2331 tbp = calloc(sizeof(*tbp),1);
2332 tbp->magic = SMB_PACKETMAGIC;
2335 tbp->resumeCode = 0;
2341 tbp->ncb_length = 0;
2344 tbp->stringsp = NULL;
2346 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2351 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2354 tbp = smb_GetPacket();
2355 memcpy(tbp, pkt, sizeof(smb_packet_t));
2356 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2357 tbp->stringsp = NULL;
2359 smb_HoldVC(tbp->vcp);
2363 static NCB *smb_GetNCB(void)
2368 lock_ObtainWrite(&smb_globalLock);
2369 tbp = smb_ncbFreeListp;
2371 smb_ncbFreeListp = tbp->nextp;
2372 lock_ReleaseWrite(&smb_globalLock);
2374 tbp = calloc(sizeof(*tbp),1);
2375 tbp->magic = SMB_NCBMAGIC;
2378 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2380 memset(&tbp->ncb, 0, sizeof(NCB));
2385 static void FreeSMBStrings(smb_packet_t * pkt)
2390 for (s = pkt->stringsp; s; s = ns) {
2394 pkt->stringsp = NULL;
2397 void smb_FreePacket(smb_packet_t *tbp)
2399 smb_vc_t * vcp = NULL;
2400 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2402 lock_ObtainWrite(&smb_globalLock);
2403 tbp->nextp = smb_packetFreeListp;
2404 smb_packetFreeListp = tbp;
2405 tbp->magic = SMB_PACKETMAGIC;
2409 tbp->resumeCode = 0;
2415 tbp->ncb_length = 0;
2417 FreeSMBStrings(tbp);
2418 lock_ReleaseWrite(&smb_globalLock);
2424 static void smb_FreeNCB(NCB *bufferp)
2428 tbp = (smb_ncb_t *) bufferp;
2429 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2431 lock_ObtainWrite(&smb_globalLock);
2432 tbp->nextp = smb_ncbFreeListp;
2433 smb_ncbFreeListp = tbp;
2434 lock_ReleaseWrite(&smb_globalLock);
2437 /* get a ptr to the data part of a packet, and its count */
2438 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2442 unsigned char *afterParmsp;
2444 parmBytes = *smbp->wctp << 1;
2445 afterParmsp = smbp->wctp + parmBytes + 1;
2447 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2448 if (nbytesp) *nbytesp = dataBytes;
2450 /* don't forget to skip the data byte count, since it follows
2451 * the parameters; that's where the "2" comes from below.
2453 return (unsigned char *) (afterParmsp + 2);
2456 /* must set all the returned parameters before playing around with the
2457 * data region, since the data region is located past the end of the
2458 * variable number of parameters.
2460 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2462 unsigned char *afterParmsp;
2464 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2466 *afterParmsp++ = dsize & 0xff;
2467 *afterParmsp = (dsize>>8) & 0xff;
2470 /* return the parm'th parameter in the smbp packet */
2471 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2474 unsigned char *parmDatap;
2476 parmCount = *smbp->wctp;
2478 if (parm >= parmCount) {
2481 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2482 parm, parmCount, smbp->ncb_length);
2483 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2484 parm, parmCount, smbp->ncb_length);
2485 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2486 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2487 osi_panic(s, __FILE__, __LINE__);
2489 parmDatap = smbp->wctp + (2*parm) + 1;
2491 return parmDatap[0] + (parmDatap[1] << 8);
2494 /* return the parm'th parameter in the smbp packet */
2495 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2498 unsigned char *parmDatap;
2500 parmCount = *smbp->wctp;
2502 if (parm >= parmCount) {
2505 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2506 parm, parmCount, smbp->ncb_length);
2507 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2508 parm, parmCount, smbp->ncb_length);
2509 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2510 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2511 osi_panic(s, __FILE__, __LINE__);
2513 parmDatap = smbp->wctp + (2*parm) + 1;
2515 return parmDatap[0];
2518 /* return the parm'th parameter in the smbp packet */
2519 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2522 unsigned char *parmDatap;
2524 parmCount = *smbp->wctp;
2526 if (parm + 1 >= parmCount) {
2529 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2530 parm, parmCount, smbp->ncb_length);
2531 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2532 parm, parmCount, smbp->ncb_length);
2533 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2534 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2535 osi_panic(s, __FILE__, __LINE__);
2537 parmDatap = smbp->wctp + (2*parm) + 1;
2539 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2542 /* return the parm'th parameter in the smbp packet */
2543 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2546 unsigned char *parmDatap;
2548 parmCount = *smbp->wctp;
2550 if (parm * 2 + offset >= parmCount * 2) {
2553 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2554 parm, offset, parmCount, smbp->ncb_length);
2555 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2556 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2557 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2558 parm, offset, parmCount, smbp->ncb_length);
2559 osi_panic(s, __FILE__, __LINE__);
2561 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2563 return parmDatap[0] + (parmDatap[1] << 8);
2566 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2568 unsigned char *parmDatap;
2570 /* make sure we have enough slots */
2571 if (*smbp->wctp <= slot)
2572 *smbp->wctp = slot+1;
2574 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2575 *parmDatap++ = parmValue & 0xff;
2576 *parmDatap = (parmValue>>8) & 0xff;
2579 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2581 unsigned char *parmDatap;
2583 /* make sure we have enough slots */
2584 if (*smbp->wctp <= slot)
2585 *smbp->wctp = slot+2;
2587 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2588 *parmDatap++ = parmValue & 0xff;
2589 *parmDatap++ = (parmValue>>8) & 0xff;
2590 *parmDatap++ = (parmValue>>16) & 0xff;
2591 *parmDatap = (parmValue>>24) & 0xff;
2594 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2596 unsigned char *parmDatap;
2599 /* make sure we have enough slots */
2600 if (*smbp->wctp <= slot)
2601 *smbp->wctp = slot+4;
2603 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2605 *parmDatap++ = *parmValuep++;
2608 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2610 unsigned char *parmDatap;
2612 /* make sure we have enough slots */
2613 if (*smbp->wctp <= slot) {
2614 if (smbp->oddByte) {
2616 *smbp->wctp = slot+1;
2621 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2622 *parmDatap++ = parmValue & 0xff;
2627 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2628 clientchar_t *inPathp)
2630 clientchar_t *lastSlashp;
2631 clientchar_t *streamp = NULL;
2632 clientchar_t *typep = NULL;
2634 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2635 if (lastComponentp) {
2636 *lastComponentp = lastSlashp;
2640 * If the name contains a stream name and a type
2641 * and the stream name is the nul-string and the
2642 * type is $DATA, then strip "::$DATA" from the
2643 * last component string that is returned.
2645 * Otherwise, return the full path name and allow
2646 * the file name to be rejected because it contains
2649 typep = cm_ClientStrRChr(lastSlashp, L':');
2650 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2652 streamp = cm_ClientStrRChr(lastSlashp, L':');
2653 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2657 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2658 osi_LogSaveClientString(smb_logp,streamp),
2659 osi_LogSaveClientString(smb_logp,typep));
2663 if (inPathp == lastSlashp)
2665 *outPathp++ = *inPathp++;
2674 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2675 char **chainpp, int flags)
2678 afs_uint32 type = *inp++;
2681 * The first byte specifies the type of the input string.
2682 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2686 /* Length Counted */
2687 case 0x1: /* Data Block */
2688 case 0x5: /* Variable Block */
2689 cb = *inp++ << 16 | *inp++;
2692 /* Null-terminated string */
2693 case 0x4: /* ASCII */
2694 case 0x3: /* Pathname */
2695 case 0x2: /* Dialect */
2696 cb = sizeof(pktp->data) - (inp - pktp->data);
2697 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2698 #ifdef DEBUG_UNICODE
2701 cb = sizeof(pktp->data);
2706 return NULL; /* invalid input */
2710 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2711 flags |= SMB_STRF_FORCEASCII;
2714 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2717 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2718 char ** chainpp, int flags)
2723 if (!WANTS_UNICODE(pktp))
2724 flags |= SMB_STRF_FORCEASCII;
2727 cb = sizeof(pktp->data) - (inp - pktp->data);
2728 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2729 #ifdef DEBUG_UNICODE
2732 cb = sizeof(pktp->data);
2734 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2735 flags | SMB_STRF_SRCNULTERM);
2738 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2739 size_t cb, char ** chainpp, int flags)
2742 if (!WANTS_UNICODE(pktp))
2743 flags |= SMB_STRF_FORCEASCII;
2746 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2749 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2750 size_t cch, char ** chainpp, int flags)
2755 if (!WANTS_UNICODE(pktp))
2756 flags |= SMB_STRF_FORCEASCII;
2758 cb = cch * sizeof(wchar_t);
2761 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2765 smb_ParseStringBuf(const unsigned char * bufbase,
2766 cm_space_t ** stringspp,
2767 unsigned char *inp, size_t *pcb_max,
2768 char **chainpp, int flags)
2771 if (!(flags & SMB_STRF_FORCEASCII)) {
2773 cm_space_t * spacep;
2776 if (bufbase && ((inp - bufbase) % 2) != 0) {
2777 inp++; /* unicode strings are always word aligned */
2781 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2783 cch_src = *pcb_max / sizeof(wchar_t);
2787 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2794 spacep = cm_GetSpace();
2795 spacep->nextp = *stringspp;
2796 *stringspp = spacep;
2800 *chainpp = inp + sizeof(wchar_t);
2803 *(spacep->wdata) = 0;
2804 return spacep->wdata;
2807 StringCchCopyNW(spacep->wdata,
2808 lengthof(spacep->wdata),
2809 (const clientchar_t *) inp, cch_src);
2812 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2814 return spacep->wdata;
2818 cm_space_t * spacep;
2821 /* Not using Unicode */
2823 *chainpp = inp + strlen(inp) + 1;
2826 spacep = cm_GetSpace();
2827 spacep->nextp = *stringspp;
2828 *stringspp = spacep;
2830 cchdest = lengthof(spacep->wdata);
2831 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2832 spacep->wdata, cchdest);
2834 return spacep->wdata;
2840 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2842 size_t * plen, int flags)
2848 /* we are only calculating the required size */
2855 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2857 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2858 if (!(flags & SMB_STRF_IGNORENUL))
2859 *plen += sizeof(wchar_t);
2861 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2871 cch_str = cm_ClientStrLen(str);
2872 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2875 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2883 /* if outp != NULL ... */
2885 /* Number of bytes left in the buffer.
2887 If outp lies inside the packet data buffer, we assume that the
2888 buffer is the packet data buffer. Otherwise we assume that the
2889 buffer is sizeof(packet->data).
2892 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2893 align = (int)((outp - pktp->data) % 2);
2894 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2896 align = (int)(((size_t) outp) % 2);
2897 buffersize = (int)sizeof(pktp->data);
2902 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2908 if (*str == _C('\0')) {
2910 if (buffersize < sizeof(wchar_t))
2913 *((wchar_t *) outp) = L'\0';
2914 if (plen && !(flags & SMB_STRF_IGNORENUL))
2915 *plen += sizeof(wchar_t);
2916 return outp + sizeof(wchar_t);
2919 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2921 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2922 osi_LogSaveClientString(smb_logp, str),
2928 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2930 return outp + sizeof(wchar_t) * nchars;
2938 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2941 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2943 return outp + cch_dest;
2947 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2953 tlen = inp[0] + (inp[1]<<8);
2954 inp += 2; /* skip length field */
2957 *chainpp = inp + tlen;
2966 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2970 if (*inp++ != 0x1) return NULL;
2971 tlen = inp[0] + (inp[1]<<8);
2972 inp += 2; /* skip length field */
2975 *chainpp = inp + tlen;
2978 if (lengthp) *lengthp = tlen;
2983 /* format a packet as a response */
2984 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2989 outp = (smb_t *) op;
2991 /* zero the basic structure through the smb_wct field, and zero the data
2992 * size field, assuming that wct stays zero; otherwise, you have to
2993 * explicitly set the data size field, too.
2995 inSmbp = (smb_t *) inp;
2996 memset(outp, 0, sizeof(smb_t)+2);
3002 outp->com = inSmbp->com;
3003 outp->tid = inSmbp->tid;
3004 outp->pid = inSmbp->pid;
3005 outp->uid = inSmbp->uid;
3006 outp->mid = inSmbp->mid;
3007 outp->res[0] = inSmbp->res[0];
3008 outp->res[1] = inSmbp->res[1];
3009 op->inCom = inSmbp->com;
3011 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3012 #ifdef SEND_CANONICAL_PATHNAMES
3013 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3015 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3017 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3018 outp->flg2 |= SMB_FLAGS2_UNICODE;
3021 /* copy fields in generic packet area */
3022 op->wctp = &outp->wct;
3025 /* send a (probably response) packet; vcp tells us to whom to send it.
3026 * we compute the length by looking at wct and bcc fields.
3028 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3038 ncbp = smb_GetNCB();
3042 memset(ncbp, 0, sizeof(NCB));
3044 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3045 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3046 extra += tp[0] + (tp[1]<<8);
3047 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3048 extra += 3; /* wct and length fields */
3050 ncbp->ncb_length = extra; /* bytes to send */
3051 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3052 ncbp->ncb_lana_num = vcp->lana;
3053 ncbp->ncb_command = NCBSEND; /* op means send data */
3054 ncbp->ncb_buffer = (char *) inp;/* packet */
3055 code = Netbios(ncbp);
3058 const char * s = ncb_error_string(code);
3059 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3060 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3062 lock_ObtainMutex(&vcp->mx);
3063 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3064 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3066 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3067 lock_ReleaseMutex(&vcp->mx);
3068 lock_ObtainWrite(&smb_globalLock);
3069 dead_sessions[vcp->session] = TRUE;
3070 lock_ReleaseWrite(&smb_globalLock);
3071 smb_CleanupDeadVC(vcp);
3073 lock_ReleaseMutex(&vcp->mx);
3081 void smb_MapNTError(long code, unsigned long *NTStatusp)
3083 unsigned long NTStatus;
3085 /* map CM_ERROR_* errors to NT 32-bit status codes */
3086 /* NT Status codes are listed in ntstatus.h not winerror.h */
3090 else if (code == CM_ERROR_NOSUCHCELL) {
3091 NTStatus = 0xC0000034L; /* Name not found */
3093 else if (code == CM_ERROR_NOSUCHVOLUME) {
3094 NTStatus = 0xC0000034L; /* Name not found */
3096 else if (code == CM_ERROR_TIMEDOUT) {
3098 NTStatus = 0xC00000CFL; /* Sharing Paused */
3100 /* Do not send Timeout to the SMB redirector.
3101 * It causes the redirector to drop the connection */
3102 NTStatus = 0x00000102L; /* Timeout */
3103 /* do not send Retry to the SMB redirector.
3104 * It believes the error comes from the transport
3105 * layer not from the SMB server. */
3106 NTStatus = 0xC000022DL; /* Retry */
3108 NTStatus = 0xC00000B5L; /* I/O Timeout */
3111 else if (code == CM_ERROR_RETRY) {
3113 NTStatus = 0xC000022DL; /* Retry */
3115 NTStatus = 0xC00000B5L; /* I/O Timeout */
3118 else if (code == CM_ERROR_NOACCESS) {
3119 NTStatus = 0xC0000022L; /* Access denied */
3121 else if (code == CM_ERROR_READONLY) {
3122 NTStatus = 0xC00000A2L; /* Write protected */
3124 else if (code == CM_ERROR_NOSUCHFILE ||
3125 code == CM_ERROR_BPLUS_NOMATCH) {
3126 NTStatus = 0xC0000034L; /* Name not found */
3128 else if (code == CM_ERROR_NOSUCHPATH) {
3129 NTStatus = 0xC000003AL; /* Object path not found */
3131 else if (code == CM_ERROR_TOOBIG) {
3132 NTStatus = 0xC000007BL; /* Invalid image format */
3134 else if (code == CM_ERROR_INVAL) {
3135 NTStatus = 0xC000000DL; /* Invalid parameter */
3137 else if (code == CM_ERROR_BADFD) {
3138 NTStatus = 0xC0000008L; /* Invalid handle */
3140 else if (code == CM_ERROR_BADFDOP) {
3141 NTStatus = 0xC0000022L; /* Access denied */
3143 else if (code == CM_ERROR_UNKNOWN) {
3144 NTStatus = 0xC0000022L; /* Access denied */
3146 else if (code == CM_ERROR_EXISTS) {
3147 NTStatus = 0xC0000035L; /* Object name collision */
3149 else if (code == CM_ERROR_NOTEMPTY) {
3150 NTStatus = 0xC0000101L; /* Directory not empty */
3152 else if (code == CM_ERROR_CROSSDEVLINK) {
3153 NTStatus = 0xC00000D4L; /* Not same device */
3155 else if (code == CM_ERROR_NOTDIR) {
3156 NTStatus = 0xC0000103L; /* Not a directory */
3158 else if (code == CM_ERROR_ISDIR) {
3159 NTStatus = 0xC00000BAL; /* File is a directory */
3161 else if (code == CM_ERROR_BADOP) {
3163 /* I have no idea where this comes from */
3164 NTStatus = 0xC09820FFL; /* SMB no support */
3166 NTStatus = 0xC00000BBL; /* Not supported */
3167 #endif /* COMMENT */
3169 else if (code == CM_ERROR_BADSHARENAME) {
3170 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3172 else if (code == CM_ERROR_NOIPC) {
3174 NTStatus = 0xC0000022L; /* Access Denied */
3176 NTStatus = 0xC000013DL; /* Remote Resources */
3179 else if (code == CM_ERROR_CLOCKSKEW ||
3180 code == RXKADNOAUTH) {
3181 NTStatus = 0xC0000133L; /* Time difference at DC */
3183 else if (code == CM_ERROR_BADTID) {
3184 NTStatus = 0xC0982005L; /* SMB bad TID */
3186 else if (code == CM_ERROR_USESTD) {
3187 NTStatus = 0xC09820FBL; /* SMB use standard */
3189 else if (code == CM_ERROR_QUOTA) {
3190 NTStatus = 0xC0000044L; /* Quota exceeded */
3192 else if (code == CM_ERROR_SPACE) {
3193 NTStatus = 0xC000007FL; /* Disk full */
3195 else if (code == CM_ERROR_ATSYS) {
3196 NTStatus = 0xC0000033L; /* Object name invalid */
3198 else if (code == CM_ERROR_BADNTFILENAME) {
3199 NTStatus = 0xC0000033L; /* Object name invalid */
3201 else if (code == CM_ERROR_WOULDBLOCK) {
3202 NTStatus = 0xC00000D8L; /* Can't wait */
3204 else if (code == CM_ERROR_SHARING_VIOLATION) {
3205 NTStatus = 0xC0000043L; /* Sharing violation */
3207 else if (code == CM_ERROR_LOCK_CONFLICT) {
3208 NTStatus = 0xC0000054L; /* Lock conflict */
3210 else if (code == CM_ERROR_PARTIALWRITE) {
3211 NTStatus = 0xC000007FL; /* Disk full */
3213 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3214 NTStatus = 0xC0000023L; /* Buffer too small */
3216 else if (code == CM_ERROR_BUFFER_OVERFLOW) {
3217 NTStatus = 0x80000005L; /* Buffer overflow */
3219 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3220 NTStatus = 0xC0000035L; /* Object name collision */
3222 else if (code == CM_ERROR_BADPASSWORD) {
3223 NTStatus = 0xC000006DL; /* unknown username or bad password */
3225 else if (code == CM_ERROR_BADLOGONTYPE) {
3226 NTStatus = 0xC000015BL; /* logon type not granted */
3228 else if (code == CM_ERROR_GSSCONTINUE) {
3229 NTStatus = 0xC0000016L; /* more processing required */
3231 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3233 NTStatus = 0xC0000280L; /* reparse point not resolved */
3235 NTStatus = 0xC0000022L; /* Access Denied */
3238 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3239 NTStatus = 0xC0000257L; /* Path Not Covered */
3241 else if (code == CM_ERROR_ALLBUSY) {
3243 NTStatus = 0xC000022DL; /* Retry */
3245 NTStatus = 0xC0020018L; /* RPC_NT_SERVER_TOO_BUSY */
3248 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3250 NTStatus = 0xC000003AL; /* Path not found */
3252 NTStatus = 0xC0020017L; /* RPC_NT_SERVER_UNAVAILABLE */
3255 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3256 NTStatus = 0xC0000322L; /* No Kerberos key */
3258 else if (code == CM_ERROR_BAD_LEVEL) {
3259 NTStatus = 0xC0000148L; /* Invalid Level */
3261 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3262 NTStatus = 0xC000007EL; /* Range Not Locked */
3264 else if (code == CM_ERROR_NOSUCHDEVICE) {
3265 NTStatus = 0xC000000EL; /* No Such Device */
3267 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3268 NTStatus = 0xC0000055L; /* Lock Not Granted */
3270 else if (code == ENOMEM) {
3271 NTStatus = 0xC0000017L; /* Out of Memory */
3273 else if (code == CM_ERROR_RPC_MOREDATA) {
3274 NTStatus = 0x80000005L; /* Buffer overflow */
3277 NTStatus = 0xC0982001L; /* SMB non-specific error */
3280 *NTStatusp = NTStatus;
3281 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3285 * NTSTATUS <-> Win32 Error Translation
3286 * http://support.microsoft.com/kb/113996
3288 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3290 unsigned long Win32E;
3292 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3296 else if (code == CM_ERROR_NOSUCHCELL) {
3297 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3299 else if (code == CM_ERROR_NOSUCHVOLUME) {
3300 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3302 else if (code == CM_ERROR_TIMEDOUT) {
3304 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3306 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3309 else if (code == CM_ERROR_RETRY) {
3310 Win32E = ERROR_RETRY; /* Retry */
3312 else if (code == CM_ERROR_NOACCESS) {
3313 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3315 else if (code == CM_ERROR_READONLY) {
3316 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3318 else if (code == CM_ERROR_NOSUCHFILE ||
3319 code == CM_ERROR_BPLUS_NOMATCH) {
3320 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3322 else if (code == CM_ERROR_NOSUCHPATH) {
3323 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3325 else if (code == CM_ERROR_TOOBIG) {
3326 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3328 else if (code == CM_ERROR_INVAL) {
3329 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3331 else if (code == CM_ERROR_BADFD) {
3332 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3334 else if (code == CM_ERROR_BADFDOP) {
3335 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3337 else if (code == CM_ERROR_UNKNOWN) {
3338 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3340 else if (code == CM_ERROR_EXISTS) {
3341 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3343 else if (code == CM_ERROR_NOTEMPTY) {
3344 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3346 else if (code == CM_ERROR_CROSSDEVLINK) {
3347 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3349 else if (code == CM_ERROR_NOTDIR) {
3350 Win32E = ERROR_DIRECTORY; /* Not a directory */
3352 else if (code == CM_ERROR_ISDIR) {
3353 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3355 else if (code == CM_ERROR_BADOP) {
3356 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3358 else if (code == CM_ERROR_BADSHARENAME) {
3359 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3361 else if (code == CM_ERROR_NOIPC) {
3363 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3365 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3368 else if (code == CM_ERROR_CLOCKSKEW ||
3369 code == RXKADNOAUTH) {
3370 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3372 else if (code == CM_ERROR_BADTID) {
3373 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3375 else if (code == CM_ERROR_USESTD) {
3376 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3378 else if (code == CM_ERROR_QUOTA) {
3379 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3381 else if (code == CM_ERROR_SPACE) {
3382 Win32E = ERROR_DISK_FULL; /* Disk full */
3384 else if (code == CM_ERROR_ATSYS) {
3385 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3387 else if (code == CM_ERROR_BADNTFILENAME) {
3388 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3390 else if (code == CM_ERROR_WOULDBLOCK) {
3391 Win32E = WAIT_TIMEOUT; /* Can't wait */
3393 else if (code == CM_ERROR_SHARING_VIOLATION) {
3394 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3396 else if (code == CM_ERROR_LOCK_CONFLICT) {
3397 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3399 else if (code == CM_ERROR_PARTIALWRITE) {
3400 Win32E = ERROR_DISK_FULL; /* Disk full */
3402 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3403 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3405 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3406 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3408 else if (code == CM_ERROR_BADPASSWORD) {
3409 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3411 else if (code == CM_ERROR_BADLOGONTYPE) {
3412 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3414 else if (code == CM_ERROR_GSSCONTINUE) {
3415 Win32E = ERROR_MORE_DATA; /* more processing required */
3417 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3419 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3421 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3424 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3425 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3427 else if (code == CM_ERROR_ALLBUSY) {
3428 Win32E = ERROR_RETRY; /* Retry */
3430 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3431 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3433 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3434 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3436 else if (code == CM_ERROR_BAD_LEVEL) {
3437 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3439 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3440 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3442 else if (code == CM_ERROR_NOSUCHDEVICE) {
3443 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3445 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3446 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3448 else if (code == ENOMEM) {
3449 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3451 else if (code == CM_ERROR_RPC_MOREDATA) {
3452 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3455 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3459 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3462 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3463 unsigned char *classp)
3465 unsigned char class;
3466 unsigned short error;
3468 /* map CM_ERROR_* errors to SMB errors */
3469 if (code == CM_ERROR_NOSUCHCELL) {
3471 error = 3; /* bad path */
3473 else if (code == CM_ERROR_NOSUCHVOLUME) {
3475 error = 3; /* bad path */
3477 else if (code == CM_ERROR_TIMEDOUT) {
3479 error = 81; /* server is paused */
3481 else if (code == CM_ERROR_RETRY) {
3482 class = 2; /* shouldn't happen */
3485 else if (code == CM_ERROR_NOACCESS) {
3487 error = 4; /* bad access */
3489 else if (code == CM_ERROR_READONLY) {
3491 error = 19; /* read only */
3493 else if (code == CM_ERROR_NOSUCHFILE ||
3494 code == CM_ERROR_BPLUS_NOMATCH) {
3496 error = 2; /* ENOENT! */
3498 else if (code == CM_ERROR_NOSUCHPATH) {
3500 error = 3; /* Bad path */
3502 else if (code == CM_ERROR_TOOBIG) {
3504 error = 11; /* bad format */
3506 else if (code == CM_ERROR_INVAL) {
3507 class = 2; /* server non-specific error code */
3510 else if (code == CM_ERROR_BADFD) {
3512 error = 6; /* invalid file handle */
3514 else if (code == CM_ERROR_BADFDOP) {
3515 class = 1; /* invalid op on FD */
3518 else if (code == CM_ERROR_EXISTS) {
3520 error = 80; /* file already exists */
3522 else if (code == CM_ERROR_NOTEMPTY) {
3524 error = 5; /* delete directory not empty */
3526 else if (code == CM_ERROR_CROSSDEVLINK) {
3528 error = 17; /* EXDEV */
3530 else if (code == CM_ERROR_NOTDIR) {
3531 class = 1; /* bad path */
3534 else if (code == CM_ERROR_ISDIR) {
3535 class = 1; /* access denied; DOS doesn't have a good match */
3538 else if (code == CM_ERROR_BADOP) {
3542 else if (code == CM_ERROR_BADSHARENAME) {
3546 else if (code == CM_ERROR_NOIPC) {
3548 error = 4; /* bad access */
3550 else if (code == CM_ERROR_CLOCKSKEW) {
3551 class = 1; /* invalid function */
3554 else if (code == CM_ERROR_BADTID) {
3558 else if (code == CM_ERROR_USESTD) {
3562 else if (code == CM_ERROR_REMOTECONN) {
3566 else if (code == CM_ERROR_QUOTA) {
3567 if (vcp->flags & SMB_VCFLAG_USEV3) {
3569 error = 39; /* disk full */
3573 error = 5; /* access denied */
3576 else if (code == CM_ERROR_SPACE) {
3577 if (vcp->flags & SMB_VCFLAG_USEV3) {
3579 error = 39; /* disk full */
3583 error = 5; /* access denied */
3586 else if (code == CM_ERROR_PARTIALWRITE) {
3588 error = 39; /* disk full */
3590 else if (code == CM_ERROR_ATSYS) {
3592 error = 2; /* ENOENT */
3594 else if (code == CM_ERROR_WOULDBLOCK) {
3596 error = 33; /* lock conflict */
3598 else if (code == CM_ERROR_LOCK_CONFLICT) {
3600 error = 33; /* lock conflict */
3602 else if (code == CM_ERROR_SHARING_VIOLATION) {
3604 error = 33; /* lock conflict */
3606 else if (code == CM_ERROR_NOFILES) {
3608 error = 18; /* no files in search */
3610 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3612 error = 183; /* Samba uses this */
3614 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3615 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3617 error = 2; /* bad password */
3619 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3621 error = 3; /* bad path */
3630 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3633 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3635 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3636 return CM_ERROR_BADOP;
3640 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3642 unsigned short EchoCount, i;
3643 char *data, *outdata;
3646 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3648 for (i=1; i<=EchoCount; i++) {
3649 data = smb_GetSMBData(inp, &dataSize);
3650 smb_SetSMBParm(outp, 0, i);
3651 smb_SetSMBDataLength(outp, dataSize);
3652 outdata = smb_GetSMBData(outp, NULL);
3653 memcpy(outdata, data, dataSize);
3654 smb_SendPacket(vcp, outp);
3660 /* SMB_COM_READ_RAW */
3661 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3664 long count, minCount, finalCount;
3668 smb_t *smbp = (smb_t*) inp;
3670 cm_user_t *userp = NULL;
3673 char *rawBuf = NULL;
3678 fd = smb_GetSMBParm(inp, 0);
3679 count = smb_GetSMBParm(inp, 3);
3680 minCount = smb_GetSMBParm(inp, 4);
3681 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3683 if (*inp->wctp == 10) {
3684 /* we were sent a request with 64-bit file offsets */
3685 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3687 if (LargeIntegerLessThanZero(offset)) {
3688 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3692 /* we were sent a request with 32-bit file offsets */
3693 offset.HighPart = 0;
3696 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3697 fd, offset.HighPart, offset.LowPart, count);
3699 fidp = smb_FindFID(vcp, fd, 0);
3701 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3705 lock_ObtainMutex(&fidp->mx);
3707 lock_ReleaseMutex(&fidp->mx);
3708 smb_ReleaseFID(fidp);
3709 return CM_ERROR_BADFD;
3712 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3713 lock_ReleaseMutex(&fidp->mx);
3714 smb_CloseFID(vcp, fidp, NULL, 0);
3715 code = CM_ERROR_NOSUCHFILE;
3721 LARGE_INTEGER LOffset, LLength;
3724 key = cm_GenerateKey(vcp->vcID, pid, fd);
3726 LOffset.HighPart = offset.HighPart;
3727 LOffset.LowPart = offset.LowPart;
3728 LLength.HighPart = 0;
3729 LLength.LowPart = count;
3731 lock_ObtainWrite(&fidp->scp->rw);
3732 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3733 lock_ReleaseWrite(&fidp->scp->rw);
3736 lock_ReleaseMutex(&fidp->mx);
3740 lock_ObtainMutex(&smb_RawBufLock);
3742 /* Get a raw buf, from head of list */
3743 rawBuf = smb_RawBufs;
3744 smb_RawBufs = *(char **)smb_RawBufs;
3746 lock_ReleaseMutex(&smb_RawBufLock);
3748 lock_ReleaseMutex(&fidp->mx);
3752 if (fidp->flags & SMB_FID_IOCTL)
3754 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3756 /* Give back raw buffer */
3757 lock_ObtainMutex(&smb_RawBufLock);
3758 *((char **) rawBuf) = smb_RawBufs;
3760 smb_RawBufs = rawBuf;
3761 lock_ReleaseMutex(&smb_RawBufLock);
3764 lock_ReleaseMutex(&fidp->mx);
3765 smb_ReleaseFID(fidp);
3768 lock_ReleaseMutex(&fidp->mx);
3770 userp = smb_GetUserFromVCP(vcp, inp);
3772 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3778 cm_ReleaseUser(userp);
3781 smb_ReleaseFID(fidp);
3785 memset(ncbp, 0, sizeof(NCB));
3787 ncbp->ncb_length = (unsigned short) finalCount;
3788 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3789 ncbp->ncb_lana_num = vcp->lana;
3790 ncbp->ncb_command = NCBSEND;
3791 ncbp->ncb_buffer = rawBuf;
3793 code = Netbios(ncbp);
3795 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3798 /* Give back raw buffer */
3799 lock_ObtainMutex(&smb_RawBufLock);
3800 *((char **) rawBuf) = smb_RawBufs;
3802 smb_RawBufs = rawBuf;
3803 lock_ReleaseMutex(&smb_RawBufLock);
3809 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3811 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3816 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3818 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3823 /* SMB_COM_NEGOTIATE */
3824 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3831 int VistaProtoIndex;
3832 int protoIndex; /* index we're using */
3837 char protocol_array[10][1024]; /* protocol signature of the client */
3838 int caps; /* capabilities */
3841 TIME_ZONE_INFORMATION tzi;
3843 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3846 namep = smb_GetSMBData(inp, &dbytes);
3849 coreProtoIndex = -1; /* not found */
3852 VistaProtoIndex = -1;
3853 while(namex < dbytes) {
3854 osi_Log1(smb_logp, "Protocol %s",
3855 osi_LogSaveString(smb_logp, namep+1));
3856 strcpy(protocol_array[tcounter], namep+1);
3858 /* namep points at the first protocol, or really, a 0x02
3859 * byte preceding the null-terminated ASCII name.
3861 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3862 coreProtoIndex = tcounter;
3864 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3865 v3ProtoIndex = tcounter;
3867 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3868 NTProtoIndex = tcounter;
3870 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3871 VistaProtoIndex = tcounter;
3874 /* compute size of protocol entry */
3875 entryLength = (int)strlen(namep+1);
3876 entryLength += 2; /* 0x02 bytes and null termination */
3878 /* advance over this protocol entry */
3879 namex += entryLength;
3880 namep += entryLength;
3881 tcounter++; /* which proto entry we're looking at */
3884 lock_ObtainMutex(&vcp->mx);
3886 if (VistaProtoIndex != -1) {
3887 protoIndex = VistaProtoIndex;
3888 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3891 if (NTProtoIndex != -1) {
3892 protoIndex = NTProtoIndex;
3893 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3895 else if (v3ProtoIndex != -1) {
3896 protoIndex = v3ProtoIndex;
3897 vcp->flags |= SMB_VCFLAG_USEV3;
3899 else if (coreProtoIndex != -1) {
3900 protoIndex = coreProtoIndex;
3901 vcp->flags |= SMB_VCFLAG_USECORE;
3903 else protoIndex = -1;
3904 lock_ReleaseMutex(&vcp->mx);
3906 if (protoIndex == -1)
3907 return CM_ERROR_INVAL;
3908 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3909 smb_SetSMBParm(outp, 0, protoIndex);
3910 if (smb_authType != SMB_AUTH_NONE) {
3911 smb_SetSMBParmByte(outp, 1,
3912 NEGOTIATE_SECURITY_USER_LEVEL |
3913 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3915 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3917 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3918 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3919 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3920 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3921 /* The session key is not a well documented field however most clients
3922 * will echo back the session key to the server. Currently we are using
3923 * the same value for all sessions. We should generate a random value
3924 * and store it into the vcp
3926 smb_SetSMBParmLong(outp, 7, 0x1a2b3c4d); /* session key */
3928 * Tried changing the capabilities to support for W2K - defect 117695
3929 * Maybe something else needs to be changed here?
3933 smb_SetSMBParmLong(outp, 9, 0x43fd);
3935 smb_SetSMBParmLong(outp, 9, 0x251);
3938 * 32-bit error codes *
3944 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3946 NTNEGOTIATE_CAPABILITY_DFS |
3948 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3949 NTNEGOTIATE_CAPABILITY_NTFIND |
3950 NTNEGOTIATE_CAPABILITY_RAWMODE |
3951 NTNEGOTIATE_CAPABILITY_NTSMB;
3953 if ( smb_authType == SMB_AUTH_EXTENDED )
3954 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3957 if ( smb_UseUnicode ) {
3958 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3962 smb_SetSMBParmLong(outp, 9, caps);
3964 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3965 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3966 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3968 GetTimeZoneInformation(&tzi);
3969 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3971 if (smb_authType == SMB_AUTH_NTLM) {
3972 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3973 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3974 /* paste in encryption key */
3975 datap = smb_GetSMBData(outp, NULL);
3976 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3977 /* and the faux domain name */
3978 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3979 datap + MSV1_0_CHALLENGE_LENGTH,
3980 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3981 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3985 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3987 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3989 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3991 datap = smb_GetSMBData(outp, NULL);
3992 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3995 datap += sizeof(smb_ServerGUID);
3996 memcpy(datap, secBlob, secBlobLength);
4000 smb_SetSMBParmByte(outp, 16, 0);/* Challenge length */
4001 smb_SetSMBDataLength(outp, smb_ServerDomainNameLength);
4002 datap = smb_GetSMBData(outp, NULL);
4003 /* the faux domain name */
4004 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4006 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4009 else if (v3ProtoIndex != -1) {
4010 smb_SetSMBParm(outp, 0, protoIndex);
4012 /* NOTE: Extended authentication cannot be negotiated with v3
4013 * therefore we fail over to NTLM
4015 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4016 smb_SetSMBParm(outp, 1,
4017 NEGOTIATE_SECURITY_USER_LEVEL |
4018 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
4020 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4022 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4023 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
4024 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
4025 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
4026 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
4027 smb_SetSMBParm(outp, 7, 1);
4029 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
4030 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
4031 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
4033 GetTimeZoneInformation(&tzi);
4034 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
4036 /* NOTE: Extended authentication cannot be negotiated with v3
4037 * therefore we fail over to NTLM
4039 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4040 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
4041 smb_SetSMBParm(outp, 12, 0); /* resvd */
4042 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
4043 datap = smb_GetSMBData(outp, NULL);
4044 /* paste in a new encryption key */
4045 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4046 /* and the faux domain name */
4047 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4048 datap + MSV1_0_CHALLENGE_LENGTH,
4049 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4051 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4052 smb_SetSMBParm(outp, 12, 0); /* resvd */
4053 smb_SetSMBDataLength(outp, 0);
4056 else if (coreProtoIndex != -1) { /* not really supported anymore */
4057 smb_SetSMBParm(outp, 0, protoIndex);
4058 smb_SetSMBDataLength(outp, 0);
4063 void smb_CheckVCs(void)
4065 smb_vc_t * vcp, *nextp;
4066 smb_packet_t * outp = smb_GetPacket();
4069 lock_ObtainWrite(&smb_rctLock);
4070 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4072 if (vcp->magic != SMB_VC_MAGIC)
4073 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4074 __FILE__, __LINE__);
4076 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4078 smb_HoldVCNoLock(vcp);
4081 * obtain a reference to 'nextp' now because we drop the
4082 * smb_rctLock later and the list contents could change
4083 * or 'vcp' could be destroyed when released.
4087 smb_HoldVCNoLock(nextp);
4089 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4090 smb_ReleaseVCNoLock(vcp);
4094 smb_FormatResponsePacket(vcp, NULL, outp);
4095 smbp = (smb_t *)outp;
4096 outp->inCom = smbp->com = 0x2b /* Echo */;
4104 smb_SetSMBParm(outp, 0, 0);
4105 smb_SetSMBDataLength(outp, 0);
4106 lock_ReleaseWrite(&smb_rctLock);
4108 smb_SendPacket(vcp, outp);
4110 lock_ObtainWrite(&smb_rctLock);
4111 smb_ReleaseVCNoLock(vcp);
4113 lock_ReleaseWrite(&smb_rctLock);
4114 smb_FreePacket(outp);
4117 void smb_Daemon(void *parmp)
4119 afs_uint32 count = 0;
4120 smb_username_t **unpp;
4123 while(smbShutdownFlag == 0) {
4127 if (smbShutdownFlag == 1)
4130 if ((count % 72) == 0) { /* every five minutes */
4132 time_t old_localZero = smb_localZero;
4134 /* Initialize smb_localZero */
4135 myTime.tm_isdst = -1; /* compute whether on DST or not */
4136 myTime.tm_year = 70;
4142 smb_localZero = mktime(&myTime);
4144 #ifdef AFS_FREELANCE
4145 if ( smb_localZero != old_localZero )
4146 cm_noteLocalMountPointChange(FALSE);
4152 /* GC smb_username_t objects that will no longer be used */
4154 lock_ObtainWrite(&smb_rctLock);
4155 for ( unpp=&usernamesp; *unpp; ) {
4157 smb_username_t *unp;
4159 lock_ObtainMutex(&(*unpp)->mx);
4160 if ( (*unpp)->refCount > 0 ||
4161 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4162 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4164 else if (!smb_LogoffTokenTransfer ||
4165 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4167 lock_ReleaseMutex(&(*unpp)->mx);
4175 lock_FinalizeMutex(&unp->mx);
4181 cm_ReleaseUser(userp);
4183 unpp = &(*unpp)->nextp;
4186 lock_ReleaseWrite(&smb_rctLock);
4188 /* XXX GC dir search entries */
4192 void smb_WaitingLocksDaemon()
4194 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4195 smb_waitingLock_t *wl, *wlNext;
4198 smb_packet_t *inp, *outp;
4202 while (smbShutdownFlag == 0) {
4203 lock_ObtainWrite(&smb_globalLock);
4204 nwlRequest = smb_allWaitingLocks;
4205 if (nwlRequest == NULL) {
4206 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4211 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4218 lock_ObtainWrite(&smb_globalLock);
4220 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4222 wlRequest = nwlRequest;
4223 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4224 lock_ReleaseWrite(&smb_globalLock);
4228 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4229 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4232 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4233 code = CM_ERROR_LOCK_NOT_GRANTED;
4237 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4239 /* wl->state is either _DONE or _WAITING. _ERROR
4240 would no longer be on the queue. */
4241 code = cm_RetryLock( wl->lockp,
4242 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4245 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4246 } else if (code != CM_ERROR_WOULDBLOCK) {
4247 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4252 if (code == CM_ERROR_WOULDBLOCK) {
4255 if (wlRequest->msTimeout != 0xffffffff
4256 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4268 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4271 scp = wlRequest->scp;
4272 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4276 lock_ObtainWrite(&scp->rw);
4278 for (wl = wlRequest->locks; wl; wl = wlNext) {
4279 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4281 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4282 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4283 wl->LLength, wl->key, 0, NULL, &req);
4285 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4290 lock_ReleaseWrite(&scp->rw);
4294 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4297 for (wl = wlRequest->locks; wl; wl = wlNext) {
4298 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4299 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4304 vcp = wlRequest->vcp;
4305 inp = wlRequest->inp;
4306 outp = wlRequest->outp;
4307 ncbp = smb_GetNCB();
4308 ncbp->ncb_length = inp->ncb_length;
4309 inp->spacep = cm_GetSpace();
4311 /* Remove waitingLock from list */
4312 lock_ObtainWrite(&smb_globalLock);
4313 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4315 lock_ReleaseWrite(&smb_globalLock);
4317 /* Resume packet processing */
4319 smb_SetSMBDataLength(outp, 0);
4320 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4321 outp->resumeCode = code;
4323 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4326 cm_FreeSpace(inp->spacep);
4327 smb_FreePacket(inp);
4328 smb_FreePacket(outp);
4330 cm_ReleaseSCache(wlRequest->scp);
4333 } while (nwlRequest && smbShutdownFlag == 0);
4338 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4340 osi_Log0(smb_logp, "SMB receive get disk attributes");
4342 smb_SetSMBParm(outp, 0, 32000);
4343 smb_SetSMBParm(outp, 1, 64);
4344 smb_SetSMBParm(outp, 2, 1024);
4345 smb_SetSMBParm(outp, 3, 30000);
4346 smb_SetSMBParm(outp, 4, 0);
4347 smb_SetSMBDataLength(outp, 0);
4351 /* SMB_COM_TREE_CONNECT */
4352 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4356 unsigned short newTid;
4357 clientchar_t shareName[AFSPATHMAX];
4358 clientchar_t *sharePath;
4361 clientchar_t *pathp;
4364 osi_Log0(smb_logp, "SMB receive tree connect");
4366 /* parse input parameters */
4369 tbp = smb_GetSMBData(inp, NULL);
4370 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4372 return CM_ERROR_BADSMB;
4374 tp = cm_ClientStrRChr(pathp, '\\');
4376 return CM_ERROR_BADSMB;
4377 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4379 lock_ObtainMutex(&vcp->mx);
4380 newTid = vcp->tidCounter++;
4381 lock_ReleaseMutex(&vcp->mx);
4383 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4384 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4386 return CM_ERROR_BADSMB;
4387 userp = smb_GetUserFromUID(uidp);
4388 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4389 smb_ReleaseUID(uidp);
4391 smb_ReleaseTID(tidp, FALSE);
4392 return CM_ERROR_BADSHARENAME;
4394 lock_ObtainMutex(&tidp->mx);
4395 tidp->userp = userp;
4396 tidp->pathname = sharePath;
4397 lock_ReleaseMutex(&tidp->mx);
4398 smb_ReleaseTID(tidp, FALSE);
4400 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4401 smb_SetSMBParm(rsp, 1, newTid);
4402 smb_SetSMBDataLength(rsp, 0);
4404 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4408 /* set maskp to the mask part of the incoming path.
4409 * Mask is 11 bytes long (8.3 with the dot elided).
4410 * Returns true if succeeds with a valid name, otherwise it does
4411 * its best, but returns false.
4413 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4421 /* starts off valid */
4424 /* mask starts out all blanks */
4425 memset(maskp, ' ', 11);
4428 /* find last backslash, or use whole thing if there is none */
4429 tp = cm_ClientStrRChr(pathp, '\\');
4433 tp++; /* skip slash */
4437 /* names starting with a dot are illegal */
4445 if (tc == '.' || tc == '"')
4453 /* if we get here, tp point after the dot */
4454 up = maskp+8; /* ext goes here */
4461 if (tc == '.' || tc == '"')
4464 /* copy extension if not too long */
4474 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4476 clientchar_t umask[11];
4484 /* XXX redo this, calling cm_MatchMask with a converted mask */
4486 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4490 /* otherwise, we have a valid 8.3 name; see if we have a match,
4491 * treating '?' as a wildcard in maskp (but not in the file name).
4493 tp1 = umask; /* real name, in mask format */
4494 tp2 = maskp; /* mask, in mask format */
4495 for(i=0; i<11; i++) {
4496 tc1 = *tp1++; /* clientchar_t from real name */
4497 tc2 = *tp2++; /* clientchar_t from mask */
4498 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4499 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4502 if (tc2 == '?' && tc1 != ' ')
4509 /* we got a match */
4513 clientchar_t *smb_FindMask(clientchar_t *pathp)
4517 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4520 return tp+1; /* skip the slash */
4522 return pathp; /* no slash, return the entire path */
4525 /* SMB_COM_SEARCH for a volume label
4527 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4528 dispatch function.) */
4529 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4531 clientchar_t *pathp;
4533 clientchar_t mask[12];
4534 unsigned char *statBlockp;
4535 unsigned char initStatBlock[21];
4538 osi_Log0(smb_logp, "SMB receive search volume");
4540 /* pull pathname and stat block out of request */
4541 tp = smb_GetSMBData(inp, NULL);
4542 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4543 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4545 return CM_ERROR_BADSMB;
4546 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4547 osi_assertx(statBlockp != NULL, "null statBlock");
4549 statBlockp = initStatBlock;
4553 /* for returning to caller */
4554 smb_Get8Dot3MaskFromPath(mask, pathp);
4556 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4557 tp = smb_GetSMBData(outp, NULL);
4559 *tp++ = 43; /* bytes in a dir entry */
4560 *tp++ = 0; /* high byte in counter */
4562 /* now marshall the dir entry, starting with the search status */
4563 *tp++ = statBlockp[0]; /* Reserved */
4564 memcpy(tp, mask, 11); tp += 11; /* FileName */
4566 /* now pass back server use info, with 1st byte non-zero */
4568 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4570 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4572 *tp++ = 0x8; /* attribute: volume */
4582 /* 4 byte file size */
4588 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4591 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4592 memset(tp, ' ', 13);
4595 /* set the length of the data part of the packet to 43 + 3, for the dir
4596 * entry plus the 5 and the length fields.
4598 smb_SetSMBDataLength(outp, 46);
4603 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4604 clientchar_t * tidPathp, clientchar_t * relPathp,
4605 cm_user_t *userp, cm_req_t *reqp)
4613 smb_dirListPatch_t *patchp;
4614 smb_dirListPatch_t *npatchp;
4615 clientchar_t path[AFSPATHMAX];
4617 afs_int32 mustFake = 0;
4619 code = cm_FindACLCache(dscp, userp, &rights);
4621 lock_ObtainWrite(&dscp->rw);
4622 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4623 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4624 lock_ReleaseWrite(&dscp->rw);
4625 if (code == CM_ERROR_NOACCESS) {
4633 if (!mustFake) { /* Bulk Stat */
4635 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4637 memset(bsp, 0, sizeof(cm_bulkStat_t));
4639 for (patchp = *dirPatchespp, count=0;
4641 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4642 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4646 if (lock_TryWrite(&tscp->rw)) {
4647 /* we have an entry that we can look at */
4648 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4649 /* we have a callback on it. Don't bother
4650 * fetching this stat entry, since we're happy
4651 * with the info we have.
4653 lock_ReleaseWrite(&tscp->rw);
4654 cm_ReleaseSCache(tscp);
4657 lock_ReleaseWrite(&tscp->rw);
4659 cm_ReleaseSCache(tscp);
4663 bsp->fids[i].Volume = patchp->fid.volume;
4664 bsp->fids[i].Vnode = patchp->fid.vnode;
4665 bsp->fids[i].Unique = patchp->fid.unique;
4667 if (bsp->counter == AFSCBMAX) {
4668 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4669 memset(bsp, 0, sizeof(cm_bulkStat_t));
4673 if (bsp->counter > 0)
4674 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4679 for (patchp = *dirPatchespp; patchp; patchp =
4680 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4682 dptr = patchp->dptr;
4684 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4685 relPathp ? relPathp : _C(""), patchp->dep->name);
4686 reqp->relPathp = path;
4687 reqp->tidPathp = tidPathp;
4689 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4690 reqp->relPathp = reqp->tidPathp = NULL;
4693 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4694 *dptr++ = SMB_ATTR_HIDDEN;
4697 lock_ObtainWrite(&scp->rw);
4698 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4699 lock_ReleaseWrite(&scp->rw);
4701 /* set the attribute */
4702 switch (scp->fileType) {
4703 case CM_SCACHETYPE_DIRECTORY:
4704 case CM_SCACHETYPE_MOUNTPOINT:
4705 case CM_SCACHETYPE_INVALID:
4706 attr = SMB_ATTR_DIRECTORY;
4708 case CM_SCACHETYPE_SYMLINK:
4709 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4710 attr = SMB_ATTR_DIRECTORY;
4712 attr = SMB_ATTR_NORMAL;
4715 /* if we get here we either have a normal file
4716 * or we have a file for which we have never
4717 * received status info. In this case, we can
4718 * check the even/odd value of the entry's vnode.
4719 * odd means it is to be treated as a directory
4720 * and even means it is to be treated as a file.
4722 if (mustFake && (scp->fid.vnode & 0x1))
4723 attr = SMB_ATTR_DIRECTORY;
4725 attr = SMB_ATTR_NORMAL;
4729 /* 1969-12-31 23:59:58 +00*/
4730 dosTime = 0xEBBFBF7D;
4733 shortTemp = (unsigned short) (dosTime & 0xffff);
4734 *((u_short *)dptr) = shortTemp;
4737 /* and copy out date */
4738 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4739 *((u_short *)dptr) = shortTemp;
4742 /* copy out file length */
4743 *((u_long *)dptr) = 0;
4746 lock_ConvertWToR(&scp->rw);
4747 attr = smb_Attributes(scp);
4748 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4749 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4750 attr |= SMB_ATTR_HIDDEN;
4754 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4757 shortTemp = (unsigned short) (dosTime & 0xffff);
4758 *((u_short *)dptr) = shortTemp;
4761 /* and copy out date */
4762 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4763 *((u_short *)dptr) = shortTemp;
4766 /* copy out file length */
4767 *((u_long *)dptr) = scp->length.LowPart;
4769 lock_ReleaseRead(&scp->rw);
4771 cm_ReleaseSCache(scp);
4774 /* now free the patches */
4775 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4776 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4780 /* and mark the list as empty */
4781 *dirPatchespp = NULL;
4787 /* SMB_COM_SEARCH */
4788 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4794 clientchar_t *pathp;
4795 cm_dirEntry_t *dep = 0;
4797 smb_dirListPatch_t *dirListPatchesp;
4798 smb_dirListPatch_t *curPatchp;
4802 osi_hyper_t dirLength;
4803 osi_hyper_t bufferOffset;
4804 osi_hyper_t curOffset;
4806 unsigned char *inCookiep;
4807 smb_dirSearch_t *dsp;
4811 unsigned long clientCookie;
4812 cm_pageHeader_t *pageHeaderp;
4813 cm_user_t *userp = NULL;
4815 clientchar_t mask[12];
4817 long nextEntryCookie;
4818 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4819 char resByte; /* reserved byte from the cookie */
4820 char *op; /* output data ptr */
4821 char *origOp; /* original value of op */
4822 cm_space_t *spacep; /* for pathname buffer */
4826 clientchar_t *tidPathp = 0;
4833 maxCount = smb_GetSMBParm(inp, 0);
4835 dirListPatchesp = NULL;
4837 caseFold = CM_FLAG_CASEFOLD;
4839 tp = smb_GetSMBData(inp, NULL);
4840 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4841 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4843 return CM_ERROR_BADSMB;
4845 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4847 return CM_ERROR_BADSMB;
4849 /* We can handle long names */
4850 if (vcp->flags & SMB_VCFLAG_USENT)
4851 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4853 /* make sure we got a whole search status */
4854 if (dataLength < 21) {
4855 nextCookie = 0; /* start at the beginning of the dir */
4858 attribute = smb_GetSMBParm(inp, 1);
4860 /* handle volume info in another function */
4861 if (attribute & 0x8)
4862 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4864 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4865 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4867 if (*pathp == 0) { /* null pathp, treat as root dir */
4868 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4869 return CM_ERROR_NOFILES;
4873 dsp = smb_NewDirSearch(0);
4874 dsp->attribute = attribute;
4875 smb_Get8Dot3MaskFromPath(mask, pathp);
4876 memcpy(dsp->mask, mask, 12);
4878 /* track if this is likely to match a lot of entries */
4879 if (smb_Is8Dot3StarMask(mask))
4884 /* pull the next cookie value out of the search status block */
4885 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4886 + (inCookiep[16]<<24);
4887 dsp = smb_FindDirSearch(inCookiep[12]);
4889 /* can't find dir search status; fatal error */
4890 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4891 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4892 return CM_ERROR_BADFD;
4894 attribute = dsp->attribute;
4895 resByte = inCookiep[0];
4897 /* copy out client cookie, in host byte order. Don't bother
4898 * interpreting it, since we're just passing it through, anyway.
4900 memcpy(&clientCookie, &inCookiep[17], 4);
4902 memcpy(mask, dsp->mask, 12);
4904 /* assume we're doing a star match if it has continued for more
4910 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4911 nextCookie, dsp->cookie, attribute);
4913 userp = smb_GetUserFromVCP(vcp, inp);
4915 /* try to get the vnode for the path name next */
4916 lock_ObtainMutex(&dsp->mx);
4919 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4923 spacep = inp->spacep;
4924 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4925 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4927 lock_ReleaseMutex(&dsp->mx);
4928 cm_ReleaseUser(userp);
4929 smb_DeleteDirSearch(dsp);
4930 smb_ReleaseDirSearch(dsp);
4931 return CM_ERROR_NOFILES;
4933 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4934 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4936 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
4937 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4940 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4943 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4944 cm_ReleaseSCache(scp);
4945 lock_ReleaseMutex(&dsp->mx);
4946 cm_ReleaseUser(userp);
4947 smb_DeleteDirSearch(dsp);
4948 smb_ReleaseDirSearch(dsp);
4949 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4950 return CM_ERROR_PATH_NOT_COVERED;
4952 return CM_ERROR_NOSUCHPATH;
4954 #endif /* DFS_SUPPORT */
4957 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4958 /* we need one hold for the entry we just stored into,
4959 * and one for our own processing. When we're done with this
4960 * function, we'll drop the one for our own processing.
4961 * We held it once from the namei call, and so we do another hold
4965 lock_ObtainWrite(&scp->rw);
4966 dsp->flags |= SMB_DIRSEARCH_BULKST;
4967 lock_ReleaseWrite(&scp->rw);
4970 lock_ReleaseMutex(&dsp->mx);
4972 cm_ReleaseUser(userp);
4973 smb_DeleteDirSearch(dsp);
4974 smb_ReleaseDirSearch(dsp);
4978 /* reserves space for parameter; we'll adjust it again later to the
4979 * real count of the # of entries we returned once we've actually
4980 * assembled the directory listing.
4982 smb_SetSMBParm(outp, 0, 0);
4984 /* get the directory size */
4985 lock_ObtainWrite(&scp->rw);
4986 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4987 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4989 lock_ReleaseWrite(&scp->rw);
4990 cm_ReleaseSCache(scp);
4991 cm_ReleaseUser(userp);
4992 smb_DeleteDirSearch(dsp);
4993 smb_ReleaseDirSearch(dsp);
4997 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4999 dirLength = scp->length;
5001 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5002 curOffset.HighPart = 0;
5003 curOffset.LowPart = nextCookie;
5004 origOp = op = smb_GetSMBData(outp, NULL);
5005 /* and write out the basic header */
5006 *op++ = 5; /* variable block */
5007 op += 2; /* skip vbl block length; we'll fill it in later */
5011 clientchar_t *actualName = NULL;
5012 int free_actualName = 0;
5013 clientchar_t shortName[13];
5014 clientchar_t *shortNameEnd;
5016 /* make sure that curOffset.LowPart doesn't point to the first
5017 * 32 bytes in the 2nd through last dir page, and that it doesn't
5018 * point at the first 13 32-byte chunks in the first dir page,
5019 * since those are dir and page headers, and don't contain useful
5022 temp = curOffset.LowPart & (2048-1);
5023 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5024 /* we're in the first page */
5025 if (temp < 13*32) temp = 13*32;
5028 /* we're in a later dir page */
5029 if (temp < 32) temp = 32;
5032 /* make sure the low order 5 bits are zero */
5035 /* now put temp bits back ito curOffset.LowPart */
5036 curOffset.LowPart &= ~(2048-1);
5037 curOffset.LowPart |= temp;
5039 /* check if we've returned all the names that will fit in the
5042 if (returnedNames >= maxCount) {
5043 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5044 returnedNames, maxCount);
5048 /* check if we've passed the dir's EOF */
5049 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5051 /* see if we can use the bufferp we have now; compute in which page
5052 * the current offset would be, and check whether that's the offset
5053 * of the buffer we have. If not, get the buffer.
5055 thyper.HighPart = curOffset.HighPart;
5056 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5057 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5060 buf_Release(bufferp);
5063 lock_ReleaseWrite(&scp->rw);
5064 code = buf_Get(scp, &thyper, &req, &bufferp);
5065 lock_ObtainMutex(&dsp->mx);
5067 /* now, if we're doing a star match, do bulk fetching of all of
5068 * the status info for files in the dir.
5071 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5073 lock_ObtainWrite(&scp->rw);
5074 lock_ReleaseMutex(&dsp->mx);
5076 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5080 bufferOffset = thyper;
5082 /* now get the data in the cache */
5084 code = cm_SyncOp(scp, bufferp, userp, &req,
5086 CM_SCACHESYNC_NEEDCALLBACK |
5087 CM_SCACHESYNC_READ);
5089 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5093 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5095 if (cm_HaveBuffer(scp, bufferp, 0)) {
5096 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5100 /* otherwise, load the buffer and try again */
5101 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5103 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5104 scp, bufferp, code);
5109 buf_Release(bufferp);
5113 } /* if (wrong buffer) ... */
5115 /* now we have the buffer containing the entry we're interested in; copy
5116 * it out if it represents a non-deleted entry.
5118 entryInDir = curOffset.LowPart & (2048-1);
5119 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5121 /* page header will help tell us which entries are free. Page header
5122 * can change more often than once per buffer, since AFS 3 dir page size
5123 * may be less than (but not more than a buffer package buffer.
5125 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5126 temp &= ~(2048 - 1); /* turn off intra-page bits */
5127 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5129 /* now determine which entry we're looking at in the page. If it is
5130 * free (there's a free bitmap at the start of the dir), we should
5131 * skip these 32 bytes.
5133 slotInPage = (entryInDir & 0x7e0) >> 5;
5134 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5135 /* this entry is free */
5136 numDirChunks = 1; /* only skip this guy */
5140 tp = bufferp->datap + entryInBuffer;
5141 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5143 /* while we're here, compute the next entry's location, too,
5144 * since we'll need it when writing out the cookie into the dir
5147 * XXXX Probably should do more sanity checking.
5149 numDirChunks = cm_NameEntries(dep->name, NULL);
5151 /* compute the offset of the cookie representing the next entry */
5152 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5154 /* Compute 8.3 name if necessary */
5155 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5156 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5159 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5160 actualName = shortName;
5161 free_actualName = 0;
5163 free_actualName = 1;
5166 if (actualName == NULL) {
5167 /* Couldn't convert the name for some reason */
5168 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5169 osi_LogSaveString(smb_logp, dep->name));
5173 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5174 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5175 osi_LogSaveClientString(smb_logp, actualName));
5177 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5178 /* this is one of the entries to use: it is not deleted
5179 * and it matches the star pattern we're looking for.
5182 /* Eliminate entries that don't match requested
5185 /* no hidden files */
5186 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5187 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5191 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5193 /* We have already done the cm_TryBulkStat above */
5194 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5195 fileType = cm_FindFileType(&fid);
5196 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5197 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5199 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5200 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5201 fileType == CM_SCACHETYPE_DFSLINK ||
5202 fileType == CM_SCACHETYPE_INVALID)
5203 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5208 memcpy(op, mask, 11); op += 11;
5209 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5210 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5211 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5212 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5213 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5214 memcpy(op, &clientCookie, 4); op += 4;
5216 /* now we emit the attribute. This is sort of tricky,
5217 * since we need to really stat the file to find out
5218 * what type of entry we've got. Right now, we're
5219 * copying out data from a buffer, while holding the
5220 * scp locked, so it isn't really convenient to stat
5221 * something now. We'll put in a place holder now,
5222 * and make a second pass before returning this to get
5223 * the real attributes. So, we just skip the data for
5224 * now, and adjust it later. We allocate a patch
5225 * record to make it easy to find this point later.
5226 * The replay will happen at a time when it is safe to
5227 * unlock the directory.
5229 curPatchp = malloc(sizeof(*curPatchp));
5230 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5231 curPatchp->dptr = op;
5232 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5234 /* do hidden attribute here since name won't be around when applying
5238 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5239 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5241 curPatchp->flags = 0;
5243 op += 9; /* skip attr, time, date and size */
5245 /* zero out name area. The spec says to pad with
5246 * spaces, but Samba doesn't, and neither do we.
5250 /* finally, we get to copy out the name; we know that
5251 * it fits in 8.3 or the pattern wouldn't match, but it
5252 * never hurts to be sure.
5254 cm_ClientStringToUtf8(actualName, -1, op, 13);
5255 if (smb_StoreAnsiFilenames)
5257 /* This is a UCHAR field, which is ASCII even if Unicode
5260 /* Uppercase if requested by client */
5261 if (!KNOWS_LONG_NAMES(inp))
5266 /* now, adjust the # of entries copied */
5268 } /* if we're including this name */
5271 if (free_actualName && actualName) {
5276 /* and adjust curOffset to be where the new cookie is */
5277 thyper.HighPart = 0;
5278 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5279 curOffset = LargeIntegerAdd(thyper, curOffset);
5280 } /* while copying data for dir listing */
5282 /* release the mutex */
5283 lock_ReleaseWrite(&scp->rw);
5285 buf_Release(bufferp);
5289 /* apply and free last set of patches; if not doing a star match, this
5290 * will be empty, but better safe (and freeing everything) than sorry.
5292 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5294 /* special return code for unsuccessful search */
5295 if (code == 0 && dataLength < 21 && returnedNames == 0)
5296 code = CM_ERROR_NOFILES;
5298 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5299 returnedNames, code);
5302 smb_DeleteDirSearch(dsp);
5303 smb_ReleaseDirSearch(dsp);
5304 cm_ReleaseSCache(scp);
5305 cm_ReleaseUser(userp);
5309 /* finalize the output buffer */
5310 smb_SetSMBParm(outp, 0, returnedNames);
5311 temp = (long) (op - origOp);
5312 smb_SetSMBDataLength(outp, temp);
5314 /* the data area is a variable block, which has a 5 (already there)
5315 * followed by the length of the # of data bytes. We now know this to
5316 * be "temp," although that includes the 3 bytes of vbl block header.
5317 * Deduct for them and fill in the length field.
5319 temp -= 3; /* deduct vbl block info */
5320 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5321 origOp[1] = (unsigned char)(temp & 0xff);
5322 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5323 if (returnedNames == 0)
5324 smb_DeleteDirSearch(dsp);
5325 smb_ReleaseDirSearch(dsp);
5326 cm_ReleaseSCache(scp);
5327 cm_ReleaseUser(userp);
5332 /* verify that this is a valid path to a directory. I don't know why they
5333 * don't use the get file attributes call.
5335 * SMB_COM_CHECK_DIRECTORY
5337 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5339 clientchar_t *pathp;
5341 cm_scache_t *rootScp;
5342 cm_scache_t *newScp;
5346 clientchar_t *tidPathp;
5352 pdata = smb_GetSMBData(inp, NULL);
5353 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5355 return CM_ERROR_BADSMB;
5356 osi_Log1(smb_logp, "SMB receive check path %S",
5357 osi_LogSaveClientString(smb_logp, pathp));
5359 userp = smb_GetUserFromVCP(vcp, inp);
5361 rootScp = cm_RootSCachep(userp, &req);
5363 caseFold = CM_FLAG_CASEFOLD;
5365 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5367 cm_ReleaseUser(userp);
5368 return CM_ERROR_NOSUCHPATH;
5370 code = cm_NameI(rootScp, pathp,
5371 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5372 userp, tidPathp, &req, &newScp);
5375 cm_ReleaseUser(userp);
5380 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5381 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5382 cm_ReleaseSCache(newScp);
5383 cm_ReleaseUser(userp);
5384 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5385 return CM_ERROR_PATH_NOT_COVERED;
5387 return CM_ERROR_NOSUCHPATH;
5389 #endif /* DFS_SUPPORT */
5391 /* now lock the vnode with a callback; returns with newScp locked */
5392 lock_ObtainWrite(&newScp->rw);
5393 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5394 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5396 if (code != CM_ERROR_NOACCESS) {
5397 lock_ReleaseWrite(&newScp->rw);
5398 cm_ReleaseSCache(newScp);
5399 cm_ReleaseUser(userp);
5403 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5406 attrs = smb_Attributes(newScp);
5408 if (!(attrs & SMB_ATTR_DIRECTORY))
5409 code = CM_ERROR_NOTDIR;
5411 lock_ReleaseWrite(&newScp->rw);
5413 cm_ReleaseSCache(newScp);
5414 cm_ReleaseUser(userp);
5418 /* SMB_COM_SET_INFORMATION */
5419 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5421 clientchar_t *pathp;
5423 cm_scache_t *rootScp;
5424 unsigned short attribute;
5426 cm_scache_t *newScp;
5430 clientchar_t *tidPathp;
5436 /* decode basic attributes we're passed */
5437 attribute = smb_GetSMBParm(inp, 0);
5438 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5440 datap = smb_GetSMBData(inp, NULL);
5441 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5443 return CM_ERROR_BADSMB;
5445 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5446 dosTime, attribute);
5448 userp = smb_GetUserFromVCP(vcp, inp);
5450 rootScp = cm_RootSCachep(userp, &req);
5452 caseFold = CM_FLAG_CASEFOLD;
5454 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5456 cm_ReleaseUser(userp);
5457 return CM_ERROR_NOSUCHFILE;
5459 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5460 tidPathp, &req, &newScp);
5463 cm_ReleaseUser(userp);
5468 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5469 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5470 cm_ReleaseSCache(newScp);
5471 cm_ReleaseUser(userp);
5472 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5473 return CM_ERROR_PATH_NOT_COVERED;
5475 return CM_ERROR_NOSUCHPATH;
5477 #endif /* DFS_SUPPORT */
5479 /* now lock the vnode with a callback; returns with newScp locked; we
5480 * need the current status to determine what the new status is, in some
5483 lock_ObtainWrite(&newScp->rw);
5484 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5485 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5487 lock_ReleaseWrite(&newScp->rw);
5488 cm_ReleaseSCache(newScp);
5489 cm_ReleaseUser(userp);
5493 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5495 /* Check for RO volume */
5496 if (newScp->flags & CM_SCACHEFLAG_RO) {
5497 lock_ReleaseWrite(&newScp->rw);
5498 cm_ReleaseSCache(newScp);
5499 cm_ReleaseUser(userp);
5500 return CM_ERROR_READONLY;
5503 /* prepare for setattr call */
5506 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5507 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5509 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5510 /* we're told to make a writable file read-only */
5511 attr.unixModeBits = newScp->unixModeBits & ~0222;
5512 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5514 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5515 /* we're told to make a read-only file writable */
5516 attr.unixModeBits = newScp->unixModeBits | 0222;
5517 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5519 lock_ReleaseWrite(&newScp->rw);
5521 /* now call setattr */
5523 code = cm_SetAttr(newScp, &attr, userp, &req);
5527 cm_ReleaseSCache(newScp);
5528 cm_ReleaseUser(userp);
5534 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5536 clientchar_t *pathp;
5538 cm_scache_t *rootScp;
5539 cm_scache_t *newScp, *dscp;
5544 clientchar_t *tidPathp;
5546 clientchar_t *lastComp;
5552 datap = smb_GetSMBData(inp, NULL);
5553 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5555 return CM_ERROR_BADSMB;
5557 if (*pathp == 0) /* null path */
5560 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5561 osi_LogSaveClientString(smb_logp, pathp));
5563 userp = smb_GetUserFromVCP(vcp, inp);
5565 rootScp = cm_RootSCachep(userp, &req);
5567 /* we shouldn't need this for V3 requests, but we seem to */
5568 caseFold = CM_FLAG_CASEFOLD;
5570 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5572 cm_ReleaseUser(userp);
5573 return CM_ERROR_NOSUCHFILE;
5577 * XXX Strange hack XXX
5579 * As of Patch 5 (16 July 97), we are having the following problem:
5580 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5581 * requests to look up "desktop.ini" in all the subdirectories.
5582 * This can cause zillions of timeouts looking up non-existent cells
5583 * and volumes, especially in the top-level directory.
5585 * We have not found any way to avoid this or work around it except
5586 * to explicitly ignore the requests for mount points that haven't
5587 * yet been evaluated and for directories that haven't yet been
5590 * We should modify this hack to provide a fake desktop.ini file
5591 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5593 spacep = inp->spacep;
5594 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5595 #ifndef SPECIAL_FOLDERS
5596 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5597 code = cm_NameI(rootScp, spacep->wdata,
5598 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5599 userp, tidPathp, &req, &dscp);
5602 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5603 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5605 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5606 return CM_ERROR_PATH_NOT_COVERED;
5608 return CM_ERROR_NOSUCHPATH;
5610 #endif /* DFS_SUPPORT */
5611 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5612 code = CM_ERROR_NOSUCHFILE;
5613 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5614 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
5619 code = CM_ERROR_NOSUCHFILE;
5621 cm_ReleaseSCache(dscp);
5623 cm_ReleaseUser(userp);
5627 else if (code != CM_ERROR_NOSUCHFILE &&
5628 code != CM_ERROR_NOSUCHPATH &&
5629 code != CM_ERROR_BPLUS_NOMATCH)
5631 cm_ReleaseUser(userp);
5635 #endif /* SPECIAL_FOLDERS */
5637 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5638 tidPathp, &req, &newScp);
5640 cm_ReleaseUser(userp);
5645 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5646 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5647 cm_ReleaseSCache(newScp);
5648 cm_ReleaseUser(userp);
5649 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5650 return CM_ERROR_PATH_NOT_COVERED;
5652 return CM_ERROR_NOSUCHPATH;
5654 #endif /* DFS_SUPPORT */
5656 /* now lock the vnode with a callback; returns with newScp locked */
5657 lock_ObtainWrite(&newScp->rw);
5658 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5659 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5661 lock_ReleaseWrite(&newScp->rw);
5662 cm_ReleaseSCache(newScp);
5663 cm_ReleaseUser(userp);
5667 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5669 attrs = smb_Attributes(newScp);
5671 smb_SetSMBParm(outp, 0, attrs);
5673 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5674 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5675 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5676 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5677 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5678 smb_SetSMBParm(outp, 5, 0);
5679 smb_SetSMBParm(outp, 6, 0);
5680 smb_SetSMBParm(outp, 7, 0);
5681 smb_SetSMBParm(outp, 8, 0);
5682 smb_SetSMBParm(outp, 9, 0);
5683 smb_SetSMBDataLength(outp, 0);
5684 lock_ReleaseWrite(&newScp->rw);
5686 cm_ReleaseSCache(newScp);
5687 cm_ReleaseUser(userp);
5692 /* SMB_COM_TREE_DISCONNECT */
5693 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5697 osi_Log0(smb_logp, "SMB receive tree disconnect");
5699 /* find the tree and free it */
5700 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5702 lock_ObtainWrite(&smb_rctLock);
5704 smb_ReleaseTID(tidp, TRUE);
5705 lock_ReleaseWrite(&smb_rctLock);
5712 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5715 clientchar_t *pathp;
5716 clientchar_t *lastNamep;
5725 clientchar_t *tidPathp;
5731 datap = smb_GetSMBData(inp, NULL);
5732 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5734 return CM_ERROR_BADSMB;
5736 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5738 #ifdef DEBUG_VERBOSE
5742 hexpath = osi_HexifyString( pathp );
5743 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5748 share = smb_GetSMBParm(inp, 0);
5749 attribute = smb_GetSMBParm(inp, 1);
5751 spacep = inp->spacep;
5752 /* smb_StripLastComponent will strip "::$DATA" if present */
5753 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5755 if (!cm_IsValidClientString(pathp)) {
5757 clientchar_t * hexp;
5759 hexp = cm_GetRawCharsAlloc(pathp, -1);
5760 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5761 osi_LogSaveClientString(smb_logp, hexp));
5765 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5767 return CM_ERROR_BADNTFILENAME;
5770 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5771 /* special case magic file name for receiving IOCTL requests
5772 * (since IOCTL calls themselves aren't getting through).
5774 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5775 smb_SetupIoctlFid(fidp, spacep);
5776 smb_SetSMBParm(outp, 0, fidp->fid);
5777 smb_SetSMBParm(outp, 1, 0); /* attrs */
5778 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5779 smb_SetSMBParm(outp, 3, 0);
5780 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5781 smb_SetSMBParm(outp, 5, 0x7fff);
5782 /* pass the open mode back */
5783 smb_SetSMBParm(outp, 6, (share & 0xf));
5784 smb_SetSMBDataLength(outp, 0);
5785 smb_ReleaseFID(fidp);
5789 userp = smb_GetUserFromVCP(vcp, inp);
5791 caseFold = CM_FLAG_CASEFOLD;
5793 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5795 cm_ReleaseUser(userp);
5796 return CM_ERROR_NOSUCHPATH;
5798 code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
5799 tidPathp, &req, &scp);
5802 cm_ReleaseUser(userp);
5807 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5808 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5809 cm_ReleaseSCache(scp);
5810 cm_ReleaseUser(userp);
5811 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5812 return CM_ERROR_PATH_NOT_COVERED;
5814 return CM_ERROR_NOSUCHPATH;
5816 #endif /* DFS_SUPPORT */
5818 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5820 cm_ReleaseSCache(scp);
5821 cm_ReleaseUser(userp);
5825 /* don't need callback to check file type, since file types never
5826 * change, and namei and cm_Lookup all stat the object at least once on
5827 * a successful return.
5829 if (scp->fileType != CM_SCACHETYPE_FILE) {
5830 cm_ReleaseSCache(scp);
5831 cm_ReleaseUser(userp);
5832 return CM_ERROR_ISDIR;
5835 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5836 osi_assertx(fidp, "null smb_fid_t");
5838 lock_ObtainMutex(&fidp->mx);
5839 if ((share & 0xf) == 0)
5840 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5841 else if ((share & 0xf) == 1)
5842 fidp->flags |= SMB_FID_OPENWRITE;
5844 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5848 fidp->userp = userp;
5850 /* and a pointer to the vnode */
5852 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5853 lock_ObtainWrite(&scp->rw);
5854 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5856 smb_SetSMBParm(outp, 0, fidp->fid);
5857 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5858 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5859 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5860 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5861 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5862 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5863 /* pass the open mode back; XXXX add access checks */
5864 smb_SetSMBParm(outp, 6, (share & 0xf));
5865 smb_SetSMBDataLength(outp, 0);
5866 lock_ReleaseMutex(&fidp->mx);
5867 lock_ReleaseRead(&scp->rw);
5870 cm_Open(scp, 0, userp);
5872 /* send and free packet */
5873 smb_ReleaseFID(fidp);
5874 cm_ReleaseUser(userp);
5875 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5879 typedef struct smb_unlinkRock {
5884 clientchar_t *maskp; /* pointer to the star pattern */
5887 cm_dirEntryList_t * matches;
5890 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5893 smb_unlinkRock_t *rockp;
5896 normchar_t matchName[MAX_PATH];
5900 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5901 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5902 caseFold |= CM_FLAG_8DOT3;
5904 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5905 /* Can't convert name */
5906 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5907 osi_LogSaveString(smb_logp, dep->name));
5911 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5913 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5914 !cm_Is8Dot3(matchName)) {
5915 cm_Gen8Dot3Name(dep, matchName, NULL);
5916 /* 8.3 matches are always case insensitive */
5917 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5920 osi_Log1(smb_logp, "Found match %S",
5921 osi_LogSaveClientString(smb_logp, matchName));
5923 cm_DirEntryListAdd(dep->name, &rockp->matches);
5927 /* If we made a case sensitive exact match, we might as well quit now. */
5928 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5929 code = CM_ERROR_STOPNOW;
5938 /* SMB_COM_DELETE */
5939 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5943 clientchar_t *pathp;
5947 clientchar_t *lastNamep;
5948 smb_unlinkRock_t rock;
5952 clientchar_t *tidPathp;
5956 memset(&rock, 0, sizeof(rock));
5958 attribute = smb_GetSMBParm(inp, 0);
5960 tp = smb_GetSMBData(inp, NULL);
5961 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5963 return CM_ERROR_BADSMB;
5965 osi_Log1(smb_logp, "SMB receive unlink %S",
5966 osi_LogSaveClientString(smb_logp, pathp));
5968 spacep = inp->spacep;
5969 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5971 userp = smb_GetUserFromVCP(vcp, inp);
5973 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5975 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5977 cm_ReleaseUser(userp);
5978 return CM_ERROR_NOSUCHPATH;
5980 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
5983 cm_ReleaseUser(userp);
5988 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5989 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5990 cm_ReleaseSCache(dscp);
5991 cm_ReleaseUser(userp);
5992 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5993 return CM_ERROR_PATH_NOT_COVERED;
5995 return CM_ERROR_NOSUCHPATH;
5997 #endif /* DFS_SUPPORT */
5999 /* otherwise, scp points to the parent directory. */
6006 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
6008 code = CM_ERROR_NOSUCHFILE;
6011 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6014 thyper.HighPart = 0;
6019 rock.matches = NULL;
6021 /* Now, if we aren't dealing with a wildcard match, we first try an exact
6022 * match. If that fails, we do a case insensitve match.
6024 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6025 !smb_IsStarMask(rock.maskp)) {
6026 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6029 thyper.HighPart = 0;
6030 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6035 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6037 if (code == CM_ERROR_STOPNOW)
6040 if (code == 0 && rock.matches) {
6041 cm_dirEntryList_t * entry;
6043 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6044 normchar_t normalizedName[MAX_PATH];
6046 /* Note: entry->name is a non-normalized name */
6048 osi_Log1(smb_logp, "Unlinking %s",
6049 osi_LogSaveString(smb_logp, entry->name));
6051 /* We assume this works because entry->name was
6052 successfully converted in smb_UnlinkProc() once. */
6053 cm_FsStringToNormString(entry->name, -1,
6054 normalizedName, lengthof(normalizedName));
6056 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6058 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6059 smb_NotifyChange(FILE_ACTION_REMOVED,
6060 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6061 dscp, normalizedName, NULL, TRUE);
6065 cm_DirEntryListFree(&rock.matches);
6069 cm_ReleaseUser(userp);
6072 cm_ReleaseSCache(dscp);
6077 if (code == 0 && !rock.any)
6078 code = CM_ERROR_NOSUCHFILE;
6082 typedef struct smb_renameRock {
6083 cm_scache_t *odscp; /* old dir */
6084 cm_scache_t *ndscp; /* new dir */
6085 cm_user_t *userp; /* user */
6086 cm_req_t *reqp; /* request struct */
6087 smb_vc_t *vcp; /* virtual circuit */
6088 normchar_t *maskp; /* pointer to star pattern of old file name */
6089 int flags; /* tilde, casefold, etc */
6090 clientchar_t *newNamep; /* ptr to the new file's name */
6091 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6092 clientchar_t clOldName[MAX_PATH]; /* client name */
6096 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6099 smb_renameRock_t *rockp;
6102 normchar_t matchName[MAX_PATH];
6104 rockp = (smb_renameRock_t *) vrockp;
6106 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6107 /* Can't convert string */
6108 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6109 osi_LogSaveString(smb_logp, dep->name));
6113 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6114 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6115 caseFold |= CM_FLAG_8DOT3;
6117 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6119 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6120 !cm_Is8Dot3(matchName)) {
6121 cm_Gen8Dot3Name(dep, matchName, NULL);
6122 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6127 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6128 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6130 code = CM_ERROR_STOPNOW;
6140 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6143 cm_space_t *spacep = NULL;
6144 smb_renameRock_t rock;
6145 cm_scache_t *oldDscp = NULL;
6146 cm_scache_t *newDscp = NULL;
6147 cm_scache_t *tmpscp= NULL;
6148 cm_scache_t *tmpscp2 = NULL;
6149 clientchar_t *oldLastNamep;
6150 clientchar_t *newLastNamep;
6154 clientchar_t *tidPathp;
6158 userp = smb_GetUserFromVCP(vcp, inp);
6159 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6161 cm_ReleaseUser(userp);
6162 return CM_ERROR_NOSUCHPATH;
6166 memset(&rock, 0, sizeof(rock));
6168 spacep = inp->spacep;
6169 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6171 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6172 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6173 userp, tidPathp, &req, &oldDscp);
6175 cm_ReleaseUser(userp);
6180 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6181 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6182 cm_ReleaseSCache(oldDscp);
6183 cm_ReleaseUser(userp);
6184 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6185 return CM_ERROR_PATH_NOT_COVERED;
6187 return CM_ERROR_NOSUCHPATH;
6189 #endif /* DFS_SUPPORT */
6191 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6192 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6193 userp, tidPathp, &req, &newDscp);
6196 cm_ReleaseSCache(oldDscp);
6197 cm_ReleaseUser(userp);
6202 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6203 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6204 cm_ReleaseSCache(oldDscp);
6205 cm_ReleaseSCache(newDscp);
6206 cm_ReleaseUser(userp);
6207 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6208 return CM_ERROR_PATH_NOT_COVERED;
6210 return CM_ERROR_NOSUCHPATH;
6212 #endif /* DFS_SUPPORT */
6215 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6216 * next, get the component names, and lower case them.
6219 /* handle the old name first */
6221 oldLastNamep = oldPathp;
6225 /* and handle the new name, too */
6227 newLastNamep = newPathp;
6231 /* TODO: The old name could be a wildcard. The new name must not be */
6233 /* Check if the file already exists; if so return error */
6234 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6235 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6236 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6238 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6239 osi_LogSaveClientString(smb_logp, newLastNamep));
6241 /* Check if the old and the new names differ only in case. If so return
6242 * success, else return CM_ERROR_EXISTS
6244 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6246 /* This would be a success only if the old file is *as same as* the new file */
6247 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6249 if (tmpscp == tmpscp2)
6252 code = CM_ERROR_EXISTS;
6253 cm_ReleaseSCache(tmpscp2);
6256 code = CM_ERROR_NOSUCHFILE;
6259 /* file exist, do not rename, also fixes move */
6260 osi_Log0(smb_logp, "Can't rename. Target already exists");
6261 code = CM_ERROR_EXISTS;
6266 /* do the vnode call */
6267 rock.odscp = oldDscp;
6268 rock.ndscp = newDscp;
6272 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6274 code = CM_ERROR_NOSUCHFILE;
6277 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6278 rock.newNamep = newLastNamep;
6279 rock.fsOldName[0] = '\0';
6280 rock.clOldName[0] = '\0';
6283 /* Now search the directory for the pattern, and do the appropriate rename when found */
6284 thyper.LowPart = 0; /* search dir from here */
6285 thyper.HighPart = 0;
6287 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6288 if (code == 0 && !rock.any) {
6290 thyper.HighPart = 0;
6291 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6292 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6294 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6296 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6297 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6298 rock.ndscp, rock.newNamep, rock.userp,
6300 /* if the call worked, stop doing the search now, since we
6301 * really only want to rename one file.
6304 osi_Log0(smb_logp, "cm_Rename failure");
6305 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6306 } else if (code == 0) {
6307 code = CM_ERROR_NOSUCHFILE;
6310 /* Handle Change Notification */
6312 * Being lazy, not distinguishing between files and dirs in this
6313 * filter, since we'd have to do a lookup.
6316 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6317 if (oldDscp == newDscp) {
6318 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6319 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6320 filter, oldDscp, rock.clOldName,
6321 newLastNamep, TRUE);
6323 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6324 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6325 filter, oldDscp, rock.clOldName,
6327 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6328 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6329 filter, newDscp, newLastNamep,
6336 cm_ReleaseSCache(tmpscp);
6338 cm_ReleaseUser(userp);
6340 cm_ReleaseSCache(oldDscp);
6342 cm_ReleaseSCache(newDscp);
6350 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6353 cm_space_t *spacep = NULL;
6354 cm_scache_t *oldDscp = NULL;
6355 cm_scache_t *newDscp = NULL;
6356 cm_scache_t *tmpscp= NULL;
6357 cm_scache_t *tmpscp2 = NULL;
6358 cm_scache_t *sscp = NULL;
6359 clientchar_t *oldLastNamep;
6360 clientchar_t *newLastNamep;
6363 clientchar_t *tidPathp;
6367 userp = smb_GetUserFromVCP(vcp, inp);
6369 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6371 cm_ReleaseUser(userp);
6372 return CM_ERROR_NOSUCHPATH;
6377 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6379 spacep = inp->spacep;
6380 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6382 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6383 userp, tidPathp, &req, &oldDscp);
6385 cm_ReleaseUser(userp);
6390 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6391 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6392 cm_ReleaseSCache(oldDscp);
6393 cm_ReleaseUser(userp);
6394 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6395 return CM_ERROR_PATH_NOT_COVERED;
6397 return CM_ERROR_NOSUCHPATH;
6399 #endif /* DFS_SUPPORT */
6401 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6402 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6403 userp, tidPathp, &req, &newDscp);
6405 cm_ReleaseSCache(oldDscp);
6406 cm_ReleaseUser(userp);
6411 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6412 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6413 cm_ReleaseSCache(newDscp);
6414 cm_ReleaseSCache(oldDscp);
6415 cm_ReleaseUser(userp);
6416 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6417 return CM_ERROR_PATH_NOT_COVERED;
6419 return CM_ERROR_NOSUCHPATH;
6421 #endif /* DFS_SUPPORT */
6423 /* Now, although we did two lookups for the two directories (because the same
6424 * directory can be referenced through different paths), we only allow hard links
6425 * within the same directory. */
6426 if (oldDscp != newDscp) {
6427 cm_ReleaseSCache(oldDscp);
6428 cm_ReleaseSCache(newDscp);
6429 cm_ReleaseUser(userp);
6430 return CM_ERROR_CROSSDEVLINK;
6433 /* handle the old name first */
6435 oldLastNamep = oldPathp;
6439 /* and handle the new name, too */
6441 newLastNamep = newPathp;
6445 /* now lookup the old name */
6446 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6447 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6449 cm_ReleaseSCache(oldDscp);
6450 cm_ReleaseSCache(newDscp);
6451 cm_ReleaseUser(userp);
6455 /* Check if the file already exists; if so return error */
6456 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6457 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6458 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6460 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6461 osi_LogSaveClientString(smb_logp, newLastNamep));
6463 /* if the existing link is to the same file, then we return success */
6465 if(sscp == tmpscp) {
6468 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6469 code = CM_ERROR_EXISTS;
6474 cm_ReleaseSCache(tmpscp);
6475 cm_ReleaseSCache(sscp);
6476 cm_ReleaseSCache(newDscp);
6477 cm_ReleaseSCache(oldDscp);
6478 cm_ReleaseUser(userp);
6482 /* now create the hardlink */
6483 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6484 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6485 osi_Log1(smb_logp," Link returns 0x%x", code);
6487 /* Handle Change Notification */
6489 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6490 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6491 smb_NotifyChange(FILE_ACTION_ADDED,
6492 filter, newDscp, newLastNamep,
6497 cm_ReleaseSCache(tmpscp);
6498 cm_ReleaseUser(userp);
6499 cm_ReleaseSCache(sscp);
6500 cm_ReleaseSCache(oldDscp);
6501 cm_ReleaseSCache(newDscp);
6505 /* SMB_COM_RENAME */
6507 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6509 clientchar_t *oldPathp;
6510 clientchar_t *newPathp;
6514 tp = smb_GetSMBData(inp, NULL);
6515 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6517 return CM_ERROR_BADSMB;
6518 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6520 return CM_ERROR_BADSMB;
6522 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6523 osi_LogSaveClientString(smb_logp, oldPathp),
6524 osi_LogSaveClientString(smb_logp, newPathp));
6526 if (!cm_IsValidClientString(newPathp)) {
6528 clientchar_t * hexp;
6530 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6531 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6532 osi_LogSaveClientString(smb_logp, hexp));
6536 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6538 return CM_ERROR_BADNTFILENAME;
6541 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6543 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6549 typedef struct smb_rmdirRock {
6553 normchar_t *maskp; /* pointer to the star pattern */
6556 cm_dirEntryList_t * matches;
6559 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6562 smb_rmdirRock_t *rockp;
6564 normchar_t matchName[MAX_PATH];
6566 rockp = (smb_rmdirRock_t *) vrockp;
6568 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6569 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6570 osi_LogSaveString(smb_logp, dep->name));
6574 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6575 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6577 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6579 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6580 !cm_Is8Dot3(matchName)) {
6581 cm_Gen8Dot3Name(dep, matchName, NULL);
6582 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6587 cm_DirEntryListAdd(dep->name, &rockp->matches);
6594 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6597 clientchar_t *pathp;
6601 clientchar_t *lastNamep;
6602 smb_rmdirRock_t rock;
6606 clientchar_t *tidPathp;
6610 memset(&rock, 0, sizeof(rock));
6612 tp = smb_GetSMBData(inp, NULL);
6613 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6615 return CM_ERROR_BADSMB;
6617 spacep = inp->spacep;
6618 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6620 userp = smb_GetUserFromVCP(vcp, inp);
6622 caseFold = CM_FLAG_CASEFOLD;
6624 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6626 cm_ReleaseUser(userp);
6627 return CM_ERROR_NOSUCHPATH;
6629 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6630 userp, tidPathp, &req, &dscp);
6633 cm_ReleaseUser(userp);
6638 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6639 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6640 cm_ReleaseSCache(dscp);
6641 cm_ReleaseUser(userp);
6642 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6643 return CM_ERROR_PATH_NOT_COVERED;
6645 return CM_ERROR_NOSUCHPATH;
6647 #endif /* DFS_SUPPORT */
6649 /* otherwise, scp points to the parent directory. */
6656 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6658 code = CM_ERROR_NOSUCHFILE;
6661 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6664 thyper.HighPart = 0;
6668 rock.matches = NULL;
6670 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6671 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6672 if (code == 0 && !rock.any) {
6674 thyper.HighPart = 0;
6675 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6676 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6679 if (code == 0 && rock.matches) {
6680 cm_dirEntryList_t * entry;
6682 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6683 clientchar_t clientName[MAX_PATH];
6685 /* We assume this will succeed because smb_RmdirProc()
6686 successfully converted entry->name once above. */
6687 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6689 osi_Log1(smb_logp, "Removing directory %s",
6690 osi_LogSaveString(smb_logp, entry->name));
6692 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6694 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6695 smb_NotifyChange(FILE_ACTION_REMOVED,
6696 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6697 dscp, clientName, NULL, TRUE);
6703 cm_DirEntryListFree(&rock.matches);
6706 cm_ReleaseUser(userp);
6709 cm_ReleaseSCache(dscp);
6711 if (code == 0 && !rock.any)
6712 code = CM_ERROR_NOSUCHFILE;
6721 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6731 fid = smb_GetSMBParm(inp, 0);
6733 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6735 fid = smb_ChainFID(fid, inp);
6736 fidp = smb_FindFID(vcp, fid, 0);
6738 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6740 return CM_ERROR_BADFD;
6742 userp = smb_GetUserFromVCP(vcp, inp);
6744 lock_ObtainMutex(&fidp->mx);
6745 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6746 cm_ReleaseUser(userp);
6747 lock_ReleaseMutex(&fidp->mx);
6748 smb_ReleaseFID(fidp);
6749 return CM_ERROR_BADFD;
6752 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6753 lock_ReleaseMutex(&fidp->mx);
6754 cm_ReleaseUser(userp);
6755 smb_CloseFID(vcp, fidp, NULL, 0);
6756 smb_ReleaseFID(fidp);
6757 return CM_ERROR_NOSUCHFILE;
6760 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6761 cm_scache_t * scp = fidp->scp;
6763 lock_ReleaseMutex(&fidp->mx);
6764 code = cm_FSync(scp, userp, &req, FALSE);
6765 cm_ReleaseSCache(scp);
6767 lock_ReleaseMutex(&fidp->mx);
6771 cm_ReleaseUser(userp);
6772 smb_ReleaseFID(fidp);
6776 struct smb_FullNameRock {
6779 clientchar_t *fullName;
6780 fschar_t *originalName;
6783 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6786 normchar_t matchName[MAX_PATH];
6787 struct smb_FullNameRock *vrockp;
6789 vrockp = (struct smb_FullNameRock *)rockp;
6791 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6792 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6793 osi_LogSaveString(smb_logp, dep->name));
6797 if (!cm_Is8Dot3(matchName)) {
6798 clientchar_t shortName[13];
6800 cm_Gen8Dot3Name(dep, shortName, NULL);
6802 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6803 vrockp->fullName = cm_ClientStrDup(matchName);
6804 vrockp->originalName = cm_FsStrDup(dep->name);
6805 return CM_ERROR_STOPNOW;
6808 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6809 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6810 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6811 vrockp->fullName = cm_ClientStrDup(matchName);
6812 vrockp->originalName = cm_FsStrDup(dep->name);
6813 return CM_ERROR_STOPNOW;
6818 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6819 clientchar_t **newPathp, fschar_t ** originalPathp,
6820 cm_user_t *userp, cm_req_t *reqp)
6822 struct smb_FullNameRock rock;
6825 memset(&rock, 0, sizeof(rock));
6829 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6830 if (code == CM_ERROR_STOPNOW) {
6831 *newPathp = rock.fullName;
6832 *originalPathp = rock.originalName;
6834 *newPathp = cm_ClientStrDup(pathp);
6835 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6839 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6840 afs_uint32 dosTime) {
6843 cm_scache_t *dscp = NULL;
6844 clientchar_t *pathp = NULL;
6845 cm_scache_t * scp = NULL;
6846 cm_scache_t *delscp = NULL;
6847 int nullcreator = 0;
6849 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6850 fidp, fidp->fid, scp, vcp);
6853 lock_ObtainMutex(&fidp->mx);
6854 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6856 lock_ReleaseMutex(&fidp->mx);
6857 osi_Log0(smb_logp, " No user specified. Not closing fid");
6858 return CM_ERROR_BADFD;
6861 userp = fidp->userp; /* no hold required since fidp is held
6862 throughout the function */
6863 lock_ReleaseMutex(&fidp->mx);
6868 lock_ObtainWrite(&smb_rctLock);
6869 if (fidp->deleteOk) {
6870 osi_Log0(smb_logp, " Fid already closed.");
6871 lock_ReleaseWrite(&smb_rctLock);
6872 return CM_ERROR_BADFD;
6875 lock_ReleaseWrite(&smb_rctLock);
6877 lock_ObtainMutex(&fidp->mx);
6878 if (fidp->NTopen_dscp) {
6879 dscp = fidp->NTopen_dscp;
6880 cm_HoldSCache(dscp);
6883 if (fidp->NTopen_pathp)
6884 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6891 /* Don't jump the gun on an async raw write */
6892 while (fidp->raw_writers) {
6893 lock_ReleaseMutex(&fidp->mx);
6894 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6895 lock_ObtainMutex(&fidp->mx);
6898 /* watch for ioctl closes, and read-only opens */
6900 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6901 == SMB_FID_OPENWRITE) {
6902 if (dosTime != 0 && dosTime != -1) {
6903 lock_ObtainWrite(&fidp->scp->rw);
6904 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6905 /* This fixes defect 10958 */
6906 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6907 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6908 lock_ReleaseWrite(&fidp->scp->rw);
6910 if (smb_AsyncStore != 2) {
6911 lock_ReleaseMutex(&fidp->mx);
6912 code = cm_FSync(scp, userp, &req, FALSE);
6913 lock_ObtainMutex(&fidp->mx);
6919 /* unlock any pending locks */
6920 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6921 scp->fileType == CM_SCACHETYPE_FILE) {
6925 lock_ReleaseMutex(&fidp->mx);
6927 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6929 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6930 lock_ObtainWrite(&scp->rw);
6932 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6933 CM_SCACHESYNC_NEEDCALLBACK
6934 | CM_SCACHESYNC_GETSTATUS
6935 | CM_SCACHESYNC_LOCK);
6939 "smb CoreClose SyncOp failure code 0x%x", tcode);
6940 goto post_syncopdone;
6943 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6945 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6949 lock_ReleaseWrite(&scp->rw);
6950 lock_ObtainMutex(&fidp->mx);
6953 if (fidp->flags & SMB_FID_DELONCLOSE) {
6954 clientchar_t *fullPathp = NULL;
6955 fschar_t *originalNamep = NULL;
6957 lock_ReleaseMutex(&fidp->mx);
6959 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6964 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6965 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6966 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6968 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6969 smb_NotifyChange(FILE_ACTION_REMOVED,
6970 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6971 dscp, fullPathp, NULL, TRUE);
6974 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6976 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6977 smb_NotifyChange(FILE_ACTION_REMOVED,
6978 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6979 dscp, fullPathp, NULL, TRUE);
6986 free(originalNamep);
6988 lock_ObtainMutex(&fidp->mx);
6989 fidp->flags &= ~SMB_FID_DELONCLOSE;
6992 /* if this was a newly created file, then clear the creator
6993 * in the stat cache entry. */
6994 if (fidp->flags & SMB_FID_CREATED) {
6996 fidp->flags &= ~SMB_FID_CREATED;
6999 if (fidp->flags & SMB_FID_NTOPEN) {
7000 cm_ReleaseSCache(fidp->NTopen_dscp);
7001 fidp->NTopen_dscp = NULL;
7002 free(fidp->NTopen_pathp);
7003 fidp->NTopen_pathp = NULL;
7004 fidp->flags &= ~SMB_FID_NTOPEN;
7006 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
7007 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7010 if (fidp->NTopen_wholepathp) {
7011 free(fidp->NTopen_wholepathp);
7012 fidp->NTopen_wholepathp = NULL;
7016 cm_ReleaseSCache(fidp->scp);
7019 lock_ReleaseMutex(&fidp->mx);
7022 cm_ReleaseSCache(dscp);
7025 cm_ReleaseSCache(delscp);
7029 lock_ObtainWrite(&scp->rw);
7030 if (nullcreator && scp->creator == userp)
7031 scp->creator = NULL;
7032 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7033 lock_ReleaseWrite(&scp->rw);
7034 cm_ReleaseSCache(scp);
7044 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7052 fid = smb_GetSMBParm(inp, 0);
7053 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7055 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7057 fid = smb_ChainFID(fid, inp);
7058 fidp = smb_FindFID(vcp, fid, 0);
7060 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
7062 return CM_ERROR_BADFD;
7065 userp = smb_GetUserFromVCP(vcp, inp);
7067 code = smb_CloseFID(vcp, fidp, userp, dosTime);
7069 smb_ReleaseFID(fidp);
7070 cm_ReleaseUser(userp);
7075 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7077 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7078 cm_user_t *userp, long *readp)
7084 osi_hyper_t fileLength;
7086 osi_hyper_t lastByte;
7087 osi_hyper_t bufferOffset;
7091 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7094 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7095 fidp->fid, offsetp->LowPart, count);
7099 lock_ObtainMutex(&fidp->mx);
7100 /* make sure we have a readable FD */
7101 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7102 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7103 fidp->fid, fidp->flags);
7104 lock_ReleaseMutex(&fidp->mx);
7105 code = CM_ERROR_BADFDOP;
7110 lock_ReleaseMutex(&fidp->mx);
7111 code = CM_ERROR_BADFD;
7122 lock_ObtainWrite(&scp->rw);
7124 if (offset.HighPart == 0) {
7125 chunk = offset.LowPart >> cm_logChunkSize;
7126 if (chunk != fidp->curr_chunk) {
7127 fidp->prev_chunk = fidp->curr_chunk;
7128 fidp->curr_chunk = chunk;
7130 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7133 lock_ReleaseMutex(&fidp->mx);
7135 /* start by looking up the file's end */
7136 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7137 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7141 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7143 /* now we have the entry locked, look up the length */
7144 fileLength = scp->length;
7146 /* adjust count down so that it won't go past EOF */
7147 thyper.LowPart = count;
7148 thyper.HighPart = 0;
7149 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7151 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7152 /* we'd read past EOF, so just stop at fileLength bytes.
7153 * Start by computing how many bytes remain in the file.
7155 thyper = LargeIntegerSubtract(fileLength, offset);
7157 /* if we are past EOF, read 0 bytes */
7158 if (LargeIntegerLessThanZero(thyper))
7161 count = thyper.LowPart;
7166 /* now, copy the data one buffer at a time,
7167 * until we've filled the request packet
7170 /* if we've copied all the data requested, we're done */
7171 if (count <= 0) break;
7173 /* otherwise, load up a buffer of data */
7174 thyper.HighPart = offset.HighPart;
7175 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7176 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7179 buf_Release(bufferp);
7182 lock_ReleaseWrite(&scp->rw);
7184 code = buf_Get(scp, &thyper, &req, &bufferp);
7186 lock_ObtainWrite(&scp->rw);
7187 if (code) goto done;
7188 bufferOffset = thyper;
7190 /* now get the data in the cache */
7192 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7193 CM_SCACHESYNC_NEEDCALLBACK |
7194 CM_SCACHESYNC_READ);
7198 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7200 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7202 /* otherwise, load the buffer and try again */
7203 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7207 buf_Release(bufferp);
7211 } /* if (wrong buffer) ... */
7213 /* now we have the right buffer loaded. Copy out the
7214 * data from here to the user's buffer.
7216 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7218 /* and figure out how many bytes we want from this buffer */
7219 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7220 if (nbytes > count) nbytes = count; /* don't go past EOF */
7222 /* now copy the data */
7223 memcpy(op, bufferp->datap + bufIndex, nbytes);
7225 /* adjust counters, pointers, etc. */
7228 thyper.LowPart = nbytes;
7229 thyper.HighPart = 0;
7230 offset = LargeIntegerAdd(thyper, offset);
7234 lock_ReleaseWrite(&scp->rw);
7236 buf_Release(bufferp);
7238 if (code == 0 && sequential)
7239 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7241 cm_ReleaseSCache(scp);
7244 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7245 fidp->fid, code, *readp);
7250 * smb_WriteData -- common code for Write and Raw Write
7252 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7253 cm_user_t *userp, long *writtenp)
7255 osi_hyper_t offset = *offsetp;
7258 cm_scache_t *scp = NULL;
7259 osi_hyper_t fileLength; /* file's length at start of write */
7260 osi_hyper_t minLength; /* don't read past this */
7261 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7262 cm_buf_t *bufferp = NULL;
7263 osi_hyper_t thyper; /* hyper tmp variable */
7264 osi_hyper_t bufferOffset;
7265 afs_uint32 bufIndex; /* index in buffer where our data is */
7266 int doWriteBack = 0;
7267 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7270 int needSyncOpDone = 0;
7272 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7273 fidp->fid, offsetp->LowPart, count);
7277 lock_ObtainMutex(&fidp->mx);
7278 /* make sure we have a writable FD */
7279 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7280 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7281 fidp->fid, fidp->flags);
7282 lock_ReleaseMutex(&fidp->mx);
7283 code = CM_ERROR_BADFDOP;
7291 lock_ReleaseMutex(&fidp->mx);
7293 lock_ObtainWrite(&scp->rw);
7294 /* start by looking up the file's end */
7295 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7296 CM_SCACHESYNC_NEEDCALLBACK
7297 | CM_SCACHESYNC_SETSTATUS
7298 | CM_SCACHESYNC_GETSTATUS);
7302 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7304 /* now we have the entry locked, look up the length */
7305 fileLength = scp->length;
7306 minLength = fileLength;
7307 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7308 minLength = scp->serverLength;
7310 /* adjust file length if we extend past EOF */
7311 thyper.LowPart = count;
7312 thyper.HighPart = 0;
7313 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7314 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7315 /* we'd write past EOF, so extend the file */
7316 scp->mask |= CM_SCACHEMASK_LENGTH;
7317 scp->length = thyper;
7318 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7320 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7322 /* now, if the new position (thyper) and the old (offset) are in
7323 * different storeback windows, remember to store back the previous
7324 * storeback window when we're done with the write.
7326 * the purpose of this logic is to slow down the CIFS client
7327 * in order to avoid the client disconnecting during the CLOSE
7328 * operation if there are too many dirty buffers left to write
7329 * than can be accomplished during 45 seconds. This used to be
7330 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7331 * so that we can read larger amounts of data at a time.
7333 if (smb_AsyncStore == 1 &&
7334 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7335 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7336 /* they're different */
7338 writeBackOffset.HighPart = offset.HighPart;
7339 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7344 /* now, copy the data one buffer at a time, until we've filled the
7346 while (count != 0) {
7348 /* handle over quota or out of space */
7349 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7350 *writtenp = written;
7351 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7355 /* otherwise, load up a buffer of data */
7356 thyper.HighPart = offset.HighPart;
7357 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7358 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7361 if (needSyncOpDone) {
7362 cm_SyncOpDone(scp, bufferp,
7363 CM_SCACHESYNC_NEEDCALLBACK
7364 | CM_SCACHESYNC_WRITE
7365 | CM_SCACHESYNC_BUFLOCKED);
7368 lock_ReleaseMutex(&bufferp->mx);
7369 buf_Release(bufferp);
7372 lock_ReleaseWrite(&scp->rw);
7374 code = buf_Get(scp, &thyper, &req, &bufferp);
7376 lock_ObtainMutex(&bufferp->mx);
7377 lock_ObtainWrite(&scp->rw);
7378 if (code) goto done;
7380 bufferOffset = thyper;
7382 /* now get the data in the cache */
7384 if (!needSyncOpDone) {
7385 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7386 CM_SCACHESYNC_NEEDCALLBACK
7387 | CM_SCACHESYNC_WRITE
7388 | CM_SCACHESYNC_BUFLOCKED);
7395 /* If we're overwriting the entire buffer, or
7396 * if we're writing at or past EOF, mark the
7397 * buffer as current so we don't call
7398 * cm_GetBuffer. This skips the fetch from the
7399 * server in those cases where we're going to
7400 * obliterate all the data in the buffer anyway,
7401 * or in those cases where there is no useful
7402 * data at the server to start with.
7404 * Use minLength instead of scp->length, since
7405 * the latter has already been updated by this
7408 * The scp lock has been dropped multiple times
7409 * so the minLength must be refreshed before it
7413 minLength = scp->length;
7414 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7415 minLength = scp->serverLength;
7417 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7418 || LargeIntegerEqualTo(offset, bufferp->offset)
7419 && (count >= cm_data.buf_blockSize
7420 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7421 ConvertLongToLargeInteger(count)),
7423 if (count < cm_data.buf_blockSize
7424 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7425 memset(bufferp->datap, 0,
7426 cm_data.buf_blockSize);
7427 bufferp->dataVersion = scp->dataVersion;
7430 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7432 /* otherwise, load the buffer and try again */
7433 cm_SyncOpDone(scp, bufferp,
7434 CM_SCACHESYNC_NEEDCALLBACK
7435 | CM_SCACHESYNC_WRITE
7436 | CM_SCACHESYNC_BUFLOCKED);
7439 lock_ReleaseMutex(&bufferp->mx);
7440 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7442 lock_ReleaseWrite(&scp->rw);
7443 lock_ObtainMutex(&bufferp->mx);
7444 lock_ObtainWrite(&scp->rw);
7448 } /* if (wrong buffer) ... */
7450 /* now we have the right buffer loaded. Copy out the
7451 * data from here to the user's buffer.
7453 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7455 /* and figure out how many bytes we want from this buffer */
7456 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7458 nbytes = count; /* don't go past end of request */
7460 /* now copy the data */
7461 memcpy(bufferp->datap + bufIndex, op, nbytes);
7462 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7464 /* adjust counters, pointers, etc. */
7468 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7469 } /* while count != 0 */
7472 if (bufferp && needSyncOpDone) {
7473 cm_SyncOpDone(scp, bufferp,
7474 CM_SCACHESYNC_NEEDCALLBACK
7475 | CM_SCACHESYNC_WRITE
7476 | CM_SCACHESYNC_BUFLOCKED);
7479 lock_ReleaseWrite(&scp->rw);
7482 lock_ReleaseMutex(&bufferp->mx);
7483 buf_Release(bufferp);
7486 lock_ObtainMutex(&fidp->mx);
7487 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7488 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7490 lock_ReleaseMutex(&fidp->mx);
7491 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7492 fidp->NTopen_dscp, fidp->NTopen_pathp,
7495 lock_ReleaseMutex(&fidp->mx);
7499 if (smb_AsyncStore > 0) {
7503 lock_ObtainWrite(&scp->rw);
7504 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7506 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7507 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7509 lock_ReleaseWrite(&scp->rw);
7510 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7511 writeBackOffset.HighPart,
7512 smb_AsyncStoreSize, 0, userp);
7513 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7516 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7520 cm_ReleaseSCache(scp);
7523 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7524 fidp->fid, code, *writtenp);
7529 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7532 unsigned short count;
7534 unsigned short hint;
7535 long written = 0, total_written = 0;
7538 smb_t* smbp = (smb_t*) inp;
7542 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7544 int inDataBlockCount;
7546 fd = smb_GetSMBParm(inp, 0);
7547 count = smb_GetSMBParm(inp, 1);
7548 offset.HighPart = 0; /* too bad */
7549 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7550 hint = smb_GetSMBParm(inp, 4);
7552 op = smb_GetSMBData(inp, NULL);
7553 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7555 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7556 fd, offset.LowPart, count);
7558 fd = smb_ChainFID(fd, inp);
7559 fidp = smb_FindFID(vcp, fd, 0);
7561 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7563 return CM_ERROR_BADFD;
7566 lock_ObtainMutex(&fidp->mx);
7567 if (fidp->flags & SMB_FID_IOCTL) {
7568 lock_ReleaseMutex(&fidp->mx);
7569 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7570 smb_ReleaseFID(fidp);
7571 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7575 if (fidp->flags & SMB_FID_RPC) {
7576 lock_ReleaseMutex(&fidp->mx);
7577 code = smb_RPCWrite(fidp, vcp, inp, outp);
7578 smb_ReleaseFID(fidp);
7579 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7584 lock_ReleaseMutex(&fidp->mx);
7585 smb_ReleaseFID(fidp);
7586 return CM_ERROR_BADFD;
7589 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7590 lock_ReleaseMutex(&fidp->mx);
7591 smb_CloseFID(vcp, fidp, NULL, 0);
7592 smb_ReleaseFID(fidp);
7593 return CM_ERROR_NOSUCHFILE;
7598 lock_ReleaseMutex(&fidp->mx);
7599 userp = smb_GetUserFromVCP(vcp, inp);
7603 LARGE_INTEGER LOffset;
7604 LARGE_INTEGER LLength;
7607 key = cm_GenerateKey(vcp->vcID, pid, fd);
7609 LOffset.HighPart = offset.HighPart;
7610 LOffset.LowPart = offset.LowPart;
7611 LLength.HighPart = 0;
7612 LLength.LowPart = count;
7614 lock_ObtainWrite(&scp->rw);
7615 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7616 lock_ReleaseWrite(&scp->rw);
7619 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7624 /* special case: 0 bytes transferred means truncate to this position */
7628 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7632 truncAttr.mask = CM_ATTRMASK_LENGTH;
7633 truncAttr.length.LowPart = offset.LowPart;
7634 truncAttr.length.HighPart = 0;
7635 lock_ObtainMutex(&fidp->mx);
7636 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7637 fidp->flags |= SMB_FID_LENGTHSETDONE;
7638 lock_ReleaseMutex(&fidp->mx);
7639 smb_SetSMBParm(outp, 0, 0 /* count */);
7640 smb_SetSMBDataLength(outp, 0);
7645 * Work around bug in NT client
7647 * When copying a file, the NT client should first copy the data,
7648 * then copy the last write time. But sometimes the NT client does
7649 * these in the wrong order, so the data copies would inadvertently
7650 * cause the last write time to be overwritten. We try to detect this,
7651 * and don't set client mod time if we think that would go against the
7654 lock_ObtainMutex(&fidp->mx);
7655 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7656 lock_ObtainWrite(&fidp->scp->rw);
7657 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7658 fidp->scp->clientModTime = time(NULL);
7659 lock_ReleaseWrite(&fidp->scp->rw);
7661 lock_ReleaseMutex(&fidp->mx);
7664 while ( code == 0 && count > 0 ) {
7665 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7666 if (code == 0 && written == 0)
7667 code = CM_ERROR_PARTIALWRITE;
7669 offset = LargeIntegerAdd(offset,
7670 ConvertLongToLargeInteger(written));
7671 count -= (unsigned short)written;
7672 total_written += written;
7676 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7677 total_written, code);
7679 /* set the packet data length to 3 bytes for the data block header,
7680 * plus the size of the data.
7682 smb_SetSMBParm(outp, 0, total_written);
7683 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7684 smb_SetSMBParm(outp, 3, hint);
7685 smb_SetSMBDataLength(outp, 0);
7688 smb_ReleaseFID(fidp);
7689 cm_ReleaseUser(userp);
7690 cm_ReleaseSCache(scp);
7695 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7696 NCB *ncbp, raw_write_cont_t *rwcp)
7705 fd = smb_GetSMBParm(inp, 0);
7706 fidp = smb_FindFID(vcp, fd, 0);
7708 lock_ObtainMutex(&fidp->mx);
7710 lock_ReleaseMutex(&fidp->mx);
7711 smb_ReleaseFID(fidp);
7715 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7716 lock_ReleaseMutex(&fidp->mx);
7717 smb_CloseFID(vcp, fidp, NULL, 0);
7718 smb_ReleaseFID(fidp);
7721 lock_ReleaseMutex(&fidp->mx);
7723 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7724 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7726 userp = smb_GetUserFromVCP(vcp, inp);
7729 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7731 if (rwcp->writeMode & 0x1) { /* synchronous */
7734 smb_FormatResponsePacket(vcp, inp, outp);
7735 op = (smb_t *) outp;
7736 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7737 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7738 smb_SetSMBDataLength(outp, 0);
7739 smb_SendPacket(vcp, outp);
7740 smb_FreePacket(outp);
7742 else { /* asynchronous */
7743 lock_ObtainMutex(&fidp->mx);
7744 fidp->raw_writers--;
7745 if (fidp->raw_writers == 0)
7746 thrd_SetEvent(fidp->raw_write_event);
7747 lock_ReleaseMutex(&fidp->mx);
7750 /* Give back raw buffer */
7751 lock_ObtainMutex(&smb_RawBufLock);
7752 *((char **)rawBuf) = smb_RawBufs;
7753 smb_RawBufs = rawBuf;
7754 lock_ReleaseMutex(&smb_RawBufLock);
7756 smb_ReleaseFID(fidp);
7757 cm_ReleaseUser(userp);
7760 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7765 /* SMB_COM_WRITE_RAW */
7766 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7769 long count, written = 0, total_written = 0;
7773 smb_t *smbp = (smb_t*) inp;
7778 unsigned short writeMode;
7780 fd = smb_GetSMBParm(inp, 0);
7781 totalCount = smb_GetSMBParm(inp, 1);
7782 count = smb_GetSMBParm(inp, 10);
7783 writeMode = smb_GetSMBParm(inp, 7);
7785 op = (char *) inp->data;
7786 op += smb_GetSMBParm(inp, 11);
7788 offset.HighPart = 0;
7789 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7791 if (*inp->wctp == 14) {
7792 /* we received a 64-bit file offset */
7793 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7795 if (LargeIntegerLessThanZero(offset)) {
7797 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7798 offset.HighPart, offset.LowPart);
7799 return CM_ERROR_BADSMB;
7802 offset.HighPart = 0; /* 32-bit file offset */
7806 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7807 fd, offset.HighPart, offset.LowPart, count);
7809 " WriteRaw WriteMode 0x%x",
7812 fd = smb_ChainFID(fd, inp);
7813 fidp = smb_FindFID(vcp, fd, 0);
7815 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7817 return CM_ERROR_BADFD;
7819 lock_ObtainMutex(&fidp->mx);
7821 lock_ReleaseMutex(&fidp->mx);
7822 smb_ReleaseFID(fidp);
7823 return CM_ERROR_BADFD;
7826 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7827 lock_ReleaseMutex(&fidp->mx);
7828 smb_CloseFID(vcp, fidp, NULL, 0);
7829 smb_ReleaseFID(fidp);
7830 return CM_ERROR_NOSUCHFILE;
7835 lock_ReleaseMutex(&fidp->mx);
7840 LARGE_INTEGER LOffset;
7841 LARGE_INTEGER LLength;
7844 key = cm_GenerateKey(vcp->vcID, pid, fd);
7846 LOffset.HighPart = offset.HighPart;
7847 LOffset.LowPart = offset.LowPart;
7848 LLength.HighPart = 0;
7849 LLength.LowPart = count;
7851 lock_ObtainWrite(&scp->rw);
7852 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7853 lock_ReleaseWrite(&scp->rw);
7856 cm_ReleaseSCache(scp);
7857 smb_ReleaseFID(fidp);
7862 userp = smb_GetUserFromVCP(vcp, inp);
7865 * Work around bug in NT client
7867 * When copying a file, the NT client should first copy the data,
7868 * then copy the last write time. But sometimes the NT client does
7869 * these in the wrong order, so the data copies would inadvertently
7870 * cause the last write time to be overwritten. We try to detect this,
7871 * and don't set client mod time if we think that would go against the
7874 lock_ObtainMutex(&fidp->mx);
7875 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7876 lock_ObtainWrite(&fidp->scp->rw);
7877 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7878 fidp->scp->clientModTime = time(NULL);
7879 lock_ReleaseWrite(&fidp->scp->rw);
7881 lock_ReleaseMutex(&fidp->mx);
7884 while ( code == 0 && count > 0 ) {
7885 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7886 if (code == 0 && written == 0)
7887 code = CM_ERROR_PARTIALWRITE;
7889 offset = LargeIntegerAdd(offset,
7890 ConvertLongToLargeInteger(written));
7893 total_written += written;
7897 /* Get a raw buffer */
7900 lock_ObtainMutex(&smb_RawBufLock);
7902 /* Get a raw buf, from head of list */
7903 rawBuf = smb_RawBufs;
7904 smb_RawBufs = *(char **)smb_RawBufs;
7907 code = CM_ERROR_USESTD;
7909 lock_ReleaseMutex(&smb_RawBufLock);
7912 /* Don't allow a premature Close */
7913 if (code == 0 && (writeMode & 1) == 0) {
7914 lock_ObtainMutex(&fidp->mx);
7915 fidp->raw_writers++;
7916 thrd_ResetEvent(fidp->raw_write_event);
7917 lock_ReleaseMutex(&fidp->mx);
7920 smb_ReleaseFID(fidp);
7921 cm_ReleaseUser(userp);
7922 cm_ReleaseSCache(scp);
7925 smb_SetSMBParm(outp, 0, total_written);
7926 smb_SetSMBDataLength(outp, 0);
7927 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7932 offset = LargeIntegerAdd(offset,
7933 ConvertLongToLargeInteger(count));
7937 rwcp->offset.HighPart = offset.HighPart;
7938 rwcp->offset.LowPart = offset.LowPart;
7939 rwcp->count = totalCount - count;
7940 rwcp->writeMode = writeMode;
7941 rwcp->alreadyWritten = total_written;
7943 /* set the packet data length to 3 bytes for the data block header,
7944 * plus the size of the data.
7946 smb_SetSMBParm(outp, 0, 0xffff);
7947 smb_SetSMBDataLength(outp, 0);
7953 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7956 long count, finalCount;
7960 smb_t *smbp = (smb_t*) inp;
7966 fd = smb_GetSMBParm(inp, 0);
7967 count = smb_GetSMBParm(inp, 1);
7968 offset.HighPart = 0; /* too bad */
7969 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7971 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7972 fd, offset.LowPart, count);
7974 fd = smb_ChainFID(fd, inp);
7975 fidp = smb_FindFID(vcp, fd, 0);
7977 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7979 return CM_ERROR_BADFD;
7981 lock_ObtainMutex(&fidp->mx);
7982 if (fidp->flags & SMB_FID_IOCTL) {
7983 lock_ReleaseMutex(&fidp->mx);
7984 code = smb_IoctlRead(fidp, vcp, inp, outp);
7985 smb_ReleaseFID(fidp);
7989 if (fidp->flags & SMB_FID_RPC) {
7990 lock_ReleaseMutex(&fidp->mx);
7991 code = smb_RPCRead(fidp, vcp, inp, outp);
7992 smb_ReleaseFID(fidp);
7997 lock_ReleaseMutex(&fidp->mx);
7998 smb_ReleaseFID(fidp);
7999 return CM_ERROR_BADFD;
8002 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8003 lock_ReleaseMutex(&fidp->mx);
8004 smb_CloseFID(vcp, fidp, NULL, 0);
8005 smb_ReleaseFID(fidp);
8006 return CM_ERROR_NOSUCHFILE;
8011 lock_ReleaseMutex(&fidp->mx);
8014 LARGE_INTEGER LOffset, LLength;
8018 key = cm_GenerateKey(vcp->vcID, pid, fd);
8020 LOffset.HighPart = 0;
8021 LOffset.LowPart = offset.LowPart;
8022 LLength.HighPart = 0;
8023 LLength.LowPart = count;
8025 lock_ObtainWrite(&scp->rw);
8026 code = cm_LockCheckRead(scp, LOffset, LLength, key);
8027 lock_ReleaseWrite(&scp->rw);
8030 cm_ReleaseSCache(scp);
8031 smb_ReleaseFID(fidp);
8035 userp = smb_GetUserFromVCP(vcp, inp);
8037 /* remember this for final results */
8038 smb_SetSMBParm(outp, 0, count);
8039 smb_SetSMBParm(outp, 1, 0);
8040 smb_SetSMBParm(outp, 2, 0);
8041 smb_SetSMBParm(outp, 3, 0);
8042 smb_SetSMBParm(outp, 4, 0);
8044 /* set the packet data length to 3 bytes for the data block header,
8045 * plus the size of the data.
8047 smb_SetSMBDataLength(outp, count+3);
8049 /* get op ptr after putting in the parms, since otherwise we don't
8050 * know where the data really is.
8052 op = smb_GetSMBData(outp, NULL);
8054 /* now emit the data block header: 1 byte of type and 2 bytes of length */
8055 *op++ = 1; /* data block marker */
8056 *op++ = (unsigned char) (count & 0xff);
8057 *op++ = (unsigned char) ((count >> 8) & 0xff);
8059 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8061 /* fix some things up */
8062 smb_SetSMBParm(outp, 0, finalCount);
8063 smb_SetSMBDataLength(outp, finalCount+3);
8065 smb_ReleaseFID(fidp);
8067 cm_ReleaseUser(userp);
8068 cm_ReleaseSCache(scp);
8072 /* SMB_COM_CREATE_DIRECTORY */
8073 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8075 clientchar_t *pathp;
8080 cm_scache_t *dscp; /* dir we're dealing with */
8081 cm_scache_t *scp; /* file we're creating */
8083 int initialModeBits;
8084 clientchar_t *lastNamep;
8086 clientchar_t *tidPathp;
8093 /* compute initial mode bits based on read-only flag in attributes */
8094 initialModeBits = 0777;
8096 tp = smb_GetSMBData(inp, NULL);
8097 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8099 return CM_ERROR_BADSMB;
8101 spacep = inp->spacep;
8102 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8104 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8105 return CM_ERROR_EXISTS;
8107 userp = smb_GetUserFromVCP(vcp, inp);
8109 caseFold = CM_FLAG_CASEFOLD;
8111 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8113 cm_ReleaseUser(userp);
8114 return CM_ERROR_NOSUCHPATH;
8117 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
8118 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8119 userp, tidPathp, &req, &dscp);
8122 cm_ReleaseUser(userp);
8127 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8128 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8129 cm_ReleaseSCache(dscp);
8130 cm_ReleaseUser(userp);
8131 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8132 return CM_ERROR_PATH_NOT_COVERED;
8134 return CM_ERROR_NOSUCHPATH;
8136 #endif /* DFS_SUPPORT */
8138 /* otherwise, scp points to the parent directory. Do a lookup, and
8139 * fail if we find it. Otherwise, we do the create.
8145 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8146 if (scp) cm_ReleaseSCache(scp);
8147 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8148 if (code == 0) code = CM_ERROR_EXISTS;
8149 cm_ReleaseSCache(dscp);
8150 cm_ReleaseUser(userp);
8154 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8155 setAttr.clientModTime = time(NULL);
8156 smb_SetInitialModeBitsForDir(0, &setAttr);
8158 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8159 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8160 smb_NotifyChange(FILE_ACTION_ADDED,
8161 FILE_NOTIFY_CHANGE_DIR_NAME,
8162 dscp, lastNamep, NULL, TRUE);
8164 /* we don't need this any longer */
8165 cm_ReleaseSCache(dscp);
8168 /* something went wrong creating or truncating the file */
8169 cm_ReleaseUser(userp);
8173 /* otherwise we succeeded */
8174 smb_SetSMBDataLength(outp, 0);
8175 cm_ReleaseUser(userp);
8180 BOOL smb_IsLegalFilename(clientchar_t *filename)
8183 * Find the longest substring of filename that does not contain
8184 * any of the chars in illegalChars. If that substring is less
8185 * than the length of the whole string, then one or more of the
8186 * illegal chars is in filename.
8188 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8194 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8195 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8197 clientchar_t *pathp;
8203 cm_scache_t *dscp; /* dir we're dealing with */
8204 cm_scache_t *scp; /* file we're creating */
8208 clientchar_t *lastNamep;
8211 clientchar_t *tidPathp;
8213 int created = 0; /* the file was new */
8218 excl = (inp->inCom == 0x03)? 0 : 1;
8220 attributes = smb_GetSMBParm(inp, 0);
8221 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8223 tp = smb_GetSMBData(inp, NULL);
8224 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8226 return CM_ERROR_BADSMB;
8228 spacep = inp->spacep;
8229 /* smb_StripLastComponent will strip "::$DATA" if present */
8230 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8232 if (!cm_IsValidClientString(pathp)) {
8234 clientchar_t * hexp;
8236 hexp = cm_GetRawCharsAlloc(pathp, -1);
8237 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8238 osi_LogSaveClientString(smb_logp, hexp));
8242 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8244 return CM_ERROR_BADNTFILENAME;
8247 userp = smb_GetUserFromVCP(vcp, inp);
8249 caseFold = CM_FLAG_CASEFOLD;
8251 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8253 cm_ReleaseUser(userp);
8254 return CM_ERROR_NOSUCHPATH;
8256 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8257 userp, tidPathp, &req, &dscp);
8260 cm_ReleaseUser(userp);
8265 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8266 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8267 cm_ReleaseSCache(dscp);
8268 cm_ReleaseUser(userp);
8269 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8270 return CM_ERROR_PATH_NOT_COVERED;
8272 return CM_ERROR_NOSUCHPATH;
8274 #endif /* DFS_SUPPORT */
8276 /* otherwise, scp points to the parent directory. Do a lookup, and
8277 * truncate the file if we find it, otherwise we create the file.
8284 if (!smb_IsLegalFilename(lastNamep))
8285 return CM_ERROR_BADNTFILENAME;
8287 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8288 #ifdef DEBUG_VERBOSE
8291 hexp = osi_HexifyString( lastNamep );
8292 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8297 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8298 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8299 cm_ReleaseSCache(dscp);
8300 cm_ReleaseUser(userp);
8304 /* if we get here, if code is 0, the file exists and is represented by
8305 * scp. Otherwise, we have to create it.
8309 /* oops, file shouldn't be there */
8310 cm_ReleaseSCache(dscp);
8311 cm_ReleaseSCache(scp);
8312 cm_ReleaseUser(userp);
8313 return CM_ERROR_EXISTS;
8316 setAttr.mask = CM_ATTRMASK_LENGTH;
8317 setAttr.length.LowPart = 0;
8318 setAttr.length.HighPart = 0;
8319 code = cm_SetAttr(scp, &setAttr, userp, &req);
8322 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8323 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8324 smb_SetInitialModeBitsForFile(attributes, &setAttr);
8326 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8330 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8331 smb_NotifyChange(FILE_ACTION_ADDED,
8332 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8333 dscp, lastNamep, NULL, TRUE);
8334 } else if (!excl && code == CM_ERROR_EXISTS) {
8335 /* not an exclusive create, and someone else tried
8336 * creating it already, then we open it anyway. We
8337 * don't bother retrying after this, since if this next
8338 * fails, that means that the file was deleted after
8339 * we started this call.
8341 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8344 setAttr.mask = CM_ATTRMASK_LENGTH;
8345 setAttr.length.LowPart = 0;
8346 setAttr.length.HighPart = 0;
8347 code = cm_SetAttr(scp, &setAttr, userp, &req);
8352 /* we don't need this any longer */
8353 cm_ReleaseSCache(dscp);
8356 /* something went wrong creating or truncating the file */
8357 if (scp) cm_ReleaseSCache(scp);
8358 cm_ReleaseUser(userp);
8362 /* make sure we only open files */
8363 if (scp->fileType != CM_SCACHETYPE_FILE) {
8364 cm_ReleaseSCache(scp);
8365 cm_ReleaseUser(userp);
8366 return CM_ERROR_ISDIR;
8369 /* now all we have to do is open the file itself */
8370 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8371 osi_assertx(fidp, "null smb_fid_t");
8375 lock_ObtainMutex(&fidp->mx);
8376 /* always create it open for read/write */
8377 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8379 /* remember that the file was newly created */
8381 fidp->flags |= SMB_FID_CREATED;
8383 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8385 /* save a pointer to the vnode */
8387 lock_ObtainWrite(&scp->rw);
8388 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8389 lock_ReleaseWrite(&scp->rw);
8392 fidp->userp = userp;
8393 lock_ReleaseMutex(&fidp->mx);
8395 smb_SetSMBParm(outp, 0, fidp->fid);
8396 smb_SetSMBDataLength(outp, 0);
8398 cm_Open(scp, 0, userp);
8400 smb_ReleaseFID(fidp);
8401 cm_ReleaseUser(userp);
8402 /* leave scp held since we put it in fidp->scp */
8407 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8410 osi_hyper_t new_offset;
8421 fd = smb_GetSMBParm(inp, 0);
8422 whence = smb_GetSMBParm(inp, 1);
8423 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8425 /* try to find the file descriptor */
8426 fd = smb_ChainFID(fd, inp);
8427 fidp = smb_FindFID(vcp, fd, 0);
8429 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8431 return CM_ERROR_BADFD;
8433 lock_ObtainMutex(&fidp->mx);
8434 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8435 lock_ReleaseMutex(&fidp->mx);
8436 smb_ReleaseFID(fidp);
8437 return CM_ERROR_BADFD;
8440 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8441 lock_ReleaseMutex(&fidp->mx);
8442 smb_CloseFID(vcp, fidp, NULL, 0);
8443 smb_ReleaseFID(fidp);
8444 return CM_ERROR_NOSUCHFILE;
8447 lock_ReleaseMutex(&fidp->mx);
8449 userp = smb_GetUserFromVCP(vcp, inp);
8451 lock_ObtainMutex(&fidp->mx);
8454 lock_ReleaseMutex(&fidp->mx);
8455 lock_ObtainWrite(&scp->rw);
8456 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8457 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8459 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8461 /* offset from current offset */
8462 new_offset = LargeIntegerAdd(fidp->offset,
8463 ConvertLongToLargeInteger(offset));
8465 else if (whence == 2) {
8466 /* offset from current EOF */
8467 new_offset = LargeIntegerAdd(scp->length,
8468 ConvertLongToLargeInteger(offset));
8470 new_offset = ConvertLongToLargeInteger(offset);
8473 fidp->offset = new_offset;
8474 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8475 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8476 smb_SetSMBDataLength(outp, 0);
8478 lock_ReleaseWrite(&scp->rw);
8479 smb_ReleaseFID(fidp);
8480 cm_ReleaseSCache(scp);
8481 cm_ReleaseUser(userp);
8485 /* dispatch all of the requests received in a packet. Due to chaining, this may
8486 * be more than one request.
8488 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8489 NCB *ncbp, raw_write_cont_t *rwcp)
8493 unsigned long code = 0;
8494 unsigned char *outWctp;
8495 int nparms; /* # of bytes of parameters */
8497 int nbytes; /* bytes of data, excluding count */
8500 unsigned short errCode;
8501 unsigned long NTStatus;
8503 unsigned char errClass;
8504 unsigned int oldGen;
8505 DWORD oldTime, newTime;
8507 /* get easy pointer to the data */
8508 smbp = (smb_t *) inp->data;
8510 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8511 /* setup the basic parms for the initial request in the packet */
8512 inp->inCom = smbp->com;
8513 inp->wctp = &smbp->wct;
8515 inp->ncb_length = ncbp->ncb_length;
8520 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8521 /* log it and discard it */
8522 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8523 __FILE__, __LINE__, ncbp->ncb_length);
8524 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8528 /* We are an ongoing op */
8529 thrd_Increment(&ongoingOps);
8531 /* set up response packet for receiving output */
8532 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8533 smb_FormatResponsePacket(vcp, inp, outp);
8534 outWctp = outp->wctp;
8536 /* Remember session generation number and time */
8537 oldGen = sessionGen;
8538 oldTime = GetTickCount();
8540 while (inp->inCom != 0xff) {
8541 dp = &smb_dispatchTable[inp->inCom];
8543 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8544 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8545 code = outp->resumeCode;
8549 /* process each request in the packet; inCom, wctp and inCount
8550 * are already set up.
8552 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8555 /* now do the dispatch */
8556 /* start by formatting the response record a little, as a default */
8557 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8559 outWctp[1] = 0xff; /* no operation */
8560 outWctp[2] = 0; /* padding */
8565 /* not a chained request, this is a more reasonable default */
8566 outWctp[0] = 0; /* wct of zero */
8567 outWctp[1] = 0; /* and bcc (word) of zero */
8571 /* once set, stays set. Doesn't matter, since we never chain
8572 * "no response" calls.
8574 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8578 /* we have a recognized operation */
8579 char * opName = myCrt_Dispatch(inp->inCom);
8582 smbp = (smb_t *) inp;
8584 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8585 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8586 if (inp->inCom == 0x1d) {
8588 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8590 code = (*(dp->procp)) (vcp, inp, outp);
8592 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8593 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8595 newTime = GetTickCount();
8596 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8597 opName, smbp->mid, newTime - oldTime);
8600 if ( code == CM_ERROR_BADSMB ||
8601 code == CM_ERROR_BADOP )
8603 #endif /* LOG_PACKET */
8605 /* ReceiveV3Tran2A handles its own logging */
8606 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8609 clientchar_t *treepath = NULL; /* do not free */
8610 clientchar_t *pathname = NULL;
8611 cm_fid_t afid = {0,0,0,0,0};
8613 uidp = smb_FindUID(vcp, smbp->uid, 0);
8614 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8615 fidp = smb_FindFID(vcp, inp->fid, 0);
8618 lock_ObtainMutex(&fidp->mx);
8619 if (fidp->NTopen_pathp)
8620 pathname = fidp->NTopen_pathp;
8622 afid = fidp->scp->fid;
8624 if (inp->stringsp->wdata)
8625 pathname = inp->stringsp->wdata;
8628 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)",
8629 opName, newTime - oldTime,
8630 smbp->uid, uidp ? uidp->unp->name : NULL,
8631 smbp->pid, smbp->mid, smbp->tid,
8634 afid.cell, afid.volume, afid.vnode, afid.unique);
8637 lock_ReleaseMutex(&fidp->mx);
8640 smb_ReleaseUID(uidp);
8642 smb_ReleaseFID(fidp);
8645 if (oldGen != sessionGen) {
8646 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8647 newTime - oldTime, ncbp->ncb_length);
8648 osi_Log3(smb_logp, "Request %s straddled session startup, "
8649 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8652 FreeSMBStrings(inp);
8654 /* bad opcode, fail the request, after displaying it */
8655 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8658 #endif /* LOG_PACKET */
8661 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8662 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8663 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8664 if (code == IDCANCEL)
8667 code = CM_ERROR_BADOP;
8670 /* catastrophic failure: log as much as possible */
8671 if (code == CM_ERROR_BADSMB) {
8672 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8676 #endif /* LOG_PACKET */
8677 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8680 code = CM_ERROR_INVAL;
8683 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8684 thrd_Decrement(&ongoingOps);
8689 /* now, if we failed, turn the current response into an empty
8690 * one, and fill in the response packet's error code.
8693 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8694 smb_MapNTError(code, &NTStatus);
8695 outWctp = outp->wctp;
8696 smbp = (smb_t *) &outp->data;
8697 if (code != CM_ERROR_PARTIALWRITE
8698 && code != CM_ERROR_BUFFERTOOSMALL
8699 && code != CM_ERROR_GSSCONTINUE) {
8700 /* nuke wct and bcc. For a partial
8701 * write or an in-process authentication handshake,
8702 * assume they're OK.
8708 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8709 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8710 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8711 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8712 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8716 smb_MapCoreError(code, vcp, &errCode, &errClass);
8717 outWctp = outp->wctp;
8718 smbp = (smb_t *) &outp->data;
8719 if (code != CM_ERROR_PARTIALWRITE) {
8720 /* nuke wct and bcc. For a partial
8721 * write, assume they're OK.
8727 smbp->errLow = (unsigned char) (errCode & 0xff);
8728 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8729 smbp->rcls = errClass;
8732 } /* error occurred */
8734 /* if we're here, we've finished one request. Look to see if
8735 * this is a chained opcode. If it is, setup things to process
8736 * the chained request, and setup the output buffer to hold the
8737 * chained response. Start by finding the next input record.
8739 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8740 break; /* not a chained req */
8741 tp = inp->wctp; /* points to start of last request */
8742 /* in a chained request, the first two
8743 * parm fields are required, and are
8744 * AndXCommand/AndXReserved and
8746 if (tp[0] < 2) break;
8747 if (tp[1] == 0xff) break; /* no more chained opcodes */
8749 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8752 /* and now append the next output request to the end of this
8753 * last request. Begin by finding out where the last response
8754 * ends, since that's where we'll put our new response.
8756 outWctp = outp->wctp; /* ptr to out parameters */
8757 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8758 nparms = outWctp[0] << 1;
8759 tp = outWctp + nparms + 1; /* now points to bcc field */
8760 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8761 tp += 2 /* for the count itself */ + nbytes;
8762 /* tp now points to the new output record; go back and patch the
8763 * second parameter (off2) to point to the new record.
8765 temp = (unsigned int)(tp - outp->data);
8766 outWctp[3] = (unsigned char) (temp & 0xff);
8767 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8768 outWctp[2] = 0; /* padding */
8769 outWctp[1] = inp->inCom; /* next opcode */
8771 /* finally, setup for the next iteration */
8774 } /* while loop over all requests in the packet */
8776 /* now send the output packet, and return */
8778 smb_SendPacket(vcp, outp);
8779 thrd_Decrement(&ongoingOps);
8784 /* Wait for Netbios() calls to return, and make the results available to server
8785 * threads. Note that server threads can't wait on the NCBevents array
8786 * themselves, because NCB events are manual-reset, and the servers would race
8787 * each other to reset them.
8789 void smb_ClientWaiter(void *parmp)
8794 while (smbShutdownFlag == 0) {
8795 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8797 if (code == WAIT_OBJECT_0)
8800 /* error checking */
8801 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8803 int abandonIdx = code - WAIT_ABANDONED_0;
8804 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8807 if (code == WAIT_IO_COMPLETION)
8809 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8813 if (code == WAIT_TIMEOUT)
8815 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8818 if (code == WAIT_FAILED)
8820 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8823 idx = code - WAIT_OBJECT_0;
8825 /* check idx range! */
8826 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8828 /* this is fatal - log as much as possible */
8829 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8830 osi_assertx(0, "invalid index");
8833 thrd_ResetEvent(NCBevents[idx]);
8834 thrd_SetEvent(NCBreturns[0][idx]);
8839 * Try to have one NCBRECV request waiting for every live session. Not more
8840 * than one, because if there is more than one, it's hard to handle Write Raw.
8842 void smb_ServerWaiter(void *parmp)
8845 int idx_session, idx_NCB;
8848 while (smbShutdownFlag == 0) {
8850 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8852 if (code == WAIT_OBJECT_0)
8855 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8857 int abandonIdx = code - WAIT_ABANDONED_0;
8858 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8861 if (code == WAIT_IO_COMPLETION)
8863 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8867 if (code == WAIT_TIMEOUT)
8869 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8872 if (code == WAIT_FAILED)
8874 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8877 idx_session = code - WAIT_OBJECT_0;
8879 /* check idx range! */
8880 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8882 /* this is fatal - log as much as possible */
8883 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8884 osi_assertx(0, "invalid index");
8889 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8891 if (code == WAIT_OBJECT_0) {
8892 if (smbShutdownFlag == 1)
8898 /* error checking */
8899 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8901 int abandonIdx = code - WAIT_ABANDONED_0;
8902 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8905 if (code == WAIT_IO_COMPLETION)
8907 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8911 if (code == WAIT_TIMEOUT)
8913 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8916 if (code == WAIT_FAILED)
8918 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8921 idx_NCB = code - WAIT_OBJECT_0;
8923 /* check idx range! */
8924 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8926 /* this is fatal - log as much as possible */
8927 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8928 osi_assertx(0, "invalid index");
8931 /* Link them together */
8932 NCBsessions[idx_NCB] = idx_session;
8935 ncbp = NCBs[idx_NCB];
8936 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8937 ncbp->ncb_command = NCBRECV | ASYNCH;
8938 ncbp->ncb_lana_num = lanas[idx_session];
8939 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8940 ncbp->ncb_event = NCBevents[idx_NCB];
8941 ncbp->ncb_length = SMB_PACKETSIZE;
8946 typedef struct _monitored_task {
8949 LARGE_INTEGER start_time;
8951 BOOL trace_timer_hit;
8952 BOOL dump_timer_hit;
8955 typedef struct osi_queueHT {
8956 osi_queue_t * headp;
8957 osi_queue_t * tailp;
8960 static osi_queue_t *smb_monitored_tasks = NULL;
8961 static osi_queue_t *smb_free_monitored_tasks = NULL;
8963 static osi_mutex_t _monitor_mx;
8965 static HANDLE h_monitored_task_queue = NULL;
8966 static HANDLE h_monitored_task_shutdown = NULL;
8968 static time_t smb_last_dump_time = 0;
8970 DWORD smb_monitorReqs = 0;
8972 /* FILETIME comparison fuzz */
8973 #define MONITOR_FUZZ_TIMEOUT (1 * 10000000i64)
8975 /* Trace timeout is at 60 seconds */
8976 #define MONITOR_TRACE_TIMEOUT (60 * 10000000i64)
8978 /* Dump timeout is at 120 seconds */
8979 #define MONITOR_DUMP_TIMEOUT (120 * 10000000i64)
8981 /* Time before another dump is performed in seconds*/
8982 #define MONITOR_DUMP_RESET_TIMEOUT (600)
8984 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
8987 LARGE_INTEGER earliest;
8990 GetSystemTimeAsFileTime(&now);
8991 earliest.LowPart = now.dwLowDateTime;
8992 earliest.HighPart = now.dwHighDateTime;
8993 earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
8995 while ((t = (monitored_task *) taskmq->headp) != NULL &&
8997 (t->start_time.QuadPart < earliest.QuadPart ||
8999 t->dump_timer_hit)) {
9001 osi_QRemoveHT(&taskmq->headp,
9005 lock_ObtainMutex(&_monitor_mx);
9006 osi_QAdd(&smb_free_monitored_tasks, &t->q);
9007 lock_ReleaseMutex(&_monitor_mx);
9010 #ifdef INVARIANT_CHECK
9016 for (t = (monitored_task *) taskmq->headp;
9018 t = (monitored_task *) osi_QNext(&t->q)) {
9019 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9020 last.QuadPart = t->start_time.QuadPart;
9026 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
9028 monitored_task * task;
9029 monitored_task * tasks;
9031 lock_ObtainMutex(&_monitor_mx);
9032 tasks = (monitored_task *) smb_monitored_tasks;
9033 smb_monitored_tasks = NULL;
9034 lock_ReleaseMutex(&_monitor_mx);
9039 osi_QRemove((osi_queue_t **) &tasks, &task->q);
9041 if (task->started) {
9047 q.prevp = taskmq->tailp;
9049 /* Insertion sort by start_time. Earliest request is
9050 first. Since we are likely to receive new requests
9051 later, we start inserting from the back. */
9054 ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
9058 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
9059 else if (p->prevp == NULL)
9060 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
9062 osi_queue_t *o = p->prevp;
9064 osi_assert(o->nextp == p);
9068 p->prevp = &task->q;
9069 o->nextp = &task->q;
9073 /* Some task ending */
9077 for (p = taskmq->headp;
9081 monitored_task * mt = (monitored_task *) p;
9083 if (mt->task_id == task->task_id) {
9085 osi_QRemoveHT(&taskmq->headp,
9088 lock_ObtainMutex(&_monitor_mx);
9089 osi_QAdd(&smb_free_monitored_tasks, p);
9090 lock_ReleaseMutex(&_monitor_mx);
9096 lock_ObtainMutex(&_monitor_mx);
9097 osi_QAdd(&smb_free_monitored_tasks, &task->q);
9098 lock_ReleaseMutex(&_monitor_mx);
9102 #ifdef INVARIANT_CHECK
9109 for (t = (monitored_task *) taskmq->headp;
9111 t = (monitored_task *) osi_QNext(&t->q)) {
9112 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9113 last.QuadPart = t->start_time.QuadPart;
9119 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9121 if (!task->trace_timer_hit) {
9123 task->trace_timer_hit = TRUE;
9125 osi_LogEnable(afsd_logp);
9126 rx_DebugOnOff(TRUE);
9128 } else if (!task->dump_timer_hit) {
9133 if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9134 task->dump_timer_hit = TRUE;
9135 smb_last_dump_time = now;
9137 GenerateMiniDump(NULL);
9143 * Server request monitoring
9145 * The server monitor runs in a separate thread and monitors server
9146 * requests for potential timeouts. It examines notifcations queued
9147 * by smb_NotifyRequestEvent() and waits for potential timeout events:
9149 * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9150 * enables trace logging.
9152 * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9153 * out a dump file that will hopefully contain enough evidence to
9154 * figure out why the timeout event occurred.
9157 void smb_ServerMonitor(VOID * parmp)
9159 osi_queueHT_t in_progress = { NULL, NULL };
9160 HANDLE h_timer = NULL;
9164 h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9165 h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9166 h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9168 lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9170 h_all[0] = h_monitored_task_queue;
9172 h_all[2] = h_monitored_task_shutdown;
9177 rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9179 if (rv == WAIT_OBJECT_0) {
9181 smb_SlurpNewTaskMonitors(&in_progress);
9183 } else if (rv == WAIT_OBJECT_0 + 1) {
9185 smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9193 /* refresh timers */
9197 smb_PurgeOldTaskMonitors(&in_progress);
9198 t = (monitored_task *) in_progress.headp;
9200 if (t && !t->trace_timer_hit) {
9203 due = t->start_time;
9204 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9206 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9207 } else if (t && !t->dump_timer_hit) {
9211 due = t->start_time;
9212 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9214 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9216 CancelWaitableTimer(h_timer);
9218 /* CancelWaitableTimer() doesn't reset the timer if it
9219 was already signalled. */
9220 WaitForSingleObject(h_timer, 0);
9228 h = h_monitored_task_queue;
9229 h_monitored_task_queue = NULL;
9232 h = h_monitored_task_shutdown;
9233 h_monitored_task_shutdown = NULL;
9236 CloseHandle(h_timer);
9238 lock_FinalizeMutex(&_monitor_mx);
9242 monitored_task * task;
9244 while (in_progress.headp) {
9245 task = (monitored_task *) in_progress.headp;
9246 osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9250 for (task = (monitored_task *) smb_free_monitored_tasks;
9251 task; task = (monitored_task *) smb_free_monitored_tasks) {
9252 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9256 for (task = (monitored_task *) smb_monitored_tasks;
9257 task; task = (monitored_task *) smb_monitored_tasks) {
9258 osi_QRemove(&smb_monitored_tasks, &task->q);
9264 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9266 monitored_task * task;
9268 lock_ObtainMutex(&_monitor_mx);
9269 task = (monitored_task *) smb_free_monitored_tasks;
9271 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9272 lock_ReleaseMutex(&_monitor_mx);
9275 task = malloc(sizeof(monitored_task));
9276 memset(task, 0, sizeof(*task));
9278 task->task_id = task_id;
9279 task->started = started;
9284 GetSystemTimeAsFileTime(&now);
9285 task->start_time.HighPart = now.dwHighDateTime;
9286 task->start_time.LowPart = now.dwLowDateTime;
9289 lock_ObtainMutex(&_monitor_mx);
9290 osi_QAdd(&smb_monitored_tasks, &task->q);
9291 lock_ReleaseMutex(&_monitor_mx);
9293 SetEvent(h_monitored_task_queue);
9296 void smb_ShutdownMonitor()
9298 SetEvent(h_monitored_task_shutdown);
9302 * The top level loop for handling SMB request messages. Each server thread
9303 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9304 * NCB and buffer for the incoming request are loaned to us.
9306 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
9307 * to immediately send a request for the rest of the data. This must come
9308 * before any other traffic for that session, so we delay setting the session
9309 * event until that data has come in.
9311 void smb_Server(VOID *parmp)
9313 INT_PTR myIdx = (INT_PTR) parmp;
9317 smb_packet_t *outbufp;
9319 int idx_NCB, idx_session;
9321 smb_vc_t *vcp = NULL;
9324 rx_StartClientThread();
9326 outncbp = smb_GetNCB();
9327 outbufp = smb_GetPacket();
9328 outbufp->ncbp = outncbp;
9336 cm_ResetServerPriority();
9338 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9341 /* terminate silently if shutdown flag is set */
9342 if (code == WAIT_OBJECT_0) {
9343 if (smbShutdownFlag == 1) {
9344 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9350 /* error checking */
9351 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9353 int abandonIdx = code - WAIT_ABANDONED_0;
9354 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9357 if (code == WAIT_IO_COMPLETION)
9359 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9363 if (code == WAIT_TIMEOUT)
9365 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9368 if (code == WAIT_FAILED)
9370 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9373 idx_NCB = code - WAIT_OBJECT_0;
9375 /* check idx range! */
9376 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9378 /* this is fatal - log as much as possible */
9379 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9380 osi_assertx(0, "invalid index");
9383 ncbp = NCBs[idx_NCB];
9384 idx_session = NCBsessions[idx_NCB];
9385 rc = ncbp->ncb_retcode;
9387 if (rc != NRC_PENDING && rc != NRC_GOODRET)
9388 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9392 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9396 /* Can this happen? Or is it just my UNIX paranoia? */
9397 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9402 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9405 /* Client closed session */
9406 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9408 lock_ObtainMutex(&vcp->mx);
9409 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9410 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9412 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9413 lock_ReleaseMutex(&vcp->mx);
9414 lock_ObtainWrite(&smb_globalLock);
9415 dead_sessions[vcp->session] = TRUE;
9416 lock_ReleaseWrite(&smb_globalLock);
9418 lock_ReleaseMutex(&vcp->mx);
9420 smb_CleanupDeadVC(vcp);
9427 /* Treat as transient error */
9428 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9431 "dispatch smb recv failed, message incomplete, ncb_length %d",
9434 "SMB message incomplete, "
9435 "length %d", ncbp->ncb_length);
9438 * We used to discard the packet.
9439 * Instead, try handling it normally.
9443 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9447 /* A weird error code. Log it, sleep, and continue. */
9448 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9450 lock_ObtainMutex(&vcp->mx);
9451 if (vcp->errorCount++ > 3) {
9452 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9453 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9454 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9456 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9457 lock_ReleaseMutex(&vcp->mx);
9458 lock_ObtainWrite(&smb_globalLock);
9459 dead_sessions[vcp->session] = TRUE;
9460 lock_ReleaseWrite(&smb_globalLock);
9462 lock_ReleaseMutex(&vcp->mx);
9464 smb_CleanupDeadVC(vcp);
9470 lock_ReleaseMutex(&vcp->mx);
9474 thrd_SetEvent(SessionEvents[idx_session]);
9480 /* Success, so now dispatch on all the data in the packet */
9482 smb_concurrentCalls++;
9483 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9484 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9487 * If at this point vcp is NULL (implies that packet was invalid)
9488 * then we are in big trouble. This means either :
9489 * a) we have the wrong NCB.
9490 * b) Netbios screwed up the call.
9491 * c) The VC was already marked dead before we were able to
9493 * Obviously this implies that
9494 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9495 * lanas[idx_session] != ncbp->ncb_lana_num )
9496 * Either way, we can't do anything with this packet.
9497 * Log, sleep and resume.
9500 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9504 ncbp->ncb_lana_num);
9506 /* Also log in the trace log. */
9507 osi_Log4(smb_logp, "Server: VCP does not exist!"
9508 "LSNs[idx_session]=[%d],"
9509 "lanas[idx_session]=[%d],"
9510 "ncbp->ncb_lsn=[%d],"
9511 "ncbp->ncb_lana_num=[%d]",
9515 ncbp->ncb_lana_num);
9517 /* thrd_Sleep(1000); Don't bother sleeping */
9518 thrd_SetEvent(SessionEvents[idx_session]);
9519 smb_concurrentCalls--;
9523 cm_SetRequestStartTime();
9524 if (smb_monitorReqs) {
9525 smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9528 vcp->errorCount = 0;
9529 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9530 smbp = (smb_t *)bufp->data;
9537 if (smbp->com == 0x1d) {
9538 /* Special handling for Write Raw */
9539 raw_write_cont_t rwc;
9541 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9542 if (rwc.code == 0) {
9543 EVENT_HANDLE rwevent;
9544 char eventName[MAX_PATH];
9546 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9547 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9548 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9549 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9551 ncbp->ncb_command = NCBRECV | ASYNCH;
9552 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9553 ncbp->ncb_lana_num = vcp->lana;
9554 ncbp->ncb_buffer = rwc.buf;
9555 ncbp->ncb_length = 65535;
9556 ncbp->ncb_event = rwevent;
9558 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9559 thrd_CloseHandle(rwevent);
9561 thrd_SetEvent(SessionEvents[idx_session]);
9563 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9565 else if (smbp->com == 0xa0) {
9567 * Serialize the handling for NT Transact
9570 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9571 thrd_SetEvent(SessionEvents[idx_session]);
9573 thrd_SetEvent(SessionEvents[idx_session]);
9574 /* TODO: what else needs to be serialized? */
9575 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9579 __except( smb_ServerExceptionFilter() ) {
9583 if (smb_monitorReqs) {
9584 smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9586 smb_concurrentCalls--;
9589 thrd_SetEvent(NCBavails[idx_NCB]);
9594 smb_FreePacket(outbufp);
9596 smb_FreeNCB(outncbp);
9600 * Exception filter for the server threads. If an exception occurs in the
9601 * dispatch routines, which is where exceptions are most common, then do a
9602 * force trace and give control to upstream exception handlers. Useful for
9605 DWORD smb_ServerExceptionFilter(void) {
9606 /* While this is not the best time to do a trace, if it succeeds, then
9607 * we have a trace (assuming tracing was enabled). Otherwise, this should
9608 * throw a second exception.
9610 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9611 afsd_ForceTrace(TRUE);
9612 buf_ForceTrace(TRUE);
9613 return EXCEPTION_CONTINUE_SEARCH;
9617 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9618 * If the number of server threads is M, and the number of live sessions is
9619 * N, then the number of NCB's in use at any time either waiting for, or
9620 * holding, received messages is M + N, so that is how many NCB's get created.
9622 void InitNCBslot(int idx)
9624 struct smb_packet *bufp;
9625 EVENT_HANDLE retHandle;
9627 char eventName[MAX_PATH];
9629 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9631 NCBs[idx] = smb_GetNCB();
9632 sprintf(eventName,"NCBavails[%d]", idx);
9633 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9634 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9635 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9636 sprintf(eventName,"NCBevents[%d]", idx);
9637 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9638 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9639 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9640 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9641 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9642 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9643 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9644 for (i=0; i<smb_NumServerThreads; i++)
9645 NCBreturns[i][idx] = retHandle;
9646 bufp = smb_GetPacket();
9647 bufp->spacep = cm_GetSpace();
9651 /* listen for new connections */
9652 void smb_Listener(void *parmp)
9658 afs_uint32 session, thread;
9659 smb_vc_t *vcp = NULL;
9661 char rname[NCBNAMSZ+1];
9662 char cname[MAX_COMPUTERNAME_LENGTH+1];
9663 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9664 INT_PTR lana = (INT_PTR) parmp;
9665 char eventName[MAX_PATH];
9666 int bridgeCount = 0;
9667 int nowildCount = 0;
9669 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9670 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9671 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9672 thrd_ResetEvent(ListenerShutdown[lana]);
9674 ncbp = smb_GetNCB();
9676 /* retrieve computer name */
9677 GetComputerName(cname, &cnamelen);
9680 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9681 memset(ncbp, 0, sizeof(NCB));
9684 ncbp->ncb_command = NCBLISTEN;
9685 ncbp->ncb_rto = 0; /* No receive timeout */
9686 ncbp->ncb_sto = 0; /* No send timeout */
9688 /* pad out with spaces instead of null termination */
9689 len = (long)strlen(smb_localNamep);
9690 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9691 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9693 strcpy(ncbp->ncb_callname, "*");
9694 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9696 ncbp->ncb_lana_num = (UCHAR)lana;
9698 code = Netbios(ncbp);
9700 if (code == NRC_NAMERR) {
9701 /* An smb shutdown or Vista resume must have taken place */
9703 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9704 ncbp->ncb_lana_num);
9705 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9707 if (lock_TryMutex(&smb_StartedLock)) {
9708 lana_list.lana[i] = LANA_INVALID;
9709 lock_ReleaseMutex(&smb_StartedLock);
9712 } else if (code == NRC_BRIDGE || code != 0) {
9713 int lanaRemaining = 0;
9715 if (code == NRC_BRIDGE) {
9716 if (++bridgeCount <= 5) {
9717 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9720 } else if (code == NRC_NOWILD) {
9721 if (++nowildCount <= 5) {
9722 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9724 if (bridgeCount > 0) {
9725 memset(ncbp, 0, sizeof(*ncbp));
9726 ncbp->ncb_command = NCBADDNAME;
9727 ncbp->ncb_lana_num = (UCHAR)lana;
9728 /* pad out with spaces instead of null termination */
9729 len = (long)strlen(smb_localNamep);
9730 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9731 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9732 code = Netbios(ncbp);
9738 while (!lock_TryMutex(&smb_StartedLock)) {
9739 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9745 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9746 ncbp->ncb_lana_num, ncb_error_string(code));
9747 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9748 ncbp->ncb_lana_num, ncb_error_string(code));
9750 for (i = 0; i < lana_list.length; i++) {
9751 if (lana_list.lana[i] == lana) {
9752 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9753 lana_list.lana[i] = LANA_INVALID;
9755 if (lana_list.lana[i] != LANA_INVALID)
9759 if (lanaRemaining == 0) {
9760 cm_VolStatus_Network_Stopped(cm_NetbiosName
9765 smb_ListenerState = SMB_LISTENER_STOPPED;
9766 smb_LANadapter = LANA_INVALID;
9767 lana_list.length = 0;
9769 lock_ReleaseMutex(&smb_StartedLock);
9773 else if (code != 0) {
9774 char tbuffer[AFSPATHMAX];
9776 /* terminate silently if shutdown flag is set */
9777 while (!lock_TryMutex(&smb_StartedLock)) {
9778 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9784 "NCBLISTEN lana=%d failed with code %d [%s]",
9785 ncbp->ncb_lana_num, code, ncb_error_string(code));
9787 "Client exiting due to network failure. Please restart client.\n");
9790 "Client exiting due to network failure. Please restart client.\n"
9791 "NCBLISTEN lana=%d failed with code %d [%s]",
9792 ncbp->ncb_lana_num, code, ncb_error_string(code));
9794 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9795 MB_OK|MB_SERVICE_NOTIFICATION);
9796 osi_panic(tbuffer, __FILE__, __LINE__);
9798 lock_ReleaseMutex(&smb_StartedLock);
9803 /* a successful packet received. clear bridge error count */
9807 /* check for remote conns */
9808 /* first get remote name and insert null terminator */
9809 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9810 for (i=NCBNAMSZ; i>0; i--) {
9811 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9817 /* compare with local name */
9819 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9820 flags |= SMB_VCFLAG_REMOTECONN;
9823 lock_ObtainMutex(&smb_ListenerLock);
9825 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9826 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9828 /* now ncbp->ncb_lsn is the connection ID */
9829 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9830 if (vcp->session == 0) {
9831 /* New generation */
9832 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9835 /* Log session startup */
9837 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9838 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9839 #endif /* NOTSERVICE */
9840 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9841 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9843 if (reportSessionStartups) {
9844 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9847 lock_ObtainMutex(&vcp->mx);
9848 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9849 vcp->flags |= flags;
9850 lock_ReleaseMutex(&vcp->mx);
9852 /* Allocate slot in session arrays */
9853 /* Re-use dead session if possible, otherwise add one more */
9854 /* But don't look at session[0], it is reserved */
9855 lock_ObtainWrite(&smb_globalLock);
9856 for (session = 1; session < numSessions; session++) {
9857 if (dead_sessions[session]) {
9858 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9859 dead_sessions[session] = FALSE;
9863 lock_ReleaseWrite(&smb_globalLock);
9865 /* We are re-using an existing VC because the lsn and lana
9867 session = vcp->session;
9869 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9871 /* Log session startup */
9873 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9874 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9875 #endif /* NOTSERVICE */
9876 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9877 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9879 if (reportSessionStartups) {
9880 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9884 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9885 unsigned long code = CM_ERROR_ALLBUSY;
9886 smb_packet_t * outp = smb_GetPacket();
9887 unsigned char *outWctp;
9890 smb_FormatResponsePacket(vcp, NULL, outp);
9893 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9894 unsigned long NTStatus;
9895 smb_MapNTError(code, &NTStatus);
9896 outWctp = outp->wctp;
9897 smbp = (smb_t *) &outp->data;
9901 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9902 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9903 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9904 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9905 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9907 unsigned short errCode;
9908 unsigned char errClass;
9909 smb_MapCoreError(code, vcp, &errCode, &errClass);
9910 outWctp = outp->wctp;
9911 smbp = (smb_t *) &outp->data;
9915 smbp->errLow = (unsigned char) (errCode & 0xff);
9916 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9917 smbp->rcls = errClass;
9920 smb_SendPacket(vcp, outp);
9921 smb_FreePacket(outp);
9923 lock_ObtainMutex(&vcp->mx);
9924 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9925 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9927 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9928 lock_ReleaseMutex(&vcp->mx);
9929 lock_ObtainWrite(&smb_globalLock);
9930 dead_sessions[vcp->session] = TRUE;
9931 lock_ReleaseWrite(&smb_globalLock);
9932 smb_CleanupDeadVC(vcp);
9934 lock_ReleaseMutex(&vcp->mx);
9937 /* assert that we do not exceed the maximum number of sessions or NCBs.
9938 * we should probably want to wait for a session to be freed in case
9941 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9942 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9944 lock_ObtainMutex(&vcp->mx);
9945 vcp->session = session;
9946 lock_ReleaseMutex(&vcp->mx);
9947 lock_ObtainWrite(&smb_globalLock);
9948 LSNs[session] = ncbp->ncb_lsn;
9949 lanas[session] = ncbp->ncb_lana_num;
9950 lock_ReleaseWrite(&smb_globalLock);
9952 if (session == numSessions) {
9953 /* Add new NCB for new session */
9954 char eventName[MAX_PATH];
9956 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9958 InitNCBslot(numNCBs);
9959 lock_ObtainWrite(&smb_globalLock);
9961 lock_ReleaseWrite(&smb_globalLock);
9962 thrd_SetEvent(NCBavails[0]);
9963 thrd_SetEvent(NCBevents[0]);
9964 for (thread = 0; thread < smb_NumServerThreads; thread++)
9965 thrd_SetEvent(NCBreturns[thread][0]);
9966 /* Also add new session event */
9967 sprintf(eventName, "SessionEvents[%d]", session);
9968 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9969 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9970 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9971 lock_ObtainWrite(&smb_globalLock);
9973 lock_ReleaseWrite(&smb_globalLock);
9974 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9975 thrd_SetEvent(SessionEvents[0]);
9977 thrd_SetEvent(SessionEvents[session]);
9983 lock_ReleaseMutex(&smb_ListenerLock);
9984 } /* dispatch while loop */
9988 thrd_SetEvent(ListenerShutdown[lana]);
9993 configureBackConnectionHostNames(void)
9995 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9996 * there is a restriction on the use of SMB authentication on loopback connections.
9997 * There are two work arounds available:
9999 * (1) We can disable the check for matching host names. This does not
10000 * require a reboot:
10001 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
10002 * "DisableLoopbackCheck"=dword:00000001
10004 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
10005 * does require a reboot:
10006 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
10007 * "BackConnectionHostNames"=multi-sz
10009 * The algorithm will be:
10010 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
10011 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
10012 * (2b1) and check to see if DisableLoopbackCheck is set.
10013 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
10014 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
10015 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
10016 * check for the UnsetDisableLoopbackCheck value.
10017 * If set, set the DisableLoopbackCheck flag to 0x0
10018 * and delete the UnsetDisableLoopbackCheck value
10020 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
10021 * force Windows to use the loopback authentication mechanism for the specified
10024 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
10025 * service session that set it.
10031 DWORD dwSize, dwAllocSize;
10033 PBYTE pHostNames = NULL, pName = NULL;
10034 BOOL bNameFound = FALSE;
10035 static BOOL bLoopbackCheckDisabled = FALSE;
10037 /* BackConnectionHostNames and DisableLoopbackCheck */
10038 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10039 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
10041 KEY_READ|KEY_WRITE,
10042 &hkMSV10) == ERROR_SUCCESS )
10044 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
10045 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10046 (dwType == REG_MULTI_SZ))
10048 dwAllocSize += 1 /* in case the source string is not nul terminated */
10049 + (DWORD)strlen(cm_NetbiosName) + 2;
10050 pHostNames = malloc(dwAllocSize);
10051 dwSize = dwAllocSize;
10052 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
10053 pHostNames, &dwSize) == ERROR_SUCCESS)
10055 for (pName = pHostNames;
10056 (pName - pHostNames < (int) dwSize) && *pName ;
10057 pName += strlen(pName) + 1)
10059 if ( !stricmp(pName, cm_NetbiosName) ) {
10067 if ( !bNameFound ) {
10068 size_t size = strlen(cm_NetbiosName) + 2;
10069 if ( !pHostNames ) {
10070 pHostNames = malloc(size);
10071 pName = pHostNames;
10073 StringCbCopyA(pName, size, cm_NetbiosName);
10075 *pName = '\0'; /* add a second nul terminator */
10077 dwType = REG_MULTI_SZ;
10078 dwSize = (DWORD)(pName - pHostNames + 1);
10079 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10081 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10082 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10084 KEY_READ|KEY_WRITE,
10085 &hkLsa) == ERROR_SUCCESS )
10087 dwSize = sizeof(DWORD);
10088 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
10090 dwType = REG_DWORD;
10091 dwSize = sizeof(DWORD);
10093 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10095 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10096 AFSREG_CLT_OPENAFS_SUBKEY,
10099 REG_OPTION_NON_VOLATILE,
10100 KEY_READ|KEY_WRITE,
10103 NULL) == ERROR_SUCCESS) {
10105 dwType = REG_DWORD;
10106 dwSize = sizeof(DWORD);
10108 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10109 bLoopbackCheckDisabled = TRUE;
10110 RegCloseKey(hkClient);
10112 RegCloseKey(hkLsa);
10115 } else if (!bLoopbackCheckDisabled) {
10116 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10117 AFSREG_CLT_OPENAFS_SUBKEY,
10120 REG_OPTION_NON_VOLATILE,
10121 KEY_READ|KEY_WRITE,
10124 NULL) == ERROR_SUCCESS) {
10126 dwSize = sizeof(DWORD);
10127 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10129 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10130 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10132 KEY_READ|KEY_WRITE,
10133 &hkLsa) == ERROR_SUCCESS )
10135 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10136 RegCloseKey(hkLsa);
10139 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10140 RegCloseKey(hkClient);
10149 RegCloseKey(hkMSV10);
10155 configureExtendedSMBSessionTimeouts(void)
10158 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10159 * new functionality:
10161 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
10162 * "ReconnectableServers" REG_MULTI_SZ
10163 * "ExtendedSessTimeout" REG_DWORD (seconds)
10164 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
10166 * These values can be used to prevent the smb redirector from timing out
10167 * smb connection to the afs smb server prematurely.
10171 DWORD dwSize, dwAllocSize;
10173 PBYTE pHostNames = NULL, pName = NULL;
10174 BOOL bNameFound = FALSE;
10176 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10177 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
10179 KEY_READ|KEY_WRITE,
10180 &hkLanMan) == ERROR_SUCCESS )
10182 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
10183 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10184 (dwType == REG_MULTI_SZ))
10186 dwAllocSize += 1 /* in case the source string is not nul terminated */
10187 + (DWORD)strlen(cm_NetbiosName) + 2;
10188 pHostNames = malloc(dwAllocSize);
10189 dwSize = dwAllocSize;
10190 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
10191 pHostNames, &dwSize) == ERROR_SUCCESS)
10193 for (pName = pHostNames;
10194 (pName - pHostNames < (int) dwSize) && *pName ;
10195 pName += strlen(pName) + 1)
10197 if ( !stricmp(pName, cm_NetbiosName) ) {
10205 if ( !bNameFound ) {
10206 size_t size = strlen(cm_NetbiosName) + 2;
10207 if ( !pHostNames ) {
10208 pHostNames = malloc(size);
10209 pName = pHostNames;
10211 StringCbCopyA(pName, size, cm_NetbiosName);
10213 *pName = '\0'; /* add a second nul terminator */
10215 dwType = REG_MULTI_SZ;
10216 dwSize = (DWORD)(pName - pHostNames + 1);
10217 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10225 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
10226 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10227 (dwType == REG_MULTI_SZ))
10229 dwAllocSize += 1 /* in case the source string is not nul terminated */
10230 + (DWORD)strlen(cm_NetbiosName) + 2;
10231 pHostNames = malloc(dwAllocSize);
10232 dwSize = dwAllocSize;
10233 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
10234 pHostNames, &dwSize) == ERROR_SUCCESS)
10236 for (pName = pHostNames;
10237 (pName - pHostNames < (int) dwSize) && *pName ;
10238 pName += strlen(pName) + 1)
10240 if ( !stricmp(pName, cm_NetbiosName) ) {
10248 if ( !bNameFound ) {
10249 size_t size = strlen(cm_NetbiosName) + 2;
10250 if ( !pHostNames ) {
10251 pHostNames = malloc(size);
10252 pName = pHostNames;
10254 StringCbCopyA(pName, size, cm_NetbiosName);
10256 *pName = '\0'; /* add a second nul terminator */
10258 dwType = REG_MULTI_SZ;
10259 dwSize = (DWORD)(pName - pHostNames + 1);
10260 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10268 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
10269 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10270 (dwType != REG_DWORD))
10272 dwType = REG_DWORD;
10273 dwSize = sizeof(dwValue);
10274 dwValue = 300; /* 5 minutes */
10275 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10277 RegCloseKey(hkLanMan);
10282 smb_LanAdapterChangeThread(void *param)
10285 * Give the IPAddrDaemon thread a chance
10286 * to block before we trigger.
10289 smb_LanAdapterChange(0);
10292 void smb_SetLanAdapterChangeDetected(void)
10297 lock_ObtainMutex(&smb_StartedLock);
10299 if (!powerStateSuspended) {
10300 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10301 NULL, 0, &lpid, "smb_LanAdapterChange");
10302 if (phandle == NULL) {
10306 gle = GetLastError();
10307 StringCchPrintf( msg, sizeof(msg)/sizeof(msg[0]),
10308 "smb_LanAdapterChangeThread thread creation failure - gle 0x%x",
10310 osi_assertx(TRUE, msg);
10312 thrd_CloseHandle(phandle);
10315 smb_LanAdapterChangeDetected = 1;
10316 lock_ReleaseMutex(&smb_StartedLock);
10319 void smb_LanAdapterChange(int locked) {
10320 lana_number_t lanaNum;
10322 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
10324 LANA_ENUM temp_list;
10329 afsi_log("smb_LanAdapterChange");
10332 lock_ObtainMutex(&smb_StartedLock);
10334 smb_LanAdapterChangeDetected = 0;
10336 if (!powerStateSuspended &&
10337 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10338 LANA_NETBIOS_NAME_FULL | LANA_NETBIOS_NO_RESET)) &&
10339 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10340 if ( isGateway != bGateway ) {
10341 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10342 smb_LANadapter, lanaNum, isGateway, bGateway);
10344 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10345 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10346 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10349 NCB *ncbp = smb_GetNCB();
10350 ncbp->ncb_command = NCBENUM;
10351 ncbp->ncb_buffer = (PUCHAR)&temp_list;
10352 ncbp->ncb_length = sizeof(temp_list);
10353 code = Netbios(ncbp);
10355 if (temp_list.length != lana_list.length) {
10356 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10357 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10360 for (i=0; i<lana_list.length; i++) {
10361 if ( temp_list.lana[i] != lana_list.lana[i] ) {
10362 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10363 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10375 smb_StopListeners(1);
10376 smb_RestartListeners(1);
10379 lock_ReleaseMutex(&smb_StartedLock);
10382 /* initialize Netbios */
10383 int smb_NetbiosInit(int locked)
10386 int i, lana, code, l;
10388 int delname_tried=0;
10390 int lana_found = 0;
10391 lana_number_t lanaNum;
10394 lock_ObtainMutex(&smb_StartedLock);
10396 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10397 smb_ListenerState != SMB_LISTENER_STOPPED) {
10400 lock_ReleaseMutex(&smb_StartedLock);
10403 /* setup the NCB system */
10404 ncbp = smb_GetNCB();
10407 * Call lanahelper to get Netbios name, lan adapter number and gateway flag
10408 * This will reset all of the network adapter's netbios state.
10410 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10411 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10413 if (smb_LANadapter != LANA_INVALID)
10414 afsi_log("LAN adapter number %d", smb_LANadapter);
10416 afsi_log("LAN adapter number not determined");
10419 afsi_log("Set for gateway service");
10421 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10423 /* something went horribly wrong. We can't proceed without a netbios name */
10425 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10426 osi_panic(buf, __FILE__, __LINE__);
10429 /* remember the name */
10430 len = (int)strlen(cm_NetbiosName);
10431 if (smb_localNamep)
10432 free(smb_localNamep);
10433 smb_localNamep = malloc(len+1);
10434 strcpy(smb_localNamep, cm_NetbiosName);
10435 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10437 /* Also copy the value to the client character encoded string */
10438 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10440 if (smb_LANadapter == LANA_INVALID) {
10441 ncbp->ncb_command = NCBENUM;
10442 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10443 ncbp->ncb_length = sizeof(lana_list);
10444 code = Netbios(ncbp);
10446 afsi_log("Netbios NCBENUM error code %d", code);
10447 osi_panic(s, __FILE__, __LINE__);
10451 lana_list.length = 1;
10452 lana_list.lana[0] = smb_LANadapter;
10455 for (i = 0; i < lana_list.length; i++) {
10456 /* reset the adaptor: in Win32, this is required for every process, and
10457 * acts as an init call, not as a real hardware reset.
10459 ncbp->ncb_command = NCBRESET;
10460 ncbp->ncb_callname[0] = 100;
10461 ncbp->ncb_callname[2] = 100;
10462 ncbp->ncb_lana_num = lana_list.lana[i];
10463 code = Netbios(ncbp);
10465 code = ncbp->ncb_retcode;
10467 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10468 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10470 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10474 /* and declare our name so we can receive connections */
10475 memset(ncbp, 0, sizeof(*ncbp));
10476 len=lstrlen(smb_localNamep);
10477 memset(smb_sharename,' ',NCBNAMSZ);
10478 memcpy(smb_sharename,smb_localNamep,len);
10479 afsi_log("lana_list.length %d", lana_list.length);
10481 /* Keep the name so we can unregister it later */
10482 for (l = 0; l < lana_list.length; l++) {
10483 lana = lana_list.lana[l];
10485 ncbp->ncb_command = NCBADDNAME;
10486 ncbp->ncb_lana_num = lana;
10487 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10488 code = Netbios(ncbp);
10490 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10491 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10493 char name[NCBNAMSZ+1];
10495 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10496 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10500 code = ncbp->ncb_retcode;
10503 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10506 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10507 if (code == NRC_BRIDGE) { /* invalid LANA num */
10508 lana_list.lana[l] = LANA_INVALID;
10511 else if (code == NRC_DUPNAME) {
10512 afsi_log("Name already exists; try to delete it");
10513 memset(ncbp, 0, sizeof(*ncbp));
10514 ncbp->ncb_command = NCBDELNAME;
10515 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10516 ncbp->ncb_lana_num = lana;
10517 code = Netbios(ncbp);
10519 code = ncbp->ncb_retcode;
10521 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10523 if (code != 0 || delname_tried) {
10524 lana_list.lana[l] = LANA_INVALID;
10526 else if (code == 0) {
10527 if (!delname_tried) {
10535 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10536 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10540 smb_LANadapter = lana;
10541 lana_found = 1; /* at least one worked */
10545 osi_assertx(lana_list.length >= 0, "empty lana list");
10547 afsi_log("No valid LANA numbers found!");
10548 lana_list.length = 0;
10549 smb_LANadapter = LANA_INVALID;
10550 smb_ListenerState = SMB_LISTENER_STOPPED;
10551 cm_VolStatus_Network_Stopped(cm_NetbiosName
10558 /* we're done with the NCB now */
10561 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10562 if (lana_list.length > 0)
10563 osi_assert(smb_LANadapter != LANA_INVALID);
10566 lock_ReleaseMutex(&smb_StartedLock);
10568 return (lana_list.length > 0 ? 1 : 0);
10571 void smb_StartListeners(int locked)
10578 lock_ObtainMutex(&smb_StartedLock);
10580 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10582 lock_ReleaseMutex(&smb_StartedLock);
10586 afsi_log("smb_StartListeners");
10587 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10588 configureBackConnectionHostNames();
10590 /* Configure Extended SMB Session Timeouts */
10591 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10592 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10593 configureExtendedSMBSessionTimeouts();
10596 smb_ListenerState = SMB_LISTENER_STARTED;
10597 cm_VolStatus_Network_Started(cm_NetbiosName
10603 for (i = 0; i < lana_list.length; i++) {
10604 if (lana_list.lana[i] == LANA_INVALID)
10606 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10607 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10608 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10609 thrd_CloseHandle(phandle);
10612 lock_ReleaseMutex(&smb_StartedLock);
10615 void smb_RestartListeners(int locked)
10618 lock_ObtainMutex(&smb_StartedLock);
10620 if (powerStateSuspended)
10621 afsi_log("smb_RestartListeners called while suspended");
10623 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10624 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10625 if (smb_NetbiosInit(1))
10626 smb_StartListeners(1);
10627 } else if (smb_LanAdapterChangeDetected) {
10628 smb_LanAdapterChange(1);
10632 lock_ReleaseMutex(&smb_StartedLock);
10635 void smb_StopListener(NCB *ncbp, int lana, int wait)
10639 memset(ncbp, 0, sizeof(*ncbp));
10640 ncbp->ncb_command = NCBDELNAME;
10641 ncbp->ncb_lana_num = lana;
10642 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10643 code = Netbios(ncbp);
10645 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10646 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10648 /* and then reset the LANA; this will cause the listener threads to exit */
10649 ncbp->ncb_command = NCBRESET;
10650 ncbp->ncb_callname[0] = 100;
10651 ncbp->ncb_callname[2] = 100;
10652 ncbp->ncb_lana_num = lana;
10653 code = Netbios(ncbp);
10655 code = ncbp->ncb_retcode;
10657 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10659 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10663 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10666 void smb_StopListeners(int locked)
10672 lock_ObtainMutex(&smb_StartedLock);
10674 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10676 lock_ReleaseMutex(&smb_StartedLock);
10680 afsi_log("smb_StopListeners");
10681 smb_ListenerState = SMB_LISTENER_STOPPED;
10682 cm_VolStatus_Network_Stopped(cm_NetbiosName
10688 ncbp = smb_GetNCB();
10690 /* Unregister the SMB name */
10691 for (l = 0; l < lana_list.length; l++) {
10692 lana = lana_list.lana[l];
10694 if (lana != LANA_INVALID) {
10695 smb_StopListener(ncbp, lana, TRUE);
10697 /* mark the adapter invalid */
10698 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10702 /* force a re-evaluation of the network adapters */
10703 lana_list.length = 0;
10704 smb_LANadapter = LANA_INVALID;
10707 lock_ReleaseMutex(&smb_StartedLock);
10710 void smb_Init(osi_log_t *logp, int useV3,
10720 EVENT_HANDLE retHandle;
10721 char eventName[MAX_PATH];
10722 int startListeners = 0;
10724 smb_MBfunc = aMBfunc;
10728 /* Initialize smb_localZero */
10729 myTime.tm_isdst = -1; /* compute whether on DST or not */
10730 myTime.tm_year = 70;
10732 myTime.tm_mday = 1;
10733 myTime.tm_hour = 0;
10736 smb_localZero = mktime(&myTime);
10738 #ifdef AFS_FREELANCE_CLIENT
10739 /* Make sure the root.afs volume has the correct time */
10740 cm_noteLocalMountPointChange(FALSE);
10743 /* initialize the remote debugging log */
10746 /* and the global lock */
10747 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10748 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10750 /* Raw I/O data structures */
10751 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10753 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10754 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10756 /* 4 Raw I/O buffers */
10757 smb_RawBufs = calloc(65536,1);
10758 *((char **)smb_RawBufs) = NULL;
10759 for (i=0; i<3; i++) {
10760 char *rawBuf = calloc(65536,1);
10761 *((char **)rawBuf) = smb_RawBufs;
10762 smb_RawBufs = rawBuf;
10765 /* global free lists */
10766 smb_ncbFreeListp = NULL;
10767 smb_packetFreeListp = NULL;
10769 lock_ObtainMutex(&smb_StartedLock);
10770 startListeners = smb_NetbiosInit(1);
10772 /* Initialize listener and server structures */
10774 memset(dead_sessions, 0, sizeof(dead_sessions));
10775 sprintf(eventName, "SessionEvents[0]");
10776 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10777 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10778 afsi_log("Event Object Already Exists: %s", eventName);
10780 smb_NumServerThreads = nThreads;
10781 sprintf(eventName, "NCBavails[0]");
10782 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10783 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10784 afsi_log("Event Object Already Exists: %s", eventName);
10785 sprintf(eventName, "NCBevents[0]");
10786 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10787 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10788 afsi_log("Event Object Already Exists: %s", eventName);
10789 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10790 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10791 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10792 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10793 afsi_log("Event Object Already Exists: %s", eventName);
10794 for (i = 0; i < smb_NumServerThreads; i++) {
10795 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10796 NCBreturns[i][0] = retHandle;
10799 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10800 for (i = 0; i < smb_NumServerThreads; i++) {
10801 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10802 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10803 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10804 afsi_log("Event Object Already Exists: %s", eventName);
10805 InitNCBslot((int)(i+1));
10807 numNCBs = smb_NumServerThreads + 1;
10809 /* Initialize dispatch table */
10810 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10811 /* Prepare the table for unknown operations */
10812 for(i=0; i<= SMB_NOPCODES; i++) {
10813 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10815 /* Fill in the ones we do know */
10816 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10817 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10818 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10819 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10820 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10821 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10822 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10823 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10824 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10825 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10826 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10827 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10828 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10829 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10830 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10831 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10832 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10833 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10834 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10835 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10836 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10837 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10838 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10839 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10840 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10841 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10842 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10843 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10844 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10845 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10846 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10847 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10848 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10849 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10850 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10851 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10852 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10853 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10854 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10855 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10856 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10857 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10858 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10859 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10860 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10861 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10862 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10863 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10864 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10865 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10866 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10867 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10868 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10869 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10870 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10871 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10872 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10873 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10874 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10875 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10876 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10877 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10878 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10879 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10880 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10881 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10882 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10883 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10884 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10885 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10886 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10887 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10888 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10889 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10891 /* setup tran 2 dispatch table */
10892 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10893 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10894 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10895 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10896 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10897 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10898 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10899 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10900 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10901 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10902 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10903 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10904 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10905 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10906 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10907 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10908 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10909 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10911 /* setup the rap dispatch table */
10912 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10913 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10914 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10915 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10916 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10920 /* if we are doing SMB authentication we have register outselves as a logon process */
10921 if (smb_authType != SMB_AUTH_NONE) {
10922 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10923 LSA_STRING afsProcessName;
10924 LSA_OPERATIONAL_MODE dummy; /*junk*/
10926 afsProcessName.Buffer = "OpenAFSClientDaemon";
10927 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10928 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10930 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10932 if (nts == STATUS_SUCCESS) {
10933 LSA_STRING packageName;
10934 /* we are registered. Find out the security package id */
10935 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10936 packageName.Length = (USHORT)strlen(packageName.Buffer);
10937 packageName.MaximumLength = packageName.Length + 1;
10938 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10939 if (nts == STATUS_SUCCESS) {
10941 * This code forces Windows to authenticate against the Logon Cache
10942 * first instead of attempting to authenticate against the Domain
10943 * Controller. When the Windows logon cache is enabled this improves
10944 * performance by removing the network access and works around a bug
10945 * seen at sites which are using a MIT Kerberos principal to login
10946 * to machines joined to a non-root domain in a multi-domain forest.
10947 * MsV1_0SetProcessOption was added in Windows XP.
10949 PVOID pResponse = NULL;
10950 ULONG cbResponse = 0;
10951 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10953 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10954 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10955 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10956 OptionsRequest.DisableOptions = FALSE;
10958 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10961 sizeof(OptionsRequest),
10967 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10968 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10971 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10973 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10974 afsi_log("MsV1_0SetProcessOption success");
10976 /* END - code from Larry */
10978 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10979 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10980 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10982 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10984 /* something went wrong. We report the error and revert back to no authentication
10985 because we can't perform any auth requests without a successful lsa handle
10986 or sec package id. */
10987 afsi_log("Reverting to NO SMB AUTH");
10988 smb_authType = SMB_AUTH_NONE;
10991 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10993 /* something went wrong. We report the error and revert back to no authentication
10994 because we can't perform any auth requests without a successful lsa handle
10995 or sec package id. */
10996 afsi_log("Reverting to NO SMB AUTH");
10997 smb_authType = SMB_AUTH_NONE;
11001 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
11002 * time prevents the failure of authentication when logged into Windows with an
11003 * external Kerberos principal mapped to a local account.
11005 else if ( smb_authType == SMB_AUTH_EXTENDED) {
11006 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
11007 * then the only option is NTLMSSP anyway; so just fallback.
11012 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
11013 if (secBlobLength == 0) {
11014 smb_authType = SMB_AUTH_NTLM;
11015 afsi_log("Reverting to SMB AUTH NTLM");
11024 /* Now get ourselves a domain name. */
11025 /* For now we are using the local computer name as the domain name.
11026 * It is actually the domain for local logins, and we are acting as
11027 * a local SMB server.
11029 bufsize = lengthof(smb_ServerDomainName) - 1;
11030 GetComputerNameW(smb_ServerDomainName, &bufsize);
11031 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
11032 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
11035 /* Start listeners, waiters, servers, and daemons */
11036 if (startListeners)
11037 smb_StartListeners(1);
11039 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
11040 NULL, 0, &lpid, "smb_ClientWaiter");
11041 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
11042 thrd_CloseHandle(phandle);
11044 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
11045 NULL, 0, &lpid, "smb_ServerWaiter");
11046 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
11047 thrd_CloseHandle(phandle);
11049 for (i=0; i<smb_NumServerThreads; i++) {
11050 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
11051 (void *) i, 0, &lpid, "smb_Server");
11052 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
11053 thrd_CloseHandle(phandle);
11056 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
11057 NULL, 0, &lpid, "smb_Daemon");
11058 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
11059 thrd_CloseHandle(phandle);
11061 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
11062 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
11063 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
11064 thrd_CloseHandle(phandle);
11066 if (smb_monitorReqs) {
11067 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
11068 NULL, 0, &lpid, "smb_ServerMonitor");
11069 osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
11070 thrd_CloseHandle(phandle);
11073 lock_ReleaseMutex(&smb_StartedLock);
11077 void smb_Shutdown(void)
11084 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11086 /* setup the NCB system */
11087 ncbp = smb_GetNCB();
11089 /* Block new sessions by setting shutdown flag */
11090 smbShutdownFlag = 1;
11092 /* Hang up all sessions */
11093 memset(ncbp, 0, sizeof(NCB));
11094 for (i = 1; i < numSessions; i++)
11096 if (dead_sessions[i])
11099 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11100 ncbp->ncb_command = NCBHANGUP;
11101 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
11102 ncbp->ncb_lsn = (UCHAR)LSNs[i];
11103 code = Netbios(ncbp);
11104 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11105 if (code == 0) code = ncbp->ncb_retcode;
11107 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11108 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11112 /* Trigger the shutdown of all SMB threads */
11113 for (i = 0; i < smb_NumServerThreads; i++)
11114 thrd_SetEvent(NCBreturns[i][0]);
11116 thrd_SetEvent(NCBevents[0]);
11117 thrd_SetEvent(SessionEvents[0]);
11118 thrd_SetEvent(NCBavails[0]);
11120 for (i = 0;i < smb_NumServerThreads; i++) {
11121 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11122 if (code == WAIT_OBJECT_0) {
11125 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11126 thrd_SetEvent(NCBreturns[i--][0]);
11130 /* Delete Netbios name */
11131 memset(ncbp, 0, sizeof(NCB));
11132 for (i = 0; i < lana_list.length; i++) {
11133 if (lana_list.lana[i] == LANA_INVALID) continue;
11134 ncbp->ncb_command = NCBDELNAME;
11135 ncbp->ncb_lana_num = lana_list.lana[i];
11136 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11137 code = Netbios(ncbp);
11139 code = ncbp->ncb_retcode;
11141 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11142 ncbp->ncb_lana_num, code);
11147 /* Release the reference counts held by the VCs */
11148 lock_ObtainWrite(&smb_rctLock);
11149 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11154 if (vcp->magic != SMB_VC_MAGIC)
11155 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11156 __FILE__, __LINE__);
11158 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11160 if (fidp->scp != NULL) {
11163 lock_ReleaseWrite(&smb_rctLock);
11164 lock_ObtainMutex(&fidp->mx);
11165 if (fidp->scp != NULL) {
11168 lock_ObtainWrite(&scp->rw);
11169 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11170 lock_ReleaseWrite(&scp->rw);
11171 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11172 cm_ReleaseSCache(scp);
11174 lock_ReleaseMutex(&fidp->mx);
11175 lock_ObtainWrite(&smb_rctLock);
11179 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11181 smb_ReleaseVCNoLock(tidp->vcp);
11183 cm_user_t *userp = tidp->userp;
11184 tidp->userp = NULL;
11185 cm_ReleaseUser(userp);
11189 lock_ReleaseWrite(&smb_rctLock);
11192 if (smb_monitorReqs) {
11193 smb_ShutdownMonitor();
11197 /* Get the UNC \\<servername>\<sharename> prefix. */
11198 char *smb_GetSharename()
11203 /* Make sure we have been properly initialized. */
11204 if (smb_localNamep == NULL)
11207 /* Allocate space for \\<servername>\<sharename>, plus the
11210 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11211 name = malloc(len);
11212 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11218 void smb_LogPacket(smb_packet_t *packet)
11222 unsigned length, paramlen, datalen, i, j;
11224 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11226 if (!packet) return;
11228 osi_Log0(smb_logp, "*** SMB packet dump ***");
11230 smbp = (smb_t *) packet->data;
11231 vp = (BYTE *) packet->data;
11233 paramlen = smbp->wct * 2;
11234 datalen = *((WORD *) (smbp->vdata + paramlen));
11235 length = sizeof(*smbp) + paramlen + 1 + datalen;
11237 for (i=0;i < length; i+=16)
11239 memset( buf, ' ', 80 );
11242 itoa( i, buf, 16 );
11244 buf[strlen(buf)] = ' ';
11246 cp = (BYTE*) buf + 7;
11248 for (j=0;j < 16 && (i+j)<length; j++)
11250 *(cp++) = hex[vp[i+j] >> 4];
11251 *(cp++) = hex[vp[i+j] & 0xf];
11261 for (j=0;j < 16 && (i+j)<length;j++)
11263 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11274 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11277 osi_Log0(smb_logp, "*** End SMB packet dump ***");
11279 #endif /* LOG_PACKET */
11282 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11288 smb_username_t *unp;
11289 smb_waitingLockRequest_t *wlrp;
11292 lock_ObtainRead(&smb_rctLock);
11294 sprintf(output, "begin dumping smb_username_t\r\n");
11295 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11296 for (unp = usernamesp; unp; unp=unp->nextp)
11298 cm_ucell_t *ucellp;
11300 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11301 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11302 unp->name ? unp->name : _C("NULL"),
11303 unp->machine ? unp->machine : _C("NULL"));
11304 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11306 sprintf(output, " begin dumping cm_ucell_t\r\n");
11307 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11309 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11310 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",
11311 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11312 ucellp->expirationTime, ucellp->gen,
11314 ucellp->cellp->name);
11315 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11318 sprintf(output, " done dumping cm_ucell_t\r\n");
11319 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11322 sprintf(output, "done dumping smb_username_t\r\n");
11323 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11326 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11327 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11330 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11331 smb_waitingLock_t *lockp;
11333 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11334 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11335 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11337 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
11338 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11339 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11340 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11341 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11342 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11344 sprintf(output, " done dumping smb_waitingLock_t\r\n");
11345 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11348 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11349 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11351 sprintf(output, "begin dumping smb_vc_t\r\n");
11352 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11354 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11360 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11361 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11362 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11364 sprintf(output, " begin dumping smb_user_t\r\n");
11365 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11366 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11367 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11368 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11369 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11371 sprintf(output, " done dumping smb_user_t\r\n");
11372 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11374 sprintf(output, " begin dumping smb_tid_t\r\n");
11375 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11376 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11377 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",
11378 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11379 tidp->pathname ? tidp->pathname : _C("NULL"));
11380 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11382 sprintf(output, " done dumping smb_tid_t\r\n");
11383 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11385 sprintf(output, " begin dumping smb_fid_t\r\n");
11386 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11388 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11390 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",
11391 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11392 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11393 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11394 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11397 sprintf(output, " done dumping smb_fid_t\r\n");
11398 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11401 sprintf(output, "done dumping smb_vc_t\r\n");
11402 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11404 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11405 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11407 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11413 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11414 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11415 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11417 sprintf(output, " begin dumping smb_user_t\r\n");
11418 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11419 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11420 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11421 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11422 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11424 sprintf(output, " done dumping smb_user_t\r\n");
11425 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11427 sprintf(output, " begin dumping smb_tid_t\r\n");
11428 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11429 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11430 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",
11431 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11432 tidp->pathname ? tidp->pathname : _C("NULL"));
11433 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11435 sprintf(output, " done dumping smb_tid_t\r\n");
11436 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11438 sprintf(output, " begin dumping smb_fid_t\r\n");
11439 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11441 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11443 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",
11444 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11445 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11446 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11447 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11450 sprintf(output, " done dumping smb_fid_t\r\n");
11451 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11454 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11455 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11458 lock_ReleaseRead(&smb_rctLock);
11462 long smb_IsNetworkStarted(void)
11465 lock_ObtainWrite(&smb_globalLock);
11466 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11467 lock_ReleaseWrite(&smb_globalLock);