2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 #pragma warning(disable: 4005)
32 #include <rx/rx_prototypes.h>
33 #include <WINNT\afsreg.h>
37 #include "lanahelper.h"
39 #define STRSAFE_NO_DEPRECATE
42 /* These characters are illegal in Windows filenames */
43 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
45 static int smbShutdownFlag = 0;
46 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
48 int smb_LogoffTokenTransfer;
49 time_t smb_LogoffTransferTimeout;
51 int smb_StoreAnsiFilenames = 0;
53 DWORD last_msg_time = 0;
57 unsigned int sessionGen = 0;
59 extern void afsi_log(char *pattern, ...);
60 extern HANDLE afsi_file;
61 extern int powerStateSuspended;
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t smb_ListenerLock;
70 osi_mutex_t smb_StartedLock;
72 unsigned char smb_LANadapter = LANA_INVALID;
73 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
74 int smb_LanAdapterChangeDetected = 0;
75 afs_uint32 smb_AsyncStore = 1;
76 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
78 BOOL isGateway = FALSE;
81 long smb_maxObsConcurrentCalls=0;
82 long smb_concurrentCalls=0;
84 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
86 smb_packet_t *smb_packetFreeListp;
87 smb_ncb_t *smb_ncbFreeListp;
89 afs_uint32 smb_NumServerThreads;
91 afs_uint32 numNCBs, numSessions, numVCs;
93 int smb_maxVCPerServer;
94 int smb_maxMpxRequests;
96 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
98 ULONG smb_lsaSecPackage;
99 LSA_STRING smb_lsaLogonOrigin;
101 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
102 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
103 EVENT_HANDLE **NCBreturns;
104 EVENT_HANDLE **NCBShutdown;
105 EVENT_HANDLE *smb_ServerShutdown;
106 EVENT_HANDLE ListenerShutdown[256];
107 DWORD NCBsessions[NCB_MAX];
109 struct smb_packet *bufs[NCB_MAX];
111 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
112 EVENT_HANDLE SessionEvents[SESSION_MAX];
113 unsigned short LSNs[SESSION_MAX];
114 int lanas[SESSION_MAX];
115 BOOL dead_sessions[SESSION_MAX];
118 osi_mutex_t smb_RawBufLock;
121 #define SMB_MASKFLAG_TILDE 1
122 #define SMB_MASKFLAG_CASEFOLD 2
124 #define RAWTIMEOUT INFINITE
127 typedef struct raw_write_cont {
136 /* dir search stuff */
137 long smb_dirSearchCounter = 1;
138 smb_dirSearch_t *smb_firstDirSearchp;
139 smb_dirSearch_t *smb_lastDirSearchp;
141 /* Initial mode bits for files and directories. Set to 0 to use
143 int smb_unixModeDefaultFile = 0666;
144 int smb_unixModeDefaultDir = 0777;
146 /* hide dot files? */
147 int smb_hideDotFiles;
149 /* Negotiate Unicode support? */
152 /* global state about V3 protocols */
153 int smb_useV3; /* try to negotiate V3 */
155 static int showErrors = 0;
156 /* MessageBox or something like it */
157 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
161 * Time in Unix format of midnight, 1/1/1970 local time.
162 * When added to dosUTime, gives Unix (AFS) time.
164 time_t smb_localZero = 0;
166 char *smb_localNamep = NULL;
168 smb_vc_t *smb_allVCsp;
169 smb_vc_t *smb_deadVCsp;
171 smb_username_t *usernamesp = NULL;
173 smb_waitingLockRequest_t *smb_allWaitingLocks;
176 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
177 NCB *ncbp, raw_write_cont_t *rwcp);
178 int smb_NetbiosInit(int);
181 void smb_LogPacket(smb_packet_t *packet);
182 #endif /* LOG_PACKET */
184 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
185 int smb_ServerDomainNameLength = 0;
186 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
187 int smb_ServerOSLength = lengthof(smb_ServerOS);
188 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
189 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
191 /* Faux server GUID. This is never checked. */
192 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
194 void smb_InitReq(cm_req_t *reqp)
197 reqp->flags |= CM_REQ_SOURCE_SMB;
200 const char * ncb_error_string(int code)
204 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
205 case 0x03: s = "NRC_ILLCMD illegal command"; break;
206 case 0x05: s = "NRC_CMDTMO command timed out"; break;
207 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
208 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
209 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
210 case 0x09: s = "NRC_NORES no resource available"; break;
211 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
212 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
213 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
214 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
215 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
216 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
217 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
218 case 0x13: s = "NRC_ILLNN illegal name number"; break;
219 case 0x14: s = "NRC_NOCALL no callname"; break;
220 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
221 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
222 case 0x17: s = "NRC_NAMERR name deleted"; break;
223 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
224 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
225 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
226 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
227 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
228 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
229 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
230 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
231 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
232 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
233 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
234 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
235 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
236 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
237 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
238 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
239 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
240 case 0x40: s = "NRC_SYSTEM system error"; break;
241 default: s = "unknown error";
247 char * myCrt_Dispatch(int i)
252 return "(00)ReceiveCoreMakeDir";
254 return "(01)ReceiveCoreRemoveDir";
256 return "(02)ReceiveCoreOpen";
258 return "(03)ReceiveCoreCreate";
260 return "(04)ReceiveCoreClose";
262 return "(05)ReceiveCoreFlush";
264 return "(06)ReceiveCoreUnlink";
266 return "(07)ReceiveCoreRename";
268 return "(08)ReceiveCoreGetFileAttributes";
270 return "(09)ReceiveCoreSetFileAttributes";
272 return "(0a)ReceiveCoreRead";
274 return "(0b)ReceiveCoreWrite";
276 return "(0c)ReceiveCoreLockRecord";
278 return "(0d)ReceiveCoreUnlockRecord";
280 return "(0e)SendCoreBadOp";
282 return "(0f)ReceiveCoreCreate";
284 return "(10)ReceiveCoreCheckPath";
286 return "(11)SendCoreBadOp";
288 return "(12)ReceiveCoreSeek";
290 return "(1a)ReceiveCoreReadRaw";
292 return "(1d)ReceiveCoreWriteRawDummy";
294 return "(22)ReceiveV3SetAttributes";
296 return "(23)ReceiveV3GetAttributes";
298 return "(24)ReceiveV3LockingX";
300 return "(25)ReceiveV3Trans";
302 return "(26)ReceiveV3Trans[aux]";
304 return "(29)SendCoreBadOp";
306 return "(2b)ReceiveCoreEcho";
308 return "(2d)ReceiveV3OpenX";
310 return "(2e)ReceiveV3ReadX";
312 return "(2f)ReceiveV3WriteX";
314 return "(32)ReceiveV3Tran2A";
316 return "(33)ReceiveV3Tran2A[aux]";
318 return "(34)ReceiveV3FindClose";
320 return "(35)ReceiveV3FindNotifyClose";
322 return "(70)ReceiveCoreTreeConnect";
324 return "(71)ReceiveCoreTreeDisconnect";
326 return "(72)ReceiveNegotiate";
328 return "(73)ReceiveV3SessionSetupX";
330 return "(74)ReceiveV3UserLogoffX";
332 return "(75)ReceiveV3TreeConnectX";
334 return "(80)ReceiveCoreGetDiskAttributes";
336 return "(81)ReceiveCoreSearchDir";
340 return "(83)FindUnique";
342 return "(84)FindClose";
344 return "(A0)ReceiveNTTransact";
346 return "(A2)ReceiveNTCreateX";
348 return "(A4)ReceiveNTCancel";
350 return "(A5)ReceiveNTRename";
352 return "(C0)OpenPrintFile";
354 return "(C1)WritePrintFile";
356 return "(C2)ClosePrintFile";
358 return "(C3)GetPrintQueue";
360 return "(D8)ReadBulk";
362 return "(D9)WriteBulk";
364 return "(DA)WriteBulkData";
366 return "unknown SMB op";
370 char * myCrt_2Dispatch(int i)
375 return "unknown SMB op-2";
377 return "S(00)CreateFile_ReceiveTran2Open";
379 return "S(01)FindFirst_ReceiveTran2SearchDir";
381 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
383 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
385 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
387 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
389 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
391 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
393 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
395 return "S(09)_ReceiveTran2FSCTL";
397 return "S(0a)_ReceiveTran2IOCTL";
399 return "S(0b)_ReceiveTran2FindNotifyFirst";
401 return "S(0c)_ReceiveTran2FindNotifyNext";
403 return "S(0d)_ReceiveTran2CreateDirectory";
405 return "S(0e)_ReceiveTran2SessionSetup";
407 return "S(0f)_QueryFileSystemInformationFid";
409 return "S(10)_ReceiveTran2GetDfsReferral";
411 return "S(11)_ReceiveTran2ReportDfsInconsistency";
415 char * myCrt_RapDispatch(int i)
420 return "unknown RAP OP";
422 return "RAP(0)NetShareEnum";
424 return "RAP(1)NetShareGetInfo";
426 return "RAP(13)NetServerGetInfo";
428 return "RAP(63)NetWkStaGetInfo";
432 char * myCrt_NmpipeDispatch(int i)
435 case SMB_TRANS_SET_NMPIPE_STATE:
436 return "SET NMPIPE STATE";
438 case SMB_TRANS_RAW_READ_NMPIPE:
439 return "RAW READ NMPIPE";
441 case SMB_TRANS_QUERY_NMPIPE_STATE:
442 return "QUERY NMPIPE STATE";
444 case SMB_TRANS_QUERY_NMPIPE_INFO:
445 return "QUERY NMPIPE INFO";
447 case SMB_TRANS_PEEK_NMPIPE:
448 return "PEEK NMPIPE";
450 case SMB_TRANS_TRANSACT_NMPIPE:
451 return "TRANSACT NMPIPE";
453 case SMB_TRANS_RAW_WRITE_NMPIPE:
454 return "WRITE NMPIPE";
456 case SMB_TRANS_READ_NMPIPE:
457 return "READ NMPIPE";
459 case SMB_TRANS_WRITE_NMPIPE:
460 return "WRITE NMPIPE";
462 case SMB_TRANS_WAIT_NMPIPE:
463 return "WAIT NMPIPE";
465 case SMB_TRANS_CALL_NMPIPE:
466 return "CALL NMPIPE";
471 /* scache must be locked */
472 unsigned int smb_Attributes(cm_scache_t *scp)
476 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
477 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
478 scp->fileType == CM_SCACHETYPE_INVALID)
480 attrs = SMB_ATTR_DIRECTORY;
481 #ifdef SPECIAL_FOLDERS
482 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
483 #endif /* SPECIAL_FOLDERS */
484 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
485 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
490 * We used to mark a file RO if it was in an RO volume, but that
491 * turns out to be impolitic in NT. See defect 10007.
494 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
495 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
497 if ((scp->unixModeBits & 0200) == 0)
498 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
504 void smb_SetInitialModeBitsForFile(int smb_attr, cm_attr_t * attr)
506 if (smb_unixModeDefaultFile != 0) {
507 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
508 attr->unixModeBits = smb_unixModeDefaultFile;
509 if (smb_attr & SMB_ATTR_READONLY)
510 attr->unixModeBits &= ~0222;
514 void smb_SetInitialModeBitsForDir(int smb_attr, cm_attr_t * attr)
516 if (smb_unixModeDefaultDir != 0) {
517 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
518 attr->unixModeBits = smb_unixModeDefaultDir;
522 /* Check if the named file/dir is a dotfile/dotdir */
523 /* String pointed to by lastComp can have leading slashes, but otherwise should have
524 no other patch components */
525 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
529 /* skip over slashes */
530 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
535 /* nulls, curdir and parent dir doesn't count */
541 if(*(s+1) == _C('.') && !*(s + 2))
548 static int ExtractBits(WORD bits, short start, short len)
555 num = bits << (16 - end);
556 num = num >> ((16 - end) + start);
561 void ShowUnixTime(char *FuncName, time_t unixTime)
566 cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
568 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
569 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
571 int day, month, year, sec, min, hour;
574 day = ExtractBits(wDate, 0, 5);
575 month = ExtractBits(wDate, 5, 4);
576 year = ExtractBits(wDate, 9, 7) + 1980;
578 sec = ExtractBits(wTime, 0, 5);
579 min = ExtractBits(wTime, 5, 6);
580 hour = ExtractBits(wTime, 11, 5);
582 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
583 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
587 /* Determine if we are observing daylight savings time */
588 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
590 TIME_ZONE_INFORMATION timeZoneInformation;
591 SYSTEMTIME utc, local, localDST;
593 /* Get the time zone info. NT uses this to calc if we are in DST. */
594 GetTimeZoneInformation(&timeZoneInformation);
596 /* Return the daylight bias */
597 *pDstBias = timeZoneInformation.DaylightBias;
599 /* Return the bias */
600 *pBias = timeZoneInformation.Bias;
602 /* Now determine if DST is being observed */
604 /* Get the UTC (GMT) time */
607 /* Convert UTC time to local time using the time zone info. If we are
608 observing DST, the calculated local time will include this.
610 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
612 /* Set the daylight bias to 0. The daylight bias is the amount of change
613 * in time that we use for daylight savings time. By setting this to 0
614 * we cause there to be no change in time during daylight savings time.
616 timeZoneInformation.DaylightBias = 0;
618 /* Convert the utc time to local time again, but this time without any
619 adjustment for daylight savings time.
621 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
623 /* If the two times are different, then it means that the localDST that
624 we calculated includes the daylight bias, and therefore we are
625 observing daylight savings time.
627 *pDST = localDST.wHour != local.wHour;
631 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
633 BOOL dst; /* Will be TRUE if observing DST */
634 LONG dstBias; /* Offset from local time if observing DST */
635 LONG bias; /* Offset from GMT for local time */
638 * This function will adjust the last write time to compensate
639 * for two bugs in the smb client:
641 * 1) During Daylight Savings Time, the LastWriteTime is ahead
642 * in time by the DaylightBias (ignoring the sign - the
643 * DaylightBias is always stored as a negative number). If
644 * the DaylightBias is -60, then the LastWriteTime will be
645 * ahead by 60 minutes.
647 * 2) If the local time zone is a positive offset from GMT, then
648 * the LastWriteTime will be the correct local time plus the
649 * Bias (ignoring the sign - a positive offset from GMT is
650 * always stored as a negative Bias). If the Bias is -120,
651 * then the LastWriteTime will be ahead by 120 minutes.
653 * These bugs can occur at the same time.
656 GetTimeZoneInfo(&dst, &dstBias, &bias);
658 /* First adjust for DST */
660 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
662 /* Now adjust for a positive offset from GMT (a negative bias). */
664 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
667 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
669 time_t diff_t = unixTime - smb_localZero;
670 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
671 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
673 *dosUTimep = (afs_uint32)diff_t;
676 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
678 *unixTimep = dosTime + smb_localZero;
681 void smb_MarkAllVCsDead(smb_vc_t * exclude)
684 smb_vc_t **vcp_to_cleanup = NULL;
685 int n_to_cleanup = 0;
688 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
690 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
691 lock_ObtainWrite(&smb_rctLock);
692 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
694 if (vcp->magic != SMB_VC_MAGIC)
695 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
701 lock_ObtainMutex(&vcp->mx);
702 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
703 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
704 lock_ReleaseMutex(&vcp->mx);
705 dead_sessions[vcp->session] = TRUE;
707 lock_ReleaseMutex(&vcp->mx);
712 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
714 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
718 vcp_to_cleanup[i++] = vcp;
719 smb_HoldVCNoLock(vcp);
722 osi_assert(i == n_to_cleanup);
724 lock_ReleaseWrite(&smb_rctLock);
725 lock_ReleaseWrite(&smb_globalLock);
727 for (i=0; i < n_to_cleanup; i++) {
728 smb_CleanupDeadVC(vcp_to_cleanup[i]);
729 smb_ReleaseVC(vcp_to_cleanup[i]);
730 vcp_to_cleanup[i] = 0;
733 free(vcp_to_cleanup);
736 #ifdef DEBUG_SMB_REFCOUNT
737 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
739 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
744 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
745 lock_ObtainWrite(&smb_rctLock);
746 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
747 if (vcp->magic != SMB_VC_MAGIC)
748 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
751 lock_ObtainMutex(&vcp->mx);
752 if (lsn == vcp->lsn && lana == vcp->lana &&
753 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
754 lock_ReleaseMutex(&vcp->mx);
755 smb_HoldVCNoLock(vcp);
758 lock_ReleaseMutex(&vcp->mx);
760 if (!vcp && (flags & SMB_FLAG_CREATE)) {
761 vcp = malloc(sizeof(*vcp));
762 memset(vcp, 0, sizeof(*vcp));
763 vcp->vcID = ++numVCs;
764 vcp->magic = SMB_VC_MAGIC;
765 vcp->refCount = 2; /* smb_allVCsp and caller */
768 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
769 vcp->nextp = smb_allVCsp;
771 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
776 if (smb_authType == SMB_AUTH_NTLM) {
777 /* We must obtain a challenge for extended auth
778 * in case the client negotiates smb v3
780 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
781 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
782 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
783 ULONG lsaRespSize = 0;
785 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
787 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
794 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
795 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
796 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
797 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
798 nts, ntsEx, lsaRespSize);
800 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
802 if (ntsEx == STATUS_SUCCESS) {
803 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
806 * This will cause the subsequent authentication to fail but
807 * that is better than us dereferencing a NULL pointer and
810 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
813 LsaFreeReturnBuffer(lsaResp);
816 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
818 if (numVCs >= CM_SESSION_RESERVED) {
820 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
823 #ifdef DEBUG_SMB_REFCOUNT
825 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
826 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
829 lock_ReleaseWrite(&smb_rctLock);
830 lock_ReleaseWrite(&smb_globalLock);
834 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
839 for(i=0; i<11; i++) {
841 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
847 static int smb_IsStarMask(clientchar_t *maskp)
853 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
859 #ifdef DEBUG_SMB_REFCOUNT
860 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
861 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
863 void smb_ReleaseVCInternal(smb_vc_t *vcp)
869 lock_AssertWrite(&smb_rctLock);
872 if (vcp->refCount == 0) {
873 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
874 #ifdef DEBUG_SMB_REFCOUNT
875 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
876 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
878 /* remove VCP from smb_deadVCsp */
879 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
885 lock_FinalizeMutex(&vcp->mx);
886 memset(vcp,0,sizeof(smb_vc_t));
889 #ifdef DEBUG_SMB_REFCOUNT
890 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
892 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
896 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
897 avcp?"":"not ",vcp, vcp->refCount);
899 /* This is a wrong. However, I suspect that there is an undercount
900 * and I don't want to release 1.4.1 in a state that will allow
901 * smb_vc_t objects to be deallocated while still in the
902 * smb_allVCsp list. The list is supposed to keep a reference
903 * to the smb_vc_t. Put it back.
907 #ifdef DEBUG_SMB_REFCOUNT
908 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
909 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
913 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
914 /* The reference count is non-zero but the VC is dead.
915 * This implies that some FIDs, TIDs, etc on the VC have yet to
916 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
917 * add a reference that will be dropped by
918 * smb_CleanupDeadVC() and try to cleanup the VC again.
919 * Eventually the refCount will drop to zero when all of the
920 * active threads working with the VC end their task.
922 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
923 vcp->refCount++; /* put the refCount back */
924 lock_ReleaseWrite(&smb_rctLock);
925 smb_CleanupDeadVC(vcp);
926 #ifdef DEBUG_SMB_REFCOUNT
927 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
928 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
930 lock_ObtainWrite(&smb_rctLock);
933 #ifdef DEBUG_SMB_REFCOUNT
934 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
935 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
940 #ifdef DEBUG_SMB_REFCOUNT
941 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
943 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
946 lock_AssertWrite(&smb_rctLock);
947 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
948 smb_ReleaseVCInternal(vcp);
951 #ifdef DEBUG_SMB_REFCOUNT
952 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
954 void smb_ReleaseVC(smb_vc_t *vcp)
957 lock_ObtainWrite(&smb_rctLock);
958 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
959 smb_ReleaseVCInternal(vcp);
960 lock_ReleaseWrite(&smb_rctLock);
963 #ifdef DEBUG_SMB_REFCOUNT
964 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
966 void smb_HoldVCNoLock(smb_vc_t *vcp)
969 lock_AssertWrite(&smb_rctLock);
971 #ifdef DEBUG_SMB_REFCOUNT
972 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
973 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
975 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
979 #ifdef DEBUG_SMB_REFCOUNT
980 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
982 void smb_HoldVC(smb_vc_t *vcp)
985 lock_ObtainWrite(&smb_rctLock);
987 #ifdef DEBUG_SMB_REFCOUNT
988 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
989 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
991 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
993 lock_ReleaseWrite(&smb_rctLock);
996 void smb_CleanupDeadVC(smb_vc_t *vcp)
1001 smb_tid_t *tidpIter;
1002 smb_tid_t *tidpNext;
1004 smb_user_t *uidpIter;
1005 smb_user_t *uidpNext;
1007 afs_uint32 refCount = 0;
1009 lock_ObtainMutex(&vcp->mx);
1010 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1011 lock_ReleaseMutex(&vcp->mx);
1012 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1015 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1016 lock_ReleaseMutex(&vcp->mx);
1017 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1019 lock_ObtainWrite(&smb_rctLock);
1020 /* remove VCP from smb_allVCsp */
1021 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1022 if ((*vcpp)->magic != SMB_VC_MAGIC)
1023 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1024 __FILE__, __LINE__);
1027 vcp->nextp = smb_deadVCsp;
1029 /* Hold onto the reference until we are done with this function */
1034 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1035 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1037 if (fidpIter->deleteOk)
1040 fid = fidpIter->fid;
1041 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1043 smb_HoldFIDNoLock(fidpIter);
1044 lock_ReleaseWrite(&smb_rctLock);
1046 smb_CloseFID(vcp, fidpIter, NULL, 0);
1047 smb_ReleaseFID(fidpIter);
1049 lock_ObtainWrite(&smb_rctLock);
1050 fidpNext = vcp->fidsp;
1053 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1054 tidpNext = tidpIter->nextp;
1055 if (tidpIter->deleteOk)
1057 tidpIter->deleteOk = 1;
1059 tid = tidpIter->tid;
1060 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1062 smb_HoldTIDNoLock(tidpIter);
1063 smb_ReleaseTID(tidpIter, TRUE);
1064 tidpNext = vcp->tidsp;
1067 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1068 uidpNext = uidpIter->nextp;
1069 if (uidpIter->deleteOk)
1071 uidpIter->deleteOk = 1;
1073 /* do not add an additional reference count for the smb_user_t
1074 * as the smb_vc_t already is holding a reference */
1075 lock_ReleaseWrite(&smb_rctLock);
1077 smb_ReleaseUID(uidpIter);
1079 lock_ObtainWrite(&smb_rctLock);
1080 uidpNext = vcp->usersp;
1083 /* The vcp is now on the deadVCsp list. We intentionally drop the
1084 * reference so that the refcount can reach 0 and we can delete it
1086 * If the refCount == 1 going into the ReleaseVCNoLock call
1087 * the object will be freed and it won't be safe to clear
1090 refCount = vcp->refCount;
1091 smb_ReleaseVCNoLock(vcp);
1093 lock_ObtainMutex(&vcp->mx);
1094 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1095 lock_ReleaseMutex(&vcp->mx);
1098 lock_ReleaseWrite(&smb_rctLock);
1099 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1102 #ifdef DEBUG_SMB_REFCOUNT
1103 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1105 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1110 lock_ObtainWrite(&smb_rctLock);
1112 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1113 if (tidp->refCount == 0 && tidp->deleteOk) {
1115 smb_ReleaseTID(tidp, TRUE);
1119 if (tid == tidp->tid) {
1124 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1125 tidp = malloc(sizeof(*tidp));
1126 memset(tidp, 0, sizeof(*tidp));
1127 tidp->nextp = vcp->tidsp;
1130 smb_HoldVCNoLock(vcp);
1132 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1135 #ifdef DEBUG_SMB_REFCOUNT
1137 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1138 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1141 lock_ReleaseWrite(&smb_rctLock);
1145 #ifdef DEBUG_SMB_REFCOUNT
1146 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1148 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1151 lock_AssertWrite(&smb_rctLock);
1153 #ifdef DEBUG_SMB_REFCOUNT
1154 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1155 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1159 #ifdef DEBUG_SMB_REFCOUNT
1160 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1162 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1167 cm_user_t *userp = NULL;
1168 smb_vc_t *vcp = NULL;
1171 lock_ObtainWrite(&smb_rctLock);
1173 lock_AssertWrite(&smb_rctLock);
1175 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1176 #ifdef DEBUG_SMB_REFCOUNT
1177 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1178 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1180 if (tidp->refCount == 0) {
1181 if (tidp->deleteOk) {
1182 ltpp = &tidp->vcp->tidsp;
1183 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1187 osi_assertx(tp != NULL, "null smb_tid_t");
1189 lock_FinalizeMutex(&tidp->mx);
1190 userp = tidp->userp; /* remember to drop ref later */
1198 smb_ReleaseVCNoLock(vcp);
1200 lock_ReleaseWrite(&smb_rctLock);
1202 cm_ReleaseUser(userp);
1205 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1207 smb_user_t *uidp = NULL;
1209 lock_ObtainWrite(&smb_rctLock);
1210 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1211 if (uid == uidp->userID) {
1213 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1215 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1219 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1220 uidp = malloc(sizeof(*uidp));
1221 memset(uidp, 0, sizeof(*uidp));
1222 uidp->nextp = vcp->usersp;
1223 uidp->refCount = 2; /* one for the vcp and one for the caller */
1225 smb_HoldVCNoLock(vcp);
1227 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1229 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1231 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1233 lock_ReleaseWrite(&smb_rctLock);
1237 afs_int32 smb_userIsLocalSystem(smb_user_t *uidp)
1240 DWORD dwSize1 = 0, dwSize2 = 0;
1241 wchar_t *pszRefDomain = NULL;
1242 SID_NAME_USE snu = SidTypeGroup;
1243 clientchar_t * secSidString = NULL;
1245 afs_int32 isSystem = 0;
1247 if (uidp->unp->flags & SMB_USERNAMEFLAG_SID) {
1248 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, uidp->unp->name);
1253 * The input name is not a SID for the user. See if we can
1254 * obtain the SID for the specified name. If we can, use
1255 * that instead of the name provided for the comparison.
1258 LookupAccountNameW( NULL /* System Name to begin Search */,
1263 gle = GetLastError();
1264 if (gle == ERROR_INSUFFICIENT_BUFFER) {
1265 pSid = malloc(dwSize1);
1267 * Although dwSize2 is supposed to include the terminating
1268 * NUL character, on Win7 it does not.
1270 pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
1273 if ( pSid && pszRefDomain ) {
1274 memset(pSid, 0, dwSize1);
1276 if (LookupAccountNameW( NULL /* System Name to begin Search */,
1279 pszRefDomain, &dwSize2,
1281 ConvertSidToStringSidW(pSid, &secSidString);
1285 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, secSidString);
1286 LocalFree(secSidString);
1297 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1300 smb_username_t *unp= NULL;
1302 lock_ObtainWrite(&smb_rctLock);
1303 for(unp = usernamesp; unp; unp = unp->nextp) {
1304 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1305 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1310 if (!unp && (flags & SMB_FLAG_CREATE)) {
1311 unp = malloc(sizeof(*unp));
1312 memset(unp, 0, sizeof(*unp));
1314 unp->nextp = usernamesp;
1315 unp->name = cm_ClientStrDup(usern);
1316 unp->machine = cm_ClientStrDup(machine);
1318 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1319 if (flags & SMB_FLAG_AFSLOGON)
1320 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1323 lock_ReleaseWrite(&smb_rctLock);
1327 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1329 smb_user_t *uidp= NULL;
1331 lock_ObtainWrite(&smb_rctLock);
1332 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1335 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1337 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1338 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1343 lock_ReleaseWrite(&smb_rctLock);
1347 void smb_ReleaseUsername(smb_username_t *unp)
1350 smb_username_t **lupp;
1351 cm_user_t *userp = NULL;
1352 time_t now = osi_Time();
1354 lock_ObtainWrite(&smb_rctLock);
1355 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1356 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1357 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1359 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1363 osi_assertx(up != NULL, "null smb_username_t");
1365 up->nextp = NULL; /* do not remove this */
1366 lock_FinalizeMutex(&unp->mx);
1372 lock_ReleaseWrite(&smb_rctLock);
1374 cm_ReleaseUser(userp);
1377 void smb_HoldUIDNoLock(smb_user_t *uidp)
1379 lock_AssertWrite(&smb_rctLock);
1383 void smb_ReleaseUID(smb_user_t *uidp)
1387 smb_username_t *unp = NULL;
1389 lock_ObtainWrite(&smb_rctLock);
1390 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1391 if (uidp->refCount == 0) {
1392 lupp = &uidp->vcp->usersp;
1393 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1397 osi_assertx(up != NULL, "null smb_user_t");
1399 lock_FinalizeMutex(&uidp->mx);
1401 smb_ReleaseVCNoLock(uidp->vcp);
1405 lock_ReleaseWrite(&smb_rctLock);
1409 cm_ReleaseUserVCRef(unp->userp);
1410 smb_ReleaseUsername(unp);
1414 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1416 cm_user_t *up = NULL;
1421 lock_ObtainMutex(&uidp->mx);
1423 up = uidp->unp->userp;
1426 lock_ReleaseMutex(&uidp->mx);
1432 /* retrieve a held reference to a user structure corresponding to an incoming
1434 * corresponding release function is cm_ReleaseUser.
1436 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1439 cm_user_t *up = NULL;
1442 smbp = (smb_t *) inp;
1443 uidp = smb_FindUID(vcp, smbp->uid, 0);
1447 up = smb_GetUserFromUID(uidp);
1449 smb_ReleaseUID(uidp);
1454 * Return a pointer to a pathname extracted from a TID structure. The
1455 * TID structure is not held; assume it won't go away.
1457 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1462 tidp = smb_FindTID(vcp, tid, 0);
1466 if (tidp->flags & SMB_TIDFLAG_IPC) {
1467 code = CM_ERROR_TIDIPC;
1468 /* tidp->pathname would be NULL, but that's fine */
1470 *treepath = tidp->pathname;
1471 smb_ReleaseTID(tidp, FALSE);
1476 /* check to see if we have a chained fid, that is, a fid that comes from an
1477 * OpenAndX message that ran earlier in this packet. In this case, the fid
1478 * field in a read, for example, request, isn't set, since the value is
1479 * supposed to be inherited from the openAndX call.
1481 int smb_ChainFID(int fid, smb_packet_t *inp)
1483 if (inp->fid == 0 || inp->inCount == 0)
1489 /* are we a priv'd user? What does this mean on NT? */
1490 int smb_SUser(cm_user_t *userp)
1495 /* find a file ID. If we pass in 0 we select an unused File ID.
1496 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1497 * smb_fid_t data structure if desired File ID cannot be found.
1499 #ifdef DEBUG_SMB_REFCOUNT
1500 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1502 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1509 if (!(flags & SMB_FLAG_CREATE))
1514 lock_ObtainWrite(&smb_rctLock);
1516 fid = vcp->fidCounter;
1519 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1520 if (fidp->refCount == 0 && fidp->deleteOk) {
1522 lock_ReleaseWrite(&smb_rctLock);
1523 smb_ReleaseFID(fidp);
1524 lock_ObtainWrite(&smb_rctLock);
1526 * We dropped the smb_rctLock so the fid value we are using
1527 * may now be used by another thread. Start over with the
1528 * current vcp->fidCounter.
1531 fid = vcp->fidCounter;
1534 if (fid == fidp->fid) {
1536 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1538 if (fid == 0xFFFF) {
1540 "New FID number wraps on vcp 0x%x", vcp);
1550 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1551 char eventName[MAX_PATH];
1555 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1557 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1559 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1560 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1561 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1562 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1563 thrd_CloseHandle(event);
1565 if (fid == 0xFFFF) {
1566 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1572 fidp = malloc(sizeof(*fidp));
1573 memset(fidp, 0, sizeof(*fidp));
1574 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1577 smb_HoldVCNoLock(vcp);
1578 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1580 fidp->curr_chunk = fidp->prev_chunk = -2;
1581 fidp->raw_write_event = event;
1583 vcp->fidCounter = fid+1;
1584 if (vcp->fidCounter == 0xFFFF) {
1585 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1587 vcp->fidCounter = 1;
1592 #ifdef DEBUG_SMB_REFCOUNT
1594 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1598 lock_ReleaseWrite(&smb_rctLock);
1603 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1604 #ifdef DEBUG_SMB_REFCOUNT
1605 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1607 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1610 smb_fid_t *fidp = NULL, *nextp = NULL;
1616 * If the fidp->scp changes out from under us then
1617 * we must not grab a refCount. It means the *fidp
1618 * was processed by smb_CloseFID() and the *fidp is
1619 * no longer valid for use.
1621 lock_ObtainWrite(&smb_rctLock);
1622 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1623 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1627 if (scp == fidp->scp) {
1628 lock_ReleaseWrite(&smb_rctLock);
1629 lock_ObtainMutex(&fidp->mx);
1630 lock_ObtainWrite(&smb_rctLock);
1631 if (scp == fidp->scp) {
1632 lock_ReleaseMutex(&fidp->mx);
1635 lock_ReleaseMutex(&fidp->mx);
1638 if (fidp->refCount > 1) {
1641 lock_ReleaseWrite(&smb_rctLock);
1642 smb_ReleaseFID(fidp);
1643 lock_ObtainWrite(&smb_rctLock);
1648 if (nextp->refCount > 1) {
1651 lock_ReleaseWrite(&smb_rctLock);
1652 smb_ReleaseFID(nextp);
1653 lock_ObtainWrite(&smb_rctLock);
1657 #ifdef DEBUG_SMB_REFCOUNT
1659 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1660 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1663 lock_ReleaseWrite(&smb_rctLock);
1667 #ifdef DEBUG_SMB_REFCOUNT
1668 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1670 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1673 lock_AssertWrite(&smb_rctLock);
1675 #ifdef DEBUG_SMB_REFCOUNT
1676 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1677 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1682 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1683 /* the smb_fid_t->mx and smb_rctLock must not be held */
1684 #ifdef DEBUG_SMB_REFCOUNT
1685 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1687 void smb_ReleaseFID(smb_fid_t *fidp)
1690 cm_scache_t *scp = NULL;
1691 cm_user_t *userp = NULL;
1692 smb_vc_t *vcp = NULL;
1693 smb_ioctl_t *ioctlp;
1695 lock_ObtainMutex(&fidp->mx);
1696 lock_ObtainWrite(&smb_rctLock);
1697 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1698 #ifdef DEBUG_SMB_REFCOUNT
1699 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1700 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1702 if (fidp->refCount == 0) {
1703 if (fidp->deleteOk) {
1706 scp = fidp->scp; /* release after lock is released */
1708 lock_ObtainWrite(&scp->rw);
1709 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1710 lock_ReleaseWrite(&scp->rw);
1711 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1714 userp = fidp->userp;
1718 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1719 thrd_CloseHandle(fidp->raw_write_event);
1721 /* and see if there is ioctl stuff to free */
1722 ioctlp = fidp->ioctlp;
1725 cm_FreeSpace(ioctlp->prefix);
1726 if (ioctlp->ioctl.inAllocp)
1727 free(ioctlp->ioctl.inAllocp);
1728 if (ioctlp->ioctl.outAllocp)
1729 free(ioctlp->ioctl.outAllocp);
1733 smb_CleanupRPCFid(fidp);
1735 lock_ReleaseMutex(&fidp->mx);
1736 lock_FinalizeMutex(&fidp->mx);
1741 smb_ReleaseVCNoLock(vcp);
1745 lock_ReleaseMutex(&fidp->mx);
1747 lock_ReleaseWrite(&smb_rctLock);
1749 /* now release the scache structure */
1751 cm_ReleaseSCache(scp);
1754 cm_ReleaseUser(userp);
1758 * Case-insensitive search for one string in another;
1759 * used to find variable names in submount pathnames.
1761 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1763 clientchar_t *cursor;
1765 for (cursor = str1; *cursor; cursor++)
1766 if (cm_ClientStrCmpI(cursor, str2) == 0)
1773 * Substitute a variable value for its name in a submount pathname. Variable
1774 * name has been identified by smb_stristr() and is in substr. Variable name
1775 * length (plus one) is in substr_size. Variable value is in newstr.
1777 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1778 unsigned int substr_size, clientchar_t *newstr)
1780 clientchar_t temp[1024];
1782 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1783 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1784 cm_ClientStrCat(str1, cchstr1, temp);
1787 clientchar_t VNUserName[] = _C("%USERNAME%");
1788 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1789 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1790 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1792 typedef struct smb_findShare_rock {
1793 clientchar_t * shareName;
1794 clientchar_t * match;
1796 } smb_findShare_rock_t;
1798 #define SMB_FINDSHARE_EXACT_MATCH 1
1799 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1801 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1805 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1806 normchar_t normName[MAX_PATH];
1808 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1809 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1810 osi_LogSaveString(smb_logp, dep->name));
1814 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1815 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1816 matchType = SMB_FINDSHARE_EXACT_MATCH;
1818 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1821 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1822 vrock->matchType = matchType;
1824 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1825 return CM_ERROR_STOPNOW;
1831 /* find a shareName in the table of submounts */
1832 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1833 clientchar_t *shareName,
1834 clientchar_t **pathNamep)
1838 clientchar_t pathName[1024];
1841 clientchar_t *p, *q;
1842 fschar_t *cellname = NULL;
1845 DWORD allSubmount = 1;
1847 /* if allSubmounts == 0, only return the //mountRoot/all share
1848 * if in fact it has been been created in the subMounts table.
1849 * This is to allow sites that want to restrict access to the
1852 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1853 0, KEY_QUERY_VALUE, &parmKey);
1854 if (code == ERROR_SUCCESS) {
1855 cblen = sizeof(allSubmount);
1856 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1857 (BYTE *) &allSubmount, &cblen);
1858 if (code != ERROR_SUCCESS) {
1861 RegCloseKey (parmKey);
1864 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1869 /* In case, the all share is disabled we need to still be able
1870 * to handle ioctl requests
1872 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1873 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1877 if (MSRPC_IsWellKnownService(shareName) ||
1878 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1879 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1885 /* Check for volume references
1887 * They look like <cell>{%,#}<volume>
1889 if (cm_ClientStrChr(shareName, '%') != NULL ||
1890 cm_ClientStrChr(shareName, '#') != NULL) {
1891 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1892 /* make room for '/@vol:' + mountchar + NULL terminator*/
1894 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1895 osi_LogSaveClientString(smb_logp, shareName));
1897 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1898 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1899 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1901 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1903 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1904 cm_ClientStrLwr(*pathNamep);
1905 osi_Log1(smb_logp, " returning pathname [%S]",
1906 osi_LogSaveClientString(smb_logp, *pathNamep));
1914 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1915 0, KEY_QUERY_VALUE, &parmKey);
1916 if (code == ERROR_SUCCESS) {
1917 cblen = sizeof(pathName);
1918 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1919 (BYTE *) pathName, &cblen);
1920 if (code != ERROR_SUCCESS)
1922 RegCloseKey (parmKey);
1926 cchlen = cblen / sizeof(clientchar_t);
1927 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1928 /* We can accept either unix or PC style AFS pathnames. Convert
1929 * Unix-style to PC style here for internal use.
1932 cchlen = lengthof(pathName);
1934 /* within this code block, we maintain, cchlen = writable
1935 buffer length of p */
1937 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1938 p += cm_mountRootCLen; /* skip mount path */
1939 cchlen -= (DWORD)(p - pathName);
1944 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1950 clientchar_t temp[1024];
1952 if (var = smb_stristr(p, VNUserName)) {
1953 if (uidp && uidp->unp)
1954 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1956 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1958 else if (var = smb_stristr(p, VNLCUserName))
1960 if (uidp && uidp->unp)
1961 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1963 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1964 cm_ClientStrLwr(temp);
1965 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1967 else if (var = smb_stristr(p, VNComputerName))
1969 sizeTemp = lengthof(temp);
1970 GetComputerNameW(temp, &sizeTemp);
1971 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1973 else if (var = smb_stristr(p, VNLCComputerName))
1975 sizeTemp = lengthof(temp);
1976 GetComputerName((LPTSTR)temp, &sizeTemp);
1977 cm_ClientStrLwr(temp);
1978 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1983 *pathNamep = cm_ClientStrDup(p);
1988 /* First lookup shareName in root.afs */
1990 smb_findShare_rock_t vrock;
1992 fschar_t ftemp[1024];
1993 clientchar_t * p = shareName;
1998 /* attempt to locate a partial match in root.afs. This is because
1999 when using the ANSI RAP calls, the share name is limited to 13 chars
2000 and hence is truncated. Of course we prefer exact matches. */
2002 thyper.HighPart = 0;
2005 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2006 if (vrock.shareName == NULL)
2009 vrock.matchType = 0;
2011 userp = (uidp? (uidp->unp ? uidp->unp->userp : cm_rootUserp) : cm_rootUserp);
2012 rscp = cm_RootSCachep(userp, &req);
2013 cm_HoldSCache(rscp);
2014 code = cm_ApplyDir(rscp, smb_FindShareProc, &vrock, &thyper,
2016 cm_ReleaseSCache(rscp);
2018 free(vrock.shareName);
2019 vrock.shareName = NULL;
2021 if (vrock.matchType) {
2022 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2023 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2028 /* if we get here, there was no match for the share in root.afs */
2029 /* so try to create \\<netbiosName>\<cellname> */
2034 /* Get the full name for this cell */
2035 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2036 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2037 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2038 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2039 if (code && cm_dnsEnabled) {
2041 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2046 /* construct the path */
2048 clientchar_t temp[1024];
2050 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2051 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2052 rw ? _C("/.%S/") : _C("/%S/"), temp);
2053 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2063 /* Client-side offline caching policy types */
2064 #define CSC_POLICY_MANUAL 0
2065 #define CSC_POLICY_DOCUMENTS 1
2066 #define CSC_POLICY_PROGRAMS 2
2067 #define CSC_POLICY_DISABLE 3
2069 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2072 clientchar_t policy[1024];
2075 int retval = CSC_POLICY_MANUAL;
2077 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2078 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2081 REG_OPTION_NON_VOLATILE,
2085 NULL ) != ERROR_SUCCESS)
2086 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2088 len = sizeof(policy);
2089 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2091 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2093 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2095 retval = CSC_POLICY_MANUAL;
2097 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2099 retval = CSC_POLICY_DOCUMENTS;
2101 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2103 retval = CSC_POLICY_PROGRAMS;
2105 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2107 retval = CSC_POLICY_DISABLE;
2110 RegCloseKey(hkCSCPolicy);
2114 /* find a dir search structure by cookie value, and return it held.
2115 * Must be called with smb_globalLock held.
2117 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2119 smb_dirSearch_t *dsp;
2121 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2122 if (dsp->cookie == cookie) {
2123 if (dsp != smb_firstDirSearchp) {
2124 /* move to head of LRU queue, too, if we're not already there */
2125 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2126 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2127 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2128 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2129 if (!smb_lastDirSearchp)
2130 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2138 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2139 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2140 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2146 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2148 lock_ObtainMutex(&dsp->mx);
2149 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2150 dsp->cookie, dsp, dsp->scp);
2151 dsp->flags |= SMB_DIRSEARCH_DELETE;
2152 if (dsp->scp != NULL) {
2153 lock_ObtainWrite(&dsp->scp->rw);
2154 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2155 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2156 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2157 dsp->scp->bulkStatProgress = hzero;
2159 lock_ReleaseWrite(&dsp->scp->rw);
2161 lock_ReleaseMutex(&dsp->mx);
2164 /* Must be called with the smb_globalLock held */
2165 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2167 cm_scache_t *scp = NULL;
2169 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2170 if (dsp->refCount == 0) {
2171 lock_ObtainMutex(&dsp->mx);
2172 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2173 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2174 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2175 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2176 lock_ReleaseMutex(&dsp->mx);
2177 lock_FinalizeMutex(&dsp->mx);
2179 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2180 dsp->cookie, dsp, scp);
2183 lock_ReleaseMutex(&dsp->mx);
2186 /* do this now to avoid spurious locking hierarchy creation */
2188 cm_ReleaseSCache(scp);
2191 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2193 lock_ObtainWrite(&smb_globalLock);
2194 smb_ReleaseDirSearchNoLock(dsp);
2195 lock_ReleaseWrite(&smb_globalLock);
2198 /* find a dir search structure by cookie value, and return it held */
2199 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2201 smb_dirSearch_t *dsp;
2203 lock_ObtainWrite(&smb_globalLock);
2204 dsp = smb_FindDirSearchNoLock(cookie);
2205 lock_ReleaseWrite(&smb_globalLock);
2209 /* GC some dir search entries, in the address space expected by the specific protocol.
2210 * Must be called with smb_globalLock held; release the lock temporarily.
2212 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2213 void smb_GCDirSearches(int isV3)
2215 smb_dirSearch_t *prevp;
2216 smb_dirSearch_t *dsp;
2217 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2221 victimCount = 0; /* how many have we got so far */
2222 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2223 /* we'll move tp from queue, so
2226 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2227 /* if no one is using this guy, and we're either in the new protocol,
2228 * or we're in the old one and this is a small enough ID to be useful
2229 * to the old protocol, GC this guy.
2231 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2232 /* hold and delete */
2233 lock_ObtainMutex(&dsp->mx);
2234 dsp->flags |= SMB_DIRSEARCH_DELETE;
2235 lock_ReleaseMutex(&dsp->mx);
2236 victimsp[victimCount++] = dsp;
2240 /* don't do more than this */
2241 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2245 /* now release them */
2246 for (i = 0; i < victimCount; i++) {
2247 smb_ReleaseDirSearchNoLock(victimsp[i]);
2251 /* function for allocating a dir search entry. We need these to remember enough context
2252 * since we don't get passed the path from call to call during a directory search.
2254 * Returns a held dir search structure, and bumps the reference count on the vnode,
2255 * since it saves a pointer to the vnode.
2257 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2259 smb_dirSearch_t *dsp;
2265 lock_ObtainWrite(&smb_globalLock);
2268 /* what's the biggest ID allowed in this version of the protocol */
2269 /* TODO: do we really want a non v3 dir search request to wrap
2270 smb_dirSearchCounter? */
2271 maxAllowed = isV3 ? 65535 : 255;
2272 if (smb_dirSearchCounter > maxAllowed)
2273 smb_dirSearchCounter = 1;
2275 start = smb_dirSearchCounter;
2278 /* twice so we have enough tries to find guys we GC after one pass;
2279 * 10 extra is just in case I mis-counted.
2281 if (++counter > 2*maxAllowed+10)
2282 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2284 if (smb_dirSearchCounter > maxAllowed) {
2285 smb_dirSearchCounter = 1;
2287 if (smb_dirSearchCounter == start) {
2289 smb_GCDirSearches(isV3);
2292 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2294 /* don't need to watch for refcount zero and deleted, since
2295 * we haven't dropped the global lock.
2298 ++smb_dirSearchCounter;
2302 dsp = malloc(sizeof(*dsp));
2303 memset(dsp, 0, sizeof(*dsp));
2304 dsp->cookie = smb_dirSearchCounter;
2305 ++smb_dirSearchCounter;
2307 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2308 dsp->lastTime = osi_Time();
2309 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2310 if (!smb_lastDirSearchp)
2311 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2313 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2317 lock_ReleaseWrite(&smb_globalLock);
2321 static smb_packet_t *smb_GetPacket(void)
2325 lock_ObtainWrite(&smb_globalLock);
2326 tbp = smb_packetFreeListp;
2328 smb_packetFreeListp = tbp->nextp;
2329 lock_ReleaseWrite(&smb_globalLock);
2331 tbp = calloc(sizeof(*tbp),1);
2332 tbp->magic = SMB_PACKETMAGIC;
2335 tbp->resumeCode = 0;
2341 tbp->ncb_length = 0;
2344 tbp->stringsp = NULL;
2346 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2351 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2354 tbp = smb_GetPacket();
2355 memcpy(tbp, pkt, sizeof(smb_packet_t));
2356 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2357 tbp->stringsp = NULL;
2359 smb_HoldVC(tbp->vcp);
2363 static NCB *smb_GetNCB(void)
2368 lock_ObtainWrite(&smb_globalLock);
2369 tbp = smb_ncbFreeListp;
2371 smb_ncbFreeListp = tbp->nextp;
2372 lock_ReleaseWrite(&smb_globalLock);
2374 tbp = calloc(sizeof(*tbp),1);
2375 tbp->magic = SMB_NCBMAGIC;
2378 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2380 memset(&tbp->ncb, 0, sizeof(NCB));
2385 static void FreeSMBStrings(smb_packet_t * pkt)
2390 for (s = pkt->stringsp; s; s = ns) {
2394 pkt->stringsp = NULL;
2397 void smb_FreePacket(smb_packet_t *tbp)
2399 smb_vc_t * vcp = NULL;
2400 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2402 lock_ObtainWrite(&smb_globalLock);
2403 tbp->nextp = smb_packetFreeListp;
2404 smb_packetFreeListp = tbp;
2405 tbp->magic = SMB_PACKETMAGIC;
2409 tbp->resumeCode = 0;
2415 tbp->ncb_length = 0;
2417 FreeSMBStrings(tbp);
2418 lock_ReleaseWrite(&smb_globalLock);
2424 static void smb_FreeNCB(NCB *bufferp)
2428 tbp = (smb_ncb_t *) bufferp;
2429 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2431 lock_ObtainWrite(&smb_globalLock);
2432 tbp->nextp = smb_ncbFreeListp;
2433 smb_ncbFreeListp = tbp;
2434 lock_ReleaseWrite(&smb_globalLock);
2437 /* get a ptr to the data part of a packet, and its count */
2438 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2442 unsigned char *afterParmsp;
2444 parmBytes = *smbp->wctp << 1;
2445 afterParmsp = smbp->wctp + parmBytes + 1;
2447 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2448 if (nbytesp) *nbytesp = dataBytes;
2450 /* don't forget to skip the data byte count, since it follows
2451 * the parameters; that's where the "2" comes from below.
2453 return (unsigned char *) (afterParmsp + 2);
2456 /* must set all the returned parameters before playing around with the
2457 * data region, since the data region is located past the end of the
2458 * variable number of parameters.
2460 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2462 unsigned char *afterParmsp;
2464 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2466 *afterParmsp++ = dsize & 0xff;
2467 *afterParmsp = (dsize>>8) & 0xff;
2470 /* return the parm'th parameter in the smbp packet */
2471 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2474 unsigned char *parmDatap;
2476 parmCount = *smbp->wctp;
2478 if (parm >= parmCount) {
2481 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2482 parm, parmCount, smbp->ncb_length);
2483 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2484 parm, parmCount, smbp->ncb_length);
2485 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2486 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2487 osi_panic(s, __FILE__, __LINE__);
2489 parmDatap = smbp->wctp + (2*parm) + 1;
2491 return parmDatap[0] + (parmDatap[1] << 8);
2494 /* return the parm'th parameter in the smbp packet */
2495 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2498 unsigned char *parmDatap;
2500 parmCount = *smbp->wctp;
2502 if (parm >= parmCount) {
2505 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2506 parm, parmCount, smbp->ncb_length);
2507 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2508 parm, parmCount, smbp->ncb_length);
2509 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2510 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2511 osi_panic(s, __FILE__, __LINE__);
2513 parmDatap = smbp->wctp + (2*parm) + 1;
2515 return parmDatap[0];
2518 /* return the parm'th parameter in the smbp packet */
2519 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2522 unsigned char *parmDatap;
2524 parmCount = *smbp->wctp;
2526 if (parm + 1 >= parmCount) {
2529 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2530 parm, parmCount, smbp->ncb_length);
2531 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2532 parm, parmCount, smbp->ncb_length);
2533 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2534 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2535 osi_panic(s, __FILE__, __LINE__);
2537 parmDatap = smbp->wctp + (2*parm) + 1;
2539 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2542 /* return the parm'th parameter in the smbp packet */
2543 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2546 unsigned char *parmDatap;
2548 parmCount = *smbp->wctp;
2550 if (parm * 2 + offset >= parmCount * 2) {
2553 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2554 parm, offset, parmCount, smbp->ncb_length);
2555 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2556 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2557 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2558 parm, offset, parmCount, smbp->ncb_length);
2559 osi_panic(s, __FILE__, __LINE__);
2561 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2563 return parmDatap[0] + (parmDatap[1] << 8);
2566 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2568 unsigned char *parmDatap;
2570 /* make sure we have enough slots */
2571 if (*smbp->wctp <= slot)
2572 *smbp->wctp = slot+1;
2574 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2575 *parmDatap++ = parmValue & 0xff;
2576 *parmDatap = (parmValue>>8) & 0xff;
2579 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2581 unsigned char *parmDatap;
2583 /* make sure we have enough slots */
2584 if (*smbp->wctp <= slot)
2585 *smbp->wctp = slot+2;
2587 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2588 *parmDatap++ = parmValue & 0xff;
2589 *parmDatap++ = (parmValue>>8) & 0xff;
2590 *parmDatap++ = (parmValue>>16) & 0xff;
2591 *parmDatap = (parmValue>>24) & 0xff;
2594 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2596 unsigned char *parmDatap;
2599 /* make sure we have enough slots */
2600 if (*smbp->wctp <= slot)
2601 *smbp->wctp = slot+4;
2603 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2605 *parmDatap++ = *parmValuep++;
2608 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2610 unsigned char *parmDatap;
2612 /* make sure we have enough slots */
2613 if (*smbp->wctp <= slot) {
2614 if (smbp->oddByte) {
2616 *smbp->wctp = slot+1;
2621 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2622 *parmDatap++ = parmValue & 0xff;
2627 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2628 clientchar_t *inPathp)
2630 clientchar_t *lastSlashp;
2631 clientchar_t *streamp = NULL;
2632 clientchar_t *typep = NULL;
2634 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2635 if (lastComponentp) {
2636 *lastComponentp = lastSlashp;
2640 * If the name contains a stream name and a type
2641 * and the stream name is the nul-string and the
2642 * type is $DATA, then strip "::$DATA" from the
2643 * last component string that is returned.
2645 * Otherwise, return the full path name and allow
2646 * the file name to be rejected because it contains
2649 typep = cm_ClientStrRChr(lastSlashp, L':');
2650 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2652 streamp = cm_ClientStrRChr(lastSlashp, L':');
2653 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2657 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2658 osi_LogSaveClientString(smb_logp,streamp),
2659 osi_LogSaveClientString(smb_logp,typep));
2663 if (inPathp == lastSlashp)
2665 *outPathp++ = *inPathp++;
2674 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2675 char **chainpp, int flags)
2678 afs_uint32 type = *inp++;
2681 * The first byte specifies the type of the input string.
2682 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2686 /* Length Counted */
2687 case 0x1: /* Data Block */
2688 case 0x5: /* Variable Block */
2689 cb = *inp++ << 16 | *inp++;
2692 /* Null-terminated string */
2693 case 0x4: /* ASCII */
2694 case 0x3: /* Pathname */
2695 case 0x2: /* Dialect */
2696 cb = sizeof(pktp->data) - (inp - pktp->data);
2697 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2698 #ifdef DEBUG_UNICODE
2701 cb = sizeof(pktp->data);
2706 return NULL; /* invalid input */
2710 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2711 flags |= SMB_STRF_FORCEASCII;
2714 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2717 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2718 char ** chainpp, int flags)
2723 if (!WANTS_UNICODE(pktp))
2724 flags |= SMB_STRF_FORCEASCII;
2727 cb = sizeof(pktp->data) - (inp - pktp->data);
2728 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2729 #ifdef DEBUG_UNICODE
2732 cb = sizeof(pktp->data);
2734 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2735 flags | SMB_STRF_SRCNULTERM);
2738 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2739 size_t cb, char ** chainpp, int flags)
2742 if (!WANTS_UNICODE(pktp))
2743 flags |= SMB_STRF_FORCEASCII;
2746 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2749 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2750 size_t cch, char ** chainpp, int flags)
2755 if (!WANTS_UNICODE(pktp))
2756 flags |= SMB_STRF_FORCEASCII;
2758 cb = cch * sizeof(wchar_t);
2761 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2765 smb_ParseStringBuf(const unsigned char * bufbase,
2766 cm_space_t ** stringspp,
2767 unsigned char *inp, size_t *pcb_max,
2768 char **chainpp, int flags)
2771 if (!(flags & SMB_STRF_FORCEASCII)) {
2773 cm_space_t * spacep;
2776 if (bufbase && ((inp - bufbase) % 2) != 0) {
2777 inp++; /* unicode strings are always word aligned */
2781 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2783 cch_src = *pcb_max / sizeof(wchar_t);
2787 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2794 spacep = cm_GetSpace();
2795 spacep->nextp = *stringspp;
2796 *stringspp = spacep;
2800 *chainpp = inp + sizeof(wchar_t);
2803 *(spacep->wdata) = 0;
2804 return spacep->wdata;
2807 StringCchCopyNW(spacep->wdata,
2808 lengthof(spacep->wdata),
2809 (const clientchar_t *) inp, cch_src);
2812 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2814 return spacep->wdata;
2818 cm_space_t * spacep;
2821 /* Not using Unicode */
2823 *chainpp = inp + strlen(inp) + 1;
2826 spacep = cm_GetSpace();
2827 spacep->nextp = *stringspp;
2828 *stringspp = spacep;
2830 cchdest = lengthof(spacep->wdata);
2831 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2832 spacep->wdata, cchdest);
2834 return spacep->wdata;
2840 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2842 size_t * plen, int flags)
2848 /* we are only calculating the required size */
2855 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2857 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2858 if (!(flags & SMB_STRF_IGNORENUL))
2859 *plen += sizeof(wchar_t);
2861 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2871 cch_str = cm_ClientStrLen(str);
2872 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2875 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2883 /* if outp != NULL ... */
2885 /* Number of bytes left in the buffer.
2887 If outp lies inside the packet data buffer, we assume that the
2888 buffer is the packet data buffer. Otherwise we assume that the
2889 buffer is sizeof(packet->data).
2892 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2893 align = (int)((outp - pktp->data) % 2);
2894 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2896 align = (int)(((size_t) outp) % 2);
2897 buffersize = (int)sizeof(pktp->data);
2902 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2908 if (*str == _C('\0')) {
2910 if (buffersize < sizeof(wchar_t))
2913 *((wchar_t *) outp) = L'\0';
2914 if (plen && !(flags & SMB_STRF_IGNORENUL))
2915 *plen += sizeof(wchar_t);
2916 return outp + sizeof(wchar_t);
2919 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2921 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2922 osi_LogSaveClientString(smb_logp, str),
2928 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2930 return outp + sizeof(wchar_t) * nchars;
2938 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2941 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2943 return outp + cch_dest;
2947 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2953 tlen = inp[0] + (inp[1]<<8);
2954 inp += 2; /* skip length field */
2957 *chainpp = inp + tlen;
2966 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2970 if (*inp++ != 0x1) return NULL;
2971 tlen = inp[0] + (inp[1]<<8);
2972 inp += 2; /* skip length field */
2975 *chainpp = inp + tlen;
2978 if (lengthp) *lengthp = tlen;
2983 /* format a packet as a response */
2984 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2989 outp = (smb_t *) op;
2991 /* zero the basic structure through the smb_wct field, and zero the data
2992 * size field, assuming that wct stays zero; otherwise, you have to
2993 * explicitly set the data size field, too.
2995 inSmbp = (smb_t *) inp;
2996 memset(outp, 0, sizeof(smb_t)+2);
3002 outp->com = inSmbp->com;
3003 outp->tid = inSmbp->tid;
3004 outp->pid = inSmbp->pid;
3005 outp->uid = inSmbp->uid;
3006 outp->mid = inSmbp->mid;
3007 outp->res[0] = inSmbp->res[0];
3008 outp->res[1] = inSmbp->res[1];
3009 op->inCom = inSmbp->com;
3011 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3012 #ifdef SEND_CANONICAL_PATHNAMES
3013 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3015 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3017 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3018 outp->flg2 |= SMB_FLAGS2_UNICODE;
3021 /* copy fields in generic packet area */
3022 op->wctp = &outp->wct;
3025 /* send a (probably response) packet; vcp tells us to whom to send it.
3026 * we compute the length by looking at wct and bcc fields.
3028 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3038 ncbp = smb_GetNCB();
3042 memset(ncbp, 0, sizeof(NCB));
3044 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3045 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3046 extra += tp[0] + (tp[1]<<8);
3047 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3048 extra += 3; /* wct and length fields */
3050 ncbp->ncb_length = extra; /* bytes to send */
3051 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3052 ncbp->ncb_lana_num = vcp->lana;
3053 ncbp->ncb_command = NCBSEND; /* op means send data */
3054 ncbp->ncb_buffer = (char *) inp;/* packet */
3055 code = Netbios(ncbp);
3058 const char * s = ncb_error_string(code);
3059 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3060 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3062 lock_ObtainMutex(&vcp->mx);
3063 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3064 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3066 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3067 lock_ReleaseMutex(&vcp->mx);
3068 lock_ObtainWrite(&smb_globalLock);
3069 dead_sessions[vcp->session] = TRUE;
3070 lock_ReleaseWrite(&smb_globalLock);
3071 smb_CleanupDeadVC(vcp);
3073 lock_ReleaseMutex(&vcp->mx);
3081 void smb_MapNTError(long code, unsigned long *NTStatusp, afs_uint32 redir)
3083 unsigned long NTStatus;
3085 /* map CM_ERROR_* errors to NT 32-bit status codes */
3086 /* NT Status codes are listed in ntstatus.h not winerror.h */
3090 else if (code == CM_ERROR_NOSUCHCELL) {
3091 NTStatus = 0xC0000034L; /* Name not found */
3093 else if (code == CM_ERROR_NOSUCHVOLUME) {
3094 NTStatus = 0xC0000034L; /* Name not found */
3096 else if (code == CM_ERROR_TIMEDOUT) {
3098 NTStatus = 0xC0020052L; /* RPC_NT_COMM_FAILURE */
3101 NTStatus = 0xC00000CFL; /* Sharing Paused */
3103 /* Do not send Timeout to the SMB redirector.
3104 * It causes the redirector to drop the connection */
3105 NTStatus = 0x00000102L; /* Timeout */
3106 /* do not send Retry to the SMB redirector.
3107 * It believes the error comes from the transport
3108 * layer not from the SMB server. */
3109 NTStatus = 0xC000022DL; /* Retry */
3111 NTStatus = 0xC00000B5L; /* I/O Timeout */
3115 else if (code == CM_ERROR_RETRY) {
3117 NTStatus = 0xC000022DL; /* Retry */
3120 NTStatus = 0xC000022DL; /* Retry */
3122 NTStatus = 0xC00000B5L; /* I/O Timeout */
3126 else if (code == CM_ERROR_NOACCESS) {
3127 NTStatus = 0xC0000022L; /* Access denied */
3129 else if (code == CM_ERROR_READONLY) {
3130 NTStatus = 0xC00000A2L; /* Write protected */
3132 else if (code == CM_ERROR_NOSUCHFILE ||
3133 code == CM_ERROR_BPLUS_NOMATCH) {
3134 NTStatus = 0xC0000034L; /* Name not found */
3136 else if (code == CM_ERROR_NOSUCHPATH) {
3137 NTStatus = 0xC000003AL; /* Object path not found */
3139 else if (code == CM_ERROR_TOOBIG) {
3140 NTStatus = 0xC000007BL; /* Invalid image format */
3142 else if (code == CM_ERROR_INVAL) {
3143 NTStatus = 0xC000000DL; /* Invalid parameter */
3145 else if (code == CM_ERROR_BADFD) {
3146 NTStatus = 0xC0000008L; /* Invalid handle */
3148 else if (code == CM_ERROR_BADFDOP) {
3149 NTStatus = 0xC0000022L; /* Access denied */
3151 else if (code == CM_ERROR_UNKNOWN) {
3152 NTStatus = 0xC0000022L; /* Access denied */
3154 else if (code == CM_ERROR_EXISTS) {
3155 NTStatus = 0xC0000035L; /* Object name collision */
3157 else if (code == CM_ERROR_NOTEMPTY) {
3158 NTStatus = 0xC0000101L; /* Directory not empty */
3160 else if (code == CM_ERROR_CROSSDEVLINK) {
3161 NTStatus = 0xC00000D4L; /* Not same device */
3163 else if (code == CM_ERROR_NOTDIR) {
3164 NTStatus = 0xC0000103L; /* Not a directory */
3166 else if (code == CM_ERROR_ISDIR) {
3167 NTStatus = 0xC00000BAL; /* File is a directory */
3169 else if (code == CM_ERROR_BADOP) {
3171 /* I have no idea where this comes from */
3172 NTStatus = 0xC09820FFL; /* SMB no support */
3174 NTStatus = 0xC00000BBL; /* Not supported */
3175 #endif /* COMMENT */
3177 else if (code == CM_ERROR_BADSHARENAME) {
3178 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3180 else if (code == CM_ERROR_NOIPC) {
3182 NTStatus = 0xC0000022L; /* Access Denied */
3184 NTStatus = 0xC000013DL; /* Remote Resources */
3187 else if (code == CM_ERROR_CLOCKSKEW ||
3188 code == RXKADNOAUTH) {
3189 NTStatus = 0xC0000133L; /* Time difference at DC */
3191 else if (code == CM_ERROR_BADTID) {
3192 NTStatus = 0xC0982005L; /* SMB bad TID */
3194 else if (code == CM_ERROR_USESTD) {
3195 NTStatus = 0xC09820FBL; /* SMB use standard */
3197 else if (code == CM_ERROR_QUOTA) {
3199 * AFS Redirector does not support Windows quota
3200 * interface. Always report disk full instead.
3203 NTStatus = 0xC000007FL; /* Disk full */
3205 NTStatus = 0xC0000044L; /* Quota exceeded */
3207 else if (code == CM_ERROR_SPACE) {
3208 NTStatus = 0xC000007FL; /* Disk full */
3210 else if (code == CM_ERROR_ATSYS) {
3211 NTStatus = 0xC0000033L; /* Object name invalid */
3213 else if (code == CM_ERROR_BADNTFILENAME) {
3214 NTStatus = 0xC0000033L; /* Object name invalid */
3216 else if (code == CM_ERROR_WOULDBLOCK) {
3217 NTStatus = 0xC00000D8L; /* Can't wait */
3219 else if (code == CM_ERROR_SHARING_VIOLATION) {
3220 NTStatus = 0xC0000043L; /* Sharing violation */
3222 else if (code == CM_ERROR_LOCK_CONFLICT) {
3223 NTStatus = 0xC0000054L; /* Lock conflict */
3225 else if (code == CM_ERROR_PARTIALWRITE) {
3226 NTStatus = 0xC000007FL; /* Disk full */
3228 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3229 NTStatus = 0xC0000023L; /* Buffer too small */
3231 else if (code == CM_ERROR_BUFFER_OVERFLOW) {
3232 NTStatus = 0x80000005L; /* Buffer overflow */
3234 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3235 NTStatus = 0xC0000035L; /* Object name collision */
3237 else if (code == CM_ERROR_BADPASSWORD) {
3238 NTStatus = 0xC000006DL; /* unknown username or bad password */
3240 else if (code == CM_ERROR_BADLOGONTYPE) {
3241 NTStatus = 0xC000015BL; /* logon type not granted */
3243 else if (code == CM_ERROR_GSSCONTINUE) {
3244 NTStatus = 0xC0000016L; /* more processing required */
3246 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3248 NTStatus = 0xC0000280L; /* reparse point not resolved */
3250 NTStatus = 0xC0000022L; /* Access Denied */
3253 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3254 NTStatus = 0xC0000257L; /* Path Not Covered */
3256 else if (code == CM_ERROR_ALLBUSY) {
3258 NTStatus = 0xC000022DL; /* Retry */
3260 NTStatus = 0xC0020018L; /* RPC_NT_SERVER_TOO_BUSY */
3263 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3265 NTStatus = 0xC000003AL; /* Path not found */
3267 NTStatus = 0xC0020017L; /* RPC_NT_SERVER_UNAVAILABLE */
3270 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3271 NTStatus = 0xC0000322L; /* No Kerberos key */
3273 else if (code == CM_ERROR_BAD_LEVEL) {
3274 NTStatus = 0xC0000148L; /* Invalid Level */
3276 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3277 NTStatus = 0xC000007EL; /* Range Not Locked */
3279 else if (code == CM_ERROR_NOSUCHDEVICE) {
3280 NTStatus = 0xC000000EL; /* No Such Device */
3282 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3283 NTStatus = 0xC0000055L; /* Lock Not Granted */
3285 else if (code == ENOMEM) {
3286 NTStatus = 0xC0000017L; /* Out of Memory */
3288 else if (code == CM_ERROR_RPC_MOREDATA) {
3289 NTStatus = 0x80000005L; /* Buffer overflow */
3293 sprintf(foo, "No mapping for 0x%X using 0xC0982001\r\n", code);
3294 OutputDebugString(foo);
3295 NTStatus = 0xC0982001L; /* SMB non-specific error */
3298 *NTStatusp = NTStatus;
3299 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3303 * NTSTATUS <-> Win32 Error Translation
3304 * http://support.microsoft.com/kb/113996
3306 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3308 unsigned long Win32E;
3310 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3314 else if (code == CM_ERROR_NOSUCHCELL) {
3315 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3317 else if (code == CM_ERROR_NOSUCHVOLUME) {
3318 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3320 else if (code == CM_ERROR_TIMEDOUT) {
3322 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3324 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3327 else if (code == CM_ERROR_RETRY) {
3328 Win32E = ERROR_RETRY; /* Retry */
3330 else if (code == CM_ERROR_NOACCESS) {
3331 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3333 else if (code == CM_ERROR_READONLY) {
3334 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3336 else if (code == CM_ERROR_NOSUCHFILE ||
3337 code == CM_ERROR_BPLUS_NOMATCH) {
3338 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3340 else if (code == CM_ERROR_NOSUCHPATH) {
3341 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3343 else if (code == CM_ERROR_TOOBIG) {
3344 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3346 else if (code == CM_ERROR_INVAL) {
3347 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3349 else if (code == CM_ERROR_BADFD) {
3350 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3352 else if (code == CM_ERROR_BADFDOP) {
3353 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3355 else if (code == CM_ERROR_UNKNOWN) {
3356 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3358 else if (code == CM_ERROR_EXISTS) {
3359 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3361 else if (code == CM_ERROR_NOTEMPTY) {
3362 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3364 else if (code == CM_ERROR_CROSSDEVLINK) {
3365 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3367 else if (code == CM_ERROR_NOTDIR) {
3368 Win32E = ERROR_DIRECTORY; /* Not a directory */
3370 else if (code == CM_ERROR_ISDIR) {
3371 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3373 else if (code == CM_ERROR_BADOP) {
3374 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3376 else if (code == CM_ERROR_BADSHARENAME) {
3377 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3379 else if (code == CM_ERROR_NOIPC) {
3381 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3383 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3386 else if (code == CM_ERROR_CLOCKSKEW ||
3387 code == RXKADNOAUTH) {
3388 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3390 else if (code == CM_ERROR_BADTID) {
3391 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3393 else if (code == CM_ERROR_USESTD) {
3394 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3396 else if (code == CM_ERROR_QUOTA) {
3397 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3399 else if (code == CM_ERROR_SPACE) {
3400 Win32E = ERROR_DISK_FULL; /* Disk full */
3402 else if (code == CM_ERROR_ATSYS) {
3403 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3405 else if (code == CM_ERROR_BADNTFILENAME) {
3406 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3408 else if (code == CM_ERROR_WOULDBLOCK) {
3409 Win32E = WAIT_TIMEOUT; /* Can't wait */
3411 else if (code == CM_ERROR_SHARING_VIOLATION) {
3412 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3414 else if (code == CM_ERROR_LOCK_CONFLICT) {
3415 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3417 else if (code == CM_ERROR_PARTIALWRITE) {
3418 Win32E = ERROR_DISK_FULL; /* Disk full */
3420 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3421 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3423 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3424 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3426 else if (code == CM_ERROR_BADPASSWORD) {
3427 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3429 else if (code == CM_ERROR_BADLOGONTYPE) {
3430 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3432 else if (code == CM_ERROR_GSSCONTINUE) {
3433 Win32E = ERROR_MORE_DATA; /* more processing required */
3435 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3437 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3439 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3442 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3443 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3445 else if (code == CM_ERROR_ALLBUSY) {
3446 Win32E = ERROR_RETRY; /* Retry */
3448 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3449 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3451 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3452 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3454 else if (code == CM_ERROR_BAD_LEVEL) {
3455 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3457 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3458 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3460 else if (code == CM_ERROR_NOSUCHDEVICE) {
3461 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3463 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3464 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3466 else if (code == ENOMEM) {
3467 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3469 else if (code == CM_ERROR_RPC_MOREDATA) {
3470 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3473 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3477 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3480 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3481 unsigned char *classp)
3483 unsigned char class;
3484 unsigned short error;
3486 /* map CM_ERROR_* errors to SMB errors */
3487 if (code == CM_ERROR_NOSUCHCELL) {
3489 error = 3; /* bad path */
3491 else if (code == CM_ERROR_NOSUCHVOLUME) {
3493 error = 3; /* bad path */
3495 else if (code == CM_ERROR_TIMEDOUT) {
3497 error = 81; /* server is paused */
3499 else if (code == CM_ERROR_RETRY) {
3500 class = 2; /* shouldn't happen */
3503 else if (code == CM_ERROR_NOACCESS) {
3505 error = 4; /* bad access */
3507 else if (code == CM_ERROR_READONLY) {
3509 error = 19; /* read only */
3511 else if (code == CM_ERROR_NOSUCHFILE ||
3512 code == CM_ERROR_BPLUS_NOMATCH) {
3514 error = 2; /* ENOENT! */
3516 else if (code == CM_ERROR_NOSUCHPATH) {
3518 error = 3; /* Bad path */
3520 else if (code == CM_ERROR_TOOBIG) {
3522 error = 11; /* bad format */
3524 else if (code == CM_ERROR_INVAL) {
3525 class = 2; /* server non-specific error code */
3528 else if (code == CM_ERROR_BADFD) {
3530 error = 6; /* invalid file handle */
3532 else if (code == CM_ERROR_BADFDOP) {
3533 class = 1; /* invalid op on FD */
3536 else if (code == CM_ERROR_EXISTS) {
3538 error = 80; /* file already exists */
3540 else if (code == CM_ERROR_NOTEMPTY) {
3542 error = 5; /* delete directory not empty */
3544 else if (code == CM_ERROR_CROSSDEVLINK) {
3546 error = 17; /* EXDEV */
3548 else if (code == CM_ERROR_NOTDIR) {
3549 class = 1; /* bad path */
3552 else if (code == CM_ERROR_ISDIR) {
3553 class = 1; /* access denied; DOS doesn't have a good match */
3556 else if (code == CM_ERROR_BADOP) {
3560 else if (code == CM_ERROR_BADSHARENAME) {
3564 else if (code == CM_ERROR_NOIPC) {
3566 error = 4; /* bad access */
3568 else if (code == CM_ERROR_CLOCKSKEW) {
3569 class = 1; /* invalid function */
3572 else if (code == CM_ERROR_BADTID) {
3576 else if (code == CM_ERROR_USESTD) {
3580 else if (code == CM_ERROR_REMOTECONN) {
3584 else if (code == CM_ERROR_QUOTA) {
3585 if (vcp->flags & SMB_VCFLAG_USEV3) {
3587 error = 39; /* disk full */
3591 error = 5; /* access denied */
3594 else if (code == CM_ERROR_SPACE) {
3595 if (vcp->flags & SMB_VCFLAG_USEV3) {
3597 error = 39; /* disk full */
3601 error = 5; /* access denied */
3604 else if (code == CM_ERROR_PARTIALWRITE) {
3606 error = 39; /* disk full */
3608 else if (code == CM_ERROR_ATSYS) {
3610 error = 2; /* ENOENT */
3612 else if (code == CM_ERROR_WOULDBLOCK) {
3614 error = 33; /* lock conflict */
3616 else if (code == CM_ERROR_LOCK_CONFLICT) {
3618 error = 33; /* lock conflict */
3620 else if (code == CM_ERROR_SHARING_VIOLATION) {
3622 error = 33; /* lock conflict */
3624 else if (code == CM_ERROR_NOFILES) {
3626 error = 18; /* no files in search */
3628 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3630 error = 183; /* Samba uses this */
3632 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3633 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3635 error = 2; /* bad password */
3637 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3639 error = 3; /* bad path */
3648 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3651 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3653 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3654 return CM_ERROR_BADOP;
3658 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3660 unsigned short EchoCount, i;
3661 char *data, *outdata;
3664 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3666 for (i=1; i<=EchoCount; i++) {
3667 data = smb_GetSMBData(inp, &dataSize);
3668 smb_SetSMBParm(outp, 0, i);
3669 smb_SetSMBDataLength(outp, dataSize);
3670 outdata = smb_GetSMBData(outp, NULL);
3671 memcpy(outdata, data, dataSize);
3672 smb_SendPacket(vcp, outp);
3678 /* SMB_COM_READ_RAW */
3679 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3682 long count, minCount, finalCount;
3686 smb_t *smbp = (smb_t*) inp;
3688 cm_user_t *userp = NULL;
3691 char *rawBuf = NULL;
3696 fd = smb_GetSMBParm(inp, 0);
3697 count = smb_GetSMBParm(inp, 3);
3698 minCount = smb_GetSMBParm(inp, 4);
3699 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3701 if (*inp->wctp == 10) {
3702 /* we were sent a request with 64-bit file offsets */
3703 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3705 if (LargeIntegerLessThanZero(offset)) {
3706 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3710 /* we were sent a request with 32-bit file offsets */
3711 offset.HighPart = 0;
3714 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3715 fd, offset.HighPart, offset.LowPart, count);
3717 fidp = smb_FindFID(vcp, fd, 0);
3719 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3723 lock_ObtainMutex(&fidp->mx);
3725 lock_ReleaseMutex(&fidp->mx);
3726 smb_ReleaseFID(fidp);
3727 return CM_ERROR_BADFD;
3730 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3731 lock_ReleaseMutex(&fidp->mx);
3732 smb_CloseFID(vcp, fidp, NULL, 0);
3733 code = CM_ERROR_NOSUCHFILE;
3739 LARGE_INTEGER LOffset, LLength;
3742 key = cm_GenerateKey(vcp->vcID, pid, fd);
3744 LOffset.HighPart = offset.HighPart;
3745 LOffset.LowPart = offset.LowPart;
3746 LLength.HighPart = 0;
3747 LLength.LowPart = count;
3749 lock_ObtainWrite(&fidp->scp->rw);
3750 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3751 lock_ReleaseWrite(&fidp->scp->rw);
3754 lock_ReleaseMutex(&fidp->mx);
3758 lock_ObtainMutex(&smb_RawBufLock);
3760 /* Get a raw buf, from head of list */
3761 rawBuf = smb_RawBufs;
3762 smb_RawBufs = *(char **)smb_RawBufs;
3764 lock_ReleaseMutex(&smb_RawBufLock);
3766 lock_ReleaseMutex(&fidp->mx);
3770 if (fidp->flags & SMB_FID_IOCTL)
3772 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3774 /* Give back raw buffer */
3775 lock_ObtainMutex(&smb_RawBufLock);
3776 *((char **) rawBuf) = smb_RawBufs;
3778 smb_RawBufs = rawBuf;
3779 lock_ReleaseMutex(&smb_RawBufLock);
3782 lock_ReleaseMutex(&fidp->mx);
3783 smb_ReleaseFID(fidp);
3786 lock_ReleaseMutex(&fidp->mx);
3788 userp = smb_GetUserFromVCP(vcp, inp);
3790 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3796 cm_ReleaseUser(userp);
3799 smb_ReleaseFID(fidp);
3803 memset(ncbp, 0, sizeof(NCB));
3805 ncbp->ncb_length = (unsigned short) finalCount;
3806 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3807 ncbp->ncb_lana_num = vcp->lana;
3808 ncbp->ncb_command = NCBSEND;
3809 ncbp->ncb_buffer = rawBuf;
3811 code = Netbios(ncbp);
3813 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3816 /* Give back raw buffer */
3817 lock_ObtainMutex(&smb_RawBufLock);
3818 *((char **) rawBuf) = smb_RawBufs;
3820 smb_RawBufs = rawBuf;
3821 lock_ReleaseMutex(&smb_RawBufLock);
3827 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3829 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3834 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3836 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3841 /* SMB_COM_NEGOTIATE */
3842 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3849 int VistaProtoIndex;
3850 int protoIndex; /* index we're using */
3855 char protocol_array[10][1024]; /* protocol signature of the client */
3856 int caps; /* capabilities */
3859 TIME_ZONE_INFORMATION tzi;
3861 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3864 namep = smb_GetSMBData(inp, &dbytes);
3867 coreProtoIndex = -1; /* not found */
3870 VistaProtoIndex = -1;
3871 while(namex < dbytes) {
3872 osi_Log1(smb_logp, "Protocol %s",
3873 osi_LogSaveString(smb_logp, namep+1));
3874 strcpy(protocol_array[tcounter], namep+1);
3876 /* namep points at the first protocol, or really, a 0x02
3877 * byte preceding the null-terminated ASCII name.
3879 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3880 coreProtoIndex = tcounter;
3882 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3883 v3ProtoIndex = tcounter;
3885 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3886 NTProtoIndex = tcounter;
3888 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3889 VistaProtoIndex = tcounter;
3892 /* compute size of protocol entry */
3893 entryLength = (int)strlen(namep+1);
3894 entryLength += 2; /* 0x02 bytes and null termination */
3896 /* advance over this protocol entry */
3897 namex += entryLength;
3898 namep += entryLength;
3899 tcounter++; /* which proto entry we're looking at */
3902 lock_ObtainMutex(&vcp->mx);
3904 if (VistaProtoIndex != -1) {
3905 protoIndex = VistaProtoIndex;
3906 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3909 if (NTProtoIndex != -1) {
3910 protoIndex = NTProtoIndex;
3911 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3913 else if (v3ProtoIndex != -1) {
3914 protoIndex = v3ProtoIndex;
3915 vcp->flags |= SMB_VCFLAG_USEV3;
3917 else if (coreProtoIndex != -1) {
3918 protoIndex = coreProtoIndex;
3919 vcp->flags |= SMB_VCFLAG_USECORE;
3921 else protoIndex = -1;
3922 lock_ReleaseMutex(&vcp->mx);
3924 if (protoIndex == -1)
3925 return CM_ERROR_INVAL;
3926 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3927 smb_SetSMBParm(outp, 0, protoIndex);
3928 if (smb_authType != SMB_AUTH_NONE) {
3929 smb_SetSMBParmByte(outp, 1,
3930 NEGOTIATE_SECURITY_USER_LEVEL |
3931 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3933 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3935 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3936 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3937 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3938 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3939 /* The session key is not a well documented field however most clients
3940 * will echo back the session key to the server. Currently we are using
3941 * the same value for all sessions. We should generate a random value
3942 * and store it into the vcp
3944 smb_SetSMBParmLong(outp, 7, 0x1a2b3c4d); /* session key */
3946 * Tried changing the capabilities to support for W2K - defect 117695
3947 * Maybe something else needs to be changed here?
3951 smb_SetSMBParmLong(outp, 9, 0x43fd);
3953 smb_SetSMBParmLong(outp, 9, 0x251);
3956 * 32-bit error codes *
3962 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3964 NTNEGOTIATE_CAPABILITY_DFS |
3966 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3967 NTNEGOTIATE_CAPABILITY_NTFIND |
3968 NTNEGOTIATE_CAPABILITY_RAWMODE |
3969 NTNEGOTIATE_CAPABILITY_NTSMB;
3971 if ( smb_authType == SMB_AUTH_EXTENDED )
3972 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3975 if ( smb_UseUnicode ) {
3976 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3980 smb_SetSMBParmLong(outp, 9, caps);
3982 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3983 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3984 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3986 GetTimeZoneInformation(&tzi);
3987 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3989 if (smb_authType == SMB_AUTH_NTLM) {
3990 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3991 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3992 /* paste in encryption key */
3993 datap = smb_GetSMBData(outp, NULL);
3994 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3995 /* and the faux domain name */
3996 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3997 datap + MSV1_0_CHALLENGE_LENGTH,
3998 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3999 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
4000 void * secBlob = NULL;
4001 int secBlobLength = 0;
4003 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
4006 * The SMB specification permits the server to save a round trip
4007 * in the GSS negotiation by sending an initial security blob.
4008 * Unfortunately, doing so trips a bug in Windows 7 and Server 2008 R2
4009 * whereby the SMB 1.x redirector drops the blob on the floor after
4010 * the first connection to the server and simply attempts to reuse
4011 * the previous authentication context. This bug can be avoided by
4012 * the server sending no security blob in the SMB_COM_NEGOTIATE
4013 * response. This forces the client to send an initial GSS init_sec_context
4014 * blob under all circumstances which works around the bug in Microsoft's
4017 * Do not call smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
4020 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
4021 datap = smb_GetSMBData(outp, NULL);
4023 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
4024 datap += sizeof(smb_ServerGUID);
4027 memcpy(datap, secBlob, secBlobLength);
4029 datap += sizeof(secBlobLength);
4032 smb_SetSMBParmByte(outp, 16, 0);/* Challenge length */
4033 smb_SetSMBDataLength(outp, smb_ServerDomainNameLength);
4034 datap = smb_GetSMBData(outp, NULL);
4035 /* the faux domain name */
4036 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4038 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4041 else if (v3ProtoIndex != -1) {
4042 smb_SetSMBParm(outp, 0, protoIndex);
4044 /* NOTE: Extended authentication cannot be negotiated with v3
4045 * therefore we fail over to NTLM
4047 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4048 smb_SetSMBParm(outp, 1,
4049 NEGOTIATE_SECURITY_USER_LEVEL |
4050 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
4052 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4054 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4055 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
4056 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
4057 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
4058 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
4059 smb_SetSMBParm(outp, 7, 1);
4061 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
4062 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
4063 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
4065 GetTimeZoneInformation(&tzi);
4066 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
4068 /* NOTE: Extended authentication cannot be negotiated with v3
4069 * therefore we fail over to NTLM
4071 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4072 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
4073 smb_SetSMBParm(outp, 12, 0); /* resvd */
4074 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
4075 datap = smb_GetSMBData(outp, NULL);
4076 /* paste in a new encryption key */
4077 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4078 /* and the faux domain name */
4079 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4080 datap + MSV1_0_CHALLENGE_LENGTH,
4081 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4083 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4084 smb_SetSMBParm(outp, 12, 0); /* resvd */
4085 smb_SetSMBDataLength(outp, 0);
4088 else if (coreProtoIndex != -1) { /* not really supported anymore */
4089 smb_SetSMBParm(outp, 0, protoIndex);
4090 smb_SetSMBDataLength(outp, 0);
4095 void smb_CheckVCs(void)
4097 smb_vc_t * vcp, *nextp;
4098 smb_packet_t * outp = smb_GetPacket();
4101 lock_ObtainWrite(&smb_rctLock);
4102 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4104 if (vcp->magic != SMB_VC_MAGIC)
4105 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4106 __FILE__, __LINE__);
4108 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4110 smb_HoldVCNoLock(vcp);
4113 * obtain a reference to 'nextp' now because we drop the
4114 * smb_rctLock later and the list contents could change
4115 * or 'vcp' could be destroyed when released.
4119 smb_HoldVCNoLock(nextp);
4121 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4122 smb_ReleaseVCNoLock(vcp);
4126 smb_FormatResponsePacket(vcp, NULL, outp);
4127 smbp = (smb_t *)outp;
4128 outp->inCom = smbp->com = 0x2b /* Echo */;
4136 smb_SetSMBParm(outp, 0, 0);
4137 smb_SetSMBDataLength(outp, 0);
4138 lock_ReleaseWrite(&smb_rctLock);
4140 smb_SendPacket(vcp, outp);
4142 lock_ObtainWrite(&smb_rctLock);
4143 smb_ReleaseVCNoLock(vcp);
4145 lock_ReleaseWrite(&smb_rctLock);
4146 smb_FreePacket(outp);
4149 void smb_Daemon(void *parmp)
4151 afs_uint32 count = 0;
4152 smb_username_t **unpp;
4155 while(smbShutdownFlag == 0) {
4159 if (smbShutdownFlag == 1)
4162 if ((count % 72) == 0) { /* every five minutes */
4164 time_t old_localZero = smb_localZero;
4166 /* Initialize smb_localZero */
4167 myTime.tm_isdst = -1; /* compute whether on DST or not */
4168 myTime.tm_year = 70;
4174 smb_localZero = mktime(&myTime);
4176 #ifdef AFS_FREELANCE
4177 if ( smb_localZero != old_localZero )
4178 cm_noteLocalMountPointChange(FALSE);
4184 /* GC smb_username_t objects that will no longer be used */
4186 lock_ObtainWrite(&smb_rctLock);
4187 for ( unpp=&usernamesp; *unpp; ) {
4189 smb_username_t *unp;
4191 lock_ObtainMutex(&(*unpp)->mx);
4192 if ( (*unpp)->refCount > 0 ||
4193 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4194 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4196 else if (!smb_LogoffTokenTransfer ||
4197 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4199 lock_ReleaseMutex(&(*unpp)->mx);
4207 lock_FinalizeMutex(&unp->mx);
4213 cm_ReleaseUser(userp);
4215 unpp = &(*unpp)->nextp;
4218 lock_ReleaseWrite(&smb_rctLock);
4220 /* XXX GC dir search entries */
4224 void smb_WaitingLocksDaemon()
4226 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4227 smb_waitingLock_t *wl, *wlNext;
4230 smb_packet_t *inp, *outp;
4234 while (smbShutdownFlag == 0) {
4235 lock_ObtainWrite(&smb_globalLock);
4236 nwlRequest = smb_allWaitingLocks;
4237 if (nwlRequest == NULL) {
4238 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4243 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4250 lock_ObtainWrite(&smb_globalLock);
4252 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4254 wlRequest = nwlRequest;
4255 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4256 lock_ReleaseWrite(&smb_globalLock);
4260 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4261 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4264 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4265 code = CM_ERROR_LOCK_NOT_GRANTED;
4269 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4271 /* wl->state is either _DONE or _WAITING. _ERROR
4272 would no longer be on the queue. */
4273 code = cm_RetryLock( wl->lockp,
4274 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4277 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4278 } else if (code != CM_ERROR_WOULDBLOCK) {
4279 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4284 if (code == CM_ERROR_WOULDBLOCK) {
4287 if (wlRequest->msTimeout != 0xffffffff
4288 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4300 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4303 scp = wlRequest->scp;
4304 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4308 lock_ObtainWrite(&scp->rw);
4310 for (wl = wlRequest->locks; wl; wl = wlNext) {
4311 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4313 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4314 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4315 wl->LLength, wl->key, 0, NULL, &req);
4317 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4322 lock_ReleaseWrite(&scp->rw);
4326 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4329 for (wl = wlRequest->locks; wl; wl = wlNext) {
4330 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4331 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4336 vcp = wlRequest->vcp;
4337 inp = wlRequest->inp;
4338 outp = wlRequest->outp;
4339 ncbp = smb_GetNCB();
4340 ncbp->ncb_length = inp->ncb_length;
4341 inp->spacep = cm_GetSpace();
4343 /* Remove waitingLock from list */
4344 lock_ObtainWrite(&smb_globalLock);
4345 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4347 lock_ReleaseWrite(&smb_globalLock);
4349 /* Resume packet processing */
4351 smb_SetSMBDataLength(outp, 0);
4352 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4353 outp->resumeCode = code;
4355 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4358 cm_FreeSpace(inp->spacep);
4359 smb_FreePacket(inp);
4360 smb_FreePacket(outp);
4362 cm_ReleaseSCache(wlRequest->scp);
4365 } while (nwlRequest && smbShutdownFlag == 0);
4370 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4372 osi_Log0(smb_logp, "SMB receive get disk attributes");
4374 smb_SetSMBParm(outp, 0, 32000);
4375 smb_SetSMBParm(outp, 1, 64);
4376 smb_SetSMBParm(outp, 2, 1024);
4377 smb_SetSMBParm(outp, 3, 30000);
4378 smb_SetSMBParm(outp, 4, 0);
4379 smb_SetSMBDataLength(outp, 0);
4383 /* SMB_COM_TREE_CONNECT */
4384 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4388 unsigned short newTid;
4389 clientchar_t shareName[AFSPATHMAX];
4390 clientchar_t *sharePath;
4393 clientchar_t *pathp;
4396 osi_Log0(smb_logp, "SMB receive tree connect");
4398 /* parse input parameters */
4401 tbp = smb_GetSMBData(inp, NULL);
4402 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4404 return CM_ERROR_BADSMB;
4406 tp = cm_ClientStrRChr(pathp, '\\');
4408 return CM_ERROR_BADSMB;
4409 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4411 lock_ObtainMutex(&vcp->mx);
4412 newTid = vcp->tidCounter++;
4413 lock_ReleaseMutex(&vcp->mx);
4415 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4416 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4418 return CM_ERROR_BADSMB;
4419 userp = smb_GetUserFromUID(uidp);
4420 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4421 smb_ReleaseUID(uidp);
4423 smb_ReleaseTID(tidp, FALSE);
4424 return CM_ERROR_BADSHARENAME;
4426 lock_ObtainMutex(&tidp->mx);
4427 tidp->userp = userp;
4428 tidp->pathname = sharePath;
4429 lock_ReleaseMutex(&tidp->mx);
4430 smb_ReleaseTID(tidp, FALSE);
4432 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4433 smb_SetSMBParm(rsp, 1, newTid);
4434 smb_SetSMBDataLength(rsp, 0);
4436 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4440 /* set maskp to the mask part of the incoming path.
4441 * Mask is 11 bytes long (8.3 with the dot elided).
4442 * Returns true if succeeds with a valid name, otherwise it does
4443 * its best, but returns false.
4445 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4453 /* starts off valid */
4456 /* mask starts out all blanks */
4457 memset(maskp, ' ', 11);
4460 /* find last backslash, or use whole thing if there is none */
4461 tp = cm_ClientStrRChr(pathp, '\\');
4465 tp++; /* skip slash */
4469 /* names starting with a dot are illegal */
4477 if (tc == '.' || tc == '"')
4485 /* if we get here, tp point after the dot */
4486 up = maskp+8; /* ext goes here */
4493 if (tc == '.' || tc == '"')
4496 /* copy extension if not too long */
4506 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4508 clientchar_t umask[11];
4516 /* XXX redo this, calling cm_MatchMask with a converted mask */
4518 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4522 /* otherwise, we have a valid 8.3 name; see if we have a match,
4523 * treating '?' as a wildcard in maskp (but not in the file name).
4525 tp1 = umask; /* real name, in mask format */
4526 tp2 = maskp; /* mask, in mask format */
4527 for(i=0; i<11; i++) {
4528 tc1 = *tp1++; /* clientchar_t from real name */
4529 tc2 = *tp2++; /* clientchar_t from mask */
4530 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4531 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4534 if (tc2 == '?' && tc1 != ' ')
4541 /* we got a match */
4545 clientchar_t *smb_FindMask(clientchar_t *pathp)
4549 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4552 return tp+1; /* skip the slash */
4554 return pathp; /* no slash, return the entire path */
4557 /* SMB_COM_SEARCH for a volume label
4559 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4560 dispatch function.) */
4561 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4563 clientchar_t *pathp;
4565 clientchar_t mask[12];
4566 unsigned char *statBlockp;
4567 unsigned char initStatBlock[21];
4570 osi_Log0(smb_logp, "SMB receive search volume");
4572 /* pull pathname and stat block out of request */
4573 tp = smb_GetSMBData(inp, NULL);
4574 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4575 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4577 return CM_ERROR_BADSMB;
4578 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4579 osi_assertx(statBlockp != NULL, "null statBlock");
4581 statBlockp = initStatBlock;
4585 /* for returning to caller */
4586 smb_Get8Dot3MaskFromPath(mask, pathp);
4588 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4589 tp = smb_GetSMBData(outp, NULL);
4591 *tp++ = 43; /* bytes in a dir entry */
4592 *tp++ = 0; /* high byte in counter */
4594 /* now marshall the dir entry, starting with the search status */
4595 *tp++ = statBlockp[0]; /* Reserved */
4596 memcpy(tp, mask, 11); tp += 11; /* FileName */
4598 /* now pass back server use info, with 1st byte non-zero */
4600 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4602 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4604 *tp++ = 0x8; /* attribute: volume */
4614 /* 4 byte file size */
4620 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4623 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4624 memset(tp, ' ', 13);
4627 /* set the length of the data part of the packet to 43 + 3, for the dir
4628 * entry plus the 5 and the length fields.
4630 smb_SetSMBDataLength(outp, 46);
4635 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4636 clientchar_t * tidPathp, clientchar_t * relPathp,
4637 cm_user_t *userp, cm_req_t *reqp)
4645 smb_dirListPatch_t *patchp;
4646 smb_dirListPatch_t *npatchp;
4647 clientchar_t path[AFSPATHMAX];
4649 afs_int32 mustFake = 0;
4651 lock_ObtainWrite(&dscp->rw);
4652 code = cm_FindACLCache(dscp, userp, &rights);
4654 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4655 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4656 if (code == CM_ERROR_NOACCESS) {
4661 lock_ReleaseWrite(&dscp->rw);
4665 if (!mustFake) { /* Bulk Stat */
4667 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4669 memset(bsp, 0, sizeof(cm_bulkStat_t));
4672 for (patchp = *dirPatchespp, count=0;
4674 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4675 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4679 if (lock_TryWrite(&tscp->rw)) {
4680 /* we have an entry that we can look at */
4681 if (!cm_EAccesFindEntry(userp, &tscp->fid) && cm_HaveCallback(tscp)) {
4682 /* we have a callback on it. Don't bother
4683 * fetching this stat entry, since we're happy
4684 * with the info we have.
4686 lock_ReleaseWrite(&tscp->rw);
4687 cm_ReleaseSCache(tscp);
4690 lock_ReleaseWrite(&tscp->rw);
4692 cm_ReleaseSCache(tscp);
4696 bsp->fids[i].Volume = patchp->fid.volume;
4697 bsp->fids[i].Vnode = patchp->fid.vnode;
4698 bsp->fids[i].Unique = patchp->fid.unique;
4700 if (bsp->counter == AFSCBMAX) {
4701 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4702 memset(bsp, 0, sizeof(cm_bulkStat_t));
4707 if (bsp->counter > 0)
4708 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4713 for (patchp = *dirPatchespp; patchp; patchp =
4714 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4716 dptr = patchp->dptr;
4718 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4719 relPathp ? relPathp : _C(""), patchp->dep->name);
4720 reqp->relPathp = path;
4721 reqp->tidPathp = tidPathp;
4723 code = cm_GetSCache(&patchp->fid, &dscp->fid, &scp, userp, reqp);
4724 reqp->relPathp = reqp->tidPathp = NULL;
4727 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4728 *dptr++ = SMB_ATTR_HIDDEN;
4731 lock_ObtainWrite(&scp->rw);
4732 if (mustFake || cm_EAccesFindEntry(userp, &scp->fid) || !cm_HaveCallback(scp)) {
4733 lock_ReleaseWrite(&scp->rw);
4735 /* set the attribute */
4736 switch (scp->fileType) {
4737 case CM_SCACHETYPE_DIRECTORY:
4738 case CM_SCACHETYPE_MOUNTPOINT:
4739 case CM_SCACHETYPE_INVALID:
4740 attr = SMB_ATTR_DIRECTORY;
4742 case CM_SCACHETYPE_SYMLINK:
4743 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4744 attr = SMB_ATTR_DIRECTORY;
4746 attr = SMB_ATTR_NORMAL;
4749 /* if we get here we either have a normal file
4750 * or we have a file for which we have never
4751 * received status info. In this case, we can
4752 * check the even/odd value of the entry's vnode.
4753 * odd means it is to be treated as a directory
4754 * and even means it is to be treated as a file.
4756 if (mustFake && (scp->fid.vnode & 0x1))
4757 attr = SMB_ATTR_DIRECTORY;
4759 attr = SMB_ATTR_NORMAL;
4763 /* 1969-12-31 23:59:58 +00*/
4764 dosTime = 0xEBBFBF7D;
4767 shortTemp = (unsigned short) (dosTime & 0xffff);
4768 *((u_short *)dptr) = shortTemp;
4771 /* and copy out date */
4772 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4773 *((u_short *)dptr) = shortTemp;
4776 /* copy out file length */
4777 *((u_long *)dptr) = 0;
4780 lock_ConvertWToR(&scp->rw);
4781 attr = smb_Attributes(scp);
4782 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4783 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4784 attr |= SMB_ATTR_HIDDEN;
4788 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4791 shortTemp = (unsigned short) (dosTime & 0xffff);
4792 *((u_short *)dptr) = shortTemp;
4795 /* and copy out date */
4796 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4797 *((u_short *)dptr) = shortTemp;
4800 /* copy out file length */
4801 *((u_long *)dptr) = scp->length.LowPart;
4803 lock_ReleaseRead(&scp->rw);
4805 cm_ReleaseSCache(scp);
4808 /* now free the patches */
4809 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4810 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4814 /* and mark the list as empty */
4815 *dirPatchespp = NULL;
4821 /* SMB_COM_SEARCH */
4822 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4828 clientchar_t *pathp;
4829 cm_dirEntry_t *dep = 0;
4831 smb_dirListPatch_t *dirListPatchesp;
4832 smb_dirListPatch_t *curPatchp;
4836 osi_hyper_t dirLength;
4837 osi_hyper_t bufferOffset;
4838 osi_hyper_t curOffset;
4840 unsigned char *inCookiep;
4841 smb_dirSearch_t *dsp;
4845 unsigned long clientCookie;
4846 cm_pageHeader_t *pageHeaderp;
4847 cm_user_t *userp = NULL;
4849 clientchar_t mask[12];
4851 long nextEntryCookie;
4852 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4853 char resByte; /* reserved byte from the cookie */
4854 char *op; /* output data ptr */
4855 char *origOp; /* original value of op */
4856 cm_space_t *spacep; /* for pathname buffer */
4860 clientchar_t *tidPathp = 0;
4867 maxCount = smb_GetSMBParm(inp, 0);
4869 dirListPatchesp = NULL;
4871 caseFold = CM_FLAG_CASEFOLD;
4873 tp = smb_GetSMBData(inp, NULL);
4874 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4875 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4877 return CM_ERROR_BADSMB;
4879 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4881 return CM_ERROR_BADSMB;
4883 /* We can handle long names */
4884 if (vcp->flags & SMB_VCFLAG_USENT)
4885 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4887 /* make sure we got a whole search status */
4888 if (dataLength < 21) {
4889 nextCookie = 0; /* start at the beginning of the dir */
4892 attribute = smb_GetSMBParm(inp, 1);
4894 /* handle volume info in another function */
4895 if (attribute & 0x8)
4896 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4898 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4899 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4901 if (*pathp == 0) { /* null pathp, treat as root dir */
4902 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4903 return CM_ERROR_NOFILES;
4907 dsp = smb_NewDirSearch(0);
4908 dsp->attribute = attribute;
4909 smb_Get8Dot3MaskFromPath(mask, pathp);
4910 memcpy(dsp->mask, mask, 12);
4912 /* track if this is likely to match a lot of entries */
4913 if (smb_Is8Dot3StarMask(mask))
4918 /* pull the next cookie value out of the search status block */
4919 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4920 + (inCookiep[16]<<24);
4921 dsp = smb_FindDirSearch(inCookiep[12]);
4923 /* can't find dir search status; fatal error */
4924 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4925 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4926 return CM_ERROR_BADFD;
4928 attribute = dsp->attribute;
4929 resByte = inCookiep[0];
4931 /* copy out client cookie, in host byte order. Don't bother
4932 * interpreting it, since we're just passing it through, anyway.
4934 memcpy(&clientCookie, &inCookiep[17], 4);
4936 memcpy(mask, dsp->mask, 12);
4938 /* assume we're doing a star match if it has continued for more
4944 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4945 nextCookie, dsp->cookie, attribute);
4947 userp = smb_GetUserFromVCP(vcp, inp);
4949 /* try to get the vnode for the path name next */
4950 lock_ObtainMutex(&dsp->mx);
4953 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4957 spacep = inp->spacep;
4958 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4959 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4961 lock_ReleaseMutex(&dsp->mx);
4962 cm_ReleaseUser(userp);
4963 smb_DeleteDirSearch(dsp);
4964 smb_ReleaseDirSearch(dsp);
4965 return CM_ERROR_NOFILES;
4967 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4968 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4970 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
4971 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4974 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4977 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4978 cm_ReleaseSCache(scp);
4979 lock_ReleaseMutex(&dsp->mx);
4980 cm_ReleaseUser(userp);
4981 smb_DeleteDirSearch(dsp);
4982 smb_ReleaseDirSearch(dsp);
4983 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4984 return CM_ERROR_PATH_NOT_COVERED;
4986 return CM_ERROR_NOSUCHPATH;
4988 #endif /* DFS_SUPPORT */
4991 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4992 /* we need one hold for the entry we just stored into,
4993 * and one for our own processing. When we're done with this
4994 * function, we'll drop the one for our own processing.
4995 * We held it once from the namei call, and so we do another hold
4999 lock_ObtainWrite(&scp->rw);
5000 dsp->flags |= SMB_DIRSEARCH_BULKST;
5001 lock_ReleaseWrite(&scp->rw);
5004 lock_ReleaseMutex(&dsp->mx);
5006 cm_ReleaseUser(userp);
5007 smb_DeleteDirSearch(dsp);
5008 smb_ReleaseDirSearch(dsp);
5012 /* reserves space for parameter; we'll adjust it again later to the
5013 * real count of the # of entries we returned once we've actually
5014 * assembled the directory listing.
5016 smb_SetSMBParm(outp, 0, 0);
5018 /* get the directory size */
5019 lock_ObtainWrite(&scp->rw);
5020 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5021 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5023 lock_ReleaseWrite(&scp->rw);
5024 cm_ReleaseSCache(scp);
5025 cm_ReleaseUser(userp);
5026 smb_DeleteDirSearch(dsp);
5027 smb_ReleaseDirSearch(dsp);
5031 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5033 dirLength = scp->length;
5035 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5036 curOffset.HighPart = 0;
5037 curOffset.LowPart = nextCookie;
5038 origOp = op = smb_GetSMBData(outp, NULL);
5039 /* and write out the basic header */
5040 *op++ = 5; /* variable block */
5041 op += 2; /* skip vbl block length; we'll fill it in later */
5045 clientchar_t *actualName = NULL;
5046 int free_actualName = 0;
5047 clientchar_t shortName[13];
5048 clientchar_t *shortNameEnd;
5050 /* make sure that curOffset.LowPart doesn't point to the first
5051 * 32 bytes in the 2nd through last dir page, and that it doesn't
5052 * point at the first 13 32-byte chunks in the first dir page,
5053 * since those are dir and page headers, and don't contain useful
5056 temp = curOffset.LowPart & (2048-1);
5057 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5058 /* we're in the first page */
5059 if (temp < 13*32) temp = 13*32;
5062 /* we're in a later dir page */
5063 if (temp < 32) temp = 32;
5066 /* make sure the low order 5 bits are zero */
5069 /* now put temp bits back ito curOffset.LowPart */
5070 curOffset.LowPart &= ~(2048-1);
5071 curOffset.LowPart |= temp;
5073 /* check if we've returned all the names that will fit in the
5076 if (returnedNames >= maxCount) {
5077 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5078 returnedNames, maxCount);
5082 /* check if we've passed the dir's EOF */
5083 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5085 /* see if we can use the bufferp we have now; compute in which page
5086 * the current offset would be, and check whether that's the offset
5087 * of the buffer we have. If not, get the buffer.
5089 thyper.HighPart = curOffset.HighPart;
5090 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5091 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5094 buf_Release(bufferp);
5097 lock_ReleaseWrite(&scp->rw);
5098 code = buf_Get(scp, &thyper, &req, &bufferp);
5099 lock_ObtainMutex(&dsp->mx);
5101 /* now, if we're doing a star match, do bulk fetching of all of
5102 * the status info for files in the dir.
5105 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5107 lock_ObtainWrite(&scp->rw);
5108 lock_ReleaseMutex(&dsp->mx);
5110 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5114 bufferOffset = thyper;
5116 /* now get the data in the cache */
5118 code = cm_SyncOp(scp, bufferp, userp, &req,
5120 CM_SCACHESYNC_NEEDCALLBACK |
5121 CM_SCACHESYNC_READ);
5123 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5127 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5129 if (cm_HaveBuffer(scp, bufferp, 0)) {
5130 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5134 /* otherwise, load the buffer and try again */
5135 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5137 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5138 scp, bufferp, code);
5143 buf_Release(bufferp);
5147 } /* if (wrong buffer) ... */
5149 /* now we have the buffer containing the entry we're interested in; copy
5150 * it out if it represents a non-deleted entry.
5152 entryInDir = curOffset.LowPart & (2048-1);
5153 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5155 /* page header will help tell us which entries are free. Page header
5156 * can change more often than once per buffer, since AFS 3 dir page size
5157 * may be less than (but not more than a buffer package buffer.
5159 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5160 temp &= ~(2048 - 1); /* turn off intra-page bits */
5161 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5163 /* now determine which entry we're looking at in the page. If it is
5164 * free (there's a free bitmap at the start of the dir), we should
5165 * skip these 32 bytes.
5167 slotInPage = (entryInDir & 0x7e0) >> 5;
5168 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5169 /* this entry is free */
5170 numDirChunks = 1; /* only skip this guy */
5174 tp = bufferp->datap + entryInBuffer;
5175 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5177 /* while we're here, compute the next entry's location, too,
5178 * since we'll need it when writing out the cookie into the dir
5181 * XXXX Probably should do more sanity checking.
5183 numDirChunks = cm_NameEntries(dep->name, NULL);
5185 /* compute the offset of the cookie representing the next entry */
5186 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5188 /* Compute 8.3 name if necessary */
5189 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5190 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5193 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5194 actualName = shortName;
5195 free_actualName = 0;
5197 free_actualName = 1;
5200 if (actualName == NULL) {
5201 /* Couldn't convert the name for some reason */
5202 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5203 osi_LogSaveString(smb_logp, dep->name));
5207 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5208 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5209 osi_LogSaveClientString(smb_logp, actualName));
5211 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5212 /* this is one of the entries to use: it is not deleted
5213 * and it matches the star pattern we're looking for.
5216 /* Eliminate entries that don't match requested
5219 /* no hidden files */
5220 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5221 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5225 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5227 /* We have already done the cm_TryBulkStat above */
5228 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5229 fileType = cm_FindFileType(&fid);
5230 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5231 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5233 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5234 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5235 fileType == CM_SCACHETYPE_DFSLINK ||
5236 fileType == CM_SCACHETYPE_INVALID)
5237 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5242 memcpy(op, mask, 11); op += 11;
5243 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5244 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5245 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5246 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5247 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5248 memcpy(op, &clientCookie, 4); op += 4;
5250 /* now we emit the attribute. This is sort of tricky,
5251 * since we need to really stat the file to find out
5252 * what type of entry we've got. Right now, we're
5253 * copying out data from a buffer, while holding the
5254 * scp locked, so it isn't really convenient to stat
5255 * something now. We'll put in a place holder now,
5256 * and make a second pass before returning this to get
5257 * the real attributes. So, we just skip the data for
5258 * now, and adjust it later. We allocate a patch
5259 * record to make it easy to find this point later.
5260 * The replay will happen at a time when it is safe to
5261 * unlock the directory.
5263 curPatchp = malloc(sizeof(*curPatchp));
5264 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5265 curPatchp->dptr = op;
5266 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5268 /* do hidden attribute here since name won't be around when applying
5272 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5273 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5275 curPatchp->flags = 0;
5277 op += 9; /* skip attr, time, date and size */
5279 /* zero out name area. The spec says to pad with
5280 * spaces, but Samba doesn't, and neither do we.
5284 /* finally, we get to copy out the name; we know that
5285 * it fits in 8.3 or the pattern wouldn't match, but it
5286 * never hurts to be sure.
5288 cm_ClientStringToUtf8(actualName, -1, op, 13);
5289 if (smb_StoreAnsiFilenames)
5291 /* This is a UCHAR field, which is ASCII even if Unicode
5294 /* Uppercase if requested by client */
5295 if (!KNOWS_LONG_NAMES(inp))
5300 /* now, adjust the # of entries copied */
5302 } /* if we're including this name */
5305 if (free_actualName && actualName) {
5310 /* and adjust curOffset to be where the new cookie is */
5311 thyper.HighPart = 0;
5312 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5313 curOffset = LargeIntegerAdd(thyper, curOffset);
5314 } /* while copying data for dir listing */
5316 /* release the mutex */
5317 lock_ReleaseWrite(&scp->rw);
5319 buf_Release(bufferp);
5323 /* apply and free last set of patches; if not doing a star match, this
5324 * will be empty, but better safe (and freeing everything) than sorry.
5326 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5328 /* special return code for unsuccessful search */
5329 if (code == 0 && dataLength < 21 && returnedNames == 0)
5330 code = CM_ERROR_NOFILES;
5332 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5333 returnedNames, code);
5336 smb_DeleteDirSearch(dsp);
5337 smb_ReleaseDirSearch(dsp);
5338 cm_ReleaseSCache(scp);
5339 cm_ReleaseUser(userp);
5343 /* finalize the output buffer */
5344 smb_SetSMBParm(outp, 0, returnedNames);
5345 temp = (long) (op - origOp);
5346 smb_SetSMBDataLength(outp, temp);
5348 /* the data area is a variable block, which has a 5 (already there)
5349 * followed by the length of the # of data bytes. We now know this to
5350 * be "temp," although that includes the 3 bytes of vbl block header.
5351 * Deduct for them and fill in the length field.
5353 temp -= 3; /* deduct vbl block info */
5354 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5355 origOp[1] = (unsigned char)(temp & 0xff);
5356 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5357 if (returnedNames == 0)
5358 smb_DeleteDirSearch(dsp);
5359 smb_ReleaseDirSearch(dsp);
5360 cm_ReleaseSCache(scp);
5361 cm_ReleaseUser(userp);
5366 /* verify that this is a valid path to a directory. I don't know why they
5367 * don't use the get file attributes call.
5369 * SMB_COM_CHECK_DIRECTORY
5371 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5373 clientchar_t *pathp;
5375 cm_scache_t *rootScp;
5376 cm_scache_t *newScp;
5380 clientchar_t *tidPathp;
5386 pdata = smb_GetSMBData(inp, NULL);
5387 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5389 return CM_ERROR_BADSMB;
5390 osi_Log1(smb_logp, "SMB receive check path %S",
5391 osi_LogSaveClientString(smb_logp, pathp));
5393 userp = smb_GetUserFromVCP(vcp, inp);
5395 rootScp = cm_RootSCachep(userp, &req);
5397 caseFold = CM_FLAG_CASEFOLD;
5399 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5401 cm_ReleaseUser(userp);
5402 return CM_ERROR_NOSUCHPATH;
5404 code = cm_NameI(rootScp, pathp,
5405 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5406 userp, tidPathp, &req, &newScp);
5409 cm_ReleaseUser(userp);
5414 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5415 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5416 cm_ReleaseSCache(newScp);
5417 cm_ReleaseUser(userp);
5418 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5419 return CM_ERROR_PATH_NOT_COVERED;
5421 return CM_ERROR_NOSUCHPATH;
5423 #endif /* DFS_SUPPORT */
5425 /* now lock the vnode with a callback; returns with newScp locked */
5426 lock_ObtainWrite(&newScp->rw);
5427 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5428 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5430 if (code != CM_ERROR_NOACCESS) {
5431 lock_ReleaseWrite(&newScp->rw);
5432 cm_ReleaseSCache(newScp);
5433 cm_ReleaseUser(userp);
5437 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5440 attrs = smb_Attributes(newScp);
5442 if (!(attrs & SMB_ATTR_DIRECTORY))
5443 code = CM_ERROR_NOTDIR;
5445 lock_ReleaseWrite(&newScp->rw);
5447 cm_ReleaseSCache(newScp);
5448 cm_ReleaseUser(userp);
5452 /* SMB_COM_SET_INFORMATION */
5453 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5455 clientchar_t *pathp;
5457 cm_scache_t *rootScp;
5458 unsigned short attribute;
5460 cm_scache_t *newScp;
5464 clientchar_t *tidPathp;
5470 /* decode basic attributes we're passed */
5471 attribute = smb_GetSMBParm(inp, 0);
5472 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5474 datap = smb_GetSMBData(inp, NULL);
5475 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5477 return CM_ERROR_BADSMB;
5479 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5480 dosTime, attribute);
5482 userp = smb_GetUserFromVCP(vcp, inp);
5484 rootScp = cm_RootSCachep(userp, &req);
5486 caseFold = CM_FLAG_CASEFOLD;
5488 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5490 cm_ReleaseUser(userp);
5491 return CM_ERROR_NOSUCHFILE;
5493 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5494 tidPathp, &req, &newScp);
5497 cm_ReleaseUser(userp);
5502 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5503 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5504 cm_ReleaseSCache(newScp);
5505 cm_ReleaseUser(userp);
5506 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5507 return CM_ERROR_PATH_NOT_COVERED;
5509 return CM_ERROR_NOSUCHPATH;
5511 #endif /* DFS_SUPPORT */
5513 /* now lock the vnode with a callback; returns with newScp locked; we
5514 * need the current status to determine what the new status is, in some
5517 lock_ObtainWrite(&newScp->rw);
5518 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5519 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5521 lock_ReleaseWrite(&newScp->rw);
5522 cm_ReleaseSCache(newScp);
5523 cm_ReleaseUser(userp);
5527 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5529 /* Check for RO volume */
5530 if (newScp->flags & CM_SCACHEFLAG_RO) {
5531 lock_ReleaseWrite(&newScp->rw);
5532 cm_ReleaseSCache(newScp);
5533 cm_ReleaseUser(userp);
5534 return CM_ERROR_READONLY;
5537 /* prepare for setattr call */
5540 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5541 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5543 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5544 /* we're told to make a writable file read-only */
5545 attr.unixModeBits = newScp->unixModeBits & ~0222;
5546 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5548 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5549 /* we're told to make a read-only file writable */
5550 attr.unixModeBits = newScp->unixModeBits | 0222;
5551 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5553 lock_ReleaseWrite(&newScp->rw);
5555 /* now call setattr */
5557 code = cm_SetAttr(newScp, &attr, userp, &req);
5561 cm_ReleaseSCache(newScp);
5562 cm_ReleaseUser(userp);
5568 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5570 clientchar_t *pathp;
5572 cm_scache_t *rootScp;
5573 cm_scache_t *newScp, *dscp;
5578 clientchar_t *tidPathp;
5580 clientchar_t *lastComp;
5586 datap = smb_GetSMBData(inp, NULL);
5587 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5589 return CM_ERROR_BADSMB;
5591 if (*pathp == 0) /* null path */
5594 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5595 osi_LogSaveClientString(smb_logp, pathp));
5597 userp = smb_GetUserFromVCP(vcp, inp);
5599 rootScp = cm_RootSCachep(userp, &req);
5601 /* we shouldn't need this for V3 requests, but we seem to */
5602 caseFold = CM_FLAG_CASEFOLD;
5604 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5606 cm_ReleaseUser(userp);
5607 return CM_ERROR_NOSUCHFILE;
5611 * XXX Strange hack XXX
5613 * As of Patch 5 (16 July 97), we are having the following problem:
5614 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5615 * requests to look up "desktop.ini" in all the subdirectories.
5616 * This can cause zillions of timeouts looking up non-existent cells
5617 * and volumes, especially in the top-level directory.
5619 * We have not found any way to avoid this or work around it except
5620 * to explicitly ignore the requests for mount points that haven't
5621 * yet been evaluated and for directories that haven't yet been
5624 * We should modify this hack to provide a fake desktop.ini file
5625 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5627 spacep = inp->spacep;
5628 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5629 #ifndef SPECIAL_FOLDERS
5630 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5631 code = cm_NameI(rootScp, spacep->wdata,
5632 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5633 userp, tidPathp, &req, &dscp);
5636 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5637 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5639 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5640 return CM_ERROR_PATH_NOT_COVERED;
5642 return CM_ERROR_NOSUCHPATH;
5644 #endif /* DFS_SUPPORT */
5645 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5646 code = CM_ERROR_NOSUCHFILE;
5647 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5648 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
5653 code = CM_ERROR_NOSUCHFILE;
5655 cm_ReleaseSCache(dscp);
5657 cm_ReleaseUser(userp);
5661 else if (code != CM_ERROR_NOSUCHFILE &&
5662 code != CM_ERROR_NOSUCHPATH &&
5663 code != CM_ERROR_BPLUS_NOMATCH)
5665 cm_ReleaseUser(userp);
5669 #endif /* SPECIAL_FOLDERS */
5671 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5672 tidPathp, &req, &newScp);
5674 cm_ReleaseUser(userp);
5679 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5680 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5681 cm_ReleaseSCache(newScp);
5682 cm_ReleaseUser(userp);
5683 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5684 return CM_ERROR_PATH_NOT_COVERED;
5686 return CM_ERROR_NOSUCHPATH;
5688 #endif /* DFS_SUPPORT */
5690 /* now lock the vnode with a callback; returns with newScp locked */
5691 lock_ObtainWrite(&newScp->rw);
5692 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5693 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5695 lock_ReleaseWrite(&newScp->rw);
5696 cm_ReleaseSCache(newScp);
5697 cm_ReleaseUser(userp);
5701 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5703 attrs = smb_Attributes(newScp);
5705 smb_SetSMBParm(outp, 0, attrs);
5707 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5708 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5709 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5710 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5711 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5712 smb_SetSMBParm(outp, 5, 0);
5713 smb_SetSMBParm(outp, 6, 0);
5714 smb_SetSMBParm(outp, 7, 0);
5715 smb_SetSMBParm(outp, 8, 0);
5716 smb_SetSMBParm(outp, 9, 0);
5717 smb_SetSMBDataLength(outp, 0);
5718 lock_ReleaseWrite(&newScp->rw);
5720 cm_ReleaseSCache(newScp);
5721 cm_ReleaseUser(userp);
5726 /* SMB_COM_TREE_DISCONNECT */
5727 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5731 osi_Log0(smb_logp, "SMB receive tree disconnect");
5733 /* find the tree and free it */
5734 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5736 lock_ObtainWrite(&smb_rctLock);
5738 smb_ReleaseTID(tidp, TRUE);
5739 lock_ReleaseWrite(&smb_rctLock);
5746 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5749 clientchar_t *pathp;
5750 clientchar_t *lastNamep;
5759 clientchar_t *tidPathp;
5765 datap = smb_GetSMBData(inp, NULL);
5766 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5768 return CM_ERROR_BADSMB;
5770 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5772 #ifdef DEBUG_VERBOSE
5776 hexpath = osi_HexifyString( pathp );
5777 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5782 share = smb_GetSMBParm(inp, 0);
5783 attribute = smb_GetSMBParm(inp, 1);
5785 spacep = inp->spacep;
5786 /* smb_StripLastComponent will strip "::$DATA" if present */
5787 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5789 if (!cm_IsValidClientString(pathp)) {
5791 clientchar_t * hexp;
5793 hexp = cm_GetRawCharsAlloc(pathp, -1);
5794 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5795 osi_LogSaveClientString(smb_logp, hexp));
5799 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5801 return CM_ERROR_BADNTFILENAME;
5804 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5805 /* special case magic file name for receiving IOCTL requests
5806 * (since IOCTL calls themselves aren't getting through).
5808 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5809 smb_SetupIoctlFid(fidp, spacep);
5810 smb_SetSMBParm(outp, 0, fidp->fid);
5811 smb_SetSMBParm(outp, 1, 0); /* attrs */
5812 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5813 smb_SetSMBParm(outp, 3, 0);
5814 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5815 smb_SetSMBParm(outp, 5, 0x7fff);
5816 /* pass the open mode back */
5817 smb_SetSMBParm(outp, 6, (share & 0xf));
5818 smb_SetSMBDataLength(outp, 0);
5819 smb_ReleaseFID(fidp);
5823 userp = smb_GetUserFromVCP(vcp, inp);
5825 caseFold = CM_FLAG_CASEFOLD;
5827 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5829 cm_ReleaseUser(userp);
5830 return CM_ERROR_NOSUCHPATH;
5832 code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
5833 tidPathp, &req, &scp);
5836 cm_ReleaseUser(userp);
5841 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5842 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5843 cm_ReleaseSCache(scp);
5844 cm_ReleaseUser(userp);
5845 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5846 return CM_ERROR_PATH_NOT_COVERED;
5848 return CM_ERROR_NOSUCHPATH;
5850 #endif /* DFS_SUPPORT */
5852 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5854 cm_ReleaseSCache(scp);
5855 cm_ReleaseUser(userp);
5859 /* don't need callback to check file type, since file types never
5860 * change, and namei and cm_Lookup all stat the object at least once on
5861 * a successful return.
5863 if (scp->fileType != CM_SCACHETYPE_FILE) {
5864 cm_ReleaseSCache(scp);
5865 cm_ReleaseUser(userp);
5866 return CM_ERROR_ISDIR;
5869 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5870 osi_assertx(fidp, "null smb_fid_t");
5872 lock_ObtainMutex(&fidp->mx);
5873 if ((share & 0xf) == 0)
5874 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5875 else if ((share & 0xf) == 1)
5876 fidp->flags |= SMB_FID_OPENWRITE;
5878 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5882 fidp->userp = userp;
5884 /* and a pointer to the vnode */
5886 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5887 lock_ObtainWrite(&scp->rw);
5888 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5890 smb_SetSMBParm(outp, 0, fidp->fid);
5891 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5892 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5893 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5894 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5895 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5896 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5897 /* pass the open mode back; XXXX add access checks */
5898 smb_SetSMBParm(outp, 6, (share & 0xf));
5899 smb_SetSMBDataLength(outp, 0);
5900 lock_ReleaseMutex(&fidp->mx);
5901 lock_ReleaseRead(&scp->rw);
5904 cm_Open(scp, 0, userp);
5906 /* send and free packet */
5907 smb_ReleaseFID(fidp);
5908 cm_ReleaseUser(userp);
5909 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5913 typedef struct smb_unlinkRock {
5918 clientchar_t *maskp; /* pointer to the star pattern */
5921 cm_dirEntryList_t * matches;
5924 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5927 smb_unlinkRock_t *rockp;
5930 normchar_t matchName[MAX_PATH];
5934 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5935 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5936 caseFold |= CM_FLAG_8DOT3;
5938 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5939 /* Can't convert name */
5940 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5941 osi_LogSaveString(smb_logp, dep->name));
5945 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5947 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5948 !cm_Is8Dot3(matchName)) {
5949 cm_Gen8Dot3Name(dep, matchName, NULL);
5950 /* 8.3 matches are always case insensitive */
5951 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5954 osi_Log1(smb_logp, "Found match %S",
5955 osi_LogSaveClientString(smb_logp, matchName));
5957 cm_DirEntryListAdd(dep->name, &rockp->matches);
5961 /* If we made a case sensitive exact match, we might as well quit now. */
5962 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5963 code = CM_ERROR_STOPNOW;
5972 /* SMB_COM_DELETE */
5973 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5977 clientchar_t *pathp;
5981 clientchar_t *lastNamep;
5982 smb_unlinkRock_t rock;
5986 clientchar_t *tidPathp;
5990 memset(&rock, 0, sizeof(rock));
5992 attribute = smb_GetSMBParm(inp, 0);
5994 tp = smb_GetSMBData(inp, NULL);
5995 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5997 return CM_ERROR_BADSMB;
5999 osi_Log1(smb_logp, "SMB receive unlink %S",
6000 osi_LogSaveClientString(smb_logp, pathp));
6002 spacep = inp->spacep;
6003 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6005 userp = smb_GetUserFromVCP(vcp, inp);
6007 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6009 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6011 cm_ReleaseUser(userp);
6012 return CM_ERROR_NOSUCHPATH;
6014 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
6017 cm_ReleaseUser(userp);
6022 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6023 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6024 cm_ReleaseSCache(dscp);
6025 cm_ReleaseUser(userp);
6026 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6027 return CM_ERROR_PATH_NOT_COVERED;
6029 return CM_ERROR_NOSUCHPATH;
6031 #endif /* DFS_SUPPORT */
6033 /* otherwise, scp points to the parent directory. */
6040 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
6042 code = CM_ERROR_NOSUCHFILE;
6045 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6048 thyper.HighPart = 0;
6053 rock.matches = NULL;
6055 /* Now, if we aren't dealing with a wildcard match, we first try an exact
6056 * match. If that fails, we do a case insensitve match.
6058 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6059 !smb_IsStarMask(rock.maskp)) {
6060 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6063 thyper.HighPart = 0;
6064 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6069 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6071 if (code == CM_ERROR_STOPNOW)
6074 if (code == 0 && rock.matches) {
6075 cm_dirEntryList_t * entry;
6077 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6078 normchar_t normalizedName[MAX_PATH];
6080 /* Note: entry->name is a non-normalized name */
6082 osi_Log1(smb_logp, "Unlinking %s",
6083 osi_LogSaveString(smb_logp, entry->name));
6085 /* We assume this works because entry->name was
6086 successfully converted in smb_UnlinkProc() once. */
6087 cm_FsStringToNormString(entry->name, -1,
6088 normalizedName, lengthof(normalizedName));
6090 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6092 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6093 smb_NotifyChange(FILE_ACTION_REMOVED,
6094 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6095 dscp, normalizedName, NULL, TRUE);
6099 cm_DirEntryListFree(&rock.matches);
6103 cm_ReleaseUser(userp);
6106 cm_ReleaseSCache(dscp);
6111 if (code == 0 && !rock.any)
6112 code = CM_ERROR_NOSUCHFILE;
6116 typedef struct smb_renameRock {
6117 cm_scache_t *odscp; /* old dir */
6118 cm_scache_t *ndscp; /* new dir */
6119 cm_user_t *userp; /* user */
6120 cm_req_t *reqp; /* request struct */
6121 smb_vc_t *vcp; /* virtual circuit */
6122 normchar_t *maskp; /* pointer to star pattern of old file name */
6123 int flags; /* tilde, casefold, etc */
6124 clientchar_t *newNamep; /* ptr to the new file's name */
6125 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6126 clientchar_t clOldName[MAX_PATH]; /* client name */
6130 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6133 smb_renameRock_t *rockp;
6136 normchar_t matchName[MAX_PATH];
6138 rockp = (smb_renameRock_t *) vrockp;
6140 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6141 /* Can't convert string */
6142 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6143 osi_LogSaveString(smb_logp, dep->name));
6147 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6148 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6149 caseFold |= CM_FLAG_8DOT3;
6151 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6153 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6154 !cm_Is8Dot3(matchName)) {
6155 cm_Gen8Dot3Name(dep, matchName, NULL);
6156 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6161 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6162 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6164 code = CM_ERROR_STOPNOW;
6174 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6177 cm_space_t *spacep = NULL;
6178 smb_renameRock_t rock;
6179 cm_scache_t *oldDscp = NULL;
6180 cm_scache_t *newDscp = NULL;
6181 cm_scache_t *tmpscp= NULL;
6182 cm_scache_t *tmpscp2 = NULL;
6183 clientchar_t *oldLastNamep;
6184 clientchar_t *newLastNamep;
6188 clientchar_t *tidPathp;
6192 userp = smb_GetUserFromVCP(vcp, inp);
6193 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6195 cm_ReleaseUser(userp);
6196 return CM_ERROR_NOSUCHPATH;
6200 memset(&rock, 0, sizeof(rock));
6202 spacep = inp->spacep;
6203 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6205 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6206 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6207 userp, tidPathp, &req, &oldDscp);
6209 cm_ReleaseUser(userp);
6214 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6215 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6216 cm_ReleaseSCache(oldDscp);
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 */
6225 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6226 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6227 userp, tidPathp, &req, &newDscp);
6230 cm_ReleaseSCache(oldDscp);
6231 cm_ReleaseUser(userp);
6236 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6237 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6238 cm_ReleaseSCache(oldDscp);
6239 cm_ReleaseSCache(newDscp);
6240 cm_ReleaseUser(userp);
6241 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6242 return CM_ERROR_PATH_NOT_COVERED;
6244 return CM_ERROR_NOSUCHPATH;
6246 #endif /* DFS_SUPPORT */
6249 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6250 * next, get the component names, and lower case them.
6253 /* handle the old name first */
6255 oldLastNamep = oldPathp;
6259 /* and handle the new name, too */
6261 newLastNamep = newPathp;
6265 /* TODO: The old name could be a wildcard. The new name must not be */
6267 /* Check if the file already exists; if so return error */
6268 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6269 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6270 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6272 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6273 osi_LogSaveClientString(smb_logp, newLastNamep));
6275 /* Check if the old and the new names differ only in case. If so return
6276 * success, else return CM_ERROR_EXISTS
6278 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6280 /* This would be a success only if the old file is *as same as* the new file */
6281 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6283 if (tmpscp == tmpscp2)
6286 code = CM_ERROR_EXISTS;
6287 cm_ReleaseSCache(tmpscp2);
6290 code = CM_ERROR_NOSUCHFILE;
6293 /* file exist, do not rename, also fixes move */
6294 osi_Log0(smb_logp, "Can't rename. Target already exists");
6295 code = CM_ERROR_EXISTS;
6300 /* do the vnode call */
6301 rock.odscp = oldDscp;
6302 rock.ndscp = newDscp;
6306 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6308 code = CM_ERROR_NOSUCHFILE;
6311 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6312 rock.newNamep = newLastNamep;
6313 rock.fsOldName[0] = '\0';
6314 rock.clOldName[0] = '\0';
6317 /* Now search the directory for the pattern, and do the appropriate rename when found */
6318 thyper.LowPart = 0; /* search dir from here */
6319 thyper.HighPart = 0;
6321 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6322 if (code == 0 && !rock.any) {
6324 thyper.HighPart = 0;
6325 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6326 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6328 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6330 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6331 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6332 rock.ndscp, rock.newNamep, rock.userp,
6334 /* if the call worked, stop doing the search now, since we
6335 * really only want to rename one file.
6338 osi_Log0(smb_logp, "cm_Rename failure");
6339 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6340 } else if (code == 0) {
6341 code = CM_ERROR_NOSUCHFILE;
6344 /* Handle Change Notification */
6346 * Being lazy, not distinguishing between files and dirs in this
6347 * filter, since we'd have to do a lookup.
6350 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6351 if (oldDscp == newDscp) {
6352 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6353 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6354 filter, oldDscp, rock.clOldName,
6355 newLastNamep, TRUE);
6357 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6358 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6359 filter, oldDscp, rock.clOldName,
6361 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6362 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6363 filter, newDscp, newLastNamep,
6370 cm_ReleaseSCache(tmpscp);
6372 cm_ReleaseUser(userp);
6374 cm_ReleaseSCache(oldDscp);
6376 cm_ReleaseSCache(newDscp);
6384 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6387 cm_space_t *spacep = NULL;
6388 cm_scache_t *oldDscp = NULL;
6389 cm_scache_t *newDscp = NULL;
6390 cm_scache_t *tmpscp= NULL;
6391 cm_scache_t *tmpscp2 = NULL;
6392 cm_scache_t *sscp = NULL;
6393 clientchar_t *oldLastNamep;
6394 clientchar_t *newLastNamep;
6397 clientchar_t *tidPathp;
6401 userp = smb_GetUserFromVCP(vcp, inp);
6403 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6405 cm_ReleaseUser(userp);
6406 return CM_ERROR_NOSUCHPATH;
6411 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6413 spacep = inp->spacep;
6414 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6416 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6417 userp, tidPathp, &req, &oldDscp);
6419 cm_ReleaseUser(userp);
6424 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6425 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6426 cm_ReleaseSCache(oldDscp);
6427 cm_ReleaseUser(userp);
6428 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6429 return CM_ERROR_PATH_NOT_COVERED;
6431 return CM_ERROR_NOSUCHPATH;
6433 #endif /* DFS_SUPPORT */
6435 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6436 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6437 userp, tidPathp, &req, &newDscp);
6439 cm_ReleaseSCache(oldDscp);
6440 cm_ReleaseUser(userp);
6445 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6446 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6447 cm_ReleaseSCache(newDscp);
6448 cm_ReleaseSCache(oldDscp);
6449 cm_ReleaseUser(userp);
6450 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6451 return CM_ERROR_PATH_NOT_COVERED;
6453 return CM_ERROR_NOSUCHPATH;
6455 #endif /* DFS_SUPPORT */
6457 /* Now, although we did two lookups for the two directories (because the same
6458 * directory can be referenced through different paths), we only allow hard links
6459 * within the same directory. */
6460 if (oldDscp != newDscp) {
6461 cm_ReleaseSCache(oldDscp);
6462 cm_ReleaseSCache(newDscp);
6463 cm_ReleaseUser(userp);
6464 return CM_ERROR_CROSSDEVLINK;
6467 /* handle the old name first */
6469 oldLastNamep = oldPathp;
6473 /* and handle the new name, too */
6475 newLastNamep = newPathp;
6479 /* now lookup the old name */
6480 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6481 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6483 cm_ReleaseSCache(oldDscp);
6484 cm_ReleaseSCache(newDscp);
6485 cm_ReleaseUser(userp);
6489 /* Check if the file already exists; if so return error */
6490 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6491 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6492 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6494 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6495 osi_LogSaveClientString(smb_logp, newLastNamep));
6497 /* if the existing link is to the same file, then we return success */
6499 if(sscp == tmpscp) {
6502 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6503 code = CM_ERROR_EXISTS;
6508 cm_ReleaseSCache(tmpscp);
6509 cm_ReleaseSCache(sscp);
6510 cm_ReleaseSCache(newDscp);
6511 cm_ReleaseSCache(oldDscp);
6512 cm_ReleaseUser(userp);
6516 /* now create the hardlink */
6517 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6518 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6519 osi_Log1(smb_logp," Link returns 0x%x", code);
6521 /* Handle Change Notification */
6523 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6524 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6525 smb_NotifyChange(FILE_ACTION_ADDED,
6526 filter, newDscp, newLastNamep,
6531 cm_ReleaseSCache(tmpscp);
6532 cm_ReleaseUser(userp);
6533 cm_ReleaseSCache(sscp);
6534 cm_ReleaseSCache(oldDscp);
6535 cm_ReleaseSCache(newDscp);
6539 /* SMB_COM_RENAME */
6541 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6543 clientchar_t *oldPathp;
6544 clientchar_t *newPathp;
6548 tp = smb_GetSMBData(inp, NULL);
6549 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6551 return CM_ERROR_BADSMB;
6552 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6554 return CM_ERROR_BADSMB;
6556 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6557 osi_LogSaveClientString(smb_logp, oldPathp),
6558 osi_LogSaveClientString(smb_logp, newPathp));
6560 if (!cm_IsValidClientString(newPathp)) {
6562 clientchar_t * hexp;
6564 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6565 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6566 osi_LogSaveClientString(smb_logp, hexp));
6570 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6572 return CM_ERROR_BADNTFILENAME;
6575 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6577 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6583 typedef struct smb_rmdirRock {
6587 normchar_t *maskp; /* pointer to the star pattern */
6590 cm_dirEntryList_t * matches;
6593 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6596 smb_rmdirRock_t *rockp;
6598 normchar_t matchName[MAX_PATH];
6600 rockp = (smb_rmdirRock_t *) vrockp;
6602 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6603 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6604 osi_LogSaveString(smb_logp, dep->name));
6608 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6609 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6611 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6613 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6614 !cm_Is8Dot3(matchName)) {
6615 cm_Gen8Dot3Name(dep, matchName, NULL);
6616 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6621 cm_DirEntryListAdd(dep->name, &rockp->matches);
6628 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6631 clientchar_t *pathp;
6635 clientchar_t *lastNamep;
6636 smb_rmdirRock_t rock;
6640 clientchar_t *tidPathp;
6644 memset(&rock, 0, sizeof(rock));
6646 tp = smb_GetSMBData(inp, NULL);
6647 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6649 return CM_ERROR_BADSMB;
6651 spacep = inp->spacep;
6652 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6654 userp = smb_GetUserFromVCP(vcp, inp);
6656 caseFold = CM_FLAG_CASEFOLD;
6658 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6660 cm_ReleaseUser(userp);
6661 return CM_ERROR_NOSUCHPATH;
6663 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6664 userp, tidPathp, &req, &dscp);
6667 cm_ReleaseUser(userp);
6672 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6673 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6674 cm_ReleaseSCache(dscp);
6675 cm_ReleaseUser(userp);
6676 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6677 return CM_ERROR_PATH_NOT_COVERED;
6679 return CM_ERROR_NOSUCHPATH;
6681 #endif /* DFS_SUPPORT */
6683 /* otherwise, scp points to the parent directory. */
6690 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6692 code = CM_ERROR_NOSUCHFILE;
6695 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6698 thyper.HighPart = 0;
6702 rock.matches = NULL;
6704 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6705 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6706 if (code == 0 && !rock.any) {
6708 thyper.HighPart = 0;
6709 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6710 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6713 if (code == 0 && rock.matches) {
6714 cm_dirEntryList_t * entry;
6716 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6717 clientchar_t clientName[MAX_PATH];
6719 /* We assume this will succeed because smb_RmdirProc()
6720 successfully converted entry->name once above. */
6721 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6723 osi_Log1(smb_logp, "Removing directory %s",
6724 osi_LogSaveString(smb_logp, entry->name));
6726 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6728 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6729 smb_NotifyChange(FILE_ACTION_REMOVED,
6730 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6731 dscp, clientName, NULL, TRUE);
6737 cm_DirEntryListFree(&rock.matches);
6740 cm_ReleaseUser(userp);
6743 cm_ReleaseSCache(dscp);
6745 if (code == 0 && !rock.any)
6746 code = CM_ERROR_NOSUCHFILE;
6755 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6765 fid = smb_GetSMBParm(inp, 0);
6767 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6769 fid = smb_ChainFID(fid, inp);
6770 fidp = smb_FindFID(vcp, fid, 0);
6772 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6774 return CM_ERROR_BADFD;
6776 userp = smb_GetUserFromVCP(vcp, inp);
6778 lock_ObtainMutex(&fidp->mx);
6779 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6780 cm_ReleaseUser(userp);
6781 lock_ReleaseMutex(&fidp->mx);
6782 smb_ReleaseFID(fidp);
6783 return CM_ERROR_BADFD;
6786 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6787 lock_ReleaseMutex(&fidp->mx);
6788 cm_ReleaseUser(userp);
6789 smb_CloseFID(vcp, fidp, NULL, 0);
6790 smb_ReleaseFID(fidp);
6791 return CM_ERROR_NOSUCHFILE;
6794 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6795 cm_scache_t * scp = fidp->scp;
6797 lock_ReleaseMutex(&fidp->mx);
6798 code = cm_FSync(scp, userp, &req, FALSE);
6799 cm_ReleaseSCache(scp);
6801 lock_ReleaseMutex(&fidp->mx);
6805 cm_ReleaseUser(userp);
6806 smb_ReleaseFID(fidp);
6810 struct smb_FullNameRock {
6813 clientchar_t *fullName;
6814 fschar_t *originalName;
6817 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6820 normchar_t matchName[MAX_PATH];
6821 struct smb_FullNameRock *vrockp;
6823 vrockp = (struct smb_FullNameRock *)rockp;
6825 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6826 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6827 osi_LogSaveString(smb_logp, dep->name));
6831 if (!cm_Is8Dot3(matchName)) {
6832 clientchar_t shortName[13];
6834 cm_Gen8Dot3Name(dep, shortName, NULL);
6836 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6837 vrockp->fullName = cm_ClientStrDup(matchName);
6838 vrockp->originalName = cm_FsStrDup(dep->name);
6839 return CM_ERROR_STOPNOW;
6842 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6843 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6844 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6845 vrockp->fullName = cm_ClientStrDup(matchName);
6846 vrockp->originalName = cm_FsStrDup(dep->name);
6847 return CM_ERROR_STOPNOW;
6852 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6853 clientchar_t **newPathp, fschar_t ** originalPathp,
6854 cm_user_t *userp, cm_req_t *reqp)
6856 struct smb_FullNameRock rock;
6859 memset(&rock, 0, sizeof(rock));
6863 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6864 if (code == CM_ERROR_STOPNOW) {
6865 *newPathp = rock.fullName;
6866 *originalPathp = rock.originalName;
6868 *newPathp = cm_ClientStrDup(pathp);
6869 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6873 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6874 afs_uint32 dosTime) {
6877 cm_scache_t *dscp = NULL;
6878 clientchar_t *pathp = NULL;
6879 cm_scache_t * scp = NULL;
6880 cm_scache_t *delscp = NULL;
6881 int nullcreator = 0;
6883 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6884 fidp, fidp->fid, scp, vcp);
6887 lock_ObtainMutex(&fidp->mx);
6888 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6890 lock_ReleaseMutex(&fidp->mx);
6891 osi_Log0(smb_logp, " No user specified. Not closing fid");
6892 return CM_ERROR_BADFD;
6895 userp = fidp->userp; /* no hold required since fidp is held
6896 throughout the function */
6897 lock_ReleaseMutex(&fidp->mx);
6902 lock_ObtainWrite(&smb_rctLock);
6903 if (fidp->deleteOk) {
6904 osi_Log0(smb_logp, " Fid already closed.");
6905 lock_ReleaseWrite(&smb_rctLock);
6906 return CM_ERROR_BADFD;
6909 lock_ReleaseWrite(&smb_rctLock);
6911 lock_ObtainMutex(&fidp->mx);
6912 if (fidp->NTopen_dscp) {
6913 dscp = fidp->NTopen_dscp;
6914 cm_HoldSCache(dscp);
6917 if (fidp->NTopen_pathp)
6918 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6925 /* Don't jump the gun on an async raw write */
6926 while (fidp->raw_writers) {
6927 lock_ReleaseMutex(&fidp->mx);
6928 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6929 lock_ObtainMutex(&fidp->mx);
6932 /* watch for ioctl closes, and read-only opens */
6934 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6935 == SMB_FID_OPENWRITE) {
6936 if (dosTime != 0 && dosTime != -1) {
6937 lock_ObtainWrite(&fidp->scp->rw);
6938 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6939 /* This fixes defect 10958 */
6940 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6941 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6942 lock_ReleaseWrite(&fidp->scp->rw);
6944 if (smb_AsyncStore != 2) {
6945 lock_ReleaseMutex(&fidp->mx);
6946 code = cm_FSync(scp, userp, &req, FALSE);
6947 lock_ObtainMutex(&fidp->mx);
6953 /* unlock any pending locks */
6954 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6955 scp->fileType == CM_SCACHETYPE_FILE) {
6959 lock_ReleaseMutex(&fidp->mx);
6962 * CM_UNLOCK_FLAG_BY_FID doesn't look at the process ID.
6965 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6966 lock_ObtainWrite(&scp->rw);
6968 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6969 CM_SCACHESYNC_NEEDCALLBACK
6970 | CM_SCACHESYNC_GETSTATUS
6971 | CM_SCACHESYNC_LOCK);
6975 "smb CoreClose SyncOp failure code 0x%x", tcode);
6976 goto post_syncopdone;
6979 cm_UnlockByKey(scp, key, CM_UNLOCK_FLAG_BY_FID, userp, &req);
6981 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6985 lock_ReleaseWrite(&scp->rw);
6986 lock_ObtainMutex(&fidp->mx);
6989 if (fidp->flags & SMB_FID_DELONCLOSE) {
6990 clientchar_t *fullPathp = NULL;
6991 fschar_t *originalNamep = NULL;
6993 lock_ReleaseMutex(&fidp->mx);
6995 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
7000 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
7001 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
7002 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
7004 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7005 smb_NotifyChange(FILE_ACTION_REMOVED,
7006 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
7007 dscp, fullPathp, NULL, TRUE);
7010 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
7012 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7013 smb_NotifyChange(FILE_ACTION_REMOVED,
7014 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7015 dscp, fullPathp, NULL, TRUE);
7022 free(originalNamep);
7024 lock_ObtainMutex(&fidp->mx);
7025 fidp->flags &= ~SMB_FID_DELONCLOSE;
7028 /* if this was a newly created file, then clear the creator
7029 * in the stat cache entry. */
7030 if (fidp->flags & SMB_FID_CREATED) {
7032 fidp->flags &= ~SMB_FID_CREATED;
7035 if (fidp->flags & SMB_FID_NTOPEN) {
7036 cm_ReleaseSCache(fidp->NTopen_dscp);
7037 fidp->NTopen_dscp = NULL;
7038 free(fidp->NTopen_pathp);
7039 fidp->NTopen_pathp = NULL;
7040 fidp->flags &= ~SMB_FID_NTOPEN;
7042 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
7043 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7046 if (fidp->NTopen_wholepathp) {
7047 free(fidp->NTopen_wholepathp);
7048 fidp->NTopen_wholepathp = NULL;
7052 cm_ReleaseSCache(fidp->scp);
7055 lock_ReleaseMutex(&fidp->mx);
7058 cm_ReleaseSCache(dscp);
7061 cm_ReleaseSCache(delscp);
7065 lock_ObtainWrite(&scp->rw);
7066 if (nullcreator && scp->creator == userp)
7067 scp->creator = NULL;
7068 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7069 lock_ReleaseWrite(&scp->rw);
7070 cm_ReleaseSCache(scp);
7080 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7088 fid = smb_GetSMBParm(inp, 0);
7089 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7091 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7093 fid = smb_ChainFID(fid, inp);
7094 fidp = smb_FindFID(vcp, fid, 0);
7096 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
7098 return CM_ERROR_BADFD;
7101 userp = smb_GetUserFromVCP(vcp, inp);
7103 code = smb_CloseFID(vcp, fidp, userp, dosTime);
7105 smb_ReleaseFID(fidp);
7106 cm_ReleaseUser(userp);
7111 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7113 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7114 cm_user_t *userp, long *readp)
7120 osi_hyper_t fileLength;
7122 osi_hyper_t lastByte;
7123 osi_hyper_t bufferOffset;
7127 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7130 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7131 fidp->fid, offsetp->LowPart, count);
7135 lock_ObtainMutex(&fidp->mx);
7136 /* make sure we have a readable FD */
7137 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7138 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7139 fidp->fid, fidp->flags);
7140 lock_ReleaseMutex(&fidp->mx);
7141 code = CM_ERROR_BADFDOP;
7146 lock_ReleaseMutex(&fidp->mx);
7147 code = CM_ERROR_BADFD;
7158 lock_ObtainWrite(&scp->rw);
7160 if (offset.HighPart == 0) {
7161 chunk = offset.LowPart >> cm_logChunkSize;
7162 if (chunk != fidp->curr_chunk) {
7163 fidp->prev_chunk = fidp->curr_chunk;
7164 fidp->curr_chunk = chunk;
7166 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7169 lock_ReleaseMutex(&fidp->mx);
7171 /* start by looking up the file's end */
7172 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7173 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7177 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7179 /* now we have the entry locked, look up the length */
7180 fileLength = scp->length;
7182 /* adjust count down so that it won't go past EOF */
7183 thyper.LowPart = count;
7184 thyper.HighPart = 0;
7185 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7187 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7188 /* we'd read past EOF, so just stop at fileLength bytes.
7189 * Start by computing how many bytes remain in the file.
7191 thyper = LargeIntegerSubtract(fileLength, offset);
7193 /* if we are past EOF, read 0 bytes */
7194 if (LargeIntegerLessThanZero(thyper))
7197 count = thyper.LowPart;
7202 /* now, copy the data one buffer at a time,
7203 * until we've filled the request packet
7206 /* if we've copied all the data requested, we're done */
7207 if (count <= 0) break;
7209 /* otherwise, load up a buffer of data */
7210 thyper.HighPart = offset.HighPart;
7211 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7212 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7215 buf_Release(bufferp);
7218 lock_ReleaseWrite(&scp->rw);
7220 code = buf_Get(scp, &thyper, &req, &bufferp);
7222 lock_ObtainWrite(&scp->rw);
7223 if (code) goto done;
7224 bufferOffset = thyper;
7226 /* now get the data in the cache */
7228 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7229 CM_SCACHESYNC_NEEDCALLBACK |
7230 CM_SCACHESYNC_READ);
7234 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7236 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7238 /* otherwise, load the buffer and try again */
7239 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7243 buf_Release(bufferp);
7247 } /* if (wrong buffer) ... */
7249 /* now we have the right buffer loaded. Copy out the
7250 * data from here to the user's buffer.
7252 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7254 /* and figure out how many bytes we want from this buffer */
7255 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7256 if (nbytes > count) nbytes = count; /* don't go past EOF */
7258 /* now copy the data */
7259 memcpy(op, bufferp->datap + bufIndex, nbytes);
7261 /* adjust counters, pointers, etc. */
7264 thyper.LowPart = nbytes;
7265 thyper.HighPart = 0;
7266 offset = LargeIntegerAdd(thyper, offset);
7270 lock_ReleaseWrite(&scp->rw);
7272 buf_Release(bufferp);
7274 if (code == 0 && sequential)
7275 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7277 cm_ReleaseSCache(scp);
7280 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7281 fidp->fid, code, *readp);
7286 * smb_WriteData -- common code for Write and Raw Write
7288 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7289 cm_user_t *userp, long *writtenp)
7291 osi_hyper_t offset = *offsetp;
7294 cm_scache_t *scp = NULL;
7295 osi_hyper_t fileLength; /* file's length at start of write */
7296 osi_hyper_t minLength; /* don't read past this */
7297 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7298 cm_buf_t *bufferp = NULL;
7299 osi_hyper_t thyper; /* hyper tmp variable */
7300 osi_hyper_t bufferOffset;
7301 afs_uint32 bufIndex; /* index in buffer where our data is */
7302 int doWriteBack = 0;
7303 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7306 int needSyncOpDone = 0;
7308 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7309 fidp->fid, offsetp->LowPart, count);
7313 lock_ObtainMutex(&fidp->mx);
7314 /* make sure we have a writable FD */
7315 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7316 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7317 fidp->fid, fidp->flags);
7318 lock_ReleaseMutex(&fidp->mx);
7319 code = CM_ERROR_BADFDOP;
7327 lock_ReleaseMutex(&fidp->mx);
7329 lock_ObtainWrite(&scp->rw);
7330 /* start by looking up the file's end */
7331 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7332 CM_SCACHESYNC_NEEDCALLBACK
7333 | CM_SCACHESYNC_SETSTATUS
7334 | CM_SCACHESYNC_GETSTATUS);
7338 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7340 /* now we have the entry locked, look up the length */
7341 fileLength = scp->length;
7342 minLength = fileLength;
7343 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7344 minLength = scp->serverLength;
7346 /* adjust file length if we extend past EOF */
7347 thyper.LowPart = count;
7348 thyper.HighPart = 0;
7349 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7350 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7351 /* we'd write past EOF, so extend the file */
7352 scp->mask |= CM_SCACHEMASK_LENGTH;
7353 scp->length = thyper;
7354 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7356 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7358 /* now, if the new position (thyper) and the old (offset) are in
7359 * different storeback windows, remember to store back the previous
7360 * storeback window when we're done with the write.
7362 * the purpose of this logic is to slow down the CIFS client
7363 * in order to avoid the client disconnecting during the CLOSE
7364 * operation if there are too many dirty buffers left to write
7365 * than can be accomplished during 45 seconds. This used to be
7366 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7367 * so that we can read larger amounts of data at a time.
7369 if (smb_AsyncStore == 1 &&
7370 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7371 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7372 /* they're different */
7374 writeBackOffset.HighPart = offset.HighPart;
7375 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7380 /* now, copy the data one buffer at a time, until we've filled the
7382 while (count != 0) {
7384 /* handle over quota or out of space */
7385 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7386 *writtenp = written;
7387 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7391 /* otherwise, load up a buffer of data */
7392 thyper.HighPart = offset.HighPart;
7393 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7394 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7397 if (needSyncOpDone) {
7398 cm_SyncOpDone(scp, bufferp,
7399 CM_SCACHESYNC_NEEDCALLBACK
7400 | CM_SCACHESYNC_WRITE
7401 | CM_SCACHESYNC_BUFLOCKED);
7404 lock_ReleaseMutex(&bufferp->mx);
7405 buf_Release(bufferp);
7408 lock_ReleaseWrite(&scp->rw);
7410 code = buf_Get(scp, &thyper, &req, &bufferp);
7412 lock_ObtainMutex(&bufferp->mx);
7413 lock_ObtainWrite(&scp->rw);
7414 if (code) goto done;
7416 bufferOffset = thyper;
7418 /* now get the data in the cache */
7420 if (!needSyncOpDone) {
7421 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7422 CM_SCACHESYNC_NEEDCALLBACK
7423 | CM_SCACHESYNC_WRITE
7424 | CM_SCACHESYNC_BUFLOCKED);
7431 /* If we're overwriting the entire buffer, or
7432 * if we're writing at or past EOF, mark the
7433 * buffer as current so we don't call
7434 * cm_GetBuffer. This skips the fetch from the
7435 * server in those cases where we're going to
7436 * obliterate all the data in the buffer anyway,
7437 * or in those cases where there is no useful
7438 * data at the server to start with.
7440 * Use minLength instead of scp->length, since
7441 * the latter has already been updated by this
7444 * The scp lock has been dropped multiple times
7445 * so the minLength must be refreshed before it
7449 minLength = scp->length;
7450 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7451 minLength = scp->serverLength;
7453 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7454 || LargeIntegerEqualTo(offset, bufferp->offset)
7455 && (count >= cm_data.buf_blockSize
7456 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7457 ConvertLongToLargeInteger(count)),
7459 if (count < cm_data.buf_blockSize
7460 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7461 memset(bufferp->datap, 0,
7462 cm_data.buf_blockSize);
7463 bufferp->dataVersion = scp->dataVersion;
7466 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7468 /* otherwise, load the buffer and try again */
7469 cm_SyncOpDone(scp, bufferp,
7470 CM_SCACHESYNC_NEEDCALLBACK
7471 | CM_SCACHESYNC_WRITE
7472 | CM_SCACHESYNC_BUFLOCKED);
7475 lock_ReleaseMutex(&bufferp->mx);
7476 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7478 lock_ReleaseWrite(&scp->rw);
7479 lock_ObtainMutex(&bufferp->mx);
7480 lock_ObtainWrite(&scp->rw);
7484 } /* if (wrong buffer) ... */
7486 /* now we have the right buffer loaded. Copy out the
7487 * data from here to the user's buffer.
7489 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7491 /* and figure out how many bytes we want from this buffer */
7492 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7494 nbytes = count; /* don't go past end of request */
7496 /* now copy the data */
7497 memcpy(bufferp->datap + bufIndex, op, nbytes);
7498 buf_SetDirty(bufferp, &req, bufIndex, nbytes, userp);
7500 /* adjust counters, pointers, etc. */
7504 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7505 } /* while count != 0 */
7508 if (bufferp && needSyncOpDone) {
7509 cm_SyncOpDone(scp, bufferp,
7510 CM_SCACHESYNC_NEEDCALLBACK
7511 | CM_SCACHESYNC_WRITE
7512 | CM_SCACHESYNC_BUFLOCKED);
7515 lock_ReleaseWrite(&scp->rw);
7518 lock_ReleaseMutex(&bufferp->mx);
7519 buf_Release(bufferp);
7522 lock_ObtainMutex(&fidp->mx);
7523 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7524 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7526 lock_ReleaseMutex(&fidp->mx);
7527 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7528 fidp->NTopen_dscp, fidp->NTopen_pathp,
7531 lock_ReleaseMutex(&fidp->mx);
7535 if (smb_AsyncStore > 0) {
7539 lock_ObtainWrite(&scp->rw);
7540 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7542 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7543 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7545 lock_ReleaseWrite(&scp->rw);
7546 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7547 writeBackOffset.HighPart,
7548 smb_AsyncStoreSize, 0, userp, &req);
7549 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7552 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7556 cm_ReleaseSCache(scp);
7559 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7560 fidp->fid, code, *writtenp);
7565 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7568 unsigned short count;
7570 unsigned short hint;
7571 long written = 0, total_written = 0;
7574 smb_t* smbp = (smb_t*) inp;
7578 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7580 int inDataBlockCount;
7582 fd = smb_GetSMBParm(inp, 0);
7583 count = smb_GetSMBParm(inp, 1);
7584 offset.HighPart = 0; /* too bad */
7585 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7586 hint = smb_GetSMBParm(inp, 4);
7588 op = smb_GetSMBData(inp, NULL);
7589 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7591 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7592 fd, offset.LowPart, count);
7594 fd = smb_ChainFID(fd, inp);
7595 fidp = smb_FindFID(vcp, fd, 0);
7597 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7599 return CM_ERROR_BADFD;
7602 lock_ObtainMutex(&fidp->mx);
7603 if (fidp->flags & SMB_FID_IOCTL) {
7604 lock_ReleaseMutex(&fidp->mx);
7605 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7606 smb_ReleaseFID(fidp);
7607 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7611 if (fidp->flags & SMB_FID_RPC) {
7612 lock_ReleaseMutex(&fidp->mx);
7613 code = smb_RPCWrite(fidp, vcp, inp, outp);
7614 smb_ReleaseFID(fidp);
7615 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7620 lock_ReleaseMutex(&fidp->mx);
7621 smb_ReleaseFID(fidp);
7622 return CM_ERROR_BADFD;
7625 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7626 lock_ReleaseMutex(&fidp->mx);
7627 smb_CloseFID(vcp, fidp, NULL, 0);
7628 smb_ReleaseFID(fidp);
7629 return CM_ERROR_NOSUCHFILE;
7634 lock_ReleaseMutex(&fidp->mx);
7635 userp = smb_GetUserFromVCP(vcp, inp);
7639 LARGE_INTEGER LOffset;
7640 LARGE_INTEGER LLength;
7643 key = cm_GenerateKey(vcp->vcID, pid, fd);
7645 LOffset.HighPart = offset.HighPart;
7646 LOffset.LowPart = offset.LowPart;
7647 LLength.HighPart = 0;
7648 LLength.LowPart = count;
7650 lock_ObtainWrite(&scp->rw);
7651 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7652 lock_ReleaseWrite(&scp->rw);
7655 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7660 /* special case: 0 bytes transferred means truncate to this position */
7664 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7668 truncAttr.mask = CM_ATTRMASK_LENGTH;
7669 truncAttr.length.LowPart = offset.LowPart;
7670 truncAttr.length.HighPart = 0;
7671 lock_ObtainMutex(&fidp->mx);
7672 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7673 fidp->flags |= SMB_FID_LENGTHSETDONE;
7674 lock_ReleaseMutex(&fidp->mx);
7675 smb_SetSMBParm(outp, 0, 0 /* count */);
7676 smb_SetSMBDataLength(outp, 0);
7681 * Work around bug in NT client
7683 * When copying a file, the NT client should first copy the data,
7684 * then copy the last write time. But sometimes the NT client does
7685 * these in the wrong order, so the data copies would inadvertently
7686 * cause the last write time to be overwritten. We try to detect this,
7687 * and don't set client mod time if we think that would go against the
7690 lock_ObtainMutex(&fidp->mx);
7691 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7692 lock_ObtainWrite(&fidp->scp->rw);
7693 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7694 fidp->scp->clientModTime = time(NULL);
7695 lock_ReleaseWrite(&fidp->scp->rw);
7697 lock_ReleaseMutex(&fidp->mx);
7700 while ( code == 0 && count > 0 ) {
7701 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7702 if (code == 0 && written == 0)
7703 code = CM_ERROR_PARTIALWRITE;
7705 offset = LargeIntegerAdd(offset,
7706 ConvertLongToLargeInteger(written));
7707 count -= (unsigned short)written;
7708 total_written += written;
7712 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7713 total_written, code);
7715 /* set the packet data length to 3 bytes for the data block header,
7716 * plus the size of the data.
7718 smb_SetSMBParm(outp, 0, total_written);
7719 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7720 smb_SetSMBParm(outp, 3, hint);
7721 smb_SetSMBDataLength(outp, 0);
7724 smb_ReleaseFID(fidp);
7725 cm_ReleaseUser(userp);
7726 cm_ReleaseSCache(scp);
7731 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7732 NCB *ncbp, raw_write_cont_t *rwcp)
7741 fd = smb_GetSMBParm(inp, 0);
7742 fidp = smb_FindFID(vcp, fd, 0);
7744 lock_ObtainMutex(&fidp->mx);
7746 lock_ReleaseMutex(&fidp->mx);
7747 smb_ReleaseFID(fidp);
7751 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7752 lock_ReleaseMutex(&fidp->mx);
7753 smb_CloseFID(vcp, fidp, NULL, 0);
7754 smb_ReleaseFID(fidp);
7757 lock_ReleaseMutex(&fidp->mx);
7759 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7760 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7762 userp = smb_GetUserFromVCP(vcp, inp);
7765 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7767 if (rwcp->writeMode & 0x1) { /* synchronous */
7770 smb_FormatResponsePacket(vcp, inp, outp);
7771 op = (smb_t *) outp;
7772 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7773 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7774 smb_SetSMBDataLength(outp, 0);
7775 smb_SendPacket(vcp, outp);
7776 smb_FreePacket(outp);
7778 else { /* asynchronous */
7779 lock_ObtainMutex(&fidp->mx);
7780 fidp->raw_writers--;
7781 if (fidp->raw_writers == 0)
7782 thrd_SetEvent(fidp->raw_write_event);
7783 lock_ReleaseMutex(&fidp->mx);
7786 /* Give back raw buffer */
7787 lock_ObtainMutex(&smb_RawBufLock);
7788 *((char **)rawBuf) = smb_RawBufs;
7789 smb_RawBufs = rawBuf;
7790 lock_ReleaseMutex(&smb_RawBufLock);
7792 smb_ReleaseFID(fidp);
7793 cm_ReleaseUser(userp);
7796 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7801 /* SMB_COM_WRITE_RAW */
7802 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7805 long count, written = 0, total_written = 0;
7809 smb_t *smbp = (smb_t*) inp;
7814 unsigned short writeMode;
7816 fd = smb_GetSMBParm(inp, 0);
7817 totalCount = smb_GetSMBParm(inp, 1);
7818 count = smb_GetSMBParm(inp, 10);
7819 writeMode = smb_GetSMBParm(inp, 7);
7821 op = (char *) inp->data;
7822 op += smb_GetSMBParm(inp, 11);
7824 offset.HighPart = 0;
7825 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7827 if (*inp->wctp == 14) {
7828 /* we received a 64-bit file offset */
7829 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7831 if (LargeIntegerLessThanZero(offset)) {
7833 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7834 offset.HighPart, offset.LowPart);
7835 return CM_ERROR_BADSMB;
7838 offset.HighPart = 0; /* 32-bit file offset */
7842 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7843 fd, offset.HighPart, offset.LowPart, count);
7845 " WriteRaw WriteMode 0x%x",
7848 fd = smb_ChainFID(fd, inp);
7849 fidp = smb_FindFID(vcp, fd, 0);
7851 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7853 return CM_ERROR_BADFD;
7855 lock_ObtainMutex(&fidp->mx);
7857 lock_ReleaseMutex(&fidp->mx);
7858 smb_ReleaseFID(fidp);
7859 return CM_ERROR_BADFD;
7862 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7863 lock_ReleaseMutex(&fidp->mx);
7864 smb_CloseFID(vcp, fidp, NULL, 0);
7865 smb_ReleaseFID(fidp);
7866 return CM_ERROR_NOSUCHFILE;
7871 lock_ReleaseMutex(&fidp->mx);
7876 LARGE_INTEGER LOffset;
7877 LARGE_INTEGER LLength;
7880 key = cm_GenerateKey(vcp->vcID, pid, fd);
7882 LOffset.HighPart = offset.HighPart;
7883 LOffset.LowPart = offset.LowPart;
7884 LLength.HighPart = 0;
7885 LLength.LowPart = count;
7887 lock_ObtainWrite(&scp->rw);
7888 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7889 lock_ReleaseWrite(&scp->rw);
7892 cm_ReleaseSCache(scp);
7893 smb_ReleaseFID(fidp);
7898 userp = smb_GetUserFromVCP(vcp, inp);
7901 * Work around bug in NT client
7903 * When copying a file, the NT client should first copy the data,
7904 * then copy the last write time. But sometimes the NT client does
7905 * these in the wrong order, so the data copies would inadvertently
7906 * cause the last write time to be overwritten. We try to detect this,
7907 * and don't set client mod time if we think that would go against the
7910 lock_ObtainMutex(&fidp->mx);
7911 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7912 lock_ObtainWrite(&fidp->scp->rw);
7913 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7914 fidp->scp->clientModTime = time(NULL);
7915 lock_ReleaseWrite(&fidp->scp->rw);
7917 lock_ReleaseMutex(&fidp->mx);
7920 while ( code == 0 && count > 0 ) {
7921 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7922 if (code == 0 && written == 0)
7923 code = CM_ERROR_PARTIALWRITE;
7925 offset = LargeIntegerAdd(offset,
7926 ConvertLongToLargeInteger(written));
7929 total_written += written;
7933 /* Get a raw buffer */
7936 lock_ObtainMutex(&smb_RawBufLock);
7938 /* Get a raw buf, from head of list */
7939 rawBuf = smb_RawBufs;
7940 smb_RawBufs = *(char **)smb_RawBufs;
7943 code = CM_ERROR_USESTD;
7945 lock_ReleaseMutex(&smb_RawBufLock);
7948 /* Don't allow a premature Close */
7949 if (code == 0 && (writeMode & 1) == 0) {
7950 lock_ObtainMutex(&fidp->mx);
7951 fidp->raw_writers++;
7952 thrd_ResetEvent(fidp->raw_write_event);
7953 lock_ReleaseMutex(&fidp->mx);
7956 smb_ReleaseFID(fidp);
7957 cm_ReleaseUser(userp);
7958 cm_ReleaseSCache(scp);
7961 smb_SetSMBParm(outp, 0, total_written);
7962 smb_SetSMBDataLength(outp, 0);
7963 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7968 offset = LargeIntegerAdd(offset,
7969 ConvertLongToLargeInteger(count));
7973 rwcp->offset.HighPart = offset.HighPart;
7974 rwcp->offset.LowPart = offset.LowPart;
7975 rwcp->count = totalCount - count;
7976 rwcp->writeMode = writeMode;
7977 rwcp->alreadyWritten = total_written;
7979 /* set the packet data length to 3 bytes for the data block header,
7980 * plus the size of the data.
7982 smb_SetSMBParm(outp, 0, 0xffff);
7983 smb_SetSMBDataLength(outp, 0);
7989 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7992 long count, finalCount;
7996 smb_t *smbp = (smb_t*) inp;
8002 fd = smb_GetSMBParm(inp, 0);
8003 count = smb_GetSMBParm(inp, 1);
8004 offset.HighPart = 0; /* too bad */
8005 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8007 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
8008 fd, offset.LowPart, count);
8010 fd = smb_ChainFID(fd, inp);
8011 fidp = smb_FindFID(vcp, fd, 0);
8013 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
8015 return CM_ERROR_BADFD;
8017 lock_ObtainMutex(&fidp->mx);
8018 if (fidp->flags & SMB_FID_IOCTL) {
8019 lock_ReleaseMutex(&fidp->mx);
8020 code = smb_IoctlRead(fidp, vcp, inp, outp);
8021 smb_ReleaseFID(fidp);
8025 if (fidp->flags & SMB_FID_RPC) {
8026 lock_ReleaseMutex(&fidp->mx);
8027 code = smb_RPCRead(fidp, vcp, inp, outp);
8028 smb_ReleaseFID(fidp);
8033 lock_ReleaseMutex(&fidp->mx);
8034 smb_ReleaseFID(fidp);
8035 return CM_ERROR_BADFD;
8038 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8039 lock_ReleaseMutex(&fidp->mx);
8040 smb_CloseFID(vcp, fidp, NULL, 0);
8041 smb_ReleaseFID(fidp);
8042 return CM_ERROR_NOSUCHFILE;
8047 lock_ReleaseMutex(&fidp->mx);
8050 LARGE_INTEGER LOffset, LLength;
8054 key = cm_GenerateKey(vcp->vcID, pid, fd);
8056 LOffset.HighPart = 0;
8057 LOffset.LowPart = offset.LowPart;
8058 LLength.HighPart = 0;
8059 LLength.LowPart = count;
8061 lock_ObtainWrite(&scp->rw);
8062 code = cm_LockCheckRead(scp, LOffset, LLength, key);
8063 lock_ReleaseWrite(&scp->rw);
8066 cm_ReleaseSCache(scp);
8067 smb_ReleaseFID(fidp);
8071 userp = smb_GetUserFromVCP(vcp, inp);
8073 /* remember this for final results */
8074 smb_SetSMBParm(outp, 0, count);
8075 smb_SetSMBParm(outp, 1, 0);
8076 smb_SetSMBParm(outp, 2, 0);
8077 smb_SetSMBParm(outp, 3, 0);
8078 smb_SetSMBParm(outp, 4, 0);
8080 /* set the packet data length to 3 bytes for the data block header,
8081 * plus the size of the data.
8083 smb_SetSMBDataLength(outp, count+3);
8085 /* get op ptr after putting in the parms, since otherwise we don't
8086 * know where the data really is.
8088 op = smb_GetSMBData(outp, NULL);
8090 /* now emit the data block header: 1 byte of type and 2 bytes of length */
8091 *op++ = 1; /* data block marker */
8092 *op++ = (unsigned char) (count & 0xff);
8093 *op++ = (unsigned char) ((count >> 8) & 0xff);
8095 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8097 /* fix some things up */
8098 smb_SetSMBParm(outp, 0, finalCount);
8099 smb_SetSMBDataLength(outp, finalCount+3);
8101 smb_ReleaseFID(fidp);
8103 cm_ReleaseUser(userp);
8104 cm_ReleaseSCache(scp);
8108 /* SMB_COM_CREATE_DIRECTORY */
8109 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8111 clientchar_t *pathp;
8116 cm_scache_t *dscp; /* dir we're dealing with */
8117 cm_scache_t *scp; /* file we're creating */
8119 int initialModeBits;
8120 clientchar_t *lastNamep;
8122 clientchar_t *tidPathp;
8129 /* compute initial mode bits based on read-only flag in attributes */
8130 initialModeBits = 0777;
8132 tp = smb_GetSMBData(inp, NULL);
8133 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8135 return CM_ERROR_BADSMB;
8137 spacep = inp->spacep;
8138 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8140 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8141 return CM_ERROR_EXISTS;
8143 userp = smb_GetUserFromVCP(vcp, inp);
8145 caseFold = CM_FLAG_CASEFOLD;
8147 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8149 cm_ReleaseUser(userp);
8150 return CM_ERROR_NOSUCHPATH;
8153 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
8154 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8155 userp, tidPathp, &req, &dscp);
8158 cm_ReleaseUser(userp);
8163 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8164 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8165 cm_ReleaseSCache(dscp);
8166 cm_ReleaseUser(userp);
8167 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8168 return CM_ERROR_PATH_NOT_COVERED;
8170 return CM_ERROR_NOSUCHPATH;
8172 #endif /* DFS_SUPPORT */
8174 /* otherwise, scp points to the parent directory. Do a lookup, and
8175 * fail if we find it. Otherwise, we do the create.
8181 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8182 if (scp) cm_ReleaseSCache(scp);
8183 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8184 if (code == 0) code = CM_ERROR_EXISTS;
8185 cm_ReleaseSCache(dscp);
8186 cm_ReleaseUser(userp);
8190 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8191 setAttr.clientModTime = time(NULL);
8192 smb_SetInitialModeBitsForDir(0, &setAttr);
8194 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8195 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8196 smb_NotifyChange(FILE_ACTION_ADDED,
8197 FILE_NOTIFY_CHANGE_DIR_NAME,
8198 dscp, lastNamep, NULL, TRUE);
8200 /* we don't need this any longer */
8201 cm_ReleaseSCache(dscp);
8204 /* something went wrong creating or truncating the file */
8205 cm_ReleaseUser(userp);
8209 /* otherwise we succeeded */
8210 smb_SetSMBDataLength(outp, 0);
8211 cm_ReleaseUser(userp);
8216 BOOL smb_IsLegalFilename(clientchar_t *filename)
8219 * Find the longest substring of filename that does not contain
8220 * any of the chars in illegalChars. If that substring is less
8221 * than the length of the whole string, then one or more of the
8222 * illegal chars is in filename.
8224 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8230 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8231 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8233 clientchar_t *pathp;
8239 cm_scache_t *dscp; /* dir we're dealing with */
8240 cm_scache_t *scp; /* file we're creating */
8244 clientchar_t *lastNamep;
8247 clientchar_t *tidPathp;
8249 int created = 0; /* the file was new */
8254 excl = (inp->inCom == 0x03)? 0 : 1;
8256 attributes = smb_GetSMBParm(inp, 0);
8257 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8259 tp = smb_GetSMBData(inp, NULL);
8260 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8262 return CM_ERROR_BADSMB;
8264 spacep = inp->spacep;
8265 /* smb_StripLastComponent will strip "::$DATA" if present */
8266 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8268 if (!cm_IsValidClientString(pathp)) {
8270 clientchar_t * hexp;
8272 hexp = cm_GetRawCharsAlloc(pathp, -1);
8273 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8274 osi_LogSaveClientString(smb_logp, hexp));
8278 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8280 return CM_ERROR_BADNTFILENAME;
8283 userp = smb_GetUserFromVCP(vcp, inp);
8285 caseFold = CM_FLAG_CASEFOLD;
8287 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8289 cm_ReleaseUser(userp);
8290 return CM_ERROR_NOSUCHPATH;
8292 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8293 userp, tidPathp, &req, &dscp);
8296 cm_ReleaseUser(userp);
8301 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8302 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8303 cm_ReleaseSCache(dscp);
8304 cm_ReleaseUser(userp);
8305 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8306 return CM_ERROR_PATH_NOT_COVERED;
8308 return CM_ERROR_NOSUCHPATH;
8310 #endif /* DFS_SUPPORT */
8312 /* otherwise, scp points to the parent directory. Do a lookup, and
8313 * truncate the file if we find it, otherwise we create the file.
8320 if (!smb_IsLegalFilename(lastNamep))
8321 return CM_ERROR_BADNTFILENAME;
8323 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8324 #ifdef DEBUG_VERBOSE
8327 hexp = osi_HexifyString( lastNamep );
8328 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8333 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8334 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8335 cm_ReleaseSCache(dscp);
8336 cm_ReleaseUser(userp);
8340 /* if we get here, if code is 0, the file exists and is represented by
8341 * scp. Otherwise, we have to create it.
8345 /* oops, file shouldn't be there */
8346 cm_ReleaseSCache(dscp);
8347 cm_ReleaseSCache(scp);
8348 cm_ReleaseUser(userp);
8349 return CM_ERROR_EXISTS;
8352 setAttr.mask = CM_ATTRMASK_LENGTH;
8353 setAttr.length.LowPart = 0;
8354 setAttr.length.HighPart = 0;
8355 code = cm_SetAttr(scp, &setAttr, userp, &req);
8358 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8359 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8360 smb_SetInitialModeBitsForFile(attributes, &setAttr);
8362 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8366 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8367 smb_NotifyChange(FILE_ACTION_ADDED,
8368 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8369 dscp, lastNamep, NULL, TRUE);
8370 } else if (!excl && code == CM_ERROR_EXISTS) {
8371 /* not an exclusive create, and someone else tried
8372 * creating it already, then we open it anyway. We
8373 * don't bother retrying after this, since if this next
8374 * fails, that means that the file was deleted after
8375 * we started this call.
8377 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8380 setAttr.mask = CM_ATTRMASK_LENGTH;
8381 setAttr.length.LowPart = 0;
8382 setAttr.length.HighPart = 0;
8383 code = cm_SetAttr(scp, &setAttr, userp, &req);
8388 /* we don't need this any longer */
8389 cm_ReleaseSCache(dscp);
8392 /* something went wrong creating or truncating the file */
8393 if (scp) cm_ReleaseSCache(scp);
8394 cm_ReleaseUser(userp);
8398 /* make sure we only open files */
8399 if (scp->fileType != CM_SCACHETYPE_FILE) {
8400 cm_ReleaseSCache(scp);
8401 cm_ReleaseUser(userp);
8402 return CM_ERROR_ISDIR;
8405 /* now all we have to do is open the file itself */
8406 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8407 osi_assertx(fidp, "null smb_fid_t");
8411 lock_ObtainMutex(&fidp->mx);
8412 /* always create it open for read/write */
8413 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8415 /* remember that the file was newly created */
8417 fidp->flags |= SMB_FID_CREATED;
8419 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8421 /* save a pointer to the vnode */
8423 lock_ObtainWrite(&scp->rw);
8424 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8425 lock_ReleaseWrite(&scp->rw);
8428 fidp->userp = userp;
8429 lock_ReleaseMutex(&fidp->mx);
8431 smb_SetSMBParm(outp, 0, fidp->fid);
8432 smb_SetSMBDataLength(outp, 0);
8434 cm_Open(scp, 0, userp);
8436 smb_ReleaseFID(fidp);
8437 cm_ReleaseUser(userp);
8438 /* leave scp held since we put it in fidp->scp */
8443 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8446 osi_hyper_t new_offset;
8457 fd = smb_GetSMBParm(inp, 0);
8458 whence = smb_GetSMBParm(inp, 1);
8459 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8461 /* try to find the file descriptor */
8462 fd = smb_ChainFID(fd, inp);
8463 fidp = smb_FindFID(vcp, fd, 0);
8465 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8467 return CM_ERROR_BADFD;
8469 lock_ObtainMutex(&fidp->mx);
8470 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8471 lock_ReleaseMutex(&fidp->mx);
8472 smb_ReleaseFID(fidp);
8473 return CM_ERROR_BADFD;
8476 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8477 lock_ReleaseMutex(&fidp->mx);
8478 smb_CloseFID(vcp, fidp, NULL, 0);
8479 smb_ReleaseFID(fidp);
8480 return CM_ERROR_NOSUCHFILE;
8483 lock_ReleaseMutex(&fidp->mx);
8485 userp = smb_GetUserFromVCP(vcp, inp);
8487 lock_ObtainMutex(&fidp->mx);
8490 lock_ReleaseMutex(&fidp->mx);
8491 lock_ObtainWrite(&scp->rw);
8492 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8493 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8495 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8497 /* offset from current offset */
8498 new_offset = LargeIntegerAdd(fidp->offset,
8499 ConvertLongToLargeInteger(offset));
8501 else if (whence == 2) {
8502 /* offset from current EOF */
8503 new_offset = LargeIntegerAdd(scp->length,
8504 ConvertLongToLargeInteger(offset));
8506 new_offset = ConvertLongToLargeInteger(offset);
8509 fidp->offset = new_offset;
8510 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8511 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8512 smb_SetSMBDataLength(outp, 0);
8514 lock_ReleaseWrite(&scp->rw);
8515 smb_ReleaseFID(fidp);
8516 cm_ReleaseSCache(scp);
8517 cm_ReleaseUser(userp);
8521 /* dispatch all of the requests received in a packet. Due to chaining, this may
8522 * be more than one request.
8524 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8525 NCB *ncbp, raw_write_cont_t *rwcp)
8529 unsigned long code = 0;
8530 unsigned char *outWctp;
8531 int nparms; /* # of bytes of parameters */
8533 int nbytes; /* bytes of data, excluding count */
8536 unsigned short errCode;
8537 unsigned long NTStatus;
8539 unsigned char errClass;
8540 unsigned int oldGen;
8541 DWORD oldTime, newTime;
8543 /* get easy pointer to the data */
8544 smbp = (smb_t *) inp->data;
8546 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8547 /* setup the basic parms for the initial request in the packet */
8548 inp->inCom = smbp->com;
8549 inp->wctp = &smbp->wct;
8551 inp->ncb_length = ncbp->ncb_length;
8556 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8557 /* log it and discard it */
8558 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8559 __FILE__, __LINE__, ncbp->ncb_length);
8560 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8564 /* We are an ongoing op */
8565 thrd_Increment(&ongoingOps);
8567 /* set up response packet for receiving output */
8568 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8569 smb_FormatResponsePacket(vcp, inp, outp);
8570 outWctp = outp->wctp;
8572 /* Remember session generation number and time */
8573 oldGen = sessionGen;
8574 oldTime = GetTickCount();
8576 while (inp->inCom != 0xff) {
8577 dp = &smb_dispatchTable[inp->inCom];
8579 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8580 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8581 code = outp->resumeCode;
8585 /* process each request in the packet; inCom, wctp and inCount
8586 * are already set up.
8588 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8591 /* now do the dispatch */
8592 /* start by formatting the response record a little, as a default */
8593 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8595 outWctp[1] = 0xff; /* no operation */
8596 outWctp[2] = 0; /* padding */
8601 /* not a chained request, this is a more reasonable default */
8602 outWctp[0] = 0; /* wct of zero */
8603 outWctp[1] = 0; /* and bcc (word) of zero */
8607 /* once set, stays set. Doesn't matter, since we never chain
8608 * "no response" calls.
8610 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8614 /* we have a recognized operation */
8615 char * opName = myCrt_Dispatch(inp->inCom);
8618 smbp = (smb_t *) inp;
8620 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8621 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8622 if (inp->inCom == 0x1d) {
8624 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8626 code = (*(dp->procp)) (vcp, inp, outp);
8628 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8629 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8631 newTime = GetTickCount();
8632 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8633 opName, smbp->mid, newTime - oldTime);
8636 if ( code == CM_ERROR_BADSMB ||
8637 code == CM_ERROR_BADOP )
8639 #endif /* LOG_PACKET */
8641 /* ReceiveV3Tran2A handles its own logging */
8642 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8645 clientchar_t *treepath = NULL; /* do not free */
8646 clientchar_t *pathname = NULL;
8647 cm_fid_t afid = {0,0,0,0,0};
8649 uidp = smb_FindUID(vcp, smbp->uid, 0);
8650 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8651 fidp = smb_FindFID(vcp, inp->fid, 0);
8654 lock_ObtainMutex(&fidp->mx);
8655 if (fidp->NTopen_pathp)
8656 pathname = fidp->NTopen_pathp;
8658 afid = fidp->scp->fid;
8660 if (inp->stringsp->wdata)
8661 pathname = inp->stringsp->wdata;
8664 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)",
8665 opName, newTime - oldTime,
8666 smbp->uid, uidp ? uidp->unp->name : NULL,
8667 smbp->pid, smbp->mid, smbp->tid,
8670 afid.cell, afid.volume, afid.vnode, afid.unique);
8673 lock_ReleaseMutex(&fidp->mx);
8676 smb_ReleaseUID(uidp);
8678 smb_ReleaseFID(fidp);
8681 if (oldGen != sessionGen) {
8682 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8683 newTime - oldTime, ncbp->ncb_length);
8684 osi_Log3(smb_logp, "Request %s straddled session startup, "
8685 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8688 FreeSMBStrings(inp);
8690 /* bad opcode, fail the request, after displaying it */
8691 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8694 #endif /* LOG_PACKET */
8697 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8698 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8699 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8700 if (code == IDCANCEL)
8703 code = CM_ERROR_BADOP;
8706 /* catastrophic failure: log as much as possible */
8707 if (code == CM_ERROR_BADSMB) {
8708 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8712 #endif /* LOG_PACKET */
8713 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8716 code = CM_ERROR_INVAL;
8719 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8720 thrd_Decrement(&ongoingOps);
8725 /* now, if we failed, turn the current response into an empty
8726 * one, and fill in the response packet's error code.
8729 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8730 smb_MapNTError(code, &NTStatus, FALSE);
8731 outWctp = outp->wctp;
8732 smbp = (smb_t *) &outp->data;
8733 if (code != CM_ERROR_PARTIALWRITE
8734 && code != CM_ERROR_BUFFERTOOSMALL
8735 && code != CM_ERROR_GSSCONTINUE) {
8736 /* nuke wct and bcc. For a partial
8737 * write or an in-process authentication handshake,
8738 * assume they're OK.
8744 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8745 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8746 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8747 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8748 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8752 smb_MapCoreError(code, vcp, &errCode, &errClass);
8753 outWctp = outp->wctp;
8754 smbp = (smb_t *) &outp->data;
8755 if (code != CM_ERROR_PARTIALWRITE) {
8756 /* nuke wct and bcc. For a partial
8757 * write, assume they're OK.
8763 smbp->errLow = (unsigned char) (errCode & 0xff);
8764 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8765 smbp->rcls = errClass;
8768 } /* error occurred */
8770 /* if we're here, we've finished one request. Look to see if
8771 * this is a chained opcode. If it is, setup things to process
8772 * the chained request, and setup the output buffer to hold the
8773 * chained response. Start by finding the next input record.
8775 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8776 break; /* not a chained req */
8777 tp = inp->wctp; /* points to start of last request */
8778 /* in a chained request, the first two
8779 * parm fields are required, and are
8780 * AndXCommand/AndXReserved and
8782 if (tp[0] < 2) break;
8783 if (tp[1] == 0xff) break; /* no more chained opcodes */
8785 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8788 /* and now append the next output request to the end of this
8789 * last request. Begin by finding out where the last response
8790 * ends, since that's where we'll put our new response.
8792 outWctp = outp->wctp; /* ptr to out parameters */
8793 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8794 nparms = outWctp[0] << 1;
8795 tp = outWctp + nparms + 1; /* now points to bcc field */
8796 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8797 tp += 2 /* for the count itself */ + nbytes;
8798 /* tp now points to the new output record; go back and patch the
8799 * second parameter (off2) to point to the new record.
8801 temp = (unsigned int)(tp - outp->data);
8802 outWctp[3] = (unsigned char) (temp & 0xff);
8803 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8804 outWctp[2] = 0; /* padding */
8805 outWctp[1] = inp->inCom; /* next opcode */
8807 /* finally, setup for the next iteration */
8810 } /* while loop over all requests in the packet */
8812 /* now send the output packet, and return */
8814 smb_SendPacket(vcp, outp);
8815 thrd_Decrement(&ongoingOps);
8820 /* Wait for Netbios() calls to return, and make the results available to server
8821 * threads. Note that server threads can't wait on the NCBevents array
8822 * themselves, because NCB events are manual-reset, and the servers would race
8823 * each other to reset them.
8825 void smb_ClientWaiter(void *parmp)
8830 while (smbShutdownFlag == 0) {
8831 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8833 if (code == WAIT_OBJECT_0)
8836 /* error checking */
8837 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8839 int abandonIdx = code - WAIT_ABANDONED_0;
8840 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8843 if (code == WAIT_IO_COMPLETION)
8845 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8849 if (code == WAIT_TIMEOUT)
8851 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8854 if (code == WAIT_FAILED)
8856 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8859 idx = code - WAIT_OBJECT_0;
8861 /* check idx range! */
8862 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8864 /* this is fatal - log as much as possible */
8865 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8866 osi_assertx(0, "invalid index");
8869 thrd_ResetEvent(NCBevents[idx]);
8870 thrd_SetEvent(NCBreturns[0][idx]);
8875 * Try to have one NCBRECV request waiting for every live session. Not more
8876 * than one, because if there is more than one, it's hard to handle Write Raw.
8878 void smb_ServerWaiter(void *parmp)
8881 int idx_session, idx_NCB;
8884 while (smbShutdownFlag == 0) {
8886 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8888 if (code == WAIT_OBJECT_0)
8891 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8893 int abandonIdx = code - WAIT_ABANDONED_0;
8894 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8897 if (code == WAIT_IO_COMPLETION)
8899 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8903 if (code == WAIT_TIMEOUT)
8905 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8908 if (code == WAIT_FAILED)
8910 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8913 idx_session = code - WAIT_OBJECT_0;
8915 /* check idx range! */
8916 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8918 /* this is fatal - log as much as possible */
8919 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8920 osi_assertx(0, "invalid index");
8925 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8927 if (code == WAIT_OBJECT_0) {
8928 if (smbShutdownFlag == 1)
8934 /* error checking */
8935 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8937 int abandonIdx = code - WAIT_ABANDONED_0;
8938 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8941 if (code == WAIT_IO_COMPLETION)
8943 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8947 if (code == WAIT_TIMEOUT)
8949 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8952 if (code == WAIT_FAILED)
8954 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8957 idx_NCB = code - WAIT_OBJECT_0;
8959 /* check idx range! */
8960 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8962 /* this is fatal - log as much as possible */
8963 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8964 osi_assertx(0, "invalid index");
8967 /* Link them together */
8968 NCBsessions[idx_NCB] = idx_session;
8971 ncbp = NCBs[idx_NCB];
8972 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8973 ncbp->ncb_command = NCBRECV | ASYNCH;
8974 ncbp->ncb_lana_num = lanas[idx_session];
8975 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8976 ncbp->ncb_event = NCBevents[idx_NCB];
8977 ncbp->ncb_length = SMB_PACKETSIZE;
8982 typedef struct _monitored_task {
8985 LARGE_INTEGER start_time;
8987 BOOL trace_timer_hit;
8988 BOOL dump_timer_hit;
8991 typedef struct osi_queueHT {
8992 osi_queue_t * headp;
8993 osi_queue_t * tailp;
8996 static osi_queue_t *smb_monitored_tasks = NULL;
8997 static osi_queue_t *smb_free_monitored_tasks = NULL;
8999 static osi_mutex_t _monitor_mx;
9001 static HANDLE h_monitored_task_queue = NULL;
9002 static HANDLE h_monitored_task_shutdown = NULL;
9004 static time_t smb_last_dump_time = 0;
9006 DWORD smb_monitorReqs = 0;
9008 /* FILETIME comparison fuzz */
9009 #define MONITOR_FUZZ_TIMEOUT (1 * 10000000i64)
9011 /* Trace timeout is at 60 seconds */
9012 #define MONITOR_TRACE_TIMEOUT (60 * 10000000i64)
9014 /* Dump timeout is at 120 seconds */
9015 #define MONITOR_DUMP_TIMEOUT (120 * 10000000i64)
9017 /* Time before another dump is performed in seconds*/
9018 #define MONITOR_DUMP_RESET_TIMEOUT (600)
9020 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
9023 LARGE_INTEGER earliest;
9026 GetSystemTimeAsFileTime(&now);
9027 earliest.LowPart = now.dwLowDateTime;
9028 earliest.HighPart = now.dwHighDateTime;
9029 earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
9031 while ((t = (monitored_task *) taskmq->headp) != NULL &&
9033 (t->start_time.QuadPart < earliest.QuadPart ||
9035 t->dump_timer_hit)) {
9037 osi_QRemoveHT(&taskmq->headp,
9041 lock_ObtainMutex(&_monitor_mx);
9042 osi_QAdd(&smb_free_monitored_tasks, &t->q);
9043 lock_ReleaseMutex(&_monitor_mx);
9046 #ifdef INVARIANT_CHECK
9052 for (t = (monitored_task *) taskmq->headp;
9054 t = (monitored_task *) osi_QNext(&t->q)) {
9055 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9056 last.QuadPart = t->start_time.QuadPart;
9062 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
9064 monitored_task * task;
9065 monitored_task * tasks;
9067 lock_ObtainMutex(&_monitor_mx);
9068 tasks = (monitored_task *) smb_monitored_tasks;
9069 smb_monitored_tasks = NULL;
9070 lock_ReleaseMutex(&_monitor_mx);
9075 osi_QRemove((osi_queue_t **) &tasks, &task->q);
9077 if (task->started) {
9083 q.prevp = taskmq->tailp;
9085 /* Insertion sort by start_time. Earliest request is
9086 first. Since we are likely to receive new requests
9087 later, we start inserting from the back. */
9090 ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
9094 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
9095 else if (p->prevp == NULL)
9096 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
9098 osi_queue_t *o = p->prevp;
9100 osi_assert(o->nextp == p);
9104 p->prevp = &task->q;
9105 o->nextp = &task->q;
9109 /* Some task ending */
9113 for (p = taskmq->headp;
9117 monitored_task * mt = (monitored_task *) p;
9119 if (mt->task_id == task->task_id) {
9121 osi_QRemoveHT(&taskmq->headp,
9124 lock_ObtainMutex(&_monitor_mx);
9125 osi_QAdd(&smb_free_monitored_tasks, p);
9126 lock_ReleaseMutex(&_monitor_mx);
9132 lock_ObtainMutex(&_monitor_mx);
9133 osi_QAdd(&smb_free_monitored_tasks, &task->q);
9134 lock_ReleaseMutex(&_monitor_mx);
9138 #ifdef INVARIANT_CHECK
9145 for (t = (monitored_task *) taskmq->headp;
9147 t = (monitored_task *) osi_QNext(&t->q)) {
9148 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9149 last.QuadPart = t->start_time.QuadPart;
9155 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9157 if (!task->trace_timer_hit) {
9159 task->trace_timer_hit = TRUE;
9161 osi_LogEnable(afsd_logp);
9162 rx_DebugOnOff(TRUE);
9164 } else if (!task->dump_timer_hit) {
9169 if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9170 task->dump_timer_hit = TRUE;
9171 smb_last_dump_time = now;
9173 GenerateMiniDump(NULL);
9179 * Server request monitoring
9181 * The server monitor runs in a separate thread and monitors server
9182 * requests for potential timeouts. It examines notifcations queued
9183 * by smb_NotifyRequestEvent() and waits for potential timeout events:
9185 * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9186 * enables trace logging.
9188 * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9189 * out a dump file that will hopefully contain enough evidence to
9190 * figure out why the timeout event occurred.
9193 void smb_ServerMonitor(VOID * parmp)
9195 osi_queueHT_t in_progress = { NULL, NULL };
9196 HANDLE h_timer = NULL;
9200 h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9201 h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9202 h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9204 lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9206 h_all[0] = h_monitored_task_queue;
9208 h_all[2] = h_monitored_task_shutdown;
9213 rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9215 if (rv == WAIT_OBJECT_0) {
9217 smb_SlurpNewTaskMonitors(&in_progress);
9219 } else if (rv == WAIT_OBJECT_0 + 1) {
9221 smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9229 /* refresh timers */
9233 smb_PurgeOldTaskMonitors(&in_progress);
9234 t = (monitored_task *) in_progress.headp;
9236 if (t && !t->trace_timer_hit) {
9239 due = t->start_time;
9240 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9242 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9243 } else if (t && !t->dump_timer_hit) {
9247 due = t->start_time;
9248 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9250 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9252 CancelWaitableTimer(h_timer);
9254 /* CancelWaitableTimer() doesn't reset the timer if it
9255 was already signalled. */
9256 WaitForSingleObject(h_timer, 0);
9264 h = h_monitored_task_queue;
9265 h_monitored_task_queue = NULL;
9268 h = h_monitored_task_shutdown;
9269 h_monitored_task_shutdown = NULL;
9272 CloseHandle(h_timer);
9274 lock_FinalizeMutex(&_monitor_mx);
9278 monitored_task * task;
9280 while (in_progress.headp) {
9281 task = (monitored_task *) in_progress.headp;
9282 osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9286 for (task = (monitored_task *) smb_free_monitored_tasks;
9287 task; task = (monitored_task *) smb_free_monitored_tasks) {
9288 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9292 for (task = (monitored_task *) smb_monitored_tasks;
9293 task; task = (monitored_task *) smb_monitored_tasks) {
9294 osi_QRemove(&smb_monitored_tasks, &task->q);
9300 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9302 monitored_task * task;
9304 lock_ObtainMutex(&_monitor_mx);
9305 task = (monitored_task *) smb_free_monitored_tasks;
9307 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9308 lock_ReleaseMutex(&_monitor_mx);
9311 task = malloc(sizeof(monitored_task));
9312 memset(task, 0, sizeof(*task));
9314 task->task_id = task_id;
9315 task->started = started;
9320 GetSystemTimeAsFileTime(&now);
9321 task->start_time.HighPart = now.dwHighDateTime;
9322 task->start_time.LowPart = now.dwLowDateTime;
9325 lock_ObtainMutex(&_monitor_mx);
9326 osi_QAdd(&smb_monitored_tasks, &task->q);
9327 lock_ReleaseMutex(&_monitor_mx);
9329 SetEvent(h_monitored_task_queue);
9332 void smb_ShutdownMonitor()
9334 SetEvent(h_monitored_task_shutdown);
9338 * The top level loop for handling SMB request messages. Each server thread
9339 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9340 * NCB and buffer for the incoming request are loaned to us.
9342 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
9343 * to immediately send a request for the rest of the data. This must come
9344 * before any other traffic for that session, so we delay setting the session
9345 * event until that data has come in.
9347 void smb_Server(VOID *parmp)
9349 INT_PTR myIdx = (INT_PTR) parmp;
9353 smb_packet_t *outbufp;
9355 int idx_NCB, idx_session;
9357 smb_vc_t *vcp = NULL;
9360 rx_StartClientThread();
9362 outncbp = smb_GetNCB();
9363 outbufp = smb_GetPacket();
9364 outbufp->ncbp = outncbp;
9372 cm_ResetServerPriority();
9374 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9377 /* terminate silently if shutdown flag is set */
9378 if (code == WAIT_OBJECT_0) {
9379 if (smbShutdownFlag == 1) {
9380 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9386 /* error checking */
9387 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9389 int abandonIdx = code - WAIT_ABANDONED_0;
9390 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9393 if (code == WAIT_IO_COMPLETION)
9395 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9399 if (code == WAIT_TIMEOUT)
9401 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9404 if (code == WAIT_FAILED)
9406 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9409 idx_NCB = code - WAIT_OBJECT_0;
9411 /* check idx range! */
9412 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9414 /* this is fatal - log as much as possible */
9415 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9416 osi_assertx(0, "invalid index");
9419 ncbp = NCBs[idx_NCB];
9420 idx_session = NCBsessions[idx_NCB];
9421 rc = ncbp->ncb_retcode;
9423 if (rc != NRC_PENDING && rc != NRC_GOODRET)
9424 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9428 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9432 /* Can this happen? Or is it just my UNIX paranoia? */
9433 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9438 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9441 /* Client closed session */
9442 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9444 lock_ObtainMutex(&vcp->mx);
9445 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9446 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9448 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9449 lock_ReleaseMutex(&vcp->mx);
9450 lock_ObtainWrite(&smb_globalLock);
9451 dead_sessions[vcp->session] = TRUE;
9452 lock_ReleaseWrite(&smb_globalLock);
9454 lock_ReleaseMutex(&vcp->mx);
9456 smb_CleanupDeadVC(vcp);
9463 /* Treat as transient error */
9464 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9467 "dispatch smb recv failed, message incomplete, ncb_length %d",
9470 "SMB message incomplete, "
9471 "length %d", ncbp->ncb_length);
9474 * We used to discard the packet.
9475 * Instead, try handling it normally.
9479 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9483 /* A weird error code. Log it, sleep, and continue. */
9484 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9486 lock_ObtainMutex(&vcp->mx);
9487 if (vcp->errorCount++ > 3) {
9488 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9489 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9490 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9492 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9493 lock_ReleaseMutex(&vcp->mx);
9494 lock_ObtainWrite(&smb_globalLock);
9495 dead_sessions[vcp->session] = TRUE;
9496 lock_ReleaseWrite(&smb_globalLock);
9498 lock_ReleaseMutex(&vcp->mx);
9500 smb_CleanupDeadVC(vcp);
9506 lock_ReleaseMutex(&vcp->mx);
9510 thrd_SetEvent(SessionEvents[idx_session]);
9516 /* Success, so now dispatch on all the data in the packet */
9518 smb_concurrentCalls++;
9519 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9520 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9523 * If at this point vcp is NULL (implies that packet was invalid)
9524 * then we are in big trouble. This means either :
9525 * a) we have the wrong NCB.
9526 * b) Netbios screwed up the call.
9527 * c) The VC was already marked dead before we were able to
9529 * Obviously this implies that
9530 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9531 * lanas[idx_session] != ncbp->ncb_lana_num )
9532 * Either way, we can't do anything with this packet.
9533 * Log, sleep and resume.
9536 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9540 ncbp->ncb_lana_num);
9542 /* Also log in the trace log. */
9543 osi_Log4(smb_logp, "Server: VCP does not exist!"
9544 "LSNs[idx_session]=[%d],"
9545 "lanas[idx_session]=[%d],"
9546 "ncbp->ncb_lsn=[%d],"
9547 "ncbp->ncb_lana_num=[%d]",
9551 ncbp->ncb_lana_num);
9553 /* thrd_Sleep(1000); Don't bother sleeping */
9554 thrd_SetEvent(SessionEvents[idx_session]);
9555 smb_concurrentCalls--;
9559 cm_SetRequestStartTime();
9560 if (smb_monitorReqs) {
9561 smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9564 vcp->errorCount = 0;
9565 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9566 smbp = (smb_t *)bufp->data;
9573 if (smbp->com == 0x1d) {
9574 /* Special handling for Write Raw */
9575 raw_write_cont_t rwc;
9577 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9578 if (rwc.code == 0) {
9579 EVENT_HANDLE rwevent;
9580 char eventName[MAX_PATH];
9582 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9583 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9584 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9585 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9587 ncbp->ncb_command = NCBRECV | ASYNCH;
9588 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9589 ncbp->ncb_lana_num = vcp->lana;
9590 ncbp->ncb_buffer = rwc.buf;
9591 ncbp->ncb_length = 65535;
9592 ncbp->ncb_event = rwevent;
9594 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9595 thrd_CloseHandle(rwevent);
9597 thrd_SetEvent(SessionEvents[idx_session]);
9599 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9601 else if (smbp->com == 0xa0) {
9603 * Serialize the handling for NT Transact
9606 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9607 thrd_SetEvent(SessionEvents[idx_session]);
9609 thrd_SetEvent(SessionEvents[idx_session]);
9610 /* TODO: what else needs to be serialized? */
9611 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9615 __except( smb_ServerExceptionFilter() ) {
9619 if (smb_monitorReqs) {
9620 smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9622 smb_concurrentCalls--;
9625 thrd_SetEvent(NCBavails[idx_NCB]);
9630 smb_FreePacket(outbufp);
9632 smb_FreeNCB(outncbp);
9636 * Exception filter for the server threads. If an exception occurs in the
9637 * dispatch routines, which is where exceptions are most common, then do a
9638 * force trace and give control to upstream exception handlers. Useful for
9641 DWORD smb_ServerExceptionFilter(void) {
9642 /* While this is not the best time to do a trace, if it succeeds, then
9643 * we have a trace (assuming tracing was enabled). Otherwise, this should
9644 * throw a second exception.
9646 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9647 afsd_ForceTrace(TRUE);
9648 buf_ForceTrace(TRUE);
9649 return EXCEPTION_CONTINUE_SEARCH;
9653 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9654 * If the number of server threads is M, and the number of live sessions is
9655 * N, then the number of NCB's in use at any time either waiting for, or
9656 * holding, received messages is M + N, so that is how many NCB's get created.
9658 void InitNCBslot(int idx)
9660 struct smb_packet *bufp;
9661 EVENT_HANDLE retHandle;
9663 char eventName[MAX_PATH];
9665 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9667 NCBs[idx] = smb_GetNCB();
9668 sprintf(eventName,"NCBavails[%d]", idx);
9669 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9670 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9671 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9672 sprintf(eventName,"NCBevents[%d]", idx);
9673 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9674 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9675 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9676 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9677 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9678 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9679 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9680 for (i=0; i<smb_NumServerThreads; i++)
9681 NCBreturns[i][idx] = retHandle;
9682 bufp = smb_GetPacket();
9683 bufp->spacep = cm_GetSpace();
9687 /* listen for new connections */
9688 void smb_Listener(void *parmp)
9694 afs_uint32 session, thread;
9695 smb_vc_t *vcp = NULL;
9697 char rname[NCBNAMSZ+1];
9698 char cname[MAX_COMPUTERNAME_LENGTH+1];
9699 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9700 INT_PTR lana = (INT_PTR) parmp;
9701 char eventName[MAX_PATH];
9702 int bridgeCount = 0;
9703 int nowildCount = 0;
9705 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9706 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9707 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9708 thrd_ResetEvent(ListenerShutdown[lana]);
9710 ncbp = smb_GetNCB();
9712 /* retrieve computer name */
9713 GetComputerName(cname, &cnamelen);
9716 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9717 memset(ncbp, 0, sizeof(NCB));
9720 ncbp->ncb_command = NCBLISTEN;
9721 ncbp->ncb_rto = 0; /* No receive timeout */
9722 ncbp->ncb_sto = 0; /* No send timeout */
9724 /* pad out with spaces instead of null termination */
9725 len = (long)strlen(smb_localNamep);
9726 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9727 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9729 strcpy(ncbp->ncb_callname, "*");
9730 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9732 ncbp->ncb_lana_num = (UCHAR)lana;
9734 code = Netbios(ncbp);
9736 if (code == NRC_NAMERR) {
9737 /* An smb shutdown or Vista resume must have taken place */
9739 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9740 ncbp->ncb_lana_num);
9741 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9743 if (lock_TryMutex(&smb_StartedLock)) {
9744 lana_list.lana[i] = LANA_INVALID;
9745 lock_ReleaseMutex(&smb_StartedLock);
9748 } else if (code == NRC_BRIDGE || code != 0) {
9749 int lanaRemaining = 0;
9751 if (code == NRC_BRIDGE) {
9752 if (++bridgeCount <= 5) {
9753 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9756 } else if (code == NRC_NOWILD) {
9757 if (++nowildCount <= 5) {
9758 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9760 if (bridgeCount > 0) {
9761 memset(ncbp, 0, sizeof(*ncbp));
9762 ncbp->ncb_command = NCBADDNAME;
9763 ncbp->ncb_lana_num = (UCHAR)lana;
9764 /* pad out with spaces instead of null termination */
9765 len = (long)strlen(smb_localNamep);
9766 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9767 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9768 code = Netbios(ncbp);
9774 while (!lock_TryMutex(&smb_StartedLock)) {
9775 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9781 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9782 ncbp->ncb_lana_num, ncb_error_string(code));
9783 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9784 ncbp->ncb_lana_num, ncb_error_string(code));
9786 for (i = 0; i < lana_list.length; i++) {
9787 if (lana_list.lana[i] == lana) {
9788 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9789 lana_list.lana[i] = LANA_INVALID;
9791 if (lana_list.lana[i] != LANA_INVALID)
9795 if (lanaRemaining == 0) {
9796 cm_VolStatus_Network_Stopped(cm_NetbiosName
9801 smb_ListenerState = SMB_LISTENER_STOPPED;
9802 smb_LANadapter = LANA_INVALID;
9803 lana_list.length = 0;
9805 lock_ReleaseMutex(&smb_StartedLock);
9809 else if (code != 0) {
9810 char tbuffer[AFSPATHMAX];
9812 /* terminate silently if shutdown flag is set */
9813 while (!lock_TryMutex(&smb_StartedLock)) {
9814 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9820 "NCBLISTEN lana=%d failed with code %d [%s]",
9821 ncbp->ncb_lana_num, code, ncb_error_string(code));
9823 "Client exiting due to network failure. Please restart client.\n");
9826 "Client exiting due to network failure. Please restart client.\n"
9827 "NCBLISTEN lana=%d failed with code %d [%s]",
9828 ncbp->ncb_lana_num, code, ncb_error_string(code));
9830 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9831 MB_OK|MB_SERVICE_NOTIFICATION);
9832 osi_panic(tbuffer, __FILE__, __LINE__);
9834 lock_ReleaseMutex(&smb_StartedLock);
9839 /* a successful packet received. clear bridge error count */
9843 /* check for remote conns */
9844 /* first get remote name and insert null terminator */
9845 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9846 for (i=NCBNAMSZ; i>0; i--) {
9847 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9853 /* compare with local name */
9855 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9856 flags |= SMB_VCFLAG_REMOTECONN;
9859 lock_ObtainMutex(&smb_ListenerLock);
9861 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9862 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9864 /* now ncbp->ncb_lsn is the connection ID */
9865 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9866 if (vcp->session == 0) {
9867 /* New generation */
9868 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9871 /* Log session startup */
9873 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9874 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9875 #endif /* NOTSERVICE */
9876 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9877 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9879 if (reportSessionStartups) {
9880 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9883 lock_ObtainMutex(&vcp->mx);
9884 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9885 vcp->flags |= flags;
9886 lock_ReleaseMutex(&vcp->mx);
9888 /* Allocate slot in session arrays */
9889 /* Re-use dead session if possible, otherwise add one more */
9890 /* But don't look at session[0], it is reserved */
9891 lock_ObtainWrite(&smb_globalLock);
9892 for (session = 1; session < numSessions; session++) {
9893 if (dead_sessions[session]) {
9894 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9895 dead_sessions[session] = FALSE;
9899 lock_ReleaseWrite(&smb_globalLock);
9901 /* We are re-using an existing VC because the lsn and lana
9903 session = vcp->session;
9905 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9907 /* Log session startup */
9909 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9910 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9911 #endif /* NOTSERVICE */
9912 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9913 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9915 if (reportSessionStartups) {
9916 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9920 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9921 unsigned long code = CM_ERROR_ALLBUSY;
9922 smb_packet_t * outp = smb_GetPacket();
9923 unsigned char *outWctp;
9926 smb_FormatResponsePacket(vcp, NULL, outp);
9929 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9930 unsigned long NTStatus;
9931 smb_MapNTError(code, &NTStatus, FALSE);
9932 outWctp = outp->wctp;
9933 smbp = (smb_t *) &outp->data;
9937 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9938 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9939 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9940 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9941 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9943 unsigned short errCode;
9944 unsigned char errClass;
9945 smb_MapCoreError(code, vcp, &errCode, &errClass);
9946 outWctp = outp->wctp;
9947 smbp = (smb_t *) &outp->data;
9951 smbp->errLow = (unsigned char) (errCode & 0xff);
9952 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9953 smbp->rcls = errClass;
9956 smb_SendPacket(vcp, outp);
9957 smb_FreePacket(outp);
9959 lock_ObtainMutex(&vcp->mx);
9960 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9961 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9963 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9964 lock_ReleaseMutex(&vcp->mx);
9965 lock_ObtainWrite(&smb_globalLock);
9966 dead_sessions[vcp->session] = TRUE;
9967 lock_ReleaseWrite(&smb_globalLock);
9968 smb_CleanupDeadVC(vcp);
9970 lock_ReleaseMutex(&vcp->mx);
9973 /* assert that we do not exceed the maximum number of sessions or NCBs.
9974 * we should probably want to wait for a session to be freed in case
9977 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9978 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9980 lock_ObtainMutex(&vcp->mx);
9981 vcp->session = session;
9982 lock_ReleaseMutex(&vcp->mx);
9983 lock_ObtainWrite(&smb_globalLock);
9984 LSNs[session] = ncbp->ncb_lsn;
9985 lanas[session] = ncbp->ncb_lana_num;
9986 lock_ReleaseWrite(&smb_globalLock);
9988 if (session == numSessions) {
9989 /* Add new NCB for new session */
9990 char eventName[MAX_PATH];
9992 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9994 InitNCBslot(numNCBs);
9995 lock_ObtainWrite(&smb_globalLock);
9997 lock_ReleaseWrite(&smb_globalLock);
9998 thrd_SetEvent(NCBavails[0]);
9999 thrd_SetEvent(NCBevents[0]);
10000 for (thread = 0; thread < smb_NumServerThreads; thread++)
10001 thrd_SetEvent(NCBreturns[thread][0]);
10002 /* Also add new session event */
10003 sprintf(eventName, "SessionEvents[%d]", session);
10004 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
10005 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10006 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
10007 lock_ObtainWrite(&smb_globalLock);
10009 lock_ReleaseWrite(&smb_globalLock);
10010 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
10011 thrd_SetEvent(SessionEvents[0]);
10013 thrd_SetEvent(SessionEvents[session]);
10016 smb_ReleaseVC(vcp);
10019 lock_ReleaseMutex(&smb_ListenerLock);
10020 } /* dispatch while loop */
10024 thrd_SetEvent(ListenerShutdown[lana]);
10029 smb_configureBackConnectionHostNames(int bEnable)
10031 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
10032 * there is a restriction on the use of SMB authentication on loopback connections.
10033 * There are two work arounds available:
10035 * (1) We can disable the check for matching host names. This does not
10036 * require a reboot:
10037 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
10038 * "DisableLoopbackCheck"=dword:00000001
10040 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
10041 * does require a reboot:
10042 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
10043 * "BackConnectionHostNames"=multi-sz
10045 * The algorithm will be:
10046 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
10047 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
10048 * (2b1) and check to see if DisableLoopbackCheck is set.
10049 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
10050 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
10051 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
10052 * check for the UnsetDisableLoopbackCheck value.
10053 * If set, set the DisableLoopbackCheck flag to 0x0
10054 * and delete the UnsetDisableLoopbackCheck value
10056 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
10057 * force Windows to use the loopback authentication mechanism for the specified
10060 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
10061 * service session that set it.
10067 DWORD dwSize, dwAllocSize;
10069 PBYTE pHostNames = NULL, pName = NULL;
10070 PBYTE pOrigNames = NULL, pOrig = NULL;
10071 BOOL bNameFound = FALSE;
10072 DWORD dwLoopbackCheckDisabled;
10073 DWORD dwszBackConnectionHostNames;
10074 size_t nbsize = strlen(cm_NetbiosName) + 2;
10076 static BOOL bLoopbackCheckDisabled = FALSE;
10078 /* DisableLoopbackCheck */
10079 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10080 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10082 KEY_READ|KEY_WRITE,
10083 &hkLsa) == ERROR_SUCCESS )
10085 dwSize = sizeof(DWORD);
10086 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwLoopbackCheckDisabled, &dwSize) != ERROR_SUCCESS)
10088 dwLoopbackCheckDisabled = 0;
10091 hkLsa = INVALID_HANDLE_VALUE;
10094 /* BackConnectionHostNames */
10095 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10096 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
10098 KEY_READ|KEY_WRITE,
10099 &hkMSV10) == ERROR_SUCCESS )
10101 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
10102 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10103 (dwType == REG_MULTI_SZ))
10105 dwAllocSize += 1 /* in case the source string is not nul terminated */
10106 + (DWORD)strlen(cm_NetbiosName) + 2;
10107 pHostNames = malloc(dwAllocSize);
10108 dwszBackConnectionHostNames = dwAllocSize;
10109 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
10110 pHostNames, &dwszBackConnectionHostNames) == ERROR_SUCCESS)
10112 for (pName = pHostNames;
10113 (pName - pHostNames < (int) dwszBackConnectionHostNames) && *pName ;
10114 pName += strlen(pName) + 1)
10116 if ( !stricmp(pName, cm_NetbiosName) ) {
10125 if ( !bNameFound ) {
10126 size_t size = strlen(cm_NetbiosName) + 2;
10127 if ( !pHostNames ) {
10128 pHostNames = malloc(size);
10129 pName = pHostNames;
10131 StringCbCopyA(pName, size, cm_NetbiosName);
10133 *pName = '\0'; /* add a second nul terminator */
10135 dwType = REG_MULTI_SZ;
10136 dwSize = (DWORD)(pName - pHostNames + 1);
10137 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10139 if ( hkLsa != INVALID_HANDLE_VALUE && !dwLoopbackCheckDisabled)
10141 dwType = REG_DWORD;
10142 dwSize = sizeof(DWORD);
10143 dwLoopbackCheckDisabled = 1;
10144 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwLoopbackCheckDisabled, dwSize);
10146 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10147 AFSREG_CLT_OPENAFS_SUBKEY,
10150 REG_OPTION_NON_VOLATILE,
10151 KEY_READ|KEY_WRITE,
10154 NULL) == ERROR_SUCCESS) {
10156 dwType = REG_DWORD;
10157 dwSize = sizeof(DWORD);
10159 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10160 bLoopbackCheckDisabled = TRUE;
10161 RegCloseKey(hkClient);
10164 } else if (!bLoopbackCheckDisabled && hkLsa != INVALID_HANDLE_VALUE) {
10165 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10166 AFSREG_CLT_OPENAFS_SUBKEY,
10169 REG_OPTION_NON_VOLATILE,
10170 KEY_READ|KEY_WRITE,
10173 NULL) == ERROR_SUCCESS) {
10175 dwSize = sizeof(DWORD);
10176 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10178 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10181 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10182 RegCloseKey(hkClient);
10186 * Disable SMB. Start by removing the DisableLoopbackCheck value if present.
10188 if (hkLsa != INVALID_HANDLE_VALUE) {
10189 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10190 AFSREG_CLT_OPENAFS_SUBKEY,
10193 REG_OPTION_NON_VOLATILE,
10194 KEY_READ|KEY_WRITE,
10197 NULL) == ERROR_SUCCESS) {
10199 dwSize = sizeof(DWORD);
10200 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10202 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10205 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10206 RegCloseKey(hkClient);
10209 /* Then remove our NetbiosName from the BackConnectionHostNames list */
10210 if ( bNameFound ) {
10212 * we found our name so if the size of the value is smaller
10213 * or equal to the length of our name alone, we are done.
10215 if ( dwszBackConnectionHostNames <= nbsize ) {
10216 RegDeleteValue( hkMSV10, "BackConnectionHostNames");
10218 pOrigNames = pHostNames;
10219 pHostNames = malloc(dwAllocSize);
10221 pOrig = pOrigNames;
10222 pName = pHostNames;
10223 while (pOrig - pOrigNames < dwszBackConnectionHostNames) {
10224 len = strlen(pOrig);
10225 if ( stricmp(pOrig, cm_NetbiosName)) {
10227 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10232 *pName = '\0'; /* add a second nul terminator */
10235 dwType = REG_MULTI_SZ;
10236 dwSize = (DWORD)(pName - pHostNames + 1);
10237 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10252 RegCloseKey(hkMSV10);
10255 if ( hkLsa != INVALID_HANDLE_VALUE ) {
10256 RegCloseKey(hkLsa);
10262 smb_configureExtendedSMBSessionTimeouts(int bEnable)
10265 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10266 * new functionality:
10268 * [HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters]
10269 * "ReconnectableServers" REG_MULTI_SZ
10270 * "ExtendedSessTimeout" REG_DWORD (seconds)
10271 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
10273 * These values can be used to prevent the smb redirector from timing out
10274 * smb connection to the afs smb server prematurely.
10278 DWORD dwSize, dwAllocSize;
10280 PBYTE pHostNames = NULL, pOrigNames = NULL, pName = NULL, pOrig = NULL;
10281 BOOL bNameFound = FALSE;
10282 DWORD dwszReconnectableServers;
10283 DWORD dwszServersWithExtendedSessTimeout;
10284 size_t nbsize = strlen(cm_NetbiosName) + 2;
10287 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10288 "SYSTEM\\CurrentControlSet\\Services\\LanmanWorkstation\\Parameters",
10290 KEY_READ|KEY_WRITE,
10291 &hkLanman) == ERROR_SUCCESS )
10293 if ((RegQueryValueEx( hkLanman, "ReconnectableServers", 0,
10294 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10295 (dwType == REG_MULTI_SZ))
10297 dwAllocSize += 1 /* in case the source string is not nul terminated */
10298 + (DWORD)strlen(cm_NetbiosName) + 2;
10299 pHostNames = malloc(dwAllocSize);
10300 dwszReconnectableServers = dwAllocSize;
10301 if (RegQueryValueEx( hkLanman, "ReconnectableServers", 0, &dwType,
10302 pHostNames, &dwszReconnectableServers) == ERROR_SUCCESS)
10304 for (pName = pHostNames;
10305 (pName - pHostNames < (int) dwszReconnectableServers) && *pName ;
10306 pName += strlen(pName) + 1)
10308 if ( !stricmp(pName, cm_NetbiosName) ) {
10317 * If our name was not found and we are enabling SMB,
10318 * add our name to the current value.
10320 if ( bEnable && !bNameFound ) {
10321 if ( !pHostNames ) {
10322 pHostNames = malloc(nbsize);
10323 pName = pHostNames;
10325 StringCbCopyA(pName, nbsize, cm_NetbiosName);
10326 pName += nbsize - 1;
10327 *pName = '\0'; /* add a second nul terminator */
10329 dwType = REG_MULTI_SZ;
10330 dwSize = (DWORD)(pName - pHostNames + 1);
10331 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10335 * If our name was found and we are disabling SMB,
10336 * remove our name from the list and update the value.
10337 * If our name is the only entry, remove the value.
10339 if ( !bEnable && bNameFound ) {
10341 * we found our name so if the size of the value is smaller
10342 * or equal to the length of our name alone, we are done.
10344 if ( dwszReconnectableServers <= nbsize ) {
10345 RegDeleteValue( hkLanman, "ReconnectableServers");
10347 pOrigNames = pHostNames;
10348 pHostNames = malloc(dwAllocSize);
10350 pOrig = pOrigNames;
10351 pName = pHostNames;
10352 while (pOrig - pOrigNames <dwszReconnectableServers ) {
10353 len = strlen(pOrig);
10354 if ( stricmp(pOrig, cm_NetbiosName)) {
10356 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10361 *pName = '\0'; /* add a second nul terminator */
10364 dwType = REG_MULTI_SZ;
10365 dwSize = (DWORD)(pName - pHostNames + 1);
10366 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10380 if ((RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0,
10381 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10382 (dwType == REG_MULTI_SZ))
10384 dwAllocSize += 1 /* in case the source string is not nul terminated */
10385 + (DWORD)strlen(cm_NetbiosName) + 2;
10386 pHostNames = malloc(dwAllocSize);
10387 dwszServersWithExtendedSessTimeout = dwAllocSize;
10388 if (RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, &dwType,
10389 pHostNames, &dwszServersWithExtendedSessTimeout) == ERROR_SUCCESS)
10391 for (pName = pHostNames;
10392 (pName - pHostNames < (int) dwszServersWithExtendedSessTimeout) && *pName ;
10393 pName += strlen(pName) + 1)
10395 if ( !stricmp(pName, cm_NetbiosName) ) {
10404 * If our name was not found and we are enabling SMB,
10405 * add our name to the current value.
10407 if ( bEnable && !bNameFound ) {
10408 size_t size = strlen(cm_NetbiosName) + 2;
10409 if ( !pHostNames ) {
10410 pHostNames = malloc(size);
10411 pName = pHostNames;
10413 StringCbCopyA(pName, size, cm_NetbiosName);
10415 *pName = '\0'; /* add a second nul terminator */
10417 dwType = REG_MULTI_SZ;
10418 dwSize = (DWORD)(pName - pHostNames + 1);
10419 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10423 * If our name was found and we are disabling SMB,
10424 * remove our name from the list and update the value.
10425 * If our name is the only entry, remove the value.
10427 if ( !bEnable && bNameFound ) {
10429 * we found our name so if the size of the value is smaller
10430 * or equal to the length of our name alone, we are done.
10432 if ( dwszServersWithExtendedSessTimeout <= nbsize ) {
10433 RegDeleteValue( hkLanman, "ServersWithExtendedSessTimeout");
10435 pOrigNames = pHostNames;
10436 pHostNames = malloc(dwAllocSize);
10438 pOrig = pOrigNames;
10439 pName = pHostNames;
10440 while (pOrig - pOrigNames < dwszServersWithExtendedSessTimeout) {
10441 len = strlen(pOrig);
10442 if ( stricmp(pOrig, cm_NetbiosName)) {
10444 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10449 *pName = '\0'; /* add a second nul terminator */
10452 dwType = REG_MULTI_SZ;
10453 dwSize = (DWORD)(pName - pHostNames + 1);
10454 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10469 if ((RegQueryValueEx( hkLanman, "ExtendedSessTimeout", 0,
10470 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10471 (dwType != REG_DWORD))
10473 dwType = REG_DWORD;
10474 dwSize = sizeof(dwValue);
10475 dwValue = 300; /* 5 minutes */
10476 RegSetValueEx( hkLanman, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10479 RegCloseKey(hkLanman);
10484 smb_LanAdapterChangeThread(void *param)
10487 * Give the IPAddrDaemon thread a chance
10488 * to block before we trigger.
10491 smb_LanAdapterChange(0);
10494 void smb_SetLanAdapterChangeDetected(void)
10499 lock_ObtainMutex(&smb_StartedLock);
10501 if (!powerStateSuspended) {
10502 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10503 NULL, 0, &lpid, "smb_LanAdapterChange");
10504 if (phandle == NULL) {
10508 gle = GetLastError();
10509 StringCchPrintf( msg, sizeof(msg)/sizeof(msg[0]),
10510 "smb_LanAdapterChangeThread thread creation failure - gle 0x%x",
10512 osi_assertx(TRUE, msg);
10514 thrd_CloseHandle(phandle);
10517 smb_LanAdapterChangeDetected = 1;
10518 lock_ReleaseMutex(&smb_StartedLock);
10521 void smb_LanAdapterChange(int locked) {
10522 lana_number_t lanaNum;
10524 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
10526 LANA_ENUM temp_list;
10531 afsi_log("smb_LanAdapterChange");
10534 lock_ObtainMutex(&smb_StartedLock);
10536 smb_LanAdapterChangeDetected = 0;
10538 if (!powerStateSuspended &&
10539 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10540 LANA_NETBIOS_NAME_FULL | LANA_NETBIOS_NO_RESET)) &&
10541 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10542 if ( isGateway != bGateway ) {
10543 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10544 smb_LANadapter, lanaNum, isGateway, bGateway);
10546 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10547 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10548 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10551 NCB *ncbp = smb_GetNCB();
10552 ncbp->ncb_command = NCBENUM;
10553 ncbp->ncb_buffer = (PUCHAR)&temp_list;
10554 ncbp->ncb_length = sizeof(temp_list);
10555 code = Netbios(ncbp);
10557 if (temp_list.length != lana_list.length) {
10558 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10559 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10562 for (i=0; i<lana_list.length; i++) {
10563 if ( temp_list.lana[i] != lana_list.lana[i] ) {
10564 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10565 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10577 smb_StopListeners(1);
10578 smb_RestartListeners(1);
10581 lock_ReleaseMutex(&smb_StartedLock);
10584 /* initialize Netbios */
10585 int smb_NetbiosInit(int locked)
10588 int i, lana, code, l;
10590 int delname_tried=0;
10592 int lana_found = 0;
10593 lana_number_t lanaNum;
10599 lock_ObtainMutex(&smb_StartedLock);
10601 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10602 smb_ListenerState != SMB_LISTENER_STOPPED) {
10605 lock_ReleaseMutex(&smb_StartedLock);
10608 /* setup the NCB system */
10609 ncbp = smb_GetNCB();
10612 * Call lanahelper to get Netbios name, lan adapter number and gateway flag
10613 * This will reset all of the network adapter's netbios state.
10615 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10616 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10618 if (smb_LANadapter != LANA_INVALID)
10619 afsi_log("LAN adapter number %d", smb_LANadapter);
10621 afsi_log("LAN adapter number not determined");
10624 afsi_log("Set for gateway service");
10626 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10628 /* something went horribly wrong. We can't proceed without a netbios name */
10630 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10631 osi_panic(buf, __FILE__, __LINE__);
10634 /* remember the name */
10635 len = (int)strlen(cm_NetbiosName);
10636 if (smb_localNamep)
10637 free(smb_localNamep);
10638 smb_localNamep = malloc(len+1);
10639 strcpy(smb_localNamep, cm_NetbiosName);
10640 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10642 /* Also copy the value to the client character encoded string */
10643 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10645 if (smb_LANadapter == LANA_INVALID) {
10646 ncbp->ncb_command = NCBENUM;
10647 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10648 ncbp->ncb_length = sizeof(lana_list);
10649 code = Netbios(ncbp);
10651 afsi_log("Netbios NCBENUM error code %d", code);
10652 osi_panic(s, __FILE__, __LINE__);
10656 lana_list.length = 1;
10657 lana_list.lana[0] = smb_LANadapter;
10660 for (i = 0; i < lana_list.length; i++) {
10661 /* reset the adaptor: in Win32, this is required for every process, and
10662 * acts as an init call, not as a real hardware reset.
10664 ncbp->ncb_command = NCBRESET;
10665 ncbp->ncb_callname[0] = 100;
10666 ncbp->ncb_callname[2] = 100;
10667 ncbp->ncb_lana_num = lana_list.lana[i];
10668 code = Netbios(ncbp);
10670 code = ncbp->ncb_retcode;
10672 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10673 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10675 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10679 /* and declare our name so we can receive connections */
10680 memset(ncbp, 0, sizeof(*ncbp));
10681 len=lstrlen(smb_localNamep);
10682 memset(smb_sharename,' ',NCBNAMSZ);
10683 memcpy(smb_sharename,smb_localNamep,len);
10684 afsi_log("lana_list.length %d", lana_list.length);
10686 /* Keep the name so we can unregister it later */
10687 for (l = 0; l < lana_list.length; l++) {
10688 lana = lana_list.lana[l];
10690 ncbp->ncb_command = NCBADDNAME;
10691 ncbp->ncb_lana_num = lana;
10692 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10693 code = Netbios(ncbp);
10695 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10696 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10698 char name[NCBNAMSZ+1];
10700 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10701 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10705 code = ncbp->ncb_retcode;
10708 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10711 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10712 if (code == NRC_BRIDGE) { /* invalid LANA num */
10713 lana_list.lana[l] = LANA_INVALID;
10716 else if (code == NRC_DUPNAME) {
10717 afsi_log("Name already exists; try to delete it");
10718 memset(ncbp, 0, sizeof(*ncbp));
10719 ncbp->ncb_command = NCBDELNAME;
10720 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10721 ncbp->ncb_lana_num = lana;
10722 code = Netbios(ncbp);
10724 code = ncbp->ncb_retcode;
10726 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10728 if (code != 0 || delname_tried) {
10729 lana_list.lana[l] = LANA_INVALID;
10731 else if (code == 0) {
10732 if (!delname_tried) {
10740 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10741 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10745 smb_LANadapter = lana;
10746 lana_found = 1; /* at least one worked */
10750 osi_assertx(lana_list.length >= 0, "empty lana list");
10752 afsi_log("No valid LANA numbers found!");
10753 lana_list.length = 0;
10754 smb_LANadapter = LANA_INVALID;
10755 smb_ListenerState = SMB_LISTENER_STOPPED;
10756 cm_VolStatus_Network_Stopped(cm_NetbiosName
10763 /* we're done with the NCB now */
10766 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10767 if (lana_list.length > 0)
10768 osi_assert(smb_LANadapter != LANA_INVALID);
10771 lock_ReleaseMutex(&smb_StartedLock);
10773 return (lana_list.length > 0 ? 1 : 0);
10776 void smb_StartListeners(int locked)
10786 lock_ObtainMutex(&smb_StartedLock);
10788 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10790 lock_ReleaseMutex(&smb_StartedLock);
10794 afsi_log("smb_StartListeners");
10795 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10796 smb_configureBackConnectionHostNames(TRUE);
10798 /* Configure Extended SMB Session Timeouts */
10799 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10800 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10801 smb_configureExtendedSMBSessionTimeouts(TRUE);
10804 smb_ListenerState = SMB_LISTENER_STARTED;
10805 cm_VolStatus_Network_Started(cm_NetbiosName
10811 for (i = 0; i < lana_list.length; i++) {
10812 if (lana_list.lana[i] == LANA_INVALID)
10814 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10815 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10816 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10817 thrd_CloseHandle(phandle);
10820 lock_ReleaseMutex(&smb_StartedLock);
10823 void smb_RestartListeners(int locked)
10829 lock_ObtainMutex(&smb_StartedLock);
10831 if (powerStateSuspended)
10832 afsi_log("smb_RestartListeners called while suspended");
10834 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10835 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10836 if (smb_NetbiosInit(1))
10837 smb_StartListeners(1);
10838 } else if (smb_LanAdapterChangeDetected) {
10839 smb_LanAdapterChange(1);
10843 lock_ReleaseMutex(&smb_StartedLock);
10846 void smb_StopListener(NCB *ncbp, int lana, int wait)
10850 memset(ncbp, 0, sizeof(*ncbp));
10851 ncbp->ncb_command = NCBDELNAME;
10852 ncbp->ncb_lana_num = lana;
10853 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10854 code = Netbios(ncbp);
10856 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10857 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10859 /* and then reset the LANA; this will cause the listener threads to exit */
10860 ncbp->ncb_command = NCBRESET;
10861 ncbp->ncb_callname[0] = 100;
10862 ncbp->ncb_callname[2] = 100;
10863 ncbp->ncb_lana_num = lana;
10864 code = Netbios(ncbp);
10866 code = ncbp->ncb_retcode;
10868 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10870 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10874 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10877 void smb_StopListeners(int locked)
10886 lock_ObtainMutex(&smb_StartedLock);
10888 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10890 lock_ReleaseMutex(&smb_StartedLock);
10894 afsi_log("smb_StopListeners");
10895 smb_ListenerState = SMB_LISTENER_STOPPED;
10896 cm_VolStatus_Network_Stopped(cm_NetbiosName
10902 ncbp = smb_GetNCB();
10904 /* Unregister the SMB name */
10905 for (l = 0; l < lana_list.length; l++) {
10906 lana = lana_list.lana[l];
10908 if (lana != LANA_INVALID) {
10909 smb_StopListener(ncbp, lana, TRUE);
10911 /* mark the adapter invalid */
10912 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10916 /* force a re-evaluation of the network adapters */
10917 lana_list.length = 0;
10918 smb_LANadapter = LANA_INVALID;
10921 lock_ReleaseMutex(&smb_StartedLock);
10924 void smb_Init(osi_log_t *logp, int useV3,
10934 EVENT_HANDLE retHandle;
10935 char eventName[MAX_PATH];
10936 int startListeners = 0;
10941 smb_MBfunc = aMBfunc;
10945 /* Initialize smb_localZero */
10946 myTime.tm_isdst = -1; /* compute whether on DST or not */
10947 myTime.tm_year = 70;
10949 myTime.tm_mday = 1;
10950 myTime.tm_hour = 0;
10953 smb_localZero = mktime(&myTime);
10955 #ifdef AFS_FREELANCE_CLIENT
10956 /* Make sure the root.afs volume has the correct time */
10957 cm_noteLocalMountPointChange(FALSE);
10960 /* initialize the remote debugging log */
10963 /* and the global lock */
10964 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10965 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10967 /* Raw I/O data structures */
10968 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10970 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10971 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10973 /* 4 Raw I/O buffers */
10974 smb_RawBufs = calloc(65536,1);
10975 *((char **)smb_RawBufs) = NULL;
10976 for (i=0; i<3; i++) {
10977 char *rawBuf = calloc(65536,1);
10978 *((char **)rawBuf) = smb_RawBufs;
10979 smb_RawBufs = rawBuf;
10982 /* global free lists */
10983 smb_ncbFreeListp = NULL;
10984 smb_packetFreeListp = NULL;
10986 lock_ObtainMutex(&smb_StartedLock);
10987 startListeners = smb_NetbiosInit(1);
10989 /* Initialize listener and server structures */
10991 memset(dead_sessions, 0, sizeof(dead_sessions));
10992 sprintf(eventName, "SessionEvents[0]");
10993 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10994 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10995 afsi_log("Event Object Already Exists: %s", eventName);
10997 smb_NumServerThreads = nThreads;
10998 sprintf(eventName, "NCBavails[0]");
10999 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11000 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11001 afsi_log("Event Object Already Exists: %s", eventName);
11002 sprintf(eventName, "NCBevents[0]");
11003 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11004 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11005 afsi_log("Event Object Already Exists: %s", eventName);
11006 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
11007 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
11008 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11009 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11010 afsi_log("Event Object Already Exists: %s", eventName);
11011 for (i = 0; i < smb_NumServerThreads; i++) {
11012 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
11013 NCBreturns[i][0] = retHandle;
11016 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
11017 for (i = 0; i < smb_NumServerThreads; i++) {
11018 sprintf(eventName, "smb_ServerShutdown[%d]", i);
11019 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11020 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11021 afsi_log("Event Object Already Exists: %s", eventName);
11022 InitNCBslot((int)(i+1));
11024 numNCBs = smb_NumServerThreads + 1;
11026 /* Initialize dispatch table */
11027 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
11028 /* Prepare the table for unknown operations */
11029 for(i=0; i<= SMB_NOPCODES; i++) {
11030 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
11032 /* Fill in the ones we do know */
11033 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
11034 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
11035 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
11036 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
11037 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
11038 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
11039 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
11040 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
11041 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
11042 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
11043 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
11044 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
11045 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
11046 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
11047 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
11048 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
11049 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
11050 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
11051 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
11052 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
11053 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
11054 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11055 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
11056 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
11057 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
11058 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
11059 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
11060 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
11061 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11062 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
11063 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11064 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
11065 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
11066 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
11067 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11068 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
11069 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
11070 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
11071 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
11072 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
11073 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
11074 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
11075 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11076 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
11077 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11078 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
11079 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
11080 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
11081 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
11082 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
11083 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
11084 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
11085 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
11086 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
11087 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
11088 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
11089 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
11090 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
11091 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
11092 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
11093 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
11094 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
11095 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
11096 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
11097 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
11098 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11099 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
11100 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
11101 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
11102 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
11103 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
11104 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
11105 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
11106 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
11108 /* setup tran 2 dispatch table */
11109 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
11110 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
11111 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
11112 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
11113 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
11114 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
11115 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
11116 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
11117 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
11118 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
11119 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
11120 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
11121 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
11122 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
11123 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
11124 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
11125 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
11126 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
11128 /* setup the rap dispatch table */
11129 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
11130 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
11131 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
11132 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
11133 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
11137 /* if we are doing SMB authentication we have register outselves as a logon process */
11138 if (smb_authType != SMB_AUTH_NONE) {
11139 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
11140 LSA_STRING afsProcessName;
11141 LSA_OPERATIONAL_MODE dummy; /*junk*/
11143 afsProcessName.Buffer = "OpenAFSClientDaemon";
11144 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
11145 afsProcessName.MaximumLength = afsProcessName.Length + 1;
11147 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
11149 if (nts == STATUS_SUCCESS) {
11150 LSA_STRING packageName;
11151 /* we are registered. Find out the security package id */
11152 packageName.Buffer = MSV1_0_PACKAGE_NAME;
11153 packageName.Length = (USHORT)strlen(packageName.Buffer);
11154 packageName.MaximumLength = packageName.Length + 1;
11155 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
11156 if (nts == STATUS_SUCCESS) {
11158 * This code forces Windows to authenticate against the Logon Cache
11159 * first instead of attempting to authenticate against the Domain
11160 * Controller. When the Windows logon cache is enabled this improves
11161 * performance by removing the network access and works around a bug
11162 * seen at sites which are using a MIT Kerberos principal to login
11163 * to machines joined to a non-root domain in a multi-domain forest.
11164 * MsV1_0SetProcessOption was added in Windows XP.
11166 PVOID pResponse = NULL;
11167 ULONG cbResponse = 0;
11168 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
11170 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
11171 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
11172 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
11173 OptionsRequest.DisableOptions = FALSE;
11175 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
11178 sizeof(OptionsRequest),
11184 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
11185 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
11188 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
11190 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
11191 afsi_log("MsV1_0SetProcessOption success");
11193 /* END - code from Larry */
11195 smb_lsaLogonOrigin.Buffer = "OpenAFS";
11196 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
11197 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
11199 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
11201 /* something went wrong. We report the error and revert back to no authentication
11202 because we can't perform any auth requests without a successful lsa handle
11203 or sec package id. */
11204 afsi_log("Reverting to NO SMB AUTH");
11205 smb_authType = SMB_AUTH_NONE;
11208 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
11210 /* something went wrong. We report the error and revert back to no authentication
11211 because we can't perform any auth requests without a successful lsa handle
11212 or sec package id. */
11213 afsi_log("Reverting to NO SMB AUTH");
11214 smb_authType = SMB_AUTH_NONE;
11218 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
11219 * time prevents the failure of authentication when logged into Windows with an
11220 * external Kerberos principal mapped to a local account.
11222 else if ( smb_authType == SMB_AUTH_EXTENDED) {
11223 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
11224 * then the only option is NTLMSSP anyway; so just fallback.
11229 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
11230 if (secBlobLength == 0) {
11231 smb_authType = SMB_AUTH_NTLM;
11232 afsi_log("Reverting to SMB AUTH NTLM");
11241 /* Now get ourselves a domain name. */
11242 /* For now we are using the local computer name as the domain name.
11243 * It is actually the domain for local logins, and we are acting as
11244 * a local SMB server.
11246 bufsize = lengthof(smb_ServerDomainName) - 1;
11247 GetComputerNameW(smb_ServerDomainName, &bufsize);
11248 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
11249 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
11252 /* Start listeners, waiters, servers, and daemons */
11253 if (startListeners)
11254 smb_StartListeners(1);
11256 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
11257 NULL, 0, &lpid, "smb_ClientWaiter");
11258 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
11259 thrd_CloseHandle(phandle);
11261 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
11262 NULL, 0, &lpid, "smb_ServerWaiter");
11263 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
11264 thrd_CloseHandle(phandle);
11266 for (i=0; i<smb_NumServerThreads; i++) {
11267 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
11268 (void *) i, 0, &lpid, "smb_Server");
11269 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
11270 thrd_CloseHandle(phandle);
11273 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
11274 NULL, 0, &lpid, "smb_Daemon");
11275 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
11276 thrd_CloseHandle(phandle);
11278 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
11279 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
11280 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
11281 thrd_CloseHandle(phandle);
11283 if (smb_monitorReqs) {
11284 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
11285 NULL, 0, &lpid, "smb_ServerMonitor");
11286 osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
11287 thrd_CloseHandle(phandle);
11290 lock_ReleaseMutex(&smb_StartedLock);
11294 void smb_Shutdown(void)
11304 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11306 /* setup the NCB system */
11307 ncbp = smb_GetNCB();
11309 /* Block new sessions by setting shutdown flag */
11310 smbShutdownFlag = 1;
11312 /* Hang up all sessions */
11313 memset(ncbp, 0, sizeof(NCB));
11314 for (i = 1; i < numSessions; i++)
11316 if (dead_sessions[i])
11319 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11320 ncbp->ncb_command = NCBHANGUP;
11321 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
11322 ncbp->ncb_lsn = (UCHAR)LSNs[i];
11323 code = Netbios(ncbp);
11324 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11325 if (code == 0) code = ncbp->ncb_retcode;
11327 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11328 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11332 /* Trigger the shutdown of all SMB threads */
11333 for (i = 0; i < smb_NumServerThreads; i++)
11334 thrd_SetEvent(NCBreturns[i][0]);
11336 thrd_SetEvent(NCBevents[0]);
11337 thrd_SetEvent(SessionEvents[0]);
11338 thrd_SetEvent(NCBavails[0]);
11340 for (i = 0;i < smb_NumServerThreads; i++) {
11341 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11342 if (code == WAIT_OBJECT_0) {
11345 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11346 thrd_SetEvent(NCBreturns[i--][0]);
11350 /* Delete Netbios name */
11351 memset(ncbp, 0, sizeof(NCB));
11352 for (i = 0; i < lana_list.length; i++) {
11353 if (lana_list.lana[i] == LANA_INVALID) continue;
11354 ncbp->ncb_command = NCBDELNAME;
11355 ncbp->ncb_lana_num = lana_list.lana[i];
11356 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11357 code = Netbios(ncbp);
11359 code = ncbp->ncb_retcode;
11361 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11362 ncbp->ncb_lana_num, code);
11367 /* Release the reference counts held by the VCs */
11368 lock_ObtainWrite(&smb_rctLock);
11369 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11374 if (vcp->magic != SMB_VC_MAGIC)
11375 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11376 __FILE__, __LINE__);
11378 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11380 if (fidp->scp != NULL) {
11383 lock_ReleaseWrite(&smb_rctLock);
11384 lock_ObtainMutex(&fidp->mx);
11385 if (fidp->scp != NULL) {
11388 lock_ObtainWrite(&scp->rw);
11389 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11390 lock_ReleaseWrite(&scp->rw);
11391 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11392 cm_ReleaseSCache(scp);
11394 lock_ReleaseMutex(&fidp->mx);
11395 lock_ObtainWrite(&smb_rctLock);
11399 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11401 smb_ReleaseVCNoLock(tidp->vcp);
11403 cm_user_t *userp = tidp->userp;
11404 tidp->userp = NULL;
11405 cm_ReleaseUser(userp);
11409 lock_ReleaseWrite(&smb_rctLock);
11412 if (smb_monitorReqs) {
11413 smb_ShutdownMonitor();
11417 /* Get the UNC \\<servername>\<sharename> prefix. */
11418 char *smb_GetSharename()
11423 /* Make sure we have been properly initialized. */
11424 if (smb_localNamep == NULL)
11427 /* Allocate space for \\<servername>\<sharename>, plus the
11430 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11431 name = malloc(len);
11432 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11438 void smb_LogPacket(smb_packet_t *packet)
11442 unsigned length, paramlen, datalen, i, j;
11444 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11446 if (!packet) return;
11448 osi_Log0(smb_logp, "*** SMB packet dump ***");
11450 smbp = (smb_t *) packet->data;
11451 vp = (BYTE *) packet->data;
11453 paramlen = smbp->wct * 2;
11454 datalen = *((WORD *) (smbp->vdata + paramlen));
11455 length = sizeof(*smbp) + paramlen + 1 + datalen;
11457 for (i=0;i < length; i+=16)
11459 memset( buf, ' ', 80 );
11462 itoa( i, buf, 16 );
11464 buf[strlen(buf)] = ' ';
11466 cp = (BYTE*) buf + 7;
11468 for (j=0;j < 16 && (i+j)<length; j++)
11470 *(cp++) = hex[vp[i+j] >> 4];
11471 *(cp++) = hex[vp[i+j] & 0xf];
11481 for (j=0;j < 16 && (i+j)<length;j++)
11483 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11494 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11497 osi_Log0(smb_logp, "*** End SMB packet dump ***");
11499 #endif /* LOG_PACKET */
11502 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11508 smb_username_t *unp;
11509 smb_waitingLockRequest_t *wlrp;
11512 lock_ObtainRead(&smb_rctLock);
11514 sprintf(output, "begin dumping smb_username_t\r\n");
11515 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11516 for (unp = usernamesp; unp; unp=unp->nextp)
11518 cm_ucell_t *ucellp;
11520 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11521 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11522 unp->name ? unp->name : _C("NULL"),
11523 unp->machine ? unp->machine : _C("NULL"));
11524 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11526 sprintf(output, " begin dumping cm_ucell_t\r\n");
11527 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11529 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11530 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",
11531 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11532 ucellp->expirationTime, ucellp->gen,
11534 ucellp->cellp->name);
11535 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11538 sprintf(output, " done dumping cm_ucell_t\r\n");
11539 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11542 sprintf(output, "done dumping smb_username_t\r\n");
11543 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11549 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11550 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11552 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11553 smb_waitingLock_t *lockp;
11555 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11556 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11557 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11559 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
11560 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11561 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11562 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11563 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11564 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11566 sprintf(output, " done dumping smb_waitingLock_t\r\n");
11567 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11570 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11571 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11573 sprintf(output, "begin dumping smb_vc_t\r\n");
11574 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11576 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11582 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11583 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11584 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11586 sprintf(output, " begin dumping smb_user_t\r\n");
11587 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11588 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11589 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11590 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11591 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11593 sprintf(output, " done dumping smb_user_t\r\n");
11594 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11596 sprintf(output, " begin dumping smb_tid_t\r\n");
11597 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11598 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11599 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",
11600 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11601 tidp->pathname ? tidp->pathname : _C("NULL"));
11602 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11604 sprintf(output, " done dumping smb_tid_t\r\n");
11605 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11607 sprintf(output, " begin dumping smb_fid_t\r\n");
11608 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11610 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11612 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",
11613 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11614 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11615 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11616 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11619 sprintf(output, " done dumping smb_fid_t\r\n");
11620 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11623 sprintf(output, "done dumping smb_vc_t\r\n");
11624 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11626 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11627 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11629 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11635 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11636 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11637 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11639 sprintf(output, " begin dumping smb_user_t\r\n");
11640 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11641 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11642 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11643 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11644 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11646 sprintf(output, " done dumping smb_user_t\r\n");
11647 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11649 sprintf(output, " begin dumping smb_tid_t\r\n");
11650 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11651 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11652 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",
11653 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11654 tidp->pathname ? tidp->pathname : _C("NULL"));
11655 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11657 sprintf(output, " done dumping smb_tid_t\r\n");
11658 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11660 sprintf(output, " begin dumping smb_fid_t\r\n");
11661 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11663 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11665 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",
11666 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11667 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11668 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11669 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11672 sprintf(output, " done dumping smb_fid_t\r\n");
11673 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11676 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11677 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11681 lock_ReleaseRead(&smb_rctLock);
11685 long smb_IsNetworkStarted(void)
11692 lock_ObtainWrite(&smb_globalLock);
11693 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11694 lock_ReleaseWrite(&smb_globalLock);