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) {
777 /* We must obtain a challenge for extended auth
778 * in case the client negotiates smb v3
780 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
781 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
782 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
783 ULONG lsaRespSize = 0;
785 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
787 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
794 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
795 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
796 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
797 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
798 nts, ntsEx, lsaRespSize);
800 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
802 if (ntsEx == STATUS_SUCCESS) {
803 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
806 * This will cause the subsequent authentication to fail but
807 * that is better than us dereferencing a NULL pointer and
810 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
813 LsaFreeReturnBuffer(lsaResp);
816 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
818 if (numVCs >= CM_SESSION_RESERVED) {
820 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
823 #ifdef DEBUG_SMB_REFCOUNT
825 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
826 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
829 lock_ReleaseWrite(&smb_rctLock);
830 lock_ReleaseWrite(&smb_globalLock);
834 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
839 for(i=0; i<11; i++) {
841 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
847 static int smb_IsStarMask(clientchar_t *maskp)
853 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
859 #ifdef DEBUG_SMB_REFCOUNT
860 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
861 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
863 void smb_ReleaseVCInternal(smb_vc_t *vcp)
869 lock_AssertWrite(&smb_rctLock);
872 if (vcp->refCount == 0) {
873 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
874 #ifdef DEBUG_SMB_REFCOUNT
875 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
876 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
878 /* remove VCP from smb_deadVCsp */
879 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
885 lock_FinalizeMutex(&vcp->mx);
886 memset(vcp,0,sizeof(smb_vc_t));
889 #ifdef DEBUG_SMB_REFCOUNT
890 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
892 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
896 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
897 avcp?"":"not ",vcp, vcp->refCount);
899 /* This is a wrong. However, I suspect that there is an undercount
900 * and I don't want to release 1.4.1 in a state that will allow
901 * smb_vc_t objects to be deallocated while still in the
902 * smb_allVCsp list. The list is supposed to keep a reference
903 * to the smb_vc_t. Put it back.
907 #ifdef DEBUG_SMB_REFCOUNT
908 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
909 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
913 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
914 /* The reference count is non-zero but the VC is dead.
915 * This implies that some FIDs, TIDs, etc on the VC have yet to
916 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
917 * add a reference that will be dropped by
918 * smb_CleanupDeadVC() and try to cleanup the VC again.
919 * Eventually the refCount will drop to zero when all of the
920 * active threads working with the VC end their task.
922 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
923 vcp->refCount++; /* put the refCount back */
924 lock_ReleaseWrite(&smb_rctLock);
925 smb_CleanupDeadVC(vcp);
926 #ifdef DEBUG_SMB_REFCOUNT
927 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
928 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
930 lock_ObtainWrite(&smb_rctLock);
933 #ifdef DEBUG_SMB_REFCOUNT
934 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
935 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
940 #ifdef DEBUG_SMB_REFCOUNT
941 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
943 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
946 lock_AssertWrite(&smb_rctLock);
947 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
948 smb_ReleaseVCInternal(vcp);
951 #ifdef DEBUG_SMB_REFCOUNT
952 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
954 void smb_ReleaseVC(smb_vc_t *vcp)
957 lock_ObtainWrite(&smb_rctLock);
958 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
959 smb_ReleaseVCInternal(vcp);
960 lock_ReleaseWrite(&smb_rctLock);
963 #ifdef DEBUG_SMB_REFCOUNT
964 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
966 void smb_HoldVCNoLock(smb_vc_t *vcp)
969 lock_AssertWrite(&smb_rctLock);
971 #ifdef DEBUG_SMB_REFCOUNT
972 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
973 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
975 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
979 #ifdef DEBUG_SMB_REFCOUNT
980 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
982 void smb_HoldVC(smb_vc_t *vcp)
985 lock_ObtainWrite(&smb_rctLock);
987 #ifdef DEBUG_SMB_REFCOUNT
988 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
989 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
991 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
993 lock_ReleaseWrite(&smb_rctLock);
996 void smb_CleanupDeadVC(smb_vc_t *vcp)
1001 smb_tid_t *tidpIter;
1002 smb_tid_t *tidpNext;
1004 smb_user_t *uidpIter;
1005 smb_user_t *uidpNext;
1007 afs_uint32 refCount = 0;
1009 lock_ObtainMutex(&vcp->mx);
1010 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1011 lock_ReleaseMutex(&vcp->mx);
1012 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1015 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1016 lock_ReleaseMutex(&vcp->mx);
1017 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1019 lock_ObtainWrite(&smb_rctLock);
1020 /* remove VCP from smb_allVCsp */
1021 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1022 if ((*vcpp)->magic != SMB_VC_MAGIC)
1023 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1024 __FILE__, __LINE__);
1027 vcp->nextp = smb_deadVCsp;
1029 /* Hold onto the reference until we are done with this function */
1034 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1035 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1037 if (fidpIter->deleteOk)
1040 fid = fidpIter->fid;
1041 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1043 smb_HoldFIDNoLock(fidpIter);
1044 lock_ReleaseWrite(&smb_rctLock);
1046 smb_CloseFID(vcp, fidpIter, NULL, 0);
1047 smb_ReleaseFID(fidpIter);
1049 lock_ObtainWrite(&smb_rctLock);
1050 fidpNext = vcp->fidsp;
1053 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1054 tidpNext = tidpIter->nextp;
1055 if (tidpIter->deleteOk)
1057 tidpIter->deleteOk = 1;
1059 tid = tidpIter->tid;
1060 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1062 smb_HoldTIDNoLock(tidpIter);
1063 smb_ReleaseTID(tidpIter, TRUE);
1064 tidpNext = vcp->tidsp;
1067 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1068 uidpNext = uidpIter->nextp;
1069 if (uidpIter->deleteOk)
1071 uidpIter->deleteOk = 1;
1073 /* do not add an additional reference count for the smb_user_t
1074 * as the smb_vc_t already is holding a reference */
1075 lock_ReleaseWrite(&smb_rctLock);
1077 smb_ReleaseUID(uidpIter);
1079 lock_ObtainWrite(&smb_rctLock);
1080 uidpNext = vcp->usersp;
1083 /* The vcp is now on the deadVCsp list. We intentionally drop the
1084 * reference so that the refcount can reach 0 and we can delete it
1086 * If the refCount == 1 going into the ReleaseVCNoLock call
1087 * the object will be freed and it won't be safe to clear
1090 refCount = vcp->refCount;
1091 smb_ReleaseVCNoLock(vcp);
1093 lock_ObtainMutex(&vcp->mx);
1094 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1095 lock_ReleaseMutex(&vcp->mx);
1098 lock_ReleaseWrite(&smb_rctLock);
1099 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1102 #ifdef DEBUG_SMB_REFCOUNT
1103 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1105 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1110 lock_ObtainWrite(&smb_rctLock);
1112 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1113 if (tidp->refCount == 0 && tidp->deleteOk) {
1115 smb_ReleaseTID(tidp, TRUE);
1119 if (tid == tidp->tid) {
1124 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1125 tidp = malloc(sizeof(*tidp));
1126 memset(tidp, 0, sizeof(*tidp));
1127 tidp->nextp = vcp->tidsp;
1130 smb_HoldVCNoLock(vcp);
1132 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1135 #ifdef DEBUG_SMB_REFCOUNT
1137 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1138 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1141 lock_ReleaseWrite(&smb_rctLock);
1145 #ifdef DEBUG_SMB_REFCOUNT
1146 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1148 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1151 lock_AssertWrite(&smb_rctLock);
1153 #ifdef DEBUG_SMB_REFCOUNT
1154 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1155 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1159 #ifdef DEBUG_SMB_REFCOUNT
1160 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1162 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1167 cm_user_t *userp = NULL;
1168 smb_vc_t *vcp = NULL;
1171 lock_ObtainWrite(&smb_rctLock);
1173 lock_AssertWrite(&smb_rctLock);
1175 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1176 #ifdef DEBUG_SMB_REFCOUNT
1177 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1178 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1180 if (tidp->refCount == 0) {
1181 if (tidp->deleteOk) {
1182 ltpp = &tidp->vcp->tidsp;
1183 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1187 osi_assertx(tp != NULL, "null smb_tid_t");
1189 lock_FinalizeMutex(&tidp->mx);
1190 userp = tidp->userp; /* remember to drop ref later */
1198 smb_ReleaseVCNoLock(vcp);
1200 lock_ReleaseWrite(&smb_rctLock);
1202 cm_ReleaseUser(userp);
1205 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1207 smb_user_t *uidp = NULL;
1209 lock_ObtainWrite(&smb_rctLock);
1210 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1211 if (uid == uidp->userID) {
1213 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1215 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1219 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1220 uidp = malloc(sizeof(*uidp));
1221 memset(uidp, 0, sizeof(*uidp));
1222 uidp->nextp = vcp->usersp;
1223 uidp->refCount = 2; /* one for the vcp and one for the caller */
1225 smb_HoldVCNoLock(vcp);
1227 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1229 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1231 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1233 lock_ReleaseWrite(&smb_rctLock);
1237 afs_int32 smb_userIsLocalSystem(smb_user_t *uidp)
1240 DWORD dwSize1 = 0, dwSize2 = 0;
1241 wchar_t *pszRefDomain = NULL;
1242 SID_NAME_USE snu = SidTypeGroup;
1243 clientchar_t * secSidString = NULL;
1245 afs_int32 isSystem = 0;
1247 if (uidp->unp->flags & SMB_USERNAMEFLAG_SID) {
1248 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, uidp->unp->name);
1253 * The input name is not a SID for the user. See if we can
1254 * obtain the SID for the specified name. If we can, use
1255 * that instead of the name provided for the comparison.
1258 LookupAccountNameW( NULL /* System Name to begin Search */,
1263 gle = GetLastError();
1264 if (gle == ERROR_INSUFFICIENT_BUFFER) {
1265 pSid = malloc(dwSize1);
1267 * Although dwSize2 is supposed to include the terminating
1268 * NUL character, on Win7 it does not.
1270 pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
1273 if ( pSid && pszRefDomain ) {
1274 memset(pSid, 0, dwSize1);
1276 if (LookupAccountNameW( NULL /* System Name to begin Search */,
1279 pszRefDomain, &dwSize2,
1281 ConvertSidToStringSidW(pSid, &secSidString);
1285 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, secSidString);
1286 LocalFree(secSidString);
1297 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1300 smb_username_t *unp= NULL;
1302 lock_ObtainWrite(&smb_rctLock);
1303 for(unp = usernamesp; unp; unp = unp->nextp) {
1304 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1305 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1310 if (!unp && (flags & SMB_FLAG_CREATE)) {
1311 unp = malloc(sizeof(*unp));
1312 memset(unp, 0, sizeof(*unp));
1314 unp->nextp = usernamesp;
1315 unp->name = cm_ClientStrDup(usern);
1316 unp->machine = cm_ClientStrDup(machine);
1318 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1319 if (flags & SMB_FLAG_AFSLOGON)
1320 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1323 lock_ReleaseWrite(&smb_rctLock);
1327 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1329 smb_user_t *uidp= NULL;
1331 lock_ObtainWrite(&smb_rctLock);
1332 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1335 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1337 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1338 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1343 lock_ReleaseWrite(&smb_rctLock);
1347 void smb_ReleaseUsername(smb_username_t *unp)
1350 smb_username_t **lupp;
1351 cm_user_t *userp = NULL;
1352 time_t now = osi_Time();
1354 lock_ObtainWrite(&smb_rctLock);
1355 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1356 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1357 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1359 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1363 osi_assertx(up != NULL, "null smb_username_t");
1365 up->nextp = NULL; /* do not remove this */
1366 lock_FinalizeMutex(&unp->mx);
1372 lock_ReleaseWrite(&smb_rctLock);
1374 cm_ReleaseUser(userp);
1377 void smb_HoldUIDNoLock(smb_user_t *uidp)
1379 lock_AssertWrite(&smb_rctLock);
1383 void smb_ReleaseUID(smb_user_t *uidp)
1387 smb_username_t *unp = NULL;
1389 lock_ObtainWrite(&smb_rctLock);
1390 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1391 if (uidp->refCount == 0) {
1392 lupp = &uidp->vcp->usersp;
1393 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1397 osi_assertx(up != NULL, "null smb_user_t");
1399 lock_FinalizeMutex(&uidp->mx);
1401 smb_ReleaseVCNoLock(uidp->vcp);
1405 lock_ReleaseWrite(&smb_rctLock);
1409 cm_ReleaseUserVCRef(unp->userp);
1410 smb_ReleaseUsername(unp);
1414 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1416 cm_user_t *up = NULL;
1421 lock_ObtainMutex(&uidp->mx);
1423 up = uidp->unp->userp;
1426 lock_ReleaseMutex(&uidp->mx);
1432 /* retrieve a held reference to a user structure corresponding to an incoming
1434 * corresponding release function is cm_ReleaseUser.
1436 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1439 cm_user_t *up = NULL;
1442 smbp = (smb_t *) inp;
1443 uidp = smb_FindUID(vcp, smbp->uid, 0);
1447 up = smb_GetUserFromUID(uidp);
1449 smb_ReleaseUID(uidp);
1454 * Return a pointer to a pathname extracted from a TID structure. The
1455 * TID structure is not held; assume it won't go away.
1457 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1462 tidp = smb_FindTID(vcp, tid, 0);
1466 if (tidp->flags & SMB_TIDFLAG_IPC) {
1467 code = CM_ERROR_TIDIPC;
1468 /* tidp->pathname would be NULL, but that's fine */
1470 *treepath = tidp->pathname;
1471 smb_ReleaseTID(tidp, FALSE);
1476 /* check to see if we have a chained fid, that is, a fid that comes from an
1477 * OpenAndX message that ran earlier in this packet. In this case, the fid
1478 * field in a read, for example, request, isn't set, since the value is
1479 * supposed to be inherited from the openAndX call.
1481 int smb_ChainFID(int fid, smb_packet_t *inp)
1483 if (inp->fid == 0 || inp->inCount == 0)
1489 /* are we a priv'd user? What does this mean on NT? */
1490 int smb_SUser(cm_user_t *userp)
1495 /* find a file ID. If we pass in 0 we select an unused File ID.
1496 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1497 * smb_fid_t data structure if desired File ID cannot be found.
1499 #ifdef DEBUG_SMB_REFCOUNT
1500 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1502 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1509 if (!(flags & SMB_FLAG_CREATE))
1514 lock_ObtainWrite(&smb_rctLock);
1516 fid = vcp->fidCounter;
1519 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1520 if (fidp->refCount == 0 && fidp->deleteOk) {
1522 lock_ReleaseWrite(&smb_rctLock);
1523 smb_ReleaseFID(fidp);
1524 lock_ObtainWrite(&smb_rctLock);
1526 * We dropped the smb_rctLock so the fid value we are using
1527 * may now be used by another thread. Start over with the
1528 * current vcp->fidCounter.
1531 fid = vcp->fidCounter;
1534 if (fid == fidp->fid) {
1536 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1538 if (fid == 0xFFFF) {
1540 "New FID number wraps on vcp 0x%x", vcp);
1550 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1551 char eventName[MAX_PATH];
1555 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1557 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1559 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1560 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1561 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1562 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1563 thrd_CloseHandle(event);
1565 if (fid == 0xFFFF) {
1566 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1572 fidp = malloc(sizeof(*fidp));
1573 memset(fidp, 0, sizeof(*fidp));
1574 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1577 smb_HoldVCNoLock(vcp);
1578 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1580 fidp->curr_chunk = fidp->prev_chunk = -2;
1581 fidp->raw_write_event = event;
1583 vcp->fidCounter = fid+1;
1584 if (vcp->fidCounter == 0xFFFF) {
1585 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1587 vcp->fidCounter = 1;
1592 #ifdef DEBUG_SMB_REFCOUNT
1594 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1598 lock_ReleaseWrite(&smb_rctLock);
1603 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1604 #ifdef DEBUG_SMB_REFCOUNT
1605 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1607 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1610 smb_fid_t *fidp = NULL, *nextp = NULL;
1616 * If the fidp->scp changes out from under us then
1617 * we must not grab a refCount. It means the *fidp
1618 * was processed by smb_CloseFID() and the *fidp is
1619 * no longer valid for use.
1621 lock_ObtainWrite(&smb_rctLock);
1622 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1623 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1627 if (scp == fidp->scp) {
1628 lock_ReleaseWrite(&smb_rctLock);
1629 lock_ObtainMutex(&fidp->mx);
1630 lock_ObtainWrite(&smb_rctLock);
1631 if (scp == fidp->scp) {
1632 lock_ReleaseMutex(&fidp->mx);
1635 lock_ReleaseMutex(&fidp->mx);
1638 if (fidp->refCount > 1) {
1641 lock_ReleaseWrite(&smb_rctLock);
1642 smb_ReleaseFID(fidp);
1643 lock_ObtainWrite(&smb_rctLock);
1648 if (nextp->refCount > 1) {
1651 lock_ReleaseWrite(&smb_rctLock);
1652 smb_ReleaseFID(nextp);
1653 lock_ObtainWrite(&smb_rctLock);
1657 #ifdef DEBUG_SMB_REFCOUNT
1659 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1660 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1663 lock_ReleaseWrite(&smb_rctLock);
1667 #ifdef DEBUG_SMB_REFCOUNT
1668 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1670 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1673 lock_AssertWrite(&smb_rctLock);
1675 #ifdef DEBUG_SMB_REFCOUNT
1676 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1677 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1682 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1683 /* the smb_fid_t->mx and smb_rctLock must not be held */
1684 #ifdef DEBUG_SMB_REFCOUNT
1685 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1687 void smb_ReleaseFID(smb_fid_t *fidp)
1690 cm_scache_t *scp = NULL;
1691 cm_user_t *userp = NULL;
1692 smb_vc_t *vcp = NULL;
1693 smb_ioctl_t *ioctlp;
1695 lock_ObtainMutex(&fidp->mx);
1696 lock_ObtainWrite(&smb_rctLock);
1697 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1698 #ifdef DEBUG_SMB_REFCOUNT
1699 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1700 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1702 if (fidp->refCount == 0) {
1703 if (fidp->deleteOk) {
1706 scp = fidp->scp; /* release after lock is released */
1708 lock_ObtainWrite(&scp->rw);
1709 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1710 lock_ReleaseWrite(&scp->rw);
1711 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1714 userp = fidp->userp;
1718 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1719 thrd_CloseHandle(fidp->raw_write_event);
1721 /* and see if there is ioctl stuff to free */
1722 ioctlp = fidp->ioctlp;
1725 cm_FreeSpace(ioctlp->prefix);
1726 if (ioctlp->ioctl.inAllocp)
1727 free(ioctlp->ioctl.inAllocp);
1728 if (ioctlp->ioctl.outAllocp)
1729 free(ioctlp->ioctl.outAllocp);
1733 smb_CleanupRPCFid(fidp);
1735 lock_ReleaseMutex(&fidp->mx);
1736 lock_FinalizeMutex(&fidp->mx);
1741 smb_ReleaseVCNoLock(vcp);
1745 lock_ReleaseMutex(&fidp->mx);
1747 lock_ReleaseWrite(&smb_rctLock);
1749 /* now release the scache structure */
1751 cm_ReleaseSCache(scp);
1754 cm_ReleaseUser(userp);
1758 * Case-insensitive search for one string in another;
1759 * used to find variable names in submount pathnames.
1761 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1763 clientchar_t *cursor;
1765 for (cursor = str1; *cursor; cursor++)
1766 if (cm_ClientStrCmpI(cursor, str2) == 0)
1773 * Substitute a variable value for its name in a submount pathname. Variable
1774 * name has been identified by smb_stristr() and is in substr. Variable name
1775 * length (plus one) is in substr_size. Variable value is in newstr.
1777 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1778 unsigned int substr_size, clientchar_t *newstr)
1780 clientchar_t temp[1024];
1782 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1783 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1784 cm_ClientStrCat(str1, cchstr1, temp);
1787 clientchar_t VNUserName[] = _C("%USERNAME%");
1788 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1789 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1790 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1792 typedef struct smb_findShare_rock {
1793 clientchar_t * shareName;
1794 clientchar_t * match;
1796 } smb_findShare_rock_t;
1798 #define SMB_FINDSHARE_EXACT_MATCH 1
1799 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1801 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1805 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1806 normchar_t normName[MAX_PATH];
1808 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1809 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1810 osi_LogSaveString(smb_logp, dep->name));
1814 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1815 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1816 matchType = SMB_FINDSHARE_EXACT_MATCH;
1818 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1821 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1822 vrock->matchType = matchType;
1824 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1825 return CM_ERROR_STOPNOW;
1831 /* find a shareName in the table of submounts */
1832 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1833 clientchar_t *shareName,
1834 clientchar_t **pathNamep)
1838 clientchar_t pathName[1024];
1841 clientchar_t *p, *q;
1842 fschar_t *cellname = NULL;
1845 DWORD allSubmount = 1;
1847 /* if allSubmounts == 0, only return the //mountRoot/all share
1848 * if in fact it has been been created in the subMounts table.
1849 * This is to allow sites that want to restrict access to the
1852 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1853 0, KEY_QUERY_VALUE, &parmKey);
1854 if (code == ERROR_SUCCESS) {
1855 cblen = sizeof(allSubmount);
1856 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1857 (BYTE *) &allSubmount, &cblen);
1858 if (code != ERROR_SUCCESS) {
1861 RegCloseKey (parmKey);
1864 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1869 /* In case, the all share is disabled we need to still be able
1870 * to handle ioctl requests
1872 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1873 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1877 if (MSRPC_IsWellKnownService(shareName) ||
1878 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1879 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1885 /* Check for volume references
1887 * They look like <cell>{%,#}<volume>
1889 if (cm_ClientStrChr(shareName, '%') != NULL ||
1890 cm_ClientStrChr(shareName, '#') != NULL) {
1891 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1892 /* make room for '/@vol:' + mountchar + NULL terminator*/
1894 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1895 osi_LogSaveClientString(smb_logp, shareName));
1897 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1898 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1899 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1901 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1903 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1904 cm_ClientStrLwr(*pathNamep);
1905 osi_Log1(smb_logp, " returning pathname [%S]",
1906 osi_LogSaveClientString(smb_logp, *pathNamep));
1914 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1915 0, KEY_QUERY_VALUE, &parmKey);
1916 if (code == ERROR_SUCCESS) {
1917 cblen = sizeof(pathName);
1918 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1919 (BYTE *) pathName, &cblen);
1920 if (code != ERROR_SUCCESS)
1922 RegCloseKey (parmKey);
1926 cchlen = cblen / sizeof(clientchar_t);
1927 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1928 /* We can accept either unix or PC style AFS pathnames. Convert
1929 * Unix-style to PC style here for internal use.
1932 cchlen = lengthof(pathName);
1934 /* within this code block, we maintain, cchlen = writable
1935 buffer length of p */
1937 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1938 p += cm_mountRootCLen; /* skip mount path */
1939 cchlen -= (DWORD)(p - pathName);
1944 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1950 clientchar_t temp[1024];
1952 if (var = smb_stristr(p, VNUserName)) {
1953 if (uidp && uidp->unp)
1954 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1956 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1958 else if (var = smb_stristr(p, VNLCUserName))
1960 if (uidp && uidp->unp)
1961 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1963 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1964 cm_ClientStrLwr(temp);
1965 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1967 else if (var = smb_stristr(p, VNComputerName))
1969 sizeTemp = lengthof(temp);
1970 GetComputerNameW(temp, &sizeTemp);
1971 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1973 else if (var = smb_stristr(p, VNLCComputerName))
1975 sizeTemp = lengthof(temp);
1976 GetComputerName((LPTSTR)temp, &sizeTemp);
1977 cm_ClientStrLwr(temp);
1978 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1983 *pathNamep = cm_ClientStrDup(p);
1988 /* First lookup shareName in root.afs */
1990 smb_findShare_rock_t vrock;
1992 fschar_t ftemp[1024];
1993 clientchar_t * p = shareName;
1998 /* attempt to locate a partial match in root.afs. This is because
1999 when using the ANSI RAP calls, the share name is limited to 13 chars
2000 and hence is truncated. Of course we prefer exact matches. */
2002 thyper.HighPart = 0;
2005 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2006 if (vrock.shareName == NULL)
2009 vrock.matchType = 0;
2011 userp = (uidp? (uidp->unp ? uidp->unp->userp : cm_rootUserp) : cm_rootUserp);
2012 rscp = cm_RootSCachep(userp, &req);
2013 cm_HoldSCache(rscp);
2014 code = cm_ApplyDir(rscp, smb_FindShareProc, &vrock, &thyper,
2016 cm_ReleaseSCache(rscp);
2018 free(vrock.shareName);
2019 vrock.shareName = NULL;
2021 if (vrock.matchType) {
2022 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2023 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2028 /* if we get here, there was no match for the share in root.afs */
2029 /* so try to create \\<netbiosName>\<cellname> */
2034 /* Get the full name for this cell */
2035 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2036 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2037 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2038 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2039 if (code && cm_dnsEnabled) {
2041 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2046 /* construct the path */
2048 clientchar_t temp[1024];
2050 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2051 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2052 rw ? _C("/.%S/") : _C("/%S/"), temp);
2053 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2063 /* Client-side offline caching policy types */
2064 #define CSC_POLICY_MANUAL 0
2065 #define CSC_POLICY_DOCUMENTS 1
2066 #define CSC_POLICY_PROGRAMS 2
2067 #define CSC_POLICY_DISABLE 3
2069 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2072 clientchar_t policy[1024];
2075 int retval = CSC_POLICY_MANUAL;
2077 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2078 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2081 REG_OPTION_NON_VOLATILE,
2085 NULL ) != ERROR_SUCCESS)
2086 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2088 len = sizeof(policy);
2089 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2091 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2093 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2095 retval = CSC_POLICY_MANUAL;
2097 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2099 retval = CSC_POLICY_DOCUMENTS;
2101 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2103 retval = CSC_POLICY_PROGRAMS;
2105 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2107 retval = CSC_POLICY_DISABLE;
2110 RegCloseKey(hkCSCPolicy);
2114 /* find a dir search structure by cookie value, and return it held.
2115 * Must be called with smb_globalLock held.
2117 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2119 smb_dirSearch_t *dsp;
2121 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2122 if (dsp->cookie == cookie) {
2123 if (dsp != smb_firstDirSearchp) {
2124 /* move to head of LRU queue, too, if we're not already there */
2125 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2126 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2127 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2128 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2129 if (!smb_lastDirSearchp)
2130 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2138 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2139 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2140 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2146 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2148 lock_ObtainMutex(&dsp->mx);
2149 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2150 dsp->cookie, dsp, dsp->scp);
2151 dsp->flags |= SMB_DIRSEARCH_DELETE;
2152 if (dsp->scp != NULL) {
2153 lock_ObtainWrite(&dsp->scp->rw);
2154 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2155 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2156 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2157 dsp->scp->bulkStatProgress = hzero;
2159 lock_ReleaseWrite(&dsp->scp->rw);
2161 lock_ReleaseMutex(&dsp->mx);
2164 /* Must be called with the smb_globalLock held */
2165 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2167 cm_scache_t *scp = NULL;
2169 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2170 if (dsp->refCount == 0) {
2171 lock_ObtainMutex(&dsp->mx);
2172 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2173 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2174 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2175 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2176 lock_ReleaseMutex(&dsp->mx);
2177 lock_FinalizeMutex(&dsp->mx);
2179 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2180 dsp->cookie, dsp, scp);
2183 lock_ReleaseMutex(&dsp->mx);
2186 /* do this now to avoid spurious locking hierarchy creation */
2188 cm_ReleaseSCache(scp);
2191 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2193 lock_ObtainWrite(&smb_globalLock);
2194 smb_ReleaseDirSearchNoLock(dsp);
2195 lock_ReleaseWrite(&smb_globalLock);
2198 /* find a dir search structure by cookie value, and return it held */
2199 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2201 smb_dirSearch_t *dsp;
2203 lock_ObtainWrite(&smb_globalLock);
2204 dsp = smb_FindDirSearchNoLock(cookie);
2205 lock_ReleaseWrite(&smb_globalLock);
2209 /* GC some dir search entries, in the address space expected by the specific protocol.
2210 * Must be called with smb_globalLock held; release the lock temporarily.
2212 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2213 void smb_GCDirSearches(int isV3)
2215 smb_dirSearch_t *prevp;
2216 smb_dirSearch_t *dsp;
2217 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2221 victimCount = 0; /* how many have we got so far */
2222 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2223 /* we'll move tp from queue, so
2226 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2227 /* if no one is using this guy, and we're either in the new protocol,
2228 * or we're in the old one and this is a small enough ID to be useful
2229 * to the old protocol, GC this guy.
2231 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2232 /* hold and delete */
2233 lock_ObtainMutex(&dsp->mx);
2234 dsp->flags |= SMB_DIRSEARCH_DELETE;
2235 lock_ReleaseMutex(&dsp->mx);
2236 victimsp[victimCount++] = dsp;
2240 /* don't do more than this */
2241 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2245 /* now release them */
2246 for (i = 0; i < victimCount; i++) {
2247 smb_ReleaseDirSearchNoLock(victimsp[i]);
2251 /* function for allocating a dir search entry. We need these to remember enough context
2252 * since we don't get passed the path from call to call during a directory search.
2254 * Returns a held dir search structure, and bumps the reference count on the vnode,
2255 * since it saves a pointer to the vnode.
2257 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2259 smb_dirSearch_t *dsp;
2265 lock_ObtainWrite(&smb_globalLock);
2268 /* what's the biggest ID allowed in this version of the protocol */
2269 /* TODO: do we really want a non v3 dir search request to wrap
2270 smb_dirSearchCounter? */
2271 maxAllowed = isV3 ? 65535 : 255;
2272 if (smb_dirSearchCounter > maxAllowed)
2273 smb_dirSearchCounter = 1;
2275 start = smb_dirSearchCounter;
2278 /* twice so we have enough tries to find guys we GC after one pass;
2279 * 10 extra is just in case I mis-counted.
2281 if (++counter > 2*maxAllowed+10)
2282 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2284 if (smb_dirSearchCounter > maxAllowed) {
2285 smb_dirSearchCounter = 1;
2287 if (smb_dirSearchCounter == start) {
2289 smb_GCDirSearches(isV3);
2292 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2294 /* don't need to watch for refcount zero and deleted, since
2295 * we haven't dropped the global lock.
2298 ++smb_dirSearchCounter;
2302 dsp = malloc(sizeof(*dsp));
2303 memset(dsp, 0, sizeof(*dsp));
2304 dsp->cookie = smb_dirSearchCounter;
2305 ++smb_dirSearchCounter;
2307 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2308 dsp->lastTime = osi_Time();
2309 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2310 if (!smb_lastDirSearchp)
2311 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2313 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2317 lock_ReleaseWrite(&smb_globalLock);
2321 static smb_packet_t *smb_GetPacket(void)
2325 lock_ObtainWrite(&smb_globalLock);
2326 tbp = smb_packetFreeListp;
2328 smb_packetFreeListp = tbp->nextp;
2329 lock_ReleaseWrite(&smb_globalLock);
2331 tbp = calloc(sizeof(*tbp),1);
2332 tbp->magic = SMB_PACKETMAGIC;
2335 tbp->resumeCode = 0;
2341 tbp->ncb_length = 0;
2344 tbp->stringsp = NULL;
2346 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2351 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2354 tbp = smb_GetPacket();
2355 memcpy(tbp, pkt, sizeof(smb_packet_t));
2356 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2357 tbp->stringsp = NULL;
2359 smb_HoldVC(tbp->vcp);
2363 static NCB *smb_GetNCB(void)
2368 lock_ObtainWrite(&smb_globalLock);
2369 tbp = smb_ncbFreeListp;
2371 smb_ncbFreeListp = tbp->nextp;
2372 lock_ReleaseWrite(&smb_globalLock);
2374 tbp = calloc(sizeof(*tbp),1);
2375 tbp->magic = SMB_NCBMAGIC;
2378 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2380 memset(&tbp->ncb, 0, sizeof(NCB));
2385 static void FreeSMBStrings(smb_packet_t * pkt)
2390 for (s = pkt->stringsp; s; s = ns) {
2394 pkt->stringsp = NULL;
2397 void smb_FreePacket(smb_packet_t *tbp)
2399 smb_vc_t * vcp = NULL;
2400 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2402 lock_ObtainWrite(&smb_globalLock);
2403 tbp->nextp = smb_packetFreeListp;
2404 smb_packetFreeListp = tbp;
2405 tbp->magic = SMB_PACKETMAGIC;
2409 tbp->resumeCode = 0;
2415 tbp->ncb_length = 0;
2417 FreeSMBStrings(tbp);
2418 lock_ReleaseWrite(&smb_globalLock);
2424 static void smb_FreeNCB(NCB *bufferp)
2428 tbp = (smb_ncb_t *) bufferp;
2429 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2431 lock_ObtainWrite(&smb_globalLock);
2432 tbp->nextp = smb_ncbFreeListp;
2433 smb_ncbFreeListp = tbp;
2434 lock_ReleaseWrite(&smb_globalLock);
2437 /* get a ptr to the data part of a packet, and its count */
2438 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2442 unsigned char *afterParmsp;
2444 parmBytes = *smbp->wctp << 1;
2445 afterParmsp = smbp->wctp + parmBytes + 1;
2447 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2448 if (nbytesp) *nbytesp = dataBytes;
2450 /* don't forget to skip the data byte count, since it follows
2451 * the parameters; that's where the "2" comes from below.
2453 return (unsigned char *) (afterParmsp + 2);
2456 /* must set all the returned parameters before playing around with the
2457 * data region, since the data region is located past the end of the
2458 * variable number of parameters.
2460 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2462 unsigned char *afterParmsp;
2464 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2466 *afterParmsp++ = dsize & 0xff;
2467 *afterParmsp = (dsize>>8) & 0xff;
2470 /* return the parm'th parameter in the smbp packet */
2471 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2474 unsigned char *parmDatap;
2476 parmCount = *smbp->wctp;
2478 if (parm >= parmCount) {
2481 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2482 parm, parmCount, smbp->ncb_length);
2483 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2484 parm, parmCount, smbp->ncb_length);
2485 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2486 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2487 osi_panic(s, __FILE__, __LINE__);
2489 parmDatap = smbp->wctp + (2*parm) + 1;
2491 return parmDatap[0] + (parmDatap[1] << 8);
2494 /* return the parm'th parameter in the smbp packet */
2495 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2498 unsigned char *parmDatap;
2500 parmCount = *smbp->wctp;
2502 if (parm >= parmCount) {
2505 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2506 parm, parmCount, smbp->ncb_length);
2507 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2508 parm, parmCount, smbp->ncb_length);
2509 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2510 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2511 osi_panic(s, __FILE__, __LINE__);
2513 parmDatap = smbp->wctp + (2*parm) + 1;
2515 return parmDatap[0];
2518 /* return the parm'th parameter in the smbp packet */
2519 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2522 unsigned char *parmDatap;
2524 parmCount = *smbp->wctp;
2526 if (parm + 1 >= parmCount) {
2529 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2530 parm, parmCount, smbp->ncb_length);
2531 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2532 parm, parmCount, smbp->ncb_length);
2533 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2534 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2535 osi_panic(s, __FILE__, __LINE__);
2537 parmDatap = smbp->wctp + (2*parm) + 1;
2539 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2542 /* return the parm'th parameter in the smbp packet */
2543 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2546 unsigned char *parmDatap;
2548 parmCount = *smbp->wctp;
2550 if (parm * 2 + offset >= parmCount * 2) {
2553 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2554 parm, offset, parmCount, smbp->ncb_length);
2555 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2556 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2557 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2558 parm, offset, parmCount, smbp->ncb_length);
2559 osi_panic(s, __FILE__, __LINE__);
2561 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2563 return parmDatap[0] + (parmDatap[1] << 8);
2566 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2568 unsigned char *parmDatap;
2570 /* make sure we have enough slots */
2571 if (*smbp->wctp <= slot)
2572 *smbp->wctp = slot+1;
2574 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2575 *parmDatap++ = parmValue & 0xff;
2576 *parmDatap = (parmValue>>8) & 0xff;
2579 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2581 unsigned char *parmDatap;
2583 /* make sure we have enough slots */
2584 if (*smbp->wctp <= slot)
2585 *smbp->wctp = slot+2;
2587 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2588 *parmDatap++ = parmValue & 0xff;
2589 *parmDatap++ = (parmValue>>8) & 0xff;
2590 *parmDatap++ = (parmValue>>16) & 0xff;
2591 *parmDatap = (parmValue>>24) & 0xff;
2594 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2596 unsigned char *parmDatap;
2599 /* make sure we have enough slots */
2600 if (*smbp->wctp <= slot)
2601 *smbp->wctp = slot+4;
2603 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2605 *parmDatap++ = *parmValuep++;
2608 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2610 unsigned char *parmDatap;
2612 /* make sure we have enough slots */
2613 if (*smbp->wctp <= slot) {
2614 if (smbp->oddByte) {
2616 *smbp->wctp = slot+1;
2621 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2622 *parmDatap++ = parmValue & 0xff;
2627 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2628 clientchar_t *inPathp)
2630 clientchar_t *lastSlashp;
2631 clientchar_t *streamp = NULL;
2632 clientchar_t *typep = NULL;
2634 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2635 if (lastComponentp) {
2636 *lastComponentp = lastSlashp;
2640 * If the name contains a stream name and a type
2641 * and the stream name is the nul-string and the
2642 * type is $DATA, then strip "::$DATA" from the
2643 * last component string that is returned.
2645 * Otherwise, return the full path name and allow
2646 * the file name to be rejected because it contains
2649 typep = cm_ClientStrRChr(lastSlashp, L':');
2650 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2652 streamp = cm_ClientStrRChr(lastSlashp, L':');
2653 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2657 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2658 osi_LogSaveClientString(smb_logp,streamp),
2659 osi_LogSaveClientString(smb_logp,typep));
2663 if (inPathp == lastSlashp)
2665 *outPathp++ = *inPathp++;
2674 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2675 char **chainpp, int flags)
2678 afs_uint32 type = *inp++;
2681 * The first byte specifies the type of the input string.
2682 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2686 /* Length Counted */
2687 case 0x1: /* Data Block */
2688 case 0x5: /* Variable Block */
2689 cb = *inp++ << 16 | *inp++;
2692 /* Null-terminated string */
2693 case 0x4: /* ASCII */
2694 case 0x3: /* Pathname */
2695 case 0x2: /* Dialect */
2696 cb = sizeof(pktp->data) - (inp - pktp->data);
2697 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2698 #ifdef DEBUG_UNICODE
2701 cb = sizeof(pktp->data);
2706 return NULL; /* invalid input */
2710 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2711 flags |= SMB_STRF_FORCEASCII;
2714 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2717 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2718 char ** chainpp, int flags)
2723 if (!WANTS_UNICODE(pktp))
2724 flags |= SMB_STRF_FORCEASCII;
2727 cb = sizeof(pktp->data) - (inp - pktp->data);
2728 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2729 #ifdef DEBUG_UNICODE
2732 cb = sizeof(pktp->data);
2734 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2735 flags | SMB_STRF_SRCNULTERM);
2738 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2739 size_t cb, char ** chainpp, int flags)
2742 if (!WANTS_UNICODE(pktp))
2743 flags |= SMB_STRF_FORCEASCII;
2746 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2749 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2750 size_t cch, char ** chainpp, int flags)
2755 if (!WANTS_UNICODE(pktp))
2756 flags |= SMB_STRF_FORCEASCII;
2758 cb = cch * sizeof(wchar_t);
2761 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2765 smb_ParseStringBuf(const unsigned char * bufbase,
2766 cm_space_t ** stringspp,
2767 unsigned char *inp, size_t *pcb_max,
2768 char **chainpp, int flags)
2771 if (!(flags & SMB_STRF_FORCEASCII)) {
2773 cm_space_t * spacep;
2776 if (bufbase && ((inp - bufbase) % 2) != 0) {
2777 inp++; /* unicode strings are always word aligned */
2781 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2783 cch_src = *pcb_max / sizeof(wchar_t);
2787 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2794 spacep = cm_GetSpace();
2795 spacep->nextp = *stringspp;
2796 *stringspp = spacep;
2800 *chainpp = inp + sizeof(wchar_t);
2803 *(spacep->wdata) = 0;
2804 return spacep->wdata;
2807 StringCchCopyNW(spacep->wdata,
2808 lengthof(spacep->wdata),
2809 (const clientchar_t *) inp, cch_src);
2812 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2814 return spacep->wdata;
2818 cm_space_t * spacep;
2821 /* Not using Unicode */
2823 *chainpp = inp + strlen(inp) + 1;
2826 spacep = cm_GetSpace();
2827 spacep->nextp = *stringspp;
2828 *stringspp = spacep;
2830 cchdest = lengthof(spacep->wdata);
2831 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2832 spacep->wdata, cchdest);
2834 return spacep->wdata;
2840 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2842 size_t * plen, int flags)
2848 /* we are only calculating the required size */
2855 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2857 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2858 if (!(flags & SMB_STRF_IGNORENUL))
2859 *plen += sizeof(wchar_t);
2861 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2871 cch_str = cm_ClientStrLen(str);
2872 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2875 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2883 /* if outp != NULL ... */
2885 /* Number of bytes left in the buffer.
2887 If outp lies inside the packet data buffer, we assume that the
2888 buffer is the packet data buffer. Otherwise we assume that the
2889 buffer is sizeof(packet->data).
2892 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2893 align = (int)((outp - pktp->data) % 2);
2894 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2896 align = (int)(((size_t) outp) % 2);
2897 buffersize = (int)sizeof(pktp->data);
2902 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2908 if (*str == _C('\0')) {
2910 if (buffersize < sizeof(wchar_t))
2913 *((wchar_t *) outp) = L'\0';
2914 if (plen && !(flags & SMB_STRF_IGNORENUL))
2915 *plen += sizeof(wchar_t);
2916 return outp + sizeof(wchar_t);
2919 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2921 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2922 osi_LogSaveClientString(smb_logp, str),
2928 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2930 return outp + sizeof(wchar_t) * nchars;
2938 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2941 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2943 return outp + cch_dest;
2947 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2953 tlen = inp[0] + (inp[1]<<8);
2954 inp += 2; /* skip length field */
2957 *chainpp = inp + tlen;
2966 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2970 if (*inp++ != 0x1) return NULL;
2971 tlen = inp[0] + (inp[1]<<8);
2972 inp += 2; /* skip length field */
2975 *chainpp = inp + tlen;
2978 if (lengthp) *lengthp = tlen;
2983 /* format a packet as a response */
2984 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2989 outp = (smb_t *) op;
2991 /* zero the basic structure through the smb_wct field, and zero the data
2992 * size field, assuming that wct stays zero; otherwise, you have to
2993 * explicitly set the data size field, too.
2995 inSmbp = (smb_t *) inp;
2996 memset(outp, 0, sizeof(smb_t)+2);
3002 outp->com = inSmbp->com;
3003 outp->tid = inSmbp->tid;
3004 outp->pid = inSmbp->pid;
3005 outp->uid = inSmbp->uid;
3006 outp->mid = inSmbp->mid;
3007 outp->res[0] = inSmbp->res[0];
3008 outp->res[1] = inSmbp->res[1];
3009 op->inCom = inSmbp->com;
3011 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3012 #ifdef SEND_CANONICAL_PATHNAMES
3013 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3015 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3017 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3018 outp->flg2 |= SMB_FLAGS2_UNICODE;
3021 /* copy fields in generic packet area */
3022 op->wctp = &outp->wct;
3025 /* send a (probably response) packet; vcp tells us to whom to send it.
3026 * we compute the length by looking at wct and bcc fields.
3028 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3038 ncbp = smb_GetNCB();
3042 memset(ncbp, 0, sizeof(NCB));
3044 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3045 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3046 extra += tp[0] + (tp[1]<<8);
3047 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3048 extra += 3; /* wct and length fields */
3050 ncbp->ncb_length = extra; /* bytes to send */
3051 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3052 ncbp->ncb_lana_num = vcp->lana;
3053 ncbp->ncb_command = NCBSEND; /* op means send data */
3054 ncbp->ncb_buffer = (char *) inp;/* packet */
3055 code = Netbios(ncbp);
3058 const char * s = ncb_error_string(code);
3059 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3060 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3062 lock_ObtainMutex(&vcp->mx);
3063 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3064 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3066 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3067 lock_ReleaseMutex(&vcp->mx);
3068 lock_ObtainWrite(&smb_globalLock);
3069 dead_sessions[vcp->session] = TRUE;
3070 lock_ReleaseWrite(&smb_globalLock);
3071 smb_CleanupDeadVC(vcp);
3073 lock_ReleaseMutex(&vcp->mx);
3081 void smb_MapNTError(long code, unsigned long *NTStatusp, afs_uint32 redir)
3083 unsigned long NTStatus;
3085 /* map CM_ERROR_* errors to NT 32-bit status codes */
3086 /* NT Status codes are listed in ntstatus.h not winerror.h */
3090 else if (code == CM_ERROR_NOSUCHCELL) {
3091 NTStatus = 0xC0000034L; /* Name not found */
3093 else if (code == CM_ERROR_NOSUCHVOLUME) {
3094 NTStatus = 0xC0000034L; /* Name not found */
3096 else if (code == CM_ERROR_TIMEDOUT) {
3098 NTStatus = 0xC0020052L; /* RPC_NT_COMM_FAILURE */
3101 NTStatus = 0xC00000CFL; /* Sharing Paused */
3103 /* Do not send Timeout to the SMB redirector.
3104 * It causes the redirector to drop the connection */
3105 NTStatus = 0x00000102L; /* Timeout */
3106 /* do not send Retry to the SMB redirector.
3107 * It believes the error comes from the transport
3108 * layer not from the SMB server. */
3109 NTStatus = 0xC000022DL; /* Retry */
3111 NTStatus = 0xC00000B5L; /* I/O Timeout */
3115 else if (code == CM_ERROR_RETRY) {
3117 NTStatus = 0xC000022DL; /* Retry */
3120 NTStatus = 0xC000022DL; /* Retry */
3122 NTStatus = 0xC00000B5L; /* I/O Timeout */
3126 else if (code == CM_ERROR_NOACCESS) {
3127 NTStatus = 0xC0000022L; /* Access denied */
3129 else if (code == CM_ERROR_READONLY) {
3130 NTStatus = 0xC00000A2L; /* Write protected */
3132 else if (code == CM_ERROR_NOSUCHFILE ||
3133 code == CM_ERROR_BPLUS_NOMATCH) {
3134 NTStatus = 0xC0000034L; /* Name not found */
3136 else if (code == CM_ERROR_NOSUCHPATH) {
3137 NTStatus = 0xC000003AL; /* Object path not found */
3139 else if (code == CM_ERROR_TOOBIG) {
3140 NTStatus = 0xC000007BL; /* Invalid image format */
3142 else if (code == CM_ERROR_INVAL) {
3143 NTStatus = 0xC000000DL; /* Invalid parameter */
3145 else if (code == CM_ERROR_BADFD) {
3146 NTStatus = 0xC0000008L; /* Invalid handle */
3148 else if (code == CM_ERROR_BADFDOP) {
3149 NTStatus = 0xC0000022L; /* Access denied */
3151 else if (code == CM_ERROR_UNKNOWN) {
3152 NTStatus = 0xC0000022L; /* Access denied */
3154 else if (code == CM_ERROR_EXISTS) {
3155 NTStatus = 0xC0000035L; /* Object name collision */
3157 else if (code == CM_ERROR_NOTEMPTY) {
3158 NTStatus = 0xC0000101L; /* Directory not empty */
3160 else if (code == CM_ERROR_CROSSDEVLINK) {
3161 NTStatus = 0xC00000D4L; /* Not same device */
3163 else if (code == CM_ERROR_NOTDIR) {
3164 NTStatus = 0xC0000103L; /* Not a directory */
3166 else if (code == CM_ERROR_ISDIR) {
3167 NTStatus = 0xC00000BAL; /* File is a directory */
3169 else if (code == CM_ERROR_BADOP) {
3171 /* I have no idea where this comes from */
3172 NTStatus = 0xC09820FFL; /* SMB no support */
3174 NTStatus = 0xC00000BBL; /* Not supported */
3175 #endif /* COMMENT */
3177 else if (code == CM_ERROR_BADSHARENAME) {
3178 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3180 else if (code == CM_ERROR_NOIPC) {
3182 NTStatus = 0xC0000022L; /* Access Denied */
3184 NTStatus = 0xC000013DL; /* Remote Resources */
3187 else if (code == CM_ERROR_CLOCKSKEW ||
3188 code == RXKADNOAUTH) {
3189 NTStatus = 0xC0000133L; /* Time difference at DC */
3191 else if (code == CM_ERROR_BADTID) {
3192 NTStatus = 0xC0982005L; /* SMB bad TID */
3194 else if (code == CM_ERROR_USESTD) {
3195 NTStatus = 0xC09820FBL; /* SMB use standard */
3197 else if (code == CM_ERROR_QUOTA) {
3198 NTStatus = 0xC0000044L; /* Quota exceeded */
3200 else if (code == CM_ERROR_SPACE) {
3201 NTStatus = 0xC000007FL; /* Disk full */
3203 else if (code == CM_ERROR_ATSYS) {
3204 NTStatus = 0xC0000033L; /* Object name invalid */
3206 else if (code == CM_ERROR_BADNTFILENAME) {
3207 NTStatus = 0xC0000033L; /* Object name invalid */
3209 else if (code == CM_ERROR_WOULDBLOCK) {
3210 NTStatus = 0xC00000D8L; /* Can't wait */
3212 else if (code == CM_ERROR_SHARING_VIOLATION) {
3213 NTStatus = 0xC0000043L; /* Sharing violation */
3215 else if (code == CM_ERROR_LOCK_CONFLICT) {
3216 NTStatus = 0xC0000054L; /* Lock conflict */
3218 else if (code == CM_ERROR_PARTIALWRITE) {
3219 NTStatus = 0xC000007FL; /* Disk full */
3221 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3222 NTStatus = 0xC0000023L; /* Buffer too small */
3224 else if (code == CM_ERROR_BUFFER_OVERFLOW) {
3225 NTStatus = 0x80000005L; /* Buffer overflow */
3227 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3228 NTStatus = 0xC0000035L; /* Object name collision */
3230 else if (code == CM_ERROR_BADPASSWORD) {
3231 NTStatus = 0xC000006DL; /* unknown username or bad password */
3233 else if (code == CM_ERROR_BADLOGONTYPE) {
3234 NTStatus = 0xC000015BL; /* logon type not granted */
3236 else if (code == CM_ERROR_GSSCONTINUE) {
3237 NTStatus = 0xC0000016L; /* more processing required */
3239 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3241 NTStatus = 0xC0000280L; /* reparse point not resolved */
3243 NTStatus = 0xC0000022L; /* Access Denied */
3246 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3247 NTStatus = 0xC0000257L; /* Path Not Covered */
3249 else if (code == CM_ERROR_ALLBUSY) {
3251 NTStatus = 0xC000022DL; /* Retry */
3253 NTStatus = 0xC0020018L; /* RPC_NT_SERVER_TOO_BUSY */
3256 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3258 NTStatus = 0xC000003AL; /* Path not found */
3260 NTStatus = 0xC0020017L; /* RPC_NT_SERVER_UNAVAILABLE */
3263 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3264 NTStatus = 0xC0000322L; /* No Kerberos key */
3266 else if (code == CM_ERROR_BAD_LEVEL) {
3267 NTStatus = 0xC0000148L; /* Invalid Level */
3269 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3270 NTStatus = 0xC000007EL; /* Range Not Locked */
3272 else if (code == CM_ERROR_NOSUCHDEVICE) {
3273 NTStatus = 0xC000000EL; /* No Such Device */
3275 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3276 NTStatus = 0xC0000055L; /* Lock Not Granted */
3278 else if (code == ENOMEM) {
3279 NTStatus = 0xC0000017L; /* Out of Memory */
3281 else if (code == CM_ERROR_RPC_MOREDATA) {
3282 NTStatus = 0x80000005L; /* Buffer overflow */
3286 sprintf(foo, "No mapping for 0x%X using 0xC0982001\r\n", code);
3287 OutputDebugString(foo);
3288 NTStatus = 0xC0982001L; /* SMB non-specific error */
3291 *NTStatusp = NTStatus;
3292 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3296 * NTSTATUS <-> Win32 Error Translation
3297 * http://support.microsoft.com/kb/113996
3299 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3301 unsigned long Win32E;
3303 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3307 else if (code == CM_ERROR_NOSUCHCELL) {
3308 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3310 else if (code == CM_ERROR_NOSUCHVOLUME) {
3311 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3313 else if (code == CM_ERROR_TIMEDOUT) {
3315 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3317 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3320 else if (code == CM_ERROR_RETRY) {
3321 Win32E = ERROR_RETRY; /* Retry */
3323 else if (code == CM_ERROR_NOACCESS) {
3324 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3326 else if (code == CM_ERROR_READONLY) {
3327 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3329 else if (code == CM_ERROR_NOSUCHFILE ||
3330 code == CM_ERROR_BPLUS_NOMATCH) {
3331 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3333 else if (code == CM_ERROR_NOSUCHPATH) {
3334 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3336 else if (code == CM_ERROR_TOOBIG) {
3337 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3339 else if (code == CM_ERROR_INVAL) {
3340 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3342 else if (code == CM_ERROR_BADFD) {
3343 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3345 else if (code == CM_ERROR_BADFDOP) {
3346 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3348 else if (code == CM_ERROR_UNKNOWN) {
3349 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3351 else if (code == CM_ERROR_EXISTS) {
3352 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3354 else if (code == CM_ERROR_NOTEMPTY) {
3355 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3357 else if (code == CM_ERROR_CROSSDEVLINK) {
3358 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3360 else if (code == CM_ERROR_NOTDIR) {
3361 Win32E = ERROR_DIRECTORY; /* Not a directory */
3363 else if (code == CM_ERROR_ISDIR) {
3364 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3366 else if (code == CM_ERROR_BADOP) {
3367 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3369 else if (code == CM_ERROR_BADSHARENAME) {
3370 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3372 else if (code == CM_ERROR_NOIPC) {
3374 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3376 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3379 else if (code == CM_ERROR_CLOCKSKEW ||
3380 code == RXKADNOAUTH) {
3381 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3383 else if (code == CM_ERROR_BADTID) {
3384 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3386 else if (code == CM_ERROR_USESTD) {
3387 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3389 else if (code == CM_ERROR_QUOTA) {
3390 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3392 else if (code == CM_ERROR_SPACE) {
3393 Win32E = ERROR_DISK_FULL; /* Disk full */
3395 else if (code == CM_ERROR_ATSYS) {
3396 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3398 else if (code == CM_ERROR_BADNTFILENAME) {
3399 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3401 else if (code == CM_ERROR_WOULDBLOCK) {
3402 Win32E = WAIT_TIMEOUT; /* Can't wait */
3404 else if (code == CM_ERROR_SHARING_VIOLATION) {
3405 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3407 else if (code == CM_ERROR_LOCK_CONFLICT) {
3408 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3410 else if (code == CM_ERROR_PARTIALWRITE) {
3411 Win32E = ERROR_DISK_FULL; /* Disk full */
3413 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3414 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3416 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3417 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3419 else if (code == CM_ERROR_BADPASSWORD) {
3420 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3422 else if (code == CM_ERROR_BADLOGONTYPE) {
3423 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3425 else if (code == CM_ERROR_GSSCONTINUE) {
3426 Win32E = ERROR_MORE_DATA; /* more processing required */
3428 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3430 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3432 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3435 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3436 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3438 else if (code == CM_ERROR_ALLBUSY) {
3439 Win32E = ERROR_RETRY; /* Retry */
3441 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3442 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3444 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3445 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3447 else if (code == CM_ERROR_BAD_LEVEL) {
3448 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3450 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3451 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3453 else if (code == CM_ERROR_NOSUCHDEVICE) {
3454 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3456 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3457 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3459 else if (code == ENOMEM) {
3460 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3462 else if (code == CM_ERROR_RPC_MOREDATA) {
3463 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3466 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3470 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3473 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3474 unsigned char *classp)
3476 unsigned char class;
3477 unsigned short error;
3479 /* map CM_ERROR_* errors to SMB errors */
3480 if (code == CM_ERROR_NOSUCHCELL) {
3482 error = 3; /* bad path */
3484 else if (code == CM_ERROR_NOSUCHVOLUME) {
3486 error = 3; /* bad path */
3488 else if (code == CM_ERROR_TIMEDOUT) {
3490 error = 81; /* server is paused */
3492 else if (code == CM_ERROR_RETRY) {
3493 class = 2; /* shouldn't happen */
3496 else if (code == CM_ERROR_NOACCESS) {
3498 error = 4; /* bad access */
3500 else if (code == CM_ERROR_READONLY) {
3502 error = 19; /* read only */
3504 else if (code == CM_ERROR_NOSUCHFILE ||
3505 code == CM_ERROR_BPLUS_NOMATCH) {
3507 error = 2; /* ENOENT! */
3509 else if (code == CM_ERROR_NOSUCHPATH) {
3511 error = 3; /* Bad path */
3513 else if (code == CM_ERROR_TOOBIG) {
3515 error = 11; /* bad format */
3517 else if (code == CM_ERROR_INVAL) {
3518 class = 2; /* server non-specific error code */
3521 else if (code == CM_ERROR_BADFD) {
3523 error = 6; /* invalid file handle */
3525 else if (code == CM_ERROR_BADFDOP) {
3526 class = 1; /* invalid op on FD */
3529 else if (code == CM_ERROR_EXISTS) {
3531 error = 80; /* file already exists */
3533 else if (code == CM_ERROR_NOTEMPTY) {
3535 error = 5; /* delete directory not empty */
3537 else if (code == CM_ERROR_CROSSDEVLINK) {
3539 error = 17; /* EXDEV */
3541 else if (code == CM_ERROR_NOTDIR) {
3542 class = 1; /* bad path */
3545 else if (code == CM_ERROR_ISDIR) {
3546 class = 1; /* access denied; DOS doesn't have a good match */
3549 else if (code == CM_ERROR_BADOP) {
3553 else if (code == CM_ERROR_BADSHARENAME) {
3557 else if (code == CM_ERROR_NOIPC) {
3559 error = 4; /* bad access */
3561 else if (code == CM_ERROR_CLOCKSKEW) {
3562 class = 1; /* invalid function */
3565 else if (code == CM_ERROR_BADTID) {
3569 else if (code == CM_ERROR_USESTD) {
3573 else if (code == CM_ERROR_REMOTECONN) {
3577 else if (code == CM_ERROR_QUOTA) {
3578 if (vcp->flags & SMB_VCFLAG_USEV3) {
3580 error = 39; /* disk full */
3584 error = 5; /* access denied */
3587 else if (code == CM_ERROR_SPACE) {
3588 if (vcp->flags & SMB_VCFLAG_USEV3) {
3590 error = 39; /* disk full */
3594 error = 5; /* access denied */
3597 else if (code == CM_ERROR_PARTIALWRITE) {
3599 error = 39; /* disk full */
3601 else if (code == CM_ERROR_ATSYS) {
3603 error = 2; /* ENOENT */
3605 else if (code == CM_ERROR_WOULDBLOCK) {
3607 error = 33; /* lock conflict */
3609 else if (code == CM_ERROR_LOCK_CONFLICT) {
3611 error = 33; /* lock conflict */
3613 else if (code == CM_ERROR_SHARING_VIOLATION) {
3615 error = 33; /* lock conflict */
3617 else if (code == CM_ERROR_NOFILES) {
3619 error = 18; /* no files in search */
3621 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3623 error = 183; /* Samba uses this */
3625 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3626 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3628 error = 2; /* bad password */
3630 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3632 error = 3; /* bad path */
3641 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3644 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3646 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3647 return CM_ERROR_BADOP;
3651 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3653 unsigned short EchoCount, i;
3654 char *data, *outdata;
3657 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3659 for (i=1; i<=EchoCount; i++) {
3660 data = smb_GetSMBData(inp, &dataSize);
3661 smb_SetSMBParm(outp, 0, i);
3662 smb_SetSMBDataLength(outp, dataSize);
3663 outdata = smb_GetSMBData(outp, NULL);
3664 memcpy(outdata, data, dataSize);
3665 smb_SendPacket(vcp, outp);
3671 /* SMB_COM_READ_RAW */
3672 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3675 long count, minCount, finalCount;
3679 smb_t *smbp = (smb_t*) inp;
3681 cm_user_t *userp = NULL;
3684 char *rawBuf = NULL;
3689 fd = smb_GetSMBParm(inp, 0);
3690 count = smb_GetSMBParm(inp, 3);
3691 minCount = smb_GetSMBParm(inp, 4);
3692 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3694 if (*inp->wctp == 10) {
3695 /* we were sent a request with 64-bit file offsets */
3696 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3698 if (LargeIntegerLessThanZero(offset)) {
3699 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3703 /* we were sent a request with 32-bit file offsets */
3704 offset.HighPart = 0;
3707 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3708 fd, offset.HighPart, offset.LowPart, count);
3710 fidp = smb_FindFID(vcp, fd, 0);
3712 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3716 lock_ObtainMutex(&fidp->mx);
3718 lock_ReleaseMutex(&fidp->mx);
3719 smb_ReleaseFID(fidp);
3720 return CM_ERROR_BADFD;
3723 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3724 lock_ReleaseMutex(&fidp->mx);
3725 smb_CloseFID(vcp, fidp, NULL, 0);
3726 code = CM_ERROR_NOSUCHFILE;
3732 LARGE_INTEGER LOffset, LLength;
3735 key = cm_GenerateKey(vcp->vcID, pid, fd);
3737 LOffset.HighPart = offset.HighPart;
3738 LOffset.LowPart = offset.LowPart;
3739 LLength.HighPart = 0;
3740 LLength.LowPart = count;
3742 lock_ObtainWrite(&fidp->scp->rw);
3743 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3744 lock_ReleaseWrite(&fidp->scp->rw);
3747 lock_ReleaseMutex(&fidp->mx);
3751 lock_ObtainMutex(&smb_RawBufLock);
3753 /* Get a raw buf, from head of list */
3754 rawBuf = smb_RawBufs;
3755 smb_RawBufs = *(char **)smb_RawBufs;
3757 lock_ReleaseMutex(&smb_RawBufLock);
3759 lock_ReleaseMutex(&fidp->mx);
3763 if (fidp->flags & SMB_FID_IOCTL)
3765 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3767 /* Give back raw buffer */
3768 lock_ObtainMutex(&smb_RawBufLock);
3769 *((char **) rawBuf) = smb_RawBufs;
3771 smb_RawBufs = rawBuf;
3772 lock_ReleaseMutex(&smb_RawBufLock);
3775 lock_ReleaseMutex(&fidp->mx);
3776 smb_ReleaseFID(fidp);
3779 lock_ReleaseMutex(&fidp->mx);
3781 userp = smb_GetUserFromVCP(vcp, inp);
3783 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3789 cm_ReleaseUser(userp);
3792 smb_ReleaseFID(fidp);
3796 memset(ncbp, 0, sizeof(NCB));
3798 ncbp->ncb_length = (unsigned short) finalCount;
3799 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3800 ncbp->ncb_lana_num = vcp->lana;
3801 ncbp->ncb_command = NCBSEND;
3802 ncbp->ncb_buffer = rawBuf;
3804 code = Netbios(ncbp);
3806 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3809 /* Give back raw buffer */
3810 lock_ObtainMutex(&smb_RawBufLock);
3811 *((char **) rawBuf) = smb_RawBufs;
3813 smb_RawBufs = rawBuf;
3814 lock_ReleaseMutex(&smb_RawBufLock);
3820 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3822 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3827 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3829 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3834 /* SMB_COM_NEGOTIATE */
3835 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3842 int VistaProtoIndex;
3843 int protoIndex; /* index we're using */
3848 char protocol_array[10][1024]; /* protocol signature of the client */
3849 int caps; /* capabilities */
3852 TIME_ZONE_INFORMATION tzi;
3854 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3857 namep = smb_GetSMBData(inp, &dbytes);
3860 coreProtoIndex = -1; /* not found */
3863 VistaProtoIndex = -1;
3864 while(namex < dbytes) {
3865 osi_Log1(smb_logp, "Protocol %s",
3866 osi_LogSaveString(smb_logp, namep+1));
3867 strcpy(protocol_array[tcounter], namep+1);
3869 /* namep points at the first protocol, or really, a 0x02
3870 * byte preceding the null-terminated ASCII name.
3872 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3873 coreProtoIndex = tcounter;
3875 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3876 v3ProtoIndex = tcounter;
3878 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3879 NTProtoIndex = tcounter;
3881 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3882 VistaProtoIndex = tcounter;
3885 /* compute size of protocol entry */
3886 entryLength = (int)strlen(namep+1);
3887 entryLength += 2; /* 0x02 bytes and null termination */
3889 /* advance over this protocol entry */
3890 namex += entryLength;
3891 namep += entryLength;
3892 tcounter++; /* which proto entry we're looking at */
3895 lock_ObtainMutex(&vcp->mx);
3897 if (VistaProtoIndex != -1) {
3898 protoIndex = VistaProtoIndex;
3899 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3902 if (NTProtoIndex != -1) {
3903 protoIndex = NTProtoIndex;
3904 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3906 else if (v3ProtoIndex != -1) {
3907 protoIndex = v3ProtoIndex;
3908 vcp->flags |= SMB_VCFLAG_USEV3;
3910 else if (coreProtoIndex != -1) {
3911 protoIndex = coreProtoIndex;
3912 vcp->flags |= SMB_VCFLAG_USECORE;
3914 else protoIndex = -1;
3915 lock_ReleaseMutex(&vcp->mx);
3917 if (protoIndex == -1)
3918 return CM_ERROR_INVAL;
3919 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3920 smb_SetSMBParm(outp, 0, protoIndex);
3921 if (smb_authType != SMB_AUTH_NONE) {
3922 smb_SetSMBParmByte(outp, 1,
3923 NEGOTIATE_SECURITY_USER_LEVEL |
3924 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3926 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3928 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3929 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3930 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3931 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3932 /* The session key is not a well documented field however most clients
3933 * will echo back the session key to the server. Currently we are using
3934 * the same value for all sessions. We should generate a random value
3935 * and store it into the vcp
3937 smb_SetSMBParmLong(outp, 7, 0x1a2b3c4d); /* session key */
3939 * Tried changing the capabilities to support for W2K - defect 117695
3940 * Maybe something else needs to be changed here?
3944 smb_SetSMBParmLong(outp, 9, 0x43fd);
3946 smb_SetSMBParmLong(outp, 9, 0x251);
3949 * 32-bit error codes *
3955 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3957 NTNEGOTIATE_CAPABILITY_DFS |
3959 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3960 NTNEGOTIATE_CAPABILITY_NTFIND |
3961 NTNEGOTIATE_CAPABILITY_RAWMODE |
3962 NTNEGOTIATE_CAPABILITY_NTSMB;
3964 if ( smb_authType == SMB_AUTH_EXTENDED )
3965 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3968 if ( smb_UseUnicode ) {
3969 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3973 smb_SetSMBParmLong(outp, 9, caps);
3975 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3976 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3977 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3979 GetTimeZoneInformation(&tzi);
3980 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3982 if (smb_authType == SMB_AUTH_NTLM) {
3983 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3984 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3985 /* paste in encryption key */
3986 datap = smb_GetSMBData(outp, NULL);
3987 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3988 /* and the faux domain name */
3989 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3990 datap + MSV1_0_CHALLENGE_LENGTH,
3991 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3992 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3993 void * secBlob = NULL;
3994 int secBlobLength = 0;
3996 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3999 * The SMB specification permits the server to save a round trip
4000 * in the GSS negotiation by sending an initial security blob.
4001 * Unfortunately, doing so trips a bug in Windows 7 and Server 2008 R2
4002 * whereby the SMB 1.x redirector drops the blob on the floor after
4003 * the first connection to the server and simply attempts to reuse
4004 * the previous authentication context. This bug can be avoided by
4005 * the server sending no security blob in the SMB_COM_NEGOTIATE
4006 * response. This forces the client to send an initial GSS init_sec_context
4007 * blob under all circumstances which works around the bug in Microsoft's
4010 * Do not call smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
4013 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
4014 datap = smb_GetSMBData(outp, NULL);
4016 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
4017 datap += sizeof(smb_ServerGUID);
4020 memcpy(datap, secBlob, secBlobLength);
4022 datap += sizeof(secBlobLength);
4025 smb_SetSMBParmByte(outp, 16, 0);/* Challenge length */
4026 smb_SetSMBDataLength(outp, smb_ServerDomainNameLength);
4027 datap = smb_GetSMBData(outp, NULL);
4028 /* the faux domain name */
4029 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4031 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4034 else if (v3ProtoIndex != -1) {
4035 smb_SetSMBParm(outp, 0, protoIndex);
4037 /* NOTE: Extended authentication cannot be negotiated with v3
4038 * therefore we fail over to NTLM
4040 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4041 smb_SetSMBParm(outp, 1,
4042 NEGOTIATE_SECURITY_USER_LEVEL |
4043 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
4045 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4047 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4048 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
4049 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
4050 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
4051 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
4052 smb_SetSMBParm(outp, 7, 1);
4054 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
4055 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
4056 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
4058 GetTimeZoneInformation(&tzi);
4059 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
4061 /* NOTE: Extended authentication cannot be negotiated with v3
4062 * therefore we fail over to NTLM
4064 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4065 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
4066 smb_SetSMBParm(outp, 12, 0); /* resvd */
4067 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
4068 datap = smb_GetSMBData(outp, NULL);
4069 /* paste in a new encryption key */
4070 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4071 /* and the faux domain name */
4072 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4073 datap + MSV1_0_CHALLENGE_LENGTH,
4074 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4076 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4077 smb_SetSMBParm(outp, 12, 0); /* resvd */
4078 smb_SetSMBDataLength(outp, 0);
4081 else if (coreProtoIndex != -1) { /* not really supported anymore */
4082 smb_SetSMBParm(outp, 0, protoIndex);
4083 smb_SetSMBDataLength(outp, 0);
4088 void smb_CheckVCs(void)
4090 smb_vc_t * vcp, *nextp;
4091 smb_packet_t * outp = smb_GetPacket();
4094 lock_ObtainWrite(&smb_rctLock);
4095 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4097 if (vcp->magic != SMB_VC_MAGIC)
4098 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4099 __FILE__, __LINE__);
4101 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4103 smb_HoldVCNoLock(vcp);
4106 * obtain a reference to 'nextp' now because we drop the
4107 * smb_rctLock later and the list contents could change
4108 * or 'vcp' could be destroyed when released.
4112 smb_HoldVCNoLock(nextp);
4114 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4115 smb_ReleaseVCNoLock(vcp);
4119 smb_FormatResponsePacket(vcp, NULL, outp);
4120 smbp = (smb_t *)outp;
4121 outp->inCom = smbp->com = 0x2b /* Echo */;
4129 smb_SetSMBParm(outp, 0, 0);
4130 smb_SetSMBDataLength(outp, 0);
4131 lock_ReleaseWrite(&smb_rctLock);
4133 smb_SendPacket(vcp, outp);
4135 lock_ObtainWrite(&smb_rctLock);
4136 smb_ReleaseVCNoLock(vcp);
4138 lock_ReleaseWrite(&smb_rctLock);
4139 smb_FreePacket(outp);
4142 void smb_Daemon(void *parmp)
4144 afs_uint32 count = 0;
4145 smb_username_t **unpp;
4148 while(smbShutdownFlag == 0) {
4152 if (smbShutdownFlag == 1)
4155 if ((count % 72) == 0) { /* every five minutes */
4157 time_t old_localZero = smb_localZero;
4159 /* Initialize smb_localZero */
4160 myTime.tm_isdst = -1; /* compute whether on DST or not */
4161 myTime.tm_year = 70;
4167 smb_localZero = mktime(&myTime);
4169 #ifdef AFS_FREELANCE
4170 if ( smb_localZero != old_localZero )
4171 cm_noteLocalMountPointChange(FALSE);
4177 /* GC smb_username_t objects that will no longer be used */
4179 lock_ObtainWrite(&smb_rctLock);
4180 for ( unpp=&usernamesp; *unpp; ) {
4182 smb_username_t *unp;
4184 lock_ObtainMutex(&(*unpp)->mx);
4185 if ( (*unpp)->refCount > 0 ||
4186 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4187 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4189 else if (!smb_LogoffTokenTransfer ||
4190 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4192 lock_ReleaseMutex(&(*unpp)->mx);
4200 lock_FinalizeMutex(&unp->mx);
4206 cm_ReleaseUser(userp);
4208 unpp = &(*unpp)->nextp;
4211 lock_ReleaseWrite(&smb_rctLock);
4213 /* XXX GC dir search entries */
4217 void smb_WaitingLocksDaemon()
4219 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4220 smb_waitingLock_t *wl, *wlNext;
4223 smb_packet_t *inp, *outp;
4227 while (smbShutdownFlag == 0) {
4228 lock_ObtainWrite(&smb_globalLock);
4229 nwlRequest = smb_allWaitingLocks;
4230 if (nwlRequest == NULL) {
4231 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4236 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4243 lock_ObtainWrite(&smb_globalLock);
4245 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4247 wlRequest = nwlRequest;
4248 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4249 lock_ReleaseWrite(&smb_globalLock);
4253 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4254 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4257 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4258 code = CM_ERROR_LOCK_NOT_GRANTED;
4262 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4264 /* wl->state is either _DONE or _WAITING. _ERROR
4265 would no longer be on the queue. */
4266 code = cm_RetryLock( wl->lockp,
4267 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4270 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4271 } else if (code != CM_ERROR_WOULDBLOCK) {
4272 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4277 if (code == CM_ERROR_WOULDBLOCK) {
4280 if (wlRequest->msTimeout != 0xffffffff
4281 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4293 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4296 scp = wlRequest->scp;
4297 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4301 lock_ObtainWrite(&scp->rw);
4303 for (wl = wlRequest->locks; wl; wl = wlNext) {
4304 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4306 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4307 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4308 wl->LLength, wl->key, 0, NULL, &req);
4310 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4315 lock_ReleaseWrite(&scp->rw);
4319 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4322 for (wl = wlRequest->locks; wl; wl = wlNext) {
4323 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4324 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4329 vcp = wlRequest->vcp;
4330 inp = wlRequest->inp;
4331 outp = wlRequest->outp;
4332 ncbp = smb_GetNCB();
4333 ncbp->ncb_length = inp->ncb_length;
4334 inp->spacep = cm_GetSpace();
4336 /* Remove waitingLock from list */
4337 lock_ObtainWrite(&smb_globalLock);
4338 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4340 lock_ReleaseWrite(&smb_globalLock);
4342 /* Resume packet processing */
4344 smb_SetSMBDataLength(outp, 0);
4345 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4346 outp->resumeCode = code;
4348 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4351 cm_FreeSpace(inp->spacep);
4352 smb_FreePacket(inp);
4353 smb_FreePacket(outp);
4355 cm_ReleaseSCache(wlRequest->scp);
4358 } while (nwlRequest && smbShutdownFlag == 0);
4363 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4365 osi_Log0(smb_logp, "SMB receive get disk attributes");
4367 smb_SetSMBParm(outp, 0, 32000);
4368 smb_SetSMBParm(outp, 1, 64);
4369 smb_SetSMBParm(outp, 2, 1024);
4370 smb_SetSMBParm(outp, 3, 30000);
4371 smb_SetSMBParm(outp, 4, 0);
4372 smb_SetSMBDataLength(outp, 0);
4376 /* SMB_COM_TREE_CONNECT */
4377 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4381 unsigned short newTid;
4382 clientchar_t shareName[AFSPATHMAX];
4383 clientchar_t *sharePath;
4386 clientchar_t *pathp;
4389 osi_Log0(smb_logp, "SMB receive tree connect");
4391 /* parse input parameters */
4394 tbp = smb_GetSMBData(inp, NULL);
4395 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4397 return CM_ERROR_BADSMB;
4399 tp = cm_ClientStrRChr(pathp, '\\');
4401 return CM_ERROR_BADSMB;
4402 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4404 lock_ObtainMutex(&vcp->mx);
4405 newTid = vcp->tidCounter++;
4406 lock_ReleaseMutex(&vcp->mx);
4408 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4409 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4411 return CM_ERROR_BADSMB;
4412 userp = smb_GetUserFromUID(uidp);
4413 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4414 smb_ReleaseUID(uidp);
4416 smb_ReleaseTID(tidp, FALSE);
4417 return CM_ERROR_BADSHARENAME;
4419 lock_ObtainMutex(&tidp->mx);
4420 tidp->userp = userp;
4421 tidp->pathname = sharePath;
4422 lock_ReleaseMutex(&tidp->mx);
4423 smb_ReleaseTID(tidp, FALSE);
4425 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4426 smb_SetSMBParm(rsp, 1, newTid);
4427 smb_SetSMBDataLength(rsp, 0);
4429 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4433 /* set maskp to the mask part of the incoming path.
4434 * Mask is 11 bytes long (8.3 with the dot elided).
4435 * Returns true if succeeds with a valid name, otherwise it does
4436 * its best, but returns false.
4438 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4446 /* starts off valid */
4449 /* mask starts out all blanks */
4450 memset(maskp, ' ', 11);
4453 /* find last backslash, or use whole thing if there is none */
4454 tp = cm_ClientStrRChr(pathp, '\\');
4458 tp++; /* skip slash */
4462 /* names starting with a dot are illegal */
4470 if (tc == '.' || tc == '"')
4478 /* if we get here, tp point after the dot */
4479 up = maskp+8; /* ext goes here */
4486 if (tc == '.' || tc == '"')
4489 /* copy extension if not too long */
4499 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4501 clientchar_t umask[11];
4509 /* XXX redo this, calling cm_MatchMask with a converted mask */
4511 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4515 /* otherwise, we have a valid 8.3 name; see if we have a match,
4516 * treating '?' as a wildcard in maskp (but not in the file name).
4518 tp1 = umask; /* real name, in mask format */
4519 tp2 = maskp; /* mask, in mask format */
4520 for(i=0; i<11; i++) {
4521 tc1 = *tp1++; /* clientchar_t from real name */
4522 tc2 = *tp2++; /* clientchar_t from mask */
4523 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4524 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4527 if (tc2 == '?' && tc1 != ' ')
4534 /* we got a match */
4538 clientchar_t *smb_FindMask(clientchar_t *pathp)
4542 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4545 return tp+1; /* skip the slash */
4547 return pathp; /* no slash, return the entire path */
4550 /* SMB_COM_SEARCH for a volume label
4552 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4553 dispatch function.) */
4554 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4556 clientchar_t *pathp;
4558 clientchar_t mask[12];
4559 unsigned char *statBlockp;
4560 unsigned char initStatBlock[21];
4563 osi_Log0(smb_logp, "SMB receive search volume");
4565 /* pull pathname and stat block out of request */
4566 tp = smb_GetSMBData(inp, NULL);
4567 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4568 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4570 return CM_ERROR_BADSMB;
4571 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4572 osi_assertx(statBlockp != NULL, "null statBlock");
4574 statBlockp = initStatBlock;
4578 /* for returning to caller */
4579 smb_Get8Dot3MaskFromPath(mask, pathp);
4581 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4582 tp = smb_GetSMBData(outp, NULL);
4584 *tp++ = 43; /* bytes in a dir entry */
4585 *tp++ = 0; /* high byte in counter */
4587 /* now marshall the dir entry, starting with the search status */
4588 *tp++ = statBlockp[0]; /* Reserved */
4589 memcpy(tp, mask, 11); tp += 11; /* FileName */
4591 /* now pass back server use info, with 1st byte non-zero */
4593 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4595 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4597 *tp++ = 0x8; /* attribute: volume */
4607 /* 4 byte file size */
4613 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4616 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4617 memset(tp, ' ', 13);
4620 /* set the length of the data part of the packet to 43 + 3, for the dir
4621 * entry plus the 5 and the length fields.
4623 smb_SetSMBDataLength(outp, 46);
4628 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4629 clientchar_t * tidPathp, clientchar_t * relPathp,
4630 cm_user_t *userp, cm_req_t *reqp)
4638 smb_dirListPatch_t *patchp;
4639 smb_dirListPatch_t *npatchp;
4640 clientchar_t path[AFSPATHMAX];
4642 afs_int32 mustFake = 0;
4644 lock_ObtainWrite(&dscp->rw);
4645 code = cm_FindACLCache(dscp, userp, &rights);
4647 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4648 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4649 if (code == CM_ERROR_NOACCESS) {
4654 lock_ReleaseWrite(&dscp->rw);
4658 if (!mustFake) { /* Bulk Stat */
4660 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4662 memset(bsp, 0, sizeof(cm_bulkStat_t));
4665 for (patchp = *dirPatchespp, count=0;
4667 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4668 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4672 if (lock_TryWrite(&tscp->rw)) {
4673 /* we have an entry that we can look at */
4674 if (!cm_EAccesFindEntry(userp, &tscp->fid) && cm_HaveCallback(tscp)) {
4675 /* we have a callback on it. Don't bother
4676 * fetching this stat entry, since we're happy
4677 * with the info we have.
4679 lock_ReleaseWrite(&tscp->rw);
4680 cm_ReleaseSCache(tscp);
4683 lock_ReleaseWrite(&tscp->rw);
4685 cm_ReleaseSCache(tscp);
4689 bsp->fids[i].Volume = patchp->fid.volume;
4690 bsp->fids[i].Vnode = patchp->fid.vnode;
4691 bsp->fids[i].Unique = patchp->fid.unique;
4693 if (bsp->counter == AFSCBMAX) {
4694 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4695 memset(bsp, 0, sizeof(cm_bulkStat_t));
4700 if (bsp->counter > 0)
4701 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4706 for (patchp = *dirPatchespp; patchp; patchp =
4707 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4709 dptr = patchp->dptr;
4711 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4712 relPathp ? relPathp : _C(""), patchp->dep->name);
4713 reqp->relPathp = path;
4714 reqp->tidPathp = tidPathp;
4716 code = cm_GetSCache(&patchp->fid, &dscp->fid, &scp, userp, reqp);
4717 reqp->relPathp = reqp->tidPathp = NULL;
4720 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4721 *dptr++ = SMB_ATTR_HIDDEN;
4724 lock_ObtainWrite(&scp->rw);
4725 if (mustFake || cm_EAccesFindEntry(userp, &scp->fid) || !cm_HaveCallback(scp)) {
4726 lock_ReleaseWrite(&scp->rw);
4728 /* set the attribute */
4729 switch (scp->fileType) {
4730 case CM_SCACHETYPE_DIRECTORY:
4731 case CM_SCACHETYPE_MOUNTPOINT:
4732 case CM_SCACHETYPE_INVALID:
4733 attr = SMB_ATTR_DIRECTORY;
4735 case CM_SCACHETYPE_SYMLINK:
4736 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4737 attr = SMB_ATTR_DIRECTORY;
4739 attr = SMB_ATTR_NORMAL;
4742 /* if we get here we either have a normal file
4743 * or we have a file for which we have never
4744 * received status info. In this case, we can
4745 * check the even/odd value of the entry's vnode.
4746 * odd means it is to be treated as a directory
4747 * and even means it is to be treated as a file.
4749 if (mustFake && (scp->fid.vnode & 0x1))
4750 attr = SMB_ATTR_DIRECTORY;
4752 attr = SMB_ATTR_NORMAL;
4756 /* 1969-12-31 23:59:58 +00*/
4757 dosTime = 0xEBBFBF7D;
4760 shortTemp = (unsigned short) (dosTime & 0xffff);
4761 *((u_short *)dptr) = shortTemp;
4764 /* and copy out date */
4765 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4766 *((u_short *)dptr) = shortTemp;
4769 /* copy out file length */
4770 *((u_long *)dptr) = 0;
4773 lock_ConvertWToR(&scp->rw);
4774 attr = smb_Attributes(scp);
4775 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4776 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4777 attr |= SMB_ATTR_HIDDEN;
4781 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4784 shortTemp = (unsigned short) (dosTime & 0xffff);
4785 *((u_short *)dptr) = shortTemp;
4788 /* and copy out date */
4789 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4790 *((u_short *)dptr) = shortTemp;
4793 /* copy out file length */
4794 *((u_long *)dptr) = scp->length.LowPart;
4796 lock_ReleaseRead(&scp->rw);
4798 cm_ReleaseSCache(scp);
4801 /* now free the patches */
4802 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4803 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4807 /* and mark the list as empty */
4808 *dirPatchespp = NULL;
4814 /* SMB_COM_SEARCH */
4815 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4821 clientchar_t *pathp;
4822 cm_dirEntry_t *dep = 0;
4824 smb_dirListPatch_t *dirListPatchesp;
4825 smb_dirListPatch_t *curPatchp;
4829 osi_hyper_t dirLength;
4830 osi_hyper_t bufferOffset;
4831 osi_hyper_t curOffset;
4833 unsigned char *inCookiep;
4834 smb_dirSearch_t *dsp;
4838 unsigned long clientCookie;
4839 cm_pageHeader_t *pageHeaderp;
4840 cm_user_t *userp = NULL;
4842 clientchar_t mask[12];
4844 long nextEntryCookie;
4845 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4846 char resByte; /* reserved byte from the cookie */
4847 char *op; /* output data ptr */
4848 char *origOp; /* original value of op */
4849 cm_space_t *spacep; /* for pathname buffer */
4853 clientchar_t *tidPathp = 0;
4860 maxCount = smb_GetSMBParm(inp, 0);
4862 dirListPatchesp = NULL;
4864 caseFold = CM_FLAG_CASEFOLD;
4866 tp = smb_GetSMBData(inp, NULL);
4867 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4868 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4870 return CM_ERROR_BADSMB;
4872 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4874 return CM_ERROR_BADSMB;
4876 /* We can handle long names */
4877 if (vcp->flags & SMB_VCFLAG_USENT)
4878 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4880 /* make sure we got a whole search status */
4881 if (dataLength < 21) {
4882 nextCookie = 0; /* start at the beginning of the dir */
4885 attribute = smb_GetSMBParm(inp, 1);
4887 /* handle volume info in another function */
4888 if (attribute & 0x8)
4889 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4891 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4892 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4894 if (*pathp == 0) { /* null pathp, treat as root dir */
4895 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4896 return CM_ERROR_NOFILES;
4900 dsp = smb_NewDirSearch(0);
4901 dsp->attribute = attribute;
4902 smb_Get8Dot3MaskFromPath(mask, pathp);
4903 memcpy(dsp->mask, mask, 12);
4905 /* track if this is likely to match a lot of entries */
4906 if (smb_Is8Dot3StarMask(mask))
4911 /* pull the next cookie value out of the search status block */
4912 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4913 + (inCookiep[16]<<24);
4914 dsp = smb_FindDirSearch(inCookiep[12]);
4916 /* can't find dir search status; fatal error */
4917 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4918 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4919 return CM_ERROR_BADFD;
4921 attribute = dsp->attribute;
4922 resByte = inCookiep[0];
4924 /* copy out client cookie, in host byte order. Don't bother
4925 * interpreting it, since we're just passing it through, anyway.
4927 memcpy(&clientCookie, &inCookiep[17], 4);
4929 memcpy(mask, dsp->mask, 12);
4931 /* assume we're doing a star match if it has continued for more
4937 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4938 nextCookie, dsp->cookie, attribute);
4940 userp = smb_GetUserFromVCP(vcp, inp);
4942 /* try to get the vnode for the path name next */
4943 lock_ObtainMutex(&dsp->mx);
4946 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4950 spacep = inp->spacep;
4951 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4952 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4954 lock_ReleaseMutex(&dsp->mx);
4955 cm_ReleaseUser(userp);
4956 smb_DeleteDirSearch(dsp);
4957 smb_ReleaseDirSearch(dsp);
4958 return CM_ERROR_NOFILES;
4960 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4961 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4963 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
4964 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4967 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4970 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4971 cm_ReleaseSCache(scp);
4972 lock_ReleaseMutex(&dsp->mx);
4973 cm_ReleaseUser(userp);
4974 smb_DeleteDirSearch(dsp);
4975 smb_ReleaseDirSearch(dsp);
4976 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4977 return CM_ERROR_PATH_NOT_COVERED;
4979 return CM_ERROR_NOSUCHPATH;
4981 #endif /* DFS_SUPPORT */
4984 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4985 /* we need one hold for the entry we just stored into,
4986 * and one for our own processing. When we're done with this
4987 * function, we'll drop the one for our own processing.
4988 * We held it once from the namei call, and so we do another hold
4992 lock_ObtainWrite(&scp->rw);
4993 dsp->flags |= SMB_DIRSEARCH_BULKST;
4994 lock_ReleaseWrite(&scp->rw);
4997 lock_ReleaseMutex(&dsp->mx);
4999 cm_ReleaseUser(userp);
5000 smb_DeleteDirSearch(dsp);
5001 smb_ReleaseDirSearch(dsp);
5005 /* reserves space for parameter; we'll adjust it again later to the
5006 * real count of the # of entries we returned once we've actually
5007 * assembled the directory listing.
5009 smb_SetSMBParm(outp, 0, 0);
5011 /* get the directory size */
5012 lock_ObtainWrite(&scp->rw);
5013 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5014 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5016 lock_ReleaseWrite(&scp->rw);
5017 cm_ReleaseSCache(scp);
5018 cm_ReleaseUser(userp);
5019 smb_DeleteDirSearch(dsp);
5020 smb_ReleaseDirSearch(dsp);
5024 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5026 dirLength = scp->length;
5028 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5029 curOffset.HighPart = 0;
5030 curOffset.LowPart = nextCookie;
5031 origOp = op = smb_GetSMBData(outp, NULL);
5032 /* and write out the basic header */
5033 *op++ = 5; /* variable block */
5034 op += 2; /* skip vbl block length; we'll fill it in later */
5038 clientchar_t *actualName = NULL;
5039 int free_actualName = 0;
5040 clientchar_t shortName[13];
5041 clientchar_t *shortNameEnd;
5043 /* make sure that curOffset.LowPart doesn't point to the first
5044 * 32 bytes in the 2nd through last dir page, and that it doesn't
5045 * point at the first 13 32-byte chunks in the first dir page,
5046 * since those are dir and page headers, and don't contain useful
5049 temp = curOffset.LowPart & (2048-1);
5050 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5051 /* we're in the first page */
5052 if (temp < 13*32) temp = 13*32;
5055 /* we're in a later dir page */
5056 if (temp < 32) temp = 32;
5059 /* make sure the low order 5 bits are zero */
5062 /* now put temp bits back ito curOffset.LowPart */
5063 curOffset.LowPart &= ~(2048-1);
5064 curOffset.LowPart |= temp;
5066 /* check if we've returned all the names that will fit in the
5069 if (returnedNames >= maxCount) {
5070 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5071 returnedNames, maxCount);
5075 /* check if we've passed the dir's EOF */
5076 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5078 /* see if we can use the bufferp we have now; compute in which page
5079 * the current offset would be, and check whether that's the offset
5080 * of the buffer we have. If not, get the buffer.
5082 thyper.HighPart = curOffset.HighPart;
5083 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5084 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5087 buf_Release(bufferp);
5090 lock_ReleaseWrite(&scp->rw);
5091 code = buf_Get(scp, &thyper, &req, &bufferp);
5092 lock_ObtainMutex(&dsp->mx);
5094 /* now, if we're doing a star match, do bulk fetching of all of
5095 * the status info for files in the dir.
5098 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5100 lock_ObtainWrite(&scp->rw);
5101 lock_ReleaseMutex(&dsp->mx);
5103 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5107 bufferOffset = thyper;
5109 /* now get the data in the cache */
5111 code = cm_SyncOp(scp, bufferp, userp, &req,
5113 CM_SCACHESYNC_NEEDCALLBACK |
5114 CM_SCACHESYNC_READ);
5116 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5120 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5122 if (cm_HaveBuffer(scp, bufferp, 0)) {
5123 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5127 /* otherwise, load the buffer and try again */
5128 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5130 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5131 scp, bufferp, code);
5136 buf_Release(bufferp);
5140 } /* if (wrong buffer) ... */
5142 /* now we have the buffer containing the entry we're interested in; copy
5143 * it out if it represents a non-deleted entry.
5145 entryInDir = curOffset.LowPart & (2048-1);
5146 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5148 /* page header will help tell us which entries are free. Page header
5149 * can change more often than once per buffer, since AFS 3 dir page size
5150 * may be less than (but not more than a buffer package buffer.
5152 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5153 temp &= ~(2048 - 1); /* turn off intra-page bits */
5154 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5156 /* now determine which entry we're looking at in the page. If it is
5157 * free (there's a free bitmap at the start of the dir), we should
5158 * skip these 32 bytes.
5160 slotInPage = (entryInDir & 0x7e0) >> 5;
5161 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5162 /* this entry is free */
5163 numDirChunks = 1; /* only skip this guy */
5167 tp = bufferp->datap + entryInBuffer;
5168 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5170 /* while we're here, compute the next entry's location, too,
5171 * since we'll need it when writing out the cookie into the dir
5174 * XXXX Probably should do more sanity checking.
5176 numDirChunks = cm_NameEntries(dep->name, NULL);
5178 /* compute the offset of the cookie representing the next entry */
5179 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5181 /* Compute 8.3 name if necessary */
5182 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5183 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5186 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5187 actualName = shortName;
5188 free_actualName = 0;
5190 free_actualName = 1;
5193 if (actualName == NULL) {
5194 /* Couldn't convert the name for some reason */
5195 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5196 osi_LogSaveString(smb_logp, dep->name));
5200 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5201 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5202 osi_LogSaveClientString(smb_logp, actualName));
5204 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5205 /* this is one of the entries to use: it is not deleted
5206 * and it matches the star pattern we're looking for.
5209 /* Eliminate entries that don't match requested
5212 /* no hidden files */
5213 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5214 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5218 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5220 /* We have already done the cm_TryBulkStat above */
5221 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5222 fileType = cm_FindFileType(&fid);
5223 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5224 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5226 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5227 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5228 fileType == CM_SCACHETYPE_DFSLINK ||
5229 fileType == CM_SCACHETYPE_INVALID)
5230 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5235 memcpy(op, mask, 11); op += 11;
5236 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5237 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5238 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5239 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5240 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5241 memcpy(op, &clientCookie, 4); op += 4;
5243 /* now we emit the attribute. This is sort of tricky,
5244 * since we need to really stat the file to find out
5245 * what type of entry we've got. Right now, we're
5246 * copying out data from a buffer, while holding the
5247 * scp locked, so it isn't really convenient to stat
5248 * something now. We'll put in a place holder now,
5249 * and make a second pass before returning this to get
5250 * the real attributes. So, we just skip the data for
5251 * now, and adjust it later. We allocate a patch
5252 * record to make it easy to find this point later.
5253 * The replay will happen at a time when it is safe to
5254 * unlock the directory.
5256 curPatchp = malloc(sizeof(*curPatchp));
5257 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5258 curPatchp->dptr = op;
5259 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5261 /* do hidden attribute here since name won't be around when applying
5265 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5266 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5268 curPatchp->flags = 0;
5270 op += 9; /* skip attr, time, date and size */
5272 /* zero out name area. The spec says to pad with
5273 * spaces, but Samba doesn't, and neither do we.
5277 /* finally, we get to copy out the name; we know that
5278 * it fits in 8.3 or the pattern wouldn't match, but it
5279 * never hurts to be sure.
5281 cm_ClientStringToUtf8(actualName, -1, op, 13);
5282 if (smb_StoreAnsiFilenames)
5284 /* This is a UCHAR field, which is ASCII even if Unicode
5287 /* Uppercase if requested by client */
5288 if (!KNOWS_LONG_NAMES(inp))
5293 /* now, adjust the # of entries copied */
5295 } /* if we're including this name */
5298 if (free_actualName && actualName) {
5303 /* and adjust curOffset to be where the new cookie is */
5304 thyper.HighPart = 0;
5305 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5306 curOffset = LargeIntegerAdd(thyper, curOffset);
5307 } /* while copying data for dir listing */
5309 /* release the mutex */
5310 lock_ReleaseWrite(&scp->rw);
5312 buf_Release(bufferp);
5316 /* apply and free last set of patches; if not doing a star match, this
5317 * will be empty, but better safe (and freeing everything) than sorry.
5319 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5321 /* special return code for unsuccessful search */
5322 if (code == 0 && dataLength < 21 && returnedNames == 0)
5323 code = CM_ERROR_NOFILES;
5325 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5326 returnedNames, code);
5329 smb_DeleteDirSearch(dsp);
5330 smb_ReleaseDirSearch(dsp);
5331 cm_ReleaseSCache(scp);
5332 cm_ReleaseUser(userp);
5336 /* finalize the output buffer */
5337 smb_SetSMBParm(outp, 0, returnedNames);
5338 temp = (long) (op - origOp);
5339 smb_SetSMBDataLength(outp, temp);
5341 /* the data area is a variable block, which has a 5 (already there)
5342 * followed by the length of the # of data bytes. We now know this to
5343 * be "temp," although that includes the 3 bytes of vbl block header.
5344 * Deduct for them and fill in the length field.
5346 temp -= 3; /* deduct vbl block info */
5347 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5348 origOp[1] = (unsigned char)(temp & 0xff);
5349 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5350 if (returnedNames == 0)
5351 smb_DeleteDirSearch(dsp);
5352 smb_ReleaseDirSearch(dsp);
5353 cm_ReleaseSCache(scp);
5354 cm_ReleaseUser(userp);
5359 /* verify that this is a valid path to a directory. I don't know why they
5360 * don't use the get file attributes call.
5362 * SMB_COM_CHECK_DIRECTORY
5364 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5366 clientchar_t *pathp;
5368 cm_scache_t *rootScp;
5369 cm_scache_t *newScp;
5373 clientchar_t *tidPathp;
5379 pdata = smb_GetSMBData(inp, NULL);
5380 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5382 return CM_ERROR_BADSMB;
5383 osi_Log1(smb_logp, "SMB receive check path %S",
5384 osi_LogSaveClientString(smb_logp, pathp));
5386 userp = smb_GetUserFromVCP(vcp, inp);
5388 rootScp = cm_RootSCachep(userp, &req);
5390 caseFold = CM_FLAG_CASEFOLD;
5392 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5394 cm_ReleaseUser(userp);
5395 return CM_ERROR_NOSUCHPATH;
5397 code = cm_NameI(rootScp, pathp,
5398 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5399 userp, tidPathp, &req, &newScp);
5402 cm_ReleaseUser(userp);
5407 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5408 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5409 cm_ReleaseSCache(newScp);
5410 cm_ReleaseUser(userp);
5411 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5412 return CM_ERROR_PATH_NOT_COVERED;
5414 return CM_ERROR_NOSUCHPATH;
5416 #endif /* DFS_SUPPORT */
5418 /* now lock the vnode with a callback; returns with newScp locked */
5419 lock_ObtainWrite(&newScp->rw);
5420 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5421 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5423 if (code != CM_ERROR_NOACCESS) {
5424 lock_ReleaseWrite(&newScp->rw);
5425 cm_ReleaseSCache(newScp);
5426 cm_ReleaseUser(userp);
5430 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5433 attrs = smb_Attributes(newScp);
5435 if (!(attrs & SMB_ATTR_DIRECTORY))
5436 code = CM_ERROR_NOTDIR;
5438 lock_ReleaseWrite(&newScp->rw);
5440 cm_ReleaseSCache(newScp);
5441 cm_ReleaseUser(userp);
5445 /* SMB_COM_SET_INFORMATION */
5446 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5448 clientchar_t *pathp;
5450 cm_scache_t *rootScp;
5451 unsigned short attribute;
5453 cm_scache_t *newScp;
5457 clientchar_t *tidPathp;
5463 /* decode basic attributes we're passed */
5464 attribute = smb_GetSMBParm(inp, 0);
5465 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5467 datap = smb_GetSMBData(inp, NULL);
5468 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5470 return CM_ERROR_BADSMB;
5472 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5473 dosTime, attribute);
5475 userp = smb_GetUserFromVCP(vcp, inp);
5477 rootScp = cm_RootSCachep(userp, &req);
5479 caseFold = CM_FLAG_CASEFOLD;
5481 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5483 cm_ReleaseUser(userp);
5484 return CM_ERROR_NOSUCHFILE;
5486 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5487 tidPathp, &req, &newScp);
5490 cm_ReleaseUser(userp);
5495 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5496 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5497 cm_ReleaseSCache(newScp);
5498 cm_ReleaseUser(userp);
5499 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5500 return CM_ERROR_PATH_NOT_COVERED;
5502 return CM_ERROR_NOSUCHPATH;
5504 #endif /* DFS_SUPPORT */
5506 /* now lock the vnode with a callback; returns with newScp locked; we
5507 * need the current status to determine what the new status is, in some
5510 lock_ObtainWrite(&newScp->rw);
5511 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5512 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5514 lock_ReleaseWrite(&newScp->rw);
5515 cm_ReleaseSCache(newScp);
5516 cm_ReleaseUser(userp);
5520 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5522 /* Check for RO volume */
5523 if (newScp->flags & CM_SCACHEFLAG_RO) {
5524 lock_ReleaseWrite(&newScp->rw);
5525 cm_ReleaseSCache(newScp);
5526 cm_ReleaseUser(userp);
5527 return CM_ERROR_READONLY;
5530 /* prepare for setattr call */
5533 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5534 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5536 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5537 /* we're told to make a writable file read-only */
5538 attr.unixModeBits = newScp->unixModeBits & ~0222;
5539 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5541 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5542 /* we're told to make a read-only file writable */
5543 attr.unixModeBits = newScp->unixModeBits | 0222;
5544 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5546 lock_ReleaseWrite(&newScp->rw);
5548 /* now call setattr */
5550 code = cm_SetAttr(newScp, &attr, userp, &req);
5554 cm_ReleaseSCache(newScp);
5555 cm_ReleaseUser(userp);
5561 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5563 clientchar_t *pathp;
5565 cm_scache_t *rootScp;
5566 cm_scache_t *newScp, *dscp;
5571 clientchar_t *tidPathp;
5573 clientchar_t *lastComp;
5579 datap = smb_GetSMBData(inp, NULL);
5580 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5582 return CM_ERROR_BADSMB;
5584 if (*pathp == 0) /* null path */
5587 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5588 osi_LogSaveClientString(smb_logp, pathp));
5590 userp = smb_GetUserFromVCP(vcp, inp);
5592 rootScp = cm_RootSCachep(userp, &req);
5594 /* we shouldn't need this for V3 requests, but we seem to */
5595 caseFold = CM_FLAG_CASEFOLD;
5597 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5599 cm_ReleaseUser(userp);
5600 return CM_ERROR_NOSUCHFILE;
5604 * XXX Strange hack XXX
5606 * As of Patch 5 (16 July 97), we are having the following problem:
5607 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5608 * requests to look up "desktop.ini" in all the subdirectories.
5609 * This can cause zillions of timeouts looking up non-existent cells
5610 * and volumes, especially in the top-level directory.
5612 * We have not found any way to avoid this or work around it except
5613 * to explicitly ignore the requests for mount points that haven't
5614 * yet been evaluated and for directories that haven't yet been
5617 * We should modify this hack to provide a fake desktop.ini file
5618 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5620 spacep = inp->spacep;
5621 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5622 #ifndef SPECIAL_FOLDERS
5623 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5624 code = cm_NameI(rootScp, spacep->wdata,
5625 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5626 userp, tidPathp, &req, &dscp);
5629 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5630 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5632 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5633 return CM_ERROR_PATH_NOT_COVERED;
5635 return CM_ERROR_NOSUCHPATH;
5637 #endif /* DFS_SUPPORT */
5638 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5639 code = CM_ERROR_NOSUCHFILE;
5640 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5641 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
5646 code = CM_ERROR_NOSUCHFILE;
5648 cm_ReleaseSCache(dscp);
5650 cm_ReleaseUser(userp);
5654 else if (code != CM_ERROR_NOSUCHFILE &&
5655 code != CM_ERROR_NOSUCHPATH &&
5656 code != CM_ERROR_BPLUS_NOMATCH)
5658 cm_ReleaseUser(userp);
5662 #endif /* SPECIAL_FOLDERS */
5664 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5665 tidPathp, &req, &newScp);
5667 cm_ReleaseUser(userp);
5672 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5673 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5674 cm_ReleaseSCache(newScp);
5675 cm_ReleaseUser(userp);
5676 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5677 return CM_ERROR_PATH_NOT_COVERED;
5679 return CM_ERROR_NOSUCHPATH;
5681 #endif /* DFS_SUPPORT */
5683 /* now lock the vnode with a callback; returns with newScp locked */
5684 lock_ObtainWrite(&newScp->rw);
5685 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5686 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5688 lock_ReleaseWrite(&newScp->rw);
5689 cm_ReleaseSCache(newScp);
5690 cm_ReleaseUser(userp);
5694 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5696 attrs = smb_Attributes(newScp);
5698 smb_SetSMBParm(outp, 0, attrs);
5700 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5701 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5702 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5703 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5704 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5705 smb_SetSMBParm(outp, 5, 0);
5706 smb_SetSMBParm(outp, 6, 0);
5707 smb_SetSMBParm(outp, 7, 0);
5708 smb_SetSMBParm(outp, 8, 0);
5709 smb_SetSMBParm(outp, 9, 0);
5710 smb_SetSMBDataLength(outp, 0);
5711 lock_ReleaseWrite(&newScp->rw);
5713 cm_ReleaseSCache(newScp);
5714 cm_ReleaseUser(userp);
5719 /* SMB_COM_TREE_DISCONNECT */
5720 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5724 osi_Log0(smb_logp, "SMB receive tree disconnect");
5726 /* find the tree and free it */
5727 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5729 lock_ObtainWrite(&smb_rctLock);
5731 smb_ReleaseTID(tidp, TRUE);
5732 lock_ReleaseWrite(&smb_rctLock);
5739 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5742 clientchar_t *pathp;
5743 clientchar_t *lastNamep;
5752 clientchar_t *tidPathp;
5758 datap = smb_GetSMBData(inp, NULL);
5759 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5761 return CM_ERROR_BADSMB;
5763 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5765 #ifdef DEBUG_VERBOSE
5769 hexpath = osi_HexifyString( pathp );
5770 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5775 share = smb_GetSMBParm(inp, 0);
5776 attribute = smb_GetSMBParm(inp, 1);
5778 spacep = inp->spacep;
5779 /* smb_StripLastComponent will strip "::$DATA" if present */
5780 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5782 if (!cm_IsValidClientString(pathp)) {
5784 clientchar_t * hexp;
5786 hexp = cm_GetRawCharsAlloc(pathp, -1);
5787 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5788 osi_LogSaveClientString(smb_logp, hexp));
5792 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5794 return CM_ERROR_BADNTFILENAME;
5797 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5798 /* special case magic file name for receiving IOCTL requests
5799 * (since IOCTL calls themselves aren't getting through).
5801 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5802 smb_SetupIoctlFid(fidp, spacep);
5803 smb_SetSMBParm(outp, 0, fidp->fid);
5804 smb_SetSMBParm(outp, 1, 0); /* attrs */
5805 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5806 smb_SetSMBParm(outp, 3, 0);
5807 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5808 smb_SetSMBParm(outp, 5, 0x7fff);
5809 /* pass the open mode back */
5810 smb_SetSMBParm(outp, 6, (share & 0xf));
5811 smb_SetSMBDataLength(outp, 0);
5812 smb_ReleaseFID(fidp);
5816 userp = smb_GetUserFromVCP(vcp, inp);
5818 caseFold = CM_FLAG_CASEFOLD;
5820 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5822 cm_ReleaseUser(userp);
5823 return CM_ERROR_NOSUCHPATH;
5825 code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
5826 tidPathp, &req, &scp);
5829 cm_ReleaseUser(userp);
5834 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5835 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5836 cm_ReleaseSCache(scp);
5837 cm_ReleaseUser(userp);
5838 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5839 return CM_ERROR_PATH_NOT_COVERED;
5841 return CM_ERROR_NOSUCHPATH;
5843 #endif /* DFS_SUPPORT */
5845 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5847 cm_ReleaseSCache(scp);
5848 cm_ReleaseUser(userp);
5852 /* don't need callback to check file type, since file types never
5853 * change, and namei and cm_Lookup all stat the object at least once on
5854 * a successful return.
5856 if (scp->fileType != CM_SCACHETYPE_FILE) {
5857 cm_ReleaseSCache(scp);
5858 cm_ReleaseUser(userp);
5859 return CM_ERROR_ISDIR;
5862 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5863 osi_assertx(fidp, "null smb_fid_t");
5865 lock_ObtainMutex(&fidp->mx);
5866 if ((share & 0xf) == 0)
5867 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5868 else if ((share & 0xf) == 1)
5869 fidp->flags |= SMB_FID_OPENWRITE;
5871 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5875 fidp->userp = userp;
5877 /* and a pointer to the vnode */
5879 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5880 lock_ObtainWrite(&scp->rw);
5881 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5883 smb_SetSMBParm(outp, 0, fidp->fid);
5884 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5885 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5886 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5887 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5888 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5889 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5890 /* pass the open mode back; XXXX add access checks */
5891 smb_SetSMBParm(outp, 6, (share & 0xf));
5892 smb_SetSMBDataLength(outp, 0);
5893 lock_ReleaseMutex(&fidp->mx);
5894 lock_ReleaseRead(&scp->rw);
5897 cm_Open(scp, 0, userp);
5899 /* send and free packet */
5900 smb_ReleaseFID(fidp);
5901 cm_ReleaseUser(userp);
5902 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5906 typedef struct smb_unlinkRock {
5911 clientchar_t *maskp; /* pointer to the star pattern */
5914 cm_dirEntryList_t * matches;
5917 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5920 smb_unlinkRock_t *rockp;
5923 normchar_t matchName[MAX_PATH];
5927 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5928 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5929 caseFold |= CM_FLAG_8DOT3;
5931 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5932 /* Can't convert name */
5933 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5934 osi_LogSaveString(smb_logp, dep->name));
5938 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5940 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5941 !cm_Is8Dot3(matchName)) {
5942 cm_Gen8Dot3Name(dep, matchName, NULL);
5943 /* 8.3 matches are always case insensitive */
5944 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5947 osi_Log1(smb_logp, "Found match %S",
5948 osi_LogSaveClientString(smb_logp, matchName));
5950 cm_DirEntryListAdd(dep->name, &rockp->matches);
5954 /* If we made a case sensitive exact match, we might as well quit now. */
5955 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5956 code = CM_ERROR_STOPNOW;
5965 /* SMB_COM_DELETE */
5966 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5970 clientchar_t *pathp;
5974 clientchar_t *lastNamep;
5975 smb_unlinkRock_t rock;
5979 clientchar_t *tidPathp;
5983 memset(&rock, 0, sizeof(rock));
5985 attribute = smb_GetSMBParm(inp, 0);
5987 tp = smb_GetSMBData(inp, NULL);
5988 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5990 return CM_ERROR_BADSMB;
5992 osi_Log1(smb_logp, "SMB receive unlink %S",
5993 osi_LogSaveClientString(smb_logp, pathp));
5995 spacep = inp->spacep;
5996 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5998 userp = smb_GetUserFromVCP(vcp, inp);
6000 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6002 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6004 cm_ReleaseUser(userp);
6005 return CM_ERROR_NOSUCHPATH;
6007 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
6010 cm_ReleaseUser(userp);
6015 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6016 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6017 cm_ReleaseSCache(dscp);
6018 cm_ReleaseUser(userp);
6019 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6020 return CM_ERROR_PATH_NOT_COVERED;
6022 return CM_ERROR_NOSUCHPATH;
6024 #endif /* DFS_SUPPORT */
6026 /* otherwise, scp points to the parent directory. */
6033 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
6035 code = CM_ERROR_NOSUCHFILE;
6038 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6041 thyper.HighPart = 0;
6046 rock.matches = NULL;
6048 /* Now, if we aren't dealing with a wildcard match, we first try an exact
6049 * match. If that fails, we do a case insensitve match.
6051 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6052 !smb_IsStarMask(rock.maskp)) {
6053 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6056 thyper.HighPart = 0;
6057 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6062 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6064 if (code == CM_ERROR_STOPNOW)
6067 if (code == 0 && rock.matches) {
6068 cm_dirEntryList_t * entry;
6070 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6071 normchar_t normalizedName[MAX_PATH];
6073 /* Note: entry->name is a non-normalized name */
6075 osi_Log1(smb_logp, "Unlinking %s",
6076 osi_LogSaveString(smb_logp, entry->name));
6078 /* We assume this works because entry->name was
6079 successfully converted in smb_UnlinkProc() once. */
6080 cm_FsStringToNormString(entry->name, -1,
6081 normalizedName, lengthof(normalizedName));
6083 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6085 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6086 smb_NotifyChange(FILE_ACTION_REMOVED,
6087 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6088 dscp, normalizedName, NULL, TRUE);
6092 cm_DirEntryListFree(&rock.matches);
6096 cm_ReleaseUser(userp);
6099 cm_ReleaseSCache(dscp);
6104 if (code == 0 && !rock.any)
6105 code = CM_ERROR_NOSUCHFILE;
6109 typedef struct smb_renameRock {
6110 cm_scache_t *odscp; /* old dir */
6111 cm_scache_t *ndscp; /* new dir */
6112 cm_user_t *userp; /* user */
6113 cm_req_t *reqp; /* request struct */
6114 smb_vc_t *vcp; /* virtual circuit */
6115 normchar_t *maskp; /* pointer to star pattern of old file name */
6116 int flags; /* tilde, casefold, etc */
6117 clientchar_t *newNamep; /* ptr to the new file's name */
6118 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6119 clientchar_t clOldName[MAX_PATH]; /* client name */
6123 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6126 smb_renameRock_t *rockp;
6129 normchar_t matchName[MAX_PATH];
6131 rockp = (smb_renameRock_t *) vrockp;
6133 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6134 /* Can't convert string */
6135 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6136 osi_LogSaveString(smb_logp, dep->name));
6140 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6141 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6142 caseFold |= CM_FLAG_8DOT3;
6144 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6146 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6147 !cm_Is8Dot3(matchName)) {
6148 cm_Gen8Dot3Name(dep, matchName, NULL);
6149 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6154 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6155 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6157 code = CM_ERROR_STOPNOW;
6167 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6170 cm_space_t *spacep = NULL;
6171 smb_renameRock_t rock;
6172 cm_scache_t *oldDscp = NULL;
6173 cm_scache_t *newDscp = NULL;
6174 cm_scache_t *tmpscp= NULL;
6175 cm_scache_t *tmpscp2 = NULL;
6176 clientchar_t *oldLastNamep;
6177 clientchar_t *newLastNamep;
6181 clientchar_t *tidPathp;
6185 userp = smb_GetUserFromVCP(vcp, inp);
6186 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6188 cm_ReleaseUser(userp);
6189 return CM_ERROR_NOSUCHPATH;
6193 memset(&rock, 0, sizeof(rock));
6195 spacep = inp->spacep;
6196 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6198 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6199 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6200 userp, tidPathp, &req, &oldDscp);
6202 cm_ReleaseUser(userp);
6207 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6208 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6209 cm_ReleaseSCache(oldDscp);
6210 cm_ReleaseUser(userp);
6211 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6212 return CM_ERROR_PATH_NOT_COVERED;
6214 return CM_ERROR_NOSUCHPATH;
6216 #endif /* DFS_SUPPORT */
6218 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6219 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6220 userp, tidPathp, &req, &newDscp);
6223 cm_ReleaseSCache(oldDscp);
6224 cm_ReleaseUser(userp);
6229 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6230 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6231 cm_ReleaseSCache(oldDscp);
6232 cm_ReleaseSCache(newDscp);
6233 cm_ReleaseUser(userp);
6234 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6235 return CM_ERROR_PATH_NOT_COVERED;
6237 return CM_ERROR_NOSUCHPATH;
6239 #endif /* DFS_SUPPORT */
6242 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6243 * next, get the component names, and lower case them.
6246 /* handle the old name first */
6248 oldLastNamep = oldPathp;
6252 /* and handle the new name, too */
6254 newLastNamep = newPathp;
6258 /* TODO: The old name could be a wildcard. The new name must not be */
6260 /* Check if the file already exists; if so return error */
6261 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6262 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6263 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6265 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6266 osi_LogSaveClientString(smb_logp, newLastNamep));
6268 /* Check if the old and the new names differ only in case. If so return
6269 * success, else return CM_ERROR_EXISTS
6271 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6273 /* This would be a success only if the old file is *as same as* the new file */
6274 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6276 if (tmpscp == tmpscp2)
6279 code = CM_ERROR_EXISTS;
6280 cm_ReleaseSCache(tmpscp2);
6283 code = CM_ERROR_NOSUCHFILE;
6286 /* file exist, do not rename, also fixes move */
6287 osi_Log0(smb_logp, "Can't rename. Target already exists");
6288 code = CM_ERROR_EXISTS;
6293 /* do the vnode call */
6294 rock.odscp = oldDscp;
6295 rock.ndscp = newDscp;
6299 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6301 code = CM_ERROR_NOSUCHFILE;
6304 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6305 rock.newNamep = newLastNamep;
6306 rock.fsOldName[0] = '\0';
6307 rock.clOldName[0] = '\0';
6310 /* Now search the directory for the pattern, and do the appropriate rename when found */
6311 thyper.LowPart = 0; /* search dir from here */
6312 thyper.HighPart = 0;
6314 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6315 if (code == 0 && !rock.any) {
6317 thyper.HighPart = 0;
6318 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6319 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6321 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6323 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6324 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6325 rock.ndscp, rock.newNamep, rock.userp,
6327 /* if the call worked, stop doing the search now, since we
6328 * really only want to rename one file.
6331 osi_Log0(smb_logp, "cm_Rename failure");
6332 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6333 } else if (code == 0) {
6334 code = CM_ERROR_NOSUCHFILE;
6337 /* Handle Change Notification */
6339 * Being lazy, not distinguishing between files and dirs in this
6340 * filter, since we'd have to do a lookup.
6343 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6344 if (oldDscp == newDscp) {
6345 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6346 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6347 filter, oldDscp, rock.clOldName,
6348 newLastNamep, TRUE);
6350 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6351 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6352 filter, oldDscp, rock.clOldName,
6354 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6355 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6356 filter, newDscp, newLastNamep,
6363 cm_ReleaseSCache(tmpscp);
6365 cm_ReleaseUser(userp);
6367 cm_ReleaseSCache(oldDscp);
6369 cm_ReleaseSCache(newDscp);
6377 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6380 cm_space_t *spacep = NULL;
6381 cm_scache_t *oldDscp = NULL;
6382 cm_scache_t *newDscp = NULL;
6383 cm_scache_t *tmpscp= NULL;
6384 cm_scache_t *tmpscp2 = NULL;
6385 cm_scache_t *sscp = NULL;
6386 clientchar_t *oldLastNamep;
6387 clientchar_t *newLastNamep;
6390 clientchar_t *tidPathp;
6394 userp = smb_GetUserFromVCP(vcp, inp);
6396 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6398 cm_ReleaseUser(userp);
6399 return CM_ERROR_NOSUCHPATH;
6404 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6406 spacep = inp->spacep;
6407 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6409 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6410 userp, tidPathp, &req, &oldDscp);
6412 cm_ReleaseUser(userp);
6417 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6418 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6419 cm_ReleaseSCache(oldDscp);
6420 cm_ReleaseUser(userp);
6421 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6422 return CM_ERROR_PATH_NOT_COVERED;
6424 return CM_ERROR_NOSUCHPATH;
6426 #endif /* DFS_SUPPORT */
6428 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6429 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6430 userp, tidPathp, &req, &newDscp);
6432 cm_ReleaseSCache(oldDscp);
6433 cm_ReleaseUser(userp);
6438 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6439 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6440 cm_ReleaseSCache(newDscp);
6441 cm_ReleaseSCache(oldDscp);
6442 cm_ReleaseUser(userp);
6443 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6444 return CM_ERROR_PATH_NOT_COVERED;
6446 return CM_ERROR_NOSUCHPATH;
6448 #endif /* DFS_SUPPORT */
6450 /* Now, although we did two lookups for the two directories (because the same
6451 * directory can be referenced through different paths), we only allow hard links
6452 * within the same directory. */
6453 if (oldDscp != newDscp) {
6454 cm_ReleaseSCache(oldDscp);
6455 cm_ReleaseSCache(newDscp);
6456 cm_ReleaseUser(userp);
6457 return CM_ERROR_CROSSDEVLINK;
6460 /* handle the old name first */
6462 oldLastNamep = oldPathp;
6466 /* and handle the new name, too */
6468 newLastNamep = newPathp;
6472 /* now lookup the old name */
6473 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6474 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6476 cm_ReleaseSCache(oldDscp);
6477 cm_ReleaseSCache(newDscp);
6478 cm_ReleaseUser(userp);
6482 /* Check if the file already exists; if so return error */
6483 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6484 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6485 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6487 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6488 osi_LogSaveClientString(smb_logp, newLastNamep));
6490 /* if the existing link is to the same file, then we return success */
6492 if(sscp == tmpscp) {
6495 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6496 code = CM_ERROR_EXISTS;
6501 cm_ReleaseSCache(tmpscp);
6502 cm_ReleaseSCache(sscp);
6503 cm_ReleaseSCache(newDscp);
6504 cm_ReleaseSCache(oldDscp);
6505 cm_ReleaseUser(userp);
6509 /* now create the hardlink */
6510 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6511 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6512 osi_Log1(smb_logp," Link returns 0x%x", code);
6514 /* Handle Change Notification */
6516 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6517 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6518 smb_NotifyChange(FILE_ACTION_ADDED,
6519 filter, newDscp, newLastNamep,
6524 cm_ReleaseSCache(tmpscp);
6525 cm_ReleaseUser(userp);
6526 cm_ReleaseSCache(sscp);
6527 cm_ReleaseSCache(oldDscp);
6528 cm_ReleaseSCache(newDscp);
6532 /* SMB_COM_RENAME */
6534 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6536 clientchar_t *oldPathp;
6537 clientchar_t *newPathp;
6541 tp = smb_GetSMBData(inp, NULL);
6542 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6544 return CM_ERROR_BADSMB;
6545 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6547 return CM_ERROR_BADSMB;
6549 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6550 osi_LogSaveClientString(smb_logp, oldPathp),
6551 osi_LogSaveClientString(smb_logp, newPathp));
6553 if (!cm_IsValidClientString(newPathp)) {
6555 clientchar_t * hexp;
6557 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6558 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6559 osi_LogSaveClientString(smb_logp, hexp));
6563 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6565 return CM_ERROR_BADNTFILENAME;
6568 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6570 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6576 typedef struct smb_rmdirRock {
6580 normchar_t *maskp; /* pointer to the star pattern */
6583 cm_dirEntryList_t * matches;
6586 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6589 smb_rmdirRock_t *rockp;
6591 normchar_t matchName[MAX_PATH];
6593 rockp = (smb_rmdirRock_t *) vrockp;
6595 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6596 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6597 osi_LogSaveString(smb_logp, dep->name));
6601 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6602 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6604 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6606 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6607 !cm_Is8Dot3(matchName)) {
6608 cm_Gen8Dot3Name(dep, matchName, NULL);
6609 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6614 cm_DirEntryListAdd(dep->name, &rockp->matches);
6621 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6624 clientchar_t *pathp;
6628 clientchar_t *lastNamep;
6629 smb_rmdirRock_t rock;
6633 clientchar_t *tidPathp;
6637 memset(&rock, 0, sizeof(rock));
6639 tp = smb_GetSMBData(inp, NULL);
6640 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6642 return CM_ERROR_BADSMB;
6644 spacep = inp->spacep;
6645 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6647 userp = smb_GetUserFromVCP(vcp, inp);
6649 caseFold = CM_FLAG_CASEFOLD;
6651 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6653 cm_ReleaseUser(userp);
6654 return CM_ERROR_NOSUCHPATH;
6656 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6657 userp, tidPathp, &req, &dscp);
6660 cm_ReleaseUser(userp);
6665 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6666 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6667 cm_ReleaseSCache(dscp);
6668 cm_ReleaseUser(userp);
6669 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6670 return CM_ERROR_PATH_NOT_COVERED;
6672 return CM_ERROR_NOSUCHPATH;
6674 #endif /* DFS_SUPPORT */
6676 /* otherwise, scp points to the parent directory. */
6683 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6685 code = CM_ERROR_NOSUCHFILE;
6688 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6691 thyper.HighPart = 0;
6695 rock.matches = NULL;
6697 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6698 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6699 if (code == 0 && !rock.any) {
6701 thyper.HighPart = 0;
6702 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6703 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6706 if (code == 0 && rock.matches) {
6707 cm_dirEntryList_t * entry;
6709 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6710 clientchar_t clientName[MAX_PATH];
6712 /* We assume this will succeed because smb_RmdirProc()
6713 successfully converted entry->name once above. */
6714 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6716 osi_Log1(smb_logp, "Removing directory %s",
6717 osi_LogSaveString(smb_logp, entry->name));
6719 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6721 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6722 smb_NotifyChange(FILE_ACTION_REMOVED,
6723 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6724 dscp, clientName, NULL, TRUE);
6730 cm_DirEntryListFree(&rock.matches);
6733 cm_ReleaseUser(userp);
6736 cm_ReleaseSCache(dscp);
6738 if (code == 0 && !rock.any)
6739 code = CM_ERROR_NOSUCHFILE;
6748 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6758 fid = smb_GetSMBParm(inp, 0);
6760 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6762 fid = smb_ChainFID(fid, inp);
6763 fidp = smb_FindFID(vcp, fid, 0);
6765 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6767 return CM_ERROR_BADFD;
6769 userp = smb_GetUserFromVCP(vcp, inp);
6771 lock_ObtainMutex(&fidp->mx);
6772 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6773 cm_ReleaseUser(userp);
6774 lock_ReleaseMutex(&fidp->mx);
6775 smb_ReleaseFID(fidp);
6776 return CM_ERROR_BADFD;
6779 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6780 lock_ReleaseMutex(&fidp->mx);
6781 cm_ReleaseUser(userp);
6782 smb_CloseFID(vcp, fidp, NULL, 0);
6783 smb_ReleaseFID(fidp);
6784 return CM_ERROR_NOSUCHFILE;
6787 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6788 cm_scache_t * scp = fidp->scp;
6790 lock_ReleaseMutex(&fidp->mx);
6791 code = cm_FSync(scp, userp, &req, FALSE);
6792 cm_ReleaseSCache(scp);
6794 lock_ReleaseMutex(&fidp->mx);
6798 cm_ReleaseUser(userp);
6799 smb_ReleaseFID(fidp);
6803 struct smb_FullNameRock {
6806 clientchar_t *fullName;
6807 fschar_t *originalName;
6810 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6813 normchar_t matchName[MAX_PATH];
6814 struct smb_FullNameRock *vrockp;
6816 vrockp = (struct smb_FullNameRock *)rockp;
6818 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6819 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6820 osi_LogSaveString(smb_logp, dep->name));
6824 if (!cm_Is8Dot3(matchName)) {
6825 clientchar_t shortName[13];
6827 cm_Gen8Dot3Name(dep, shortName, NULL);
6829 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6830 vrockp->fullName = cm_ClientStrDup(matchName);
6831 vrockp->originalName = cm_FsStrDup(dep->name);
6832 return CM_ERROR_STOPNOW;
6835 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6836 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6837 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6838 vrockp->fullName = cm_ClientStrDup(matchName);
6839 vrockp->originalName = cm_FsStrDup(dep->name);
6840 return CM_ERROR_STOPNOW;
6845 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6846 clientchar_t **newPathp, fschar_t ** originalPathp,
6847 cm_user_t *userp, cm_req_t *reqp)
6849 struct smb_FullNameRock rock;
6852 memset(&rock, 0, sizeof(rock));
6856 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6857 if (code == CM_ERROR_STOPNOW) {
6858 *newPathp = rock.fullName;
6859 *originalPathp = rock.originalName;
6861 *newPathp = cm_ClientStrDup(pathp);
6862 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6866 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6867 afs_uint32 dosTime) {
6870 cm_scache_t *dscp = NULL;
6871 clientchar_t *pathp = NULL;
6872 cm_scache_t * scp = NULL;
6873 cm_scache_t *delscp = NULL;
6874 int nullcreator = 0;
6876 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6877 fidp, fidp->fid, scp, vcp);
6880 lock_ObtainMutex(&fidp->mx);
6881 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6883 lock_ReleaseMutex(&fidp->mx);
6884 osi_Log0(smb_logp, " No user specified. Not closing fid");
6885 return CM_ERROR_BADFD;
6888 userp = fidp->userp; /* no hold required since fidp is held
6889 throughout the function */
6890 lock_ReleaseMutex(&fidp->mx);
6895 lock_ObtainWrite(&smb_rctLock);
6896 if (fidp->deleteOk) {
6897 osi_Log0(smb_logp, " Fid already closed.");
6898 lock_ReleaseWrite(&smb_rctLock);
6899 return CM_ERROR_BADFD;
6902 lock_ReleaseWrite(&smb_rctLock);
6904 lock_ObtainMutex(&fidp->mx);
6905 if (fidp->NTopen_dscp) {
6906 dscp = fidp->NTopen_dscp;
6907 cm_HoldSCache(dscp);
6910 if (fidp->NTopen_pathp)
6911 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6918 /* Don't jump the gun on an async raw write */
6919 while (fidp->raw_writers) {
6920 lock_ReleaseMutex(&fidp->mx);
6921 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6922 lock_ObtainMutex(&fidp->mx);
6925 /* watch for ioctl closes, and read-only opens */
6927 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6928 == SMB_FID_OPENWRITE) {
6929 if (dosTime != 0 && dosTime != -1) {
6930 lock_ObtainWrite(&fidp->scp->rw);
6931 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6932 /* This fixes defect 10958 */
6933 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6934 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6935 lock_ReleaseWrite(&fidp->scp->rw);
6937 if (smb_AsyncStore != 2) {
6938 lock_ReleaseMutex(&fidp->mx);
6939 code = cm_FSync(scp, userp, &req, FALSE);
6940 lock_ObtainMutex(&fidp->mx);
6946 /* unlock any pending locks */
6947 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6948 scp->fileType == CM_SCACHETYPE_FILE) {
6952 lock_ReleaseMutex(&fidp->mx);
6955 * CM_UNLOCK_FLAG_BY_FID doesn't look at the process ID.
6958 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6959 lock_ObtainWrite(&scp->rw);
6961 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6962 CM_SCACHESYNC_NEEDCALLBACK
6963 | CM_SCACHESYNC_GETSTATUS
6964 | CM_SCACHESYNC_LOCK);
6968 "smb CoreClose SyncOp failure code 0x%x", tcode);
6969 goto post_syncopdone;
6972 cm_UnlockByKey(scp, key, CM_UNLOCK_FLAG_BY_FID, userp, &req);
6974 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6978 lock_ReleaseWrite(&scp->rw);
6979 lock_ObtainMutex(&fidp->mx);
6982 if (fidp->flags & SMB_FID_DELONCLOSE) {
6983 clientchar_t *fullPathp = NULL;
6984 fschar_t *originalNamep = NULL;
6986 lock_ReleaseMutex(&fidp->mx);
6988 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6993 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6994 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6995 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6997 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6998 smb_NotifyChange(FILE_ACTION_REMOVED,
6999 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
7000 dscp, fullPathp, NULL, TRUE);
7003 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
7005 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7006 smb_NotifyChange(FILE_ACTION_REMOVED,
7007 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7008 dscp, fullPathp, NULL, TRUE);
7015 free(originalNamep);
7017 lock_ObtainMutex(&fidp->mx);
7018 fidp->flags &= ~SMB_FID_DELONCLOSE;
7021 /* if this was a newly created file, then clear the creator
7022 * in the stat cache entry. */
7023 if (fidp->flags & SMB_FID_CREATED) {
7025 fidp->flags &= ~SMB_FID_CREATED;
7028 if (fidp->flags & SMB_FID_NTOPEN) {
7029 cm_ReleaseSCache(fidp->NTopen_dscp);
7030 fidp->NTopen_dscp = NULL;
7031 free(fidp->NTopen_pathp);
7032 fidp->NTopen_pathp = NULL;
7033 fidp->flags &= ~SMB_FID_NTOPEN;
7035 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
7036 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7039 if (fidp->NTopen_wholepathp) {
7040 free(fidp->NTopen_wholepathp);
7041 fidp->NTopen_wholepathp = NULL;
7045 cm_ReleaseSCache(fidp->scp);
7048 lock_ReleaseMutex(&fidp->mx);
7051 cm_ReleaseSCache(dscp);
7054 cm_ReleaseSCache(delscp);
7058 lock_ObtainWrite(&scp->rw);
7059 if (nullcreator && scp->creator == userp)
7060 scp->creator = NULL;
7061 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7062 lock_ReleaseWrite(&scp->rw);
7063 cm_ReleaseSCache(scp);
7073 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7081 fid = smb_GetSMBParm(inp, 0);
7082 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7084 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7086 fid = smb_ChainFID(fid, inp);
7087 fidp = smb_FindFID(vcp, fid, 0);
7089 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
7091 return CM_ERROR_BADFD;
7094 userp = smb_GetUserFromVCP(vcp, inp);
7096 code = smb_CloseFID(vcp, fidp, userp, dosTime);
7098 smb_ReleaseFID(fidp);
7099 cm_ReleaseUser(userp);
7104 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7106 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7107 cm_user_t *userp, long *readp)
7113 osi_hyper_t fileLength;
7115 osi_hyper_t lastByte;
7116 osi_hyper_t bufferOffset;
7120 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7123 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7124 fidp->fid, offsetp->LowPart, count);
7128 lock_ObtainMutex(&fidp->mx);
7129 /* make sure we have a readable FD */
7130 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7131 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7132 fidp->fid, fidp->flags);
7133 lock_ReleaseMutex(&fidp->mx);
7134 code = CM_ERROR_BADFDOP;
7139 lock_ReleaseMutex(&fidp->mx);
7140 code = CM_ERROR_BADFD;
7151 lock_ObtainWrite(&scp->rw);
7153 if (offset.HighPart == 0) {
7154 chunk = offset.LowPart >> cm_logChunkSize;
7155 if (chunk != fidp->curr_chunk) {
7156 fidp->prev_chunk = fidp->curr_chunk;
7157 fidp->curr_chunk = chunk;
7159 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7162 lock_ReleaseMutex(&fidp->mx);
7164 /* start by looking up the file's end */
7165 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7166 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7170 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7172 /* now we have the entry locked, look up the length */
7173 fileLength = scp->length;
7175 /* adjust count down so that it won't go past EOF */
7176 thyper.LowPart = count;
7177 thyper.HighPart = 0;
7178 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7180 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7181 /* we'd read past EOF, so just stop at fileLength bytes.
7182 * Start by computing how many bytes remain in the file.
7184 thyper = LargeIntegerSubtract(fileLength, offset);
7186 /* if we are past EOF, read 0 bytes */
7187 if (LargeIntegerLessThanZero(thyper))
7190 count = thyper.LowPart;
7195 /* now, copy the data one buffer at a time,
7196 * until we've filled the request packet
7199 /* if we've copied all the data requested, we're done */
7200 if (count <= 0) break;
7202 /* otherwise, load up a buffer of data */
7203 thyper.HighPart = offset.HighPart;
7204 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7205 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7208 buf_Release(bufferp);
7211 lock_ReleaseWrite(&scp->rw);
7213 code = buf_Get(scp, &thyper, &req, &bufferp);
7215 lock_ObtainWrite(&scp->rw);
7216 if (code) goto done;
7217 bufferOffset = thyper;
7219 /* now get the data in the cache */
7221 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7222 CM_SCACHESYNC_NEEDCALLBACK |
7223 CM_SCACHESYNC_READ);
7227 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7229 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7231 /* otherwise, load the buffer and try again */
7232 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7236 buf_Release(bufferp);
7240 } /* if (wrong buffer) ... */
7242 /* now we have the right buffer loaded. Copy out the
7243 * data from here to the user's buffer.
7245 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7247 /* and figure out how many bytes we want from this buffer */
7248 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7249 if (nbytes > count) nbytes = count; /* don't go past EOF */
7251 /* now copy the data */
7252 memcpy(op, bufferp->datap + bufIndex, nbytes);
7254 /* adjust counters, pointers, etc. */
7257 thyper.LowPart = nbytes;
7258 thyper.HighPart = 0;
7259 offset = LargeIntegerAdd(thyper, offset);
7263 lock_ReleaseWrite(&scp->rw);
7265 buf_Release(bufferp);
7267 if (code == 0 && sequential)
7268 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7270 cm_ReleaseSCache(scp);
7273 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7274 fidp->fid, code, *readp);
7279 * smb_WriteData -- common code for Write and Raw Write
7281 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7282 cm_user_t *userp, long *writtenp)
7284 osi_hyper_t offset = *offsetp;
7287 cm_scache_t *scp = NULL;
7288 osi_hyper_t fileLength; /* file's length at start of write */
7289 osi_hyper_t minLength; /* don't read past this */
7290 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7291 cm_buf_t *bufferp = NULL;
7292 osi_hyper_t thyper; /* hyper tmp variable */
7293 osi_hyper_t bufferOffset;
7294 afs_uint32 bufIndex; /* index in buffer where our data is */
7295 int doWriteBack = 0;
7296 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7299 int needSyncOpDone = 0;
7301 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7302 fidp->fid, offsetp->LowPart, count);
7306 lock_ObtainMutex(&fidp->mx);
7307 /* make sure we have a writable FD */
7308 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7309 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7310 fidp->fid, fidp->flags);
7311 lock_ReleaseMutex(&fidp->mx);
7312 code = CM_ERROR_BADFDOP;
7320 lock_ReleaseMutex(&fidp->mx);
7322 lock_ObtainWrite(&scp->rw);
7323 /* start by looking up the file's end */
7324 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7325 CM_SCACHESYNC_NEEDCALLBACK
7326 | CM_SCACHESYNC_SETSTATUS
7327 | CM_SCACHESYNC_GETSTATUS);
7331 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7333 /* now we have the entry locked, look up the length */
7334 fileLength = scp->length;
7335 minLength = fileLength;
7336 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7337 minLength = scp->serverLength;
7339 /* adjust file length if we extend past EOF */
7340 thyper.LowPart = count;
7341 thyper.HighPart = 0;
7342 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7343 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7344 /* we'd write past EOF, so extend the file */
7345 scp->mask |= CM_SCACHEMASK_LENGTH;
7346 scp->length = thyper;
7347 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7349 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7351 /* now, if the new position (thyper) and the old (offset) are in
7352 * different storeback windows, remember to store back the previous
7353 * storeback window when we're done with the write.
7355 * the purpose of this logic is to slow down the CIFS client
7356 * in order to avoid the client disconnecting during the CLOSE
7357 * operation if there are too many dirty buffers left to write
7358 * than can be accomplished during 45 seconds. This used to be
7359 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7360 * so that we can read larger amounts of data at a time.
7362 if (smb_AsyncStore == 1 &&
7363 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7364 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7365 /* they're different */
7367 writeBackOffset.HighPart = offset.HighPart;
7368 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7373 /* now, copy the data one buffer at a time, until we've filled the
7375 while (count != 0) {
7377 /* handle over quota or out of space */
7378 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7379 *writtenp = written;
7380 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7384 /* otherwise, load up a buffer of data */
7385 thyper.HighPart = offset.HighPart;
7386 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7387 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7390 if (needSyncOpDone) {
7391 cm_SyncOpDone(scp, bufferp,
7392 CM_SCACHESYNC_NEEDCALLBACK
7393 | CM_SCACHESYNC_WRITE
7394 | CM_SCACHESYNC_BUFLOCKED);
7397 lock_ReleaseMutex(&bufferp->mx);
7398 buf_Release(bufferp);
7401 lock_ReleaseWrite(&scp->rw);
7403 code = buf_Get(scp, &thyper, &req, &bufferp);
7405 lock_ObtainMutex(&bufferp->mx);
7406 lock_ObtainWrite(&scp->rw);
7407 if (code) goto done;
7409 bufferOffset = thyper;
7411 /* now get the data in the cache */
7413 if (!needSyncOpDone) {
7414 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7415 CM_SCACHESYNC_NEEDCALLBACK
7416 | CM_SCACHESYNC_WRITE
7417 | CM_SCACHESYNC_BUFLOCKED);
7424 /* If we're overwriting the entire buffer, or
7425 * if we're writing at or past EOF, mark the
7426 * buffer as current so we don't call
7427 * cm_GetBuffer. This skips the fetch from the
7428 * server in those cases where we're going to
7429 * obliterate all the data in the buffer anyway,
7430 * or in those cases where there is no useful
7431 * data at the server to start with.
7433 * Use minLength instead of scp->length, since
7434 * the latter has already been updated by this
7437 * The scp lock has been dropped multiple times
7438 * so the minLength must be refreshed before it
7442 minLength = scp->length;
7443 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7444 minLength = scp->serverLength;
7446 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7447 || LargeIntegerEqualTo(offset, bufferp->offset)
7448 && (count >= cm_data.buf_blockSize
7449 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7450 ConvertLongToLargeInteger(count)),
7452 if (count < cm_data.buf_blockSize
7453 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7454 memset(bufferp->datap, 0,
7455 cm_data.buf_blockSize);
7456 bufferp->dataVersion = scp->dataVersion;
7459 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7461 /* otherwise, load the buffer and try again */
7462 cm_SyncOpDone(scp, bufferp,
7463 CM_SCACHESYNC_NEEDCALLBACK
7464 | CM_SCACHESYNC_WRITE
7465 | CM_SCACHESYNC_BUFLOCKED);
7468 lock_ReleaseMutex(&bufferp->mx);
7469 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7471 lock_ReleaseWrite(&scp->rw);
7472 lock_ObtainMutex(&bufferp->mx);
7473 lock_ObtainWrite(&scp->rw);
7477 } /* if (wrong buffer) ... */
7479 /* now we have the right buffer loaded. Copy out the
7480 * data from here to the user's buffer.
7482 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7484 /* and figure out how many bytes we want from this buffer */
7485 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7487 nbytes = count; /* don't go past end of request */
7489 /* now copy the data */
7490 memcpy(bufferp->datap + bufIndex, op, nbytes);
7491 buf_SetDirty(bufferp, &req, bufIndex, nbytes, userp);
7493 /* adjust counters, pointers, etc. */
7497 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7498 } /* while count != 0 */
7501 if (bufferp && needSyncOpDone) {
7502 cm_SyncOpDone(scp, bufferp,
7503 CM_SCACHESYNC_NEEDCALLBACK
7504 | CM_SCACHESYNC_WRITE
7505 | CM_SCACHESYNC_BUFLOCKED);
7508 lock_ReleaseWrite(&scp->rw);
7511 lock_ReleaseMutex(&bufferp->mx);
7512 buf_Release(bufferp);
7515 lock_ObtainMutex(&fidp->mx);
7516 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7517 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7519 lock_ReleaseMutex(&fidp->mx);
7520 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7521 fidp->NTopen_dscp, fidp->NTopen_pathp,
7524 lock_ReleaseMutex(&fidp->mx);
7528 if (smb_AsyncStore > 0) {
7532 lock_ObtainWrite(&scp->rw);
7533 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7535 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7536 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7538 lock_ReleaseWrite(&scp->rw);
7539 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7540 writeBackOffset.HighPart,
7541 smb_AsyncStoreSize, 0, userp, &req);
7542 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7545 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7549 cm_ReleaseSCache(scp);
7552 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7553 fidp->fid, code, *writtenp);
7558 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7561 unsigned short count;
7563 unsigned short hint;
7564 long written = 0, total_written = 0;
7567 smb_t* smbp = (smb_t*) inp;
7571 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7573 int inDataBlockCount;
7575 fd = smb_GetSMBParm(inp, 0);
7576 count = smb_GetSMBParm(inp, 1);
7577 offset.HighPart = 0; /* too bad */
7578 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7579 hint = smb_GetSMBParm(inp, 4);
7581 op = smb_GetSMBData(inp, NULL);
7582 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7584 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7585 fd, offset.LowPart, count);
7587 fd = smb_ChainFID(fd, inp);
7588 fidp = smb_FindFID(vcp, fd, 0);
7590 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7592 return CM_ERROR_BADFD;
7595 lock_ObtainMutex(&fidp->mx);
7596 if (fidp->flags & SMB_FID_IOCTL) {
7597 lock_ReleaseMutex(&fidp->mx);
7598 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7599 smb_ReleaseFID(fidp);
7600 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7604 if (fidp->flags & SMB_FID_RPC) {
7605 lock_ReleaseMutex(&fidp->mx);
7606 code = smb_RPCWrite(fidp, vcp, inp, outp);
7607 smb_ReleaseFID(fidp);
7608 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7613 lock_ReleaseMutex(&fidp->mx);
7614 smb_ReleaseFID(fidp);
7615 return CM_ERROR_BADFD;
7618 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7619 lock_ReleaseMutex(&fidp->mx);
7620 smb_CloseFID(vcp, fidp, NULL, 0);
7621 smb_ReleaseFID(fidp);
7622 return CM_ERROR_NOSUCHFILE;
7627 lock_ReleaseMutex(&fidp->mx);
7628 userp = smb_GetUserFromVCP(vcp, inp);
7632 LARGE_INTEGER LOffset;
7633 LARGE_INTEGER LLength;
7636 key = cm_GenerateKey(vcp->vcID, pid, fd);
7638 LOffset.HighPart = offset.HighPart;
7639 LOffset.LowPart = offset.LowPart;
7640 LLength.HighPart = 0;
7641 LLength.LowPart = count;
7643 lock_ObtainWrite(&scp->rw);
7644 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7645 lock_ReleaseWrite(&scp->rw);
7648 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7653 /* special case: 0 bytes transferred means truncate to this position */
7657 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7661 truncAttr.mask = CM_ATTRMASK_LENGTH;
7662 truncAttr.length.LowPart = offset.LowPart;
7663 truncAttr.length.HighPart = 0;
7664 lock_ObtainMutex(&fidp->mx);
7665 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7666 fidp->flags |= SMB_FID_LENGTHSETDONE;
7667 lock_ReleaseMutex(&fidp->mx);
7668 smb_SetSMBParm(outp, 0, 0 /* count */);
7669 smb_SetSMBDataLength(outp, 0);
7674 * Work around bug in NT client
7676 * When copying a file, the NT client should first copy the data,
7677 * then copy the last write time. But sometimes the NT client does
7678 * these in the wrong order, so the data copies would inadvertently
7679 * cause the last write time to be overwritten. We try to detect this,
7680 * and don't set client mod time if we think that would go against the
7683 lock_ObtainMutex(&fidp->mx);
7684 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7685 lock_ObtainWrite(&fidp->scp->rw);
7686 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7687 fidp->scp->clientModTime = time(NULL);
7688 lock_ReleaseWrite(&fidp->scp->rw);
7690 lock_ReleaseMutex(&fidp->mx);
7693 while ( code == 0 && count > 0 ) {
7694 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7695 if (code == 0 && written == 0)
7696 code = CM_ERROR_PARTIALWRITE;
7698 offset = LargeIntegerAdd(offset,
7699 ConvertLongToLargeInteger(written));
7700 count -= (unsigned short)written;
7701 total_written += written;
7705 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7706 total_written, code);
7708 /* set the packet data length to 3 bytes for the data block header,
7709 * plus the size of the data.
7711 smb_SetSMBParm(outp, 0, total_written);
7712 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7713 smb_SetSMBParm(outp, 3, hint);
7714 smb_SetSMBDataLength(outp, 0);
7717 smb_ReleaseFID(fidp);
7718 cm_ReleaseUser(userp);
7719 cm_ReleaseSCache(scp);
7724 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7725 NCB *ncbp, raw_write_cont_t *rwcp)
7734 fd = smb_GetSMBParm(inp, 0);
7735 fidp = smb_FindFID(vcp, fd, 0);
7737 lock_ObtainMutex(&fidp->mx);
7739 lock_ReleaseMutex(&fidp->mx);
7740 smb_ReleaseFID(fidp);
7744 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7745 lock_ReleaseMutex(&fidp->mx);
7746 smb_CloseFID(vcp, fidp, NULL, 0);
7747 smb_ReleaseFID(fidp);
7750 lock_ReleaseMutex(&fidp->mx);
7752 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7753 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7755 userp = smb_GetUserFromVCP(vcp, inp);
7758 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7760 if (rwcp->writeMode & 0x1) { /* synchronous */
7763 smb_FormatResponsePacket(vcp, inp, outp);
7764 op = (smb_t *) outp;
7765 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7766 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7767 smb_SetSMBDataLength(outp, 0);
7768 smb_SendPacket(vcp, outp);
7769 smb_FreePacket(outp);
7771 else { /* asynchronous */
7772 lock_ObtainMutex(&fidp->mx);
7773 fidp->raw_writers--;
7774 if (fidp->raw_writers == 0)
7775 thrd_SetEvent(fidp->raw_write_event);
7776 lock_ReleaseMutex(&fidp->mx);
7779 /* Give back raw buffer */
7780 lock_ObtainMutex(&smb_RawBufLock);
7781 *((char **)rawBuf) = smb_RawBufs;
7782 smb_RawBufs = rawBuf;
7783 lock_ReleaseMutex(&smb_RawBufLock);
7785 smb_ReleaseFID(fidp);
7786 cm_ReleaseUser(userp);
7789 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7794 /* SMB_COM_WRITE_RAW */
7795 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7798 long count, written = 0, total_written = 0;
7802 smb_t *smbp = (smb_t*) inp;
7807 unsigned short writeMode;
7809 fd = smb_GetSMBParm(inp, 0);
7810 totalCount = smb_GetSMBParm(inp, 1);
7811 count = smb_GetSMBParm(inp, 10);
7812 writeMode = smb_GetSMBParm(inp, 7);
7814 op = (char *) inp->data;
7815 op += smb_GetSMBParm(inp, 11);
7817 offset.HighPart = 0;
7818 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7820 if (*inp->wctp == 14) {
7821 /* we received a 64-bit file offset */
7822 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7824 if (LargeIntegerLessThanZero(offset)) {
7826 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7827 offset.HighPart, offset.LowPart);
7828 return CM_ERROR_BADSMB;
7831 offset.HighPart = 0; /* 32-bit file offset */
7835 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7836 fd, offset.HighPart, offset.LowPart, count);
7838 " WriteRaw WriteMode 0x%x",
7841 fd = smb_ChainFID(fd, inp);
7842 fidp = smb_FindFID(vcp, fd, 0);
7844 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7846 return CM_ERROR_BADFD;
7848 lock_ObtainMutex(&fidp->mx);
7850 lock_ReleaseMutex(&fidp->mx);
7851 smb_ReleaseFID(fidp);
7852 return CM_ERROR_BADFD;
7855 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7856 lock_ReleaseMutex(&fidp->mx);
7857 smb_CloseFID(vcp, fidp, NULL, 0);
7858 smb_ReleaseFID(fidp);
7859 return CM_ERROR_NOSUCHFILE;
7864 lock_ReleaseMutex(&fidp->mx);
7869 LARGE_INTEGER LOffset;
7870 LARGE_INTEGER LLength;
7873 key = cm_GenerateKey(vcp->vcID, pid, fd);
7875 LOffset.HighPart = offset.HighPart;
7876 LOffset.LowPart = offset.LowPart;
7877 LLength.HighPart = 0;
7878 LLength.LowPart = count;
7880 lock_ObtainWrite(&scp->rw);
7881 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7882 lock_ReleaseWrite(&scp->rw);
7885 cm_ReleaseSCache(scp);
7886 smb_ReleaseFID(fidp);
7891 userp = smb_GetUserFromVCP(vcp, inp);
7894 * Work around bug in NT client
7896 * When copying a file, the NT client should first copy the data,
7897 * then copy the last write time. But sometimes the NT client does
7898 * these in the wrong order, so the data copies would inadvertently
7899 * cause the last write time to be overwritten. We try to detect this,
7900 * and don't set client mod time if we think that would go against the
7903 lock_ObtainMutex(&fidp->mx);
7904 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7905 lock_ObtainWrite(&fidp->scp->rw);
7906 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7907 fidp->scp->clientModTime = time(NULL);
7908 lock_ReleaseWrite(&fidp->scp->rw);
7910 lock_ReleaseMutex(&fidp->mx);
7913 while ( code == 0 && count > 0 ) {
7914 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7915 if (code == 0 && written == 0)
7916 code = CM_ERROR_PARTIALWRITE;
7918 offset = LargeIntegerAdd(offset,
7919 ConvertLongToLargeInteger(written));
7922 total_written += written;
7926 /* Get a raw buffer */
7929 lock_ObtainMutex(&smb_RawBufLock);
7931 /* Get a raw buf, from head of list */
7932 rawBuf = smb_RawBufs;
7933 smb_RawBufs = *(char **)smb_RawBufs;
7936 code = CM_ERROR_USESTD;
7938 lock_ReleaseMutex(&smb_RawBufLock);
7941 /* Don't allow a premature Close */
7942 if (code == 0 && (writeMode & 1) == 0) {
7943 lock_ObtainMutex(&fidp->mx);
7944 fidp->raw_writers++;
7945 thrd_ResetEvent(fidp->raw_write_event);
7946 lock_ReleaseMutex(&fidp->mx);
7949 smb_ReleaseFID(fidp);
7950 cm_ReleaseUser(userp);
7951 cm_ReleaseSCache(scp);
7954 smb_SetSMBParm(outp, 0, total_written);
7955 smb_SetSMBDataLength(outp, 0);
7956 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7961 offset = LargeIntegerAdd(offset,
7962 ConvertLongToLargeInteger(count));
7966 rwcp->offset.HighPart = offset.HighPart;
7967 rwcp->offset.LowPart = offset.LowPart;
7968 rwcp->count = totalCount - count;
7969 rwcp->writeMode = writeMode;
7970 rwcp->alreadyWritten = total_written;
7972 /* set the packet data length to 3 bytes for the data block header,
7973 * plus the size of the data.
7975 smb_SetSMBParm(outp, 0, 0xffff);
7976 smb_SetSMBDataLength(outp, 0);
7982 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7985 long count, finalCount;
7989 smb_t *smbp = (smb_t*) inp;
7995 fd = smb_GetSMBParm(inp, 0);
7996 count = smb_GetSMBParm(inp, 1);
7997 offset.HighPart = 0; /* too bad */
7998 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8000 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
8001 fd, offset.LowPart, count);
8003 fd = smb_ChainFID(fd, inp);
8004 fidp = smb_FindFID(vcp, fd, 0);
8006 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
8008 return CM_ERROR_BADFD;
8010 lock_ObtainMutex(&fidp->mx);
8011 if (fidp->flags & SMB_FID_IOCTL) {
8012 lock_ReleaseMutex(&fidp->mx);
8013 code = smb_IoctlRead(fidp, vcp, inp, outp);
8014 smb_ReleaseFID(fidp);
8018 if (fidp->flags & SMB_FID_RPC) {
8019 lock_ReleaseMutex(&fidp->mx);
8020 code = smb_RPCRead(fidp, vcp, inp, outp);
8021 smb_ReleaseFID(fidp);
8026 lock_ReleaseMutex(&fidp->mx);
8027 smb_ReleaseFID(fidp);
8028 return CM_ERROR_BADFD;
8031 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8032 lock_ReleaseMutex(&fidp->mx);
8033 smb_CloseFID(vcp, fidp, NULL, 0);
8034 smb_ReleaseFID(fidp);
8035 return CM_ERROR_NOSUCHFILE;
8040 lock_ReleaseMutex(&fidp->mx);
8043 LARGE_INTEGER LOffset, LLength;
8047 key = cm_GenerateKey(vcp->vcID, pid, fd);
8049 LOffset.HighPart = 0;
8050 LOffset.LowPart = offset.LowPart;
8051 LLength.HighPart = 0;
8052 LLength.LowPart = count;
8054 lock_ObtainWrite(&scp->rw);
8055 code = cm_LockCheckRead(scp, LOffset, LLength, key);
8056 lock_ReleaseWrite(&scp->rw);
8059 cm_ReleaseSCache(scp);
8060 smb_ReleaseFID(fidp);
8064 userp = smb_GetUserFromVCP(vcp, inp);
8066 /* remember this for final results */
8067 smb_SetSMBParm(outp, 0, count);
8068 smb_SetSMBParm(outp, 1, 0);
8069 smb_SetSMBParm(outp, 2, 0);
8070 smb_SetSMBParm(outp, 3, 0);
8071 smb_SetSMBParm(outp, 4, 0);
8073 /* set the packet data length to 3 bytes for the data block header,
8074 * plus the size of the data.
8076 smb_SetSMBDataLength(outp, count+3);
8078 /* get op ptr after putting in the parms, since otherwise we don't
8079 * know where the data really is.
8081 op = smb_GetSMBData(outp, NULL);
8083 /* now emit the data block header: 1 byte of type and 2 bytes of length */
8084 *op++ = 1; /* data block marker */
8085 *op++ = (unsigned char) (count & 0xff);
8086 *op++ = (unsigned char) ((count >> 8) & 0xff);
8088 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8090 /* fix some things up */
8091 smb_SetSMBParm(outp, 0, finalCount);
8092 smb_SetSMBDataLength(outp, finalCount+3);
8094 smb_ReleaseFID(fidp);
8096 cm_ReleaseUser(userp);
8097 cm_ReleaseSCache(scp);
8101 /* SMB_COM_CREATE_DIRECTORY */
8102 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8104 clientchar_t *pathp;
8109 cm_scache_t *dscp; /* dir we're dealing with */
8110 cm_scache_t *scp; /* file we're creating */
8112 int initialModeBits;
8113 clientchar_t *lastNamep;
8115 clientchar_t *tidPathp;
8122 /* compute initial mode bits based on read-only flag in attributes */
8123 initialModeBits = 0777;
8125 tp = smb_GetSMBData(inp, NULL);
8126 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8128 return CM_ERROR_BADSMB;
8130 spacep = inp->spacep;
8131 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8133 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8134 return CM_ERROR_EXISTS;
8136 userp = smb_GetUserFromVCP(vcp, inp);
8138 caseFold = CM_FLAG_CASEFOLD;
8140 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8142 cm_ReleaseUser(userp);
8143 return CM_ERROR_NOSUCHPATH;
8146 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
8147 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8148 userp, tidPathp, &req, &dscp);
8151 cm_ReleaseUser(userp);
8156 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8157 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8158 cm_ReleaseSCache(dscp);
8159 cm_ReleaseUser(userp);
8160 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8161 return CM_ERROR_PATH_NOT_COVERED;
8163 return CM_ERROR_NOSUCHPATH;
8165 #endif /* DFS_SUPPORT */
8167 /* otherwise, scp points to the parent directory. Do a lookup, and
8168 * fail if we find it. Otherwise, we do the create.
8174 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8175 if (scp) cm_ReleaseSCache(scp);
8176 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8177 if (code == 0) code = CM_ERROR_EXISTS;
8178 cm_ReleaseSCache(dscp);
8179 cm_ReleaseUser(userp);
8183 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8184 setAttr.clientModTime = time(NULL);
8185 smb_SetInitialModeBitsForDir(0, &setAttr);
8187 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8188 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8189 smb_NotifyChange(FILE_ACTION_ADDED,
8190 FILE_NOTIFY_CHANGE_DIR_NAME,
8191 dscp, lastNamep, NULL, TRUE);
8193 /* we don't need this any longer */
8194 cm_ReleaseSCache(dscp);
8197 /* something went wrong creating or truncating the file */
8198 cm_ReleaseUser(userp);
8202 /* otherwise we succeeded */
8203 smb_SetSMBDataLength(outp, 0);
8204 cm_ReleaseUser(userp);
8209 BOOL smb_IsLegalFilename(clientchar_t *filename)
8212 * Find the longest substring of filename that does not contain
8213 * any of the chars in illegalChars. If that substring is less
8214 * than the length of the whole string, then one or more of the
8215 * illegal chars is in filename.
8217 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8223 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8224 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8226 clientchar_t *pathp;
8232 cm_scache_t *dscp; /* dir we're dealing with */
8233 cm_scache_t *scp; /* file we're creating */
8237 clientchar_t *lastNamep;
8240 clientchar_t *tidPathp;
8242 int created = 0; /* the file was new */
8247 excl = (inp->inCom == 0x03)? 0 : 1;
8249 attributes = smb_GetSMBParm(inp, 0);
8250 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8252 tp = smb_GetSMBData(inp, NULL);
8253 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8255 return CM_ERROR_BADSMB;
8257 spacep = inp->spacep;
8258 /* smb_StripLastComponent will strip "::$DATA" if present */
8259 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8261 if (!cm_IsValidClientString(pathp)) {
8263 clientchar_t * hexp;
8265 hexp = cm_GetRawCharsAlloc(pathp, -1);
8266 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8267 osi_LogSaveClientString(smb_logp, hexp));
8271 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8273 return CM_ERROR_BADNTFILENAME;
8276 userp = smb_GetUserFromVCP(vcp, inp);
8278 caseFold = CM_FLAG_CASEFOLD;
8280 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8282 cm_ReleaseUser(userp);
8283 return CM_ERROR_NOSUCHPATH;
8285 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8286 userp, tidPathp, &req, &dscp);
8289 cm_ReleaseUser(userp);
8294 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8295 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8296 cm_ReleaseSCache(dscp);
8297 cm_ReleaseUser(userp);
8298 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8299 return CM_ERROR_PATH_NOT_COVERED;
8301 return CM_ERROR_NOSUCHPATH;
8303 #endif /* DFS_SUPPORT */
8305 /* otherwise, scp points to the parent directory. Do a lookup, and
8306 * truncate the file if we find it, otherwise we create the file.
8313 if (!smb_IsLegalFilename(lastNamep))
8314 return CM_ERROR_BADNTFILENAME;
8316 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8317 #ifdef DEBUG_VERBOSE
8320 hexp = osi_HexifyString( lastNamep );
8321 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8326 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8327 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8328 cm_ReleaseSCache(dscp);
8329 cm_ReleaseUser(userp);
8333 /* if we get here, if code is 0, the file exists and is represented by
8334 * scp. Otherwise, we have to create it.
8338 /* oops, file shouldn't be there */
8339 cm_ReleaseSCache(dscp);
8340 cm_ReleaseSCache(scp);
8341 cm_ReleaseUser(userp);
8342 return CM_ERROR_EXISTS;
8345 setAttr.mask = CM_ATTRMASK_LENGTH;
8346 setAttr.length.LowPart = 0;
8347 setAttr.length.HighPart = 0;
8348 code = cm_SetAttr(scp, &setAttr, userp, &req);
8351 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8352 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8353 smb_SetInitialModeBitsForFile(attributes, &setAttr);
8355 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8359 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8360 smb_NotifyChange(FILE_ACTION_ADDED,
8361 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8362 dscp, lastNamep, NULL, TRUE);
8363 } else if (!excl && code == CM_ERROR_EXISTS) {
8364 /* not an exclusive create, and someone else tried
8365 * creating it already, then we open it anyway. We
8366 * don't bother retrying after this, since if this next
8367 * fails, that means that the file was deleted after
8368 * we started this call.
8370 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8373 setAttr.mask = CM_ATTRMASK_LENGTH;
8374 setAttr.length.LowPart = 0;
8375 setAttr.length.HighPart = 0;
8376 code = cm_SetAttr(scp, &setAttr, userp, &req);
8381 /* we don't need this any longer */
8382 cm_ReleaseSCache(dscp);
8385 /* something went wrong creating or truncating the file */
8386 if (scp) cm_ReleaseSCache(scp);
8387 cm_ReleaseUser(userp);
8391 /* make sure we only open files */
8392 if (scp->fileType != CM_SCACHETYPE_FILE) {
8393 cm_ReleaseSCache(scp);
8394 cm_ReleaseUser(userp);
8395 return CM_ERROR_ISDIR;
8398 /* now all we have to do is open the file itself */
8399 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8400 osi_assertx(fidp, "null smb_fid_t");
8404 lock_ObtainMutex(&fidp->mx);
8405 /* always create it open for read/write */
8406 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8408 /* remember that the file was newly created */
8410 fidp->flags |= SMB_FID_CREATED;
8412 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8414 /* save a pointer to the vnode */
8416 lock_ObtainWrite(&scp->rw);
8417 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8418 lock_ReleaseWrite(&scp->rw);
8421 fidp->userp = userp;
8422 lock_ReleaseMutex(&fidp->mx);
8424 smb_SetSMBParm(outp, 0, fidp->fid);
8425 smb_SetSMBDataLength(outp, 0);
8427 cm_Open(scp, 0, userp);
8429 smb_ReleaseFID(fidp);
8430 cm_ReleaseUser(userp);
8431 /* leave scp held since we put it in fidp->scp */
8436 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8439 osi_hyper_t new_offset;
8450 fd = smb_GetSMBParm(inp, 0);
8451 whence = smb_GetSMBParm(inp, 1);
8452 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8454 /* try to find the file descriptor */
8455 fd = smb_ChainFID(fd, inp);
8456 fidp = smb_FindFID(vcp, fd, 0);
8458 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8460 return CM_ERROR_BADFD;
8462 lock_ObtainMutex(&fidp->mx);
8463 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8464 lock_ReleaseMutex(&fidp->mx);
8465 smb_ReleaseFID(fidp);
8466 return CM_ERROR_BADFD;
8469 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8470 lock_ReleaseMutex(&fidp->mx);
8471 smb_CloseFID(vcp, fidp, NULL, 0);
8472 smb_ReleaseFID(fidp);
8473 return CM_ERROR_NOSUCHFILE;
8476 lock_ReleaseMutex(&fidp->mx);
8478 userp = smb_GetUserFromVCP(vcp, inp);
8480 lock_ObtainMutex(&fidp->mx);
8483 lock_ReleaseMutex(&fidp->mx);
8484 lock_ObtainWrite(&scp->rw);
8485 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8486 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8488 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8490 /* offset from current offset */
8491 new_offset = LargeIntegerAdd(fidp->offset,
8492 ConvertLongToLargeInteger(offset));
8494 else if (whence == 2) {
8495 /* offset from current EOF */
8496 new_offset = LargeIntegerAdd(scp->length,
8497 ConvertLongToLargeInteger(offset));
8499 new_offset = ConvertLongToLargeInteger(offset);
8502 fidp->offset = new_offset;
8503 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8504 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8505 smb_SetSMBDataLength(outp, 0);
8507 lock_ReleaseWrite(&scp->rw);
8508 smb_ReleaseFID(fidp);
8509 cm_ReleaseSCache(scp);
8510 cm_ReleaseUser(userp);
8514 /* dispatch all of the requests received in a packet. Due to chaining, this may
8515 * be more than one request.
8517 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8518 NCB *ncbp, raw_write_cont_t *rwcp)
8522 unsigned long code = 0;
8523 unsigned char *outWctp;
8524 int nparms; /* # of bytes of parameters */
8526 int nbytes; /* bytes of data, excluding count */
8529 unsigned short errCode;
8530 unsigned long NTStatus;
8532 unsigned char errClass;
8533 unsigned int oldGen;
8534 DWORD oldTime, newTime;
8536 /* get easy pointer to the data */
8537 smbp = (smb_t *) inp->data;
8539 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8540 /* setup the basic parms for the initial request in the packet */
8541 inp->inCom = smbp->com;
8542 inp->wctp = &smbp->wct;
8544 inp->ncb_length = ncbp->ncb_length;
8549 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8550 /* log it and discard it */
8551 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8552 __FILE__, __LINE__, ncbp->ncb_length);
8553 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8557 /* We are an ongoing op */
8558 thrd_Increment(&ongoingOps);
8560 /* set up response packet for receiving output */
8561 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8562 smb_FormatResponsePacket(vcp, inp, outp);
8563 outWctp = outp->wctp;
8565 /* Remember session generation number and time */
8566 oldGen = sessionGen;
8567 oldTime = GetTickCount();
8569 while (inp->inCom != 0xff) {
8570 dp = &smb_dispatchTable[inp->inCom];
8572 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8573 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8574 code = outp->resumeCode;
8578 /* process each request in the packet; inCom, wctp and inCount
8579 * are already set up.
8581 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8584 /* now do the dispatch */
8585 /* start by formatting the response record a little, as a default */
8586 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8588 outWctp[1] = 0xff; /* no operation */
8589 outWctp[2] = 0; /* padding */
8594 /* not a chained request, this is a more reasonable default */
8595 outWctp[0] = 0; /* wct of zero */
8596 outWctp[1] = 0; /* and bcc (word) of zero */
8600 /* once set, stays set. Doesn't matter, since we never chain
8601 * "no response" calls.
8603 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8607 /* we have a recognized operation */
8608 char * opName = myCrt_Dispatch(inp->inCom);
8611 smbp = (smb_t *) inp;
8613 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8614 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8615 if (inp->inCom == 0x1d) {
8617 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8619 code = (*(dp->procp)) (vcp, inp, outp);
8621 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8622 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8624 newTime = GetTickCount();
8625 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8626 opName, smbp->mid, newTime - oldTime);
8629 if ( code == CM_ERROR_BADSMB ||
8630 code == CM_ERROR_BADOP )
8632 #endif /* LOG_PACKET */
8634 /* ReceiveV3Tran2A handles its own logging */
8635 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8638 clientchar_t *treepath = NULL; /* do not free */
8639 clientchar_t *pathname = NULL;
8640 cm_fid_t afid = {0,0,0,0,0};
8642 uidp = smb_FindUID(vcp, smbp->uid, 0);
8643 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8644 fidp = smb_FindFID(vcp, inp->fid, 0);
8647 lock_ObtainMutex(&fidp->mx);
8648 if (fidp->NTopen_pathp)
8649 pathname = fidp->NTopen_pathp;
8651 afid = fidp->scp->fid;
8653 if (inp->stringsp->wdata)
8654 pathname = inp->stringsp->wdata;
8657 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)",
8658 opName, newTime - oldTime,
8659 smbp->uid, uidp ? uidp->unp->name : NULL,
8660 smbp->pid, smbp->mid, smbp->tid,
8663 afid.cell, afid.volume, afid.vnode, afid.unique);
8666 lock_ReleaseMutex(&fidp->mx);
8669 smb_ReleaseUID(uidp);
8671 smb_ReleaseFID(fidp);
8674 if (oldGen != sessionGen) {
8675 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8676 newTime - oldTime, ncbp->ncb_length);
8677 osi_Log3(smb_logp, "Request %s straddled session startup, "
8678 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8681 FreeSMBStrings(inp);
8683 /* bad opcode, fail the request, after displaying it */
8684 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8687 #endif /* LOG_PACKET */
8690 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8691 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8692 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8693 if (code == IDCANCEL)
8696 code = CM_ERROR_BADOP;
8699 /* catastrophic failure: log as much as possible */
8700 if (code == CM_ERROR_BADSMB) {
8701 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8705 #endif /* LOG_PACKET */
8706 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8709 code = CM_ERROR_INVAL;
8712 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8713 thrd_Decrement(&ongoingOps);
8718 /* now, if we failed, turn the current response into an empty
8719 * one, and fill in the response packet's error code.
8722 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8723 smb_MapNTError(code, &NTStatus, FALSE);
8724 outWctp = outp->wctp;
8725 smbp = (smb_t *) &outp->data;
8726 if (code != CM_ERROR_PARTIALWRITE
8727 && code != CM_ERROR_BUFFERTOOSMALL
8728 && code != CM_ERROR_GSSCONTINUE) {
8729 /* nuke wct and bcc. For a partial
8730 * write or an in-process authentication handshake,
8731 * assume they're OK.
8737 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8738 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8739 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8740 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8741 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8745 smb_MapCoreError(code, vcp, &errCode, &errClass);
8746 outWctp = outp->wctp;
8747 smbp = (smb_t *) &outp->data;
8748 if (code != CM_ERROR_PARTIALWRITE) {
8749 /* nuke wct and bcc. For a partial
8750 * write, assume they're OK.
8756 smbp->errLow = (unsigned char) (errCode & 0xff);
8757 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8758 smbp->rcls = errClass;
8761 } /* error occurred */
8763 /* if we're here, we've finished one request. Look to see if
8764 * this is a chained opcode. If it is, setup things to process
8765 * the chained request, and setup the output buffer to hold the
8766 * chained response. Start by finding the next input record.
8768 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8769 break; /* not a chained req */
8770 tp = inp->wctp; /* points to start of last request */
8771 /* in a chained request, the first two
8772 * parm fields are required, and are
8773 * AndXCommand/AndXReserved and
8775 if (tp[0] < 2) break;
8776 if (tp[1] == 0xff) break; /* no more chained opcodes */
8778 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8781 /* and now append the next output request to the end of this
8782 * last request. Begin by finding out where the last response
8783 * ends, since that's where we'll put our new response.
8785 outWctp = outp->wctp; /* ptr to out parameters */
8786 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8787 nparms = outWctp[0] << 1;
8788 tp = outWctp + nparms + 1; /* now points to bcc field */
8789 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8790 tp += 2 /* for the count itself */ + nbytes;
8791 /* tp now points to the new output record; go back and patch the
8792 * second parameter (off2) to point to the new record.
8794 temp = (unsigned int)(tp - outp->data);
8795 outWctp[3] = (unsigned char) (temp & 0xff);
8796 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8797 outWctp[2] = 0; /* padding */
8798 outWctp[1] = inp->inCom; /* next opcode */
8800 /* finally, setup for the next iteration */
8803 } /* while loop over all requests in the packet */
8805 /* now send the output packet, and return */
8807 smb_SendPacket(vcp, outp);
8808 thrd_Decrement(&ongoingOps);
8813 /* Wait for Netbios() calls to return, and make the results available to server
8814 * threads. Note that server threads can't wait on the NCBevents array
8815 * themselves, because NCB events are manual-reset, and the servers would race
8816 * each other to reset them.
8818 void smb_ClientWaiter(void *parmp)
8823 while (smbShutdownFlag == 0) {
8824 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8826 if (code == WAIT_OBJECT_0)
8829 /* error checking */
8830 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8832 int abandonIdx = code - WAIT_ABANDONED_0;
8833 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8836 if (code == WAIT_IO_COMPLETION)
8838 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8842 if (code == WAIT_TIMEOUT)
8844 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8847 if (code == WAIT_FAILED)
8849 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8852 idx = code - WAIT_OBJECT_0;
8854 /* check idx range! */
8855 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8857 /* this is fatal - log as much as possible */
8858 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8859 osi_assertx(0, "invalid index");
8862 thrd_ResetEvent(NCBevents[idx]);
8863 thrd_SetEvent(NCBreturns[0][idx]);
8868 * Try to have one NCBRECV request waiting for every live session. Not more
8869 * than one, because if there is more than one, it's hard to handle Write Raw.
8871 void smb_ServerWaiter(void *parmp)
8874 int idx_session, idx_NCB;
8877 while (smbShutdownFlag == 0) {
8879 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8881 if (code == WAIT_OBJECT_0)
8884 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8886 int abandonIdx = code - WAIT_ABANDONED_0;
8887 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8890 if (code == WAIT_IO_COMPLETION)
8892 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8896 if (code == WAIT_TIMEOUT)
8898 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8901 if (code == WAIT_FAILED)
8903 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8906 idx_session = code - WAIT_OBJECT_0;
8908 /* check idx range! */
8909 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8911 /* this is fatal - log as much as possible */
8912 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8913 osi_assertx(0, "invalid index");
8918 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8920 if (code == WAIT_OBJECT_0) {
8921 if (smbShutdownFlag == 1)
8927 /* error checking */
8928 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8930 int abandonIdx = code - WAIT_ABANDONED_0;
8931 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8934 if (code == WAIT_IO_COMPLETION)
8936 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8940 if (code == WAIT_TIMEOUT)
8942 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8945 if (code == WAIT_FAILED)
8947 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8950 idx_NCB = code - WAIT_OBJECT_0;
8952 /* check idx range! */
8953 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8955 /* this is fatal - log as much as possible */
8956 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8957 osi_assertx(0, "invalid index");
8960 /* Link them together */
8961 NCBsessions[idx_NCB] = idx_session;
8964 ncbp = NCBs[idx_NCB];
8965 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8966 ncbp->ncb_command = NCBRECV | ASYNCH;
8967 ncbp->ncb_lana_num = lanas[idx_session];
8968 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8969 ncbp->ncb_event = NCBevents[idx_NCB];
8970 ncbp->ncb_length = SMB_PACKETSIZE;
8975 typedef struct _monitored_task {
8978 LARGE_INTEGER start_time;
8980 BOOL trace_timer_hit;
8981 BOOL dump_timer_hit;
8984 typedef struct osi_queueHT {
8985 osi_queue_t * headp;
8986 osi_queue_t * tailp;
8989 static osi_queue_t *smb_monitored_tasks = NULL;
8990 static osi_queue_t *smb_free_monitored_tasks = NULL;
8992 static osi_mutex_t _monitor_mx;
8994 static HANDLE h_monitored_task_queue = NULL;
8995 static HANDLE h_monitored_task_shutdown = NULL;
8997 static time_t smb_last_dump_time = 0;
8999 DWORD smb_monitorReqs = 0;
9001 /* FILETIME comparison fuzz */
9002 #define MONITOR_FUZZ_TIMEOUT (1 * 10000000i64)
9004 /* Trace timeout is at 60 seconds */
9005 #define MONITOR_TRACE_TIMEOUT (60 * 10000000i64)
9007 /* Dump timeout is at 120 seconds */
9008 #define MONITOR_DUMP_TIMEOUT (120 * 10000000i64)
9010 /* Time before another dump is performed in seconds*/
9011 #define MONITOR_DUMP_RESET_TIMEOUT (600)
9013 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
9016 LARGE_INTEGER earliest;
9019 GetSystemTimeAsFileTime(&now);
9020 earliest.LowPart = now.dwLowDateTime;
9021 earliest.HighPart = now.dwHighDateTime;
9022 earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
9024 while ((t = (monitored_task *) taskmq->headp) != NULL &&
9026 (t->start_time.QuadPart < earliest.QuadPart ||
9028 t->dump_timer_hit)) {
9030 osi_QRemoveHT(&taskmq->headp,
9034 lock_ObtainMutex(&_monitor_mx);
9035 osi_QAdd(&smb_free_monitored_tasks, &t->q);
9036 lock_ReleaseMutex(&_monitor_mx);
9039 #ifdef INVARIANT_CHECK
9045 for (t = (monitored_task *) taskmq->headp;
9047 t = (monitored_task *) osi_QNext(&t->q)) {
9048 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9049 last.QuadPart = t->start_time.QuadPart;
9055 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
9057 monitored_task * task;
9058 monitored_task * tasks;
9060 lock_ObtainMutex(&_monitor_mx);
9061 tasks = (monitored_task *) smb_monitored_tasks;
9062 smb_monitored_tasks = NULL;
9063 lock_ReleaseMutex(&_monitor_mx);
9068 osi_QRemove((osi_queue_t **) &tasks, &task->q);
9070 if (task->started) {
9076 q.prevp = taskmq->tailp;
9078 /* Insertion sort by start_time. Earliest request is
9079 first. Since we are likely to receive new requests
9080 later, we start inserting from the back. */
9083 ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
9087 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
9088 else if (p->prevp == NULL)
9089 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
9091 osi_queue_t *o = p->prevp;
9093 osi_assert(o->nextp == p);
9097 p->prevp = &task->q;
9098 o->nextp = &task->q;
9102 /* Some task ending */
9106 for (p = taskmq->headp;
9110 monitored_task * mt = (monitored_task *) p;
9112 if (mt->task_id == task->task_id) {
9114 osi_QRemoveHT(&taskmq->headp,
9117 lock_ObtainMutex(&_monitor_mx);
9118 osi_QAdd(&smb_free_monitored_tasks, p);
9119 lock_ReleaseMutex(&_monitor_mx);
9125 lock_ObtainMutex(&_monitor_mx);
9126 osi_QAdd(&smb_free_monitored_tasks, &task->q);
9127 lock_ReleaseMutex(&_monitor_mx);
9131 #ifdef INVARIANT_CHECK
9138 for (t = (monitored_task *) taskmq->headp;
9140 t = (monitored_task *) osi_QNext(&t->q)) {
9141 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9142 last.QuadPart = t->start_time.QuadPart;
9148 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9150 if (!task->trace_timer_hit) {
9152 task->trace_timer_hit = TRUE;
9154 osi_LogEnable(afsd_logp);
9155 rx_DebugOnOff(TRUE);
9157 } else if (!task->dump_timer_hit) {
9162 if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9163 task->dump_timer_hit = TRUE;
9164 smb_last_dump_time = now;
9166 GenerateMiniDump(NULL);
9172 * Server request monitoring
9174 * The server monitor runs in a separate thread and monitors server
9175 * requests for potential timeouts. It examines notifcations queued
9176 * by smb_NotifyRequestEvent() and waits for potential timeout events:
9178 * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9179 * enables trace logging.
9181 * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9182 * out a dump file that will hopefully contain enough evidence to
9183 * figure out why the timeout event occurred.
9186 void smb_ServerMonitor(VOID * parmp)
9188 osi_queueHT_t in_progress = { NULL, NULL };
9189 HANDLE h_timer = NULL;
9193 h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9194 h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9195 h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9197 lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9199 h_all[0] = h_monitored_task_queue;
9201 h_all[2] = h_monitored_task_shutdown;
9206 rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9208 if (rv == WAIT_OBJECT_0) {
9210 smb_SlurpNewTaskMonitors(&in_progress);
9212 } else if (rv == WAIT_OBJECT_0 + 1) {
9214 smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9222 /* refresh timers */
9226 smb_PurgeOldTaskMonitors(&in_progress);
9227 t = (monitored_task *) in_progress.headp;
9229 if (t && !t->trace_timer_hit) {
9232 due = t->start_time;
9233 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9235 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9236 } else if (t && !t->dump_timer_hit) {
9240 due = t->start_time;
9241 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9243 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9245 CancelWaitableTimer(h_timer);
9247 /* CancelWaitableTimer() doesn't reset the timer if it
9248 was already signalled. */
9249 WaitForSingleObject(h_timer, 0);
9257 h = h_monitored_task_queue;
9258 h_monitored_task_queue = NULL;
9261 h = h_monitored_task_shutdown;
9262 h_monitored_task_shutdown = NULL;
9265 CloseHandle(h_timer);
9267 lock_FinalizeMutex(&_monitor_mx);
9271 monitored_task * task;
9273 while (in_progress.headp) {
9274 task = (monitored_task *) in_progress.headp;
9275 osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9279 for (task = (monitored_task *) smb_free_monitored_tasks;
9280 task; task = (monitored_task *) smb_free_monitored_tasks) {
9281 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9285 for (task = (monitored_task *) smb_monitored_tasks;
9286 task; task = (monitored_task *) smb_monitored_tasks) {
9287 osi_QRemove(&smb_monitored_tasks, &task->q);
9293 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9295 monitored_task * task;
9297 lock_ObtainMutex(&_monitor_mx);
9298 task = (monitored_task *) smb_free_monitored_tasks;
9300 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9301 lock_ReleaseMutex(&_monitor_mx);
9304 task = malloc(sizeof(monitored_task));
9305 memset(task, 0, sizeof(*task));
9307 task->task_id = task_id;
9308 task->started = started;
9313 GetSystemTimeAsFileTime(&now);
9314 task->start_time.HighPart = now.dwHighDateTime;
9315 task->start_time.LowPart = now.dwLowDateTime;
9318 lock_ObtainMutex(&_monitor_mx);
9319 osi_QAdd(&smb_monitored_tasks, &task->q);
9320 lock_ReleaseMutex(&_monitor_mx);
9322 SetEvent(h_monitored_task_queue);
9325 void smb_ShutdownMonitor()
9327 SetEvent(h_monitored_task_shutdown);
9331 * The top level loop for handling SMB request messages. Each server thread
9332 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9333 * NCB and buffer for the incoming request are loaned to us.
9335 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
9336 * to immediately send a request for the rest of the data. This must come
9337 * before any other traffic for that session, so we delay setting the session
9338 * event until that data has come in.
9340 void smb_Server(VOID *parmp)
9342 INT_PTR myIdx = (INT_PTR) parmp;
9346 smb_packet_t *outbufp;
9348 int idx_NCB, idx_session;
9350 smb_vc_t *vcp = NULL;
9353 rx_StartClientThread();
9355 outncbp = smb_GetNCB();
9356 outbufp = smb_GetPacket();
9357 outbufp->ncbp = outncbp;
9365 cm_ResetServerPriority();
9367 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9370 /* terminate silently if shutdown flag is set */
9371 if (code == WAIT_OBJECT_0) {
9372 if (smbShutdownFlag == 1) {
9373 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9379 /* error checking */
9380 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9382 int abandonIdx = code - WAIT_ABANDONED_0;
9383 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9386 if (code == WAIT_IO_COMPLETION)
9388 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9392 if (code == WAIT_TIMEOUT)
9394 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9397 if (code == WAIT_FAILED)
9399 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9402 idx_NCB = code - WAIT_OBJECT_0;
9404 /* check idx range! */
9405 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9407 /* this is fatal - log as much as possible */
9408 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9409 osi_assertx(0, "invalid index");
9412 ncbp = NCBs[idx_NCB];
9413 idx_session = NCBsessions[idx_NCB];
9414 rc = ncbp->ncb_retcode;
9416 if (rc != NRC_PENDING && rc != NRC_GOODRET)
9417 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9421 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9425 /* Can this happen? Or is it just my UNIX paranoia? */
9426 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9431 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9434 /* Client closed session */
9435 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9437 lock_ObtainMutex(&vcp->mx);
9438 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9439 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9441 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9442 lock_ReleaseMutex(&vcp->mx);
9443 lock_ObtainWrite(&smb_globalLock);
9444 dead_sessions[vcp->session] = TRUE;
9445 lock_ReleaseWrite(&smb_globalLock);
9447 lock_ReleaseMutex(&vcp->mx);
9449 smb_CleanupDeadVC(vcp);
9456 /* Treat as transient error */
9457 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9460 "dispatch smb recv failed, message incomplete, ncb_length %d",
9463 "SMB message incomplete, "
9464 "length %d", ncbp->ncb_length);
9467 * We used to discard the packet.
9468 * Instead, try handling it normally.
9472 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9476 /* A weird error code. Log it, sleep, and continue. */
9477 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9479 lock_ObtainMutex(&vcp->mx);
9480 if (vcp->errorCount++ > 3) {
9481 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9482 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9483 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9485 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9486 lock_ReleaseMutex(&vcp->mx);
9487 lock_ObtainWrite(&smb_globalLock);
9488 dead_sessions[vcp->session] = TRUE;
9489 lock_ReleaseWrite(&smb_globalLock);
9491 lock_ReleaseMutex(&vcp->mx);
9493 smb_CleanupDeadVC(vcp);
9499 lock_ReleaseMutex(&vcp->mx);
9503 thrd_SetEvent(SessionEvents[idx_session]);
9509 /* Success, so now dispatch on all the data in the packet */
9511 smb_concurrentCalls++;
9512 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9513 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9516 * If at this point vcp is NULL (implies that packet was invalid)
9517 * then we are in big trouble. This means either :
9518 * a) we have the wrong NCB.
9519 * b) Netbios screwed up the call.
9520 * c) The VC was already marked dead before we were able to
9522 * Obviously this implies that
9523 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9524 * lanas[idx_session] != ncbp->ncb_lana_num )
9525 * Either way, we can't do anything with this packet.
9526 * Log, sleep and resume.
9529 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9533 ncbp->ncb_lana_num);
9535 /* Also log in the trace log. */
9536 osi_Log4(smb_logp, "Server: VCP does not exist!"
9537 "LSNs[idx_session]=[%d],"
9538 "lanas[idx_session]=[%d],"
9539 "ncbp->ncb_lsn=[%d],"
9540 "ncbp->ncb_lana_num=[%d]",
9544 ncbp->ncb_lana_num);
9546 /* thrd_Sleep(1000); Don't bother sleeping */
9547 thrd_SetEvent(SessionEvents[idx_session]);
9548 smb_concurrentCalls--;
9552 cm_SetRequestStartTime();
9553 if (smb_monitorReqs) {
9554 smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9557 vcp->errorCount = 0;
9558 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9559 smbp = (smb_t *)bufp->data;
9566 if (smbp->com == 0x1d) {
9567 /* Special handling for Write Raw */
9568 raw_write_cont_t rwc;
9570 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9571 if (rwc.code == 0) {
9572 EVENT_HANDLE rwevent;
9573 char eventName[MAX_PATH];
9575 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9576 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9577 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9578 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9580 ncbp->ncb_command = NCBRECV | ASYNCH;
9581 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9582 ncbp->ncb_lana_num = vcp->lana;
9583 ncbp->ncb_buffer = rwc.buf;
9584 ncbp->ncb_length = 65535;
9585 ncbp->ncb_event = rwevent;
9587 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9588 thrd_CloseHandle(rwevent);
9590 thrd_SetEvent(SessionEvents[idx_session]);
9592 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9594 else if (smbp->com == 0xa0) {
9596 * Serialize the handling for NT Transact
9599 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9600 thrd_SetEvent(SessionEvents[idx_session]);
9602 thrd_SetEvent(SessionEvents[idx_session]);
9603 /* TODO: what else needs to be serialized? */
9604 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9608 __except( smb_ServerExceptionFilter() ) {
9612 if (smb_monitorReqs) {
9613 smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9615 smb_concurrentCalls--;
9618 thrd_SetEvent(NCBavails[idx_NCB]);
9623 smb_FreePacket(outbufp);
9625 smb_FreeNCB(outncbp);
9629 * Exception filter for the server threads. If an exception occurs in the
9630 * dispatch routines, which is where exceptions are most common, then do a
9631 * force trace and give control to upstream exception handlers. Useful for
9634 DWORD smb_ServerExceptionFilter(void) {
9635 /* While this is not the best time to do a trace, if it succeeds, then
9636 * we have a trace (assuming tracing was enabled). Otherwise, this should
9637 * throw a second exception.
9639 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9640 afsd_ForceTrace(TRUE);
9641 buf_ForceTrace(TRUE);
9642 return EXCEPTION_CONTINUE_SEARCH;
9646 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9647 * If the number of server threads is M, and the number of live sessions is
9648 * N, then the number of NCB's in use at any time either waiting for, or
9649 * holding, received messages is M + N, so that is how many NCB's get created.
9651 void InitNCBslot(int idx)
9653 struct smb_packet *bufp;
9654 EVENT_HANDLE retHandle;
9656 char eventName[MAX_PATH];
9658 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9660 NCBs[idx] = smb_GetNCB();
9661 sprintf(eventName,"NCBavails[%d]", idx);
9662 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9663 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9664 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9665 sprintf(eventName,"NCBevents[%d]", idx);
9666 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9667 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9668 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9669 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9670 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9671 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9672 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9673 for (i=0; i<smb_NumServerThreads; i++)
9674 NCBreturns[i][idx] = retHandle;
9675 bufp = smb_GetPacket();
9676 bufp->spacep = cm_GetSpace();
9680 /* listen for new connections */
9681 void smb_Listener(void *parmp)
9687 afs_uint32 session, thread;
9688 smb_vc_t *vcp = NULL;
9690 char rname[NCBNAMSZ+1];
9691 char cname[MAX_COMPUTERNAME_LENGTH+1];
9692 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9693 INT_PTR lana = (INT_PTR) parmp;
9694 char eventName[MAX_PATH];
9695 int bridgeCount = 0;
9696 int nowildCount = 0;
9698 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9699 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9700 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9701 thrd_ResetEvent(ListenerShutdown[lana]);
9703 ncbp = smb_GetNCB();
9705 /* retrieve computer name */
9706 GetComputerName(cname, &cnamelen);
9709 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9710 memset(ncbp, 0, sizeof(NCB));
9713 ncbp->ncb_command = NCBLISTEN;
9714 ncbp->ncb_rto = 0; /* No receive timeout */
9715 ncbp->ncb_sto = 0; /* No send timeout */
9717 /* pad out with spaces instead of null termination */
9718 len = (long)strlen(smb_localNamep);
9719 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9720 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9722 strcpy(ncbp->ncb_callname, "*");
9723 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9725 ncbp->ncb_lana_num = (UCHAR)lana;
9727 code = Netbios(ncbp);
9729 if (code == NRC_NAMERR) {
9730 /* An smb shutdown or Vista resume must have taken place */
9732 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9733 ncbp->ncb_lana_num);
9734 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9736 if (lock_TryMutex(&smb_StartedLock)) {
9737 lana_list.lana[i] = LANA_INVALID;
9738 lock_ReleaseMutex(&smb_StartedLock);
9741 } else if (code == NRC_BRIDGE || code != 0) {
9742 int lanaRemaining = 0;
9744 if (code == NRC_BRIDGE) {
9745 if (++bridgeCount <= 5) {
9746 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9749 } else if (code == NRC_NOWILD) {
9750 if (++nowildCount <= 5) {
9751 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9753 if (bridgeCount > 0) {
9754 memset(ncbp, 0, sizeof(*ncbp));
9755 ncbp->ncb_command = NCBADDNAME;
9756 ncbp->ncb_lana_num = (UCHAR)lana;
9757 /* pad out with spaces instead of null termination */
9758 len = (long)strlen(smb_localNamep);
9759 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9760 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9761 code = Netbios(ncbp);
9767 while (!lock_TryMutex(&smb_StartedLock)) {
9768 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9774 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9775 ncbp->ncb_lana_num, ncb_error_string(code));
9776 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9777 ncbp->ncb_lana_num, ncb_error_string(code));
9779 for (i = 0; i < lana_list.length; i++) {
9780 if (lana_list.lana[i] == lana) {
9781 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9782 lana_list.lana[i] = LANA_INVALID;
9784 if (lana_list.lana[i] != LANA_INVALID)
9788 if (lanaRemaining == 0) {
9789 cm_VolStatus_Network_Stopped(cm_NetbiosName
9794 smb_ListenerState = SMB_LISTENER_STOPPED;
9795 smb_LANadapter = LANA_INVALID;
9796 lana_list.length = 0;
9798 lock_ReleaseMutex(&smb_StartedLock);
9802 else if (code != 0) {
9803 char tbuffer[AFSPATHMAX];
9805 /* terminate silently if shutdown flag is set */
9806 while (!lock_TryMutex(&smb_StartedLock)) {
9807 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9813 "NCBLISTEN lana=%d failed with code %d [%s]",
9814 ncbp->ncb_lana_num, code, ncb_error_string(code));
9816 "Client exiting due to network failure. Please restart client.\n");
9819 "Client exiting due to network failure. Please restart client.\n"
9820 "NCBLISTEN lana=%d failed with code %d [%s]",
9821 ncbp->ncb_lana_num, code, ncb_error_string(code));
9823 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9824 MB_OK|MB_SERVICE_NOTIFICATION);
9825 osi_panic(tbuffer, __FILE__, __LINE__);
9827 lock_ReleaseMutex(&smb_StartedLock);
9832 /* a successful packet received. clear bridge error count */
9836 /* check for remote conns */
9837 /* first get remote name and insert null terminator */
9838 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9839 for (i=NCBNAMSZ; i>0; i--) {
9840 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9846 /* compare with local name */
9848 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9849 flags |= SMB_VCFLAG_REMOTECONN;
9852 lock_ObtainMutex(&smb_ListenerLock);
9854 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9855 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9857 /* now ncbp->ncb_lsn is the connection ID */
9858 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9859 if (vcp->session == 0) {
9860 /* New generation */
9861 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9864 /* Log session startup */
9866 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9867 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9868 #endif /* NOTSERVICE */
9869 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9870 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9872 if (reportSessionStartups) {
9873 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9876 lock_ObtainMutex(&vcp->mx);
9877 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9878 vcp->flags |= flags;
9879 lock_ReleaseMutex(&vcp->mx);
9881 /* Allocate slot in session arrays */
9882 /* Re-use dead session if possible, otherwise add one more */
9883 /* But don't look at session[0], it is reserved */
9884 lock_ObtainWrite(&smb_globalLock);
9885 for (session = 1; session < numSessions; session++) {
9886 if (dead_sessions[session]) {
9887 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9888 dead_sessions[session] = FALSE;
9892 lock_ReleaseWrite(&smb_globalLock);
9894 /* We are re-using an existing VC because the lsn and lana
9896 session = vcp->session;
9898 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9900 /* Log session startup */
9902 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9903 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9904 #endif /* NOTSERVICE */
9905 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9906 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9908 if (reportSessionStartups) {
9909 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9913 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9914 unsigned long code = CM_ERROR_ALLBUSY;
9915 smb_packet_t * outp = smb_GetPacket();
9916 unsigned char *outWctp;
9919 smb_FormatResponsePacket(vcp, NULL, outp);
9922 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9923 unsigned long NTStatus;
9924 smb_MapNTError(code, &NTStatus, FALSE);
9925 outWctp = outp->wctp;
9926 smbp = (smb_t *) &outp->data;
9930 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9931 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9932 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9933 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9934 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9936 unsigned short errCode;
9937 unsigned char errClass;
9938 smb_MapCoreError(code, vcp, &errCode, &errClass);
9939 outWctp = outp->wctp;
9940 smbp = (smb_t *) &outp->data;
9944 smbp->errLow = (unsigned char) (errCode & 0xff);
9945 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9946 smbp->rcls = errClass;
9949 smb_SendPacket(vcp, outp);
9950 smb_FreePacket(outp);
9952 lock_ObtainMutex(&vcp->mx);
9953 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9954 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9956 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9957 lock_ReleaseMutex(&vcp->mx);
9958 lock_ObtainWrite(&smb_globalLock);
9959 dead_sessions[vcp->session] = TRUE;
9960 lock_ReleaseWrite(&smb_globalLock);
9961 smb_CleanupDeadVC(vcp);
9963 lock_ReleaseMutex(&vcp->mx);
9966 /* assert that we do not exceed the maximum number of sessions or NCBs.
9967 * we should probably want to wait for a session to be freed in case
9970 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9971 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9973 lock_ObtainMutex(&vcp->mx);
9974 vcp->session = session;
9975 lock_ReleaseMutex(&vcp->mx);
9976 lock_ObtainWrite(&smb_globalLock);
9977 LSNs[session] = ncbp->ncb_lsn;
9978 lanas[session] = ncbp->ncb_lana_num;
9979 lock_ReleaseWrite(&smb_globalLock);
9981 if (session == numSessions) {
9982 /* Add new NCB for new session */
9983 char eventName[MAX_PATH];
9985 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9987 InitNCBslot(numNCBs);
9988 lock_ObtainWrite(&smb_globalLock);
9990 lock_ReleaseWrite(&smb_globalLock);
9991 thrd_SetEvent(NCBavails[0]);
9992 thrd_SetEvent(NCBevents[0]);
9993 for (thread = 0; thread < smb_NumServerThreads; thread++)
9994 thrd_SetEvent(NCBreturns[thread][0]);
9995 /* Also add new session event */
9996 sprintf(eventName, "SessionEvents[%d]", session);
9997 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9998 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9999 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
10000 lock_ObtainWrite(&smb_globalLock);
10002 lock_ReleaseWrite(&smb_globalLock);
10003 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
10004 thrd_SetEvent(SessionEvents[0]);
10006 thrd_SetEvent(SessionEvents[session]);
10009 smb_ReleaseVC(vcp);
10012 lock_ReleaseMutex(&smb_ListenerLock);
10013 } /* dispatch while loop */
10017 thrd_SetEvent(ListenerShutdown[lana]);
10022 smb_configureBackConnectionHostNames(int bEnable)
10024 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
10025 * there is a restriction on the use of SMB authentication on loopback connections.
10026 * There are two work arounds available:
10028 * (1) We can disable the check for matching host names. This does not
10029 * require a reboot:
10030 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
10031 * "DisableLoopbackCheck"=dword:00000001
10033 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
10034 * does require a reboot:
10035 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
10036 * "BackConnectionHostNames"=multi-sz
10038 * The algorithm will be:
10039 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
10040 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
10041 * (2b1) and check to see if DisableLoopbackCheck is set.
10042 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
10043 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
10044 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
10045 * check for the UnsetDisableLoopbackCheck value.
10046 * If set, set the DisableLoopbackCheck flag to 0x0
10047 * and delete the UnsetDisableLoopbackCheck value
10049 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
10050 * force Windows to use the loopback authentication mechanism for the specified
10053 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
10054 * service session that set it.
10060 DWORD dwSize, dwAllocSize;
10062 PBYTE pHostNames = NULL, pName = NULL;
10063 PBYTE pOrigNames = NULL, pOrig = NULL;
10064 BOOL bNameFound = FALSE;
10065 DWORD dwLoopbackCheckDisabled;
10066 DWORD dwszBackConnectionHostNames;
10067 size_t nbsize = strlen(cm_NetbiosName) + 2;
10069 static BOOL bLoopbackCheckDisabled = FALSE;
10071 /* DisableLoopbackCheck */
10072 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10073 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10075 KEY_READ|KEY_WRITE,
10076 &hkLsa) == ERROR_SUCCESS )
10078 dwSize = sizeof(DWORD);
10079 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwLoopbackCheckDisabled, &dwSize) != ERROR_SUCCESS)
10081 dwLoopbackCheckDisabled = 0;
10084 hkLsa = INVALID_HANDLE_VALUE;
10087 /* BackConnectionHostNames */
10088 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10089 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
10091 KEY_READ|KEY_WRITE,
10092 &hkMSV10) == ERROR_SUCCESS )
10094 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
10095 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10096 (dwType == REG_MULTI_SZ))
10098 dwAllocSize += 1 /* in case the source string is not nul terminated */
10099 + (DWORD)strlen(cm_NetbiosName) + 2;
10100 pHostNames = malloc(dwAllocSize);
10101 dwszBackConnectionHostNames = dwAllocSize;
10102 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
10103 pHostNames, &dwszBackConnectionHostNames) == ERROR_SUCCESS)
10105 for (pName = pHostNames;
10106 (pName - pHostNames < (int) dwszBackConnectionHostNames) && *pName ;
10107 pName += strlen(pName) + 1)
10109 if ( !stricmp(pName, cm_NetbiosName) ) {
10118 if ( !bNameFound ) {
10119 size_t size = strlen(cm_NetbiosName) + 2;
10120 if ( !pHostNames ) {
10121 pHostNames = malloc(size);
10122 pName = pHostNames;
10124 StringCbCopyA(pName, size, cm_NetbiosName);
10126 *pName = '\0'; /* add a second nul terminator */
10128 dwType = REG_MULTI_SZ;
10129 dwSize = (DWORD)(pName - pHostNames + 1);
10130 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10132 if ( hkLsa != INVALID_HANDLE_VALUE && !dwLoopbackCheckDisabled)
10134 dwType = REG_DWORD;
10135 dwSize = sizeof(DWORD);
10136 dwLoopbackCheckDisabled = 1;
10137 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwLoopbackCheckDisabled, dwSize);
10139 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10140 AFSREG_CLT_OPENAFS_SUBKEY,
10143 REG_OPTION_NON_VOLATILE,
10144 KEY_READ|KEY_WRITE,
10147 NULL) == ERROR_SUCCESS) {
10149 dwType = REG_DWORD;
10150 dwSize = sizeof(DWORD);
10152 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10153 bLoopbackCheckDisabled = TRUE;
10154 RegCloseKey(hkClient);
10157 } else if (!bLoopbackCheckDisabled && hkLsa != INVALID_HANDLE_VALUE) {
10158 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10159 AFSREG_CLT_OPENAFS_SUBKEY,
10162 REG_OPTION_NON_VOLATILE,
10163 KEY_READ|KEY_WRITE,
10166 NULL) == ERROR_SUCCESS) {
10168 dwSize = sizeof(DWORD);
10169 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10171 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10174 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10175 RegCloseKey(hkClient);
10179 * Disable SMB. Start by removing the DisableLoopbackCheck value if present.
10181 if (hkLsa != INVALID_HANDLE_VALUE) {
10182 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10183 AFSREG_CLT_OPENAFS_SUBKEY,
10186 REG_OPTION_NON_VOLATILE,
10187 KEY_READ|KEY_WRITE,
10190 NULL) == ERROR_SUCCESS) {
10192 dwSize = sizeof(DWORD);
10193 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10195 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10198 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10199 RegCloseKey(hkClient);
10202 /* Then remove our NetbiosName from the BackConnectionHostNames list */
10203 if ( bNameFound ) {
10205 * we found our name so if the size of the value is smaller
10206 * or equal to the length of our name alone, we are done.
10208 if ( dwszBackConnectionHostNames <= nbsize ) {
10209 RegDeleteValue( hkMSV10, "BackConnectionHostNames");
10211 pOrigNames = pHostNames;
10212 pHostNames = malloc(dwAllocSize);
10214 pOrig = pOrigNames;
10215 pName = pHostNames;
10216 while (pOrig - pOrigNames < dwszBackConnectionHostNames) {
10217 len = strlen(pOrig);
10218 if ( stricmp(pOrig, cm_NetbiosName)) {
10220 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10225 *pName = '\0'; /* add a second nul terminator */
10228 dwType = REG_MULTI_SZ;
10229 dwSize = (DWORD)(pName - pHostNames + 1);
10230 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10245 RegCloseKey(hkMSV10);
10248 if ( hkLsa != INVALID_HANDLE_VALUE ) {
10249 RegCloseKey(hkLsa);
10255 smb_configureExtendedSMBSessionTimeouts(int bEnable)
10258 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10259 * new functionality:
10261 * [HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters]
10262 * "ReconnectableServers" REG_MULTI_SZ
10263 * "ExtendedSessTimeout" REG_DWORD (seconds)
10264 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
10266 * These values can be used to prevent the smb redirector from timing out
10267 * smb connection to the afs smb server prematurely.
10271 DWORD dwSize, dwAllocSize;
10273 PBYTE pHostNames = NULL, pOrigNames = NULL, pName = NULL, pOrig = NULL;
10274 BOOL bNameFound = FALSE;
10275 DWORD dwszReconnectableServers;
10276 DWORD dwszServersWithExtendedSessTimeout;
10277 size_t nbsize = strlen(cm_NetbiosName) + 2;
10280 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10281 "SYSTEM\\CurrentControlSet\\Services\\LanmanWorkstation\\Parameters",
10283 KEY_READ|KEY_WRITE,
10284 &hkLanman) == ERROR_SUCCESS )
10286 if ((RegQueryValueEx( hkLanman, "ReconnectableServers", 0,
10287 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10288 (dwType == REG_MULTI_SZ))
10290 dwAllocSize += 1 /* in case the source string is not nul terminated */
10291 + (DWORD)strlen(cm_NetbiosName) + 2;
10292 pHostNames = malloc(dwAllocSize);
10293 dwszReconnectableServers = dwAllocSize;
10294 if (RegQueryValueEx( hkLanman, "ReconnectableServers", 0, &dwType,
10295 pHostNames, &dwszReconnectableServers) == ERROR_SUCCESS)
10297 for (pName = pHostNames;
10298 (pName - pHostNames < (int) dwszReconnectableServers) && *pName ;
10299 pName += strlen(pName) + 1)
10301 if ( !stricmp(pName, cm_NetbiosName) ) {
10310 * If our name was not found and we are enabling SMB,
10311 * add our name to the current value.
10313 if ( bEnable && !bNameFound ) {
10314 if ( !pHostNames ) {
10315 pHostNames = malloc(nbsize);
10316 pName = pHostNames;
10318 StringCbCopyA(pName, nbsize, cm_NetbiosName);
10319 pName += nbsize - 1;
10320 *pName = '\0'; /* add a second nul terminator */
10322 dwType = REG_MULTI_SZ;
10323 dwSize = (DWORD)(pName - pHostNames + 1);
10324 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10328 * If our name was found and we are disabling SMB,
10329 * remove our name from the list and update the value.
10330 * If our name is the only entry, remove the value.
10332 if ( !bEnable && bNameFound ) {
10334 * we found our name so if the size of the value is smaller
10335 * or equal to the length of our name alone, we are done.
10337 if ( dwszReconnectableServers <= nbsize ) {
10338 RegDeleteValue( hkLanman, "ReconnectableServers");
10340 pOrigNames = pHostNames;
10341 pHostNames = malloc(dwAllocSize);
10343 pOrig = pOrigNames;
10344 pName = pHostNames;
10345 while (pOrig - pOrigNames <dwszReconnectableServers ) {
10346 len = strlen(pOrig);
10347 if ( stricmp(pOrig, cm_NetbiosName)) {
10349 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10354 *pName = '\0'; /* add a second nul terminator */
10357 dwType = REG_MULTI_SZ;
10358 dwSize = (DWORD)(pName - pHostNames + 1);
10359 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10373 if ((RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0,
10374 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10375 (dwType == REG_MULTI_SZ))
10377 dwAllocSize += 1 /* in case the source string is not nul terminated */
10378 + (DWORD)strlen(cm_NetbiosName) + 2;
10379 pHostNames = malloc(dwAllocSize);
10380 dwszServersWithExtendedSessTimeout = dwAllocSize;
10381 if (RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, &dwType,
10382 pHostNames, &dwszServersWithExtendedSessTimeout) == ERROR_SUCCESS)
10384 for (pName = pHostNames;
10385 (pName - pHostNames < (int) dwszServersWithExtendedSessTimeout) && *pName ;
10386 pName += strlen(pName) + 1)
10388 if ( !stricmp(pName, cm_NetbiosName) ) {
10397 * If our name was not found and we are enabling SMB,
10398 * add our name to the current value.
10400 if ( bEnable && !bNameFound ) {
10401 size_t size = strlen(cm_NetbiosName) + 2;
10402 if ( !pHostNames ) {
10403 pHostNames = malloc(size);
10404 pName = pHostNames;
10406 StringCbCopyA(pName, size, cm_NetbiosName);
10408 *pName = '\0'; /* add a second nul terminator */
10410 dwType = REG_MULTI_SZ;
10411 dwSize = (DWORD)(pName - pHostNames + 1);
10412 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10416 * If our name was found and we are disabling SMB,
10417 * remove our name from the list and update the value.
10418 * If our name is the only entry, remove the value.
10420 if ( !bEnable && bNameFound ) {
10422 * we found our name so if the size of the value is smaller
10423 * or equal to the length of our name alone, we are done.
10425 if ( dwszServersWithExtendedSessTimeout <= nbsize ) {
10426 RegDeleteValue( hkLanman, "ServersWithExtendedSessTimeout");
10428 pOrigNames = pHostNames;
10429 pHostNames = malloc(dwAllocSize);
10431 pOrig = pOrigNames;
10432 pName = pHostNames;
10433 while (pOrig - pOrigNames < dwszServersWithExtendedSessTimeout) {
10434 len = strlen(pOrig);
10435 if ( stricmp(pOrig, cm_NetbiosName)) {
10437 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10442 *pName = '\0'; /* add a second nul terminator */
10445 dwType = REG_MULTI_SZ;
10446 dwSize = (DWORD)(pName - pHostNames + 1);
10447 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10462 if ((RegQueryValueEx( hkLanman, "ExtendedSessTimeout", 0,
10463 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10464 (dwType != REG_DWORD))
10466 dwType = REG_DWORD;
10467 dwSize = sizeof(dwValue);
10468 dwValue = 300; /* 5 minutes */
10469 RegSetValueEx( hkLanman, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10472 RegCloseKey(hkLanman);
10477 smb_LanAdapterChangeThread(void *param)
10480 * Give the IPAddrDaemon thread a chance
10481 * to block before we trigger.
10484 smb_LanAdapterChange(0);
10487 void smb_SetLanAdapterChangeDetected(void)
10492 lock_ObtainMutex(&smb_StartedLock);
10494 if (!powerStateSuspended) {
10495 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10496 NULL, 0, &lpid, "smb_LanAdapterChange");
10497 if (phandle == NULL) {
10501 gle = GetLastError();
10502 StringCchPrintf( msg, sizeof(msg)/sizeof(msg[0]),
10503 "smb_LanAdapterChangeThread thread creation failure - gle 0x%x",
10505 osi_assertx(TRUE, msg);
10507 thrd_CloseHandle(phandle);
10510 smb_LanAdapterChangeDetected = 1;
10511 lock_ReleaseMutex(&smb_StartedLock);
10514 void smb_LanAdapterChange(int locked) {
10515 lana_number_t lanaNum;
10517 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
10519 LANA_ENUM temp_list;
10524 afsi_log("smb_LanAdapterChange");
10527 lock_ObtainMutex(&smb_StartedLock);
10529 smb_LanAdapterChangeDetected = 0;
10531 if (!powerStateSuspended &&
10532 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10533 LANA_NETBIOS_NAME_FULL | LANA_NETBIOS_NO_RESET)) &&
10534 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10535 if ( isGateway != bGateway ) {
10536 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10537 smb_LANadapter, lanaNum, isGateway, bGateway);
10539 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10540 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10541 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10544 NCB *ncbp = smb_GetNCB();
10545 ncbp->ncb_command = NCBENUM;
10546 ncbp->ncb_buffer = (PUCHAR)&temp_list;
10547 ncbp->ncb_length = sizeof(temp_list);
10548 code = Netbios(ncbp);
10550 if (temp_list.length != lana_list.length) {
10551 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10552 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10555 for (i=0; i<lana_list.length; i++) {
10556 if ( temp_list.lana[i] != lana_list.lana[i] ) {
10557 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10558 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10570 smb_StopListeners(1);
10571 smb_RestartListeners(1);
10574 lock_ReleaseMutex(&smb_StartedLock);
10577 /* initialize Netbios */
10578 int smb_NetbiosInit(int locked)
10581 int i, lana, code, l;
10583 int delname_tried=0;
10585 int lana_found = 0;
10586 lana_number_t lanaNum;
10592 lock_ObtainMutex(&smb_StartedLock);
10594 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10595 smb_ListenerState != SMB_LISTENER_STOPPED) {
10598 lock_ReleaseMutex(&smb_StartedLock);
10601 /* setup the NCB system */
10602 ncbp = smb_GetNCB();
10605 * Call lanahelper to get Netbios name, lan adapter number and gateway flag
10606 * This will reset all of the network adapter's netbios state.
10608 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10609 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10611 if (smb_LANadapter != LANA_INVALID)
10612 afsi_log("LAN adapter number %d", smb_LANadapter);
10614 afsi_log("LAN adapter number not determined");
10617 afsi_log("Set for gateway service");
10619 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10621 /* something went horribly wrong. We can't proceed without a netbios name */
10623 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10624 osi_panic(buf, __FILE__, __LINE__);
10627 /* remember the name */
10628 len = (int)strlen(cm_NetbiosName);
10629 if (smb_localNamep)
10630 free(smb_localNamep);
10631 smb_localNamep = malloc(len+1);
10632 strcpy(smb_localNamep, cm_NetbiosName);
10633 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10635 /* Also copy the value to the client character encoded string */
10636 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10638 if (smb_LANadapter == LANA_INVALID) {
10639 ncbp->ncb_command = NCBENUM;
10640 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10641 ncbp->ncb_length = sizeof(lana_list);
10642 code = Netbios(ncbp);
10644 afsi_log("Netbios NCBENUM error code %d", code);
10645 osi_panic(s, __FILE__, __LINE__);
10649 lana_list.length = 1;
10650 lana_list.lana[0] = smb_LANadapter;
10653 for (i = 0; i < lana_list.length; i++) {
10654 /* reset the adaptor: in Win32, this is required for every process, and
10655 * acts as an init call, not as a real hardware reset.
10657 ncbp->ncb_command = NCBRESET;
10658 ncbp->ncb_callname[0] = 100;
10659 ncbp->ncb_callname[2] = 100;
10660 ncbp->ncb_lana_num = lana_list.lana[i];
10661 code = Netbios(ncbp);
10663 code = ncbp->ncb_retcode;
10665 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10666 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10668 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10672 /* and declare our name so we can receive connections */
10673 memset(ncbp, 0, sizeof(*ncbp));
10674 len=lstrlen(smb_localNamep);
10675 memset(smb_sharename,' ',NCBNAMSZ);
10676 memcpy(smb_sharename,smb_localNamep,len);
10677 afsi_log("lana_list.length %d", lana_list.length);
10679 /* Keep the name so we can unregister it later */
10680 for (l = 0; l < lana_list.length; l++) {
10681 lana = lana_list.lana[l];
10683 ncbp->ncb_command = NCBADDNAME;
10684 ncbp->ncb_lana_num = lana;
10685 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10686 code = Netbios(ncbp);
10688 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10689 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10691 char name[NCBNAMSZ+1];
10693 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10694 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10698 code = ncbp->ncb_retcode;
10701 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10704 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10705 if (code == NRC_BRIDGE) { /* invalid LANA num */
10706 lana_list.lana[l] = LANA_INVALID;
10709 else if (code == NRC_DUPNAME) {
10710 afsi_log("Name already exists; try to delete it");
10711 memset(ncbp, 0, sizeof(*ncbp));
10712 ncbp->ncb_command = NCBDELNAME;
10713 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10714 ncbp->ncb_lana_num = lana;
10715 code = Netbios(ncbp);
10717 code = ncbp->ncb_retcode;
10719 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10721 if (code != 0 || delname_tried) {
10722 lana_list.lana[l] = LANA_INVALID;
10724 else if (code == 0) {
10725 if (!delname_tried) {
10733 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10734 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10738 smb_LANadapter = lana;
10739 lana_found = 1; /* at least one worked */
10743 osi_assertx(lana_list.length >= 0, "empty lana list");
10745 afsi_log("No valid LANA numbers found!");
10746 lana_list.length = 0;
10747 smb_LANadapter = LANA_INVALID;
10748 smb_ListenerState = SMB_LISTENER_STOPPED;
10749 cm_VolStatus_Network_Stopped(cm_NetbiosName
10756 /* we're done with the NCB now */
10759 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10760 if (lana_list.length > 0)
10761 osi_assert(smb_LANadapter != LANA_INVALID);
10764 lock_ReleaseMutex(&smb_StartedLock);
10766 return (lana_list.length > 0 ? 1 : 0);
10769 void smb_StartListeners(int locked)
10779 lock_ObtainMutex(&smb_StartedLock);
10781 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10783 lock_ReleaseMutex(&smb_StartedLock);
10787 afsi_log("smb_StartListeners");
10788 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10789 smb_configureBackConnectionHostNames(TRUE);
10791 /* Configure Extended SMB Session Timeouts */
10792 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10793 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10794 smb_configureExtendedSMBSessionTimeouts(TRUE);
10797 smb_ListenerState = SMB_LISTENER_STARTED;
10798 cm_VolStatus_Network_Started(cm_NetbiosName
10804 for (i = 0; i < lana_list.length; i++) {
10805 if (lana_list.lana[i] == LANA_INVALID)
10807 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10808 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10809 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10810 thrd_CloseHandle(phandle);
10813 lock_ReleaseMutex(&smb_StartedLock);
10816 void smb_RestartListeners(int locked)
10822 lock_ObtainMutex(&smb_StartedLock);
10824 if (powerStateSuspended)
10825 afsi_log("smb_RestartListeners called while suspended");
10827 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10828 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10829 if (smb_NetbiosInit(1))
10830 smb_StartListeners(1);
10831 } else if (smb_LanAdapterChangeDetected) {
10832 smb_LanAdapterChange(1);
10836 lock_ReleaseMutex(&smb_StartedLock);
10839 void smb_StopListener(NCB *ncbp, int lana, int wait)
10843 memset(ncbp, 0, sizeof(*ncbp));
10844 ncbp->ncb_command = NCBDELNAME;
10845 ncbp->ncb_lana_num = lana;
10846 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10847 code = Netbios(ncbp);
10849 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10850 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10852 /* and then reset the LANA; this will cause the listener threads to exit */
10853 ncbp->ncb_command = NCBRESET;
10854 ncbp->ncb_callname[0] = 100;
10855 ncbp->ncb_callname[2] = 100;
10856 ncbp->ncb_lana_num = lana;
10857 code = Netbios(ncbp);
10859 code = ncbp->ncb_retcode;
10861 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10863 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10867 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10870 void smb_StopListeners(int locked)
10879 lock_ObtainMutex(&smb_StartedLock);
10881 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10883 lock_ReleaseMutex(&smb_StartedLock);
10887 afsi_log("smb_StopListeners");
10888 smb_ListenerState = SMB_LISTENER_STOPPED;
10889 cm_VolStatus_Network_Stopped(cm_NetbiosName
10895 ncbp = smb_GetNCB();
10897 /* Unregister the SMB name */
10898 for (l = 0; l < lana_list.length; l++) {
10899 lana = lana_list.lana[l];
10901 if (lana != LANA_INVALID) {
10902 smb_StopListener(ncbp, lana, TRUE);
10904 /* mark the adapter invalid */
10905 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10909 /* force a re-evaluation of the network adapters */
10910 lana_list.length = 0;
10911 smb_LANadapter = LANA_INVALID;
10914 lock_ReleaseMutex(&smb_StartedLock);
10917 void smb_Init(osi_log_t *logp, int useV3,
10927 EVENT_HANDLE retHandle;
10928 char eventName[MAX_PATH];
10929 int startListeners = 0;
10934 smb_MBfunc = aMBfunc;
10938 /* Initialize smb_localZero */
10939 myTime.tm_isdst = -1; /* compute whether on DST or not */
10940 myTime.tm_year = 70;
10942 myTime.tm_mday = 1;
10943 myTime.tm_hour = 0;
10946 smb_localZero = mktime(&myTime);
10948 #ifdef AFS_FREELANCE_CLIENT
10949 /* Make sure the root.afs volume has the correct time */
10950 cm_noteLocalMountPointChange(FALSE);
10953 /* initialize the remote debugging log */
10956 /* and the global lock */
10957 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10958 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10960 /* Raw I/O data structures */
10961 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10963 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10964 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10966 /* 4 Raw I/O buffers */
10967 smb_RawBufs = calloc(65536,1);
10968 *((char **)smb_RawBufs) = NULL;
10969 for (i=0; i<3; i++) {
10970 char *rawBuf = calloc(65536,1);
10971 *((char **)rawBuf) = smb_RawBufs;
10972 smb_RawBufs = rawBuf;
10975 /* global free lists */
10976 smb_ncbFreeListp = NULL;
10977 smb_packetFreeListp = NULL;
10979 lock_ObtainMutex(&smb_StartedLock);
10980 startListeners = smb_NetbiosInit(1);
10982 /* Initialize listener and server structures */
10984 memset(dead_sessions, 0, sizeof(dead_sessions));
10985 sprintf(eventName, "SessionEvents[0]");
10986 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10987 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10988 afsi_log("Event Object Already Exists: %s", eventName);
10990 smb_NumServerThreads = nThreads;
10991 sprintf(eventName, "NCBavails[0]");
10992 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10993 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10994 afsi_log("Event Object Already Exists: %s", eventName);
10995 sprintf(eventName, "NCBevents[0]");
10996 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10997 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10998 afsi_log("Event Object Already Exists: %s", eventName);
10999 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
11000 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
11001 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11002 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11003 afsi_log("Event Object Already Exists: %s", eventName);
11004 for (i = 0; i < smb_NumServerThreads; i++) {
11005 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
11006 NCBreturns[i][0] = retHandle;
11009 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
11010 for (i = 0; i < smb_NumServerThreads; i++) {
11011 sprintf(eventName, "smb_ServerShutdown[%d]", i);
11012 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11013 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11014 afsi_log("Event Object Already Exists: %s", eventName);
11015 InitNCBslot((int)(i+1));
11017 numNCBs = smb_NumServerThreads + 1;
11019 /* Initialize dispatch table */
11020 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
11021 /* Prepare the table for unknown operations */
11022 for(i=0; i<= SMB_NOPCODES; i++) {
11023 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
11025 /* Fill in the ones we do know */
11026 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
11027 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
11028 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
11029 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
11030 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
11031 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
11032 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
11033 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
11034 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
11035 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
11036 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
11037 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
11038 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
11039 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
11040 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
11041 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
11042 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
11043 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
11044 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
11045 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
11046 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
11047 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11048 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
11049 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
11050 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
11051 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
11052 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
11053 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
11054 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11055 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
11056 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11057 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
11058 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
11059 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
11060 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11061 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
11062 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
11063 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
11064 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
11065 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
11066 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
11067 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
11068 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11069 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
11070 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11071 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
11072 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
11073 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
11074 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
11075 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
11076 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
11077 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
11078 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
11079 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
11080 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
11081 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
11082 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
11083 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
11084 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
11085 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
11086 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
11087 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
11088 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
11089 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
11090 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
11091 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11092 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
11093 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
11094 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
11095 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
11096 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
11097 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
11098 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
11099 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
11101 /* setup tran 2 dispatch table */
11102 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
11103 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
11104 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
11105 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
11106 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
11107 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
11108 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
11109 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
11110 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
11111 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
11112 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
11113 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
11114 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
11115 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
11116 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
11117 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
11118 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
11119 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
11121 /* setup the rap dispatch table */
11122 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
11123 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
11124 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
11125 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
11126 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
11130 /* if we are doing SMB authentication we have register outselves as a logon process */
11131 if (smb_authType != SMB_AUTH_NONE) {
11132 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
11133 LSA_STRING afsProcessName;
11134 LSA_OPERATIONAL_MODE dummy; /*junk*/
11136 afsProcessName.Buffer = "OpenAFSClientDaemon";
11137 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
11138 afsProcessName.MaximumLength = afsProcessName.Length + 1;
11140 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
11142 if (nts == STATUS_SUCCESS) {
11143 LSA_STRING packageName;
11144 /* we are registered. Find out the security package id */
11145 packageName.Buffer = MSV1_0_PACKAGE_NAME;
11146 packageName.Length = (USHORT)strlen(packageName.Buffer);
11147 packageName.MaximumLength = packageName.Length + 1;
11148 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
11149 if (nts == STATUS_SUCCESS) {
11151 * This code forces Windows to authenticate against the Logon Cache
11152 * first instead of attempting to authenticate against the Domain
11153 * Controller. When the Windows logon cache is enabled this improves
11154 * performance by removing the network access and works around a bug
11155 * seen at sites which are using a MIT Kerberos principal to login
11156 * to machines joined to a non-root domain in a multi-domain forest.
11157 * MsV1_0SetProcessOption was added in Windows XP.
11159 PVOID pResponse = NULL;
11160 ULONG cbResponse = 0;
11161 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
11163 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
11164 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
11165 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
11166 OptionsRequest.DisableOptions = FALSE;
11168 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
11171 sizeof(OptionsRequest),
11177 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
11178 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
11181 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
11183 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
11184 afsi_log("MsV1_0SetProcessOption success");
11186 /* END - code from Larry */
11188 smb_lsaLogonOrigin.Buffer = "OpenAFS";
11189 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
11190 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
11192 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
11194 /* something went wrong. We report the error and revert back to no authentication
11195 because we can't perform any auth requests without a successful lsa handle
11196 or sec package id. */
11197 afsi_log("Reverting to NO SMB AUTH");
11198 smb_authType = SMB_AUTH_NONE;
11201 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
11203 /* something went wrong. We report the error and revert back to no authentication
11204 because we can't perform any auth requests without a successful lsa handle
11205 or sec package id. */
11206 afsi_log("Reverting to NO SMB AUTH");
11207 smb_authType = SMB_AUTH_NONE;
11211 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
11212 * time prevents the failure of authentication when logged into Windows with an
11213 * external Kerberos principal mapped to a local account.
11215 else if ( smb_authType == SMB_AUTH_EXTENDED) {
11216 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
11217 * then the only option is NTLMSSP anyway; so just fallback.
11222 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
11223 if (secBlobLength == 0) {
11224 smb_authType = SMB_AUTH_NTLM;
11225 afsi_log("Reverting to SMB AUTH NTLM");
11234 /* Now get ourselves a domain name. */
11235 /* For now we are using the local computer name as the domain name.
11236 * It is actually the domain for local logins, and we are acting as
11237 * a local SMB server.
11239 bufsize = lengthof(smb_ServerDomainName) - 1;
11240 GetComputerNameW(smb_ServerDomainName, &bufsize);
11241 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
11242 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
11245 /* Start listeners, waiters, servers, and daemons */
11246 if (startListeners)
11247 smb_StartListeners(1);
11249 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
11250 NULL, 0, &lpid, "smb_ClientWaiter");
11251 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
11252 thrd_CloseHandle(phandle);
11254 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
11255 NULL, 0, &lpid, "smb_ServerWaiter");
11256 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
11257 thrd_CloseHandle(phandle);
11259 for (i=0; i<smb_NumServerThreads; i++) {
11260 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
11261 (void *) i, 0, &lpid, "smb_Server");
11262 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
11263 thrd_CloseHandle(phandle);
11266 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
11267 NULL, 0, &lpid, "smb_Daemon");
11268 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
11269 thrd_CloseHandle(phandle);
11271 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
11272 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
11273 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
11274 thrd_CloseHandle(phandle);
11276 if (smb_monitorReqs) {
11277 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
11278 NULL, 0, &lpid, "smb_ServerMonitor");
11279 osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
11280 thrd_CloseHandle(phandle);
11283 lock_ReleaseMutex(&smb_StartedLock);
11287 void smb_Shutdown(void)
11297 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11299 /* setup the NCB system */
11300 ncbp = smb_GetNCB();
11302 /* Block new sessions by setting shutdown flag */
11303 smbShutdownFlag = 1;
11305 /* Hang up all sessions */
11306 memset(ncbp, 0, sizeof(NCB));
11307 for (i = 1; i < numSessions; i++)
11309 if (dead_sessions[i])
11312 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11313 ncbp->ncb_command = NCBHANGUP;
11314 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
11315 ncbp->ncb_lsn = (UCHAR)LSNs[i];
11316 code = Netbios(ncbp);
11317 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11318 if (code == 0) code = ncbp->ncb_retcode;
11320 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11321 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11325 /* Trigger the shutdown of all SMB threads */
11326 for (i = 0; i < smb_NumServerThreads; i++)
11327 thrd_SetEvent(NCBreturns[i][0]);
11329 thrd_SetEvent(NCBevents[0]);
11330 thrd_SetEvent(SessionEvents[0]);
11331 thrd_SetEvent(NCBavails[0]);
11333 for (i = 0;i < smb_NumServerThreads; i++) {
11334 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11335 if (code == WAIT_OBJECT_0) {
11338 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11339 thrd_SetEvent(NCBreturns[i--][0]);
11343 /* Delete Netbios name */
11344 memset(ncbp, 0, sizeof(NCB));
11345 for (i = 0; i < lana_list.length; i++) {
11346 if (lana_list.lana[i] == LANA_INVALID) continue;
11347 ncbp->ncb_command = NCBDELNAME;
11348 ncbp->ncb_lana_num = lana_list.lana[i];
11349 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11350 code = Netbios(ncbp);
11352 code = ncbp->ncb_retcode;
11354 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11355 ncbp->ncb_lana_num, code);
11360 /* Release the reference counts held by the VCs */
11361 lock_ObtainWrite(&smb_rctLock);
11362 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11367 if (vcp->magic != SMB_VC_MAGIC)
11368 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11369 __FILE__, __LINE__);
11371 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11373 if (fidp->scp != NULL) {
11376 lock_ReleaseWrite(&smb_rctLock);
11377 lock_ObtainMutex(&fidp->mx);
11378 if (fidp->scp != NULL) {
11381 lock_ObtainWrite(&scp->rw);
11382 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11383 lock_ReleaseWrite(&scp->rw);
11384 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11385 cm_ReleaseSCache(scp);
11387 lock_ReleaseMutex(&fidp->mx);
11388 lock_ObtainWrite(&smb_rctLock);
11392 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11394 smb_ReleaseVCNoLock(tidp->vcp);
11396 cm_user_t *userp = tidp->userp;
11397 tidp->userp = NULL;
11398 cm_ReleaseUser(userp);
11402 lock_ReleaseWrite(&smb_rctLock);
11405 if (smb_monitorReqs) {
11406 smb_ShutdownMonitor();
11410 /* Get the UNC \\<servername>\<sharename> prefix. */
11411 char *smb_GetSharename()
11416 /* Make sure we have been properly initialized. */
11417 if (smb_localNamep == NULL)
11420 /* Allocate space for \\<servername>\<sharename>, plus the
11423 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11424 name = malloc(len);
11425 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11431 void smb_LogPacket(smb_packet_t *packet)
11435 unsigned length, paramlen, datalen, i, j;
11437 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11439 if (!packet) return;
11441 osi_Log0(smb_logp, "*** SMB packet dump ***");
11443 smbp = (smb_t *) packet->data;
11444 vp = (BYTE *) packet->data;
11446 paramlen = smbp->wct * 2;
11447 datalen = *((WORD *) (smbp->vdata + paramlen));
11448 length = sizeof(*smbp) + paramlen + 1 + datalen;
11450 for (i=0;i < length; i+=16)
11452 memset( buf, ' ', 80 );
11455 itoa( i, buf, 16 );
11457 buf[strlen(buf)] = ' ';
11459 cp = (BYTE*) buf + 7;
11461 for (j=0;j < 16 && (i+j)<length; j++)
11463 *(cp++) = hex[vp[i+j] >> 4];
11464 *(cp++) = hex[vp[i+j] & 0xf];
11474 for (j=0;j < 16 && (i+j)<length;j++)
11476 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11487 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11490 osi_Log0(smb_logp, "*** End SMB packet dump ***");
11492 #endif /* LOG_PACKET */
11495 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11501 smb_username_t *unp;
11502 smb_waitingLockRequest_t *wlrp;
11505 lock_ObtainRead(&smb_rctLock);
11507 sprintf(output, "begin dumping smb_username_t\r\n");
11508 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11509 for (unp = usernamesp; unp; unp=unp->nextp)
11511 cm_ucell_t *ucellp;
11513 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11514 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11515 unp->name ? unp->name : _C("NULL"),
11516 unp->machine ? unp->machine : _C("NULL"));
11517 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11519 sprintf(output, " begin dumping cm_ucell_t\r\n");
11520 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11522 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11523 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",
11524 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11525 ucellp->expirationTime, ucellp->gen,
11527 ucellp->cellp->name);
11528 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11531 sprintf(output, " done dumping cm_ucell_t\r\n");
11532 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11535 sprintf(output, "done dumping smb_username_t\r\n");
11536 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11542 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11543 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11545 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11546 smb_waitingLock_t *lockp;
11548 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11549 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11550 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11552 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
11553 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11554 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11555 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11556 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11557 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11559 sprintf(output, " done dumping smb_waitingLock_t\r\n");
11560 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11563 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11564 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11566 sprintf(output, "begin dumping smb_vc_t\r\n");
11567 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11569 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11575 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11576 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11577 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11579 sprintf(output, " begin dumping smb_user_t\r\n");
11580 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11581 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11582 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11583 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11584 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11586 sprintf(output, " done dumping smb_user_t\r\n");
11587 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11589 sprintf(output, " begin dumping smb_tid_t\r\n");
11590 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11591 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11592 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",
11593 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11594 tidp->pathname ? tidp->pathname : _C("NULL"));
11595 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11597 sprintf(output, " done dumping smb_tid_t\r\n");
11598 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11600 sprintf(output, " begin dumping smb_fid_t\r\n");
11601 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11603 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11605 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",
11606 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11607 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11608 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11609 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11612 sprintf(output, " done dumping smb_fid_t\r\n");
11613 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11616 sprintf(output, "done dumping smb_vc_t\r\n");
11617 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11619 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11620 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11622 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11628 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11629 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11630 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11632 sprintf(output, " begin dumping smb_user_t\r\n");
11633 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11634 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11635 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11636 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11637 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11639 sprintf(output, " done dumping smb_user_t\r\n");
11640 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11642 sprintf(output, " begin dumping smb_tid_t\r\n");
11643 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11644 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11645 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",
11646 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11647 tidp->pathname ? tidp->pathname : _C("NULL"));
11648 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11650 sprintf(output, " done dumping smb_tid_t\r\n");
11651 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11653 sprintf(output, " begin dumping smb_fid_t\r\n");
11654 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11656 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11658 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",
11659 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11660 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11661 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11662 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11665 sprintf(output, " done dumping smb_fid_t\r\n");
11666 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11669 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11670 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11674 lock_ReleaseRead(&smb_rctLock);
11678 long smb_IsNetworkStarted(void)
11685 lock_ObtainWrite(&smb_globalLock);
11686 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11687 lock_ReleaseWrite(&smb_globalLock);