2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 #pragma warning(disable: 4005)
32 #include <rx/rx_prototypes.h>
33 #include <WINNT\afsreg.h>
37 #include "lanahelper.h"
39 #define STRSAFE_NO_DEPRECATE
42 /* These characters are illegal in Windows filenames */
43 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
45 static int smbShutdownFlag = 0;
46 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
48 int smb_LogoffTokenTransfer;
49 time_t smb_LogoffTransferTimeout;
51 int smb_StoreAnsiFilenames = 0;
53 DWORD last_msg_time = 0;
57 unsigned int sessionGen = 0;
59 extern void afsi_log(char *pattern, ...);
60 extern HANDLE afsi_file;
61 extern int powerStateSuspended;
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t smb_ListenerLock;
70 osi_mutex_t smb_StartedLock;
72 unsigned char smb_LANadapter = LANA_INVALID;
73 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
74 int smb_LanAdapterChangeDetected = 0;
75 afs_uint32 smb_AsyncStore = 1;
76 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
78 BOOL isGateway = FALSE;
81 long smb_maxObsConcurrentCalls=0;
82 long smb_concurrentCalls=0;
84 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
86 smb_packet_t *smb_packetFreeListp;
87 smb_ncb_t *smb_ncbFreeListp;
89 afs_uint32 smb_NumServerThreads;
91 afs_uint32 numNCBs, numSessions, numVCs;
93 int smb_maxVCPerServer;
94 int smb_maxMpxRequests;
96 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
98 ULONG smb_lsaSecPackage;
99 LSA_STRING smb_lsaLogonOrigin;
101 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
102 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
103 EVENT_HANDLE **NCBreturns;
104 EVENT_HANDLE **NCBShutdown;
105 EVENT_HANDLE *smb_ServerShutdown;
106 EVENT_HANDLE ListenerShutdown[256];
107 DWORD NCBsessions[NCB_MAX];
109 struct smb_packet *bufs[NCB_MAX];
111 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
112 EVENT_HANDLE SessionEvents[SESSION_MAX];
113 unsigned short LSNs[SESSION_MAX];
114 int lanas[SESSION_MAX];
115 BOOL dead_sessions[SESSION_MAX];
118 osi_mutex_t smb_RawBufLock;
121 #define SMB_MASKFLAG_TILDE 1
122 #define SMB_MASKFLAG_CASEFOLD 2
124 #define RAWTIMEOUT INFINITE
127 typedef struct raw_write_cont {
136 /* dir search stuff */
137 long smb_dirSearchCounter = 1;
138 smb_dirSearch_t *smb_firstDirSearchp;
139 smb_dirSearch_t *smb_lastDirSearchp;
141 /* Initial mode bits for files and directories. Set to 0 to use
143 int smb_unixModeDefaultFile = 0666;
144 int smb_unixModeDefaultDir = 0777;
146 /* hide dot files? */
147 int smb_hideDotFiles;
149 /* Negotiate Unicode support? */
152 /* global state about V3 protocols */
153 int smb_useV3; /* try to negotiate V3 */
155 static int showErrors = 0;
156 /* MessageBox or something like it */
157 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
161 * Time in Unix format of midnight, 1/1/1970 local time.
162 * When added to dosUTime, gives Unix (AFS) time.
164 time_t smb_localZero = 0;
166 char *smb_localNamep = NULL;
168 smb_vc_t *smb_allVCsp;
169 smb_vc_t *smb_deadVCsp;
171 smb_username_t *usernamesp = NULL;
173 smb_waitingLockRequest_t *smb_allWaitingLocks;
176 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
177 NCB *ncbp, raw_write_cont_t *rwcp);
178 int smb_NetbiosInit(int);
181 void smb_LogPacket(smb_packet_t *packet);
182 #endif /* LOG_PACKET */
184 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
185 int smb_ServerDomainNameLength = 0;
186 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
187 int smb_ServerOSLength = lengthof(smb_ServerOS);
188 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
189 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
191 /* Faux server GUID. This is never checked. */
192 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
194 void smb_InitReq(cm_req_t *reqp)
197 reqp->flags |= CM_REQ_SOURCE_SMB;
200 const char * ncb_error_string(int code)
204 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
205 case 0x03: s = "NRC_ILLCMD illegal command"; break;
206 case 0x05: s = "NRC_CMDTMO command timed out"; break;
207 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
208 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
209 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
210 case 0x09: s = "NRC_NORES no resource available"; break;
211 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
212 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
213 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
214 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
215 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
216 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
217 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
218 case 0x13: s = "NRC_ILLNN illegal name number"; break;
219 case 0x14: s = "NRC_NOCALL no callname"; break;
220 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
221 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
222 case 0x17: s = "NRC_NAMERR name deleted"; break;
223 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
224 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
225 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
226 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
227 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
228 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
229 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
230 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
231 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
232 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
233 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
234 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
235 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
236 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
237 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
238 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
239 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
240 case 0x40: s = "NRC_SYSTEM system error"; break;
241 default: s = "unknown error";
247 char * myCrt_Dispatch(int i)
252 return "(00)ReceiveCoreMakeDir";
254 return "(01)ReceiveCoreRemoveDir";
256 return "(02)ReceiveCoreOpen";
258 return "(03)ReceiveCoreCreate";
260 return "(04)ReceiveCoreClose";
262 return "(05)ReceiveCoreFlush";
264 return "(06)ReceiveCoreUnlink";
266 return "(07)ReceiveCoreRename";
268 return "(08)ReceiveCoreGetFileAttributes";
270 return "(09)ReceiveCoreSetFileAttributes";
272 return "(0a)ReceiveCoreRead";
274 return "(0b)ReceiveCoreWrite";
276 return "(0c)ReceiveCoreLockRecord";
278 return "(0d)ReceiveCoreUnlockRecord";
280 return "(0e)SendCoreBadOp";
282 return "(0f)ReceiveCoreCreate";
284 return "(10)ReceiveCoreCheckPath";
286 return "(11)SendCoreBadOp";
288 return "(12)ReceiveCoreSeek";
290 return "(1a)ReceiveCoreReadRaw";
292 return "(1d)ReceiveCoreWriteRawDummy";
294 return "(22)ReceiveV3SetAttributes";
296 return "(23)ReceiveV3GetAttributes";
298 return "(24)ReceiveV3LockingX";
300 return "(25)ReceiveV3Trans";
302 return "(26)ReceiveV3Trans[aux]";
304 return "(29)SendCoreBadOp";
306 return "(2b)ReceiveCoreEcho";
308 return "(2d)ReceiveV3OpenX";
310 return "(2e)ReceiveV3ReadX";
312 return "(2f)ReceiveV3WriteX";
314 return "(32)ReceiveV3Tran2A";
316 return "(33)ReceiveV3Tran2A[aux]";
318 return "(34)ReceiveV3FindClose";
320 return "(35)ReceiveV3FindNotifyClose";
322 return "(70)ReceiveCoreTreeConnect";
324 return "(71)ReceiveCoreTreeDisconnect";
326 return "(72)ReceiveNegotiate";
328 return "(73)ReceiveV3SessionSetupX";
330 return "(74)ReceiveV3UserLogoffX";
332 return "(75)ReceiveV3TreeConnectX";
334 return "(80)ReceiveCoreGetDiskAttributes";
336 return "(81)ReceiveCoreSearchDir";
340 return "(83)FindUnique";
342 return "(84)FindClose";
344 return "(A0)ReceiveNTTransact";
346 return "(A2)ReceiveNTCreateX";
348 return "(A4)ReceiveNTCancel";
350 return "(A5)ReceiveNTRename";
352 return "(C0)OpenPrintFile";
354 return "(C1)WritePrintFile";
356 return "(C2)ClosePrintFile";
358 return "(C3)GetPrintQueue";
360 return "(D8)ReadBulk";
362 return "(D9)WriteBulk";
364 return "(DA)WriteBulkData";
366 return "unknown SMB op";
370 char * myCrt_2Dispatch(int i)
375 return "unknown SMB op-2";
377 return "S(00)CreateFile_ReceiveTran2Open";
379 return "S(01)FindFirst_ReceiveTran2SearchDir";
381 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
383 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
385 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
387 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
389 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
391 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
393 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
395 return "S(09)_ReceiveTran2FSCTL";
397 return "S(0a)_ReceiveTran2IOCTL";
399 return "S(0b)_ReceiveTran2FindNotifyFirst";
401 return "S(0c)_ReceiveTran2FindNotifyNext";
403 return "S(0d)_ReceiveTran2CreateDirectory";
405 return "S(0e)_ReceiveTran2SessionSetup";
407 return "S(0f)_QueryFileSystemInformationFid";
409 return "S(10)_ReceiveTran2GetDfsReferral";
411 return "S(11)_ReceiveTran2ReportDfsInconsistency";
415 char * myCrt_RapDispatch(int i)
420 return "unknown RAP OP";
422 return "RAP(0)NetShareEnum";
424 return "RAP(1)NetShareGetInfo";
426 return "RAP(13)NetServerGetInfo";
428 return "RAP(63)NetWkStaGetInfo";
432 char * myCrt_NmpipeDispatch(int i)
435 case SMB_TRANS_SET_NMPIPE_STATE:
436 return "SET NMPIPE STATE";
438 case SMB_TRANS_RAW_READ_NMPIPE:
439 return "RAW READ NMPIPE";
441 case SMB_TRANS_QUERY_NMPIPE_STATE:
442 return "QUERY NMPIPE STATE";
444 case SMB_TRANS_QUERY_NMPIPE_INFO:
445 return "QUERY NMPIPE INFO";
447 case SMB_TRANS_PEEK_NMPIPE:
448 return "PEEK NMPIPE";
450 case SMB_TRANS_TRANSACT_NMPIPE:
451 return "TRANSACT NMPIPE";
453 case SMB_TRANS_RAW_WRITE_NMPIPE:
454 return "WRITE NMPIPE";
456 case SMB_TRANS_READ_NMPIPE:
457 return "READ NMPIPE";
459 case SMB_TRANS_WRITE_NMPIPE:
460 return "WRITE NMPIPE";
462 case SMB_TRANS_WAIT_NMPIPE:
463 return "WAIT NMPIPE";
465 case SMB_TRANS_CALL_NMPIPE:
466 return "CALL NMPIPE";
471 /* scache must be locked */
472 unsigned int smb_Attributes(cm_scache_t *scp)
476 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
477 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
478 scp->fileType == CM_SCACHETYPE_INVALID)
480 attrs = SMB_ATTR_DIRECTORY;
481 #ifdef SPECIAL_FOLDERS
482 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
483 #endif /* SPECIAL_FOLDERS */
484 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
485 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
490 * We used to mark a file RO if it was in an RO volume, but that
491 * turns out to be impolitic in NT. See defect 10007.
494 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
495 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
497 if ((scp->unixModeBits & 0200) == 0)
498 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
504 void smb_SetInitialModeBitsForFile(int smb_attr, cm_attr_t * attr)
506 if (smb_unixModeDefaultFile != 0) {
507 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
508 attr->unixModeBits = smb_unixModeDefaultFile;
509 if (smb_attr & SMB_ATTR_READONLY)
510 attr->unixModeBits &= ~0222;
514 void smb_SetInitialModeBitsForDir(int smb_attr, cm_attr_t * attr)
516 if (smb_unixModeDefaultDir != 0) {
517 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
518 attr->unixModeBits = smb_unixModeDefaultDir;
522 /* Check if the named file/dir is a dotfile/dotdir */
523 /* String pointed to by lastComp can have leading slashes, but otherwise should have
524 no other patch components */
525 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
529 /* skip over slashes */
530 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
535 /* nulls, curdir and parent dir doesn't count */
541 if(*(s+1) == _C('.') && !*(s + 2))
548 static int ExtractBits(WORD bits, short start, short len)
555 num = bits << (16 - end);
556 num = num >> ((16 - end) + start);
561 void ShowUnixTime(char *FuncName, time_t unixTime)
566 cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
568 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
569 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
571 int day, month, year, sec, min, hour;
574 day = ExtractBits(wDate, 0, 5);
575 month = ExtractBits(wDate, 5, 4);
576 year = ExtractBits(wDate, 9, 7) + 1980;
578 sec = ExtractBits(wTime, 0, 5);
579 min = ExtractBits(wTime, 5, 6);
580 hour = ExtractBits(wTime, 11, 5);
582 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
583 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
587 /* Determine if we are observing daylight savings time */
588 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
590 TIME_ZONE_INFORMATION timeZoneInformation;
591 SYSTEMTIME utc, local, localDST;
593 /* Get the time zone info. NT uses this to calc if we are in DST. */
594 GetTimeZoneInformation(&timeZoneInformation);
596 /* Return the daylight bias */
597 *pDstBias = timeZoneInformation.DaylightBias;
599 /* Return the bias */
600 *pBias = timeZoneInformation.Bias;
602 /* Now determine if DST is being observed */
604 /* Get the UTC (GMT) time */
607 /* Convert UTC time to local time using the time zone info. If we are
608 observing DST, the calculated local time will include this.
610 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
612 /* Set the daylight bias to 0. The daylight bias is the amount of change
613 * in time that we use for daylight savings time. By setting this to 0
614 * we cause there to be no change in time during daylight savings time.
616 timeZoneInformation.DaylightBias = 0;
618 /* Convert the utc time to local time again, but this time without any
619 adjustment for daylight savings time.
621 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
623 /* If the two times are different, then it means that the localDST that
624 we calculated includes the daylight bias, and therefore we are
625 observing daylight savings time.
627 *pDST = localDST.wHour != local.wHour;
631 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
633 BOOL dst; /* Will be TRUE if observing DST */
634 LONG dstBias; /* Offset from local time if observing DST */
635 LONG bias; /* Offset from GMT for local time */
638 * This function will adjust the last write time to compensate
639 * for two bugs in the smb client:
641 * 1) During Daylight Savings Time, the LastWriteTime is ahead
642 * in time by the DaylightBias (ignoring the sign - the
643 * DaylightBias is always stored as a negative number). If
644 * the DaylightBias is -60, then the LastWriteTime will be
645 * ahead by 60 minutes.
647 * 2) If the local time zone is a positive offset from GMT, then
648 * the LastWriteTime will be the correct local time plus the
649 * Bias (ignoring the sign - a positive offset from GMT is
650 * always stored as a negative Bias). If the Bias is -120,
651 * then the LastWriteTime will be ahead by 120 minutes.
653 * These bugs can occur at the same time.
656 GetTimeZoneInfo(&dst, &dstBias, &bias);
658 /* First adjust for DST */
660 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
662 /* Now adjust for a positive offset from GMT (a negative bias). */
664 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
667 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
669 time_t diff_t = unixTime - smb_localZero;
670 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
671 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
673 *dosUTimep = (afs_uint32)diff_t;
676 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
678 *unixTimep = dosTime + smb_localZero;
681 void smb_MarkAllVCsDead(smb_vc_t * exclude)
684 smb_vc_t **vcp_to_cleanup = NULL;
685 int n_to_cleanup = 0;
688 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
690 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
691 lock_ObtainWrite(&smb_rctLock);
692 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
694 if (vcp->magic != SMB_VC_MAGIC)
695 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
701 lock_ObtainMutex(&vcp->mx);
702 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
703 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
704 lock_ReleaseMutex(&vcp->mx);
705 dead_sessions[vcp->session] = TRUE;
707 lock_ReleaseMutex(&vcp->mx);
712 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
714 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
718 vcp_to_cleanup[i++] = vcp;
719 smb_HoldVCNoLock(vcp);
722 osi_assert(i == n_to_cleanup);
724 lock_ReleaseWrite(&smb_rctLock);
725 lock_ReleaseWrite(&smb_globalLock);
727 for (i=0; i < n_to_cleanup; i++) {
728 smb_CleanupDeadVC(vcp_to_cleanup[i]);
729 smb_ReleaseVC(vcp_to_cleanup[i]);
730 vcp_to_cleanup[i] = 0;
733 free(vcp_to_cleanup);
736 #ifdef DEBUG_SMB_REFCOUNT
737 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
739 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
744 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
745 lock_ObtainWrite(&smb_rctLock);
746 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
747 if (vcp->magic != SMB_VC_MAGIC)
748 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
751 lock_ObtainMutex(&vcp->mx);
752 if (lsn == vcp->lsn && lana == vcp->lana &&
753 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
754 lock_ReleaseMutex(&vcp->mx);
755 smb_HoldVCNoLock(vcp);
758 lock_ReleaseMutex(&vcp->mx);
760 if (!vcp && (flags & SMB_FLAG_CREATE)) {
761 vcp = malloc(sizeof(*vcp));
762 memset(vcp, 0, sizeof(*vcp));
763 vcp->vcID = ++numVCs;
764 vcp->magic = SMB_VC_MAGIC;
765 vcp->refCount = 2; /* smb_allVCsp and caller */
768 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
769 vcp->nextp = smb_allVCsp;
771 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
776 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
777 /* We must obtain a challenge for extended auth
778 * in case the client negotiates smb v3
780 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
781 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
782 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
783 ULONG lsaRespSize = 0;
785 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
787 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
794 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
795 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
796 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
797 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
798 nts, ntsEx, lsaRespSize);
800 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
802 if (ntsEx == STATUS_SUCCESS) {
803 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
806 * This will cause the subsequent authentication to fail but
807 * that is better than us dereferencing a NULL pointer and
810 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
813 LsaFreeReturnBuffer(lsaResp);
816 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
818 if (numVCs >= CM_SESSION_RESERVED) {
820 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
823 #ifdef DEBUG_SMB_REFCOUNT
825 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
826 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
829 lock_ReleaseWrite(&smb_rctLock);
830 lock_ReleaseWrite(&smb_globalLock);
834 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
839 for(i=0; i<11; i++) {
841 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
847 static int smb_IsStarMask(clientchar_t *maskp)
853 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
859 #ifdef DEBUG_SMB_REFCOUNT
860 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
861 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
863 void smb_ReleaseVCInternal(smb_vc_t *vcp)
869 lock_AssertWrite(&smb_rctLock);
872 if (vcp->refCount == 0) {
873 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
874 #ifdef DEBUG_SMB_REFCOUNT
875 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
876 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
878 /* remove VCP from smb_deadVCsp */
879 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
885 lock_FinalizeMutex(&vcp->mx);
886 memset(vcp,0,sizeof(smb_vc_t));
889 #ifdef DEBUG_SMB_REFCOUNT
890 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
892 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
896 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
897 avcp?"":"not ",vcp, vcp->refCount);
899 /* This is a wrong. However, I suspect that there is an undercount
900 * and I don't want to release 1.4.1 in a state that will allow
901 * smb_vc_t objects to be deallocated while still in the
902 * smb_allVCsp list. The list is supposed to keep a reference
903 * to the smb_vc_t. Put it back.
907 #ifdef DEBUG_SMB_REFCOUNT
908 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
909 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
913 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
914 /* The reference count is non-zero but the VC is dead.
915 * This implies that some FIDs, TIDs, etc on the VC have yet to
916 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
917 * add a reference that will be dropped by
918 * smb_CleanupDeadVC() and try to cleanup the VC again.
919 * Eventually the refCount will drop to zero when all of the
920 * active threads working with the VC end their task.
922 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
923 vcp->refCount++; /* put the refCount back */
924 lock_ReleaseWrite(&smb_rctLock);
925 smb_CleanupDeadVC(vcp);
926 #ifdef DEBUG_SMB_REFCOUNT
927 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
928 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
930 lock_ObtainWrite(&smb_rctLock);
933 #ifdef DEBUG_SMB_REFCOUNT
934 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
935 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
940 #ifdef DEBUG_SMB_REFCOUNT
941 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
943 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
946 lock_AssertWrite(&smb_rctLock);
947 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
948 smb_ReleaseVCInternal(vcp);
951 #ifdef DEBUG_SMB_REFCOUNT
952 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
954 void smb_ReleaseVC(smb_vc_t *vcp)
957 lock_ObtainWrite(&smb_rctLock);
958 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
959 smb_ReleaseVCInternal(vcp);
960 lock_ReleaseWrite(&smb_rctLock);
963 #ifdef DEBUG_SMB_REFCOUNT
964 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
966 void smb_HoldVCNoLock(smb_vc_t *vcp)
969 lock_AssertWrite(&smb_rctLock);
971 #ifdef DEBUG_SMB_REFCOUNT
972 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
973 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
975 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
979 #ifdef DEBUG_SMB_REFCOUNT
980 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
982 void smb_HoldVC(smb_vc_t *vcp)
985 lock_ObtainWrite(&smb_rctLock);
987 #ifdef DEBUG_SMB_REFCOUNT
988 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
989 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
991 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
993 lock_ReleaseWrite(&smb_rctLock);
996 void smb_CleanupDeadVC(smb_vc_t *vcp)
1001 smb_tid_t *tidpIter;
1002 smb_tid_t *tidpNext;
1004 smb_user_t *uidpIter;
1005 smb_user_t *uidpNext;
1007 afs_uint32 refCount = 0;
1009 lock_ObtainMutex(&vcp->mx);
1010 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1011 lock_ReleaseMutex(&vcp->mx);
1012 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1015 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1016 lock_ReleaseMutex(&vcp->mx);
1017 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1019 lock_ObtainWrite(&smb_rctLock);
1020 /* remove VCP from smb_allVCsp */
1021 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1022 if ((*vcpp)->magic != SMB_VC_MAGIC)
1023 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1024 __FILE__, __LINE__);
1027 vcp->nextp = smb_deadVCsp;
1029 /* Hold onto the reference until we are done with this function */
1034 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1035 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1037 if (fidpIter->deleteOk)
1040 fid = fidpIter->fid;
1041 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1043 smb_HoldFIDNoLock(fidpIter);
1044 lock_ReleaseWrite(&smb_rctLock);
1046 smb_CloseFID(vcp, fidpIter, NULL, 0);
1047 smb_ReleaseFID(fidpIter);
1049 lock_ObtainWrite(&smb_rctLock);
1050 fidpNext = vcp->fidsp;
1053 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1054 tidpNext = tidpIter->nextp;
1055 if (tidpIter->deleteOk)
1057 tidpIter->deleteOk = 1;
1059 tid = tidpIter->tid;
1060 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1062 smb_HoldTIDNoLock(tidpIter);
1063 smb_ReleaseTID(tidpIter, TRUE);
1064 tidpNext = vcp->tidsp;
1067 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1068 uidpNext = uidpIter->nextp;
1069 if (uidpIter->deleteOk)
1071 uidpIter->deleteOk = 1;
1073 /* do not add an additional reference count for the smb_user_t
1074 * as the smb_vc_t already is holding a reference */
1075 lock_ReleaseWrite(&smb_rctLock);
1077 smb_ReleaseUID(uidpIter);
1079 lock_ObtainWrite(&smb_rctLock);
1080 uidpNext = vcp->usersp;
1083 /* The vcp is now on the deadVCsp list. We intentionally drop the
1084 * reference so that the refcount can reach 0 and we can delete it
1086 * If the refCount == 1 going into the ReleaseVCNoLock call
1087 * the object will be freed and it won't be safe to clear
1090 refCount = vcp->refCount;
1091 smb_ReleaseVCNoLock(vcp);
1093 lock_ObtainMutex(&vcp->mx);
1094 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1095 lock_ReleaseMutex(&vcp->mx);
1098 lock_ReleaseWrite(&smb_rctLock);
1099 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1102 #ifdef DEBUG_SMB_REFCOUNT
1103 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1105 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1110 lock_ObtainWrite(&smb_rctLock);
1112 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1113 if (tidp->refCount == 0 && tidp->deleteOk) {
1115 smb_ReleaseTID(tidp, TRUE);
1119 if (tid == tidp->tid) {
1124 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1125 tidp = malloc(sizeof(*tidp));
1126 memset(tidp, 0, sizeof(*tidp));
1127 tidp->nextp = vcp->tidsp;
1130 smb_HoldVCNoLock(vcp);
1132 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1135 #ifdef DEBUG_SMB_REFCOUNT
1137 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1138 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1141 lock_ReleaseWrite(&smb_rctLock);
1145 #ifdef DEBUG_SMB_REFCOUNT
1146 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1148 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1151 lock_AssertWrite(&smb_rctLock);
1153 #ifdef DEBUG_SMB_REFCOUNT
1154 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1155 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1159 #ifdef DEBUG_SMB_REFCOUNT
1160 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1162 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1167 cm_user_t *userp = NULL;
1168 smb_vc_t *vcp = NULL;
1171 lock_ObtainWrite(&smb_rctLock);
1173 lock_AssertWrite(&smb_rctLock);
1175 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1176 #ifdef DEBUG_SMB_REFCOUNT
1177 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1178 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1180 if (tidp->refCount == 0) {
1181 if (tidp->deleteOk) {
1182 ltpp = &tidp->vcp->tidsp;
1183 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1187 osi_assertx(tp != NULL, "null smb_tid_t");
1189 lock_FinalizeMutex(&tidp->mx);
1190 userp = tidp->userp; /* remember to drop ref later */
1198 smb_ReleaseVCNoLock(vcp);
1200 lock_ReleaseWrite(&smb_rctLock);
1202 cm_ReleaseUser(userp);
1205 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1207 smb_user_t *uidp = NULL;
1209 lock_ObtainWrite(&smb_rctLock);
1210 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1211 if (uid == uidp->userID) {
1213 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1215 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1219 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1220 uidp = malloc(sizeof(*uidp));
1221 memset(uidp, 0, sizeof(*uidp));
1222 uidp->nextp = vcp->usersp;
1223 uidp->refCount = 2; /* one for the vcp and one for the caller */
1225 smb_HoldVCNoLock(vcp);
1227 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1229 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1231 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1233 lock_ReleaseWrite(&smb_rctLock);
1237 afs_int32 smb_userIsLocalSystem(smb_user_t *uidp)
1240 DWORD dwSize1 = 0, dwSize2 = 0;
1241 wchar_t *pszRefDomain = NULL;
1242 SID_NAME_USE snu = SidTypeGroup;
1243 clientchar_t * secSidString = NULL;
1245 afs_int32 isSystem = 0;
1247 if (uidp->unp->flags & SMB_USERNAMEFLAG_SID) {
1248 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, uidp->unp->name);
1253 * The input name is not a SID for the user. See if we can
1254 * obtain the SID for the specified name. If we can, use
1255 * that instead of the name provided for the comparison.
1258 LookupAccountNameW( NULL /* System Name to begin Search */,
1263 gle = GetLastError();
1264 if (gle == ERROR_INSUFFICIENT_BUFFER) {
1265 pSid = malloc(dwSize1);
1267 * Although dwSize2 is supposed to include the terminating
1268 * NUL character, on Win7 it does not.
1270 pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
1273 if ( pSid && pszRefDomain ) {
1274 memset(pSid, 0, dwSize1);
1276 if (LookupAccountNameW( NULL /* System Name to begin Search */,
1279 pszRefDomain, &dwSize2,
1281 ConvertSidToStringSidW(pSid, &secSidString);
1285 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, secSidString);
1286 LocalFree(secSidString);
1297 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1300 smb_username_t *unp= NULL;
1302 lock_ObtainWrite(&smb_rctLock);
1303 for(unp = usernamesp; unp; unp = unp->nextp) {
1304 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1305 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1310 if (!unp && (flags & SMB_FLAG_CREATE)) {
1311 unp = malloc(sizeof(*unp));
1312 memset(unp, 0, sizeof(*unp));
1314 unp->nextp = usernamesp;
1315 unp->name = cm_ClientStrDup(usern);
1316 unp->machine = cm_ClientStrDup(machine);
1318 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1319 if (flags & SMB_FLAG_AFSLOGON)
1320 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1323 lock_ReleaseWrite(&smb_rctLock);
1327 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1329 smb_user_t *uidp= NULL;
1331 lock_ObtainWrite(&smb_rctLock);
1332 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1335 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1337 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1338 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1343 lock_ReleaseWrite(&smb_rctLock);
1347 void smb_ReleaseUsername(smb_username_t *unp)
1350 smb_username_t **lupp;
1351 cm_user_t *userp = NULL;
1352 time_t now = osi_Time();
1354 lock_ObtainWrite(&smb_rctLock);
1355 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1356 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1357 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1359 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1363 osi_assertx(up != NULL, "null smb_username_t");
1365 up->nextp = NULL; /* do not remove this */
1366 lock_FinalizeMutex(&unp->mx);
1372 lock_ReleaseWrite(&smb_rctLock);
1374 cm_ReleaseUser(userp);
1377 void smb_HoldUIDNoLock(smb_user_t *uidp)
1379 lock_AssertWrite(&smb_rctLock);
1383 void smb_ReleaseUID(smb_user_t *uidp)
1387 smb_username_t *unp = NULL;
1389 lock_ObtainWrite(&smb_rctLock);
1390 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1391 if (uidp->refCount == 0) {
1392 lupp = &uidp->vcp->usersp;
1393 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1397 osi_assertx(up != NULL, "null smb_user_t");
1399 lock_FinalizeMutex(&uidp->mx);
1401 smb_ReleaseVCNoLock(uidp->vcp);
1405 lock_ReleaseWrite(&smb_rctLock);
1409 cm_ReleaseUserVCRef(unp->userp);
1410 smb_ReleaseUsername(unp);
1414 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1416 cm_user_t *up = NULL;
1421 lock_ObtainMutex(&uidp->mx);
1423 up = uidp->unp->userp;
1426 lock_ReleaseMutex(&uidp->mx);
1432 /* retrieve a held reference to a user structure corresponding to an incoming
1434 * corresponding release function is cm_ReleaseUser.
1436 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1439 cm_user_t *up = NULL;
1442 smbp = (smb_t *) inp;
1443 uidp = smb_FindUID(vcp, smbp->uid, 0);
1447 up = smb_GetUserFromUID(uidp);
1449 smb_ReleaseUID(uidp);
1454 * Return a pointer to a pathname extracted from a TID structure. The
1455 * TID structure is not held; assume it won't go away.
1457 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1462 tidp = smb_FindTID(vcp, tid, 0);
1466 if (tidp->flags & SMB_TIDFLAG_IPC) {
1467 code = CM_ERROR_TIDIPC;
1468 /* tidp->pathname would be NULL, but that's fine */
1470 *treepath = tidp->pathname;
1471 smb_ReleaseTID(tidp, FALSE);
1476 /* check to see if we have a chained fid, that is, a fid that comes from an
1477 * OpenAndX message that ran earlier in this packet. In this case, the fid
1478 * field in a read, for example, request, isn't set, since the value is
1479 * supposed to be inherited from the openAndX call.
1481 int smb_ChainFID(int fid, smb_packet_t *inp)
1483 if (inp->fid == 0 || inp->inCount == 0)
1489 /* are we a priv'd user? What does this mean on NT? */
1490 int smb_SUser(cm_user_t *userp)
1495 /* find a file ID. If we pass in 0 we select an unused File ID.
1496 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1497 * smb_fid_t data structure if desired File ID cannot be found.
1499 #ifdef DEBUG_SMB_REFCOUNT
1500 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1502 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1509 if (!(flags & SMB_FLAG_CREATE))
1514 lock_ObtainWrite(&smb_rctLock);
1516 fid = vcp->fidCounter;
1519 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1520 if (fidp->refCount == 0 && fidp->deleteOk) {
1522 lock_ReleaseWrite(&smb_rctLock);
1523 smb_ReleaseFID(fidp);
1524 lock_ObtainWrite(&smb_rctLock);
1526 * We dropped the smb_rctLock so the fid value we are using
1527 * may now be used by another thread. Start over with the
1528 * current vcp->fidCounter.
1531 fid = vcp->fidCounter;
1534 if (fid == fidp->fid) {
1536 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1538 if (fid == 0xFFFF) {
1540 "New FID number wraps on vcp 0x%x", vcp);
1550 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1551 char eventName[MAX_PATH];
1555 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1557 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1559 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1560 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1561 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1562 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1563 thrd_CloseHandle(event);
1565 if (fid == 0xFFFF) {
1566 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1572 fidp = malloc(sizeof(*fidp));
1573 memset(fidp, 0, sizeof(*fidp));
1574 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1577 smb_HoldVCNoLock(vcp);
1578 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1580 fidp->curr_chunk = fidp->prev_chunk = -2;
1581 fidp->raw_write_event = event;
1583 vcp->fidCounter = fid+1;
1584 if (vcp->fidCounter == 0xFFFF) {
1585 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1587 vcp->fidCounter = 1;
1592 #ifdef DEBUG_SMB_REFCOUNT
1594 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1598 lock_ReleaseWrite(&smb_rctLock);
1603 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1604 #ifdef DEBUG_SMB_REFCOUNT
1605 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1607 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1610 smb_fid_t *fidp = NULL, *nextp = NULL;
1616 * If the fidp->scp changes out from under us then
1617 * we must not grab a refCount. It means the *fidp
1618 * was processed by smb_CloseFID() and the *fidp is
1619 * no longer valid for use.
1621 lock_ObtainWrite(&smb_rctLock);
1622 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1623 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1627 if (scp == fidp->scp) {
1628 lock_ReleaseWrite(&smb_rctLock);
1629 lock_ObtainMutex(&fidp->mx);
1630 lock_ObtainWrite(&smb_rctLock);
1631 if (scp == fidp->scp) {
1632 lock_ReleaseMutex(&fidp->mx);
1635 lock_ReleaseMutex(&fidp->mx);
1638 if (fidp->refCount > 1) {
1641 lock_ReleaseWrite(&smb_rctLock);
1642 smb_ReleaseFID(fidp);
1643 lock_ObtainWrite(&smb_rctLock);
1648 if (nextp->refCount > 1) {
1651 lock_ReleaseWrite(&smb_rctLock);
1652 smb_ReleaseFID(nextp);
1653 lock_ObtainWrite(&smb_rctLock);
1657 #ifdef DEBUG_SMB_REFCOUNT
1659 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1660 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1663 lock_ReleaseWrite(&smb_rctLock);
1667 #ifdef DEBUG_SMB_REFCOUNT
1668 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1670 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1673 lock_AssertWrite(&smb_rctLock);
1675 #ifdef DEBUG_SMB_REFCOUNT
1676 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1677 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1682 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1683 /* the smb_fid_t->mx and smb_rctLock must not be held */
1684 #ifdef DEBUG_SMB_REFCOUNT
1685 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1687 void smb_ReleaseFID(smb_fid_t *fidp)
1690 cm_scache_t *scp = NULL;
1691 cm_user_t *userp = NULL;
1692 smb_vc_t *vcp = NULL;
1693 smb_ioctl_t *ioctlp;
1695 lock_ObtainMutex(&fidp->mx);
1696 lock_ObtainWrite(&smb_rctLock);
1697 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1698 #ifdef DEBUG_SMB_REFCOUNT
1699 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1700 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1702 if (fidp->refCount == 0) {
1703 if (fidp->deleteOk) {
1706 scp = fidp->scp; /* release after lock is released */
1708 lock_ObtainWrite(&scp->rw);
1709 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1710 lock_ReleaseWrite(&scp->rw);
1711 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1714 userp = fidp->userp;
1718 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1719 thrd_CloseHandle(fidp->raw_write_event);
1721 /* and see if there is ioctl stuff to free */
1722 ioctlp = fidp->ioctlp;
1725 cm_FreeSpace(ioctlp->prefix);
1726 if (ioctlp->ioctl.inAllocp)
1727 free(ioctlp->ioctl.inAllocp);
1728 if (ioctlp->ioctl.outAllocp)
1729 free(ioctlp->ioctl.outAllocp);
1733 smb_CleanupRPCFid(fidp);
1735 lock_ReleaseMutex(&fidp->mx);
1736 lock_FinalizeMutex(&fidp->mx);
1741 smb_ReleaseVCNoLock(vcp);
1745 lock_ReleaseMutex(&fidp->mx);
1747 lock_ReleaseWrite(&smb_rctLock);
1749 /* now release the scache structure */
1751 cm_ReleaseSCache(scp);
1754 cm_ReleaseUser(userp);
1758 * Case-insensitive search for one string in another;
1759 * used to find variable names in submount pathnames.
1761 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1763 clientchar_t *cursor;
1765 for (cursor = str1; *cursor; cursor++)
1766 if (cm_ClientStrCmpI(cursor, str2) == 0)
1773 * Substitute a variable value for its name in a submount pathname. Variable
1774 * name has been identified by smb_stristr() and is in substr. Variable name
1775 * length (plus one) is in substr_size. Variable value is in newstr.
1777 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1778 unsigned int substr_size, clientchar_t *newstr)
1780 clientchar_t temp[1024];
1782 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1783 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1784 cm_ClientStrCat(str1, cchstr1, temp);
1787 clientchar_t VNUserName[] = _C("%USERNAME%");
1788 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1789 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1790 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1792 typedef struct smb_findShare_rock {
1793 clientchar_t * shareName;
1794 clientchar_t * match;
1796 } smb_findShare_rock_t;
1798 #define SMB_FINDSHARE_EXACT_MATCH 1
1799 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1801 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1805 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1806 normchar_t normName[MAX_PATH];
1808 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1809 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1810 osi_LogSaveString(smb_logp, dep->name));
1814 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1815 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1816 matchType = SMB_FINDSHARE_EXACT_MATCH;
1818 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1821 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1822 vrock->matchType = matchType;
1824 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1825 return CM_ERROR_STOPNOW;
1831 /* find a shareName in the table of submounts */
1832 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1833 clientchar_t *shareName,
1834 clientchar_t **pathNamep)
1838 clientchar_t pathName[1024];
1841 clientchar_t *p, *q;
1842 fschar_t *cellname = NULL;
1845 DWORD allSubmount = 1;
1847 /* if allSubmounts == 0, only return the //mountRoot/all share
1848 * if in fact it has been been created in the subMounts table.
1849 * This is to allow sites that want to restrict access to the
1852 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1853 0, KEY_QUERY_VALUE, &parmKey);
1854 if (code == ERROR_SUCCESS) {
1855 cblen = sizeof(allSubmount);
1856 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1857 (BYTE *) &allSubmount, &cblen);
1858 if (code != ERROR_SUCCESS) {
1861 RegCloseKey (parmKey);
1864 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1869 /* In case, the all share is disabled we need to still be able
1870 * to handle ioctl requests
1872 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1873 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1877 if (MSRPC_IsWellKnownService(shareName) ||
1878 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1879 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1885 /* Check for volume references
1887 * They look like <cell>{%,#}<volume>
1889 if (cm_ClientStrChr(shareName, '%') != NULL ||
1890 cm_ClientStrChr(shareName, '#') != NULL) {
1891 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1892 /* make room for '/@vol:' + mountchar + NULL terminator*/
1894 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1895 osi_LogSaveClientString(smb_logp, shareName));
1897 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1898 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1899 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1901 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1903 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1904 cm_ClientStrLwr(*pathNamep);
1905 osi_Log1(smb_logp, " returning pathname [%S]",
1906 osi_LogSaveClientString(smb_logp, *pathNamep));
1914 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1915 0, KEY_QUERY_VALUE, &parmKey);
1916 if (code == ERROR_SUCCESS) {
1917 cblen = sizeof(pathName);
1918 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1919 (BYTE *) pathName, &cblen);
1920 if (code != ERROR_SUCCESS)
1922 RegCloseKey (parmKey);
1926 cchlen = cblen / sizeof(clientchar_t);
1927 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1928 /* We can accept either unix or PC style AFS pathnames. Convert
1929 * Unix-style to PC style here for internal use.
1932 cchlen = lengthof(pathName);
1934 /* within this code block, we maintain, cchlen = writable
1935 buffer length of p */
1937 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1938 p += cm_mountRootCLen; /* skip mount path */
1939 cchlen -= (DWORD)(p - pathName);
1944 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1950 clientchar_t temp[1024];
1952 if (var = smb_stristr(p, VNUserName)) {
1953 if (uidp && uidp->unp)
1954 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1956 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1958 else if (var = smb_stristr(p, VNLCUserName))
1960 if (uidp && uidp->unp)
1961 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1963 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1964 cm_ClientStrLwr(temp);
1965 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1967 else if (var = smb_stristr(p, VNComputerName))
1969 sizeTemp = lengthof(temp);
1970 GetComputerNameW(temp, &sizeTemp);
1971 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1973 else if (var = smb_stristr(p, VNLCComputerName))
1975 sizeTemp = lengthof(temp);
1976 GetComputerName((LPTSTR)temp, &sizeTemp);
1977 cm_ClientStrLwr(temp);
1978 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1983 *pathNamep = cm_ClientStrDup(p);
1988 /* First lookup shareName in root.afs */
1990 smb_findShare_rock_t vrock;
1992 fschar_t ftemp[1024];
1993 clientchar_t * p = shareName;
1998 /* attempt to locate a partial match in root.afs. This is because
1999 when using the ANSI RAP calls, the share name is limited to 13 chars
2000 and hence is truncated. Of course we prefer exact matches. */
2002 thyper.HighPart = 0;
2005 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2006 if (vrock.shareName == NULL)
2009 vrock.matchType = 0;
2011 userp = (uidp? (uidp->unp ? uidp->unp->userp : cm_rootUserp) : cm_rootUserp);
2012 rscp = cm_RootSCachep(userp, &req);
2013 cm_HoldSCache(rscp);
2014 code = cm_ApplyDir(rscp, smb_FindShareProc, &vrock, &thyper,
2016 cm_ReleaseSCache(rscp);
2018 free(vrock.shareName);
2019 vrock.shareName = NULL;
2021 if (vrock.matchType) {
2022 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2023 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2028 /* if we get here, there was no match for the share in root.afs */
2029 /* so try to create \\<netbiosName>\<cellname> */
2034 /* Get the full name for this cell */
2035 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2036 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2037 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2038 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2039 if (code && cm_dnsEnabled) {
2041 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2046 /* construct the path */
2048 clientchar_t temp[1024];
2050 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2051 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2052 rw ? _C("/.%S/") : _C("/%S/"), temp);
2053 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2063 /* Client-side offline caching policy types */
2064 #define CSC_POLICY_MANUAL 0
2065 #define CSC_POLICY_DOCUMENTS 1
2066 #define CSC_POLICY_PROGRAMS 2
2067 #define CSC_POLICY_DISABLE 3
2069 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2072 clientchar_t policy[1024];
2075 int retval = CSC_POLICY_MANUAL;
2077 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2078 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2081 REG_OPTION_NON_VOLATILE,
2085 NULL ) != ERROR_SUCCESS)
2086 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2088 len = sizeof(policy);
2089 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2091 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2093 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2095 retval = CSC_POLICY_MANUAL;
2097 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2099 retval = CSC_POLICY_DOCUMENTS;
2101 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2103 retval = CSC_POLICY_PROGRAMS;
2105 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2107 retval = CSC_POLICY_DISABLE;
2110 RegCloseKey(hkCSCPolicy);
2114 /* find a dir search structure by cookie value, and return it held.
2115 * Must be called with smb_globalLock held.
2117 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2119 smb_dirSearch_t *dsp;
2121 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2122 if (dsp->cookie == cookie) {
2123 if (dsp != smb_firstDirSearchp) {
2124 /* move to head of LRU queue, too, if we're not already there */
2125 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2126 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2127 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2128 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2129 if (!smb_lastDirSearchp)
2130 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2138 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2139 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2140 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2146 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2148 lock_ObtainMutex(&dsp->mx);
2149 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2150 dsp->cookie, dsp, dsp->scp);
2151 dsp->flags |= SMB_DIRSEARCH_DELETE;
2152 if (dsp->scp != NULL) {
2153 lock_ObtainWrite(&dsp->scp->rw);
2154 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2155 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2156 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2157 dsp->scp->bulkStatProgress = hzero;
2159 lock_ReleaseWrite(&dsp->scp->rw);
2161 lock_ReleaseMutex(&dsp->mx);
2164 /* Must be called with the smb_globalLock held */
2165 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2167 cm_scache_t *scp = NULL;
2169 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2170 if (dsp->refCount == 0) {
2171 lock_ObtainMutex(&dsp->mx);
2172 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2173 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2174 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2175 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2176 lock_ReleaseMutex(&dsp->mx);
2177 lock_FinalizeMutex(&dsp->mx);
2179 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2180 dsp->cookie, dsp, scp);
2183 lock_ReleaseMutex(&dsp->mx);
2186 /* do this now to avoid spurious locking hierarchy creation */
2188 cm_ReleaseSCache(scp);
2191 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2193 lock_ObtainWrite(&smb_globalLock);
2194 smb_ReleaseDirSearchNoLock(dsp);
2195 lock_ReleaseWrite(&smb_globalLock);
2198 /* find a dir search structure by cookie value, and return it held */
2199 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2201 smb_dirSearch_t *dsp;
2203 lock_ObtainWrite(&smb_globalLock);
2204 dsp = smb_FindDirSearchNoLock(cookie);
2205 lock_ReleaseWrite(&smb_globalLock);
2209 /* GC some dir search entries, in the address space expected by the specific protocol.
2210 * Must be called with smb_globalLock held; release the lock temporarily.
2212 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2213 void smb_GCDirSearches(int isV3)
2215 smb_dirSearch_t *prevp;
2216 smb_dirSearch_t *dsp;
2217 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2221 victimCount = 0; /* how many have we got so far */
2222 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2223 /* we'll move tp from queue, so
2226 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2227 /* if no one is using this guy, and we're either in the new protocol,
2228 * or we're in the old one and this is a small enough ID to be useful
2229 * to the old protocol, GC this guy.
2231 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2232 /* hold and delete */
2233 lock_ObtainMutex(&dsp->mx);
2234 dsp->flags |= SMB_DIRSEARCH_DELETE;
2235 lock_ReleaseMutex(&dsp->mx);
2236 victimsp[victimCount++] = dsp;
2240 /* don't do more than this */
2241 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2245 /* now release them */
2246 for (i = 0; i < victimCount; i++) {
2247 smb_ReleaseDirSearchNoLock(victimsp[i]);
2251 /* function for allocating a dir search entry. We need these to remember enough context
2252 * since we don't get passed the path from call to call during a directory search.
2254 * Returns a held dir search structure, and bumps the reference count on the vnode,
2255 * since it saves a pointer to the vnode.
2257 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2259 smb_dirSearch_t *dsp;
2265 lock_ObtainWrite(&smb_globalLock);
2268 /* what's the biggest ID allowed in this version of the protocol */
2269 /* TODO: do we really want a non v3 dir search request to wrap
2270 smb_dirSearchCounter? */
2271 maxAllowed = isV3 ? 65535 : 255;
2272 if (smb_dirSearchCounter > maxAllowed)
2273 smb_dirSearchCounter = 1;
2275 start = smb_dirSearchCounter;
2278 /* twice so we have enough tries to find guys we GC after one pass;
2279 * 10 extra is just in case I mis-counted.
2281 if (++counter > 2*maxAllowed+10)
2282 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2284 if (smb_dirSearchCounter > maxAllowed) {
2285 smb_dirSearchCounter = 1;
2287 if (smb_dirSearchCounter == start) {
2289 smb_GCDirSearches(isV3);
2292 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2294 /* don't need to watch for refcount zero and deleted, since
2295 * we haven't dropped the global lock.
2298 ++smb_dirSearchCounter;
2302 dsp = malloc(sizeof(*dsp));
2303 memset(dsp, 0, sizeof(*dsp));
2304 dsp->cookie = smb_dirSearchCounter;
2305 ++smb_dirSearchCounter;
2307 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2308 dsp->lastTime = osi_Time();
2309 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2310 if (!smb_lastDirSearchp)
2311 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2313 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2317 lock_ReleaseWrite(&smb_globalLock);
2321 static smb_packet_t *smb_GetPacket(void)
2325 lock_ObtainWrite(&smb_globalLock);
2326 tbp = smb_packetFreeListp;
2328 smb_packetFreeListp = tbp->nextp;
2329 lock_ReleaseWrite(&smb_globalLock);
2331 tbp = calloc(sizeof(*tbp),1);
2332 tbp->magic = SMB_PACKETMAGIC;
2335 tbp->resumeCode = 0;
2341 tbp->ncb_length = 0;
2344 tbp->stringsp = NULL;
2346 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2351 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2354 tbp = smb_GetPacket();
2355 memcpy(tbp, pkt, sizeof(smb_packet_t));
2356 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2357 tbp->stringsp = NULL;
2359 smb_HoldVC(tbp->vcp);
2363 static NCB *smb_GetNCB(void)
2368 lock_ObtainWrite(&smb_globalLock);
2369 tbp = smb_ncbFreeListp;
2371 smb_ncbFreeListp = tbp->nextp;
2372 lock_ReleaseWrite(&smb_globalLock);
2374 tbp = calloc(sizeof(*tbp),1);
2375 tbp->magic = SMB_NCBMAGIC;
2378 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2380 memset(&tbp->ncb, 0, sizeof(NCB));
2385 static void FreeSMBStrings(smb_packet_t * pkt)
2390 for (s = pkt->stringsp; s; s = ns) {
2394 pkt->stringsp = NULL;
2397 void smb_FreePacket(smb_packet_t *tbp)
2399 smb_vc_t * vcp = NULL;
2400 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2402 lock_ObtainWrite(&smb_globalLock);
2403 tbp->nextp = smb_packetFreeListp;
2404 smb_packetFreeListp = tbp;
2405 tbp->magic = SMB_PACKETMAGIC;
2409 tbp->resumeCode = 0;
2415 tbp->ncb_length = 0;
2417 FreeSMBStrings(tbp);
2418 lock_ReleaseWrite(&smb_globalLock);
2424 static void smb_FreeNCB(NCB *bufferp)
2428 tbp = (smb_ncb_t *) bufferp;
2429 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2431 lock_ObtainWrite(&smb_globalLock);
2432 tbp->nextp = smb_ncbFreeListp;
2433 smb_ncbFreeListp = tbp;
2434 lock_ReleaseWrite(&smb_globalLock);
2437 /* get a ptr to the data part of a packet, and its count */
2438 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2442 unsigned char *afterParmsp;
2444 parmBytes = *smbp->wctp << 1;
2445 afterParmsp = smbp->wctp + parmBytes + 1;
2447 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2448 if (nbytesp) *nbytesp = dataBytes;
2450 /* don't forget to skip the data byte count, since it follows
2451 * the parameters; that's where the "2" comes from below.
2453 return (unsigned char *) (afterParmsp + 2);
2456 /* must set all the returned parameters before playing around with the
2457 * data region, since the data region is located past the end of the
2458 * variable number of parameters.
2460 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2462 unsigned char *afterParmsp;
2464 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2466 *afterParmsp++ = dsize & 0xff;
2467 *afterParmsp = (dsize>>8) & 0xff;
2470 /* return the parm'th parameter in the smbp packet */
2471 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2474 unsigned char *parmDatap;
2476 parmCount = *smbp->wctp;
2478 if (parm >= parmCount) {
2481 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2482 parm, parmCount, smbp->ncb_length);
2483 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2484 parm, parmCount, smbp->ncb_length);
2485 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2486 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2487 osi_panic(s, __FILE__, __LINE__);
2489 parmDatap = smbp->wctp + (2*parm) + 1;
2491 return parmDatap[0] + (parmDatap[1] << 8);
2494 /* return the parm'th parameter in the smbp packet */
2495 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2498 unsigned char *parmDatap;
2500 parmCount = *smbp->wctp;
2502 if (parm >= parmCount) {
2505 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2506 parm, parmCount, smbp->ncb_length);
2507 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2508 parm, parmCount, smbp->ncb_length);
2509 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2510 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2511 osi_panic(s, __FILE__, __LINE__);
2513 parmDatap = smbp->wctp + (2*parm) + 1;
2515 return parmDatap[0];
2518 /* return the parm'th parameter in the smbp packet */
2519 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2522 unsigned char *parmDatap;
2524 parmCount = *smbp->wctp;
2526 if (parm + 1 >= parmCount) {
2529 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2530 parm, parmCount, smbp->ncb_length);
2531 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2532 parm, parmCount, smbp->ncb_length);
2533 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2534 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2535 osi_panic(s, __FILE__, __LINE__);
2537 parmDatap = smbp->wctp + (2*parm) + 1;
2539 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2542 /* return the parm'th parameter in the smbp packet */
2543 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2546 unsigned char *parmDatap;
2548 parmCount = *smbp->wctp;
2550 if (parm * 2 + offset >= parmCount * 2) {
2553 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2554 parm, offset, parmCount, smbp->ncb_length);
2555 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2556 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2557 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2558 parm, offset, parmCount, smbp->ncb_length);
2559 osi_panic(s, __FILE__, __LINE__);
2561 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2563 return parmDatap[0] + (parmDatap[1] << 8);
2566 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2568 unsigned char *parmDatap;
2570 /* make sure we have enough slots */
2571 if (*smbp->wctp <= slot)
2572 *smbp->wctp = slot+1;
2574 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2575 *parmDatap++ = parmValue & 0xff;
2576 *parmDatap = (parmValue>>8) & 0xff;
2579 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2581 unsigned char *parmDatap;
2583 /* make sure we have enough slots */
2584 if (*smbp->wctp <= slot)
2585 *smbp->wctp = slot+2;
2587 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2588 *parmDatap++ = parmValue & 0xff;
2589 *parmDatap++ = (parmValue>>8) & 0xff;
2590 *parmDatap++ = (parmValue>>16) & 0xff;
2591 *parmDatap = (parmValue>>24) & 0xff;
2594 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2596 unsigned char *parmDatap;
2599 /* make sure we have enough slots */
2600 if (*smbp->wctp <= slot)
2601 *smbp->wctp = slot+4;
2603 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2605 *parmDatap++ = *parmValuep++;
2608 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2610 unsigned char *parmDatap;
2612 /* make sure we have enough slots */
2613 if (*smbp->wctp <= slot) {
2614 if (smbp->oddByte) {
2616 *smbp->wctp = slot+1;
2621 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2622 *parmDatap++ = parmValue & 0xff;
2627 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2628 clientchar_t *inPathp)
2630 clientchar_t *lastSlashp;
2631 clientchar_t *streamp = NULL;
2632 clientchar_t *typep = NULL;
2634 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2635 if (lastComponentp) {
2636 *lastComponentp = lastSlashp;
2640 * If the name contains a stream name and a type
2641 * and the stream name is the nul-string and the
2642 * type is $DATA, then strip "::$DATA" from the
2643 * last component string that is returned.
2645 * Otherwise, return the full path name and allow
2646 * the file name to be rejected because it contains
2649 typep = cm_ClientStrRChr(lastSlashp, L':');
2650 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2652 streamp = cm_ClientStrRChr(lastSlashp, L':');
2653 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2657 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2658 osi_LogSaveClientString(smb_logp,streamp),
2659 osi_LogSaveClientString(smb_logp,typep));
2663 if (inPathp == lastSlashp)
2665 *outPathp++ = *inPathp++;
2674 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2675 char **chainpp, int flags)
2678 afs_uint32 type = *inp++;
2681 * The first byte specifies the type of the input string.
2682 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2686 /* Length Counted */
2687 case 0x1: /* Data Block */
2688 case 0x5: /* Variable Block */
2689 cb = *inp++ << 16 | *inp++;
2692 /* Null-terminated string */
2693 case 0x4: /* ASCII */
2694 case 0x3: /* Pathname */
2695 case 0x2: /* Dialect */
2696 cb = sizeof(pktp->data) - (inp - pktp->data);
2697 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2698 #ifdef DEBUG_UNICODE
2701 cb = sizeof(pktp->data);
2706 return NULL; /* invalid input */
2710 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2711 flags |= SMB_STRF_FORCEASCII;
2714 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2717 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2718 char ** chainpp, int flags)
2723 if (!WANTS_UNICODE(pktp))
2724 flags |= SMB_STRF_FORCEASCII;
2727 cb = sizeof(pktp->data) - (inp - pktp->data);
2728 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2729 #ifdef DEBUG_UNICODE
2732 cb = sizeof(pktp->data);
2734 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2735 flags | SMB_STRF_SRCNULTERM);
2738 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2739 size_t cb, char ** chainpp, int flags)
2742 if (!WANTS_UNICODE(pktp))
2743 flags |= SMB_STRF_FORCEASCII;
2746 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2749 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2750 size_t cch, char ** chainpp, int flags)
2755 if (!WANTS_UNICODE(pktp))
2756 flags |= SMB_STRF_FORCEASCII;
2758 cb = cch * sizeof(wchar_t);
2761 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2765 smb_ParseStringBuf(const unsigned char * bufbase,
2766 cm_space_t ** stringspp,
2767 unsigned char *inp, size_t *pcb_max,
2768 char **chainpp, int flags)
2771 if (!(flags & SMB_STRF_FORCEASCII)) {
2773 cm_space_t * spacep;
2776 if (bufbase && ((inp - bufbase) % 2) != 0) {
2777 inp++; /* unicode strings are always word aligned */
2781 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2783 cch_src = *pcb_max / sizeof(wchar_t);
2787 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2794 spacep = cm_GetSpace();
2795 spacep->nextp = *stringspp;
2796 *stringspp = spacep;
2800 *chainpp = inp + sizeof(wchar_t);
2803 *(spacep->wdata) = 0;
2804 return spacep->wdata;
2807 StringCchCopyNW(spacep->wdata,
2808 lengthof(spacep->wdata),
2809 (const clientchar_t *) inp, cch_src);
2812 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2814 return spacep->wdata;
2818 cm_space_t * spacep;
2821 /* Not using Unicode */
2823 *chainpp = inp + strlen(inp) + 1;
2826 spacep = cm_GetSpace();
2827 spacep->nextp = *stringspp;
2828 *stringspp = spacep;
2830 cchdest = lengthof(spacep->wdata);
2831 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2832 spacep->wdata, cchdest);
2834 return spacep->wdata;
2840 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2842 size_t * plen, int flags)
2848 /* we are only calculating the required size */
2855 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2857 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2858 if (!(flags & SMB_STRF_IGNORENUL))
2859 *plen += sizeof(wchar_t);
2861 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2871 cch_str = cm_ClientStrLen(str);
2872 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2875 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2883 /* if outp != NULL ... */
2885 /* Number of bytes left in the buffer.
2887 If outp lies inside the packet data buffer, we assume that the
2888 buffer is the packet data buffer. Otherwise we assume that the
2889 buffer is sizeof(packet->data).
2892 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2893 align = (int)((outp - pktp->data) % 2);
2894 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2896 align = (int)(((size_t) outp) % 2);
2897 buffersize = (int)sizeof(pktp->data);
2902 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2908 if (*str == _C('\0')) {
2910 if (buffersize < sizeof(wchar_t))
2913 *((wchar_t *) outp) = L'\0';
2914 if (plen && !(flags & SMB_STRF_IGNORENUL))
2915 *plen += sizeof(wchar_t);
2916 return outp + sizeof(wchar_t);
2919 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2921 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2922 osi_LogSaveClientString(smb_logp, str),
2928 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2930 return outp + sizeof(wchar_t) * nchars;
2938 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2941 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2943 return outp + cch_dest;
2947 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2953 tlen = inp[0] + (inp[1]<<8);
2954 inp += 2; /* skip length field */
2957 *chainpp = inp + tlen;
2966 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2970 if (*inp++ != 0x1) return NULL;
2971 tlen = inp[0] + (inp[1]<<8);
2972 inp += 2; /* skip length field */
2975 *chainpp = inp + tlen;
2978 if (lengthp) *lengthp = tlen;
2983 /* format a packet as a response */
2984 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2989 outp = (smb_t *) op;
2991 /* zero the basic structure through the smb_wct field, and zero the data
2992 * size field, assuming that wct stays zero; otherwise, you have to
2993 * explicitly set the data size field, too.
2995 inSmbp = (smb_t *) inp;
2996 memset(outp, 0, sizeof(smb_t)+2);
3002 outp->com = inSmbp->com;
3003 outp->tid = inSmbp->tid;
3004 outp->pid = inSmbp->pid;
3005 outp->uid = inSmbp->uid;
3006 outp->mid = inSmbp->mid;
3007 outp->res[0] = inSmbp->res[0];
3008 outp->res[1] = inSmbp->res[1];
3009 op->inCom = inSmbp->com;
3011 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3012 #ifdef SEND_CANONICAL_PATHNAMES
3013 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3015 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3017 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3018 outp->flg2 |= SMB_FLAGS2_UNICODE;
3021 /* copy fields in generic packet area */
3022 op->wctp = &outp->wct;
3025 /* send a (probably response) packet; vcp tells us to whom to send it.
3026 * we compute the length by looking at wct and bcc fields.
3028 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3038 ncbp = smb_GetNCB();
3042 memset(ncbp, 0, sizeof(NCB));
3044 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3045 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3046 extra += tp[0] + (tp[1]<<8);
3047 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3048 extra += 3; /* wct and length fields */
3050 ncbp->ncb_length = extra; /* bytes to send */
3051 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3052 ncbp->ncb_lana_num = vcp->lana;
3053 ncbp->ncb_command = NCBSEND; /* op means send data */
3054 ncbp->ncb_buffer = (char *) inp;/* packet */
3055 code = Netbios(ncbp);
3058 const char * s = ncb_error_string(code);
3059 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3060 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3062 lock_ObtainMutex(&vcp->mx);
3063 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3064 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3066 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3067 lock_ReleaseMutex(&vcp->mx);
3068 lock_ObtainWrite(&smb_globalLock);
3069 dead_sessions[vcp->session] = TRUE;
3070 lock_ReleaseWrite(&smb_globalLock);
3071 smb_CleanupDeadVC(vcp);
3073 lock_ReleaseMutex(&vcp->mx);
3081 void smb_MapNTError(long code, unsigned long *NTStatusp, afs_uint32 redir)
3083 unsigned long NTStatus;
3085 /* map CM_ERROR_* errors to NT 32-bit status codes */
3086 /* NT Status codes are listed in ntstatus.h not winerror.h */
3090 else if (code == CM_ERROR_NOSUCHCELL) {
3091 NTStatus = 0xC0000034L; /* Name not found */
3093 else if (code == CM_ERROR_NOSUCHVOLUME) {
3094 NTStatus = 0xC0000034L; /* Name not found */
3096 else if (code == CM_ERROR_TIMEDOUT) {
3098 NTStatus = 0xC0020052L; /* RPC_NT_COMM_FAILURE */
3101 NTStatus = 0xC00000CFL; /* Sharing Paused */
3103 /* Do not send Timeout to the SMB redirector.
3104 * It causes the redirector to drop the connection */
3105 NTStatus = 0x00000102L; /* Timeout */
3106 /* do not send Retry to the SMB redirector.
3107 * It believes the error comes from the transport
3108 * layer not from the SMB server. */
3109 NTStatus = 0xC000022DL; /* Retry */
3111 NTStatus = 0xC00000B5L; /* I/O Timeout */
3115 else if (code == CM_ERROR_RETRY) {
3117 NTStatus = 0xC000022DL; /* Retry */
3120 NTStatus = 0xC000022DL; /* Retry */
3122 NTStatus = 0xC00000B5L; /* I/O Timeout */
3126 else if (code == CM_ERROR_NOACCESS) {
3127 NTStatus = 0xC0000022L; /* Access denied */
3129 else if (code == CM_ERROR_READONLY) {
3130 NTStatus = 0xC00000A2L; /* Write protected */
3132 else if (code == CM_ERROR_NOSUCHFILE ||
3133 code == CM_ERROR_BPLUS_NOMATCH) {
3134 NTStatus = 0xC0000034L; /* Name not found */
3136 else if (code == CM_ERROR_NOSUCHPATH) {
3137 NTStatus = 0xC000003AL; /* Object path not found */
3139 else if (code == CM_ERROR_TOOBIG) {
3140 NTStatus = 0xC000007BL; /* Invalid image format */
3142 else if (code == CM_ERROR_INVAL) {
3143 NTStatus = 0xC000000DL; /* Invalid parameter */
3145 else if (code == CM_ERROR_BADFD) {
3146 NTStatus = 0xC0000008L; /* Invalid handle */
3148 else if (code == CM_ERROR_BADFDOP) {
3149 NTStatus = 0xC0000022L; /* Access denied */
3151 else if (code == CM_ERROR_UNKNOWN) {
3152 NTStatus = 0xC0000022L; /* Access denied */
3154 else if (code == CM_ERROR_EXISTS) {
3155 NTStatus = 0xC0000035L; /* Object name collision */
3157 else if (code == CM_ERROR_NOTEMPTY) {
3158 NTStatus = 0xC0000101L; /* Directory not empty */
3160 else if (code == CM_ERROR_CROSSDEVLINK) {
3161 NTStatus = 0xC00000D4L; /* Not same device */
3163 else if (code == CM_ERROR_NOTDIR) {
3164 NTStatus = 0xC0000103L; /* Not a directory */
3166 else if (code == CM_ERROR_ISDIR) {
3167 NTStatus = 0xC00000BAL; /* File is a directory */
3169 else if (code == CM_ERROR_BADOP) {
3171 /* I have no idea where this comes from */
3172 NTStatus = 0xC09820FFL; /* SMB no support */
3174 NTStatus = 0xC00000BBL; /* Not supported */
3175 #endif /* COMMENT */
3177 else if (code == CM_ERROR_BADSHARENAME) {
3178 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3180 else if (code == CM_ERROR_NOIPC) {
3182 NTStatus = 0xC0000022L; /* Access Denied */
3184 NTStatus = 0xC000013DL; /* Remote Resources */
3187 else if (code == CM_ERROR_CLOCKSKEW ||
3188 code == RXKADNOAUTH) {
3189 NTStatus = 0xC0000133L; /* Time difference at DC */
3191 else if (code == CM_ERROR_BADTID) {
3192 NTStatus = 0xC0982005L; /* SMB bad TID */
3194 else if (code == CM_ERROR_USESTD) {
3195 NTStatus = 0xC09820FBL; /* SMB use standard */
3197 else if (code == CM_ERROR_QUOTA) {
3198 NTStatus = 0xC0000044L; /* Quota exceeded */
3200 else if (code == CM_ERROR_SPACE) {
3201 NTStatus = 0xC000007FL; /* Disk full */
3203 else if (code == CM_ERROR_ATSYS) {
3204 NTStatus = 0xC0000033L; /* Object name invalid */
3206 else if (code == CM_ERROR_BADNTFILENAME) {
3207 NTStatus = 0xC0000033L; /* Object name invalid */
3209 else if (code == CM_ERROR_WOULDBLOCK) {
3210 NTStatus = 0xC00000D8L; /* Can't wait */
3212 else if (code == CM_ERROR_SHARING_VIOLATION) {
3213 NTStatus = 0xC0000043L; /* Sharing violation */
3215 else if (code == CM_ERROR_LOCK_CONFLICT) {
3216 NTStatus = 0xC0000054L; /* Lock conflict */
3218 else if (code == CM_ERROR_PARTIALWRITE) {
3219 NTStatus = 0xC000007FL; /* Disk full */
3221 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3222 NTStatus = 0xC0000023L; /* Buffer too small */
3224 else if (code == CM_ERROR_BUFFER_OVERFLOW) {
3225 NTStatus = 0x80000005L; /* Buffer overflow */
3227 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3228 NTStatus = 0xC0000035L; /* Object name collision */
3230 else if (code == CM_ERROR_BADPASSWORD) {
3231 NTStatus = 0xC000006DL; /* unknown username or bad password */
3233 else if (code == CM_ERROR_BADLOGONTYPE) {
3234 NTStatus = 0xC000015BL; /* logon type not granted */
3236 else if (code == CM_ERROR_GSSCONTINUE) {
3237 NTStatus = 0xC0000016L; /* more processing required */
3239 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3241 NTStatus = 0xC0000280L; /* reparse point not resolved */
3243 NTStatus = 0xC0000022L; /* Access Denied */
3246 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3247 NTStatus = 0xC0000257L; /* Path Not Covered */
3249 else if (code == CM_ERROR_ALLBUSY) {
3251 NTStatus = 0xC000022DL; /* Retry */
3253 NTStatus = 0xC0020018L; /* RPC_NT_SERVER_TOO_BUSY */
3256 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3258 NTStatus = 0xC000003AL; /* Path not found */
3260 NTStatus = 0xC0020017L; /* RPC_NT_SERVER_UNAVAILABLE */
3263 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3264 NTStatus = 0xC0000322L; /* No Kerberos key */
3266 else if (code == CM_ERROR_BAD_LEVEL) {
3267 NTStatus = 0xC0000148L; /* Invalid Level */
3269 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3270 NTStatus = 0xC000007EL; /* Range Not Locked */
3272 else if (code == CM_ERROR_NOSUCHDEVICE) {
3273 NTStatus = 0xC000000EL; /* No Such Device */
3275 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3276 NTStatus = 0xC0000055L; /* Lock Not Granted */
3278 else if (code == ENOMEM) {
3279 NTStatus = 0xC0000017L; /* Out of Memory */
3281 else if (code == CM_ERROR_RPC_MOREDATA) {
3282 NTStatus = 0x80000005L; /* Buffer overflow */
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 ) {
3996 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3998 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
4000 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
4002 datap = smb_GetSMBData(outp, NULL);
4003 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
4006 datap += sizeof(smb_ServerGUID);
4007 memcpy(datap, secBlob, secBlobLength);
4011 smb_SetSMBParmByte(outp, 16, 0);/* Challenge length */
4012 smb_SetSMBDataLength(outp, smb_ServerDomainNameLength);
4013 datap = smb_GetSMBData(outp, NULL);
4014 /* the faux domain name */
4015 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4017 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4020 else if (v3ProtoIndex != -1) {
4021 smb_SetSMBParm(outp, 0, protoIndex);
4023 /* NOTE: Extended authentication cannot be negotiated with v3
4024 * therefore we fail over to NTLM
4026 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4027 smb_SetSMBParm(outp, 1,
4028 NEGOTIATE_SECURITY_USER_LEVEL |
4029 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
4031 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4033 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4034 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
4035 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
4036 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
4037 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
4038 smb_SetSMBParm(outp, 7, 1);
4040 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
4041 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
4042 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
4044 GetTimeZoneInformation(&tzi);
4045 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
4047 /* NOTE: Extended authentication cannot be negotiated with v3
4048 * therefore we fail over to NTLM
4050 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4051 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
4052 smb_SetSMBParm(outp, 12, 0); /* resvd */
4053 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
4054 datap = smb_GetSMBData(outp, NULL);
4055 /* paste in a new encryption key */
4056 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4057 /* and the faux domain name */
4058 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4059 datap + MSV1_0_CHALLENGE_LENGTH,
4060 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4062 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4063 smb_SetSMBParm(outp, 12, 0); /* resvd */
4064 smb_SetSMBDataLength(outp, 0);
4067 else if (coreProtoIndex != -1) { /* not really supported anymore */
4068 smb_SetSMBParm(outp, 0, protoIndex);
4069 smb_SetSMBDataLength(outp, 0);
4074 void smb_CheckVCs(void)
4076 smb_vc_t * vcp, *nextp;
4077 smb_packet_t * outp = smb_GetPacket();
4080 lock_ObtainWrite(&smb_rctLock);
4081 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4083 if (vcp->magic != SMB_VC_MAGIC)
4084 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4085 __FILE__, __LINE__);
4087 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4089 smb_HoldVCNoLock(vcp);
4092 * obtain a reference to 'nextp' now because we drop the
4093 * smb_rctLock later and the list contents could change
4094 * or 'vcp' could be destroyed when released.
4098 smb_HoldVCNoLock(nextp);
4100 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4101 smb_ReleaseVCNoLock(vcp);
4105 smb_FormatResponsePacket(vcp, NULL, outp);
4106 smbp = (smb_t *)outp;
4107 outp->inCom = smbp->com = 0x2b /* Echo */;
4115 smb_SetSMBParm(outp, 0, 0);
4116 smb_SetSMBDataLength(outp, 0);
4117 lock_ReleaseWrite(&smb_rctLock);
4119 smb_SendPacket(vcp, outp);
4121 lock_ObtainWrite(&smb_rctLock);
4122 smb_ReleaseVCNoLock(vcp);
4124 lock_ReleaseWrite(&smb_rctLock);
4125 smb_FreePacket(outp);
4128 void smb_Daemon(void *parmp)
4130 afs_uint32 count = 0;
4131 smb_username_t **unpp;
4134 while(smbShutdownFlag == 0) {
4138 if (smbShutdownFlag == 1)
4141 if ((count % 72) == 0) { /* every five minutes */
4143 time_t old_localZero = smb_localZero;
4145 /* Initialize smb_localZero */
4146 myTime.tm_isdst = -1; /* compute whether on DST or not */
4147 myTime.tm_year = 70;
4153 smb_localZero = mktime(&myTime);
4155 #ifdef AFS_FREELANCE
4156 if ( smb_localZero != old_localZero )
4157 cm_noteLocalMountPointChange(FALSE);
4163 /* GC smb_username_t objects that will no longer be used */
4165 lock_ObtainWrite(&smb_rctLock);
4166 for ( unpp=&usernamesp; *unpp; ) {
4168 smb_username_t *unp;
4170 lock_ObtainMutex(&(*unpp)->mx);
4171 if ( (*unpp)->refCount > 0 ||
4172 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4173 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4175 else if (!smb_LogoffTokenTransfer ||
4176 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4178 lock_ReleaseMutex(&(*unpp)->mx);
4186 lock_FinalizeMutex(&unp->mx);
4192 cm_ReleaseUser(userp);
4194 unpp = &(*unpp)->nextp;
4197 lock_ReleaseWrite(&smb_rctLock);
4199 /* XXX GC dir search entries */
4203 void smb_WaitingLocksDaemon()
4205 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4206 smb_waitingLock_t *wl, *wlNext;
4209 smb_packet_t *inp, *outp;
4213 while (smbShutdownFlag == 0) {
4214 lock_ObtainWrite(&smb_globalLock);
4215 nwlRequest = smb_allWaitingLocks;
4216 if (nwlRequest == NULL) {
4217 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4222 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4229 lock_ObtainWrite(&smb_globalLock);
4231 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4233 wlRequest = nwlRequest;
4234 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4235 lock_ReleaseWrite(&smb_globalLock);
4239 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4240 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4243 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4244 code = CM_ERROR_LOCK_NOT_GRANTED;
4248 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4250 /* wl->state is either _DONE or _WAITING. _ERROR
4251 would no longer be on the queue. */
4252 code = cm_RetryLock( wl->lockp,
4253 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4256 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4257 } else if (code != CM_ERROR_WOULDBLOCK) {
4258 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4263 if (code == CM_ERROR_WOULDBLOCK) {
4266 if (wlRequest->msTimeout != 0xffffffff
4267 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4279 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4282 scp = wlRequest->scp;
4283 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4287 lock_ObtainWrite(&scp->rw);
4289 for (wl = wlRequest->locks; wl; wl = wlNext) {
4290 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4292 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4293 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4294 wl->LLength, wl->key, 0, NULL, &req);
4296 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4301 lock_ReleaseWrite(&scp->rw);
4305 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4308 for (wl = wlRequest->locks; wl; wl = wlNext) {
4309 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4310 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4315 vcp = wlRequest->vcp;
4316 inp = wlRequest->inp;
4317 outp = wlRequest->outp;
4318 ncbp = smb_GetNCB();
4319 ncbp->ncb_length = inp->ncb_length;
4320 inp->spacep = cm_GetSpace();
4322 /* Remove waitingLock from list */
4323 lock_ObtainWrite(&smb_globalLock);
4324 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4326 lock_ReleaseWrite(&smb_globalLock);
4328 /* Resume packet processing */
4330 smb_SetSMBDataLength(outp, 0);
4331 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4332 outp->resumeCode = code;
4334 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4337 cm_FreeSpace(inp->spacep);
4338 smb_FreePacket(inp);
4339 smb_FreePacket(outp);
4341 cm_ReleaseSCache(wlRequest->scp);
4344 } while (nwlRequest && smbShutdownFlag == 0);
4349 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4351 osi_Log0(smb_logp, "SMB receive get disk attributes");
4353 smb_SetSMBParm(outp, 0, 32000);
4354 smb_SetSMBParm(outp, 1, 64);
4355 smb_SetSMBParm(outp, 2, 1024);
4356 smb_SetSMBParm(outp, 3, 30000);
4357 smb_SetSMBParm(outp, 4, 0);
4358 smb_SetSMBDataLength(outp, 0);
4362 /* SMB_COM_TREE_CONNECT */
4363 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4367 unsigned short newTid;
4368 clientchar_t shareName[AFSPATHMAX];
4369 clientchar_t *sharePath;
4372 clientchar_t *pathp;
4375 osi_Log0(smb_logp, "SMB receive tree connect");
4377 /* parse input parameters */
4380 tbp = smb_GetSMBData(inp, NULL);
4381 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4383 return CM_ERROR_BADSMB;
4385 tp = cm_ClientStrRChr(pathp, '\\');
4387 return CM_ERROR_BADSMB;
4388 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4390 lock_ObtainMutex(&vcp->mx);
4391 newTid = vcp->tidCounter++;
4392 lock_ReleaseMutex(&vcp->mx);
4394 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4395 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4397 return CM_ERROR_BADSMB;
4398 userp = smb_GetUserFromUID(uidp);
4399 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4400 smb_ReleaseUID(uidp);
4402 smb_ReleaseTID(tidp, FALSE);
4403 return CM_ERROR_BADSHARENAME;
4405 lock_ObtainMutex(&tidp->mx);
4406 tidp->userp = userp;
4407 tidp->pathname = sharePath;
4408 lock_ReleaseMutex(&tidp->mx);
4409 smb_ReleaseTID(tidp, FALSE);
4411 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4412 smb_SetSMBParm(rsp, 1, newTid);
4413 smb_SetSMBDataLength(rsp, 0);
4415 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4419 /* set maskp to the mask part of the incoming path.
4420 * Mask is 11 bytes long (8.3 with the dot elided).
4421 * Returns true if succeeds with a valid name, otherwise it does
4422 * its best, but returns false.
4424 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4432 /* starts off valid */
4435 /* mask starts out all blanks */
4436 memset(maskp, ' ', 11);
4439 /* find last backslash, or use whole thing if there is none */
4440 tp = cm_ClientStrRChr(pathp, '\\');
4444 tp++; /* skip slash */
4448 /* names starting with a dot are illegal */
4456 if (tc == '.' || tc == '"')
4464 /* if we get here, tp point after the dot */
4465 up = maskp+8; /* ext goes here */
4472 if (tc == '.' || tc == '"')
4475 /* copy extension if not too long */
4485 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4487 clientchar_t umask[11];
4495 /* XXX redo this, calling cm_MatchMask with a converted mask */
4497 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4501 /* otherwise, we have a valid 8.3 name; see if we have a match,
4502 * treating '?' as a wildcard in maskp (but not in the file name).
4504 tp1 = umask; /* real name, in mask format */
4505 tp2 = maskp; /* mask, in mask format */
4506 for(i=0; i<11; i++) {
4507 tc1 = *tp1++; /* clientchar_t from real name */
4508 tc2 = *tp2++; /* clientchar_t from mask */
4509 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4510 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4513 if (tc2 == '?' && tc1 != ' ')
4520 /* we got a match */
4524 clientchar_t *smb_FindMask(clientchar_t *pathp)
4528 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4531 return tp+1; /* skip the slash */
4533 return pathp; /* no slash, return the entire path */
4536 /* SMB_COM_SEARCH for a volume label
4538 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4539 dispatch function.) */
4540 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4542 clientchar_t *pathp;
4544 clientchar_t mask[12];
4545 unsigned char *statBlockp;
4546 unsigned char initStatBlock[21];
4549 osi_Log0(smb_logp, "SMB receive search volume");
4551 /* pull pathname and stat block out of request */
4552 tp = smb_GetSMBData(inp, NULL);
4553 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4554 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4556 return CM_ERROR_BADSMB;
4557 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4558 osi_assertx(statBlockp != NULL, "null statBlock");
4560 statBlockp = initStatBlock;
4564 /* for returning to caller */
4565 smb_Get8Dot3MaskFromPath(mask, pathp);
4567 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4568 tp = smb_GetSMBData(outp, NULL);
4570 *tp++ = 43; /* bytes in a dir entry */
4571 *tp++ = 0; /* high byte in counter */
4573 /* now marshall the dir entry, starting with the search status */
4574 *tp++ = statBlockp[0]; /* Reserved */
4575 memcpy(tp, mask, 11); tp += 11; /* FileName */
4577 /* now pass back server use info, with 1st byte non-zero */
4579 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4581 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4583 *tp++ = 0x8; /* attribute: volume */
4593 /* 4 byte file size */
4599 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4602 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4603 memset(tp, ' ', 13);
4606 /* set the length of the data part of the packet to 43 + 3, for the dir
4607 * entry plus the 5 and the length fields.
4609 smb_SetSMBDataLength(outp, 46);
4614 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4615 clientchar_t * tidPathp, clientchar_t * relPathp,
4616 cm_user_t *userp, cm_req_t *reqp)
4624 smb_dirListPatch_t *patchp;
4625 smb_dirListPatch_t *npatchp;
4626 clientchar_t path[AFSPATHMAX];
4628 afs_int32 mustFake = 0;
4630 code = cm_FindACLCache(dscp, userp, &rights);
4632 lock_ObtainWrite(&dscp->rw);
4633 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4634 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4635 lock_ReleaseWrite(&dscp->rw);
4636 if (code == CM_ERROR_NOACCESS) {
4644 if (!mustFake) { /* Bulk Stat */
4646 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4648 memset(bsp, 0, sizeof(cm_bulkStat_t));
4650 for (patchp = *dirPatchespp, count=0;
4652 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4653 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4657 if (lock_TryWrite(&tscp->rw)) {
4658 /* we have an entry that we can look at */
4659 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4660 /* we have a callback on it. Don't bother
4661 * fetching this stat entry, since we're happy
4662 * with the info we have.
4664 lock_ReleaseWrite(&tscp->rw);
4665 cm_ReleaseSCache(tscp);
4668 lock_ReleaseWrite(&tscp->rw);
4670 cm_ReleaseSCache(tscp);
4674 bsp->fids[i].Volume = patchp->fid.volume;
4675 bsp->fids[i].Vnode = patchp->fid.vnode;
4676 bsp->fids[i].Unique = patchp->fid.unique;
4678 if (bsp->counter == AFSCBMAX) {
4679 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4680 memset(bsp, 0, sizeof(cm_bulkStat_t));
4684 if (bsp->counter > 0)
4685 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4690 for (patchp = *dirPatchespp; patchp; patchp =
4691 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4693 dptr = patchp->dptr;
4695 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4696 relPathp ? relPathp : _C(""), patchp->dep->name);
4697 reqp->relPathp = path;
4698 reqp->tidPathp = tidPathp;
4700 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4701 reqp->relPathp = reqp->tidPathp = NULL;
4704 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4705 *dptr++ = SMB_ATTR_HIDDEN;
4708 lock_ObtainWrite(&scp->rw);
4709 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4710 lock_ReleaseWrite(&scp->rw);
4712 /* set the attribute */
4713 switch (scp->fileType) {
4714 case CM_SCACHETYPE_DIRECTORY:
4715 case CM_SCACHETYPE_MOUNTPOINT:
4716 case CM_SCACHETYPE_INVALID:
4717 attr = SMB_ATTR_DIRECTORY;
4719 case CM_SCACHETYPE_SYMLINK:
4720 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4721 attr = SMB_ATTR_DIRECTORY;
4723 attr = SMB_ATTR_NORMAL;
4726 /* if we get here we either have a normal file
4727 * or we have a file for which we have never
4728 * received status info. In this case, we can
4729 * check the even/odd value of the entry's vnode.
4730 * odd means it is to be treated as a directory
4731 * and even means it is to be treated as a file.
4733 if (mustFake && (scp->fid.vnode & 0x1))
4734 attr = SMB_ATTR_DIRECTORY;
4736 attr = SMB_ATTR_NORMAL;
4740 /* 1969-12-31 23:59:58 +00*/
4741 dosTime = 0xEBBFBF7D;
4744 shortTemp = (unsigned short) (dosTime & 0xffff);
4745 *((u_short *)dptr) = shortTemp;
4748 /* and copy out date */
4749 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4750 *((u_short *)dptr) = shortTemp;
4753 /* copy out file length */
4754 *((u_long *)dptr) = 0;
4757 lock_ConvertWToR(&scp->rw);
4758 attr = smb_Attributes(scp);
4759 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4760 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4761 attr |= SMB_ATTR_HIDDEN;
4765 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4768 shortTemp = (unsigned short) (dosTime & 0xffff);
4769 *((u_short *)dptr) = shortTemp;
4772 /* and copy out date */
4773 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4774 *((u_short *)dptr) = shortTemp;
4777 /* copy out file length */
4778 *((u_long *)dptr) = scp->length.LowPart;
4780 lock_ReleaseRead(&scp->rw);
4782 cm_ReleaseSCache(scp);
4785 /* now free the patches */
4786 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4787 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4791 /* and mark the list as empty */
4792 *dirPatchespp = NULL;
4798 /* SMB_COM_SEARCH */
4799 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4805 clientchar_t *pathp;
4806 cm_dirEntry_t *dep = 0;
4808 smb_dirListPatch_t *dirListPatchesp;
4809 smb_dirListPatch_t *curPatchp;
4813 osi_hyper_t dirLength;
4814 osi_hyper_t bufferOffset;
4815 osi_hyper_t curOffset;
4817 unsigned char *inCookiep;
4818 smb_dirSearch_t *dsp;
4822 unsigned long clientCookie;
4823 cm_pageHeader_t *pageHeaderp;
4824 cm_user_t *userp = NULL;
4826 clientchar_t mask[12];
4828 long nextEntryCookie;
4829 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4830 char resByte; /* reserved byte from the cookie */
4831 char *op; /* output data ptr */
4832 char *origOp; /* original value of op */
4833 cm_space_t *spacep; /* for pathname buffer */
4837 clientchar_t *tidPathp = 0;
4844 maxCount = smb_GetSMBParm(inp, 0);
4846 dirListPatchesp = NULL;
4848 caseFold = CM_FLAG_CASEFOLD;
4850 tp = smb_GetSMBData(inp, NULL);
4851 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4852 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4854 return CM_ERROR_BADSMB;
4856 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4858 return CM_ERROR_BADSMB;
4860 /* We can handle long names */
4861 if (vcp->flags & SMB_VCFLAG_USENT)
4862 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4864 /* make sure we got a whole search status */
4865 if (dataLength < 21) {
4866 nextCookie = 0; /* start at the beginning of the dir */
4869 attribute = smb_GetSMBParm(inp, 1);
4871 /* handle volume info in another function */
4872 if (attribute & 0x8)
4873 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4875 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4876 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4878 if (*pathp == 0) { /* null pathp, treat as root dir */
4879 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4880 return CM_ERROR_NOFILES;
4884 dsp = smb_NewDirSearch(0);
4885 dsp->attribute = attribute;
4886 smb_Get8Dot3MaskFromPath(mask, pathp);
4887 memcpy(dsp->mask, mask, 12);
4889 /* track if this is likely to match a lot of entries */
4890 if (smb_Is8Dot3StarMask(mask))
4895 /* pull the next cookie value out of the search status block */
4896 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4897 + (inCookiep[16]<<24);
4898 dsp = smb_FindDirSearch(inCookiep[12]);
4900 /* can't find dir search status; fatal error */
4901 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4902 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4903 return CM_ERROR_BADFD;
4905 attribute = dsp->attribute;
4906 resByte = inCookiep[0];
4908 /* copy out client cookie, in host byte order. Don't bother
4909 * interpreting it, since we're just passing it through, anyway.
4911 memcpy(&clientCookie, &inCookiep[17], 4);
4913 memcpy(mask, dsp->mask, 12);
4915 /* assume we're doing a star match if it has continued for more
4921 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4922 nextCookie, dsp->cookie, attribute);
4924 userp = smb_GetUserFromVCP(vcp, inp);
4926 /* try to get the vnode for the path name next */
4927 lock_ObtainMutex(&dsp->mx);
4930 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4934 spacep = inp->spacep;
4935 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4936 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4938 lock_ReleaseMutex(&dsp->mx);
4939 cm_ReleaseUser(userp);
4940 smb_DeleteDirSearch(dsp);
4941 smb_ReleaseDirSearch(dsp);
4942 return CM_ERROR_NOFILES;
4944 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4945 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4947 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
4948 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4951 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4954 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4955 cm_ReleaseSCache(scp);
4956 lock_ReleaseMutex(&dsp->mx);
4957 cm_ReleaseUser(userp);
4958 smb_DeleteDirSearch(dsp);
4959 smb_ReleaseDirSearch(dsp);
4960 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4961 return CM_ERROR_PATH_NOT_COVERED;
4963 return CM_ERROR_NOSUCHPATH;
4965 #endif /* DFS_SUPPORT */
4968 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4969 /* we need one hold for the entry we just stored into,
4970 * and one for our own processing. When we're done with this
4971 * function, we'll drop the one for our own processing.
4972 * We held it once from the namei call, and so we do another hold
4976 lock_ObtainWrite(&scp->rw);
4977 dsp->flags |= SMB_DIRSEARCH_BULKST;
4978 lock_ReleaseWrite(&scp->rw);
4981 lock_ReleaseMutex(&dsp->mx);
4983 cm_ReleaseUser(userp);
4984 smb_DeleteDirSearch(dsp);
4985 smb_ReleaseDirSearch(dsp);
4989 /* reserves space for parameter; we'll adjust it again later to the
4990 * real count of the # of entries we returned once we've actually
4991 * assembled the directory listing.
4993 smb_SetSMBParm(outp, 0, 0);
4995 /* get the directory size */
4996 lock_ObtainWrite(&scp->rw);
4997 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4998 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5000 lock_ReleaseWrite(&scp->rw);
5001 cm_ReleaseSCache(scp);
5002 cm_ReleaseUser(userp);
5003 smb_DeleteDirSearch(dsp);
5004 smb_ReleaseDirSearch(dsp);
5008 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5010 dirLength = scp->length;
5012 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5013 curOffset.HighPart = 0;
5014 curOffset.LowPart = nextCookie;
5015 origOp = op = smb_GetSMBData(outp, NULL);
5016 /* and write out the basic header */
5017 *op++ = 5; /* variable block */
5018 op += 2; /* skip vbl block length; we'll fill it in later */
5022 clientchar_t *actualName = NULL;
5023 int free_actualName = 0;
5024 clientchar_t shortName[13];
5025 clientchar_t *shortNameEnd;
5027 /* make sure that curOffset.LowPart doesn't point to the first
5028 * 32 bytes in the 2nd through last dir page, and that it doesn't
5029 * point at the first 13 32-byte chunks in the first dir page,
5030 * since those are dir and page headers, and don't contain useful
5033 temp = curOffset.LowPart & (2048-1);
5034 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5035 /* we're in the first page */
5036 if (temp < 13*32) temp = 13*32;
5039 /* we're in a later dir page */
5040 if (temp < 32) temp = 32;
5043 /* make sure the low order 5 bits are zero */
5046 /* now put temp bits back ito curOffset.LowPart */
5047 curOffset.LowPart &= ~(2048-1);
5048 curOffset.LowPart |= temp;
5050 /* check if we've returned all the names that will fit in the
5053 if (returnedNames >= maxCount) {
5054 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5055 returnedNames, maxCount);
5059 /* check if we've passed the dir's EOF */
5060 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5062 /* see if we can use the bufferp we have now; compute in which page
5063 * the current offset would be, and check whether that's the offset
5064 * of the buffer we have. If not, get the buffer.
5066 thyper.HighPart = curOffset.HighPart;
5067 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5068 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5071 buf_Release(bufferp);
5074 lock_ReleaseWrite(&scp->rw);
5075 code = buf_Get(scp, &thyper, &req, &bufferp);
5076 lock_ObtainMutex(&dsp->mx);
5078 /* now, if we're doing a star match, do bulk fetching of all of
5079 * the status info for files in the dir.
5082 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5084 lock_ObtainWrite(&scp->rw);
5085 lock_ReleaseMutex(&dsp->mx);
5087 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5091 bufferOffset = thyper;
5093 /* now get the data in the cache */
5095 code = cm_SyncOp(scp, bufferp, userp, &req,
5097 CM_SCACHESYNC_NEEDCALLBACK |
5098 CM_SCACHESYNC_READ);
5100 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5104 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5106 if (cm_HaveBuffer(scp, bufferp, 0)) {
5107 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5111 /* otherwise, load the buffer and try again */
5112 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5114 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5115 scp, bufferp, code);
5120 buf_Release(bufferp);
5124 } /* if (wrong buffer) ... */
5126 /* now we have the buffer containing the entry we're interested in; copy
5127 * it out if it represents a non-deleted entry.
5129 entryInDir = curOffset.LowPart & (2048-1);
5130 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5132 /* page header will help tell us which entries are free. Page header
5133 * can change more often than once per buffer, since AFS 3 dir page size
5134 * may be less than (but not more than a buffer package buffer.
5136 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5137 temp &= ~(2048 - 1); /* turn off intra-page bits */
5138 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5140 /* now determine which entry we're looking at in the page. If it is
5141 * free (there's a free bitmap at the start of the dir), we should
5142 * skip these 32 bytes.
5144 slotInPage = (entryInDir & 0x7e0) >> 5;
5145 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5146 /* this entry is free */
5147 numDirChunks = 1; /* only skip this guy */
5151 tp = bufferp->datap + entryInBuffer;
5152 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5154 /* while we're here, compute the next entry's location, too,
5155 * since we'll need it when writing out the cookie into the dir
5158 * XXXX Probably should do more sanity checking.
5160 numDirChunks = cm_NameEntries(dep->name, NULL);
5162 /* compute the offset of the cookie representing the next entry */
5163 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5165 /* Compute 8.3 name if necessary */
5166 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5167 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5170 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5171 actualName = shortName;
5172 free_actualName = 0;
5174 free_actualName = 1;
5177 if (actualName == NULL) {
5178 /* Couldn't convert the name for some reason */
5179 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5180 osi_LogSaveString(smb_logp, dep->name));
5184 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5185 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5186 osi_LogSaveClientString(smb_logp, actualName));
5188 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5189 /* this is one of the entries to use: it is not deleted
5190 * and it matches the star pattern we're looking for.
5193 /* Eliminate entries that don't match requested
5196 /* no hidden files */
5197 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5198 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5202 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5204 /* We have already done the cm_TryBulkStat above */
5205 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5206 fileType = cm_FindFileType(&fid);
5207 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5208 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5210 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5211 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5212 fileType == CM_SCACHETYPE_DFSLINK ||
5213 fileType == CM_SCACHETYPE_INVALID)
5214 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5219 memcpy(op, mask, 11); op += 11;
5220 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5221 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5222 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5223 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5224 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5225 memcpy(op, &clientCookie, 4); op += 4;
5227 /* now we emit the attribute. This is sort of tricky,
5228 * since we need to really stat the file to find out
5229 * what type of entry we've got. Right now, we're
5230 * copying out data from a buffer, while holding the
5231 * scp locked, so it isn't really convenient to stat
5232 * something now. We'll put in a place holder now,
5233 * and make a second pass before returning this to get
5234 * the real attributes. So, we just skip the data for
5235 * now, and adjust it later. We allocate a patch
5236 * record to make it easy to find this point later.
5237 * The replay will happen at a time when it is safe to
5238 * unlock the directory.
5240 curPatchp = malloc(sizeof(*curPatchp));
5241 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5242 curPatchp->dptr = op;
5243 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5245 /* do hidden attribute here since name won't be around when applying
5249 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5250 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5252 curPatchp->flags = 0;
5254 op += 9; /* skip attr, time, date and size */
5256 /* zero out name area. The spec says to pad with
5257 * spaces, but Samba doesn't, and neither do we.
5261 /* finally, we get to copy out the name; we know that
5262 * it fits in 8.3 or the pattern wouldn't match, but it
5263 * never hurts to be sure.
5265 cm_ClientStringToUtf8(actualName, -1, op, 13);
5266 if (smb_StoreAnsiFilenames)
5268 /* This is a UCHAR field, which is ASCII even if Unicode
5271 /* Uppercase if requested by client */
5272 if (!KNOWS_LONG_NAMES(inp))
5277 /* now, adjust the # of entries copied */
5279 } /* if we're including this name */
5282 if (free_actualName && actualName) {
5287 /* and adjust curOffset to be where the new cookie is */
5288 thyper.HighPart = 0;
5289 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5290 curOffset = LargeIntegerAdd(thyper, curOffset);
5291 } /* while copying data for dir listing */
5293 /* release the mutex */
5294 lock_ReleaseWrite(&scp->rw);
5296 buf_Release(bufferp);
5300 /* apply and free last set of patches; if not doing a star match, this
5301 * will be empty, but better safe (and freeing everything) than sorry.
5303 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5305 /* special return code for unsuccessful search */
5306 if (code == 0 && dataLength < 21 && returnedNames == 0)
5307 code = CM_ERROR_NOFILES;
5309 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5310 returnedNames, code);
5313 smb_DeleteDirSearch(dsp);
5314 smb_ReleaseDirSearch(dsp);
5315 cm_ReleaseSCache(scp);
5316 cm_ReleaseUser(userp);
5320 /* finalize the output buffer */
5321 smb_SetSMBParm(outp, 0, returnedNames);
5322 temp = (long) (op - origOp);
5323 smb_SetSMBDataLength(outp, temp);
5325 /* the data area is a variable block, which has a 5 (already there)
5326 * followed by the length of the # of data bytes. We now know this to
5327 * be "temp," although that includes the 3 bytes of vbl block header.
5328 * Deduct for them and fill in the length field.
5330 temp -= 3; /* deduct vbl block info */
5331 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5332 origOp[1] = (unsigned char)(temp & 0xff);
5333 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5334 if (returnedNames == 0)
5335 smb_DeleteDirSearch(dsp);
5336 smb_ReleaseDirSearch(dsp);
5337 cm_ReleaseSCache(scp);
5338 cm_ReleaseUser(userp);
5343 /* verify that this is a valid path to a directory. I don't know why they
5344 * don't use the get file attributes call.
5346 * SMB_COM_CHECK_DIRECTORY
5348 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5350 clientchar_t *pathp;
5352 cm_scache_t *rootScp;
5353 cm_scache_t *newScp;
5357 clientchar_t *tidPathp;
5363 pdata = smb_GetSMBData(inp, NULL);
5364 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5366 return CM_ERROR_BADSMB;
5367 osi_Log1(smb_logp, "SMB receive check path %S",
5368 osi_LogSaveClientString(smb_logp, pathp));
5370 userp = smb_GetUserFromVCP(vcp, inp);
5372 rootScp = cm_RootSCachep(userp, &req);
5374 caseFold = CM_FLAG_CASEFOLD;
5376 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5378 cm_ReleaseUser(userp);
5379 return CM_ERROR_NOSUCHPATH;
5381 code = cm_NameI(rootScp, pathp,
5382 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5383 userp, tidPathp, &req, &newScp);
5386 cm_ReleaseUser(userp);
5391 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5392 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5393 cm_ReleaseSCache(newScp);
5394 cm_ReleaseUser(userp);
5395 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5396 return CM_ERROR_PATH_NOT_COVERED;
5398 return CM_ERROR_NOSUCHPATH;
5400 #endif /* DFS_SUPPORT */
5402 /* now lock the vnode with a callback; returns with newScp locked */
5403 lock_ObtainWrite(&newScp->rw);
5404 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5405 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5407 if (code != CM_ERROR_NOACCESS) {
5408 lock_ReleaseWrite(&newScp->rw);
5409 cm_ReleaseSCache(newScp);
5410 cm_ReleaseUser(userp);
5414 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5417 attrs = smb_Attributes(newScp);
5419 if (!(attrs & SMB_ATTR_DIRECTORY))
5420 code = CM_ERROR_NOTDIR;
5422 lock_ReleaseWrite(&newScp->rw);
5424 cm_ReleaseSCache(newScp);
5425 cm_ReleaseUser(userp);
5429 /* SMB_COM_SET_INFORMATION */
5430 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5432 clientchar_t *pathp;
5434 cm_scache_t *rootScp;
5435 unsigned short attribute;
5437 cm_scache_t *newScp;
5441 clientchar_t *tidPathp;
5447 /* decode basic attributes we're passed */
5448 attribute = smb_GetSMBParm(inp, 0);
5449 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5451 datap = smb_GetSMBData(inp, NULL);
5452 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5454 return CM_ERROR_BADSMB;
5456 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5457 dosTime, attribute);
5459 userp = smb_GetUserFromVCP(vcp, inp);
5461 rootScp = cm_RootSCachep(userp, &req);
5463 caseFold = CM_FLAG_CASEFOLD;
5465 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5467 cm_ReleaseUser(userp);
5468 return CM_ERROR_NOSUCHFILE;
5470 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5471 tidPathp, &req, &newScp);
5474 cm_ReleaseUser(userp);
5479 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5480 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5481 cm_ReleaseSCache(newScp);
5482 cm_ReleaseUser(userp);
5483 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5484 return CM_ERROR_PATH_NOT_COVERED;
5486 return CM_ERROR_NOSUCHPATH;
5488 #endif /* DFS_SUPPORT */
5490 /* now lock the vnode with a callback; returns with newScp locked; we
5491 * need the current status to determine what the new status is, in some
5494 lock_ObtainWrite(&newScp->rw);
5495 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5496 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5498 lock_ReleaseWrite(&newScp->rw);
5499 cm_ReleaseSCache(newScp);
5500 cm_ReleaseUser(userp);
5504 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5506 /* Check for RO volume */
5507 if (newScp->flags & CM_SCACHEFLAG_RO) {
5508 lock_ReleaseWrite(&newScp->rw);
5509 cm_ReleaseSCache(newScp);
5510 cm_ReleaseUser(userp);
5511 return CM_ERROR_READONLY;
5514 /* prepare for setattr call */
5517 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5518 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5520 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5521 /* we're told to make a writable file read-only */
5522 attr.unixModeBits = newScp->unixModeBits & ~0222;
5523 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5525 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5526 /* we're told to make a read-only file writable */
5527 attr.unixModeBits = newScp->unixModeBits | 0222;
5528 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5530 lock_ReleaseWrite(&newScp->rw);
5532 /* now call setattr */
5534 code = cm_SetAttr(newScp, &attr, userp, &req);
5538 cm_ReleaseSCache(newScp);
5539 cm_ReleaseUser(userp);
5545 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5547 clientchar_t *pathp;
5549 cm_scache_t *rootScp;
5550 cm_scache_t *newScp, *dscp;
5555 clientchar_t *tidPathp;
5557 clientchar_t *lastComp;
5563 datap = smb_GetSMBData(inp, NULL);
5564 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5566 return CM_ERROR_BADSMB;
5568 if (*pathp == 0) /* null path */
5571 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5572 osi_LogSaveClientString(smb_logp, pathp));
5574 userp = smb_GetUserFromVCP(vcp, inp);
5576 rootScp = cm_RootSCachep(userp, &req);
5578 /* we shouldn't need this for V3 requests, but we seem to */
5579 caseFold = CM_FLAG_CASEFOLD;
5581 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5583 cm_ReleaseUser(userp);
5584 return CM_ERROR_NOSUCHFILE;
5588 * XXX Strange hack XXX
5590 * As of Patch 5 (16 July 97), we are having the following problem:
5591 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5592 * requests to look up "desktop.ini" in all the subdirectories.
5593 * This can cause zillions of timeouts looking up non-existent cells
5594 * and volumes, especially in the top-level directory.
5596 * We have not found any way to avoid this or work around it except
5597 * to explicitly ignore the requests for mount points that haven't
5598 * yet been evaluated and for directories that haven't yet been
5601 * We should modify this hack to provide a fake desktop.ini file
5602 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5604 spacep = inp->spacep;
5605 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5606 #ifndef SPECIAL_FOLDERS
5607 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5608 code = cm_NameI(rootScp, spacep->wdata,
5609 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5610 userp, tidPathp, &req, &dscp);
5613 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5614 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5616 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5617 return CM_ERROR_PATH_NOT_COVERED;
5619 return CM_ERROR_NOSUCHPATH;
5621 #endif /* DFS_SUPPORT */
5622 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5623 code = CM_ERROR_NOSUCHFILE;
5624 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5625 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
5630 code = CM_ERROR_NOSUCHFILE;
5632 cm_ReleaseSCache(dscp);
5634 cm_ReleaseUser(userp);
5638 else if (code != CM_ERROR_NOSUCHFILE &&
5639 code != CM_ERROR_NOSUCHPATH &&
5640 code != CM_ERROR_BPLUS_NOMATCH)
5642 cm_ReleaseUser(userp);
5646 #endif /* SPECIAL_FOLDERS */
5648 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5649 tidPathp, &req, &newScp);
5651 cm_ReleaseUser(userp);
5656 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5657 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5658 cm_ReleaseSCache(newScp);
5659 cm_ReleaseUser(userp);
5660 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5661 return CM_ERROR_PATH_NOT_COVERED;
5663 return CM_ERROR_NOSUCHPATH;
5665 #endif /* DFS_SUPPORT */
5667 /* now lock the vnode with a callback; returns with newScp locked */
5668 lock_ObtainWrite(&newScp->rw);
5669 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5670 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5672 lock_ReleaseWrite(&newScp->rw);
5673 cm_ReleaseSCache(newScp);
5674 cm_ReleaseUser(userp);
5678 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5680 attrs = smb_Attributes(newScp);
5682 smb_SetSMBParm(outp, 0, attrs);
5684 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5685 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5686 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5687 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5688 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5689 smb_SetSMBParm(outp, 5, 0);
5690 smb_SetSMBParm(outp, 6, 0);
5691 smb_SetSMBParm(outp, 7, 0);
5692 smb_SetSMBParm(outp, 8, 0);
5693 smb_SetSMBParm(outp, 9, 0);
5694 smb_SetSMBDataLength(outp, 0);
5695 lock_ReleaseWrite(&newScp->rw);
5697 cm_ReleaseSCache(newScp);
5698 cm_ReleaseUser(userp);
5703 /* SMB_COM_TREE_DISCONNECT */
5704 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5708 osi_Log0(smb_logp, "SMB receive tree disconnect");
5710 /* find the tree and free it */
5711 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5713 lock_ObtainWrite(&smb_rctLock);
5715 smb_ReleaseTID(tidp, TRUE);
5716 lock_ReleaseWrite(&smb_rctLock);
5723 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5726 clientchar_t *pathp;
5727 clientchar_t *lastNamep;
5736 clientchar_t *tidPathp;
5742 datap = smb_GetSMBData(inp, NULL);
5743 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5745 return CM_ERROR_BADSMB;
5747 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5749 #ifdef DEBUG_VERBOSE
5753 hexpath = osi_HexifyString( pathp );
5754 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5759 share = smb_GetSMBParm(inp, 0);
5760 attribute = smb_GetSMBParm(inp, 1);
5762 spacep = inp->spacep;
5763 /* smb_StripLastComponent will strip "::$DATA" if present */
5764 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5766 if (!cm_IsValidClientString(pathp)) {
5768 clientchar_t * hexp;
5770 hexp = cm_GetRawCharsAlloc(pathp, -1);
5771 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5772 osi_LogSaveClientString(smb_logp, hexp));
5776 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5778 return CM_ERROR_BADNTFILENAME;
5781 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5782 /* special case magic file name for receiving IOCTL requests
5783 * (since IOCTL calls themselves aren't getting through).
5785 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5786 smb_SetupIoctlFid(fidp, spacep);
5787 smb_SetSMBParm(outp, 0, fidp->fid);
5788 smb_SetSMBParm(outp, 1, 0); /* attrs */
5789 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5790 smb_SetSMBParm(outp, 3, 0);
5791 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5792 smb_SetSMBParm(outp, 5, 0x7fff);
5793 /* pass the open mode back */
5794 smb_SetSMBParm(outp, 6, (share & 0xf));
5795 smb_SetSMBDataLength(outp, 0);
5796 smb_ReleaseFID(fidp);
5800 userp = smb_GetUserFromVCP(vcp, inp);
5802 caseFold = CM_FLAG_CASEFOLD;
5804 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5806 cm_ReleaseUser(userp);
5807 return CM_ERROR_NOSUCHPATH;
5809 code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
5810 tidPathp, &req, &scp);
5813 cm_ReleaseUser(userp);
5818 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5819 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5820 cm_ReleaseSCache(scp);
5821 cm_ReleaseUser(userp);
5822 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5823 return CM_ERROR_PATH_NOT_COVERED;
5825 return CM_ERROR_NOSUCHPATH;
5827 #endif /* DFS_SUPPORT */
5829 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5831 cm_ReleaseSCache(scp);
5832 cm_ReleaseUser(userp);
5836 /* don't need callback to check file type, since file types never
5837 * change, and namei and cm_Lookup all stat the object at least once on
5838 * a successful return.
5840 if (scp->fileType != CM_SCACHETYPE_FILE) {
5841 cm_ReleaseSCache(scp);
5842 cm_ReleaseUser(userp);
5843 return CM_ERROR_ISDIR;
5846 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5847 osi_assertx(fidp, "null smb_fid_t");
5849 lock_ObtainMutex(&fidp->mx);
5850 if ((share & 0xf) == 0)
5851 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5852 else if ((share & 0xf) == 1)
5853 fidp->flags |= SMB_FID_OPENWRITE;
5855 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5859 fidp->userp = userp;
5861 /* and a pointer to the vnode */
5863 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5864 lock_ObtainWrite(&scp->rw);
5865 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5867 smb_SetSMBParm(outp, 0, fidp->fid);
5868 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5869 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5870 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5871 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5872 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5873 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5874 /* pass the open mode back; XXXX add access checks */
5875 smb_SetSMBParm(outp, 6, (share & 0xf));
5876 smb_SetSMBDataLength(outp, 0);
5877 lock_ReleaseMutex(&fidp->mx);
5878 lock_ReleaseRead(&scp->rw);
5881 cm_Open(scp, 0, userp);
5883 /* send and free packet */
5884 smb_ReleaseFID(fidp);
5885 cm_ReleaseUser(userp);
5886 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5890 typedef struct smb_unlinkRock {
5895 clientchar_t *maskp; /* pointer to the star pattern */
5898 cm_dirEntryList_t * matches;
5901 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5904 smb_unlinkRock_t *rockp;
5907 normchar_t matchName[MAX_PATH];
5911 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5912 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5913 caseFold |= CM_FLAG_8DOT3;
5915 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5916 /* Can't convert name */
5917 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5918 osi_LogSaveString(smb_logp, dep->name));
5922 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5924 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5925 !cm_Is8Dot3(matchName)) {
5926 cm_Gen8Dot3Name(dep, matchName, NULL);
5927 /* 8.3 matches are always case insensitive */
5928 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5931 osi_Log1(smb_logp, "Found match %S",
5932 osi_LogSaveClientString(smb_logp, matchName));
5934 cm_DirEntryListAdd(dep->name, &rockp->matches);
5938 /* If we made a case sensitive exact match, we might as well quit now. */
5939 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5940 code = CM_ERROR_STOPNOW;
5949 /* SMB_COM_DELETE */
5950 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5954 clientchar_t *pathp;
5958 clientchar_t *lastNamep;
5959 smb_unlinkRock_t rock;
5963 clientchar_t *tidPathp;
5967 memset(&rock, 0, sizeof(rock));
5969 attribute = smb_GetSMBParm(inp, 0);
5971 tp = smb_GetSMBData(inp, NULL);
5972 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5974 return CM_ERROR_BADSMB;
5976 osi_Log1(smb_logp, "SMB receive unlink %S",
5977 osi_LogSaveClientString(smb_logp, pathp));
5979 spacep = inp->spacep;
5980 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5982 userp = smb_GetUserFromVCP(vcp, inp);
5984 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5986 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5988 cm_ReleaseUser(userp);
5989 return CM_ERROR_NOSUCHPATH;
5991 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
5994 cm_ReleaseUser(userp);
5999 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6000 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6001 cm_ReleaseSCache(dscp);
6002 cm_ReleaseUser(userp);
6003 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6004 return CM_ERROR_PATH_NOT_COVERED;
6006 return CM_ERROR_NOSUCHPATH;
6008 #endif /* DFS_SUPPORT */
6010 /* otherwise, scp points to the parent directory. */
6017 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
6019 code = CM_ERROR_NOSUCHFILE;
6022 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6025 thyper.HighPart = 0;
6030 rock.matches = NULL;
6032 /* Now, if we aren't dealing with a wildcard match, we first try an exact
6033 * match. If that fails, we do a case insensitve match.
6035 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6036 !smb_IsStarMask(rock.maskp)) {
6037 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6040 thyper.HighPart = 0;
6041 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6046 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6048 if (code == CM_ERROR_STOPNOW)
6051 if (code == 0 && rock.matches) {
6052 cm_dirEntryList_t * entry;
6054 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6055 normchar_t normalizedName[MAX_PATH];
6057 /* Note: entry->name is a non-normalized name */
6059 osi_Log1(smb_logp, "Unlinking %s",
6060 osi_LogSaveString(smb_logp, entry->name));
6062 /* We assume this works because entry->name was
6063 successfully converted in smb_UnlinkProc() once. */
6064 cm_FsStringToNormString(entry->name, -1,
6065 normalizedName, lengthof(normalizedName));
6067 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6069 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6070 smb_NotifyChange(FILE_ACTION_REMOVED,
6071 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6072 dscp, normalizedName, NULL, TRUE);
6076 cm_DirEntryListFree(&rock.matches);
6080 cm_ReleaseUser(userp);
6083 cm_ReleaseSCache(dscp);
6088 if (code == 0 && !rock.any)
6089 code = CM_ERROR_NOSUCHFILE;
6093 typedef struct smb_renameRock {
6094 cm_scache_t *odscp; /* old dir */
6095 cm_scache_t *ndscp; /* new dir */
6096 cm_user_t *userp; /* user */
6097 cm_req_t *reqp; /* request struct */
6098 smb_vc_t *vcp; /* virtual circuit */
6099 normchar_t *maskp; /* pointer to star pattern of old file name */
6100 int flags; /* tilde, casefold, etc */
6101 clientchar_t *newNamep; /* ptr to the new file's name */
6102 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6103 clientchar_t clOldName[MAX_PATH]; /* client name */
6107 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6110 smb_renameRock_t *rockp;
6113 normchar_t matchName[MAX_PATH];
6115 rockp = (smb_renameRock_t *) vrockp;
6117 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6118 /* Can't convert string */
6119 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6120 osi_LogSaveString(smb_logp, dep->name));
6124 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6125 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6126 caseFold |= CM_FLAG_8DOT3;
6128 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6130 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6131 !cm_Is8Dot3(matchName)) {
6132 cm_Gen8Dot3Name(dep, matchName, NULL);
6133 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6138 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6139 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6141 code = CM_ERROR_STOPNOW;
6151 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6154 cm_space_t *spacep = NULL;
6155 smb_renameRock_t rock;
6156 cm_scache_t *oldDscp = NULL;
6157 cm_scache_t *newDscp = NULL;
6158 cm_scache_t *tmpscp= NULL;
6159 cm_scache_t *tmpscp2 = NULL;
6160 clientchar_t *oldLastNamep;
6161 clientchar_t *newLastNamep;
6165 clientchar_t *tidPathp;
6169 userp = smb_GetUserFromVCP(vcp, inp);
6170 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6172 cm_ReleaseUser(userp);
6173 return CM_ERROR_NOSUCHPATH;
6177 memset(&rock, 0, sizeof(rock));
6179 spacep = inp->spacep;
6180 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6182 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6183 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6184 userp, tidPathp, &req, &oldDscp);
6186 cm_ReleaseUser(userp);
6191 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6192 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6193 cm_ReleaseSCache(oldDscp);
6194 cm_ReleaseUser(userp);
6195 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6196 return CM_ERROR_PATH_NOT_COVERED;
6198 return CM_ERROR_NOSUCHPATH;
6200 #endif /* DFS_SUPPORT */
6202 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6203 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6204 userp, tidPathp, &req, &newDscp);
6207 cm_ReleaseSCache(oldDscp);
6208 cm_ReleaseUser(userp);
6213 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6214 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6215 cm_ReleaseSCache(oldDscp);
6216 cm_ReleaseSCache(newDscp);
6217 cm_ReleaseUser(userp);
6218 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6219 return CM_ERROR_PATH_NOT_COVERED;
6221 return CM_ERROR_NOSUCHPATH;
6223 #endif /* DFS_SUPPORT */
6226 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6227 * next, get the component names, and lower case them.
6230 /* handle the old name first */
6232 oldLastNamep = oldPathp;
6236 /* and handle the new name, too */
6238 newLastNamep = newPathp;
6242 /* TODO: The old name could be a wildcard. The new name must not be */
6244 /* Check if the file already exists; if so return error */
6245 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6246 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6247 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6249 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6250 osi_LogSaveClientString(smb_logp, newLastNamep));
6252 /* Check if the old and the new names differ only in case. If so return
6253 * success, else return CM_ERROR_EXISTS
6255 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6257 /* This would be a success only if the old file is *as same as* the new file */
6258 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6260 if (tmpscp == tmpscp2)
6263 code = CM_ERROR_EXISTS;
6264 cm_ReleaseSCache(tmpscp2);
6267 code = CM_ERROR_NOSUCHFILE;
6270 /* file exist, do not rename, also fixes move */
6271 osi_Log0(smb_logp, "Can't rename. Target already exists");
6272 code = CM_ERROR_EXISTS;
6277 /* do the vnode call */
6278 rock.odscp = oldDscp;
6279 rock.ndscp = newDscp;
6283 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6285 code = CM_ERROR_NOSUCHFILE;
6288 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6289 rock.newNamep = newLastNamep;
6290 rock.fsOldName[0] = '\0';
6291 rock.clOldName[0] = '\0';
6294 /* Now search the directory for the pattern, and do the appropriate rename when found */
6295 thyper.LowPart = 0; /* search dir from here */
6296 thyper.HighPart = 0;
6298 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6299 if (code == 0 && !rock.any) {
6301 thyper.HighPart = 0;
6302 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6303 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6305 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6307 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6308 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6309 rock.ndscp, rock.newNamep, rock.userp,
6311 /* if the call worked, stop doing the search now, since we
6312 * really only want to rename one file.
6315 osi_Log0(smb_logp, "cm_Rename failure");
6316 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6317 } else if (code == 0) {
6318 code = CM_ERROR_NOSUCHFILE;
6321 /* Handle Change Notification */
6323 * Being lazy, not distinguishing between files and dirs in this
6324 * filter, since we'd have to do a lookup.
6327 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6328 if (oldDscp == newDscp) {
6329 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6330 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6331 filter, oldDscp, rock.clOldName,
6332 newLastNamep, TRUE);
6334 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6335 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6336 filter, oldDscp, rock.clOldName,
6338 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6339 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6340 filter, newDscp, newLastNamep,
6347 cm_ReleaseSCache(tmpscp);
6349 cm_ReleaseUser(userp);
6351 cm_ReleaseSCache(oldDscp);
6353 cm_ReleaseSCache(newDscp);
6361 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6364 cm_space_t *spacep = NULL;
6365 cm_scache_t *oldDscp = NULL;
6366 cm_scache_t *newDscp = NULL;
6367 cm_scache_t *tmpscp= NULL;
6368 cm_scache_t *tmpscp2 = NULL;
6369 cm_scache_t *sscp = NULL;
6370 clientchar_t *oldLastNamep;
6371 clientchar_t *newLastNamep;
6374 clientchar_t *tidPathp;
6378 userp = smb_GetUserFromVCP(vcp, inp);
6380 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6382 cm_ReleaseUser(userp);
6383 return CM_ERROR_NOSUCHPATH;
6388 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6390 spacep = inp->spacep;
6391 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6393 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6394 userp, tidPathp, &req, &oldDscp);
6396 cm_ReleaseUser(userp);
6401 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6402 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6403 cm_ReleaseSCache(oldDscp);
6404 cm_ReleaseUser(userp);
6405 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6406 return CM_ERROR_PATH_NOT_COVERED;
6408 return CM_ERROR_NOSUCHPATH;
6410 #endif /* DFS_SUPPORT */
6412 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6413 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6414 userp, tidPathp, &req, &newDscp);
6416 cm_ReleaseSCache(oldDscp);
6417 cm_ReleaseUser(userp);
6422 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6423 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6424 cm_ReleaseSCache(newDscp);
6425 cm_ReleaseSCache(oldDscp);
6426 cm_ReleaseUser(userp);
6427 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6428 return CM_ERROR_PATH_NOT_COVERED;
6430 return CM_ERROR_NOSUCHPATH;
6432 #endif /* DFS_SUPPORT */
6434 /* Now, although we did two lookups for the two directories (because the same
6435 * directory can be referenced through different paths), we only allow hard links
6436 * within the same directory. */
6437 if (oldDscp != newDscp) {
6438 cm_ReleaseSCache(oldDscp);
6439 cm_ReleaseSCache(newDscp);
6440 cm_ReleaseUser(userp);
6441 return CM_ERROR_CROSSDEVLINK;
6444 /* handle the old name first */
6446 oldLastNamep = oldPathp;
6450 /* and handle the new name, too */
6452 newLastNamep = newPathp;
6456 /* now lookup the old name */
6457 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6458 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6460 cm_ReleaseSCache(oldDscp);
6461 cm_ReleaseSCache(newDscp);
6462 cm_ReleaseUser(userp);
6466 /* Check if the file already exists; if so return error */
6467 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6468 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6469 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6471 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6472 osi_LogSaveClientString(smb_logp, newLastNamep));
6474 /* if the existing link is to the same file, then we return success */
6476 if(sscp == tmpscp) {
6479 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6480 code = CM_ERROR_EXISTS;
6485 cm_ReleaseSCache(tmpscp);
6486 cm_ReleaseSCache(sscp);
6487 cm_ReleaseSCache(newDscp);
6488 cm_ReleaseSCache(oldDscp);
6489 cm_ReleaseUser(userp);
6493 /* now create the hardlink */
6494 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6495 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6496 osi_Log1(smb_logp," Link returns 0x%x", code);
6498 /* Handle Change Notification */
6500 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6501 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6502 smb_NotifyChange(FILE_ACTION_ADDED,
6503 filter, newDscp, newLastNamep,
6508 cm_ReleaseSCache(tmpscp);
6509 cm_ReleaseUser(userp);
6510 cm_ReleaseSCache(sscp);
6511 cm_ReleaseSCache(oldDscp);
6512 cm_ReleaseSCache(newDscp);
6516 /* SMB_COM_RENAME */
6518 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6520 clientchar_t *oldPathp;
6521 clientchar_t *newPathp;
6525 tp = smb_GetSMBData(inp, NULL);
6526 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6528 return CM_ERROR_BADSMB;
6529 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6531 return CM_ERROR_BADSMB;
6533 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6534 osi_LogSaveClientString(smb_logp, oldPathp),
6535 osi_LogSaveClientString(smb_logp, newPathp));
6537 if (!cm_IsValidClientString(newPathp)) {
6539 clientchar_t * hexp;
6541 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6542 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6543 osi_LogSaveClientString(smb_logp, hexp));
6547 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6549 return CM_ERROR_BADNTFILENAME;
6552 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6554 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6560 typedef struct smb_rmdirRock {
6564 normchar_t *maskp; /* pointer to the star pattern */
6567 cm_dirEntryList_t * matches;
6570 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6573 smb_rmdirRock_t *rockp;
6575 normchar_t matchName[MAX_PATH];
6577 rockp = (smb_rmdirRock_t *) vrockp;
6579 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6580 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6581 osi_LogSaveString(smb_logp, dep->name));
6585 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6586 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6588 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6590 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6591 !cm_Is8Dot3(matchName)) {
6592 cm_Gen8Dot3Name(dep, matchName, NULL);
6593 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6598 cm_DirEntryListAdd(dep->name, &rockp->matches);
6605 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6608 clientchar_t *pathp;
6612 clientchar_t *lastNamep;
6613 smb_rmdirRock_t rock;
6617 clientchar_t *tidPathp;
6621 memset(&rock, 0, sizeof(rock));
6623 tp = smb_GetSMBData(inp, NULL);
6624 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6626 return CM_ERROR_BADSMB;
6628 spacep = inp->spacep;
6629 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6631 userp = smb_GetUserFromVCP(vcp, inp);
6633 caseFold = CM_FLAG_CASEFOLD;
6635 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6637 cm_ReleaseUser(userp);
6638 return CM_ERROR_NOSUCHPATH;
6640 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6641 userp, tidPathp, &req, &dscp);
6644 cm_ReleaseUser(userp);
6649 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6650 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6651 cm_ReleaseSCache(dscp);
6652 cm_ReleaseUser(userp);
6653 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6654 return CM_ERROR_PATH_NOT_COVERED;
6656 return CM_ERROR_NOSUCHPATH;
6658 #endif /* DFS_SUPPORT */
6660 /* otherwise, scp points to the parent directory. */
6667 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6669 code = CM_ERROR_NOSUCHFILE;
6672 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6675 thyper.HighPart = 0;
6679 rock.matches = NULL;
6681 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6682 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6683 if (code == 0 && !rock.any) {
6685 thyper.HighPart = 0;
6686 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6687 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6690 if (code == 0 && rock.matches) {
6691 cm_dirEntryList_t * entry;
6693 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6694 clientchar_t clientName[MAX_PATH];
6696 /* We assume this will succeed because smb_RmdirProc()
6697 successfully converted entry->name once above. */
6698 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6700 osi_Log1(smb_logp, "Removing directory %s",
6701 osi_LogSaveString(smb_logp, entry->name));
6703 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6705 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6706 smb_NotifyChange(FILE_ACTION_REMOVED,
6707 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6708 dscp, clientName, NULL, TRUE);
6714 cm_DirEntryListFree(&rock.matches);
6717 cm_ReleaseUser(userp);
6720 cm_ReleaseSCache(dscp);
6722 if (code == 0 && !rock.any)
6723 code = CM_ERROR_NOSUCHFILE;
6732 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6742 fid = smb_GetSMBParm(inp, 0);
6744 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6746 fid = smb_ChainFID(fid, inp);
6747 fidp = smb_FindFID(vcp, fid, 0);
6749 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6751 return CM_ERROR_BADFD;
6753 userp = smb_GetUserFromVCP(vcp, inp);
6755 lock_ObtainMutex(&fidp->mx);
6756 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6757 cm_ReleaseUser(userp);
6758 lock_ReleaseMutex(&fidp->mx);
6759 smb_ReleaseFID(fidp);
6760 return CM_ERROR_BADFD;
6763 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6764 lock_ReleaseMutex(&fidp->mx);
6765 cm_ReleaseUser(userp);
6766 smb_CloseFID(vcp, fidp, NULL, 0);
6767 smb_ReleaseFID(fidp);
6768 return CM_ERROR_NOSUCHFILE;
6771 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6772 cm_scache_t * scp = fidp->scp;
6774 lock_ReleaseMutex(&fidp->mx);
6775 code = cm_FSync(scp, userp, &req, FALSE);
6776 cm_ReleaseSCache(scp);
6778 lock_ReleaseMutex(&fidp->mx);
6782 cm_ReleaseUser(userp);
6783 smb_ReleaseFID(fidp);
6787 struct smb_FullNameRock {
6790 clientchar_t *fullName;
6791 fschar_t *originalName;
6794 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6797 normchar_t matchName[MAX_PATH];
6798 struct smb_FullNameRock *vrockp;
6800 vrockp = (struct smb_FullNameRock *)rockp;
6802 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6803 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6804 osi_LogSaveString(smb_logp, dep->name));
6808 if (!cm_Is8Dot3(matchName)) {
6809 clientchar_t shortName[13];
6811 cm_Gen8Dot3Name(dep, shortName, NULL);
6813 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6814 vrockp->fullName = cm_ClientStrDup(matchName);
6815 vrockp->originalName = cm_FsStrDup(dep->name);
6816 return CM_ERROR_STOPNOW;
6819 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6820 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6821 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6822 vrockp->fullName = cm_ClientStrDup(matchName);
6823 vrockp->originalName = cm_FsStrDup(dep->name);
6824 return CM_ERROR_STOPNOW;
6829 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6830 clientchar_t **newPathp, fschar_t ** originalPathp,
6831 cm_user_t *userp, cm_req_t *reqp)
6833 struct smb_FullNameRock rock;
6836 memset(&rock, 0, sizeof(rock));
6840 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6841 if (code == CM_ERROR_STOPNOW) {
6842 *newPathp = rock.fullName;
6843 *originalPathp = rock.originalName;
6845 *newPathp = cm_ClientStrDup(pathp);
6846 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6850 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6851 afs_uint32 dosTime) {
6854 cm_scache_t *dscp = NULL;
6855 clientchar_t *pathp = NULL;
6856 cm_scache_t * scp = NULL;
6857 cm_scache_t *delscp = NULL;
6858 int nullcreator = 0;
6860 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6861 fidp, fidp->fid, scp, vcp);
6864 lock_ObtainMutex(&fidp->mx);
6865 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6867 lock_ReleaseMutex(&fidp->mx);
6868 osi_Log0(smb_logp, " No user specified. Not closing fid");
6869 return CM_ERROR_BADFD;
6872 userp = fidp->userp; /* no hold required since fidp is held
6873 throughout the function */
6874 lock_ReleaseMutex(&fidp->mx);
6879 lock_ObtainWrite(&smb_rctLock);
6880 if (fidp->deleteOk) {
6881 osi_Log0(smb_logp, " Fid already closed.");
6882 lock_ReleaseWrite(&smb_rctLock);
6883 return CM_ERROR_BADFD;
6886 lock_ReleaseWrite(&smb_rctLock);
6888 lock_ObtainMutex(&fidp->mx);
6889 if (fidp->NTopen_dscp) {
6890 dscp = fidp->NTopen_dscp;
6891 cm_HoldSCache(dscp);
6894 if (fidp->NTopen_pathp)
6895 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6902 /* Don't jump the gun on an async raw write */
6903 while (fidp->raw_writers) {
6904 lock_ReleaseMutex(&fidp->mx);
6905 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6906 lock_ObtainMutex(&fidp->mx);
6909 /* watch for ioctl closes, and read-only opens */
6911 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6912 == SMB_FID_OPENWRITE) {
6913 if (dosTime != 0 && dosTime != -1) {
6914 lock_ObtainWrite(&fidp->scp->rw);
6915 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6916 /* This fixes defect 10958 */
6917 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6918 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6919 lock_ReleaseWrite(&fidp->scp->rw);
6921 if (smb_AsyncStore != 2) {
6922 lock_ReleaseMutex(&fidp->mx);
6923 code = cm_FSync(scp, userp, &req, FALSE);
6924 lock_ObtainMutex(&fidp->mx);
6930 /* unlock any pending locks */
6931 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6932 scp->fileType == CM_SCACHETYPE_FILE) {
6936 lock_ReleaseMutex(&fidp->mx);
6939 * CM_UNLOCK_FLAG_BY_FID doesn't look at the process ID.
6942 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6943 lock_ObtainWrite(&scp->rw);
6945 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6946 CM_SCACHESYNC_NEEDCALLBACK
6947 | CM_SCACHESYNC_GETSTATUS
6948 | CM_SCACHESYNC_LOCK);
6952 "smb CoreClose SyncOp failure code 0x%x", tcode);
6953 goto post_syncopdone;
6956 cm_UnlockByKey(scp, key, CM_UNLOCK_FLAG_BY_FID, userp, &req);
6958 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6962 lock_ReleaseWrite(&scp->rw);
6963 lock_ObtainMutex(&fidp->mx);
6966 if (fidp->flags & SMB_FID_DELONCLOSE) {
6967 clientchar_t *fullPathp = NULL;
6968 fschar_t *originalNamep = NULL;
6970 lock_ReleaseMutex(&fidp->mx);
6972 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6977 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6978 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6979 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6981 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6982 smb_NotifyChange(FILE_ACTION_REMOVED,
6983 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6984 dscp, fullPathp, NULL, TRUE);
6987 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6989 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6990 smb_NotifyChange(FILE_ACTION_REMOVED,
6991 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6992 dscp, fullPathp, NULL, TRUE);
6999 free(originalNamep);
7001 lock_ObtainMutex(&fidp->mx);
7002 fidp->flags &= ~SMB_FID_DELONCLOSE;
7005 /* if this was a newly created file, then clear the creator
7006 * in the stat cache entry. */
7007 if (fidp->flags & SMB_FID_CREATED) {
7009 fidp->flags &= ~SMB_FID_CREATED;
7012 if (fidp->flags & SMB_FID_NTOPEN) {
7013 cm_ReleaseSCache(fidp->NTopen_dscp);
7014 fidp->NTopen_dscp = NULL;
7015 free(fidp->NTopen_pathp);
7016 fidp->NTopen_pathp = NULL;
7017 fidp->flags &= ~SMB_FID_NTOPEN;
7019 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
7020 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7023 if (fidp->NTopen_wholepathp) {
7024 free(fidp->NTopen_wholepathp);
7025 fidp->NTopen_wholepathp = NULL;
7029 cm_ReleaseSCache(fidp->scp);
7032 lock_ReleaseMutex(&fidp->mx);
7035 cm_ReleaseSCache(dscp);
7038 cm_ReleaseSCache(delscp);
7042 lock_ObtainWrite(&scp->rw);
7043 if (nullcreator && scp->creator == userp)
7044 scp->creator = NULL;
7045 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7046 lock_ReleaseWrite(&scp->rw);
7047 cm_ReleaseSCache(scp);
7057 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7065 fid = smb_GetSMBParm(inp, 0);
7066 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7068 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7070 fid = smb_ChainFID(fid, inp);
7071 fidp = smb_FindFID(vcp, fid, 0);
7073 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
7075 return CM_ERROR_BADFD;
7078 userp = smb_GetUserFromVCP(vcp, inp);
7080 code = smb_CloseFID(vcp, fidp, userp, dosTime);
7082 smb_ReleaseFID(fidp);
7083 cm_ReleaseUser(userp);
7088 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7090 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7091 cm_user_t *userp, long *readp)
7097 osi_hyper_t fileLength;
7099 osi_hyper_t lastByte;
7100 osi_hyper_t bufferOffset;
7104 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7107 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7108 fidp->fid, offsetp->LowPart, count);
7112 lock_ObtainMutex(&fidp->mx);
7113 /* make sure we have a readable FD */
7114 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7115 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7116 fidp->fid, fidp->flags);
7117 lock_ReleaseMutex(&fidp->mx);
7118 code = CM_ERROR_BADFDOP;
7123 lock_ReleaseMutex(&fidp->mx);
7124 code = CM_ERROR_BADFD;
7135 lock_ObtainWrite(&scp->rw);
7137 if (offset.HighPart == 0) {
7138 chunk = offset.LowPart >> cm_logChunkSize;
7139 if (chunk != fidp->curr_chunk) {
7140 fidp->prev_chunk = fidp->curr_chunk;
7141 fidp->curr_chunk = chunk;
7143 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7146 lock_ReleaseMutex(&fidp->mx);
7148 /* start by looking up the file's end */
7149 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7150 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7154 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7156 /* now we have the entry locked, look up the length */
7157 fileLength = scp->length;
7159 /* adjust count down so that it won't go past EOF */
7160 thyper.LowPart = count;
7161 thyper.HighPart = 0;
7162 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7164 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7165 /* we'd read past EOF, so just stop at fileLength bytes.
7166 * Start by computing how many bytes remain in the file.
7168 thyper = LargeIntegerSubtract(fileLength, offset);
7170 /* if we are past EOF, read 0 bytes */
7171 if (LargeIntegerLessThanZero(thyper))
7174 count = thyper.LowPart;
7179 /* now, copy the data one buffer at a time,
7180 * until we've filled the request packet
7183 /* if we've copied all the data requested, we're done */
7184 if (count <= 0) break;
7186 /* otherwise, load up a buffer of data */
7187 thyper.HighPart = offset.HighPart;
7188 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7189 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7192 buf_Release(bufferp);
7195 lock_ReleaseWrite(&scp->rw);
7197 code = buf_Get(scp, &thyper, &req, &bufferp);
7199 lock_ObtainWrite(&scp->rw);
7200 if (code) goto done;
7201 bufferOffset = thyper;
7203 /* now get the data in the cache */
7205 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7206 CM_SCACHESYNC_NEEDCALLBACK |
7207 CM_SCACHESYNC_READ);
7211 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7213 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7215 /* otherwise, load the buffer and try again */
7216 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7220 buf_Release(bufferp);
7224 } /* if (wrong buffer) ... */
7226 /* now we have the right buffer loaded. Copy out the
7227 * data from here to the user's buffer.
7229 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7231 /* and figure out how many bytes we want from this buffer */
7232 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7233 if (nbytes > count) nbytes = count; /* don't go past EOF */
7235 /* now copy the data */
7236 memcpy(op, bufferp->datap + bufIndex, nbytes);
7238 /* adjust counters, pointers, etc. */
7241 thyper.LowPart = nbytes;
7242 thyper.HighPart = 0;
7243 offset = LargeIntegerAdd(thyper, offset);
7247 lock_ReleaseWrite(&scp->rw);
7249 buf_Release(bufferp);
7251 if (code == 0 && sequential)
7252 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7254 cm_ReleaseSCache(scp);
7257 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7258 fidp->fid, code, *readp);
7263 * smb_WriteData -- common code for Write and Raw Write
7265 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7266 cm_user_t *userp, long *writtenp)
7268 osi_hyper_t offset = *offsetp;
7271 cm_scache_t *scp = NULL;
7272 osi_hyper_t fileLength; /* file's length at start of write */
7273 osi_hyper_t minLength; /* don't read past this */
7274 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7275 cm_buf_t *bufferp = NULL;
7276 osi_hyper_t thyper; /* hyper tmp variable */
7277 osi_hyper_t bufferOffset;
7278 afs_uint32 bufIndex; /* index in buffer where our data is */
7279 int doWriteBack = 0;
7280 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7283 int needSyncOpDone = 0;
7285 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7286 fidp->fid, offsetp->LowPart, count);
7290 lock_ObtainMutex(&fidp->mx);
7291 /* make sure we have a writable FD */
7292 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7293 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7294 fidp->fid, fidp->flags);
7295 lock_ReleaseMutex(&fidp->mx);
7296 code = CM_ERROR_BADFDOP;
7304 lock_ReleaseMutex(&fidp->mx);
7306 lock_ObtainWrite(&scp->rw);
7307 /* start by looking up the file's end */
7308 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7309 CM_SCACHESYNC_NEEDCALLBACK
7310 | CM_SCACHESYNC_SETSTATUS
7311 | CM_SCACHESYNC_GETSTATUS);
7315 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7317 /* now we have the entry locked, look up the length */
7318 fileLength = scp->length;
7319 minLength = fileLength;
7320 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7321 minLength = scp->serverLength;
7323 /* adjust file length if we extend past EOF */
7324 thyper.LowPart = count;
7325 thyper.HighPart = 0;
7326 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7327 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7328 /* we'd write past EOF, so extend the file */
7329 scp->mask |= CM_SCACHEMASK_LENGTH;
7330 scp->length = thyper;
7331 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7333 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7335 /* now, if the new position (thyper) and the old (offset) are in
7336 * different storeback windows, remember to store back the previous
7337 * storeback window when we're done with the write.
7339 * the purpose of this logic is to slow down the CIFS client
7340 * in order to avoid the client disconnecting during the CLOSE
7341 * operation if there are too many dirty buffers left to write
7342 * than can be accomplished during 45 seconds. This used to be
7343 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7344 * so that we can read larger amounts of data at a time.
7346 if (smb_AsyncStore == 1 &&
7347 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7348 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7349 /* they're different */
7351 writeBackOffset.HighPart = offset.HighPart;
7352 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7357 /* now, copy the data one buffer at a time, until we've filled the
7359 while (count != 0) {
7361 /* handle over quota or out of space */
7362 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7363 *writtenp = written;
7364 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7368 /* otherwise, load up a buffer of data */
7369 thyper.HighPart = offset.HighPart;
7370 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7371 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7374 if (needSyncOpDone) {
7375 cm_SyncOpDone(scp, bufferp,
7376 CM_SCACHESYNC_NEEDCALLBACK
7377 | CM_SCACHESYNC_WRITE
7378 | CM_SCACHESYNC_BUFLOCKED);
7381 lock_ReleaseMutex(&bufferp->mx);
7382 buf_Release(bufferp);
7385 lock_ReleaseWrite(&scp->rw);
7387 code = buf_Get(scp, &thyper, &req, &bufferp);
7389 lock_ObtainMutex(&bufferp->mx);
7390 lock_ObtainWrite(&scp->rw);
7391 if (code) goto done;
7393 bufferOffset = thyper;
7395 /* now get the data in the cache */
7397 if (!needSyncOpDone) {
7398 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7399 CM_SCACHESYNC_NEEDCALLBACK
7400 | CM_SCACHESYNC_WRITE
7401 | CM_SCACHESYNC_BUFLOCKED);
7408 /* If we're overwriting the entire buffer, or
7409 * if we're writing at or past EOF, mark the
7410 * buffer as current so we don't call
7411 * cm_GetBuffer. This skips the fetch from the
7412 * server in those cases where we're going to
7413 * obliterate all the data in the buffer anyway,
7414 * or in those cases where there is no useful
7415 * data at the server to start with.
7417 * Use minLength instead of scp->length, since
7418 * the latter has already been updated by this
7421 * The scp lock has been dropped multiple times
7422 * so the minLength must be refreshed before it
7426 minLength = scp->length;
7427 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7428 minLength = scp->serverLength;
7430 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7431 || LargeIntegerEqualTo(offset, bufferp->offset)
7432 && (count >= cm_data.buf_blockSize
7433 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7434 ConvertLongToLargeInteger(count)),
7436 if (count < cm_data.buf_blockSize
7437 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7438 memset(bufferp->datap, 0,
7439 cm_data.buf_blockSize);
7440 bufferp->dataVersion = scp->dataVersion;
7443 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7445 /* otherwise, load the buffer and try again */
7446 cm_SyncOpDone(scp, bufferp,
7447 CM_SCACHESYNC_NEEDCALLBACK
7448 | CM_SCACHESYNC_WRITE
7449 | CM_SCACHESYNC_BUFLOCKED);
7452 lock_ReleaseMutex(&bufferp->mx);
7453 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7455 lock_ReleaseWrite(&scp->rw);
7456 lock_ObtainMutex(&bufferp->mx);
7457 lock_ObtainWrite(&scp->rw);
7461 } /* if (wrong buffer) ... */
7463 /* now we have the right buffer loaded. Copy out the
7464 * data from here to the user's buffer.
7466 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7468 /* and figure out how many bytes we want from this buffer */
7469 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7471 nbytes = count; /* don't go past end of request */
7473 /* now copy the data */
7474 memcpy(bufferp->datap + bufIndex, op, nbytes);
7475 buf_SetDirty(bufferp, &req, bufIndex, nbytes, userp);
7477 /* adjust counters, pointers, etc. */
7481 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7482 } /* while count != 0 */
7485 if (bufferp && needSyncOpDone) {
7486 cm_SyncOpDone(scp, bufferp,
7487 CM_SCACHESYNC_NEEDCALLBACK
7488 | CM_SCACHESYNC_WRITE
7489 | CM_SCACHESYNC_BUFLOCKED);
7492 lock_ReleaseWrite(&scp->rw);
7495 lock_ReleaseMutex(&bufferp->mx);
7496 buf_Release(bufferp);
7499 lock_ObtainMutex(&fidp->mx);
7500 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7501 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7503 lock_ReleaseMutex(&fidp->mx);
7504 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7505 fidp->NTopen_dscp, fidp->NTopen_pathp,
7508 lock_ReleaseMutex(&fidp->mx);
7512 if (smb_AsyncStore > 0) {
7516 lock_ObtainWrite(&scp->rw);
7517 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7519 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7520 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7522 lock_ReleaseWrite(&scp->rw);
7523 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7524 writeBackOffset.HighPart,
7525 smb_AsyncStoreSize, 0, userp, &req);
7526 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7529 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7533 cm_ReleaseSCache(scp);
7536 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7537 fidp->fid, code, *writtenp);
7542 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7545 unsigned short count;
7547 unsigned short hint;
7548 long written = 0, total_written = 0;
7551 smb_t* smbp = (smb_t*) inp;
7555 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7557 int inDataBlockCount;
7559 fd = smb_GetSMBParm(inp, 0);
7560 count = smb_GetSMBParm(inp, 1);
7561 offset.HighPart = 0; /* too bad */
7562 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7563 hint = smb_GetSMBParm(inp, 4);
7565 op = smb_GetSMBData(inp, NULL);
7566 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7568 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7569 fd, offset.LowPart, count);
7571 fd = smb_ChainFID(fd, inp);
7572 fidp = smb_FindFID(vcp, fd, 0);
7574 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7576 return CM_ERROR_BADFD;
7579 lock_ObtainMutex(&fidp->mx);
7580 if (fidp->flags & SMB_FID_IOCTL) {
7581 lock_ReleaseMutex(&fidp->mx);
7582 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7583 smb_ReleaseFID(fidp);
7584 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7588 if (fidp->flags & SMB_FID_RPC) {
7589 lock_ReleaseMutex(&fidp->mx);
7590 code = smb_RPCWrite(fidp, vcp, inp, outp);
7591 smb_ReleaseFID(fidp);
7592 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7597 lock_ReleaseMutex(&fidp->mx);
7598 smb_ReleaseFID(fidp);
7599 return CM_ERROR_BADFD;
7602 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7603 lock_ReleaseMutex(&fidp->mx);
7604 smb_CloseFID(vcp, fidp, NULL, 0);
7605 smb_ReleaseFID(fidp);
7606 return CM_ERROR_NOSUCHFILE;
7611 lock_ReleaseMutex(&fidp->mx);
7612 userp = smb_GetUserFromVCP(vcp, inp);
7616 LARGE_INTEGER LOffset;
7617 LARGE_INTEGER LLength;
7620 key = cm_GenerateKey(vcp->vcID, pid, fd);
7622 LOffset.HighPart = offset.HighPart;
7623 LOffset.LowPart = offset.LowPart;
7624 LLength.HighPart = 0;
7625 LLength.LowPart = count;
7627 lock_ObtainWrite(&scp->rw);
7628 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7629 lock_ReleaseWrite(&scp->rw);
7632 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7637 /* special case: 0 bytes transferred means truncate to this position */
7641 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7645 truncAttr.mask = CM_ATTRMASK_LENGTH;
7646 truncAttr.length.LowPart = offset.LowPart;
7647 truncAttr.length.HighPart = 0;
7648 lock_ObtainMutex(&fidp->mx);
7649 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7650 fidp->flags |= SMB_FID_LENGTHSETDONE;
7651 lock_ReleaseMutex(&fidp->mx);
7652 smb_SetSMBParm(outp, 0, 0 /* count */);
7653 smb_SetSMBDataLength(outp, 0);
7658 * Work around bug in NT client
7660 * When copying a file, the NT client should first copy the data,
7661 * then copy the last write time. But sometimes the NT client does
7662 * these in the wrong order, so the data copies would inadvertently
7663 * cause the last write time to be overwritten. We try to detect this,
7664 * and don't set client mod time if we think that would go against the
7667 lock_ObtainMutex(&fidp->mx);
7668 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7669 lock_ObtainWrite(&fidp->scp->rw);
7670 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7671 fidp->scp->clientModTime = time(NULL);
7672 lock_ReleaseWrite(&fidp->scp->rw);
7674 lock_ReleaseMutex(&fidp->mx);
7677 while ( code == 0 && count > 0 ) {
7678 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7679 if (code == 0 && written == 0)
7680 code = CM_ERROR_PARTIALWRITE;
7682 offset = LargeIntegerAdd(offset,
7683 ConvertLongToLargeInteger(written));
7684 count -= (unsigned short)written;
7685 total_written += written;
7689 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7690 total_written, code);
7692 /* set the packet data length to 3 bytes for the data block header,
7693 * plus the size of the data.
7695 smb_SetSMBParm(outp, 0, total_written);
7696 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7697 smb_SetSMBParm(outp, 3, hint);
7698 smb_SetSMBDataLength(outp, 0);
7701 smb_ReleaseFID(fidp);
7702 cm_ReleaseUser(userp);
7703 cm_ReleaseSCache(scp);
7708 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7709 NCB *ncbp, raw_write_cont_t *rwcp)
7718 fd = smb_GetSMBParm(inp, 0);
7719 fidp = smb_FindFID(vcp, fd, 0);
7721 lock_ObtainMutex(&fidp->mx);
7723 lock_ReleaseMutex(&fidp->mx);
7724 smb_ReleaseFID(fidp);
7728 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7729 lock_ReleaseMutex(&fidp->mx);
7730 smb_CloseFID(vcp, fidp, NULL, 0);
7731 smb_ReleaseFID(fidp);
7734 lock_ReleaseMutex(&fidp->mx);
7736 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7737 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7739 userp = smb_GetUserFromVCP(vcp, inp);
7742 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7744 if (rwcp->writeMode & 0x1) { /* synchronous */
7747 smb_FormatResponsePacket(vcp, inp, outp);
7748 op = (smb_t *) outp;
7749 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7750 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7751 smb_SetSMBDataLength(outp, 0);
7752 smb_SendPacket(vcp, outp);
7753 smb_FreePacket(outp);
7755 else { /* asynchronous */
7756 lock_ObtainMutex(&fidp->mx);
7757 fidp->raw_writers--;
7758 if (fidp->raw_writers == 0)
7759 thrd_SetEvent(fidp->raw_write_event);
7760 lock_ReleaseMutex(&fidp->mx);
7763 /* Give back raw buffer */
7764 lock_ObtainMutex(&smb_RawBufLock);
7765 *((char **)rawBuf) = smb_RawBufs;
7766 smb_RawBufs = rawBuf;
7767 lock_ReleaseMutex(&smb_RawBufLock);
7769 smb_ReleaseFID(fidp);
7770 cm_ReleaseUser(userp);
7773 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7778 /* SMB_COM_WRITE_RAW */
7779 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7782 long count, written = 0, total_written = 0;
7786 smb_t *smbp = (smb_t*) inp;
7791 unsigned short writeMode;
7793 fd = smb_GetSMBParm(inp, 0);
7794 totalCount = smb_GetSMBParm(inp, 1);
7795 count = smb_GetSMBParm(inp, 10);
7796 writeMode = smb_GetSMBParm(inp, 7);
7798 op = (char *) inp->data;
7799 op += smb_GetSMBParm(inp, 11);
7801 offset.HighPart = 0;
7802 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7804 if (*inp->wctp == 14) {
7805 /* we received a 64-bit file offset */
7806 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7808 if (LargeIntegerLessThanZero(offset)) {
7810 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7811 offset.HighPart, offset.LowPart);
7812 return CM_ERROR_BADSMB;
7815 offset.HighPart = 0; /* 32-bit file offset */
7819 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7820 fd, offset.HighPart, offset.LowPart, count);
7822 " WriteRaw WriteMode 0x%x",
7825 fd = smb_ChainFID(fd, inp);
7826 fidp = smb_FindFID(vcp, fd, 0);
7828 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7830 return CM_ERROR_BADFD;
7832 lock_ObtainMutex(&fidp->mx);
7834 lock_ReleaseMutex(&fidp->mx);
7835 smb_ReleaseFID(fidp);
7836 return CM_ERROR_BADFD;
7839 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7840 lock_ReleaseMutex(&fidp->mx);
7841 smb_CloseFID(vcp, fidp, NULL, 0);
7842 smb_ReleaseFID(fidp);
7843 return CM_ERROR_NOSUCHFILE;
7848 lock_ReleaseMutex(&fidp->mx);
7853 LARGE_INTEGER LOffset;
7854 LARGE_INTEGER LLength;
7857 key = cm_GenerateKey(vcp->vcID, pid, fd);
7859 LOffset.HighPart = offset.HighPart;
7860 LOffset.LowPart = offset.LowPart;
7861 LLength.HighPart = 0;
7862 LLength.LowPart = count;
7864 lock_ObtainWrite(&scp->rw);
7865 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7866 lock_ReleaseWrite(&scp->rw);
7869 cm_ReleaseSCache(scp);
7870 smb_ReleaseFID(fidp);
7875 userp = smb_GetUserFromVCP(vcp, inp);
7878 * Work around bug in NT client
7880 * When copying a file, the NT client should first copy the data,
7881 * then copy the last write time. But sometimes the NT client does
7882 * these in the wrong order, so the data copies would inadvertently
7883 * cause the last write time to be overwritten. We try to detect this,
7884 * and don't set client mod time if we think that would go against the
7887 lock_ObtainMutex(&fidp->mx);
7888 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7889 lock_ObtainWrite(&fidp->scp->rw);
7890 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7891 fidp->scp->clientModTime = time(NULL);
7892 lock_ReleaseWrite(&fidp->scp->rw);
7894 lock_ReleaseMutex(&fidp->mx);
7897 while ( code == 0 && count > 0 ) {
7898 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7899 if (code == 0 && written == 0)
7900 code = CM_ERROR_PARTIALWRITE;
7902 offset = LargeIntegerAdd(offset,
7903 ConvertLongToLargeInteger(written));
7906 total_written += written;
7910 /* Get a raw buffer */
7913 lock_ObtainMutex(&smb_RawBufLock);
7915 /* Get a raw buf, from head of list */
7916 rawBuf = smb_RawBufs;
7917 smb_RawBufs = *(char **)smb_RawBufs;
7920 code = CM_ERROR_USESTD;
7922 lock_ReleaseMutex(&smb_RawBufLock);
7925 /* Don't allow a premature Close */
7926 if (code == 0 && (writeMode & 1) == 0) {
7927 lock_ObtainMutex(&fidp->mx);
7928 fidp->raw_writers++;
7929 thrd_ResetEvent(fidp->raw_write_event);
7930 lock_ReleaseMutex(&fidp->mx);
7933 smb_ReleaseFID(fidp);
7934 cm_ReleaseUser(userp);
7935 cm_ReleaseSCache(scp);
7938 smb_SetSMBParm(outp, 0, total_written);
7939 smb_SetSMBDataLength(outp, 0);
7940 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7945 offset = LargeIntegerAdd(offset,
7946 ConvertLongToLargeInteger(count));
7950 rwcp->offset.HighPart = offset.HighPart;
7951 rwcp->offset.LowPart = offset.LowPart;
7952 rwcp->count = totalCount - count;
7953 rwcp->writeMode = writeMode;
7954 rwcp->alreadyWritten = total_written;
7956 /* set the packet data length to 3 bytes for the data block header,
7957 * plus the size of the data.
7959 smb_SetSMBParm(outp, 0, 0xffff);
7960 smb_SetSMBDataLength(outp, 0);
7966 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7969 long count, finalCount;
7973 smb_t *smbp = (smb_t*) inp;
7979 fd = smb_GetSMBParm(inp, 0);
7980 count = smb_GetSMBParm(inp, 1);
7981 offset.HighPart = 0; /* too bad */
7982 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7984 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7985 fd, offset.LowPart, count);
7987 fd = smb_ChainFID(fd, inp);
7988 fidp = smb_FindFID(vcp, fd, 0);
7990 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7992 return CM_ERROR_BADFD;
7994 lock_ObtainMutex(&fidp->mx);
7995 if (fidp->flags & SMB_FID_IOCTL) {
7996 lock_ReleaseMutex(&fidp->mx);
7997 code = smb_IoctlRead(fidp, vcp, inp, outp);
7998 smb_ReleaseFID(fidp);
8002 if (fidp->flags & SMB_FID_RPC) {
8003 lock_ReleaseMutex(&fidp->mx);
8004 code = smb_RPCRead(fidp, vcp, inp, outp);
8005 smb_ReleaseFID(fidp);
8010 lock_ReleaseMutex(&fidp->mx);
8011 smb_ReleaseFID(fidp);
8012 return CM_ERROR_BADFD;
8015 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8016 lock_ReleaseMutex(&fidp->mx);
8017 smb_CloseFID(vcp, fidp, NULL, 0);
8018 smb_ReleaseFID(fidp);
8019 return CM_ERROR_NOSUCHFILE;
8024 lock_ReleaseMutex(&fidp->mx);
8027 LARGE_INTEGER LOffset, LLength;
8031 key = cm_GenerateKey(vcp->vcID, pid, fd);
8033 LOffset.HighPart = 0;
8034 LOffset.LowPart = offset.LowPart;
8035 LLength.HighPart = 0;
8036 LLength.LowPart = count;
8038 lock_ObtainWrite(&scp->rw);
8039 code = cm_LockCheckRead(scp, LOffset, LLength, key);
8040 lock_ReleaseWrite(&scp->rw);
8043 cm_ReleaseSCache(scp);
8044 smb_ReleaseFID(fidp);
8048 userp = smb_GetUserFromVCP(vcp, inp);
8050 /* remember this for final results */
8051 smb_SetSMBParm(outp, 0, count);
8052 smb_SetSMBParm(outp, 1, 0);
8053 smb_SetSMBParm(outp, 2, 0);
8054 smb_SetSMBParm(outp, 3, 0);
8055 smb_SetSMBParm(outp, 4, 0);
8057 /* set the packet data length to 3 bytes for the data block header,
8058 * plus the size of the data.
8060 smb_SetSMBDataLength(outp, count+3);
8062 /* get op ptr after putting in the parms, since otherwise we don't
8063 * know where the data really is.
8065 op = smb_GetSMBData(outp, NULL);
8067 /* now emit the data block header: 1 byte of type and 2 bytes of length */
8068 *op++ = 1; /* data block marker */
8069 *op++ = (unsigned char) (count & 0xff);
8070 *op++ = (unsigned char) ((count >> 8) & 0xff);
8072 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8074 /* fix some things up */
8075 smb_SetSMBParm(outp, 0, finalCount);
8076 smb_SetSMBDataLength(outp, finalCount+3);
8078 smb_ReleaseFID(fidp);
8080 cm_ReleaseUser(userp);
8081 cm_ReleaseSCache(scp);
8085 /* SMB_COM_CREATE_DIRECTORY */
8086 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8088 clientchar_t *pathp;
8093 cm_scache_t *dscp; /* dir we're dealing with */
8094 cm_scache_t *scp; /* file we're creating */
8096 int initialModeBits;
8097 clientchar_t *lastNamep;
8099 clientchar_t *tidPathp;
8106 /* compute initial mode bits based on read-only flag in attributes */
8107 initialModeBits = 0777;
8109 tp = smb_GetSMBData(inp, NULL);
8110 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8112 return CM_ERROR_BADSMB;
8114 spacep = inp->spacep;
8115 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8117 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8118 return CM_ERROR_EXISTS;
8120 userp = smb_GetUserFromVCP(vcp, inp);
8122 caseFold = CM_FLAG_CASEFOLD;
8124 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8126 cm_ReleaseUser(userp);
8127 return CM_ERROR_NOSUCHPATH;
8130 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
8131 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8132 userp, tidPathp, &req, &dscp);
8135 cm_ReleaseUser(userp);
8140 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8141 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8142 cm_ReleaseSCache(dscp);
8143 cm_ReleaseUser(userp);
8144 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8145 return CM_ERROR_PATH_NOT_COVERED;
8147 return CM_ERROR_NOSUCHPATH;
8149 #endif /* DFS_SUPPORT */
8151 /* otherwise, scp points to the parent directory. Do a lookup, and
8152 * fail if we find it. Otherwise, we do the create.
8158 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8159 if (scp) cm_ReleaseSCache(scp);
8160 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8161 if (code == 0) code = CM_ERROR_EXISTS;
8162 cm_ReleaseSCache(dscp);
8163 cm_ReleaseUser(userp);
8167 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8168 setAttr.clientModTime = time(NULL);
8169 smb_SetInitialModeBitsForDir(0, &setAttr);
8171 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8172 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8173 smb_NotifyChange(FILE_ACTION_ADDED,
8174 FILE_NOTIFY_CHANGE_DIR_NAME,
8175 dscp, lastNamep, NULL, TRUE);
8177 /* we don't need this any longer */
8178 cm_ReleaseSCache(dscp);
8181 /* something went wrong creating or truncating the file */
8182 cm_ReleaseUser(userp);
8186 /* otherwise we succeeded */
8187 smb_SetSMBDataLength(outp, 0);
8188 cm_ReleaseUser(userp);
8193 BOOL smb_IsLegalFilename(clientchar_t *filename)
8196 * Find the longest substring of filename that does not contain
8197 * any of the chars in illegalChars. If that substring is less
8198 * than the length of the whole string, then one or more of the
8199 * illegal chars is in filename.
8201 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8207 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8208 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8210 clientchar_t *pathp;
8216 cm_scache_t *dscp; /* dir we're dealing with */
8217 cm_scache_t *scp; /* file we're creating */
8221 clientchar_t *lastNamep;
8224 clientchar_t *tidPathp;
8226 int created = 0; /* the file was new */
8231 excl = (inp->inCom == 0x03)? 0 : 1;
8233 attributes = smb_GetSMBParm(inp, 0);
8234 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8236 tp = smb_GetSMBData(inp, NULL);
8237 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8239 return CM_ERROR_BADSMB;
8241 spacep = inp->spacep;
8242 /* smb_StripLastComponent will strip "::$DATA" if present */
8243 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8245 if (!cm_IsValidClientString(pathp)) {
8247 clientchar_t * hexp;
8249 hexp = cm_GetRawCharsAlloc(pathp, -1);
8250 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8251 osi_LogSaveClientString(smb_logp, hexp));
8255 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8257 return CM_ERROR_BADNTFILENAME;
8260 userp = smb_GetUserFromVCP(vcp, inp);
8262 caseFold = CM_FLAG_CASEFOLD;
8264 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8266 cm_ReleaseUser(userp);
8267 return CM_ERROR_NOSUCHPATH;
8269 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8270 userp, tidPathp, &req, &dscp);
8273 cm_ReleaseUser(userp);
8278 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8279 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8280 cm_ReleaseSCache(dscp);
8281 cm_ReleaseUser(userp);
8282 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8283 return CM_ERROR_PATH_NOT_COVERED;
8285 return CM_ERROR_NOSUCHPATH;
8287 #endif /* DFS_SUPPORT */
8289 /* otherwise, scp points to the parent directory. Do a lookup, and
8290 * truncate the file if we find it, otherwise we create the file.
8297 if (!smb_IsLegalFilename(lastNamep))
8298 return CM_ERROR_BADNTFILENAME;
8300 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8301 #ifdef DEBUG_VERBOSE
8304 hexp = osi_HexifyString( lastNamep );
8305 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8310 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8311 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8312 cm_ReleaseSCache(dscp);
8313 cm_ReleaseUser(userp);
8317 /* if we get here, if code is 0, the file exists and is represented by
8318 * scp. Otherwise, we have to create it.
8322 /* oops, file shouldn't be there */
8323 cm_ReleaseSCache(dscp);
8324 cm_ReleaseSCache(scp);
8325 cm_ReleaseUser(userp);
8326 return CM_ERROR_EXISTS;
8329 setAttr.mask = CM_ATTRMASK_LENGTH;
8330 setAttr.length.LowPart = 0;
8331 setAttr.length.HighPart = 0;
8332 code = cm_SetAttr(scp, &setAttr, userp, &req);
8335 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8336 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8337 smb_SetInitialModeBitsForFile(attributes, &setAttr);
8339 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8343 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8344 smb_NotifyChange(FILE_ACTION_ADDED,
8345 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8346 dscp, lastNamep, NULL, TRUE);
8347 } else if (!excl && code == CM_ERROR_EXISTS) {
8348 /* not an exclusive create, and someone else tried
8349 * creating it already, then we open it anyway. We
8350 * don't bother retrying after this, since if this next
8351 * fails, that means that the file was deleted after
8352 * we started this call.
8354 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8357 setAttr.mask = CM_ATTRMASK_LENGTH;
8358 setAttr.length.LowPart = 0;
8359 setAttr.length.HighPart = 0;
8360 code = cm_SetAttr(scp, &setAttr, userp, &req);
8365 /* we don't need this any longer */
8366 cm_ReleaseSCache(dscp);
8369 /* something went wrong creating or truncating the file */
8370 if (scp) cm_ReleaseSCache(scp);
8371 cm_ReleaseUser(userp);
8375 /* make sure we only open files */
8376 if (scp->fileType != CM_SCACHETYPE_FILE) {
8377 cm_ReleaseSCache(scp);
8378 cm_ReleaseUser(userp);
8379 return CM_ERROR_ISDIR;
8382 /* now all we have to do is open the file itself */
8383 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8384 osi_assertx(fidp, "null smb_fid_t");
8388 lock_ObtainMutex(&fidp->mx);
8389 /* always create it open for read/write */
8390 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8392 /* remember that the file was newly created */
8394 fidp->flags |= SMB_FID_CREATED;
8396 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8398 /* save a pointer to the vnode */
8400 lock_ObtainWrite(&scp->rw);
8401 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8402 lock_ReleaseWrite(&scp->rw);
8405 fidp->userp = userp;
8406 lock_ReleaseMutex(&fidp->mx);
8408 smb_SetSMBParm(outp, 0, fidp->fid);
8409 smb_SetSMBDataLength(outp, 0);
8411 cm_Open(scp, 0, userp);
8413 smb_ReleaseFID(fidp);
8414 cm_ReleaseUser(userp);
8415 /* leave scp held since we put it in fidp->scp */
8420 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8423 osi_hyper_t new_offset;
8434 fd = smb_GetSMBParm(inp, 0);
8435 whence = smb_GetSMBParm(inp, 1);
8436 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8438 /* try to find the file descriptor */
8439 fd = smb_ChainFID(fd, inp);
8440 fidp = smb_FindFID(vcp, fd, 0);
8442 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8444 return CM_ERROR_BADFD;
8446 lock_ObtainMutex(&fidp->mx);
8447 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8448 lock_ReleaseMutex(&fidp->mx);
8449 smb_ReleaseFID(fidp);
8450 return CM_ERROR_BADFD;
8453 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8454 lock_ReleaseMutex(&fidp->mx);
8455 smb_CloseFID(vcp, fidp, NULL, 0);
8456 smb_ReleaseFID(fidp);
8457 return CM_ERROR_NOSUCHFILE;
8460 lock_ReleaseMutex(&fidp->mx);
8462 userp = smb_GetUserFromVCP(vcp, inp);
8464 lock_ObtainMutex(&fidp->mx);
8467 lock_ReleaseMutex(&fidp->mx);
8468 lock_ObtainWrite(&scp->rw);
8469 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8470 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8472 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8474 /* offset from current offset */
8475 new_offset = LargeIntegerAdd(fidp->offset,
8476 ConvertLongToLargeInteger(offset));
8478 else if (whence == 2) {
8479 /* offset from current EOF */
8480 new_offset = LargeIntegerAdd(scp->length,
8481 ConvertLongToLargeInteger(offset));
8483 new_offset = ConvertLongToLargeInteger(offset);
8486 fidp->offset = new_offset;
8487 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8488 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8489 smb_SetSMBDataLength(outp, 0);
8491 lock_ReleaseWrite(&scp->rw);
8492 smb_ReleaseFID(fidp);
8493 cm_ReleaseSCache(scp);
8494 cm_ReleaseUser(userp);
8498 /* dispatch all of the requests received in a packet. Due to chaining, this may
8499 * be more than one request.
8501 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8502 NCB *ncbp, raw_write_cont_t *rwcp)
8506 unsigned long code = 0;
8507 unsigned char *outWctp;
8508 int nparms; /* # of bytes of parameters */
8510 int nbytes; /* bytes of data, excluding count */
8513 unsigned short errCode;
8514 unsigned long NTStatus;
8516 unsigned char errClass;
8517 unsigned int oldGen;
8518 DWORD oldTime, newTime;
8520 /* get easy pointer to the data */
8521 smbp = (smb_t *) inp->data;
8523 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8524 /* setup the basic parms for the initial request in the packet */
8525 inp->inCom = smbp->com;
8526 inp->wctp = &smbp->wct;
8528 inp->ncb_length = ncbp->ncb_length;
8533 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8534 /* log it and discard it */
8535 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8536 __FILE__, __LINE__, ncbp->ncb_length);
8537 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8541 /* We are an ongoing op */
8542 thrd_Increment(&ongoingOps);
8544 /* set up response packet for receiving output */
8545 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8546 smb_FormatResponsePacket(vcp, inp, outp);
8547 outWctp = outp->wctp;
8549 /* Remember session generation number and time */
8550 oldGen = sessionGen;
8551 oldTime = GetTickCount();
8553 while (inp->inCom != 0xff) {
8554 dp = &smb_dispatchTable[inp->inCom];
8556 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8557 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8558 code = outp->resumeCode;
8562 /* process each request in the packet; inCom, wctp and inCount
8563 * are already set up.
8565 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8568 /* now do the dispatch */
8569 /* start by formatting the response record a little, as a default */
8570 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8572 outWctp[1] = 0xff; /* no operation */
8573 outWctp[2] = 0; /* padding */
8578 /* not a chained request, this is a more reasonable default */
8579 outWctp[0] = 0; /* wct of zero */
8580 outWctp[1] = 0; /* and bcc (word) of zero */
8584 /* once set, stays set. Doesn't matter, since we never chain
8585 * "no response" calls.
8587 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8591 /* we have a recognized operation */
8592 char * opName = myCrt_Dispatch(inp->inCom);
8595 smbp = (smb_t *) inp;
8597 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8598 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8599 if (inp->inCom == 0x1d) {
8601 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8603 code = (*(dp->procp)) (vcp, inp, outp);
8605 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8606 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8608 newTime = GetTickCount();
8609 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8610 opName, smbp->mid, newTime - oldTime);
8613 if ( code == CM_ERROR_BADSMB ||
8614 code == CM_ERROR_BADOP )
8616 #endif /* LOG_PACKET */
8618 /* ReceiveV3Tran2A handles its own logging */
8619 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8622 clientchar_t *treepath = NULL; /* do not free */
8623 clientchar_t *pathname = NULL;
8624 cm_fid_t afid = {0,0,0,0,0};
8626 uidp = smb_FindUID(vcp, smbp->uid, 0);
8627 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8628 fidp = smb_FindFID(vcp, inp->fid, 0);
8631 lock_ObtainMutex(&fidp->mx);
8632 if (fidp->NTopen_pathp)
8633 pathname = fidp->NTopen_pathp;
8635 afid = fidp->scp->fid;
8637 if (inp->stringsp->wdata)
8638 pathname = inp->stringsp->wdata;
8641 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)",
8642 opName, newTime - oldTime,
8643 smbp->uid, uidp ? uidp->unp->name : NULL,
8644 smbp->pid, smbp->mid, smbp->tid,
8647 afid.cell, afid.volume, afid.vnode, afid.unique);
8650 lock_ReleaseMutex(&fidp->mx);
8653 smb_ReleaseUID(uidp);
8655 smb_ReleaseFID(fidp);
8658 if (oldGen != sessionGen) {
8659 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8660 newTime - oldTime, ncbp->ncb_length);
8661 osi_Log3(smb_logp, "Request %s straddled session startup, "
8662 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8665 FreeSMBStrings(inp);
8667 /* bad opcode, fail the request, after displaying it */
8668 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8671 #endif /* LOG_PACKET */
8674 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8675 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8676 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8677 if (code == IDCANCEL)
8680 code = CM_ERROR_BADOP;
8683 /* catastrophic failure: log as much as possible */
8684 if (code == CM_ERROR_BADSMB) {
8685 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8689 #endif /* LOG_PACKET */
8690 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8693 code = CM_ERROR_INVAL;
8696 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8697 thrd_Decrement(&ongoingOps);
8702 /* now, if we failed, turn the current response into an empty
8703 * one, and fill in the response packet's error code.
8706 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8707 smb_MapNTError(code, &NTStatus, FALSE);
8708 outWctp = outp->wctp;
8709 smbp = (smb_t *) &outp->data;
8710 if (code != CM_ERROR_PARTIALWRITE
8711 && code != CM_ERROR_BUFFERTOOSMALL
8712 && code != CM_ERROR_GSSCONTINUE) {
8713 /* nuke wct and bcc. For a partial
8714 * write or an in-process authentication handshake,
8715 * assume they're OK.
8721 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8722 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8723 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8724 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8725 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8729 smb_MapCoreError(code, vcp, &errCode, &errClass);
8730 outWctp = outp->wctp;
8731 smbp = (smb_t *) &outp->data;
8732 if (code != CM_ERROR_PARTIALWRITE) {
8733 /* nuke wct and bcc. For a partial
8734 * write, assume they're OK.
8740 smbp->errLow = (unsigned char) (errCode & 0xff);
8741 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8742 smbp->rcls = errClass;
8745 } /* error occurred */
8747 /* if we're here, we've finished one request. Look to see if
8748 * this is a chained opcode. If it is, setup things to process
8749 * the chained request, and setup the output buffer to hold the
8750 * chained response. Start by finding the next input record.
8752 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8753 break; /* not a chained req */
8754 tp = inp->wctp; /* points to start of last request */
8755 /* in a chained request, the first two
8756 * parm fields are required, and are
8757 * AndXCommand/AndXReserved and
8759 if (tp[0] < 2) break;
8760 if (tp[1] == 0xff) break; /* no more chained opcodes */
8762 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8765 /* and now append the next output request to the end of this
8766 * last request. Begin by finding out where the last response
8767 * ends, since that's where we'll put our new response.
8769 outWctp = outp->wctp; /* ptr to out parameters */
8770 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8771 nparms = outWctp[0] << 1;
8772 tp = outWctp + nparms + 1; /* now points to bcc field */
8773 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8774 tp += 2 /* for the count itself */ + nbytes;
8775 /* tp now points to the new output record; go back and patch the
8776 * second parameter (off2) to point to the new record.
8778 temp = (unsigned int)(tp - outp->data);
8779 outWctp[3] = (unsigned char) (temp & 0xff);
8780 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8781 outWctp[2] = 0; /* padding */
8782 outWctp[1] = inp->inCom; /* next opcode */
8784 /* finally, setup for the next iteration */
8787 } /* while loop over all requests in the packet */
8789 /* now send the output packet, and return */
8791 smb_SendPacket(vcp, outp);
8792 thrd_Decrement(&ongoingOps);
8797 /* Wait for Netbios() calls to return, and make the results available to server
8798 * threads. Note that server threads can't wait on the NCBevents array
8799 * themselves, because NCB events are manual-reset, and the servers would race
8800 * each other to reset them.
8802 void smb_ClientWaiter(void *parmp)
8807 while (smbShutdownFlag == 0) {
8808 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8810 if (code == WAIT_OBJECT_0)
8813 /* error checking */
8814 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8816 int abandonIdx = code - WAIT_ABANDONED_0;
8817 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8820 if (code == WAIT_IO_COMPLETION)
8822 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8826 if (code == WAIT_TIMEOUT)
8828 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8831 if (code == WAIT_FAILED)
8833 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8836 idx = code - WAIT_OBJECT_0;
8838 /* check idx range! */
8839 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8841 /* this is fatal - log as much as possible */
8842 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8843 osi_assertx(0, "invalid index");
8846 thrd_ResetEvent(NCBevents[idx]);
8847 thrd_SetEvent(NCBreturns[0][idx]);
8852 * Try to have one NCBRECV request waiting for every live session. Not more
8853 * than one, because if there is more than one, it's hard to handle Write Raw.
8855 void smb_ServerWaiter(void *parmp)
8858 int idx_session, idx_NCB;
8861 while (smbShutdownFlag == 0) {
8863 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8865 if (code == WAIT_OBJECT_0)
8868 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8870 int abandonIdx = code - WAIT_ABANDONED_0;
8871 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8874 if (code == WAIT_IO_COMPLETION)
8876 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8880 if (code == WAIT_TIMEOUT)
8882 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8885 if (code == WAIT_FAILED)
8887 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8890 idx_session = code - WAIT_OBJECT_0;
8892 /* check idx range! */
8893 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8895 /* this is fatal - log as much as possible */
8896 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8897 osi_assertx(0, "invalid index");
8902 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8904 if (code == WAIT_OBJECT_0) {
8905 if (smbShutdownFlag == 1)
8911 /* error checking */
8912 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8914 int abandonIdx = code - WAIT_ABANDONED_0;
8915 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8918 if (code == WAIT_IO_COMPLETION)
8920 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8924 if (code == WAIT_TIMEOUT)
8926 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8929 if (code == WAIT_FAILED)
8931 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8934 idx_NCB = code - WAIT_OBJECT_0;
8936 /* check idx range! */
8937 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8939 /* this is fatal - log as much as possible */
8940 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8941 osi_assertx(0, "invalid index");
8944 /* Link them together */
8945 NCBsessions[idx_NCB] = idx_session;
8948 ncbp = NCBs[idx_NCB];
8949 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8950 ncbp->ncb_command = NCBRECV | ASYNCH;
8951 ncbp->ncb_lana_num = lanas[idx_session];
8952 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8953 ncbp->ncb_event = NCBevents[idx_NCB];
8954 ncbp->ncb_length = SMB_PACKETSIZE;
8959 typedef struct _monitored_task {
8962 LARGE_INTEGER start_time;
8964 BOOL trace_timer_hit;
8965 BOOL dump_timer_hit;
8968 typedef struct osi_queueHT {
8969 osi_queue_t * headp;
8970 osi_queue_t * tailp;
8973 static osi_queue_t *smb_monitored_tasks = NULL;
8974 static osi_queue_t *smb_free_monitored_tasks = NULL;
8976 static osi_mutex_t _monitor_mx;
8978 static HANDLE h_monitored_task_queue = NULL;
8979 static HANDLE h_monitored_task_shutdown = NULL;
8981 static time_t smb_last_dump_time = 0;
8983 DWORD smb_monitorReqs = 0;
8985 /* FILETIME comparison fuzz */
8986 #define MONITOR_FUZZ_TIMEOUT (1 * 10000000i64)
8988 /* Trace timeout is at 60 seconds */
8989 #define MONITOR_TRACE_TIMEOUT (60 * 10000000i64)
8991 /* Dump timeout is at 120 seconds */
8992 #define MONITOR_DUMP_TIMEOUT (120 * 10000000i64)
8994 /* Time before another dump is performed in seconds*/
8995 #define MONITOR_DUMP_RESET_TIMEOUT (600)
8997 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
9000 LARGE_INTEGER earliest;
9003 GetSystemTimeAsFileTime(&now);
9004 earliest.LowPart = now.dwLowDateTime;
9005 earliest.HighPart = now.dwHighDateTime;
9006 earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
9008 while ((t = (monitored_task *) taskmq->headp) != NULL &&
9010 (t->start_time.QuadPart < earliest.QuadPart ||
9012 t->dump_timer_hit)) {
9014 osi_QRemoveHT(&taskmq->headp,
9018 lock_ObtainMutex(&_monitor_mx);
9019 osi_QAdd(&smb_free_monitored_tasks, &t->q);
9020 lock_ReleaseMutex(&_monitor_mx);
9023 #ifdef INVARIANT_CHECK
9029 for (t = (monitored_task *) taskmq->headp;
9031 t = (monitored_task *) osi_QNext(&t->q)) {
9032 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9033 last.QuadPart = t->start_time.QuadPart;
9039 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
9041 monitored_task * task;
9042 monitored_task * tasks;
9044 lock_ObtainMutex(&_monitor_mx);
9045 tasks = (monitored_task *) smb_monitored_tasks;
9046 smb_monitored_tasks = NULL;
9047 lock_ReleaseMutex(&_monitor_mx);
9052 osi_QRemove((osi_queue_t **) &tasks, &task->q);
9054 if (task->started) {
9060 q.prevp = taskmq->tailp;
9062 /* Insertion sort by start_time. Earliest request is
9063 first. Since we are likely to receive new requests
9064 later, we start inserting from the back. */
9067 ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
9071 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
9072 else if (p->prevp == NULL)
9073 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
9075 osi_queue_t *o = p->prevp;
9077 osi_assert(o->nextp == p);
9081 p->prevp = &task->q;
9082 o->nextp = &task->q;
9086 /* Some task ending */
9090 for (p = taskmq->headp;
9094 monitored_task * mt = (monitored_task *) p;
9096 if (mt->task_id == task->task_id) {
9098 osi_QRemoveHT(&taskmq->headp,
9101 lock_ObtainMutex(&_monitor_mx);
9102 osi_QAdd(&smb_free_monitored_tasks, p);
9103 lock_ReleaseMutex(&_monitor_mx);
9109 lock_ObtainMutex(&_monitor_mx);
9110 osi_QAdd(&smb_free_monitored_tasks, &task->q);
9111 lock_ReleaseMutex(&_monitor_mx);
9115 #ifdef INVARIANT_CHECK
9122 for (t = (monitored_task *) taskmq->headp;
9124 t = (monitored_task *) osi_QNext(&t->q)) {
9125 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9126 last.QuadPart = t->start_time.QuadPart;
9132 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9134 if (!task->trace_timer_hit) {
9136 task->trace_timer_hit = TRUE;
9138 osi_LogEnable(afsd_logp);
9139 rx_DebugOnOff(TRUE);
9141 } else if (!task->dump_timer_hit) {
9146 if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9147 task->dump_timer_hit = TRUE;
9148 smb_last_dump_time = now;
9150 GenerateMiniDump(NULL);
9156 * Server request monitoring
9158 * The server monitor runs in a separate thread and monitors server
9159 * requests for potential timeouts. It examines notifcations queued
9160 * by smb_NotifyRequestEvent() and waits for potential timeout events:
9162 * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9163 * enables trace logging.
9165 * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9166 * out a dump file that will hopefully contain enough evidence to
9167 * figure out why the timeout event occurred.
9170 void smb_ServerMonitor(VOID * parmp)
9172 osi_queueHT_t in_progress = { NULL, NULL };
9173 HANDLE h_timer = NULL;
9177 h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9178 h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9179 h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9181 lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9183 h_all[0] = h_monitored_task_queue;
9185 h_all[2] = h_monitored_task_shutdown;
9190 rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9192 if (rv == WAIT_OBJECT_0) {
9194 smb_SlurpNewTaskMonitors(&in_progress);
9196 } else if (rv == WAIT_OBJECT_0 + 1) {
9198 smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9206 /* refresh timers */
9210 smb_PurgeOldTaskMonitors(&in_progress);
9211 t = (monitored_task *) in_progress.headp;
9213 if (t && !t->trace_timer_hit) {
9216 due = t->start_time;
9217 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9219 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9220 } else if (t && !t->dump_timer_hit) {
9224 due = t->start_time;
9225 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9227 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9229 CancelWaitableTimer(h_timer);
9231 /* CancelWaitableTimer() doesn't reset the timer if it
9232 was already signalled. */
9233 WaitForSingleObject(h_timer, 0);
9241 h = h_monitored_task_queue;
9242 h_monitored_task_queue = NULL;
9245 h = h_monitored_task_shutdown;
9246 h_monitored_task_shutdown = NULL;
9249 CloseHandle(h_timer);
9251 lock_FinalizeMutex(&_monitor_mx);
9255 monitored_task * task;
9257 while (in_progress.headp) {
9258 task = (monitored_task *) in_progress.headp;
9259 osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9263 for (task = (monitored_task *) smb_free_monitored_tasks;
9264 task; task = (monitored_task *) smb_free_monitored_tasks) {
9265 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9269 for (task = (monitored_task *) smb_monitored_tasks;
9270 task; task = (monitored_task *) smb_monitored_tasks) {
9271 osi_QRemove(&smb_monitored_tasks, &task->q);
9277 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9279 monitored_task * task;
9281 lock_ObtainMutex(&_monitor_mx);
9282 task = (monitored_task *) smb_free_monitored_tasks;
9284 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9285 lock_ReleaseMutex(&_monitor_mx);
9288 task = malloc(sizeof(monitored_task));
9289 memset(task, 0, sizeof(*task));
9291 task->task_id = task_id;
9292 task->started = started;
9297 GetSystemTimeAsFileTime(&now);
9298 task->start_time.HighPart = now.dwHighDateTime;
9299 task->start_time.LowPart = now.dwLowDateTime;
9302 lock_ObtainMutex(&_monitor_mx);
9303 osi_QAdd(&smb_monitored_tasks, &task->q);
9304 lock_ReleaseMutex(&_monitor_mx);
9306 SetEvent(h_monitored_task_queue);
9309 void smb_ShutdownMonitor()
9311 SetEvent(h_monitored_task_shutdown);
9315 * The top level loop for handling SMB request messages. Each server thread
9316 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9317 * NCB and buffer for the incoming request are loaned to us.
9319 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
9320 * to immediately send a request for the rest of the data. This must come
9321 * before any other traffic for that session, so we delay setting the session
9322 * event until that data has come in.
9324 void smb_Server(VOID *parmp)
9326 INT_PTR myIdx = (INT_PTR) parmp;
9330 smb_packet_t *outbufp;
9332 int idx_NCB, idx_session;
9334 smb_vc_t *vcp = NULL;
9337 rx_StartClientThread();
9339 outncbp = smb_GetNCB();
9340 outbufp = smb_GetPacket();
9341 outbufp->ncbp = outncbp;
9349 cm_ResetServerPriority();
9351 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9354 /* terminate silently if shutdown flag is set */
9355 if (code == WAIT_OBJECT_0) {
9356 if (smbShutdownFlag == 1) {
9357 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9363 /* error checking */
9364 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9366 int abandonIdx = code - WAIT_ABANDONED_0;
9367 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9370 if (code == WAIT_IO_COMPLETION)
9372 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9376 if (code == WAIT_TIMEOUT)
9378 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9381 if (code == WAIT_FAILED)
9383 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9386 idx_NCB = code - WAIT_OBJECT_0;
9388 /* check idx range! */
9389 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9391 /* this is fatal - log as much as possible */
9392 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9393 osi_assertx(0, "invalid index");
9396 ncbp = NCBs[idx_NCB];
9397 idx_session = NCBsessions[idx_NCB];
9398 rc = ncbp->ncb_retcode;
9400 if (rc != NRC_PENDING && rc != NRC_GOODRET)
9401 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9405 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9409 /* Can this happen? Or is it just my UNIX paranoia? */
9410 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9415 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9418 /* Client closed session */
9419 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9421 lock_ObtainMutex(&vcp->mx);
9422 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9423 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9425 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9426 lock_ReleaseMutex(&vcp->mx);
9427 lock_ObtainWrite(&smb_globalLock);
9428 dead_sessions[vcp->session] = TRUE;
9429 lock_ReleaseWrite(&smb_globalLock);
9431 lock_ReleaseMutex(&vcp->mx);
9433 smb_CleanupDeadVC(vcp);
9440 /* Treat as transient error */
9441 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9444 "dispatch smb recv failed, message incomplete, ncb_length %d",
9447 "SMB message incomplete, "
9448 "length %d", ncbp->ncb_length);
9451 * We used to discard the packet.
9452 * Instead, try handling it normally.
9456 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9460 /* A weird error code. Log it, sleep, and continue. */
9461 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9463 lock_ObtainMutex(&vcp->mx);
9464 if (vcp->errorCount++ > 3) {
9465 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9466 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9467 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9469 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9470 lock_ReleaseMutex(&vcp->mx);
9471 lock_ObtainWrite(&smb_globalLock);
9472 dead_sessions[vcp->session] = TRUE;
9473 lock_ReleaseWrite(&smb_globalLock);
9475 lock_ReleaseMutex(&vcp->mx);
9477 smb_CleanupDeadVC(vcp);
9483 lock_ReleaseMutex(&vcp->mx);
9487 thrd_SetEvent(SessionEvents[idx_session]);
9493 /* Success, so now dispatch on all the data in the packet */
9495 smb_concurrentCalls++;
9496 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9497 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9500 * If at this point vcp is NULL (implies that packet was invalid)
9501 * then we are in big trouble. This means either :
9502 * a) we have the wrong NCB.
9503 * b) Netbios screwed up the call.
9504 * c) The VC was already marked dead before we were able to
9506 * Obviously this implies that
9507 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9508 * lanas[idx_session] != ncbp->ncb_lana_num )
9509 * Either way, we can't do anything with this packet.
9510 * Log, sleep and resume.
9513 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9517 ncbp->ncb_lana_num);
9519 /* Also log in the trace log. */
9520 osi_Log4(smb_logp, "Server: VCP does not exist!"
9521 "LSNs[idx_session]=[%d],"
9522 "lanas[idx_session]=[%d],"
9523 "ncbp->ncb_lsn=[%d],"
9524 "ncbp->ncb_lana_num=[%d]",
9528 ncbp->ncb_lana_num);
9530 /* thrd_Sleep(1000); Don't bother sleeping */
9531 thrd_SetEvent(SessionEvents[idx_session]);
9532 smb_concurrentCalls--;
9536 cm_SetRequestStartTime();
9537 if (smb_monitorReqs) {
9538 smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9541 vcp->errorCount = 0;
9542 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9543 smbp = (smb_t *)bufp->data;
9550 if (smbp->com == 0x1d) {
9551 /* Special handling for Write Raw */
9552 raw_write_cont_t rwc;
9554 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9555 if (rwc.code == 0) {
9556 EVENT_HANDLE rwevent;
9557 char eventName[MAX_PATH];
9559 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9560 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9561 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9562 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9564 ncbp->ncb_command = NCBRECV | ASYNCH;
9565 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9566 ncbp->ncb_lana_num = vcp->lana;
9567 ncbp->ncb_buffer = rwc.buf;
9568 ncbp->ncb_length = 65535;
9569 ncbp->ncb_event = rwevent;
9571 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9572 thrd_CloseHandle(rwevent);
9574 thrd_SetEvent(SessionEvents[idx_session]);
9576 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9578 else if (smbp->com == 0xa0) {
9580 * Serialize the handling for NT Transact
9583 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9584 thrd_SetEvent(SessionEvents[idx_session]);
9586 thrd_SetEvent(SessionEvents[idx_session]);
9587 /* TODO: what else needs to be serialized? */
9588 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9592 __except( smb_ServerExceptionFilter() ) {
9596 if (smb_monitorReqs) {
9597 smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9599 smb_concurrentCalls--;
9602 thrd_SetEvent(NCBavails[idx_NCB]);
9607 smb_FreePacket(outbufp);
9609 smb_FreeNCB(outncbp);
9613 * Exception filter for the server threads. If an exception occurs in the
9614 * dispatch routines, which is where exceptions are most common, then do a
9615 * force trace and give control to upstream exception handlers. Useful for
9618 DWORD smb_ServerExceptionFilter(void) {
9619 /* While this is not the best time to do a trace, if it succeeds, then
9620 * we have a trace (assuming tracing was enabled). Otherwise, this should
9621 * throw a second exception.
9623 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9624 afsd_ForceTrace(TRUE);
9625 buf_ForceTrace(TRUE);
9626 return EXCEPTION_CONTINUE_SEARCH;
9630 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9631 * If the number of server threads is M, and the number of live sessions is
9632 * N, then the number of NCB's in use at any time either waiting for, or
9633 * holding, received messages is M + N, so that is how many NCB's get created.
9635 void InitNCBslot(int idx)
9637 struct smb_packet *bufp;
9638 EVENT_HANDLE retHandle;
9640 char eventName[MAX_PATH];
9642 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9644 NCBs[idx] = smb_GetNCB();
9645 sprintf(eventName,"NCBavails[%d]", idx);
9646 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9647 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9648 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9649 sprintf(eventName,"NCBevents[%d]", idx);
9650 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9651 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9652 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9653 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9654 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9655 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9656 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9657 for (i=0; i<smb_NumServerThreads; i++)
9658 NCBreturns[i][idx] = retHandle;
9659 bufp = smb_GetPacket();
9660 bufp->spacep = cm_GetSpace();
9664 /* listen for new connections */
9665 void smb_Listener(void *parmp)
9671 afs_uint32 session, thread;
9672 smb_vc_t *vcp = NULL;
9674 char rname[NCBNAMSZ+1];
9675 char cname[MAX_COMPUTERNAME_LENGTH+1];
9676 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9677 INT_PTR lana = (INT_PTR) parmp;
9678 char eventName[MAX_PATH];
9679 int bridgeCount = 0;
9680 int nowildCount = 0;
9682 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9683 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9684 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9685 thrd_ResetEvent(ListenerShutdown[lana]);
9687 ncbp = smb_GetNCB();
9689 /* retrieve computer name */
9690 GetComputerName(cname, &cnamelen);
9693 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9694 memset(ncbp, 0, sizeof(NCB));
9697 ncbp->ncb_command = NCBLISTEN;
9698 ncbp->ncb_rto = 0; /* No receive timeout */
9699 ncbp->ncb_sto = 0; /* No send timeout */
9701 /* pad out with spaces instead of null termination */
9702 len = (long)strlen(smb_localNamep);
9703 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9704 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9706 strcpy(ncbp->ncb_callname, "*");
9707 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9709 ncbp->ncb_lana_num = (UCHAR)lana;
9711 code = Netbios(ncbp);
9713 if (code == NRC_NAMERR) {
9714 /* An smb shutdown or Vista resume must have taken place */
9716 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9717 ncbp->ncb_lana_num);
9718 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9720 if (lock_TryMutex(&smb_StartedLock)) {
9721 lana_list.lana[i] = LANA_INVALID;
9722 lock_ReleaseMutex(&smb_StartedLock);
9725 } else if (code == NRC_BRIDGE || code != 0) {
9726 int lanaRemaining = 0;
9728 if (code == NRC_BRIDGE) {
9729 if (++bridgeCount <= 5) {
9730 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9733 } else if (code == NRC_NOWILD) {
9734 if (++nowildCount <= 5) {
9735 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9737 if (bridgeCount > 0) {
9738 memset(ncbp, 0, sizeof(*ncbp));
9739 ncbp->ncb_command = NCBADDNAME;
9740 ncbp->ncb_lana_num = (UCHAR)lana;
9741 /* pad out with spaces instead of null termination */
9742 len = (long)strlen(smb_localNamep);
9743 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9744 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9745 code = Netbios(ncbp);
9751 while (!lock_TryMutex(&smb_StartedLock)) {
9752 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9758 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9759 ncbp->ncb_lana_num, ncb_error_string(code));
9760 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9761 ncbp->ncb_lana_num, ncb_error_string(code));
9763 for (i = 0; i < lana_list.length; i++) {
9764 if (lana_list.lana[i] == lana) {
9765 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9766 lana_list.lana[i] = LANA_INVALID;
9768 if (lana_list.lana[i] != LANA_INVALID)
9772 if (lanaRemaining == 0) {
9773 cm_VolStatus_Network_Stopped(cm_NetbiosName
9778 smb_ListenerState = SMB_LISTENER_STOPPED;
9779 smb_LANadapter = LANA_INVALID;
9780 lana_list.length = 0;
9782 lock_ReleaseMutex(&smb_StartedLock);
9786 else if (code != 0) {
9787 char tbuffer[AFSPATHMAX];
9789 /* terminate silently if shutdown flag is set */
9790 while (!lock_TryMutex(&smb_StartedLock)) {
9791 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9797 "NCBLISTEN lana=%d failed with code %d [%s]",
9798 ncbp->ncb_lana_num, code, ncb_error_string(code));
9800 "Client exiting due to network failure. Please restart client.\n");
9803 "Client exiting due to network failure. Please restart client.\n"
9804 "NCBLISTEN lana=%d failed with code %d [%s]",
9805 ncbp->ncb_lana_num, code, ncb_error_string(code));
9807 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9808 MB_OK|MB_SERVICE_NOTIFICATION);
9809 osi_panic(tbuffer, __FILE__, __LINE__);
9811 lock_ReleaseMutex(&smb_StartedLock);
9816 /* a successful packet received. clear bridge error count */
9820 /* check for remote conns */
9821 /* first get remote name and insert null terminator */
9822 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9823 for (i=NCBNAMSZ; i>0; i--) {
9824 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9830 /* compare with local name */
9832 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9833 flags |= SMB_VCFLAG_REMOTECONN;
9836 lock_ObtainMutex(&smb_ListenerLock);
9838 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9839 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9841 /* now ncbp->ncb_lsn is the connection ID */
9842 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9843 if (vcp->session == 0) {
9844 /* New generation */
9845 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9848 /* Log session startup */
9850 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9851 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9852 #endif /* NOTSERVICE */
9853 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9854 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9856 if (reportSessionStartups) {
9857 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9860 lock_ObtainMutex(&vcp->mx);
9861 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9862 vcp->flags |= flags;
9863 lock_ReleaseMutex(&vcp->mx);
9865 /* Allocate slot in session arrays */
9866 /* Re-use dead session if possible, otherwise add one more */
9867 /* But don't look at session[0], it is reserved */
9868 lock_ObtainWrite(&smb_globalLock);
9869 for (session = 1; session < numSessions; session++) {
9870 if (dead_sessions[session]) {
9871 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9872 dead_sessions[session] = FALSE;
9876 lock_ReleaseWrite(&smb_globalLock);
9878 /* We are re-using an existing VC because the lsn and lana
9880 session = vcp->session;
9882 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9884 /* Log session startup */
9886 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9887 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9888 #endif /* NOTSERVICE */
9889 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9890 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9892 if (reportSessionStartups) {
9893 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9897 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9898 unsigned long code = CM_ERROR_ALLBUSY;
9899 smb_packet_t * outp = smb_GetPacket();
9900 unsigned char *outWctp;
9903 smb_FormatResponsePacket(vcp, NULL, outp);
9906 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9907 unsigned long NTStatus;
9908 smb_MapNTError(code, &NTStatus, FALSE);
9909 outWctp = outp->wctp;
9910 smbp = (smb_t *) &outp->data;
9914 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9915 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9916 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9917 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9918 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9920 unsigned short errCode;
9921 unsigned char errClass;
9922 smb_MapCoreError(code, vcp, &errCode, &errClass);
9923 outWctp = outp->wctp;
9924 smbp = (smb_t *) &outp->data;
9928 smbp->errLow = (unsigned char) (errCode & 0xff);
9929 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9930 smbp->rcls = errClass;
9933 smb_SendPacket(vcp, outp);
9934 smb_FreePacket(outp);
9936 lock_ObtainMutex(&vcp->mx);
9937 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9938 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9940 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9941 lock_ReleaseMutex(&vcp->mx);
9942 lock_ObtainWrite(&smb_globalLock);
9943 dead_sessions[vcp->session] = TRUE;
9944 lock_ReleaseWrite(&smb_globalLock);
9945 smb_CleanupDeadVC(vcp);
9947 lock_ReleaseMutex(&vcp->mx);
9950 /* assert that we do not exceed the maximum number of sessions or NCBs.
9951 * we should probably want to wait for a session to be freed in case
9954 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9955 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9957 lock_ObtainMutex(&vcp->mx);
9958 vcp->session = session;
9959 lock_ReleaseMutex(&vcp->mx);
9960 lock_ObtainWrite(&smb_globalLock);
9961 LSNs[session] = ncbp->ncb_lsn;
9962 lanas[session] = ncbp->ncb_lana_num;
9963 lock_ReleaseWrite(&smb_globalLock);
9965 if (session == numSessions) {
9966 /* Add new NCB for new session */
9967 char eventName[MAX_PATH];
9969 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9971 InitNCBslot(numNCBs);
9972 lock_ObtainWrite(&smb_globalLock);
9974 lock_ReleaseWrite(&smb_globalLock);
9975 thrd_SetEvent(NCBavails[0]);
9976 thrd_SetEvent(NCBevents[0]);
9977 for (thread = 0; thread < smb_NumServerThreads; thread++)
9978 thrd_SetEvent(NCBreturns[thread][0]);
9979 /* Also add new session event */
9980 sprintf(eventName, "SessionEvents[%d]", session);
9981 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9982 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9983 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9984 lock_ObtainWrite(&smb_globalLock);
9986 lock_ReleaseWrite(&smb_globalLock);
9987 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9988 thrd_SetEvent(SessionEvents[0]);
9990 thrd_SetEvent(SessionEvents[session]);
9996 lock_ReleaseMutex(&smb_ListenerLock);
9997 } /* dispatch while loop */
10001 thrd_SetEvent(ListenerShutdown[lana]);
10006 smb_configureBackConnectionHostNames(int bEnable)
10008 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
10009 * there is a restriction on the use of SMB authentication on loopback connections.
10010 * There are two work arounds available:
10012 * (1) We can disable the check for matching host names. This does not
10013 * require a reboot:
10014 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
10015 * "DisableLoopbackCheck"=dword:00000001
10017 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
10018 * does require a reboot:
10019 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
10020 * "BackConnectionHostNames"=multi-sz
10022 * The algorithm will be:
10023 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
10024 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
10025 * (2b1) and check to see if DisableLoopbackCheck is set.
10026 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
10027 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
10028 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
10029 * check for the UnsetDisableLoopbackCheck value.
10030 * If set, set the DisableLoopbackCheck flag to 0x0
10031 * and delete the UnsetDisableLoopbackCheck value
10033 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
10034 * force Windows to use the loopback authentication mechanism for the specified
10037 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
10038 * service session that set it.
10044 DWORD dwSize, dwAllocSize;
10046 PBYTE pHostNames = NULL, pName = NULL;
10047 PBYTE pOrigNames = NULL, pOrig = NULL;
10048 BOOL bNameFound = FALSE;
10049 DWORD dwLoopbackCheckDisabled;
10050 DWORD dwszBackConnectionHostNames;
10051 size_t nbsize = strlen(cm_NetbiosName) + 2;
10053 static BOOL bLoopbackCheckDisabled = FALSE;
10055 /* DisableLoopbackCheck */
10056 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10057 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10059 KEY_READ|KEY_WRITE,
10060 &hkLsa) == ERROR_SUCCESS )
10062 dwSize = sizeof(DWORD);
10063 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwLoopbackCheckDisabled, &dwSize) != ERROR_SUCCESS)
10065 dwLoopbackCheckDisabled = 0;
10068 hkLsa = INVALID_HANDLE_VALUE;
10071 /* BackConnectionHostNames */
10072 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10073 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
10075 KEY_READ|KEY_WRITE,
10076 &hkMSV10) == ERROR_SUCCESS )
10078 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
10079 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10080 (dwType == REG_MULTI_SZ))
10082 dwAllocSize += 1 /* in case the source string is not nul terminated */
10083 + (DWORD)strlen(cm_NetbiosName) + 2;
10084 pHostNames = malloc(dwAllocSize);
10085 dwszBackConnectionHostNames = dwAllocSize;
10086 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
10087 pHostNames, &dwszBackConnectionHostNames) == ERROR_SUCCESS)
10089 for (pName = pHostNames;
10090 (pName - pHostNames < (int) dwszBackConnectionHostNames) && *pName ;
10091 pName += strlen(pName) + 1)
10093 if ( !stricmp(pName, cm_NetbiosName) ) {
10102 if ( !bNameFound ) {
10103 size_t size = strlen(cm_NetbiosName) + 2;
10104 if ( !pHostNames ) {
10105 pHostNames = malloc(size);
10106 pName = pHostNames;
10108 StringCbCopyA(pName, size, cm_NetbiosName);
10110 *pName = '\0'; /* add a second nul terminator */
10112 dwType = REG_MULTI_SZ;
10113 dwSize = (DWORD)(pName - pHostNames + 1);
10114 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10116 if ( hkLsa != INVALID_HANDLE_VALUE && !dwLoopbackCheckDisabled)
10118 dwType = REG_DWORD;
10119 dwSize = sizeof(DWORD);
10120 dwLoopbackCheckDisabled = 1;
10121 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwLoopbackCheckDisabled, dwSize);
10123 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10124 AFSREG_CLT_OPENAFS_SUBKEY,
10127 REG_OPTION_NON_VOLATILE,
10128 KEY_READ|KEY_WRITE,
10131 NULL) == ERROR_SUCCESS) {
10133 dwType = REG_DWORD;
10134 dwSize = sizeof(DWORD);
10136 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10137 bLoopbackCheckDisabled = TRUE;
10138 RegCloseKey(hkClient);
10141 } else if (!bLoopbackCheckDisabled && hkLsa != INVALID_HANDLE_VALUE) {
10142 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10143 AFSREG_CLT_OPENAFS_SUBKEY,
10146 REG_OPTION_NON_VOLATILE,
10147 KEY_READ|KEY_WRITE,
10150 NULL) == ERROR_SUCCESS) {
10152 dwSize = sizeof(DWORD);
10153 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10155 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10158 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10159 RegCloseKey(hkClient);
10163 * Disable SMB. Start by removing the DisableLoopbackCheck value if present.
10165 if (hkLsa != INVALID_HANDLE_VALUE) {
10166 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10167 AFSREG_CLT_OPENAFS_SUBKEY,
10170 REG_OPTION_NON_VOLATILE,
10171 KEY_READ|KEY_WRITE,
10174 NULL) == ERROR_SUCCESS) {
10176 dwSize = sizeof(DWORD);
10177 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10179 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10182 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10183 RegCloseKey(hkClient);
10186 /* Then remove our NetbiosName from the BackConnectionHostNames list */
10187 if ( bNameFound ) {
10189 * we found our name so if the size of the value is smaller
10190 * or equal to the length of our name alone, we are done.
10192 if ( dwszBackConnectionHostNames <= nbsize ) {
10193 RegDeleteValue( hkMSV10, "BackConnectionHostNames");
10195 pOrigNames = pHostNames;
10196 pHostNames = malloc(dwAllocSize);
10198 pOrig = pOrigNames;
10199 pName = pHostNames;
10200 while (pOrig - pOrigNames < dwszBackConnectionHostNames) {
10201 len = strlen(pOrig);
10202 if ( stricmp(pOrig, cm_NetbiosName)) {
10204 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10209 *pName = '\0'; /* add a second nul terminator */
10212 dwType = REG_MULTI_SZ;
10213 dwSize = (DWORD)(pName - pHostNames + 1);
10214 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10229 RegCloseKey(hkMSV10);
10232 if ( hkLsa != INVALID_HANDLE_VALUE ) {
10233 RegCloseKey(hkLsa);
10239 smb_configureExtendedSMBSessionTimeouts(int bEnable)
10242 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10243 * new functionality:
10245 * [HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters]
10246 * "ReconnectableServers" REG_MULTI_SZ
10247 * "ExtendedSessTimeout" REG_DWORD (seconds)
10248 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
10250 * These values can be used to prevent the smb redirector from timing out
10251 * smb connection to the afs smb server prematurely.
10255 DWORD dwSize, dwAllocSize;
10257 PBYTE pHostNames = NULL, pOrigNames = NULL, pName = NULL, pOrig = NULL;
10258 BOOL bNameFound = FALSE;
10259 DWORD dwszReconnectableServers;
10260 DWORD dwszServersWithExtendedSessTimeout;
10261 size_t nbsize = strlen(cm_NetbiosName) + 2;
10264 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10265 "SYSTEM\\CurrentControlSet\\Services\\LanmanWorkstation\\Parameters",
10267 KEY_READ|KEY_WRITE,
10268 &hkLanman) == ERROR_SUCCESS )
10270 if ((RegQueryValueEx( hkLanman, "ReconnectableServers", 0,
10271 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10272 (dwType == REG_MULTI_SZ))
10274 dwAllocSize += 1 /* in case the source string is not nul terminated */
10275 + (DWORD)strlen(cm_NetbiosName) + 2;
10276 pHostNames = malloc(dwAllocSize);
10277 dwszReconnectableServers = dwAllocSize;
10278 if (RegQueryValueEx( hkLanman, "ReconnectableServers", 0, &dwType,
10279 pHostNames, &dwszReconnectableServers) == ERROR_SUCCESS)
10281 for (pName = pHostNames;
10282 (pName - pHostNames < (int) dwszReconnectableServers) && *pName ;
10283 pName += strlen(pName) + 1)
10285 if ( !stricmp(pName, cm_NetbiosName) ) {
10294 * If our name was not found and we are enabling SMB,
10295 * add our name to the current value.
10297 if ( bEnable && !bNameFound ) {
10298 if ( !pHostNames ) {
10299 pHostNames = malloc(nbsize);
10300 pName = pHostNames;
10302 StringCbCopyA(pName, nbsize, cm_NetbiosName);
10303 pName += nbsize - 1;
10304 *pName = '\0'; /* add a second nul terminator */
10306 dwType = REG_MULTI_SZ;
10307 dwSize = (DWORD)(pName - pHostNames + 1);
10308 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10312 * If our name was found and we are disabling SMB,
10313 * remove our name from the list and update the value.
10314 * If our name is the only entry, remove the value.
10316 if ( !bEnable && bNameFound ) {
10318 * we found our name so if the size of the value is smaller
10319 * or equal to the length of our name alone, we are done.
10321 if ( dwszReconnectableServers <= nbsize ) {
10322 RegDeleteValue( hkLanman, "ReconnectableServers");
10324 pOrigNames = pHostNames;
10325 pHostNames = malloc(dwAllocSize);
10327 pOrig = pOrigNames;
10328 pName = pHostNames;
10329 while (pOrig - pOrigNames <dwszReconnectableServers ) {
10330 len = strlen(pOrig);
10331 if ( stricmp(pOrig, cm_NetbiosName)) {
10333 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10338 *pName = '\0'; /* add a second nul terminator */
10341 dwType = REG_MULTI_SZ;
10342 dwSize = (DWORD)(pName - pHostNames + 1);
10343 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10357 if ((RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0,
10358 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10359 (dwType == REG_MULTI_SZ))
10361 dwAllocSize += 1 /* in case the source string is not nul terminated */
10362 + (DWORD)strlen(cm_NetbiosName) + 2;
10363 pHostNames = malloc(dwAllocSize);
10364 dwszServersWithExtendedSessTimeout = dwAllocSize;
10365 if (RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, &dwType,
10366 pHostNames, &dwszServersWithExtendedSessTimeout) == ERROR_SUCCESS)
10368 for (pName = pHostNames;
10369 (pName - pHostNames < (int) dwszServersWithExtendedSessTimeout) && *pName ;
10370 pName += strlen(pName) + 1)
10372 if ( !stricmp(pName, cm_NetbiosName) ) {
10381 * If our name was not found and we are enabling SMB,
10382 * add our name to the current value.
10384 if ( bEnable && !bNameFound ) {
10385 size_t size = strlen(cm_NetbiosName) + 2;
10386 if ( !pHostNames ) {
10387 pHostNames = malloc(size);
10388 pName = pHostNames;
10390 StringCbCopyA(pName, size, cm_NetbiosName);
10392 *pName = '\0'; /* add a second nul terminator */
10394 dwType = REG_MULTI_SZ;
10395 dwSize = (DWORD)(pName - pHostNames + 1);
10396 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10400 * If our name was found and we are disabling SMB,
10401 * remove our name from the list and update the value.
10402 * If our name is the only entry, remove the value.
10404 if ( !bEnable && bNameFound ) {
10406 * we found our name so if the size of the value is smaller
10407 * or equal to the length of our name alone, we are done.
10409 if ( dwszServersWithExtendedSessTimeout <= nbsize ) {
10410 RegDeleteValue( hkLanman, "ServersWithExtendedSessTimeout");
10412 pOrigNames = pHostNames;
10413 pHostNames = malloc(dwAllocSize);
10415 pOrig = pOrigNames;
10416 pName = pHostNames;
10417 while (pOrig - pOrigNames < dwszServersWithExtendedSessTimeout) {
10418 len = strlen(pOrig);
10419 if ( stricmp(pOrig, cm_NetbiosName)) {
10421 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10426 *pName = '\0'; /* add a second nul terminator */
10429 dwType = REG_MULTI_SZ;
10430 dwSize = (DWORD)(pName - pHostNames + 1);
10431 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10446 if ((RegQueryValueEx( hkLanman, "ExtendedSessTimeout", 0,
10447 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10448 (dwType != REG_DWORD))
10450 dwType = REG_DWORD;
10451 dwSize = sizeof(dwValue);
10452 dwValue = 300; /* 5 minutes */
10453 RegSetValueEx( hkLanman, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10456 RegCloseKey(hkLanman);
10461 smb_LanAdapterChangeThread(void *param)
10464 * Give the IPAddrDaemon thread a chance
10465 * to block before we trigger.
10468 smb_LanAdapterChange(0);
10471 void smb_SetLanAdapterChangeDetected(void)
10476 lock_ObtainMutex(&smb_StartedLock);
10478 if (!powerStateSuspended) {
10479 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10480 NULL, 0, &lpid, "smb_LanAdapterChange");
10481 if (phandle == NULL) {
10485 gle = GetLastError();
10486 StringCchPrintf( msg, sizeof(msg)/sizeof(msg[0]),
10487 "smb_LanAdapterChangeThread thread creation failure - gle 0x%x",
10489 osi_assertx(TRUE, msg);
10491 thrd_CloseHandle(phandle);
10494 smb_LanAdapterChangeDetected = 1;
10495 lock_ReleaseMutex(&smb_StartedLock);
10498 void smb_LanAdapterChange(int locked) {
10499 lana_number_t lanaNum;
10501 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
10503 LANA_ENUM temp_list;
10508 afsi_log("smb_LanAdapterChange");
10511 lock_ObtainMutex(&smb_StartedLock);
10513 smb_LanAdapterChangeDetected = 0;
10515 if (!powerStateSuspended &&
10516 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10517 LANA_NETBIOS_NAME_FULL | LANA_NETBIOS_NO_RESET)) &&
10518 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10519 if ( isGateway != bGateway ) {
10520 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10521 smb_LANadapter, lanaNum, isGateway, bGateway);
10523 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10524 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10525 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10528 NCB *ncbp = smb_GetNCB();
10529 ncbp->ncb_command = NCBENUM;
10530 ncbp->ncb_buffer = (PUCHAR)&temp_list;
10531 ncbp->ncb_length = sizeof(temp_list);
10532 code = Netbios(ncbp);
10534 if (temp_list.length != lana_list.length) {
10535 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10536 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10539 for (i=0; i<lana_list.length; i++) {
10540 if ( temp_list.lana[i] != lana_list.lana[i] ) {
10541 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10542 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10554 smb_StopListeners(1);
10555 smb_RestartListeners(1);
10558 lock_ReleaseMutex(&smb_StartedLock);
10561 /* initialize Netbios */
10562 int smb_NetbiosInit(int locked)
10565 int i, lana, code, l;
10567 int delname_tried=0;
10569 int lana_found = 0;
10570 lana_number_t lanaNum;
10576 lock_ObtainMutex(&smb_StartedLock);
10578 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10579 smb_ListenerState != SMB_LISTENER_STOPPED) {
10582 lock_ReleaseMutex(&smb_StartedLock);
10585 /* setup the NCB system */
10586 ncbp = smb_GetNCB();
10589 * Call lanahelper to get Netbios name, lan adapter number and gateway flag
10590 * This will reset all of the network adapter's netbios state.
10592 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10593 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10595 if (smb_LANadapter != LANA_INVALID)
10596 afsi_log("LAN adapter number %d", smb_LANadapter);
10598 afsi_log("LAN adapter number not determined");
10601 afsi_log("Set for gateway service");
10603 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10605 /* something went horribly wrong. We can't proceed without a netbios name */
10607 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10608 osi_panic(buf, __FILE__, __LINE__);
10611 /* remember the name */
10612 len = (int)strlen(cm_NetbiosName);
10613 if (smb_localNamep)
10614 free(smb_localNamep);
10615 smb_localNamep = malloc(len+1);
10616 strcpy(smb_localNamep, cm_NetbiosName);
10617 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10619 /* Also copy the value to the client character encoded string */
10620 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10622 if (smb_LANadapter == LANA_INVALID) {
10623 ncbp->ncb_command = NCBENUM;
10624 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10625 ncbp->ncb_length = sizeof(lana_list);
10626 code = Netbios(ncbp);
10628 afsi_log("Netbios NCBENUM error code %d", code);
10629 osi_panic(s, __FILE__, __LINE__);
10633 lana_list.length = 1;
10634 lana_list.lana[0] = smb_LANadapter;
10637 for (i = 0; i < lana_list.length; i++) {
10638 /* reset the adaptor: in Win32, this is required for every process, and
10639 * acts as an init call, not as a real hardware reset.
10641 ncbp->ncb_command = NCBRESET;
10642 ncbp->ncb_callname[0] = 100;
10643 ncbp->ncb_callname[2] = 100;
10644 ncbp->ncb_lana_num = lana_list.lana[i];
10645 code = Netbios(ncbp);
10647 code = ncbp->ncb_retcode;
10649 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10650 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10652 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10656 /* and declare our name so we can receive connections */
10657 memset(ncbp, 0, sizeof(*ncbp));
10658 len=lstrlen(smb_localNamep);
10659 memset(smb_sharename,' ',NCBNAMSZ);
10660 memcpy(smb_sharename,smb_localNamep,len);
10661 afsi_log("lana_list.length %d", lana_list.length);
10663 /* Keep the name so we can unregister it later */
10664 for (l = 0; l < lana_list.length; l++) {
10665 lana = lana_list.lana[l];
10667 ncbp->ncb_command = NCBADDNAME;
10668 ncbp->ncb_lana_num = lana;
10669 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10670 code = Netbios(ncbp);
10672 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10673 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10675 char name[NCBNAMSZ+1];
10677 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10678 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10682 code = ncbp->ncb_retcode;
10685 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10688 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10689 if (code == NRC_BRIDGE) { /* invalid LANA num */
10690 lana_list.lana[l] = LANA_INVALID;
10693 else if (code == NRC_DUPNAME) {
10694 afsi_log("Name already exists; try to delete it");
10695 memset(ncbp, 0, sizeof(*ncbp));
10696 ncbp->ncb_command = NCBDELNAME;
10697 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10698 ncbp->ncb_lana_num = lana;
10699 code = Netbios(ncbp);
10701 code = ncbp->ncb_retcode;
10703 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10705 if (code != 0 || delname_tried) {
10706 lana_list.lana[l] = LANA_INVALID;
10708 else if (code == 0) {
10709 if (!delname_tried) {
10717 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10718 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10722 smb_LANadapter = lana;
10723 lana_found = 1; /* at least one worked */
10727 osi_assertx(lana_list.length >= 0, "empty lana list");
10729 afsi_log("No valid LANA numbers found!");
10730 lana_list.length = 0;
10731 smb_LANadapter = LANA_INVALID;
10732 smb_ListenerState = SMB_LISTENER_STOPPED;
10733 cm_VolStatus_Network_Stopped(cm_NetbiosName
10740 /* we're done with the NCB now */
10743 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10744 if (lana_list.length > 0)
10745 osi_assert(smb_LANadapter != LANA_INVALID);
10748 lock_ReleaseMutex(&smb_StartedLock);
10750 return (lana_list.length > 0 ? 1 : 0);
10753 void smb_StartListeners(int locked)
10763 lock_ObtainMutex(&smb_StartedLock);
10765 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10767 lock_ReleaseMutex(&smb_StartedLock);
10771 afsi_log("smb_StartListeners");
10772 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10773 smb_configureBackConnectionHostNames(TRUE);
10775 /* Configure Extended SMB Session Timeouts */
10776 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10777 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10778 smb_configureExtendedSMBSessionTimeouts(TRUE);
10781 smb_ListenerState = SMB_LISTENER_STARTED;
10782 cm_VolStatus_Network_Started(cm_NetbiosName
10788 for (i = 0; i < lana_list.length; i++) {
10789 if (lana_list.lana[i] == LANA_INVALID)
10791 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10792 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10793 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10794 thrd_CloseHandle(phandle);
10797 lock_ReleaseMutex(&smb_StartedLock);
10800 void smb_RestartListeners(int locked)
10806 lock_ObtainMutex(&smb_StartedLock);
10808 if (powerStateSuspended)
10809 afsi_log("smb_RestartListeners called while suspended");
10811 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10812 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10813 if (smb_NetbiosInit(1))
10814 smb_StartListeners(1);
10815 } else if (smb_LanAdapterChangeDetected) {
10816 smb_LanAdapterChange(1);
10820 lock_ReleaseMutex(&smb_StartedLock);
10823 void smb_StopListener(NCB *ncbp, int lana, int wait)
10827 memset(ncbp, 0, sizeof(*ncbp));
10828 ncbp->ncb_command = NCBDELNAME;
10829 ncbp->ncb_lana_num = lana;
10830 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10831 code = Netbios(ncbp);
10833 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10834 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10836 /* and then reset the LANA; this will cause the listener threads to exit */
10837 ncbp->ncb_command = NCBRESET;
10838 ncbp->ncb_callname[0] = 100;
10839 ncbp->ncb_callname[2] = 100;
10840 ncbp->ncb_lana_num = lana;
10841 code = Netbios(ncbp);
10843 code = ncbp->ncb_retcode;
10845 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10847 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10851 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10854 void smb_StopListeners(int locked)
10863 lock_ObtainMutex(&smb_StartedLock);
10865 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10867 lock_ReleaseMutex(&smb_StartedLock);
10871 afsi_log("smb_StopListeners");
10872 smb_ListenerState = SMB_LISTENER_STOPPED;
10873 cm_VolStatus_Network_Stopped(cm_NetbiosName
10879 ncbp = smb_GetNCB();
10881 /* Unregister the SMB name */
10882 for (l = 0; l < lana_list.length; l++) {
10883 lana = lana_list.lana[l];
10885 if (lana != LANA_INVALID) {
10886 smb_StopListener(ncbp, lana, TRUE);
10888 /* mark the adapter invalid */
10889 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10893 /* force a re-evaluation of the network adapters */
10894 lana_list.length = 0;
10895 smb_LANadapter = LANA_INVALID;
10898 lock_ReleaseMutex(&smb_StartedLock);
10901 void smb_Init(osi_log_t *logp, int useV3,
10911 EVENT_HANDLE retHandle;
10912 char eventName[MAX_PATH];
10913 int startListeners = 0;
10918 smb_MBfunc = aMBfunc;
10922 /* Initialize smb_localZero */
10923 myTime.tm_isdst = -1; /* compute whether on DST or not */
10924 myTime.tm_year = 70;
10926 myTime.tm_mday = 1;
10927 myTime.tm_hour = 0;
10930 smb_localZero = mktime(&myTime);
10932 #ifdef AFS_FREELANCE_CLIENT
10933 /* Make sure the root.afs volume has the correct time */
10934 cm_noteLocalMountPointChange(FALSE);
10937 /* initialize the remote debugging log */
10940 /* and the global lock */
10941 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10942 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10944 /* Raw I/O data structures */
10945 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10947 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10948 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10950 /* 4 Raw I/O buffers */
10951 smb_RawBufs = calloc(65536,1);
10952 *((char **)smb_RawBufs) = NULL;
10953 for (i=0; i<3; i++) {
10954 char *rawBuf = calloc(65536,1);
10955 *((char **)rawBuf) = smb_RawBufs;
10956 smb_RawBufs = rawBuf;
10959 /* global free lists */
10960 smb_ncbFreeListp = NULL;
10961 smb_packetFreeListp = NULL;
10963 lock_ObtainMutex(&smb_StartedLock);
10964 startListeners = smb_NetbiosInit(1);
10966 /* Initialize listener and server structures */
10968 memset(dead_sessions, 0, sizeof(dead_sessions));
10969 sprintf(eventName, "SessionEvents[0]");
10970 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10971 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10972 afsi_log("Event Object Already Exists: %s", eventName);
10974 smb_NumServerThreads = nThreads;
10975 sprintf(eventName, "NCBavails[0]");
10976 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10977 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10978 afsi_log("Event Object Already Exists: %s", eventName);
10979 sprintf(eventName, "NCBevents[0]");
10980 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10981 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10982 afsi_log("Event Object Already Exists: %s", eventName);
10983 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10984 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10985 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10986 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10987 afsi_log("Event Object Already Exists: %s", eventName);
10988 for (i = 0; i < smb_NumServerThreads; i++) {
10989 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10990 NCBreturns[i][0] = retHandle;
10993 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10994 for (i = 0; i < smb_NumServerThreads; i++) {
10995 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10996 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10997 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10998 afsi_log("Event Object Already Exists: %s", eventName);
10999 InitNCBslot((int)(i+1));
11001 numNCBs = smb_NumServerThreads + 1;
11003 /* Initialize dispatch table */
11004 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
11005 /* Prepare the table for unknown operations */
11006 for(i=0; i<= SMB_NOPCODES; i++) {
11007 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
11009 /* Fill in the ones we do know */
11010 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
11011 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
11012 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
11013 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
11014 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
11015 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
11016 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
11017 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
11018 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
11019 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
11020 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
11021 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
11022 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
11023 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
11024 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
11025 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
11026 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
11027 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
11028 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
11029 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
11030 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
11031 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11032 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
11033 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
11034 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
11035 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
11036 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
11037 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
11038 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11039 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
11040 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11041 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
11042 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
11043 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
11044 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11045 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
11046 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
11047 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
11048 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
11049 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
11050 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
11051 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
11052 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11053 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
11054 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11055 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
11056 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
11057 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
11058 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
11059 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
11060 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
11061 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
11062 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
11063 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
11064 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
11065 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
11066 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
11067 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
11068 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
11069 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
11070 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
11071 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
11072 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
11073 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
11074 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
11075 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11076 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
11077 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
11078 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
11079 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
11080 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
11081 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
11082 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
11083 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
11085 /* setup tran 2 dispatch table */
11086 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
11087 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
11088 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
11089 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
11090 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
11091 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
11092 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
11093 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
11094 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
11095 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
11096 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
11097 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
11098 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
11099 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
11100 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
11101 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
11102 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
11103 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
11105 /* setup the rap dispatch table */
11106 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
11107 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
11108 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
11109 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
11110 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
11114 /* if we are doing SMB authentication we have register outselves as a logon process */
11115 if (smb_authType != SMB_AUTH_NONE) {
11116 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
11117 LSA_STRING afsProcessName;
11118 LSA_OPERATIONAL_MODE dummy; /*junk*/
11120 afsProcessName.Buffer = "OpenAFSClientDaemon";
11121 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
11122 afsProcessName.MaximumLength = afsProcessName.Length + 1;
11124 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
11126 if (nts == STATUS_SUCCESS) {
11127 LSA_STRING packageName;
11128 /* we are registered. Find out the security package id */
11129 packageName.Buffer = MSV1_0_PACKAGE_NAME;
11130 packageName.Length = (USHORT)strlen(packageName.Buffer);
11131 packageName.MaximumLength = packageName.Length + 1;
11132 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
11133 if (nts == STATUS_SUCCESS) {
11135 * This code forces Windows to authenticate against the Logon Cache
11136 * first instead of attempting to authenticate against the Domain
11137 * Controller. When the Windows logon cache is enabled this improves
11138 * performance by removing the network access and works around a bug
11139 * seen at sites which are using a MIT Kerberos principal to login
11140 * to machines joined to a non-root domain in a multi-domain forest.
11141 * MsV1_0SetProcessOption was added in Windows XP.
11143 PVOID pResponse = NULL;
11144 ULONG cbResponse = 0;
11145 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
11147 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
11148 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
11149 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
11150 OptionsRequest.DisableOptions = FALSE;
11152 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
11155 sizeof(OptionsRequest),
11161 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
11162 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
11165 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
11167 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
11168 afsi_log("MsV1_0SetProcessOption success");
11170 /* END - code from Larry */
11172 smb_lsaLogonOrigin.Buffer = "OpenAFS";
11173 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
11174 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
11176 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
11178 /* something went wrong. We report the error and revert back to no authentication
11179 because we can't perform any auth requests without a successful lsa handle
11180 or sec package id. */
11181 afsi_log("Reverting to NO SMB AUTH");
11182 smb_authType = SMB_AUTH_NONE;
11185 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
11187 /* something went wrong. We report the error and revert back to no authentication
11188 because we can't perform any auth requests without a successful lsa handle
11189 or sec package id. */
11190 afsi_log("Reverting to NO SMB AUTH");
11191 smb_authType = SMB_AUTH_NONE;
11195 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
11196 * time prevents the failure of authentication when logged into Windows with an
11197 * external Kerberos principal mapped to a local account.
11199 else if ( smb_authType == SMB_AUTH_EXTENDED) {
11200 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
11201 * then the only option is NTLMSSP anyway; so just fallback.
11206 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
11207 if (secBlobLength == 0) {
11208 smb_authType = SMB_AUTH_NTLM;
11209 afsi_log("Reverting to SMB AUTH NTLM");
11218 /* Now get ourselves a domain name. */
11219 /* For now we are using the local computer name as the domain name.
11220 * It is actually the domain for local logins, and we are acting as
11221 * a local SMB server.
11223 bufsize = lengthof(smb_ServerDomainName) - 1;
11224 GetComputerNameW(smb_ServerDomainName, &bufsize);
11225 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
11226 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
11229 /* Start listeners, waiters, servers, and daemons */
11230 if (startListeners)
11231 smb_StartListeners(1);
11233 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
11234 NULL, 0, &lpid, "smb_ClientWaiter");
11235 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
11236 thrd_CloseHandle(phandle);
11238 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
11239 NULL, 0, &lpid, "smb_ServerWaiter");
11240 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
11241 thrd_CloseHandle(phandle);
11243 for (i=0; i<smb_NumServerThreads; i++) {
11244 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
11245 (void *) i, 0, &lpid, "smb_Server");
11246 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
11247 thrd_CloseHandle(phandle);
11250 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
11251 NULL, 0, &lpid, "smb_Daemon");
11252 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
11253 thrd_CloseHandle(phandle);
11255 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
11256 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
11257 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
11258 thrd_CloseHandle(phandle);
11260 if (smb_monitorReqs) {
11261 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
11262 NULL, 0, &lpid, "smb_ServerMonitor");
11263 osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
11264 thrd_CloseHandle(phandle);
11267 lock_ReleaseMutex(&smb_StartedLock);
11271 void smb_Shutdown(void)
11281 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11283 /* setup the NCB system */
11284 ncbp = smb_GetNCB();
11286 /* Block new sessions by setting shutdown flag */
11287 smbShutdownFlag = 1;
11289 /* Hang up all sessions */
11290 memset(ncbp, 0, sizeof(NCB));
11291 for (i = 1; i < numSessions; i++)
11293 if (dead_sessions[i])
11296 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11297 ncbp->ncb_command = NCBHANGUP;
11298 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
11299 ncbp->ncb_lsn = (UCHAR)LSNs[i];
11300 code = Netbios(ncbp);
11301 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11302 if (code == 0) code = ncbp->ncb_retcode;
11304 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11305 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11309 /* Trigger the shutdown of all SMB threads */
11310 for (i = 0; i < smb_NumServerThreads; i++)
11311 thrd_SetEvent(NCBreturns[i][0]);
11313 thrd_SetEvent(NCBevents[0]);
11314 thrd_SetEvent(SessionEvents[0]);
11315 thrd_SetEvent(NCBavails[0]);
11317 for (i = 0;i < smb_NumServerThreads; i++) {
11318 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11319 if (code == WAIT_OBJECT_0) {
11322 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11323 thrd_SetEvent(NCBreturns[i--][0]);
11327 /* Delete Netbios name */
11328 memset(ncbp, 0, sizeof(NCB));
11329 for (i = 0; i < lana_list.length; i++) {
11330 if (lana_list.lana[i] == LANA_INVALID) continue;
11331 ncbp->ncb_command = NCBDELNAME;
11332 ncbp->ncb_lana_num = lana_list.lana[i];
11333 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11334 code = Netbios(ncbp);
11336 code = ncbp->ncb_retcode;
11338 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11339 ncbp->ncb_lana_num, code);
11344 /* Release the reference counts held by the VCs */
11345 lock_ObtainWrite(&smb_rctLock);
11346 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11351 if (vcp->magic != SMB_VC_MAGIC)
11352 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11353 __FILE__, __LINE__);
11355 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11357 if (fidp->scp != NULL) {
11360 lock_ReleaseWrite(&smb_rctLock);
11361 lock_ObtainMutex(&fidp->mx);
11362 if (fidp->scp != NULL) {
11365 lock_ObtainWrite(&scp->rw);
11366 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11367 lock_ReleaseWrite(&scp->rw);
11368 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11369 cm_ReleaseSCache(scp);
11371 lock_ReleaseMutex(&fidp->mx);
11372 lock_ObtainWrite(&smb_rctLock);
11376 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11378 smb_ReleaseVCNoLock(tidp->vcp);
11380 cm_user_t *userp = tidp->userp;
11381 tidp->userp = NULL;
11382 cm_ReleaseUser(userp);
11386 lock_ReleaseWrite(&smb_rctLock);
11389 if (smb_monitorReqs) {
11390 smb_ShutdownMonitor();
11394 /* Get the UNC \\<servername>\<sharename> prefix. */
11395 char *smb_GetSharename()
11400 /* Make sure we have been properly initialized. */
11401 if (smb_localNamep == NULL)
11404 /* Allocate space for \\<servername>\<sharename>, plus the
11407 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11408 name = malloc(len);
11409 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11415 void smb_LogPacket(smb_packet_t *packet)
11419 unsigned length, paramlen, datalen, i, j;
11421 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11423 if (!packet) return;
11425 osi_Log0(smb_logp, "*** SMB packet dump ***");
11427 smbp = (smb_t *) packet->data;
11428 vp = (BYTE *) packet->data;
11430 paramlen = smbp->wct * 2;
11431 datalen = *((WORD *) (smbp->vdata + paramlen));
11432 length = sizeof(*smbp) + paramlen + 1 + datalen;
11434 for (i=0;i < length; i+=16)
11436 memset( buf, ' ', 80 );
11439 itoa( i, buf, 16 );
11441 buf[strlen(buf)] = ' ';
11443 cp = (BYTE*) buf + 7;
11445 for (j=0;j < 16 && (i+j)<length; j++)
11447 *(cp++) = hex[vp[i+j] >> 4];
11448 *(cp++) = hex[vp[i+j] & 0xf];
11458 for (j=0;j < 16 && (i+j)<length;j++)
11460 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11471 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11474 osi_Log0(smb_logp, "*** End SMB packet dump ***");
11476 #endif /* LOG_PACKET */
11479 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11485 smb_username_t *unp;
11486 smb_waitingLockRequest_t *wlrp;
11489 lock_ObtainRead(&smb_rctLock);
11491 sprintf(output, "begin dumping smb_username_t\r\n");
11492 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11493 for (unp = usernamesp; unp; unp=unp->nextp)
11495 cm_ucell_t *ucellp;
11497 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11498 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11499 unp->name ? unp->name : _C("NULL"),
11500 unp->machine ? unp->machine : _C("NULL"));
11501 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11503 sprintf(output, " begin dumping cm_ucell_t\r\n");
11504 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11506 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11507 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",
11508 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11509 ucellp->expirationTime, ucellp->gen,
11511 ucellp->cellp->name);
11512 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11515 sprintf(output, " done dumping cm_ucell_t\r\n");
11516 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11519 sprintf(output, "done dumping smb_username_t\r\n");
11520 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11526 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11527 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11529 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11530 smb_waitingLock_t *lockp;
11532 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11533 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11534 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11536 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
11537 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11538 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11539 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11540 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11541 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11543 sprintf(output, " done dumping smb_waitingLock_t\r\n");
11544 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11547 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11548 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11550 sprintf(output, "begin dumping smb_vc_t\r\n");
11551 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11553 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11559 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11560 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11561 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11563 sprintf(output, " begin dumping smb_user_t\r\n");
11564 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11565 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11566 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11567 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11568 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11570 sprintf(output, " done dumping smb_user_t\r\n");
11571 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11573 sprintf(output, " begin dumping smb_tid_t\r\n");
11574 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11575 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11576 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",
11577 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11578 tidp->pathname ? tidp->pathname : _C("NULL"));
11579 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11581 sprintf(output, " done dumping smb_tid_t\r\n");
11582 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11584 sprintf(output, " begin dumping smb_fid_t\r\n");
11585 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11587 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11589 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",
11590 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11591 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11592 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11593 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11596 sprintf(output, " done dumping smb_fid_t\r\n");
11597 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11600 sprintf(output, "done dumping smb_vc_t\r\n");
11601 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11603 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11604 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11606 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11612 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11613 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11614 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11616 sprintf(output, " begin dumping smb_user_t\r\n");
11617 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11618 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11619 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11620 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11621 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11623 sprintf(output, " done dumping smb_user_t\r\n");
11624 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11626 sprintf(output, " begin dumping smb_tid_t\r\n");
11627 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11628 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11629 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",
11630 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11631 tidp->pathname ? tidp->pathname : _C("NULL"));
11632 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11634 sprintf(output, " done dumping smb_tid_t\r\n");
11635 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11637 sprintf(output, " begin dumping smb_fid_t\r\n");
11638 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11640 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11642 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",
11643 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11644 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11645 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11646 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11649 sprintf(output, " done dumping smb_fid_t\r\n");
11650 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11653 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11654 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11658 lock_ReleaseRead(&smb_rctLock);
11662 long smb_IsNetworkStarted(void)
11669 lock_ObtainWrite(&smb_globalLock);
11670 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11671 lock_ReleaseWrite(&smb_globalLock);