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_INVAL_NET_RESP) {
3146 NTStatus = 0xC00000C3L; /* Invalid network response */
3148 else if (code == CM_ERROR_BADFD) {
3149 NTStatus = 0xC0000008L; /* Invalid handle */
3151 else if (code == CM_ERROR_BADFDOP) {
3152 NTStatus = 0xC0000022L; /* Access denied */
3154 else if (code == CM_ERROR_UNKNOWN) {
3155 NTStatus = 0xC0000022L; /* Access denied */
3157 else if (code == CM_ERROR_EXISTS) {
3158 NTStatus = 0xC0000035L; /* Object name collision */
3160 else if (code == CM_ERROR_NOTEMPTY) {
3161 NTStatus = 0xC0000101L; /* Directory not empty */
3163 else if (code == CM_ERROR_CROSSDEVLINK) {
3164 NTStatus = 0xC00000D4L; /* Not same device */
3166 else if (code == CM_ERROR_NOTDIR) {
3167 NTStatus = 0xC0000103L; /* Not a directory */
3169 else if (code == CM_ERROR_ISDIR) {
3170 NTStatus = 0xC00000BAL; /* File is a directory */
3172 else if (code == CM_ERROR_BADOP) {
3174 /* I have no idea where this comes from */
3175 NTStatus = 0xC09820FFL; /* SMB no support */
3177 NTStatus = 0xC00000BBL; /* Not supported */
3178 #endif /* COMMENT */
3180 else if (code == CM_ERROR_BADSHARENAME) {
3181 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3183 else if (code == CM_ERROR_NOIPC) {
3185 NTStatus = 0xC0000022L; /* Access Denied */
3187 NTStatus = 0xC000013DL; /* Remote Resources */
3190 else if (code == CM_ERROR_CLOCKSKEW ||
3191 code == RXKADNOAUTH) {
3192 NTStatus = 0xC0000133L; /* Time difference at DC */
3194 else if (code == CM_ERROR_BADTID) {
3195 NTStatus = 0xC0982005L; /* SMB bad TID */
3197 else if (code == CM_ERROR_USESTD) {
3198 NTStatus = 0xC09820FBL; /* SMB use standard */
3200 else if (code == CM_ERROR_QUOTA) {
3202 * AFS Redirector does not support Windows quota
3203 * interface. Always report disk full instead.
3206 NTStatus = 0xC000007FL; /* Disk full */
3208 NTStatus = 0xC0000044L; /* Quota exceeded */
3210 else if (code == CM_ERROR_SPACE) {
3211 NTStatus = 0xC000007FL; /* Disk full */
3213 else if (code == CM_ERROR_ATSYS) {
3214 NTStatus = 0xC0000033L; /* Object name invalid */
3216 else if (code == CM_ERROR_BADNTFILENAME) {
3217 NTStatus = 0xC0000033L; /* Object name invalid */
3219 else if (code == CM_ERROR_WOULDBLOCK) {
3220 NTStatus = 0xC00000D8L; /* Can't wait */
3222 else if (code == CM_ERROR_SHARING_VIOLATION) {
3223 NTStatus = 0xC0000043L; /* Sharing violation */
3225 else if (code == CM_ERROR_LOCK_CONFLICT) {
3226 NTStatus = 0xC0000054L; /* Lock conflict */
3228 else if (code == CM_ERROR_PARTIALWRITE) {
3229 NTStatus = 0xC000007FL; /* Disk full */
3231 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3232 NTStatus = 0xC0000023L; /* Buffer too small */
3234 else if (code == CM_ERROR_BUFFER_OVERFLOW) {
3235 NTStatus = 0x80000005L; /* Buffer overflow */
3237 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3238 NTStatus = 0xC0000035L; /* Object name collision */
3240 else if (code == CM_ERROR_BADPASSWORD) {
3241 NTStatus = 0xC000006DL; /* unknown username or bad password */
3243 else if (code == CM_ERROR_BADLOGONTYPE) {
3244 NTStatus = 0xC000015BL; /* logon type not granted */
3246 else if (code == CM_ERROR_GSSCONTINUE) {
3247 NTStatus = 0xC0000016L; /* more processing required */
3249 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3251 NTStatus = 0xC0000280L; /* reparse point not resolved */
3253 NTStatus = 0xC0000022L; /* Access Denied */
3256 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3257 NTStatus = 0xC0000257L; /* Path Not Covered */
3259 else if (code == CM_ERROR_ALLBUSY) {
3261 NTStatus = 0xC000022DL; /* Retry */
3263 NTStatus = 0xC0020018L; /* RPC_NT_SERVER_TOO_BUSY */
3266 else if (code == CM_ERROR_ALLOFFLINE ||
3267 code == CM_ERROR_ALLDOWN ||
3268 code == CM_ERROR_EMPTY) {
3270 NTStatus = 0xC000003AL; /* Path not found */
3272 NTStatus = 0xC0020017L; /* RPC_NT_SERVER_UNAVAILABLE */
3275 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3276 NTStatus = 0xC0000322L; /* No Kerberos key */
3278 else if (code == CM_ERROR_BAD_LEVEL) {
3279 NTStatus = 0xC0000148L; /* Invalid Level */
3281 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3282 NTStatus = 0xC000007EL; /* Range Not Locked */
3284 else if (code == CM_ERROR_NOSUCHDEVICE) {
3285 NTStatus = 0xC000000EL; /* No Such Device */
3287 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3288 NTStatus = 0xC0000055L; /* Lock Not Granted */
3290 else if (code == ENOMEM) {
3291 NTStatus = 0xC0000017L; /* Out of Memory */
3293 else if (code == EIO) {
3294 NTStatus = 0xC000016AL; /* Disk Operation Failure */
3296 else if (code == CM_ERROR_RPC_MOREDATA) {
3297 NTStatus = 0x80000005L; /* Buffer overflow */
3301 sprintf(foo, "No mapping for 0x%X using 0xC0982001\r\n", code);
3302 OutputDebugString(foo);
3303 NTStatus = 0xC0982001L; /* SMB non-specific error */
3306 *NTStatusp = NTStatus;
3307 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3311 * NTSTATUS <-> Win32 Error Translation
3312 * http://support.microsoft.com/kb/113996
3314 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3316 unsigned long Win32E;
3318 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3322 else if (code == CM_ERROR_NOSUCHCELL) {
3323 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3325 else if (code == CM_ERROR_NOSUCHVOLUME) {
3326 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3328 else if (code == CM_ERROR_TIMEDOUT) {
3330 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3332 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3335 else if (code == CM_ERROR_RETRY) {
3336 Win32E = ERROR_RETRY; /* Retry */
3338 else if (code == CM_ERROR_NOACCESS) {
3339 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3341 else if (code == CM_ERROR_READONLY) {
3342 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3344 else if (code == CM_ERROR_NOSUCHFILE ||
3345 code == CM_ERROR_BPLUS_NOMATCH) {
3346 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3348 else if (code == CM_ERROR_NOSUCHPATH) {
3349 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3351 else if (code == CM_ERROR_TOOBIG) {
3352 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3354 else if (code == CM_ERROR_INVAL) {
3355 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3357 else if (code == CM_ERROR_BADFD) {
3358 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3360 else if (code == CM_ERROR_BADFDOP) {
3361 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3363 else if (code == CM_ERROR_UNKNOWN) {
3364 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3366 else if (code == CM_ERROR_EXISTS) {
3367 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3369 else if (code == CM_ERROR_NOTEMPTY) {
3370 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3372 else if (code == CM_ERROR_CROSSDEVLINK) {
3373 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3375 else if (code == CM_ERROR_NOTDIR) {
3376 Win32E = ERROR_DIRECTORY; /* Not a directory */
3378 else if (code == CM_ERROR_ISDIR) {
3379 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3381 else if (code == CM_ERROR_BADOP) {
3382 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3384 else if (code == CM_ERROR_BADSHARENAME) {
3385 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3387 else if (code == CM_ERROR_NOIPC) {
3389 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3391 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3394 else if (code == CM_ERROR_CLOCKSKEW ||
3395 code == RXKADNOAUTH) {
3396 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3398 else if (code == CM_ERROR_BADTID) {
3399 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3401 else if (code == CM_ERROR_USESTD) {
3402 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3404 else if (code == CM_ERROR_QUOTA) {
3405 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3407 else if (code == CM_ERROR_SPACE) {
3408 Win32E = ERROR_DISK_FULL; /* Disk full */
3410 else if (code == CM_ERROR_ATSYS) {
3411 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3413 else if (code == CM_ERROR_BADNTFILENAME) {
3414 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3416 else if (code == CM_ERROR_WOULDBLOCK) {
3417 Win32E = WAIT_TIMEOUT; /* Can't wait */
3419 else if (code == CM_ERROR_SHARING_VIOLATION) {
3420 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3422 else if (code == CM_ERROR_LOCK_CONFLICT) {
3423 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3425 else if (code == CM_ERROR_PARTIALWRITE) {
3426 Win32E = ERROR_DISK_FULL; /* Disk full */
3428 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3429 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3431 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3432 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3434 else if (code == CM_ERROR_BADPASSWORD) {
3435 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3437 else if (code == CM_ERROR_BADLOGONTYPE) {
3438 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3440 else if (code == CM_ERROR_GSSCONTINUE) {
3441 Win32E = ERROR_MORE_DATA; /* more processing required */
3443 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3445 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3447 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3450 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3451 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3453 else if (code == CM_ERROR_ALLBUSY) {
3454 Win32E = ERROR_RETRY; /* Retry */
3456 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3457 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3459 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3460 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3462 else if (code == CM_ERROR_BAD_LEVEL) {
3463 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3465 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3466 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3468 else if (code == CM_ERROR_NOSUCHDEVICE) {
3469 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3471 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3472 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3474 else if (code == ENOMEM) {
3475 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3477 else if (code == CM_ERROR_RPC_MOREDATA) {
3478 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3481 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3485 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3488 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3489 unsigned char *classp)
3491 unsigned char class;
3492 unsigned short error;
3494 /* map CM_ERROR_* errors to SMB errors */
3495 if (code == CM_ERROR_NOSUCHCELL) {
3497 error = 3; /* bad path */
3499 else if (code == CM_ERROR_NOSUCHVOLUME) {
3501 error = 3; /* bad path */
3503 else if (code == CM_ERROR_TIMEDOUT) {
3505 error = 81; /* server is paused */
3507 else if (code == CM_ERROR_RETRY) {
3508 class = 2; /* shouldn't happen */
3511 else if (code == CM_ERROR_NOACCESS) {
3513 error = 4; /* bad access */
3515 else if (code == CM_ERROR_READONLY) {
3517 error = 19; /* read only */
3519 else if (code == CM_ERROR_NOSUCHFILE ||
3520 code == CM_ERROR_BPLUS_NOMATCH) {
3522 error = 2; /* ENOENT! */
3524 else if (code == CM_ERROR_NOSUCHPATH) {
3526 error = 3; /* Bad path */
3528 else if (code == CM_ERROR_TOOBIG) {
3530 error = 11; /* bad format */
3532 else if (code == CM_ERROR_INVAL) {
3533 class = 2; /* server non-specific error code */
3536 else if (code == CM_ERROR_BADFD) {
3538 error = 6; /* invalid file handle */
3540 else if (code == CM_ERROR_BADFDOP) {
3541 class = 1; /* invalid op on FD */
3544 else if (code == CM_ERROR_EXISTS) {
3546 error = 80; /* file already exists */
3548 else if (code == CM_ERROR_NOTEMPTY) {
3550 error = 5; /* delete directory not empty */
3552 else if (code == CM_ERROR_CROSSDEVLINK) {
3554 error = 17; /* EXDEV */
3556 else if (code == CM_ERROR_NOTDIR) {
3557 class = 1; /* bad path */
3560 else if (code == CM_ERROR_ISDIR) {
3561 class = 1; /* access denied; DOS doesn't have a good match */
3564 else if (code == CM_ERROR_BADOP) {
3568 else if (code == CM_ERROR_BADSHARENAME) {
3572 else if (code == CM_ERROR_NOIPC) {
3574 error = 4; /* bad access */
3576 else if (code == CM_ERROR_CLOCKSKEW) {
3577 class = 1; /* invalid function */
3580 else if (code == CM_ERROR_BADTID) {
3584 else if (code == CM_ERROR_USESTD) {
3588 else if (code == CM_ERROR_REMOTECONN) {
3592 else if (code == CM_ERROR_QUOTA) {
3593 if (vcp->flags & SMB_VCFLAG_USEV3) {
3595 error = 39; /* disk full */
3599 error = 5; /* access denied */
3602 else if (code == CM_ERROR_SPACE) {
3603 if (vcp->flags & SMB_VCFLAG_USEV3) {
3605 error = 39; /* disk full */
3609 error = 5; /* access denied */
3612 else if (code == CM_ERROR_PARTIALWRITE) {
3614 error = 39; /* disk full */
3616 else if (code == CM_ERROR_ATSYS) {
3618 error = 2; /* ENOENT */
3620 else if (code == CM_ERROR_WOULDBLOCK) {
3622 error = 33; /* lock conflict */
3624 else if (code == CM_ERROR_LOCK_CONFLICT) {
3626 error = 33; /* lock conflict */
3628 else if (code == CM_ERROR_SHARING_VIOLATION) {
3630 error = 33; /* lock conflict */
3632 else if (code == CM_ERROR_NOFILES) {
3634 error = 18; /* no files in search */
3636 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3638 error = 183; /* Samba uses this */
3640 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3641 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3643 error = 2; /* bad password */
3645 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3647 error = 3; /* bad path */
3656 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3659 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3661 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3662 return CM_ERROR_BADOP;
3666 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3668 unsigned short EchoCount, i;
3669 char *data, *outdata;
3672 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3674 for (i=1; i<=EchoCount; i++) {
3675 data = smb_GetSMBData(inp, &dataSize);
3676 smb_SetSMBParm(outp, 0, i);
3677 smb_SetSMBDataLength(outp, dataSize);
3678 outdata = smb_GetSMBData(outp, NULL);
3679 memcpy(outdata, data, dataSize);
3680 smb_SendPacket(vcp, outp);
3686 /* SMB_COM_READ_RAW */
3687 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3690 long count, minCount, finalCount;
3694 smb_t *smbp = (smb_t*) inp;
3696 cm_user_t *userp = NULL;
3699 char *rawBuf = NULL;
3704 fd = smb_GetSMBParm(inp, 0);
3705 count = smb_GetSMBParm(inp, 3);
3706 minCount = smb_GetSMBParm(inp, 4);
3707 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3709 if (*inp->wctp == 10) {
3710 /* we were sent a request with 64-bit file offsets */
3711 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3713 if (LargeIntegerLessThanZero(offset)) {
3714 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3718 /* we were sent a request with 32-bit file offsets */
3719 offset.HighPart = 0;
3722 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3723 fd, offset.HighPart, offset.LowPart, count);
3725 fidp = smb_FindFID(vcp, fd, 0);
3727 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3731 lock_ObtainMutex(&fidp->mx);
3733 lock_ReleaseMutex(&fidp->mx);
3734 smb_ReleaseFID(fidp);
3735 return CM_ERROR_BADFD;
3738 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3739 lock_ReleaseMutex(&fidp->mx);
3740 smb_CloseFID(vcp, fidp, NULL, 0);
3741 code = CM_ERROR_NOSUCHFILE;
3747 LARGE_INTEGER LOffset, LLength;
3750 key = cm_GenerateKey(vcp->vcID, pid, fd);
3752 LOffset.HighPart = offset.HighPart;
3753 LOffset.LowPart = offset.LowPart;
3754 LLength.HighPart = 0;
3755 LLength.LowPart = count;
3757 lock_ObtainWrite(&fidp->scp->rw);
3758 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3759 lock_ReleaseWrite(&fidp->scp->rw);
3762 lock_ReleaseMutex(&fidp->mx);
3766 lock_ObtainMutex(&smb_RawBufLock);
3768 /* Get a raw buf, from head of list */
3769 rawBuf = smb_RawBufs;
3770 smb_RawBufs = *(char **)smb_RawBufs;
3772 lock_ReleaseMutex(&smb_RawBufLock);
3774 lock_ReleaseMutex(&fidp->mx);
3778 if (fidp->flags & SMB_FID_IOCTL)
3780 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3782 /* Give back raw buffer */
3783 lock_ObtainMutex(&smb_RawBufLock);
3784 *((char **) rawBuf) = smb_RawBufs;
3786 smb_RawBufs = rawBuf;
3787 lock_ReleaseMutex(&smb_RawBufLock);
3790 lock_ReleaseMutex(&fidp->mx);
3791 smb_ReleaseFID(fidp);
3794 lock_ReleaseMutex(&fidp->mx);
3796 userp = smb_GetUserFromVCP(vcp, inp);
3798 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3804 cm_ReleaseUser(userp);
3807 smb_ReleaseFID(fidp);
3811 memset(ncbp, 0, sizeof(NCB));
3813 ncbp->ncb_length = (unsigned short) finalCount;
3814 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3815 ncbp->ncb_lana_num = vcp->lana;
3816 ncbp->ncb_command = NCBSEND;
3817 ncbp->ncb_buffer = rawBuf;
3819 code = Netbios(ncbp);
3821 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3824 /* Give back raw buffer */
3825 lock_ObtainMutex(&smb_RawBufLock);
3826 *((char **) rawBuf) = smb_RawBufs;
3828 smb_RawBufs = rawBuf;
3829 lock_ReleaseMutex(&smb_RawBufLock);
3835 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3837 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3842 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3844 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3849 /* SMB_COM_NEGOTIATE */
3850 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3857 int VistaProtoIndex;
3858 int protoIndex; /* index we're using */
3863 char protocol_array[10][1024]; /* protocol signature of the client */
3864 int caps; /* capabilities */
3867 TIME_ZONE_INFORMATION tzi;
3869 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3872 namep = smb_GetSMBData(inp, &dbytes);
3875 coreProtoIndex = -1; /* not found */
3878 VistaProtoIndex = -1;
3879 while(namex < dbytes) {
3880 osi_Log1(smb_logp, "Protocol %s",
3881 osi_LogSaveString(smb_logp, namep+1));
3882 strcpy(protocol_array[tcounter], namep+1);
3884 /* namep points at the first protocol, or really, a 0x02
3885 * byte preceding the null-terminated ASCII name.
3887 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3888 coreProtoIndex = tcounter;
3890 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3891 v3ProtoIndex = tcounter;
3893 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3894 NTProtoIndex = tcounter;
3896 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3897 VistaProtoIndex = tcounter;
3900 /* compute size of protocol entry */
3901 entryLength = (int)strlen(namep+1);
3902 entryLength += 2; /* 0x02 bytes and null termination */
3904 /* advance over this protocol entry */
3905 namex += entryLength;
3906 namep += entryLength;
3907 tcounter++; /* which proto entry we're looking at */
3910 lock_ObtainMutex(&vcp->mx);
3911 if (NTProtoIndex != -1) {
3912 protoIndex = NTProtoIndex;
3913 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3915 else if (v3ProtoIndex != -1) {
3916 protoIndex = v3ProtoIndex;
3917 vcp->flags |= SMB_VCFLAG_USEV3;
3919 else if (coreProtoIndex != -1) {
3920 protoIndex = coreProtoIndex;
3921 vcp->flags |= SMB_VCFLAG_USECORE;
3923 else protoIndex = -1;
3924 lock_ReleaseMutex(&vcp->mx);
3926 if (protoIndex == -1)
3927 return CM_ERROR_INVAL;
3928 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3929 smb_SetSMBParm(outp, 0, protoIndex);
3930 if (smb_authType != SMB_AUTH_NONE) {
3931 smb_SetSMBParmByte(outp, 1,
3932 NEGOTIATE_SECURITY_USER_LEVEL |
3933 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3935 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3937 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3938 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3939 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3940 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3941 /* The session key is not a well documented field however most clients
3942 * will echo back the session key to the server. Currently we are using
3943 * the same value for all sessions. We should generate a random value
3944 * and store it into the vcp
3946 smb_SetSMBParmLong(outp, 7, 0x1a2b3c4d); /* session key */
3948 * Tried changing the capabilities to support for W2K - defect 117695
3949 * Maybe something else needs to be changed here?
3953 smb_SetSMBParmLong(outp, 9, 0x43fd);
3955 smb_SetSMBParmLong(outp, 9, 0x251);
3958 * 32-bit error codes *
3964 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3966 NTNEGOTIATE_CAPABILITY_DFS |
3968 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3969 NTNEGOTIATE_CAPABILITY_NTFIND |
3970 NTNEGOTIATE_CAPABILITY_RAWMODE |
3971 NTNEGOTIATE_CAPABILITY_NTSMB;
3973 if ( smb_authType == SMB_AUTH_EXTENDED )
3974 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3977 if ( smb_UseUnicode ) {
3978 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3982 smb_SetSMBParmLong(outp, 9, caps);
3984 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3985 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3986 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3988 GetTimeZoneInformation(&tzi);
3989 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3991 if (smb_authType == SMB_AUTH_NTLM) {
3992 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3993 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3994 /* paste in encryption key */
3995 datap = smb_GetSMBData(outp, NULL);
3996 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3997 /* and the faux domain name */
3998 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3999 datap + MSV1_0_CHALLENGE_LENGTH,
4000 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4001 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
4002 void * secBlob = NULL;
4003 int secBlobLength = 0;
4005 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
4008 * The SMB specification permits the server to save a round trip
4009 * in the GSS negotiation by sending an initial security blob.
4010 * Unfortunately, doing so trips a bug in Windows 7 and Server 2008 R2
4011 * whereby the SMB 1.x redirector drops the blob on the floor after
4012 * the first connection to the server and simply attempts to reuse
4013 * the previous authentication context. This bug can be avoided by
4014 * the server sending no security blob in the SMB_COM_NEGOTIATE
4015 * response. This forces the client to send an initial GSS init_sec_context
4016 * blob under all circumstances which works around the bug in Microsoft's
4019 * Do not call smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
4022 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
4023 datap = smb_GetSMBData(outp, NULL);
4025 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
4026 datap += sizeof(smb_ServerGUID);
4029 memcpy(datap, secBlob, secBlobLength);
4031 datap += sizeof(secBlobLength);
4034 smb_SetSMBParmByte(outp, 16, 0);/* Challenge length */
4035 smb_SetSMBDataLength(outp, smb_ServerDomainNameLength);
4036 datap = smb_GetSMBData(outp, NULL);
4037 /* the faux domain name */
4038 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4040 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4043 else if (v3ProtoIndex != -1) {
4044 smb_SetSMBParm(outp, 0, protoIndex);
4046 /* NOTE: Extended authentication cannot be negotiated with v3
4047 * therefore we fail over to NTLM
4049 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4050 smb_SetSMBParm(outp, 1,
4051 NEGOTIATE_SECURITY_USER_LEVEL |
4052 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
4054 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4056 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4057 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
4058 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
4059 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
4060 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
4061 smb_SetSMBParm(outp, 7, 1);
4063 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
4064 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
4065 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
4067 GetTimeZoneInformation(&tzi);
4068 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
4070 /* NOTE: Extended authentication cannot be negotiated with v3
4071 * therefore we fail over to NTLM
4073 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4074 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
4075 smb_SetSMBParm(outp, 12, 0); /* resvd */
4076 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
4077 datap = smb_GetSMBData(outp, NULL);
4078 /* paste in a new encryption key */
4079 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4080 /* and the faux domain name */
4081 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4082 datap + MSV1_0_CHALLENGE_LENGTH,
4083 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4085 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4086 smb_SetSMBParm(outp, 12, 0); /* resvd */
4087 smb_SetSMBDataLength(outp, 0);
4090 else if (coreProtoIndex != -1) { /* not really supported anymore */
4091 smb_SetSMBParm(outp, 0, protoIndex);
4092 smb_SetSMBDataLength(outp, 0);
4097 void smb_CheckVCs(void)
4099 smb_vc_t * vcp, *nextp;
4100 smb_packet_t * outp = smb_GetPacket();
4103 lock_ObtainWrite(&smb_rctLock);
4104 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4106 if (vcp->magic != SMB_VC_MAGIC)
4107 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4108 __FILE__, __LINE__);
4110 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4112 smb_HoldVCNoLock(vcp);
4115 * obtain a reference to 'nextp' now because we drop the
4116 * smb_rctLock later and the list contents could change
4117 * or 'vcp' could be destroyed when released.
4121 smb_HoldVCNoLock(nextp);
4123 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4124 smb_ReleaseVCNoLock(vcp);
4128 smb_FormatResponsePacket(vcp, NULL, outp);
4129 smbp = (smb_t *)outp;
4130 outp->inCom = smbp->com = 0x2b /* Echo */;
4138 smb_SetSMBParm(outp, 0, 0);
4139 smb_SetSMBDataLength(outp, 0);
4140 lock_ReleaseWrite(&smb_rctLock);
4142 smb_SendPacket(vcp, outp);
4144 lock_ObtainWrite(&smb_rctLock);
4145 smb_ReleaseVCNoLock(vcp);
4147 lock_ReleaseWrite(&smb_rctLock);
4148 smb_FreePacket(outp);
4151 void smb_Daemon(void *parmp)
4153 afs_uint32 count = 0;
4154 smb_username_t **unpp;
4157 while(smbShutdownFlag == 0) {
4161 if (smbShutdownFlag == 1)
4164 if ((count % 72) == 0) { /* every five minutes */
4166 time_t old_localZero = smb_localZero;
4168 /* Initialize smb_localZero */
4169 myTime.tm_isdst = -1; /* compute whether on DST or not */
4170 myTime.tm_year = 70;
4176 smb_localZero = mktime(&myTime);
4178 #ifdef AFS_FREELANCE
4179 if ( smb_localZero != old_localZero )
4180 cm_noteLocalMountPointChange(FALSE);
4186 /* GC smb_username_t objects that will no longer be used */
4188 lock_ObtainWrite(&smb_rctLock);
4189 for ( unpp=&usernamesp; *unpp; ) {
4191 smb_username_t *unp;
4193 lock_ObtainMutex(&(*unpp)->mx);
4194 if ( (*unpp)->refCount > 0 ||
4195 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4196 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4198 else if (!smb_LogoffTokenTransfer ||
4199 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4201 lock_ReleaseMutex(&(*unpp)->mx);
4209 lock_FinalizeMutex(&unp->mx);
4215 cm_ReleaseUser(userp);
4217 unpp = &(*unpp)->nextp;
4220 lock_ReleaseWrite(&smb_rctLock);
4222 /* XXX GC dir search entries */
4226 void smb_WaitingLocksDaemon()
4228 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4229 smb_waitingLock_t *wl, *wlNext;
4232 smb_packet_t *inp, *outp;
4236 while (smbShutdownFlag == 0) {
4237 lock_ObtainWrite(&smb_globalLock);
4238 nwlRequest = smb_allWaitingLocks;
4239 if (nwlRequest == NULL) {
4240 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4245 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4252 lock_ObtainWrite(&smb_globalLock);
4254 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4256 wlRequest = nwlRequest;
4257 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4258 lock_ReleaseWrite(&smb_globalLock);
4262 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4263 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4266 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4267 code = CM_ERROR_LOCK_NOT_GRANTED;
4271 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4273 /* wl->state is either _DONE or _WAITING. _ERROR
4274 would no longer be on the queue. */
4275 code = cm_RetryLock( wl->lockp,
4276 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4279 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4280 } else if (code != CM_ERROR_WOULDBLOCK) {
4281 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4286 if (code == CM_ERROR_WOULDBLOCK) {
4289 if (wlRequest->msTimeout != 0xffffffff
4290 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4302 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4305 scp = wlRequest->scp;
4306 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4310 lock_ObtainWrite(&scp->rw);
4312 for (wl = wlRequest->locks; wl; wl = wlNext) {
4313 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4315 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4316 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4317 wl->LLength, wl->key, 0, NULL, &req);
4319 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4324 lock_ReleaseWrite(&scp->rw);
4328 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4331 for (wl = wlRequest->locks; wl; wl = wlNext) {
4332 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4333 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4338 vcp = wlRequest->vcp;
4339 inp = wlRequest->inp;
4340 outp = wlRequest->outp;
4341 ncbp = smb_GetNCB();
4342 ncbp->ncb_length = inp->ncb_length;
4343 inp->spacep = cm_GetSpace();
4345 /* Remove waitingLock from list */
4346 lock_ObtainWrite(&smb_globalLock);
4347 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4349 lock_ReleaseWrite(&smb_globalLock);
4351 /* Resume packet processing */
4353 smb_SetSMBDataLength(outp, 0);
4354 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4355 outp->resumeCode = code;
4357 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4360 cm_FreeSpace(inp->spacep);
4361 smb_FreePacket(inp);
4362 smb_FreePacket(outp);
4364 cm_ReleaseSCache(wlRequest->scp);
4367 } while (nwlRequest && smbShutdownFlag == 0);
4372 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4374 osi_Log0(smb_logp, "SMB receive get disk attributes");
4376 smb_SetSMBParm(outp, 0, 32000);
4377 smb_SetSMBParm(outp, 1, 64);
4378 smb_SetSMBParm(outp, 2, 1024);
4379 smb_SetSMBParm(outp, 3, 30000);
4380 smb_SetSMBParm(outp, 4, 0);
4381 smb_SetSMBDataLength(outp, 0);
4385 /* SMB_COM_TREE_CONNECT */
4386 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4390 unsigned short newTid;
4391 clientchar_t shareName[AFSPATHMAX];
4392 clientchar_t *sharePath;
4395 clientchar_t *pathp;
4398 osi_Log0(smb_logp, "SMB receive tree connect");
4400 /* parse input parameters */
4403 tbp = smb_GetSMBData(inp, NULL);
4404 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4406 return CM_ERROR_BADSMB;
4408 tp = cm_ClientStrRChr(pathp, '\\');
4410 return CM_ERROR_BADSMB;
4411 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4413 lock_ObtainMutex(&vcp->mx);
4414 newTid = vcp->tidCounter++;
4415 lock_ReleaseMutex(&vcp->mx);
4417 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4418 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4420 return CM_ERROR_BADSMB;
4421 userp = smb_GetUserFromUID(uidp);
4422 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4423 smb_ReleaseUID(uidp);
4425 smb_ReleaseTID(tidp, FALSE);
4426 return CM_ERROR_BADSHARENAME;
4428 lock_ObtainMutex(&tidp->mx);
4429 tidp->userp = userp;
4430 tidp->pathname = sharePath;
4431 lock_ReleaseMutex(&tidp->mx);
4432 smb_ReleaseTID(tidp, FALSE);
4434 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4435 smb_SetSMBParm(rsp, 1, newTid);
4436 smb_SetSMBDataLength(rsp, 0);
4438 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4442 /* set maskp to the mask part of the incoming path.
4443 * Mask is 11 bytes long (8.3 with the dot elided).
4444 * Returns true if succeeds with a valid name, otherwise it does
4445 * its best, but returns false.
4447 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4455 /* starts off valid */
4458 /* mask starts out all blanks */
4459 memset(maskp, ' ', 11);
4462 /* find last backslash, or use whole thing if there is none */
4463 tp = cm_ClientStrRChr(pathp, '\\');
4467 tp++; /* skip slash */
4471 /* names starting with a dot are illegal */
4479 if (tc == '.' || tc == '"')
4487 /* if we get here, tp point after the dot */
4488 up = maskp+8; /* ext goes here */
4495 if (tc == '.' || tc == '"')
4498 /* copy extension if not too long */
4508 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4510 clientchar_t umask[11];
4518 /* XXX redo this, calling cm_MatchMask with a converted mask */
4520 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4524 /* otherwise, we have a valid 8.3 name; see if we have a match,
4525 * treating '?' as a wildcard in maskp (but not in the file name).
4527 tp1 = umask; /* real name, in mask format */
4528 tp2 = maskp; /* mask, in mask format */
4529 for(i=0; i<11; i++) {
4530 tc1 = *tp1++; /* clientchar_t from real name */
4531 tc2 = *tp2++; /* clientchar_t from mask */
4532 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4533 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4536 if (tc2 == '?' && tc1 != ' ')
4543 /* we got a match */
4547 clientchar_t *smb_FindMask(clientchar_t *pathp)
4551 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4554 return tp+1; /* skip the slash */
4556 return pathp; /* no slash, return the entire path */
4559 /* SMB_COM_SEARCH for a volume label
4561 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4562 dispatch function.) */
4563 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4565 clientchar_t *pathp;
4567 clientchar_t mask[12];
4568 unsigned char *statBlockp;
4569 unsigned char initStatBlock[21];
4572 osi_Log0(smb_logp, "SMB receive search volume");
4574 /* pull pathname and stat block out of request */
4575 tp = smb_GetSMBData(inp, NULL);
4576 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4577 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4579 return CM_ERROR_BADSMB;
4580 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4581 osi_assertx(statBlockp != NULL, "null statBlock");
4583 statBlockp = initStatBlock;
4587 /* for returning to caller */
4588 smb_Get8Dot3MaskFromPath(mask, pathp);
4590 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4591 tp = smb_GetSMBData(outp, NULL);
4593 *tp++ = 43; /* bytes in a dir entry */
4594 *tp++ = 0; /* high byte in counter */
4596 /* now marshall the dir entry, starting with the search status */
4597 *tp++ = statBlockp[0]; /* Reserved */
4598 memcpy(tp, mask, 11); tp += 11; /* FileName */
4600 /* now pass back server use info, with 1st byte non-zero */
4602 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4604 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4606 *tp++ = 0x8; /* attribute: volume */
4616 /* 4 byte file size */
4622 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4625 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4626 memset(tp, ' ', 13);
4629 /* set the length of the data part of the packet to 43 + 3, for the dir
4630 * entry plus the 5 and the length fields.
4632 smb_SetSMBDataLength(outp, 46);
4637 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4638 clientchar_t * tidPathp, clientchar_t * relPathp,
4639 cm_user_t *userp, cm_req_t *reqp)
4647 smb_dirListPatch_t *patchp;
4648 smb_dirListPatch_t *npatchp;
4649 clientchar_t path[AFSPATHMAX];
4651 afs_int32 mustFake = 0;
4652 afs_int32 nobulkstat = 0;
4654 lock_ObtainWrite(&dscp->rw);
4655 code = cm_FindACLCache(dscp, userp, &rights);
4657 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4658 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4659 if (code == CM_ERROR_NOACCESS) {
4664 lock_ReleaseWrite(&dscp->rw);
4668 if (!mustFake) { /* Bulk Stat */
4670 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4672 memset(bsp, 0, sizeof(cm_bulkStat_t));
4676 for (patchp = *dirPatchespp, count=0;
4678 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4679 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4683 if (lock_TryWrite(&tscp->rw)) {
4684 /* we have an entry that we can look at */
4685 if (!cm_EAccesFindEntry(userp, &tscp->fid) && cm_HaveCallback(tscp)) {
4686 /* we have a callback on it. Don't bother
4687 * fetching this stat entry, since we're happy
4688 * with the info we have.
4690 lock_ReleaseWrite(&tscp->rw);
4691 cm_ReleaseSCache(tscp);
4696 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4697 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4698 lock_ReleaseWrite(&tscp->rw);
4699 cm_ReleaseSCache(tscp);
4703 lock_ReleaseWrite(&tscp->rw);
4705 cm_ReleaseSCache(tscp);
4709 bsp->fids[i].Volume = patchp->fid.volume;
4710 bsp->fids[i].Vnode = patchp->fid.vnode;
4711 bsp->fids[i].Unique = patchp->fid.unique;
4713 if (bsp->counter == AFSCBMAX) {
4714 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4715 memset(bsp, 0, sizeof(cm_bulkStat_t));
4718 if (code == CM_ERROR_BULKSTAT_FAILURE) {
4720 * If bulk stat cannot be used for this directory
4721 * we must perform individual fetch status calls.
4722 * Restart from the beginning of the patch series.
4725 goto restart_patchset;
4730 if (bsp->counter > 0)
4731 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4736 for (patchp = *dirPatchespp; patchp; patchp =
4737 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4739 dptr = patchp->dptr;
4741 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4742 relPathp ? relPathp : _C(""), patchp->dep->name);
4743 reqp->relPathp = path;
4744 reqp->tidPathp = tidPathp;
4746 code = cm_GetSCache(&patchp->fid, &dscp->fid, &scp, userp, reqp);
4747 reqp->relPathp = reqp->tidPathp = NULL;
4750 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4751 *dptr++ = SMB_ATTR_HIDDEN;
4754 lock_ObtainWrite(&scp->rw);
4755 if (mustFake || cm_EAccesFindEntry(userp, &scp->fid) || !cm_HaveCallback(scp)) {
4756 lock_ReleaseWrite(&scp->rw);
4758 /* set the attribute */
4759 switch (scp->fileType) {
4760 case CM_SCACHETYPE_DIRECTORY:
4761 case CM_SCACHETYPE_MOUNTPOINT:
4762 case CM_SCACHETYPE_INVALID:
4763 attr = SMB_ATTR_DIRECTORY;
4765 case CM_SCACHETYPE_SYMLINK:
4766 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4767 attr = SMB_ATTR_DIRECTORY;
4769 attr = SMB_ATTR_NORMAL;
4772 /* if we get here we either have a normal file
4773 * or we have a file for which we have never
4774 * received status info. In this case, we can
4775 * check the even/odd value of the entry's vnode.
4776 * odd means it is to be treated as a directory
4777 * and even means it is to be treated as a file.
4779 if (mustFake && (scp->fid.vnode & 0x1))
4780 attr = SMB_ATTR_DIRECTORY;
4782 attr = SMB_ATTR_NORMAL;
4786 /* 1969-12-31 23:59:58 +00*/
4787 dosTime = 0xEBBFBF7D;
4790 shortTemp = (unsigned short) (dosTime & 0xffff);
4791 *((u_short *)dptr) = shortTemp;
4794 /* and copy out date */
4795 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4796 *((u_short *)dptr) = shortTemp;
4799 /* copy out file length */
4800 *((u_long *)dptr) = 0;
4803 lock_ConvertWToR(&scp->rw);
4804 attr = smb_Attributes(scp);
4805 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4806 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4807 attr |= SMB_ATTR_HIDDEN;
4811 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4814 shortTemp = (unsigned short) (dosTime & 0xffff);
4815 *((u_short *)dptr) = shortTemp;
4818 /* and copy out date */
4819 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4820 *((u_short *)dptr) = shortTemp;
4823 /* copy out file length */
4824 *((u_long *)dptr) = scp->length.LowPart;
4826 lock_ReleaseRead(&scp->rw);
4828 cm_ReleaseSCache(scp);
4831 /* now free the patches */
4832 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4833 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4837 /* and mark the list as empty */
4838 *dirPatchespp = NULL;
4844 /* SMB_COM_SEARCH */
4845 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4851 clientchar_t *pathp;
4852 cm_dirEntry_t *dep = 0;
4854 smb_dirListPatch_t *dirListPatchesp;
4855 smb_dirListPatch_t *curPatchp;
4859 osi_hyper_t dirLength;
4860 osi_hyper_t bufferOffset;
4861 osi_hyper_t curOffset;
4863 unsigned char *inCookiep;
4864 smb_dirSearch_t *dsp;
4868 unsigned long clientCookie;
4869 cm_pageHeader_t *pageHeaderp;
4870 cm_user_t *userp = NULL;
4872 clientchar_t mask[12];
4874 long nextEntryCookie;
4875 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4876 char resByte; /* reserved byte from the cookie */
4877 char *op; /* output data ptr */
4878 char *origOp; /* original value of op */
4879 cm_space_t *spacep; /* for pathname buffer */
4883 clientchar_t *tidPathp = 0;
4890 maxCount = smb_GetSMBParm(inp, 0);
4892 dirListPatchesp = NULL;
4894 caseFold = CM_FLAG_CASEFOLD;
4896 tp = smb_GetSMBData(inp, NULL);
4897 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4898 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4900 return CM_ERROR_BADSMB;
4902 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4904 return CM_ERROR_BADSMB;
4906 /* We can handle long names */
4907 if (vcp->flags & SMB_VCFLAG_USENT)
4908 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4910 /* make sure we got a whole search status */
4911 if (dataLength < 21) {
4912 nextCookie = 0; /* start at the beginning of the dir */
4915 attribute = smb_GetSMBParm(inp, 1);
4917 /* handle volume info in another function */
4918 if (attribute & 0x8)
4919 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4921 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4922 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4924 if (*pathp == 0) { /* null pathp, treat as root dir */
4925 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4926 return CM_ERROR_NOFILES;
4930 dsp = smb_NewDirSearch(0);
4931 dsp->attribute = attribute;
4932 smb_Get8Dot3MaskFromPath(mask, pathp);
4933 memcpy(dsp->mask, mask, 12);
4935 /* track if this is likely to match a lot of entries */
4936 if (smb_Is8Dot3StarMask(mask))
4941 /* pull the next cookie value out of the search status block */
4942 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4943 + (inCookiep[16]<<24);
4944 dsp = smb_FindDirSearch(inCookiep[12]);
4946 /* can't find dir search status; fatal error */
4947 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4948 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4949 return CM_ERROR_BADFD;
4951 attribute = dsp->attribute;
4952 resByte = inCookiep[0];
4954 /* copy out client cookie, in host byte order. Don't bother
4955 * interpreting it, since we're just passing it through, anyway.
4957 memcpy(&clientCookie, &inCookiep[17], 4);
4959 memcpy(mask, dsp->mask, 12);
4961 /* assume we're doing a star match if it has continued for more
4967 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4968 nextCookie, dsp->cookie, attribute);
4970 userp = smb_GetUserFromVCP(vcp, inp);
4972 /* try to get the vnode for the path name next */
4973 lock_ObtainMutex(&dsp->mx);
4976 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4980 spacep = inp->spacep;
4981 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4982 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4984 lock_ReleaseMutex(&dsp->mx);
4985 cm_ReleaseUser(userp);
4986 smb_DeleteDirSearch(dsp);
4987 smb_ReleaseDirSearch(dsp);
4988 return CM_ERROR_NOFILES;
4990 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4991 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4993 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
4994 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4997 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5000 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
5001 cm_ReleaseSCache(scp);
5002 lock_ReleaseMutex(&dsp->mx);
5003 cm_ReleaseUser(userp);
5004 smb_DeleteDirSearch(dsp);
5005 smb_ReleaseDirSearch(dsp);
5006 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5007 return CM_ERROR_PATH_NOT_COVERED;
5009 return CM_ERROR_NOSUCHPATH;
5011 #endif /* DFS_SUPPORT */
5014 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
5015 /* we need one hold for the entry we just stored into,
5016 * and one for our own processing. When we're done with this
5017 * function, we'll drop the one for our own processing.
5018 * We held it once from the namei call, and so we do another hold
5022 lock_ObtainWrite(&scp->rw);
5023 dsp->flags |= SMB_DIRSEARCH_BULKST;
5024 lock_ReleaseWrite(&scp->rw);
5027 lock_ReleaseMutex(&dsp->mx);
5029 cm_ReleaseUser(userp);
5030 smb_DeleteDirSearch(dsp);
5031 smb_ReleaseDirSearch(dsp);
5035 /* reserves space for parameter; we'll adjust it again later to the
5036 * real count of the # of entries we returned once we've actually
5037 * assembled the directory listing.
5039 smb_SetSMBParm(outp, 0, 0);
5041 /* get the directory size */
5042 lock_ObtainWrite(&scp->rw);
5043 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5044 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5046 lock_ReleaseWrite(&scp->rw);
5047 cm_ReleaseSCache(scp);
5048 cm_ReleaseUser(userp);
5049 smb_DeleteDirSearch(dsp);
5050 smb_ReleaseDirSearch(dsp);
5054 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5056 dirLength = scp->length;
5058 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5059 curOffset.HighPart = 0;
5060 curOffset.LowPart = nextCookie;
5061 origOp = op = smb_GetSMBData(outp, NULL);
5062 /* and write out the basic header */
5063 *op++ = 5; /* variable block */
5064 op += 2; /* skip vbl block length; we'll fill it in later */
5068 clientchar_t *actualName = NULL;
5069 int free_actualName = 0;
5070 clientchar_t shortName[13];
5071 clientchar_t *shortNameEnd;
5073 /* make sure that curOffset.LowPart doesn't point to the first
5074 * 32 bytes in the 2nd through last dir page, and that it doesn't
5075 * point at the first 13 32-byte chunks in the first dir page,
5076 * since those are dir and page headers, and don't contain useful
5079 temp = curOffset.LowPart & (2048-1);
5080 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5081 /* we're in the first page */
5082 if (temp < 13*32) temp = 13*32;
5085 /* we're in a later dir page */
5086 if (temp < 32) temp = 32;
5089 /* make sure the low order 5 bits are zero */
5092 /* now put temp bits back ito curOffset.LowPart */
5093 curOffset.LowPart &= ~(2048-1);
5094 curOffset.LowPart |= temp;
5096 /* check if we've returned all the names that will fit in the
5099 if (returnedNames >= maxCount) {
5100 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5101 returnedNames, maxCount);
5105 /* check if we've passed the dir's EOF */
5106 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5108 /* see if we can use the bufferp we have now; compute in which page
5109 * the current offset would be, and check whether that's the offset
5110 * of the buffer we have. If not, get the buffer.
5112 thyper.HighPart = curOffset.HighPart;
5113 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5114 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5117 buf_Release(bufferp);
5120 lock_ReleaseWrite(&scp->rw);
5121 code = buf_Get(scp, &thyper, &req, 0, &bufferp);
5122 lock_ObtainMutex(&dsp->mx);
5124 /* now, if we're doing a star match, do bulk fetching of all of
5125 * the status info for files in the dir.
5128 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5130 lock_ObtainWrite(&scp->rw);
5131 lock_ReleaseMutex(&dsp->mx);
5133 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5137 bufferOffset = thyper;
5139 /* now get the data in the cache */
5141 code = cm_SyncOp(scp, bufferp, userp, &req,
5143 CM_SCACHESYNC_NEEDCALLBACK |
5144 CM_SCACHESYNC_READ);
5146 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5150 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5152 if (cm_HaveBuffer(scp, bufferp, 0)) {
5153 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5157 /* otherwise, load the buffer and try again */
5158 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5160 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5161 scp, bufferp, code);
5166 buf_Release(bufferp);
5170 } /* if (wrong buffer) ... */
5172 /* now we have the buffer containing the entry we're interested in; copy
5173 * it out if it represents a non-deleted entry.
5175 entryInDir = curOffset.LowPart & (2048-1);
5176 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5178 /* page header will help tell us which entries are free. Page header
5179 * can change more often than once per buffer, since AFS 3 dir page size
5180 * may be less than (but not more than a buffer package buffer.
5182 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5183 temp &= ~(2048 - 1); /* turn off intra-page bits */
5184 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5186 /* now determine which entry we're looking at in the page. If it is
5187 * free (there's a free bitmap at the start of the dir), we should
5188 * skip these 32 bytes.
5190 slotInPage = (entryInDir & 0x7e0) >> 5;
5191 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5192 /* this entry is free */
5193 numDirChunks = 1; /* only skip this guy */
5197 tp = bufferp->datap + entryInBuffer;
5198 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5200 /* while we're here, compute the next entry's location, too,
5201 * since we'll need it when writing out the cookie into the dir
5204 * XXXX Probably should do more sanity checking.
5206 numDirChunks = cm_NameEntries(dep->name, NULL);
5208 /* compute the offset of the cookie representing the next entry */
5209 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5211 /* Compute 8.3 name if necessary */
5212 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5213 if (dep->fid.vnode != 0 && cm_shortNames && !cm_Is8Dot3(actualName)) {
5216 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5217 actualName = shortName;
5218 free_actualName = 0;
5220 free_actualName = 1;
5223 if (actualName == NULL) {
5224 /* Couldn't convert the name for some reason */
5225 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5226 osi_LogSaveString(smb_logp, dep->name));
5230 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5231 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5232 osi_LogSaveClientString(smb_logp, actualName));
5234 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5235 /* this is one of the entries to use: it is not deleted
5236 * and it matches the star pattern we're looking for.
5239 /* Eliminate entries that don't match requested
5242 /* no hidden files */
5243 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5244 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5248 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5250 /* We have already done the cm_TryBulkStat above */
5251 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5252 fileType = cm_FindFileType(&fid);
5253 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5254 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5256 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5257 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5258 fileType == CM_SCACHETYPE_DFSLINK ||
5259 fileType == CM_SCACHETYPE_INVALID)
5260 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5265 memcpy(op, mask, 11); op += 11;
5266 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5267 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5268 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5269 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5270 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5271 memcpy(op, &clientCookie, 4); op += 4;
5273 /* now we emit the attribute. This is sort of tricky,
5274 * since we need to really stat the file to find out
5275 * what type of entry we've got. Right now, we're
5276 * copying out data from a buffer, while holding the
5277 * scp locked, so it isn't really convenient to stat
5278 * something now. We'll put in a place holder now,
5279 * and make a second pass before returning this to get
5280 * the real attributes. So, we just skip the data for
5281 * now, and adjust it later. We allocate a patch
5282 * record to make it easy to find this point later.
5283 * The replay will happen at a time when it is safe to
5284 * unlock the directory.
5286 curPatchp = malloc(sizeof(*curPatchp));
5287 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5288 curPatchp->dptr = op;
5289 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5291 /* do hidden attribute here since name won't be around when applying
5295 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5296 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5298 curPatchp->flags = 0;
5300 op += 9; /* skip attr, time, date and size */
5302 /* zero out name area. The spec says to pad with
5303 * spaces, but Samba doesn't, and neither do we.
5307 /* finally, we get to copy out the name; we know that
5308 * it fits in 8.3 or the pattern wouldn't match, but it
5309 * never hurts to be sure.
5311 cm_ClientStringToUtf8(actualName, -1, op, 13);
5312 if (smb_StoreAnsiFilenames)
5314 /* This is a UCHAR field, which is ASCII even if Unicode
5317 /* Uppercase if requested by client */
5318 if (!KNOWS_LONG_NAMES(inp))
5323 /* now, adjust the # of entries copied */
5325 } /* if we're including this name */
5328 if (free_actualName && actualName) {
5333 /* and adjust curOffset to be where the new cookie is */
5334 thyper.HighPart = 0;
5335 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5336 curOffset = LargeIntegerAdd(thyper, curOffset);
5337 } /* while copying data for dir listing */
5339 /* release the mutex */
5340 lock_ReleaseWrite(&scp->rw);
5342 buf_Release(bufferp);
5346 /* apply and free last set of patches; if not doing a star match, this
5347 * will be empty, but better safe (and freeing everything) than sorry.
5349 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5351 /* special return code for unsuccessful search */
5352 if (code == 0 && dataLength < 21 && returnedNames == 0)
5353 code = CM_ERROR_NOFILES;
5355 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5356 returnedNames, code);
5359 smb_DeleteDirSearch(dsp);
5360 smb_ReleaseDirSearch(dsp);
5361 cm_ReleaseSCache(scp);
5362 cm_ReleaseUser(userp);
5366 /* finalize the output buffer */
5367 smb_SetSMBParm(outp, 0, returnedNames);
5368 temp = (long) (op - origOp);
5369 smb_SetSMBDataLength(outp, temp);
5371 /* the data area is a variable block, which has a 5 (already there)
5372 * followed by the length of the # of data bytes. We now know this to
5373 * be "temp," although that includes the 3 bytes of vbl block header.
5374 * Deduct for them and fill in the length field.
5376 temp -= 3; /* deduct vbl block info */
5377 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5378 origOp[1] = (unsigned char)(temp & 0xff);
5379 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5380 if (returnedNames == 0)
5381 smb_DeleteDirSearch(dsp);
5382 smb_ReleaseDirSearch(dsp);
5383 cm_ReleaseSCache(scp);
5384 cm_ReleaseUser(userp);
5389 /* verify that this is a valid path to a directory. I don't know why they
5390 * don't use the get file attributes call.
5392 * SMB_COM_CHECK_DIRECTORY
5394 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5396 clientchar_t *pathp;
5398 cm_scache_t *rootScp;
5399 cm_scache_t *newScp;
5403 clientchar_t *tidPathp;
5409 pdata = smb_GetSMBData(inp, NULL);
5410 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5412 return CM_ERROR_BADSMB;
5413 osi_Log1(smb_logp, "SMB receive check path %S",
5414 osi_LogSaveClientString(smb_logp, pathp));
5416 userp = smb_GetUserFromVCP(vcp, inp);
5418 rootScp = cm_RootSCachep(userp, &req);
5420 caseFold = CM_FLAG_CASEFOLD;
5422 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5424 cm_ReleaseUser(userp);
5425 return CM_ERROR_NOSUCHPATH;
5427 code = cm_NameI(rootScp, pathp,
5428 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5429 userp, tidPathp, &req, &newScp);
5432 cm_ReleaseUser(userp);
5437 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5438 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5439 cm_ReleaseSCache(newScp);
5440 cm_ReleaseUser(userp);
5441 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5442 return CM_ERROR_PATH_NOT_COVERED;
5444 return CM_ERROR_NOSUCHPATH;
5446 #endif /* DFS_SUPPORT */
5448 /* now lock the vnode with a callback; returns with newScp locked */
5449 lock_ObtainWrite(&newScp->rw);
5450 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5451 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5453 if (code != CM_ERROR_NOACCESS) {
5454 lock_ReleaseWrite(&newScp->rw);
5455 cm_ReleaseSCache(newScp);
5456 cm_ReleaseUser(userp);
5460 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5463 attrs = smb_Attributes(newScp);
5465 if (!(attrs & SMB_ATTR_DIRECTORY))
5466 code = CM_ERROR_NOTDIR;
5468 lock_ReleaseWrite(&newScp->rw);
5470 cm_ReleaseSCache(newScp);
5471 cm_ReleaseUser(userp);
5475 /* SMB_COM_SET_INFORMATION */
5476 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5478 clientchar_t *pathp;
5480 cm_scache_t *rootScp;
5481 unsigned short attribute;
5483 cm_scache_t *newScp;
5487 clientchar_t *tidPathp;
5493 /* decode basic attributes we're passed */
5494 attribute = smb_GetSMBParm(inp, 0);
5495 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5497 datap = smb_GetSMBData(inp, NULL);
5498 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5500 return CM_ERROR_BADSMB;
5502 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5503 dosTime, attribute);
5505 userp = smb_GetUserFromVCP(vcp, inp);
5507 rootScp = cm_RootSCachep(userp, &req);
5509 caseFold = CM_FLAG_CASEFOLD;
5511 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5513 cm_ReleaseUser(userp);
5514 return CM_ERROR_NOSUCHFILE;
5516 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5517 tidPathp, &req, &newScp);
5520 cm_ReleaseUser(userp);
5525 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5526 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5527 cm_ReleaseSCache(newScp);
5528 cm_ReleaseUser(userp);
5529 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5530 return CM_ERROR_PATH_NOT_COVERED;
5532 return CM_ERROR_NOSUCHPATH;
5534 #endif /* DFS_SUPPORT */
5536 /* now lock the vnode with a callback; returns with newScp locked; we
5537 * need the current status to determine what the new status is, in some
5540 lock_ObtainWrite(&newScp->rw);
5541 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5542 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5544 lock_ReleaseWrite(&newScp->rw);
5545 cm_ReleaseSCache(newScp);
5546 cm_ReleaseUser(userp);
5550 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5552 /* Check for RO volume */
5553 if (newScp->flags & CM_SCACHEFLAG_RO) {
5554 lock_ReleaseWrite(&newScp->rw);
5555 cm_ReleaseSCache(newScp);
5556 cm_ReleaseUser(userp);
5557 return CM_ERROR_READONLY;
5560 /* prepare for setattr call */
5563 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5564 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5566 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5567 /* we're told to make a writable file read-only */
5568 attr.unixModeBits = newScp->unixModeBits & ~0222;
5569 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5571 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5572 /* we're told to make a read-only file writable */
5573 attr.unixModeBits = newScp->unixModeBits | 0222;
5574 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5576 lock_ReleaseWrite(&newScp->rw);
5578 /* now call setattr */
5580 code = cm_SetAttr(newScp, &attr, userp, &req);
5584 cm_ReleaseSCache(newScp);
5585 cm_ReleaseUser(userp);
5591 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5593 clientchar_t *pathp;
5595 cm_scache_t *rootScp;
5596 cm_scache_t *newScp, *dscp;
5601 clientchar_t *tidPathp;
5603 clientchar_t *lastComp;
5609 datap = smb_GetSMBData(inp, NULL);
5610 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5612 return CM_ERROR_BADSMB;
5614 if (*pathp == 0) /* null path */
5617 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5618 osi_LogSaveClientString(smb_logp, pathp));
5620 userp = smb_GetUserFromVCP(vcp, inp);
5622 rootScp = cm_RootSCachep(userp, &req);
5624 /* we shouldn't need this for V3 requests, but we seem to */
5625 caseFold = CM_FLAG_CASEFOLD;
5627 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5629 cm_ReleaseUser(userp);
5630 return CM_ERROR_NOSUCHFILE;
5634 * XXX Strange hack XXX
5636 * As of Patch 5 (16 July 97), we are having the following problem:
5637 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5638 * requests to look up "desktop.ini" in all the subdirectories.
5639 * This can cause zillions of timeouts looking up non-existent cells
5640 * and volumes, especially in the top-level directory.
5642 * We have not found any way to avoid this or work around it except
5643 * to explicitly ignore the requests for mount points that haven't
5644 * yet been evaluated and for directories that haven't yet been
5647 * We should modify this hack to provide a fake desktop.ini file
5648 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5650 spacep = inp->spacep;
5651 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5652 #ifndef SPECIAL_FOLDERS
5653 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5654 code = cm_NameI(rootScp, spacep->wdata,
5655 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5656 userp, tidPathp, &req, &dscp);
5659 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5660 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5662 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5663 return CM_ERROR_PATH_NOT_COVERED;
5665 return CM_ERROR_NOSUCHPATH;
5667 #endif /* DFS_SUPPORT */
5668 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5669 code = CM_ERROR_NOSUCHFILE;
5670 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5671 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
5676 code = CM_ERROR_NOSUCHFILE;
5678 cm_ReleaseSCache(dscp);
5680 cm_ReleaseUser(userp);
5684 else if (code != CM_ERROR_NOSUCHFILE &&
5685 code != CM_ERROR_NOSUCHPATH &&
5686 code != CM_ERROR_BPLUS_NOMATCH)
5688 cm_ReleaseUser(userp);
5692 #endif /* SPECIAL_FOLDERS */
5694 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5695 tidPathp, &req, &newScp);
5697 cm_ReleaseUser(userp);
5702 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5703 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5704 cm_ReleaseSCache(newScp);
5705 cm_ReleaseUser(userp);
5706 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5707 return CM_ERROR_PATH_NOT_COVERED;
5709 return CM_ERROR_NOSUCHPATH;
5711 #endif /* DFS_SUPPORT */
5713 /* now lock the vnode with a callback; returns with newScp locked */
5714 lock_ObtainWrite(&newScp->rw);
5715 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5716 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5718 lock_ReleaseWrite(&newScp->rw);
5719 cm_ReleaseSCache(newScp);
5720 cm_ReleaseUser(userp);
5724 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5726 attrs = smb_Attributes(newScp);
5728 smb_SetSMBParm(outp, 0, attrs);
5730 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5731 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5732 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5733 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5734 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5735 smb_SetSMBParm(outp, 5, 0);
5736 smb_SetSMBParm(outp, 6, 0);
5737 smb_SetSMBParm(outp, 7, 0);
5738 smb_SetSMBParm(outp, 8, 0);
5739 smb_SetSMBParm(outp, 9, 0);
5740 smb_SetSMBDataLength(outp, 0);
5741 lock_ReleaseWrite(&newScp->rw);
5743 cm_ReleaseSCache(newScp);
5744 cm_ReleaseUser(userp);
5749 /* SMB_COM_TREE_DISCONNECT */
5750 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5754 osi_Log0(smb_logp, "SMB receive tree disconnect");
5756 /* find the tree and free it */
5757 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5759 lock_ObtainWrite(&smb_rctLock);
5761 smb_ReleaseTID(tidp, TRUE);
5762 lock_ReleaseWrite(&smb_rctLock);
5769 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5772 clientchar_t *pathp;
5773 clientchar_t *lastNamep;
5782 clientchar_t *tidPathp;
5788 datap = smb_GetSMBData(inp, NULL);
5789 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5791 return CM_ERROR_BADSMB;
5793 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5795 #ifdef DEBUG_VERBOSE
5799 hexpath = osi_HexifyString( pathp );
5800 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5805 share = smb_GetSMBParm(inp, 0);
5806 attribute = smb_GetSMBParm(inp, 1);
5808 spacep = inp->spacep;
5809 /* smb_StripLastComponent will strip "::$DATA" if present */
5810 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5812 if (!cm_IsValidClientString(pathp)) {
5814 clientchar_t * hexp;
5816 hexp = cm_GetRawCharsAlloc(pathp, -1);
5817 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5818 osi_LogSaveClientString(smb_logp, hexp));
5822 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5824 return CM_ERROR_BADNTFILENAME;
5827 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5828 /* special case magic file name for receiving IOCTL requests
5829 * (since IOCTL calls themselves aren't getting through).
5831 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5832 smb_SetupIoctlFid(fidp, spacep);
5833 smb_SetSMBParm(outp, 0, fidp->fid);
5834 smb_SetSMBParm(outp, 1, 0); /* attrs */
5835 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5836 smb_SetSMBParm(outp, 3, 0);
5837 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5838 smb_SetSMBParm(outp, 5, 0x7fff);
5839 /* pass the open mode back */
5840 smb_SetSMBParm(outp, 6, (share & 0xf));
5841 smb_SetSMBDataLength(outp, 0);
5842 smb_ReleaseFID(fidp);
5846 userp = smb_GetUserFromVCP(vcp, inp);
5848 caseFold = CM_FLAG_CASEFOLD;
5850 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5852 cm_ReleaseUser(userp);
5853 return CM_ERROR_NOSUCHPATH;
5855 code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
5856 tidPathp, &req, &scp);
5859 cm_ReleaseUser(userp);
5864 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5865 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5866 cm_ReleaseSCache(scp);
5867 cm_ReleaseUser(userp);
5868 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5869 return CM_ERROR_PATH_NOT_COVERED;
5871 return CM_ERROR_NOSUCHPATH;
5873 #endif /* DFS_SUPPORT */
5875 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5877 cm_ReleaseSCache(scp);
5878 cm_ReleaseUser(userp);
5882 /* don't need callback to check file type, since file types never
5883 * change, and namei and cm_Lookup all stat the object at least once on
5884 * a successful return.
5886 if (scp->fileType != CM_SCACHETYPE_FILE) {
5887 cm_ReleaseSCache(scp);
5888 cm_ReleaseUser(userp);
5889 return CM_ERROR_ISDIR;
5892 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5893 osi_assertx(fidp, "null smb_fid_t");
5895 lock_ObtainMutex(&fidp->mx);
5896 if ((share & 0xf) == 0)
5897 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5898 else if ((share & 0xf) == 1)
5899 fidp->flags |= SMB_FID_OPENWRITE;
5901 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5905 fidp->userp = userp;
5907 /* and a pointer to the vnode */
5909 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5910 lock_ObtainWrite(&scp->rw);
5911 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5913 smb_SetSMBParm(outp, 0, fidp->fid);
5914 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5915 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5916 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5917 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5918 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5919 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5920 /* pass the open mode back; XXXX add access checks */
5921 smb_SetSMBParm(outp, 6, (share & 0xf));
5922 smb_SetSMBDataLength(outp, 0);
5923 lock_ReleaseMutex(&fidp->mx);
5924 lock_ReleaseRead(&scp->rw);
5927 cm_Open(scp, 0, userp);
5929 /* send and free packet */
5930 smb_ReleaseFID(fidp);
5931 cm_ReleaseUser(userp);
5932 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5936 typedef struct smb_unlinkRock {
5941 clientchar_t *maskp; /* pointer to the star pattern */
5944 cm_dirEntryList_t * matches;
5947 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5950 smb_unlinkRock_t *rockp;
5953 normchar_t matchName[MAX_PATH];
5957 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5958 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5959 caseFold |= CM_FLAG_8DOT3;
5961 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5962 /* Can't convert name */
5963 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5964 osi_LogSaveString(smb_logp, dep->name));
5968 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5970 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5972 !cm_Is8Dot3(matchName)) {
5973 cm_Gen8Dot3Name(dep, matchName, NULL);
5974 /* 8.3 matches are always case insensitive */
5975 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5978 osi_Log1(smb_logp, "Found match %S",
5979 osi_LogSaveClientString(smb_logp, matchName));
5981 cm_DirEntryListAdd(dep->name, &rockp->matches);
5985 /* If we made a case sensitive exact match, we might as well quit now. */
5986 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5987 code = CM_ERROR_STOPNOW;
5996 /* SMB_COM_DELETE */
5997 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6001 clientchar_t *pathp;
6005 clientchar_t *lastNamep;
6006 smb_unlinkRock_t rock;
6010 clientchar_t *tidPathp;
6014 memset(&rock, 0, sizeof(rock));
6016 attribute = smb_GetSMBParm(inp, 0);
6018 tp = smb_GetSMBData(inp, NULL);
6019 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6021 return CM_ERROR_BADSMB;
6023 osi_Log1(smb_logp, "SMB receive unlink %S",
6024 osi_LogSaveClientString(smb_logp, pathp));
6026 spacep = inp->spacep;
6027 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6029 userp = smb_GetUserFromVCP(vcp, inp);
6031 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6033 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6035 cm_ReleaseUser(userp);
6036 return CM_ERROR_NOSUCHPATH;
6038 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
6041 cm_ReleaseUser(userp);
6046 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6047 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6048 cm_ReleaseSCache(dscp);
6049 cm_ReleaseUser(userp);
6050 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6051 return CM_ERROR_PATH_NOT_COVERED;
6053 return CM_ERROR_NOSUCHPATH;
6055 #endif /* DFS_SUPPORT */
6057 /* otherwise, scp points to the parent directory. */
6064 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
6066 code = CM_ERROR_NOSUCHFILE;
6069 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6072 thyper.HighPart = 0;
6077 rock.matches = NULL;
6079 /* Now, if we aren't dealing with a wildcard match, we first try an exact
6080 * match. If that fails, we do a case insensitve match.
6082 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6083 !smb_IsStarMask(rock.maskp)) {
6084 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6087 thyper.HighPart = 0;
6088 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6093 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6095 if (code == CM_ERROR_STOPNOW)
6098 if (code == 0 && rock.matches) {
6099 cm_dirEntryList_t * entry;
6101 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6102 normchar_t normalizedName[MAX_PATH];
6104 /* Note: entry->name is a non-normalized name */
6106 osi_Log1(smb_logp, "Unlinking %s",
6107 osi_LogSaveString(smb_logp, entry->name));
6109 /* We assume this works because entry->name was
6110 successfully converted in smb_UnlinkProc() once. */
6111 cm_FsStringToNormString(entry->name, -1,
6112 normalizedName, lengthof(normalizedName));
6114 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6116 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6117 smb_NotifyChange(FILE_ACTION_REMOVED,
6118 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6119 dscp, normalizedName, NULL, TRUE);
6123 cm_DirEntryListFree(&rock.matches);
6127 cm_ReleaseUser(userp);
6130 cm_ReleaseSCache(dscp);
6135 if (code == 0 && !rock.any)
6136 code = CM_ERROR_NOSUCHFILE;
6140 typedef struct smb_renameRock {
6141 cm_scache_t *odscp; /* old dir */
6142 cm_scache_t *ndscp; /* new dir */
6143 cm_user_t *userp; /* user */
6144 cm_req_t *reqp; /* request struct */
6145 smb_vc_t *vcp; /* virtual circuit */
6146 normchar_t *maskp; /* pointer to star pattern of old file name */
6147 int flags; /* tilde, casefold, etc */
6148 clientchar_t *newNamep; /* ptr to the new file's name */
6149 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6150 clientchar_t clOldName[MAX_PATH]; /* client name */
6154 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6157 smb_renameRock_t *rockp;
6160 normchar_t matchName[MAX_PATH];
6162 rockp = (smb_renameRock_t *) vrockp;
6164 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6165 /* Can't convert string */
6166 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6167 osi_LogSaveString(smb_logp, dep->name));
6171 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6172 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6173 caseFold |= CM_FLAG_8DOT3;
6175 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6177 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6179 !cm_Is8Dot3(matchName)) {
6180 cm_Gen8Dot3Name(dep, matchName, NULL);
6181 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6186 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6187 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6189 code = CM_ERROR_STOPNOW;
6199 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6202 cm_space_t *spacep = NULL;
6203 smb_renameRock_t rock;
6204 cm_scache_t *oldDscp = NULL;
6205 cm_scache_t *newDscp = NULL;
6206 cm_scache_t *tmpscp= NULL;
6207 cm_scache_t *tmpscp2 = NULL;
6208 clientchar_t *oldLastNamep;
6209 clientchar_t *newLastNamep;
6213 clientchar_t *tidPathp;
6217 userp = smb_GetUserFromVCP(vcp, inp);
6218 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6220 cm_ReleaseUser(userp);
6221 return CM_ERROR_NOSUCHPATH;
6225 memset(&rock, 0, sizeof(rock));
6227 spacep = inp->spacep;
6228 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6230 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6231 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6232 userp, tidPathp, &req, &oldDscp);
6234 cm_ReleaseUser(userp);
6239 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6240 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6241 cm_ReleaseSCache(oldDscp);
6242 cm_ReleaseUser(userp);
6243 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6244 return CM_ERROR_PATH_NOT_COVERED;
6246 return CM_ERROR_NOSUCHPATH;
6248 #endif /* DFS_SUPPORT */
6250 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6251 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6252 userp, tidPathp, &req, &newDscp);
6255 cm_ReleaseSCache(oldDscp);
6256 cm_ReleaseUser(userp);
6261 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6262 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6263 cm_ReleaseSCache(oldDscp);
6264 cm_ReleaseSCache(newDscp);
6265 cm_ReleaseUser(userp);
6266 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6267 return CM_ERROR_PATH_NOT_COVERED;
6269 return CM_ERROR_NOSUCHPATH;
6271 #endif /* DFS_SUPPORT */
6274 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6275 * next, get the component names, and lower case them.
6278 /* handle the old name first */
6280 oldLastNamep = oldPathp;
6284 /* and handle the new name, too */
6286 newLastNamep = newPathp;
6290 /* TODO: The old name could be a wildcard. The new name must not be */
6292 /* Check if the file already exists; if so return error */
6293 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6294 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6295 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6297 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6298 osi_LogSaveClientString(smb_logp, newLastNamep));
6300 /* Check if the old and the new names differ only in case. If so return
6301 * success, else return CM_ERROR_EXISTS
6303 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6305 /* This would be a success only if the old file is *as same as* the new file */
6306 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6308 if (tmpscp == tmpscp2)
6311 code = CM_ERROR_EXISTS;
6312 cm_ReleaseSCache(tmpscp2);
6315 code = CM_ERROR_NOSUCHFILE;
6318 /* file exist, do not rename, also fixes move */
6319 osi_Log0(smb_logp, "Can't rename. Target already exists");
6320 code = CM_ERROR_EXISTS;
6325 /* do the vnode call */
6326 rock.odscp = oldDscp;
6327 rock.ndscp = newDscp;
6331 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6333 code = CM_ERROR_NOSUCHFILE;
6336 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6337 rock.newNamep = newLastNamep;
6338 rock.fsOldName[0] = '\0';
6339 rock.clOldName[0] = '\0';
6342 /* Now search the directory for the pattern, and do the appropriate rename when found */
6343 thyper.LowPart = 0; /* search dir from here */
6344 thyper.HighPart = 0;
6346 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6347 if (code == 0 && !rock.any) {
6349 thyper.HighPart = 0;
6350 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6351 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6353 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6355 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6356 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6357 rock.ndscp, rock.newNamep, rock.userp,
6359 /* if the call worked, stop doing the search now, since we
6360 * really only want to rename one file.
6363 osi_Log0(smb_logp, "cm_Rename failure");
6364 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6365 } else if (code == 0) {
6366 code = CM_ERROR_NOSUCHFILE;
6369 /* Handle Change Notification */
6371 * Being lazy, not distinguishing between files and dirs in this
6372 * filter, since we'd have to do a lookup.
6375 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6376 if (oldDscp == newDscp) {
6377 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6378 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6379 filter, oldDscp, rock.clOldName,
6380 newLastNamep, TRUE);
6382 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6383 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6384 filter, oldDscp, rock.clOldName,
6386 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6387 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6388 filter, newDscp, newLastNamep,
6395 cm_ReleaseSCache(tmpscp);
6397 cm_ReleaseUser(userp);
6399 cm_ReleaseSCache(oldDscp);
6401 cm_ReleaseSCache(newDscp);
6409 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6412 cm_space_t *spacep = NULL;
6413 cm_scache_t *oldDscp = NULL;
6414 cm_scache_t *newDscp = NULL;
6415 cm_scache_t *tmpscp= NULL;
6416 cm_scache_t *tmpscp2 = NULL;
6417 cm_scache_t *sscp = NULL;
6418 clientchar_t *oldLastNamep;
6419 clientchar_t *newLastNamep;
6422 clientchar_t *tidPathp;
6426 userp = smb_GetUserFromVCP(vcp, inp);
6428 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6430 cm_ReleaseUser(userp);
6431 return CM_ERROR_NOSUCHPATH;
6436 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6438 spacep = inp->spacep;
6439 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6441 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6442 userp, tidPathp, &req, &oldDscp);
6444 cm_ReleaseUser(userp);
6449 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6450 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6451 cm_ReleaseSCache(oldDscp);
6452 cm_ReleaseUser(userp);
6453 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6454 return CM_ERROR_PATH_NOT_COVERED;
6456 return CM_ERROR_NOSUCHPATH;
6458 #endif /* DFS_SUPPORT */
6460 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6461 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6462 userp, tidPathp, &req, &newDscp);
6464 cm_ReleaseSCache(oldDscp);
6465 cm_ReleaseUser(userp);
6470 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6471 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6472 cm_ReleaseSCache(newDscp);
6473 cm_ReleaseSCache(oldDscp);
6474 cm_ReleaseUser(userp);
6475 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6476 return CM_ERROR_PATH_NOT_COVERED;
6478 return CM_ERROR_NOSUCHPATH;
6480 #endif /* DFS_SUPPORT */
6482 /* Now, although we did two lookups for the two directories (because the same
6483 * directory can be referenced through different paths), we only allow hard links
6484 * within the same directory. */
6485 if (oldDscp != newDscp) {
6486 cm_ReleaseSCache(oldDscp);
6487 cm_ReleaseSCache(newDscp);
6488 cm_ReleaseUser(userp);
6489 return CM_ERROR_CROSSDEVLINK;
6492 /* handle the old name first */
6494 oldLastNamep = oldPathp;
6498 /* and handle the new name, too */
6500 newLastNamep = newPathp;
6504 /* now lookup the old name */
6505 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6506 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6508 cm_ReleaseSCache(oldDscp);
6509 cm_ReleaseSCache(newDscp);
6510 cm_ReleaseUser(userp);
6514 /* Check if the file already exists; if so return error */
6515 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6516 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6517 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6519 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6520 osi_LogSaveClientString(smb_logp, newLastNamep));
6522 /* if the existing link is to the same file, then we return success */
6524 if(sscp == tmpscp) {
6527 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6528 code = CM_ERROR_EXISTS;
6533 cm_ReleaseSCache(tmpscp);
6534 cm_ReleaseSCache(sscp);
6535 cm_ReleaseSCache(newDscp);
6536 cm_ReleaseSCache(oldDscp);
6537 cm_ReleaseUser(userp);
6541 /* now create the hardlink */
6542 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6543 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6544 osi_Log1(smb_logp," Link returns 0x%x", code);
6546 /* Handle Change Notification */
6548 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6549 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6550 smb_NotifyChange(FILE_ACTION_ADDED,
6551 filter, newDscp, newLastNamep,
6556 cm_ReleaseSCache(tmpscp);
6557 cm_ReleaseUser(userp);
6558 cm_ReleaseSCache(sscp);
6559 cm_ReleaseSCache(oldDscp);
6560 cm_ReleaseSCache(newDscp);
6564 /* SMB_COM_RENAME */
6566 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6568 clientchar_t *oldPathp;
6569 clientchar_t *newPathp;
6573 tp = smb_GetSMBData(inp, NULL);
6574 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6576 return CM_ERROR_BADSMB;
6577 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6579 return CM_ERROR_BADSMB;
6581 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6582 osi_LogSaveClientString(smb_logp, oldPathp),
6583 osi_LogSaveClientString(smb_logp, newPathp));
6585 if (!cm_IsValidClientString(newPathp)) {
6587 clientchar_t * hexp;
6589 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6590 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6591 osi_LogSaveClientString(smb_logp, hexp));
6595 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6597 return CM_ERROR_BADNTFILENAME;
6600 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6602 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6608 typedef struct smb_rmdirRock {
6612 normchar_t *maskp; /* pointer to the star pattern */
6615 cm_dirEntryList_t * matches;
6618 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6621 smb_rmdirRock_t *rockp;
6623 normchar_t matchName[MAX_PATH];
6625 rockp = (smb_rmdirRock_t *) vrockp;
6627 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6628 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6629 osi_LogSaveString(smb_logp, dep->name));
6633 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6634 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6636 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6638 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6640 !cm_Is8Dot3(matchName)) {
6641 cm_Gen8Dot3Name(dep, matchName, NULL);
6642 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6647 cm_DirEntryListAdd(dep->name, &rockp->matches);
6654 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6657 clientchar_t *pathp;
6661 clientchar_t *lastNamep;
6662 smb_rmdirRock_t rock;
6666 clientchar_t *tidPathp;
6670 memset(&rock, 0, sizeof(rock));
6672 tp = smb_GetSMBData(inp, NULL);
6673 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6675 return CM_ERROR_BADSMB;
6677 spacep = inp->spacep;
6678 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6680 userp = smb_GetUserFromVCP(vcp, inp);
6682 caseFold = CM_FLAG_CASEFOLD;
6684 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6686 cm_ReleaseUser(userp);
6687 return CM_ERROR_NOSUCHPATH;
6689 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6690 userp, tidPathp, &req, &dscp);
6693 cm_ReleaseUser(userp);
6698 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6699 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6700 cm_ReleaseSCache(dscp);
6701 cm_ReleaseUser(userp);
6702 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6703 return CM_ERROR_PATH_NOT_COVERED;
6705 return CM_ERROR_NOSUCHPATH;
6707 #endif /* DFS_SUPPORT */
6709 /* otherwise, scp points to the parent directory. */
6716 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6718 code = CM_ERROR_NOSUCHFILE;
6721 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6724 thyper.HighPart = 0;
6728 rock.matches = NULL;
6730 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6731 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6732 if (code == 0 && !rock.any) {
6734 thyper.HighPart = 0;
6735 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6736 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6739 if (code == 0 && rock.matches) {
6740 cm_dirEntryList_t * entry;
6742 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6743 clientchar_t clientName[MAX_PATH];
6745 /* We assume this will succeed because smb_RmdirProc()
6746 successfully converted entry->name once above. */
6747 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6749 osi_Log1(smb_logp, "Removing directory %s",
6750 osi_LogSaveString(smb_logp, entry->name));
6752 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6754 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6755 smb_NotifyChange(FILE_ACTION_REMOVED,
6756 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6757 dscp, clientName, NULL, TRUE);
6763 cm_DirEntryListFree(&rock.matches);
6766 cm_ReleaseUser(userp);
6769 cm_ReleaseSCache(dscp);
6771 if (code == 0 && !rock.any)
6772 code = CM_ERROR_NOSUCHFILE;
6781 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6791 fid = smb_GetSMBParm(inp, 0);
6793 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6795 fid = smb_ChainFID(fid, inp);
6796 fidp = smb_FindFID(vcp, fid, 0);
6798 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6800 return CM_ERROR_BADFD;
6802 userp = smb_GetUserFromVCP(vcp, inp);
6804 lock_ObtainMutex(&fidp->mx);
6805 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6806 cm_ReleaseUser(userp);
6807 lock_ReleaseMutex(&fidp->mx);
6808 smb_ReleaseFID(fidp);
6809 return CM_ERROR_BADFD;
6812 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6813 lock_ReleaseMutex(&fidp->mx);
6814 cm_ReleaseUser(userp);
6815 smb_CloseFID(vcp, fidp, NULL, 0);
6816 smb_ReleaseFID(fidp);
6817 return CM_ERROR_NOSUCHFILE;
6820 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6821 cm_scache_t * scp = fidp->scp;
6823 lock_ReleaseMutex(&fidp->mx);
6824 code = cm_FSync(scp, userp, &req, FALSE);
6825 cm_ReleaseSCache(scp);
6827 lock_ReleaseMutex(&fidp->mx);
6831 cm_ReleaseUser(userp);
6832 smb_ReleaseFID(fidp);
6836 struct smb_FullNameRock {
6839 clientchar_t *fullName;
6840 fschar_t *originalName;
6843 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6846 normchar_t matchName[MAX_PATH];
6847 struct smb_FullNameRock *vrockp;
6849 vrockp = (struct smb_FullNameRock *)rockp;
6851 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6852 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6853 osi_LogSaveString(smb_logp, dep->name));
6857 if (cm_shortNames && !cm_Is8Dot3(matchName)) {
6858 clientchar_t shortName[13];
6860 cm_Gen8Dot3Name(dep, shortName, NULL);
6862 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6863 vrockp->fullName = cm_ClientStrDup(matchName);
6864 vrockp->originalName = cm_FsStrDup(dep->name);
6865 return CM_ERROR_STOPNOW;
6868 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6869 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6870 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6871 vrockp->fullName = cm_ClientStrDup(matchName);
6872 vrockp->originalName = cm_FsStrDup(dep->name);
6873 return CM_ERROR_STOPNOW;
6878 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6879 clientchar_t **newPathp, fschar_t ** originalPathp,
6880 cm_user_t *userp, cm_req_t *reqp)
6882 struct smb_FullNameRock rock;
6885 memset(&rock, 0, sizeof(rock));
6889 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6890 if (code == CM_ERROR_STOPNOW) {
6891 *newPathp = rock.fullName;
6892 *originalPathp = rock.originalName;
6894 *newPathp = cm_ClientStrDup(pathp);
6895 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6899 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6900 afs_uint32 dosTime) {
6903 cm_scache_t *dscp = NULL;
6904 clientchar_t *pathp = NULL;
6905 cm_scache_t * scp = NULL;
6906 cm_scache_t *delscp = NULL;
6907 int nullcreator = 0;
6909 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6910 fidp, fidp->fid, scp, vcp);
6913 lock_ObtainMutex(&fidp->mx);
6914 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6916 lock_ReleaseMutex(&fidp->mx);
6917 osi_Log0(smb_logp, " No user specified. Not closing fid");
6918 return CM_ERROR_BADFD;
6921 userp = fidp->userp; /* no hold required since fidp is held
6922 throughout the function */
6923 lock_ReleaseMutex(&fidp->mx);
6928 lock_ObtainWrite(&smb_rctLock);
6929 if (fidp->deleteOk) {
6930 osi_Log0(smb_logp, " Fid already closed.");
6931 lock_ReleaseWrite(&smb_rctLock);
6932 return CM_ERROR_BADFD;
6935 lock_ReleaseWrite(&smb_rctLock);
6937 lock_ObtainMutex(&fidp->mx);
6938 if (fidp->NTopen_dscp) {
6939 dscp = fidp->NTopen_dscp;
6940 cm_HoldSCache(dscp);
6943 if (fidp->NTopen_pathp)
6944 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6951 /* Don't jump the gun on an async raw write */
6952 while (fidp->raw_writers) {
6953 lock_ReleaseMutex(&fidp->mx);
6954 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6955 lock_ObtainMutex(&fidp->mx);
6958 /* watch for ioctl closes, and read-only opens */
6960 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6961 == SMB_FID_OPENWRITE) {
6962 if (dosTime != 0 && dosTime != -1) {
6963 lock_ObtainWrite(&fidp->scp->rw);
6964 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6965 /* This fixes defect 10958 */
6966 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6967 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6968 lock_ReleaseWrite(&fidp->scp->rw);
6970 if (smb_AsyncStore != 2) {
6971 lock_ReleaseMutex(&fidp->mx);
6972 code = cm_FSync(scp, userp, &req, FALSE);
6973 lock_ObtainMutex(&fidp->mx);
6979 /* unlock any pending locks */
6980 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6981 scp->fileType == CM_SCACHETYPE_FILE) {
6985 lock_ReleaseMutex(&fidp->mx);
6988 * CM_UNLOCK_FLAG_BY_FID doesn't look at the process ID.
6991 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6992 lock_ObtainWrite(&scp->rw);
6994 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6995 CM_SCACHESYNC_NEEDCALLBACK
6996 | CM_SCACHESYNC_GETSTATUS
6997 | CM_SCACHESYNC_LOCK);
7001 "smb CoreClose SyncOp failure code 0x%x", tcode);
7002 goto post_syncopdone;
7005 cm_UnlockByKey(scp, key, CM_UNLOCK_FLAG_BY_FID, userp, &req);
7007 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
7011 lock_ReleaseWrite(&scp->rw);
7012 lock_ObtainMutex(&fidp->mx);
7015 if (fidp->flags & SMB_FID_DELONCLOSE) {
7016 clientchar_t *fullPathp = NULL;
7017 fschar_t *originalNamep = NULL;
7019 lock_ReleaseMutex(&fidp->mx);
7021 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
7026 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
7027 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
7028 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
7030 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7031 smb_NotifyChange(FILE_ACTION_REMOVED,
7032 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
7033 dscp, fullPathp, NULL, TRUE);
7036 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
7038 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7039 smb_NotifyChange(FILE_ACTION_REMOVED,
7040 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7041 dscp, fullPathp, NULL, TRUE);
7048 free(originalNamep);
7050 lock_ObtainMutex(&fidp->mx);
7051 fidp->flags &= ~SMB_FID_DELONCLOSE;
7054 /* if this was a newly created file, then clear the creator
7055 * in the stat cache entry. */
7056 if (fidp->flags & SMB_FID_CREATED) {
7058 fidp->flags &= ~SMB_FID_CREATED;
7061 if (fidp->flags & SMB_FID_NTOPEN) {
7062 cm_ReleaseSCache(fidp->NTopen_dscp);
7063 fidp->NTopen_dscp = NULL;
7064 free(fidp->NTopen_pathp);
7065 fidp->NTopen_pathp = NULL;
7066 fidp->flags &= ~SMB_FID_NTOPEN;
7068 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
7069 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7072 if (fidp->NTopen_wholepathp) {
7073 free(fidp->NTopen_wholepathp);
7074 fidp->NTopen_wholepathp = NULL;
7078 cm_ReleaseSCache(fidp->scp);
7081 lock_ReleaseMutex(&fidp->mx);
7084 cm_ReleaseSCache(dscp);
7087 cm_ReleaseSCache(delscp);
7091 lock_ObtainWrite(&scp->rw);
7092 if (nullcreator && scp->creator == userp)
7093 scp->creator = NULL;
7094 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7095 lock_ReleaseWrite(&scp->rw);
7096 cm_ReleaseSCache(scp);
7106 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7114 fid = smb_GetSMBParm(inp, 0);
7115 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7117 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7119 fid = smb_ChainFID(fid, inp);
7120 fidp = smb_FindFID(vcp, fid, 0);
7122 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
7124 return CM_ERROR_BADFD;
7127 userp = smb_GetUserFromVCP(vcp, inp);
7129 code = smb_CloseFID(vcp, fidp, userp, dosTime);
7131 smb_ReleaseFID(fidp);
7132 cm_ReleaseUser(userp);
7137 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7139 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7140 cm_user_t *userp, long *readp)
7146 osi_hyper_t fileLength;
7148 osi_hyper_t lastByte;
7149 osi_hyper_t bufferOffset;
7153 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7156 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7157 fidp->fid, offsetp->LowPart, count);
7161 lock_ObtainMutex(&fidp->mx);
7162 /* make sure we have a readable FD */
7163 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7164 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7165 fidp->fid, fidp->flags);
7166 lock_ReleaseMutex(&fidp->mx);
7167 code = CM_ERROR_BADFDOP;
7172 lock_ReleaseMutex(&fidp->mx);
7173 code = CM_ERROR_BADFD;
7184 lock_ObtainWrite(&scp->rw);
7186 if (offset.HighPart == 0) {
7187 chunk = offset.LowPart >> cm_logChunkSize;
7188 if (chunk != fidp->curr_chunk) {
7189 fidp->prev_chunk = fidp->curr_chunk;
7190 fidp->curr_chunk = chunk;
7192 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7195 lock_ReleaseMutex(&fidp->mx);
7197 /* start by looking up the file's end */
7198 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7199 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7203 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7205 /* now we have the entry locked, look up the length */
7206 fileLength = scp->length;
7208 /* adjust count down so that it won't go past EOF */
7209 thyper.LowPart = count;
7210 thyper.HighPart = 0;
7211 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7213 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7214 /* we'd read past EOF, so just stop at fileLength bytes.
7215 * Start by computing how many bytes remain in the file.
7217 thyper = LargeIntegerSubtract(fileLength, offset);
7219 /* if we are past EOF, read 0 bytes */
7220 if (LargeIntegerLessThanZero(thyper))
7223 count = thyper.LowPart;
7228 /* now, copy the data one buffer at a time,
7229 * until we've filled the request packet
7232 /* if we've copied all the data requested, we're done */
7233 if (count <= 0) break;
7235 /* otherwise, load up a buffer of data */
7236 thyper.HighPart = offset.HighPart;
7237 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7238 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7241 buf_Release(bufferp);
7244 lock_ReleaseWrite(&scp->rw);
7246 code = buf_Get(scp, &thyper, &req, 0, &bufferp);
7248 lock_ObtainWrite(&scp->rw);
7249 if (code) goto done;
7250 bufferOffset = thyper;
7252 /* now get the data in the cache */
7254 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7255 CM_SCACHESYNC_NEEDCALLBACK |
7256 CM_SCACHESYNC_READ);
7260 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7262 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7264 /* otherwise, load the buffer and try again */
7265 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7269 buf_Release(bufferp);
7273 } /* if (wrong buffer) ... */
7275 /* now we have the right buffer loaded. Copy out the
7276 * data from here to the user's buffer.
7278 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7280 /* and figure out how many bytes we want from this buffer */
7281 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7282 if (nbytes > count) nbytes = count; /* don't go past EOF */
7284 /* now copy the data */
7285 memcpy(op, bufferp->datap + bufIndex, nbytes);
7287 /* adjust counters, pointers, etc. */
7290 thyper.LowPart = nbytes;
7291 thyper.HighPart = 0;
7292 offset = LargeIntegerAdd(thyper, offset);
7296 lock_ReleaseWrite(&scp->rw);
7298 buf_Release(bufferp);
7300 if (code == 0 && sequential)
7301 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7303 cm_ReleaseSCache(scp);
7306 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7307 fidp->fid, code, *readp);
7312 * smb_WriteData -- common code for Write and Raw Write
7314 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7315 cm_user_t *userp, long *writtenp)
7317 osi_hyper_t offset = *offsetp;
7320 cm_scache_t *scp = NULL;
7321 osi_hyper_t fileLength; /* file's length at start of write */
7322 osi_hyper_t minLength; /* don't read past this */
7323 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7324 cm_buf_t *bufferp = NULL;
7325 osi_hyper_t thyper; /* hyper tmp variable */
7326 osi_hyper_t bufferOffset;
7327 afs_uint32 bufIndex; /* index in buffer where our data is */
7328 int doWriteBack = 0;
7329 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7332 int needSyncOpDone = 0;
7334 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7335 fidp->fid, offsetp->LowPart, count);
7339 lock_ObtainMutex(&fidp->mx);
7340 /* make sure we have a writable FD */
7341 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7342 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7343 fidp->fid, fidp->flags);
7344 lock_ReleaseMutex(&fidp->mx);
7345 code = CM_ERROR_BADFDOP;
7353 lock_ReleaseMutex(&fidp->mx);
7355 lock_ObtainWrite(&scp->rw);
7356 /* start by looking up the file's end */
7357 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7358 CM_SCACHESYNC_NEEDCALLBACK
7359 | CM_SCACHESYNC_SETSTATUS
7360 | CM_SCACHESYNC_GETSTATUS);
7364 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7366 /* now we have the entry locked, look up the length */
7367 fileLength = scp->length;
7368 minLength = fileLength;
7369 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7370 minLength = scp->serverLength;
7372 /* adjust file length if we extend past EOF */
7373 thyper.LowPart = count;
7374 thyper.HighPart = 0;
7375 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7376 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7377 /* we'd write past EOF, so extend the file */
7378 scp->mask |= CM_SCACHEMASK_LENGTH;
7379 scp->length = thyper;
7380 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7382 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7384 /* now, if the new position (thyper) and the old (offset) are in
7385 * different storeback windows, remember to store back the previous
7386 * storeback window when we're done with the write.
7388 * the purpose of this logic is to slow down the CIFS client
7389 * in order to avoid the client disconnecting during the CLOSE
7390 * operation if there are too many dirty buffers left to write
7391 * than can be accomplished during 45 seconds. This used to be
7392 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7393 * so that we can read larger amounts of data at a time.
7395 if (smb_AsyncStore == 1 &&
7396 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7397 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7398 /* they're different */
7400 writeBackOffset.HighPart = offset.HighPart;
7401 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7406 /* now, copy the data one buffer at a time, until we've filled the
7408 while (count != 0) {
7410 /* handle over quota or out of space */
7411 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7412 *writtenp = written;
7413 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7417 /* otherwise, load up a buffer of data */
7418 thyper.HighPart = offset.HighPart;
7419 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7420 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7423 if (needSyncOpDone) {
7424 cm_SyncOpDone(scp, bufferp,
7425 CM_SCACHESYNC_NEEDCALLBACK
7426 | CM_SCACHESYNC_WRITE
7427 | CM_SCACHESYNC_BUFLOCKED);
7430 lock_ReleaseMutex(&bufferp->mx);
7431 buf_Release(bufferp);
7434 lock_ReleaseWrite(&scp->rw);
7436 code = buf_Get(scp, &thyper, &req, 0, &bufferp);
7438 lock_ObtainMutex(&bufferp->mx);
7439 lock_ObtainWrite(&scp->rw);
7440 if (code) goto done;
7442 bufferOffset = thyper;
7444 /* now get the data in the cache */
7446 if (!needSyncOpDone) {
7447 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7448 CM_SCACHESYNC_NEEDCALLBACK
7449 | CM_SCACHESYNC_WRITE
7450 | CM_SCACHESYNC_BUFLOCKED);
7457 /* If we're overwriting the entire buffer, or
7458 * if we're writing at or past EOF, mark the
7459 * buffer as current so we don't call
7460 * cm_GetBuffer. This skips the fetch from the
7461 * server in those cases where we're going to
7462 * obliterate all the data in the buffer anyway,
7463 * or in those cases where there is no useful
7464 * data at the server to start with.
7466 * Use minLength instead of scp->length, since
7467 * the latter has already been updated by this
7470 * The scp lock has been dropped multiple times
7471 * so the minLength must be refreshed before it
7475 minLength = scp->length;
7476 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7477 minLength = scp->serverLength;
7479 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7480 || LargeIntegerEqualTo(offset, bufferp->offset)
7481 && (count >= cm_data.buf_blockSize
7482 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7483 ConvertLongToLargeInteger(count)),
7485 if (count < cm_data.buf_blockSize
7486 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7487 memset(bufferp->datap, 0,
7488 cm_data.buf_blockSize);
7489 bufferp->dataVersion = scp->dataVersion;
7492 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7494 /* otherwise, load the buffer and try again */
7495 cm_SyncOpDone(scp, bufferp,
7496 CM_SCACHESYNC_NEEDCALLBACK
7497 | CM_SCACHESYNC_WRITE
7498 | CM_SCACHESYNC_BUFLOCKED);
7501 lock_ReleaseMutex(&bufferp->mx);
7502 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7504 lock_ReleaseWrite(&scp->rw);
7505 lock_ObtainMutex(&bufferp->mx);
7506 lock_ObtainWrite(&scp->rw);
7510 } /* if (wrong buffer) ... */
7512 /* now we have the right buffer loaded. Copy out the
7513 * data from here to the user's buffer.
7515 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7517 /* and figure out how many bytes we want from this buffer */
7518 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7520 nbytes = count; /* don't go past end of request */
7522 /* now copy the data */
7523 memcpy(bufferp->datap + bufIndex, op, nbytes);
7524 buf_SetDirty(bufferp, &req, bufIndex, nbytes, userp);
7526 /* adjust counters, pointers, etc. */
7530 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7531 } /* while count != 0 */
7534 if (bufferp && needSyncOpDone) {
7535 cm_SyncOpDone(scp, bufferp,
7536 CM_SCACHESYNC_NEEDCALLBACK
7537 | CM_SCACHESYNC_WRITE
7538 | CM_SCACHESYNC_BUFLOCKED);
7541 lock_ReleaseWrite(&scp->rw);
7544 lock_ReleaseMutex(&bufferp->mx);
7545 buf_Release(bufferp);
7548 lock_ObtainMutex(&fidp->mx);
7549 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7550 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7552 lock_ReleaseMutex(&fidp->mx);
7553 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7554 fidp->NTopen_dscp, fidp->NTopen_pathp,
7557 lock_ReleaseMutex(&fidp->mx);
7561 if (smb_AsyncStore > 0) {
7564 rock_BkgStore_t *rockp = malloc(sizeof(*rockp));
7567 lock_ObtainWrite(&scp->rw);
7568 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7570 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7571 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7573 lock_ReleaseWrite(&scp->rw);
7575 rockp->length = smb_AsyncStoreSize;
7576 rockp->offset = writeBackOffset;
7578 cm_QueueBKGRequest(scp, cm_BkgStore, rockp, userp, &req);
7579 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7580 /* rock is freed by cm_BkgDaemon */
7587 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7591 cm_ReleaseSCache(scp);
7594 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7595 fidp->fid, code, *writtenp);
7600 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7603 unsigned short count;
7605 unsigned short hint;
7606 long written = 0, total_written = 0;
7609 smb_t* smbp = (smb_t*) inp;
7613 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7615 int inDataBlockCount;
7617 fd = smb_GetSMBParm(inp, 0);
7618 count = smb_GetSMBParm(inp, 1);
7619 offset.HighPart = 0; /* too bad */
7620 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7621 hint = smb_GetSMBParm(inp, 4);
7623 op = smb_GetSMBData(inp, NULL);
7624 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7626 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7627 fd, offset.LowPart, count);
7629 fd = smb_ChainFID(fd, inp);
7630 fidp = smb_FindFID(vcp, fd, 0);
7632 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7634 return CM_ERROR_BADFD;
7637 lock_ObtainMutex(&fidp->mx);
7638 if (fidp->flags & SMB_FID_IOCTL) {
7639 lock_ReleaseMutex(&fidp->mx);
7640 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7641 smb_ReleaseFID(fidp);
7642 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7646 if (fidp->flags & SMB_FID_RPC) {
7647 lock_ReleaseMutex(&fidp->mx);
7648 code = smb_RPCWrite(fidp, vcp, inp, outp);
7649 smb_ReleaseFID(fidp);
7650 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7655 lock_ReleaseMutex(&fidp->mx);
7656 smb_ReleaseFID(fidp);
7657 return CM_ERROR_BADFD;
7660 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7661 lock_ReleaseMutex(&fidp->mx);
7662 smb_CloseFID(vcp, fidp, NULL, 0);
7663 smb_ReleaseFID(fidp);
7664 return CM_ERROR_NOSUCHFILE;
7669 lock_ReleaseMutex(&fidp->mx);
7670 userp = smb_GetUserFromVCP(vcp, inp);
7674 LARGE_INTEGER LOffset;
7675 LARGE_INTEGER LLength;
7678 key = cm_GenerateKey(vcp->vcID, pid, fd);
7680 LOffset.HighPart = offset.HighPart;
7681 LOffset.LowPart = offset.LowPart;
7682 LLength.HighPart = 0;
7683 LLength.LowPart = count;
7685 lock_ObtainWrite(&scp->rw);
7686 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7687 lock_ReleaseWrite(&scp->rw);
7690 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7695 /* special case: 0 bytes transferred means truncate to this position */
7699 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7703 truncAttr.mask = CM_ATTRMASK_LENGTH;
7704 truncAttr.length.LowPart = offset.LowPart;
7705 truncAttr.length.HighPart = 0;
7706 lock_ObtainMutex(&fidp->mx);
7707 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7708 fidp->flags |= SMB_FID_LENGTHSETDONE;
7709 lock_ReleaseMutex(&fidp->mx);
7710 smb_SetSMBParm(outp, 0, 0 /* count */);
7711 smb_SetSMBDataLength(outp, 0);
7716 * Work around bug in NT client
7718 * When copying a file, the NT client should first copy the data,
7719 * then copy the last write time. But sometimes the NT client does
7720 * these in the wrong order, so the data copies would inadvertently
7721 * cause the last write time to be overwritten. We try to detect this,
7722 * and don't set client mod time if we think that would go against the
7725 lock_ObtainMutex(&fidp->mx);
7726 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7727 lock_ObtainWrite(&fidp->scp->rw);
7728 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7729 fidp->scp->clientModTime = time(NULL);
7730 lock_ReleaseWrite(&fidp->scp->rw);
7732 lock_ReleaseMutex(&fidp->mx);
7735 while ( code == 0 && count > 0 ) {
7736 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7737 if (code == 0 && written == 0)
7738 code = CM_ERROR_PARTIALWRITE;
7740 offset = LargeIntegerAdd(offset,
7741 ConvertLongToLargeInteger(written));
7742 count -= (unsigned short)written;
7743 total_written += written;
7747 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7748 total_written, code);
7750 /* set the packet data length to 3 bytes for the data block header,
7751 * plus the size of the data.
7753 smb_SetSMBParm(outp, 0, total_written);
7754 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7755 smb_SetSMBParm(outp, 3, hint);
7756 smb_SetSMBDataLength(outp, 0);
7759 smb_ReleaseFID(fidp);
7760 cm_ReleaseUser(userp);
7761 cm_ReleaseSCache(scp);
7766 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7767 NCB *ncbp, raw_write_cont_t *rwcp)
7776 fd = smb_GetSMBParm(inp, 0);
7777 fidp = smb_FindFID(vcp, fd, 0);
7779 lock_ObtainMutex(&fidp->mx);
7781 lock_ReleaseMutex(&fidp->mx);
7782 smb_ReleaseFID(fidp);
7786 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7787 lock_ReleaseMutex(&fidp->mx);
7788 smb_CloseFID(vcp, fidp, NULL, 0);
7789 smb_ReleaseFID(fidp);
7792 lock_ReleaseMutex(&fidp->mx);
7794 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7795 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7797 userp = smb_GetUserFromVCP(vcp, inp);
7800 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7802 if (rwcp->writeMode & 0x1) { /* synchronous */
7805 smb_FormatResponsePacket(vcp, inp, outp);
7806 op = (smb_t *) outp;
7807 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7808 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7809 smb_SetSMBDataLength(outp, 0);
7810 smb_SendPacket(vcp, outp);
7811 smb_FreePacket(outp);
7813 else { /* asynchronous */
7814 lock_ObtainMutex(&fidp->mx);
7815 fidp->raw_writers--;
7816 if (fidp->raw_writers == 0)
7817 thrd_SetEvent(fidp->raw_write_event);
7818 lock_ReleaseMutex(&fidp->mx);
7821 /* Give back raw buffer */
7822 lock_ObtainMutex(&smb_RawBufLock);
7823 *((char **)rawBuf) = smb_RawBufs;
7824 smb_RawBufs = rawBuf;
7825 lock_ReleaseMutex(&smb_RawBufLock);
7827 smb_ReleaseFID(fidp);
7828 cm_ReleaseUser(userp);
7831 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7836 /* SMB_COM_WRITE_RAW */
7837 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7840 long count, written = 0, total_written = 0;
7844 smb_t *smbp = (smb_t*) inp;
7849 unsigned short writeMode;
7851 fd = smb_GetSMBParm(inp, 0);
7852 totalCount = smb_GetSMBParm(inp, 1);
7853 count = smb_GetSMBParm(inp, 10);
7854 writeMode = smb_GetSMBParm(inp, 7);
7856 op = (char *) inp->data;
7857 op += smb_GetSMBParm(inp, 11);
7859 offset.HighPart = 0;
7860 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7862 if (*inp->wctp == 14) {
7863 /* we received a 64-bit file offset */
7864 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7866 if (LargeIntegerLessThanZero(offset)) {
7868 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7869 offset.HighPart, offset.LowPart);
7870 return CM_ERROR_BADSMB;
7873 offset.HighPart = 0; /* 32-bit file offset */
7877 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7878 fd, offset.HighPart, offset.LowPart, count);
7880 " WriteRaw WriteMode 0x%x",
7883 fd = smb_ChainFID(fd, inp);
7884 fidp = smb_FindFID(vcp, fd, 0);
7886 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7888 return CM_ERROR_BADFD;
7890 lock_ObtainMutex(&fidp->mx);
7892 lock_ReleaseMutex(&fidp->mx);
7893 smb_ReleaseFID(fidp);
7894 return CM_ERROR_BADFD;
7897 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7898 lock_ReleaseMutex(&fidp->mx);
7899 smb_CloseFID(vcp, fidp, NULL, 0);
7900 smb_ReleaseFID(fidp);
7901 return CM_ERROR_NOSUCHFILE;
7906 lock_ReleaseMutex(&fidp->mx);
7911 LARGE_INTEGER LOffset;
7912 LARGE_INTEGER LLength;
7915 key = cm_GenerateKey(vcp->vcID, pid, fd);
7917 LOffset.HighPart = offset.HighPart;
7918 LOffset.LowPart = offset.LowPart;
7919 LLength.HighPart = 0;
7920 LLength.LowPart = count;
7922 lock_ObtainWrite(&scp->rw);
7923 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7924 lock_ReleaseWrite(&scp->rw);
7927 cm_ReleaseSCache(scp);
7928 smb_ReleaseFID(fidp);
7933 userp = smb_GetUserFromVCP(vcp, inp);
7936 * Work around bug in NT client
7938 * When copying a file, the NT client should first copy the data,
7939 * then copy the last write time. But sometimes the NT client does
7940 * these in the wrong order, so the data copies would inadvertently
7941 * cause the last write time to be overwritten. We try to detect this,
7942 * and don't set client mod time if we think that would go against the
7945 lock_ObtainMutex(&fidp->mx);
7946 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7947 lock_ObtainWrite(&fidp->scp->rw);
7948 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7949 fidp->scp->clientModTime = time(NULL);
7950 lock_ReleaseWrite(&fidp->scp->rw);
7952 lock_ReleaseMutex(&fidp->mx);
7955 while ( code == 0 && count > 0 ) {
7956 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7957 if (code == 0 && written == 0)
7958 code = CM_ERROR_PARTIALWRITE;
7960 offset = LargeIntegerAdd(offset,
7961 ConvertLongToLargeInteger(written));
7964 total_written += written;
7968 /* Get a raw buffer */
7971 lock_ObtainMutex(&smb_RawBufLock);
7973 /* Get a raw buf, from head of list */
7974 rawBuf = smb_RawBufs;
7975 smb_RawBufs = *(char **)smb_RawBufs;
7978 code = CM_ERROR_USESTD;
7980 lock_ReleaseMutex(&smb_RawBufLock);
7983 /* Don't allow a premature Close */
7984 if (code == 0 && (writeMode & 1) == 0) {
7985 lock_ObtainMutex(&fidp->mx);
7986 fidp->raw_writers++;
7987 thrd_ResetEvent(fidp->raw_write_event);
7988 lock_ReleaseMutex(&fidp->mx);
7991 smb_ReleaseFID(fidp);
7992 cm_ReleaseUser(userp);
7993 cm_ReleaseSCache(scp);
7996 smb_SetSMBParm(outp, 0, total_written);
7997 smb_SetSMBDataLength(outp, 0);
7998 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
8003 offset = LargeIntegerAdd(offset,
8004 ConvertLongToLargeInteger(count));
8008 rwcp->offset.HighPart = offset.HighPart;
8009 rwcp->offset.LowPart = offset.LowPart;
8010 rwcp->count = totalCount - count;
8011 rwcp->writeMode = writeMode;
8012 rwcp->alreadyWritten = total_written;
8014 /* set the packet data length to 3 bytes for the data block header,
8015 * plus the size of the data.
8017 smb_SetSMBParm(outp, 0, 0xffff);
8018 smb_SetSMBDataLength(outp, 0);
8024 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8027 long count, finalCount;
8031 smb_t *smbp = (smb_t*) inp;
8037 fd = smb_GetSMBParm(inp, 0);
8038 count = smb_GetSMBParm(inp, 1);
8039 offset.HighPart = 0; /* too bad */
8040 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8042 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
8043 fd, offset.LowPart, count);
8045 fd = smb_ChainFID(fd, inp);
8046 fidp = smb_FindFID(vcp, fd, 0);
8048 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
8050 return CM_ERROR_BADFD;
8052 lock_ObtainMutex(&fidp->mx);
8053 if (fidp->flags & SMB_FID_IOCTL) {
8054 lock_ReleaseMutex(&fidp->mx);
8055 code = smb_IoctlRead(fidp, vcp, inp, outp);
8056 smb_ReleaseFID(fidp);
8060 if (fidp->flags & SMB_FID_RPC) {
8061 lock_ReleaseMutex(&fidp->mx);
8062 code = smb_RPCRead(fidp, vcp, inp, outp);
8063 smb_ReleaseFID(fidp);
8068 lock_ReleaseMutex(&fidp->mx);
8069 smb_ReleaseFID(fidp);
8070 return CM_ERROR_BADFD;
8073 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8074 lock_ReleaseMutex(&fidp->mx);
8075 smb_CloseFID(vcp, fidp, NULL, 0);
8076 smb_ReleaseFID(fidp);
8077 return CM_ERROR_NOSUCHFILE;
8082 lock_ReleaseMutex(&fidp->mx);
8085 LARGE_INTEGER LOffset, LLength;
8089 key = cm_GenerateKey(vcp->vcID, pid, fd);
8091 LOffset.HighPart = 0;
8092 LOffset.LowPart = offset.LowPart;
8093 LLength.HighPart = 0;
8094 LLength.LowPart = count;
8096 lock_ObtainWrite(&scp->rw);
8097 code = cm_LockCheckRead(scp, LOffset, LLength, key);
8098 lock_ReleaseWrite(&scp->rw);
8101 cm_ReleaseSCache(scp);
8102 smb_ReleaseFID(fidp);
8106 userp = smb_GetUserFromVCP(vcp, inp);
8108 /* remember this for final results */
8109 smb_SetSMBParm(outp, 0, count);
8110 smb_SetSMBParm(outp, 1, 0);
8111 smb_SetSMBParm(outp, 2, 0);
8112 smb_SetSMBParm(outp, 3, 0);
8113 smb_SetSMBParm(outp, 4, 0);
8115 /* set the packet data length to 3 bytes for the data block header,
8116 * plus the size of the data.
8118 smb_SetSMBDataLength(outp, count+3);
8120 /* get op ptr after putting in the parms, since otherwise we don't
8121 * know where the data really is.
8123 op = smb_GetSMBData(outp, NULL);
8125 /* now emit the data block header: 1 byte of type and 2 bytes of length */
8126 *op++ = 1; /* data block marker */
8127 *op++ = (unsigned char) (count & 0xff);
8128 *op++ = (unsigned char) ((count >> 8) & 0xff);
8130 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8132 /* fix some things up */
8133 smb_SetSMBParm(outp, 0, finalCount);
8134 smb_SetSMBDataLength(outp, finalCount+3);
8136 smb_ReleaseFID(fidp);
8138 cm_ReleaseUser(userp);
8139 cm_ReleaseSCache(scp);
8143 /* SMB_COM_CREATE_DIRECTORY */
8144 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8146 clientchar_t *pathp;
8151 cm_scache_t *dscp; /* dir we're dealing with */
8152 cm_scache_t *scp; /* file we're creating */
8154 int initialModeBits;
8155 clientchar_t *lastNamep;
8157 clientchar_t *tidPathp;
8164 /* compute initial mode bits based on read-only flag in attributes */
8165 initialModeBits = 0777;
8167 tp = smb_GetSMBData(inp, NULL);
8168 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8170 return CM_ERROR_BADSMB;
8172 spacep = inp->spacep;
8173 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8175 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8176 return CM_ERROR_EXISTS;
8178 userp = smb_GetUserFromVCP(vcp, inp);
8180 caseFold = CM_FLAG_CASEFOLD;
8182 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8184 cm_ReleaseUser(userp);
8185 return CM_ERROR_NOSUCHPATH;
8188 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
8189 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8190 userp, tidPathp, &req, &dscp);
8193 cm_ReleaseUser(userp);
8198 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8199 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8200 cm_ReleaseSCache(dscp);
8201 cm_ReleaseUser(userp);
8202 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8203 return CM_ERROR_PATH_NOT_COVERED;
8205 return CM_ERROR_NOSUCHPATH;
8207 #endif /* DFS_SUPPORT */
8209 /* otherwise, scp points to the parent directory. Do a lookup, and
8210 * fail if we find it. Otherwise, we do the create.
8216 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8217 if (scp) cm_ReleaseSCache(scp);
8218 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8219 if (code == 0) code = CM_ERROR_EXISTS;
8220 cm_ReleaseSCache(dscp);
8221 cm_ReleaseUser(userp);
8225 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8226 setAttr.clientModTime = time(NULL);
8227 smb_SetInitialModeBitsForDir(0, &setAttr);
8229 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8230 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8231 smb_NotifyChange(FILE_ACTION_ADDED,
8232 FILE_NOTIFY_CHANGE_DIR_NAME,
8233 dscp, lastNamep, NULL, TRUE);
8235 /* we don't need this any longer */
8236 cm_ReleaseSCache(dscp);
8239 /* something went wrong creating or truncating the file */
8240 cm_ReleaseUser(userp);
8244 /* otherwise we succeeded */
8245 smb_SetSMBDataLength(outp, 0);
8246 cm_ReleaseUser(userp);
8251 BOOL smb_IsLegalFilename(clientchar_t *filename)
8254 * Find the longest substring of filename that does not contain
8255 * any of the chars in illegalChars. If that substring is less
8256 * than the length of the whole string, then one or more of the
8257 * illegal chars is in filename.
8259 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8265 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8266 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8268 clientchar_t *pathp;
8274 cm_scache_t *dscp; /* dir we're dealing with */
8275 cm_scache_t *scp; /* file we're creating */
8279 clientchar_t *lastNamep;
8282 clientchar_t *tidPathp;
8284 int created = 0; /* the file was new */
8289 excl = (inp->inCom == 0x03)? 0 : 1;
8291 attributes = smb_GetSMBParm(inp, 0);
8292 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8294 tp = smb_GetSMBData(inp, NULL);
8295 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8297 return CM_ERROR_BADSMB;
8299 spacep = inp->spacep;
8300 /* smb_StripLastComponent will strip "::$DATA" if present */
8301 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8303 if (!cm_IsValidClientString(pathp)) {
8305 clientchar_t * hexp;
8307 hexp = cm_GetRawCharsAlloc(pathp, -1);
8308 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8309 osi_LogSaveClientString(smb_logp, hexp));
8313 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8315 return CM_ERROR_BADNTFILENAME;
8318 userp = smb_GetUserFromVCP(vcp, inp);
8320 caseFold = CM_FLAG_CASEFOLD;
8322 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8324 cm_ReleaseUser(userp);
8325 return CM_ERROR_NOSUCHPATH;
8327 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8328 userp, tidPathp, &req, &dscp);
8331 cm_ReleaseUser(userp);
8336 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8337 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8338 cm_ReleaseSCache(dscp);
8339 cm_ReleaseUser(userp);
8340 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8341 return CM_ERROR_PATH_NOT_COVERED;
8343 return CM_ERROR_NOSUCHPATH;
8345 #endif /* DFS_SUPPORT */
8347 /* otherwise, scp points to the parent directory. Do a lookup, and
8348 * truncate the file if we find it, otherwise we create the file.
8355 if (!smb_IsLegalFilename(lastNamep))
8356 return CM_ERROR_BADNTFILENAME;
8358 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8359 #ifdef DEBUG_VERBOSE
8362 hexp = osi_HexifyString( lastNamep );
8363 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8368 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8369 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8370 cm_ReleaseSCache(dscp);
8371 cm_ReleaseUser(userp);
8375 /* if we get here, if code is 0, the file exists and is represented by
8376 * scp. Otherwise, we have to create it.
8380 /* oops, file shouldn't be there */
8381 cm_ReleaseSCache(dscp);
8382 cm_ReleaseSCache(scp);
8383 cm_ReleaseUser(userp);
8384 return CM_ERROR_EXISTS;
8387 setAttr.mask = CM_ATTRMASK_LENGTH;
8388 setAttr.length.LowPart = 0;
8389 setAttr.length.HighPart = 0;
8390 code = cm_SetAttr(scp, &setAttr, userp, &req);
8393 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8394 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8395 smb_SetInitialModeBitsForFile(attributes, &setAttr);
8397 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8401 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8402 smb_NotifyChange(FILE_ACTION_ADDED,
8403 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8404 dscp, lastNamep, NULL, TRUE);
8405 } else if (!excl && code == CM_ERROR_EXISTS) {
8406 /* not an exclusive create, and someone else tried
8407 * creating it already, then we open it anyway. We
8408 * don't bother retrying after this, since if this next
8409 * fails, that means that the file was deleted after
8410 * we started this call.
8412 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8415 setAttr.mask = CM_ATTRMASK_LENGTH;
8416 setAttr.length.LowPart = 0;
8417 setAttr.length.HighPart = 0;
8418 code = cm_SetAttr(scp, &setAttr, userp, &req);
8423 /* we don't need this any longer */
8424 cm_ReleaseSCache(dscp);
8427 /* something went wrong creating or truncating the file */
8428 if (scp) cm_ReleaseSCache(scp);
8429 cm_ReleaseUser(userp);
8433 /* make sure we only open files */
8434 if (scp->fileType != CM_SCACHETYPE_FILE) {
8435 cm_ReleaseSCache(scp);
8436 cm_ReleaseUser(userp);
8437 return CM_ERROR_ISDIR;
8440 /* now all we have to do is open the file itself */
8441 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8442 osi_assertx(fidp, "null smb_fid_t");
8446 lock_ObtainMutex(&fidp->mx);
8447 /* always create it open for read/write */
8448 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8450 /* remember that the file was newly created */
8452 fidp->flags |= SMB_FID_CREATED;
8454 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8456 /* save a pointer to the vnode */
8458 lock_ObtainWrite(&scp->rw);
8459 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8460 lock_ReleaseWrite(&scp->rw);
8463 fidp->userp = userp;
8464 lock_ReleaseMutex(&fidp->mx);
8466 smb_SetSMBParm(outp, 0, fidp->fid);
8467 smb_SetSMBDataLength(outp, 0);
8469 cm_Open(scp, 0, userp);
8471 smb_ReleaseFID(fidp);
8472 cm_ReleaseUser(userp);
8473 /* leave scp held since we put it in fidp->scp */
8478 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8481 osi_hyper_t new_offset;
8492 fd = smb_GetSMBParm(inp, 0);
8493 whence = smb_GetSMBParm(inp, 1);
8494 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8496 /* try to find the file descriptor */
8497 fd = smb_ChainFID(fd, inp);
8498 fidp = smb_FindFID(vcp, fd, 0);
8500 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8502 return CM_ERROR_BADFD;
8504 lock_ObtainMutex(&fidp->mx);
8505 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8506 lock_ReleaseMutex(&fidp->mx);
8507 smb_ReleaseFID(fidp);
8508 return CM_ERROR_BADFD;
8511 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8512 lock_ReleaseMutex(&fidp->mx);
8513 smb_CloseFID(vcp, fidp, NULL, 0);
8514 smb_ReleaseFID(fidp);
8515 return CM_ERROR_NOSUCHFILE;
8518 lock_ReleaseMutex(&fidp->mx);
8520 userp = smb_GetUserFromVCP(vcp, inp);
8522 lock_ObtainMutex(&fidp->mx);
8525 lock_ReleaseMutex(&fidp->mx);
8526 lock_ObtainWrite(&scp->rw);
8527 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8528 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8530 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8532 /* offset from current offset */
8533 new_offset = LargeIntegerAdd(fidp->offset,
8534 ConvertLongToLargeInteger(offset));
8536 else if (whence == 2) {
8537 /* offset from current EOF */
8538 new_offset = LargeIntegerAdd(scp->length,
8539 ConvertLongToLargeInteger(offset));
8541 new_offset = ConvertLongToLargeInteger(offset);
8544 fidp->offset = new_offset;
8545 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8546 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8547 smb_SetSMBDataLength(outp, 0);
8549 lock_ReleaseWrite(&scp->rw);
8550 smb_ReleaseFID(fidp);
8551 cm_ReleaseSCache(scp);
8552 cm_ReleaseUser(userp);
8556 /* dispatch all of the requests received in a packet. Due to chaining, this may
8557 * be more than one request.
8559 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8560 NCB *ncbp, raw_write_cont_t *rwcp)
8564 unsigned long code = 0;
8565 unsigned char *outWctp;
8566 int nparms; /* # of bytes of parameters */
8568 int nbytes; /* bytes of data, excluding count */
8571 unsigned short errCode;
8572 unsigned long NTStatus;
8574 unsigned char errClass;
8575 unsigned int oldGen;
8576 DWORD oldTime, newTime;
8578 /* get easy pointer to the data */
8579 smbp = (smb_t *) inp->data;
8581 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8582 /* setup the basic parms for the initial request in the packet */
8583 inp->inCom = smbp->com;
8584 inp->wctp = &smbp->wct;
8586 inp->ncb_length = ncbp->ncb_length;
8591 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8592 /* log it and discard it */
8593 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8594 __FILE__, __LINE__, ncbp->ncb_length);
8595 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8599 /* We are an ongoing op */
8600 thrd_Increment(&ongoingOps);
8602 /* set up response packet for receiving output */
8603 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8604 smb_FormatResponsePacket(vcp, inp, outp);
8605 outWctp = outp->wctp;
8607 /* Remember session generation number and time */
8608 oldGen = sessionGen;
8609 oldTime = GetTickCount();
8611 while (inp->inCom != 0xff) {
8612 dp = &smb_dispatchTable[inp->inCom];
8614 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8615 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8616 code = outp->resumeCode;
8620 /* process each request in the packet; inCom, wctp and inCount
8621 * are already set up.
8623 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8626 /* now do the dispatch */
8627 /* start by formatting the response record a little, as a default */
8628 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8630 outWctp[1] = 0xff; /* no operation */
8631 outWctp[2] = 0; /* padding */
8636 /* not a chained request, this is a more reasonable default */
8637 outWctp[0] = 0; /* wct of zero */
8638 outWctp[1] = 0; /* and bcc (word) of zero */
8642 /* once set, stays set. Doesn't matter, since we never chain
8643 * "no response" calls.
8645 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8649 /* we have a recognized operation */
8650 char * opName = myCrt_Dispatch(inp->inCom);
8653 smbp = (smb_t *) inp;
8655 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8656 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8657 if (inp->inCom == 0x1d) {
8659 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8661 code = (*(dp->procp)) (vcp, inp, outp);
8663 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8664 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8666 newTime = GetTickCount();
8667 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8668 opName, smbp->mid, newTime - oldTime);
8671 if ( code == CM_ERROR_BADSMB ||
8672 code == CM_ERROR_BADOP )
8674 #endif /* LOG_PACKET */
8676 /* ReceiveV3Tran2A handles its own logging */
8677 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8680 clientchar_t *treepath = NULL; /* do not free */
8681 clientchar_t *pathname = NULL;
8682 cm_fid_t afid = {0,0,0,0,0};
8684 uidp = smb_FindUID(vcp, smbp->uid, 0);
8685 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8686 fidp = smb_FindFID(vcp, inp->fid, 0);
8689 lock_ObtainMutex(&fidp->mx);
8690 if (fidp->NTopen_pathp)
8691 pathname = fidp->NTopen_pathp;
8693 afid = fidp->scp->fid;
8695 if (inp->stringsp->wdata)
8696 pathname = inp->stringsp->wdata;
8699 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)",
8700 opName, newTime - oldTime,
8701 smbp->uid, uidp ? uidp->unp->name : NULL,
8702 smbp->pid, smbp->mid, smbp->tid,
8705 afid.cell, afid.volume, afid.vnode, afid.unique);
8708 lock_ReleaseMutex(&fidp->mx);
8711 smb_ReleaseUID(uidp);
8713 smb_ReleaseFID(fidp);
8716 if (oldGen != sessionGen) {
8717 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8718 newTime - oldTime, ncbp->ncb_length);
8719 osi_Log3(smb_logp, "Request %s straddled session startup, "
8720 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8723 FreeSMBStrings(inp);
8725 /* bad opcode, fail the request, after displaying it */
8726 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8729 #endif /* LOG_PACKET */
8732 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8733 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8734 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8735 if (code == IDCANCEL)
8738 code = CM_ERROR_BADOP;
8741 /* catastrophic failure: log as much as possible */
8742 if (code == CM_ERROR_BADSMB) {
8743 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8747 #endif /* LOG_PACKET */
8748 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8751 code = CM_ERROR_INVAL;
8754 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8755 thrd_Decrement(&ongoingOps);
8760 /* now, if we failed, turn the current response into an empty
8761 * one, and fill in the response packet's error code.
8764 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8765 smb_MapNTError(code, &NTStatus, FALSE);
8766 outWctp = outp->wctp;
8767 smbp = (smb_t *) &outp->data;
8768 if (code != CM_ERROR_PARTIALWRITE
8769 && code != CM_ERROR_BUFFERTOOSMALL
8770 && code != CM_ERROR_GSSCONTINUE) {
8771 /* nuke wct and bcc. For a partial
8772 * write or an in-process authentication handshake,
8773 * assume they're OK.
8779 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8780 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8781 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8782 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8783 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8787 smb_MapCoreError(code, vcp, &errCode, &errClass);
8788 outWctp = outp->wctp;
8789 smbp = (smb_t *) &outp->data;
8790 if (code != CM_ERROR_PARTIALWRITE) {
8791 /* nuke wct and bcc. For a partial
8792 * write, assume they're OK.
8798 smbp->errLow = (unsigned char) (errCode & 0xff);
8799 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8800 smbp->rcls = errClass;
8803 } /* error occurred */
8805 /* if we're here, we've finished one request. Look to see if
8806 * this is a chained opcode. If it is, setup things to process
8807 * the chained request, and setup the output buffer to hold the
8808 * chained response. Start by finding the next input record.
8810 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8811 break; /* not a chained req */
8812 tp = inp->wctp; /* points to start of last request */
8813 /* in a chained request, the first two
8814 * parm fields are required, and are
8815 * AndXCommand/AndXReserved and
8817 if (tp[0] < 2) break;
8818 if (tp[1] == 0xff) break; /* no more chained opcodes */
8820 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8823 /* and now append the next output request to the end of this
8824 * last request. Begin by finding out where the last response
8825 * ends, since that's where we'll put our new response.
8827 outWctp = outp->wctp; /* ptr to out parameters */
8828 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8829 nparms = outWctp[0] << 1;
8830 tp = outWctp + nparms + 1; /* now points to bcc field */
8831 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8832 tp += 2 /* for the count itself */ + nbytes;
8833 /* tp now points to the new output record; go back and patch the
8834 * second parameter (off2) to point to the new record.
8836 temp = (unsigned int)(tp - outp->data);
8837 outWctp[3] = (unsigned char) (temp & 0xff);
8838 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8839 outWctp[2] = 0; /* padding */
8840 outWctp[1] = inp->inCom; /* next opcode */
8842 /* finally, setup for the next iteration */
8845 } /* while loop over all requests in the packet */
8847 /* now send the output packet, and return */
8849 smb_SendPacket(vcp, outp);
8850 thrd_Decrement(&ongoingOps);
8855 /* Wait for Netbios() calls to return, and make the results available to server
8856 * threads. Note that server threads can't wait on the NCBevents array
8857 * themselves, because NCB events are manual-reset, and the servers would race
8858 * each other to reset them.
8860 void smb_ClientWaiter(void *parmp)
8865 while (smbShutdownFlag == 0) {
8866 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8868 if (code == WAIT_OBJECT_0)
8871 /* error checking */
8872 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8874 int abandonIdx = code - WAIT_ABANDONED_0;
8875 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8878 if (code == WAIT_IO_COMPLETION)
8880 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8884 if (code == WAIT_TIMEOUT)
8886 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8889 if (code == WAIT_FAILED)
8891 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8894 idx = code - WAIT_OBJECT_0;
8896 /* check idx range! */
8897 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8899 /* this is fatal - log as much as possible */
8900 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8901 osi_assertx(0, "invalid index");
8904 thrd_ResetEvent(NCBevents[idx]);
8905 thrd_SetEvent(NCBreturns[0][idx]);
8910 * Try to have one NCBRECV request waiting for every live session. Not more
8911 * than one, because if there is more than one, it's hard to handle Write Raw.
8913 void smb_ServerWaiter(void *parmp)
8916 int idx_session, idx_NCB;
8919 while (smbShutdownFlag == 0) {
8921 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8923 if (code == WAIT_OBJECT_0)
8926 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8928 int abandonIdx = code - WAIT_ABANDONED_0;
8929 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8932 if (code == WAIT_IO_COMPLETION)
8934 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8938 if (code == WAIT_TIMEOUT)
8940 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8943 if (code == WAIT_FAILED)
8945 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8948 idx_session = code - WAIT_OBJECT_0;
8950 /* check idx range! */
8951 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8953 /* this is fatal - log as much as possible */
8954 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8955 osi_assertx(0, "invalid index");
8960 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8962 if (code == WAIT_OBJECT_0) {
8963 if (smbShutdownFlag == 1)
8969 /* error checking */
8970 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8972 int abandonIdx = code - WAIT_ABANDONED_0;
8973 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8976 if (code == WAIT_IO_COMPLETION)
8978 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8982 if (code == WAIT_TIMEOUT)
8984 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8987 if (code == WAIT_FAILED)
8989 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8992 idx_NCB = code - WAIT_OBJECT_0;
8994 /* check idx range! */
8995 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8997 /* this is fatal - log as much as possible */
8998 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8999 osi_assertx(0, "invalid index");
9002 /* Link them together */
9003 NCBsessions[idx_NCB] = idx_session;
9006 ncbp = NCBs[idx_NCB];
9007 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
9008 ncbp->ncb_command = NCBRECV | ASYNCH;
9009 ncbp->ncb_lana_num = lanas[idx_session];
9010 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
9011 ncbp->ncb_event = NCBevents[idx_NCB];
9012 ncbp->ncb_length = SMB_PACKETSIZE;
9017 typedef struct _monitored_task {
9020 LARGE_INTEGER start_time;
9022 BOOL trace_timer_hit;
9023 BOOL dump_timer_hit;
9026 typedef struct osi_queueHT {
9027 osi_queue_t * headp;
9028 osi_queue_t * tailp;
9031 static osi_queue_t *smb_monitored_tasks = NULL;
9032 static osi_queue_t *smb_free_monitored_tasks = NULL;
9034 static osi_mutex_t _monitor_mx;
9036 static HANDLE h_monitored_task_queue = NULL;
9037 static HANDLE h_monitored_task_shutdown = NULL;
9039 static time_t smb_last_dump_time = 0;
9041 DWORD smb_monitorReqs = 0;
9043 /* FILETIME comparison fuzz */
9044 #define MONITOR_FUZZ_TIMEOUT (1 * 10000000i64)
9046 /* Trace timeout is at 60 seconds */
9047 #define MONITOR_TRACE_TIMEOUT (60 * 10000000i64)
9049 /* Dump timeout is at 120 seconds */
9050 #define MONITOR_DUMP_TIMEOUT (120 * 10000000i64)
9052 /* Time before another dump is performed in seconds*/
9053 #define MONITOR_DUMP_RESET_TIMEOUT (600)
9055 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
9058 LARGE_INTEGER earliest;
9061 GetSystemTimeAsFileTime(&now);
9062 earliest.LowPart = now.dwLowDateTime;
9063 earliest.HighPart = now.dwHighDateTime;
9064 earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
9066 while ((t = (monitored_task *) taskmq->headp) != NULL &&
9068 (t->start_time.QuadPart < earliest.QuadPart ||
9070 t->dump_timer_hit)) {
9072 osi_QRemoveHT(&taskmq->headp,
9076 lock_ObtainMutex(&_monitor_mx);
9077 osi_QAdd(&smb_free_monitored_tasks, &t->q);
9078 lock_ReleaseMutex(&_monitor_mx);
9081 #ifdef INVARIANT_CHECK
9087 for (t = (monitored_task *) taskmq->headp;
9089 t = (monitored_task *) osi_QNext(&t->q)) {
9090 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9091 last.QuadPart = t->start_time.QuadPart;
9097 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
9099 monitored_task * task;
9100 monitored_task * tasks;
9102 lock_ObtainMutex(&_monitor_mx);
9103 tasks = (monitored_task *) smb_monitored_tasks;
9104 smb_monitored_tasks = NULL;
9105 lock_ReleaseMutex(&_monitor_mx);
9110 osi_QRemove((osi_queue_t **) &tasks, &task->q);
9112 if (task->started) {
9118 q.prevp = taskmq->tailp;
9120 /* Insertion sort by start_time. Earliest request is
9121 first. Since we are likely to receive new requests
9122 later, we start inserting from the back. */
9125 ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
9129 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
9130 else if (p->prevp == NULL)
9131 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
9133 osi_queue_t *o = p->prevp;
9135 osi_assert(o->nextp == p);
9139 p->prevp = &task->q;
9140 o->nextp = &task->q;
9144 /* Some task ending */
9148 for (p = taskmq->headp;
9152 monitored_task * mt = (monitored_task *) p;
9154 if (mt->task_id == task->task_id) {
9156 osi_QRemoveHT(&taskmq->headp,
9159 lock_ObtainMutex(&_monitor_mx);
9160 osi_QAdd(&smb_free_monitored_tasks, p);
9161 lock_ReleaseMutex(&_monitor_mx);
9167 lock_ObtainMutex(&_monitor_mx);
9168 osi_QAdd(&smb_free_monitored_tasks, &task->q);
9169 lock_ReleaseMutex(&_monitor_mx);
9173 #ifdef INVARIANT_CHECK
9180 for (t = (monitored_task *) taskmq->headp;
9182 t = (monitored_task *) osi_QNext(&t->q)) {
9183 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9184 last.QuadPart = t->start_time.QuadPart;
9190 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9192 if (!task->trace_timer_hit) {
9194 task->trace_timer_hit = TRUE;
9196 osi_LogEnable(afsd_logp);
9197 rx_DebugOnOff(TRUE);
9199 } else if (!task->dump_timer_hit) {
9204 if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9205 task->dump_timer_hit = TRUE;
9206 smb_last_dump_time = now;
9208 GenerateMiniDump(NULL);
9214 * Server request monitoring
9216 * The server monitor runs in a separate thread and monitors server
9217 * requests for potential timeouts. It examines notifcations queued
9218 * by smb_NotifyRequestEvent() and waits for potential timeout events:
9220 * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9221 * enables trace logging.
9223 * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9224 * out a dump file that will hopefully contain enough evidence to
9225 * figure out why the timeout event occurred.
9228 void smb_ServerMonitor(VOID * parmp)
9230 osi_queueHT_t in_progress = { NULL, NULL };
9231 HANDLE h_timer = NULL;
9235 h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9236 h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9237 h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9239 lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9241 h_all[0] = h_monitored_task_queue;
9243 h_all[2] = h_monitored_task_shutdown;
9248 rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9250 if (rv == WAIT_OBJECT_0) {
9252 smb_SlurpNewTaskMonitors(&in_progress);
9254 } else if (rv == WAIT_OBJECT_0 + 1) {
9256 smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9264 /* refresh timers */
9268 smb_PurgeOldTaskMonitors(&in_progress);
9269 t = (monitored_task *) in_progress.headp;
9271 if (t && !t->trace_timer_hit) {
9274 due = t->start_time;
9275 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9277 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9278 } else if (t && !t->dump_timer_hit) {
9282 due = t->start_time;
9283 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9285 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9287 CancelWaitableTimer(h_timer);
9289 /* CancelWaitableTimer() doesn't reset the timer if it
9290 was already signalled. */
9291 WaitForSingleObject(h_timer, 0);
9299 h = h_monitored_task_queue;
9300 h_monitored_task_queue = NULL;
9303 h = h_monitored_task_shutdown;
9304 h_monitored_task_shutdown = NULL;
9307 CloseHandle(h_timer);
9309 lock_FinalizeMutex(&_monitor_mx);
9313 monitored_task * task;
9315 while (in_progress.headp) {
9316 task = (monitored_task *) in_progress.headp;
9317 osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9321 for (task = (monitored_task *) smb_free_monitored_tasks;
9322 task; task = (monitored_task *) smb_free_monitored_tasks) {
9323 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9327 for (task = (monitored_task *) smb_monitored_tasks;
9328 task; task = (monitored_task *) smb_monitored_tasks) {
9329 osi_QRemove(&smb_monitored_tasks, &task->q);
9335 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9337 monitored_task * task;
9339 lock_ObtainMutex(&_monitor_mx);
9340 task = (monitored_task *) smb_free_monitored_tasks;
9342 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9343 lock_ReleaseMutex(&_monitor_mx);
9346 task = malloc(sizeof(monitored_task));
9347 memset(task, 0, sizeof(*task));
9349 task->task_id = task_id;
9350 task->started = started;
9355 GetSystemTimeAsFileTime(&now);
9356 task->start_time.HighPart = now.dwHighDateTime;
9357 task->start_time.LowPart = now.dwLowDateTime;
9360 lock_ObtainMutex(&_monitor_mx);
9361 osi_QAdd(&smb_monitored_tasks, &task->q);
9362 lock_ReleaseMutex(&_monitor_mx);
9364 SetEvent(h_monitored_task_queue);
9367 void smb_ShutdownMonitor()
9369 SetEvent(h_monitored_task_shutdown);
9373 * The top level loop for handling SMB request messages. Each server thread
9374 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9375 * NCB and buffer for the incoming request are loaned to us.
9377 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
9378 * to immediately send a request for the rest of the data. This must come
9379 * before any other traffic for that session, so we delay setting the session
9380 * event until that data has come in.
9382 void smb_Server(VOID *parmp)
9384 INT_PTR myIdx = (INT_PTR) parmp;
9388 smb_packet_t *outbufp;
9390 int idx_NCB, idx_session;
9392 smb_vc_t *vcp = NULL;
9395 rx_StartClientThread();
9397 outncbp = smb_GetNCB();
9398 outbufp = smb_GetPacket();
9399 outbufp->ncbp = outncbp;
9407 cm_ResetServerPriority();
9409 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9412 /* terminate silently if shutdown flag is set */
9413 if (code == WAIT_OBJECT_0) {
9414 if (smbShutdownFlag == 1) {
9415 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9421 /* error checking */
9422 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9424 int abandonIdx = code - WAIT_ABANDONED_0;
9425 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9428 if (code == WAIT_IO_COMPLETION)
9430 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9434 if (code == WAIT_TIMEOUT)
9436 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9439 if (code == WAIT_FAILED)
9441 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9444 idx_NCB = code - WAIT_OBJECT_0;
9446 /* check idx range! */
9447 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9449 /* this is fatal - log as much as possible */
9450 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9451 osi_assertx(0, "invalid index");
9454 ncbp = NCBs[idx_NCB];
9455 idx_session = NCBsessions[idx_NCB];
9456 rc = ncbp->ncb_retcode;
9458 if (rc != NRC_PENDING && rc != NRC_GOODRET)
9459 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9463 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9467 /* Can this happen? Or is it just my UNIX paranoia? */
9468 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9473 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9476 /* Client closed session */
9477 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9479 lock_ObtainMutex(&vcp->mx);
9480 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9481 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9483 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9484 lock_ReleaseMutex(&vcp->mx);
9485 lock_ObtainWrite(&smb_globalLock);
9486 dead_sessions[vcp->session] = TRUE;
9487 lock_ReleaseWrite(&smb_globalLock);
9489 lock_ReleaseMutex(&vcp->mx);
9491 smb_CleanupDeadVC(vcp);
9498 /* Treat as transient error */
9499 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9502 "dispatch smb recv failed, message incomplete, ncb_length %d",
9505 "SMB message incomplete, "
9506 "length %d", ncbp->ncb_length);
9509 * We used to discard the packet.
9510 * Instead, try handling it normally.
9514 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9518 /* A weird error code. Log it, sleep, and continue. */
9519 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9521 lock_ObtainMutex(&vcp->mx);
9522 if (vcp->errorCount++ > 3) {
9523 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9524 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9525 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9527 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9528 lock_ReleaseMutex(&vcp->mx);
9529 lock_ObtainWrite(&smb_globalLock);
9530 dead_sessions[vcp->session] = TRUE;
9531 lock_ReleaseWrite(&smb_globalLock);
9533 lock_ReleaseMutex(&vcp->mx);
9535 smb_CleanupDeadVC(vcp);
9541 lock_ReleaseMutex(&vcp->mx);
9545 thrd_SetEvent(SessionEvents[idx_session]);
9551 /* Success, so now dispatch on all the data in the packet */
9553 smb_concurrentCalls++;
9554 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9555 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9558 * If at this point vcp is NULL (implies that packet was invalid)
9559 * then we are in big trouble. This means either :
9560 * a) we have the wrong NCB.
9561 * b) Netbios screwed up the call.
9562 * c) The VC was already marked dead before we were able to
9564 * Obviously this implies that
9565 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9566 * lanas[idx_session] != ncbp->ncb_lana_num )
9567 * Either way, we can't do anything with this packet.
9568 * Log, sleep and resume.
9571 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9575 ncbp->ncb_lana_num);
9577 /* Also log in the trace log. */
9578 osi_Log4(smb_logp, "Server: VCP does not exist!"
9579 "LSNs[idx_session]=[%d],"
9580 "lanas[idx_session]=[%d],"
9581 "ncbp->ncb_lsn=[%d],"
9582 "ncbp->ncb_lana_num=[%d]",
9586 ncbp->ncb_lana_num);
9588 /* thrd_Sleep(1000); Don't bother sleeping */
9589 thrd_SetEvent(SessionEvents[idx_session]);
9590 smb_concurrentCalls--;
9594 cm_SetRequestStartTime();
9595 if (smb_monitorReqs) {
9596 smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9599 vcp->errorCount = 0;
9600 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9601 smbp = (smb_t *)bufp->data;
9608 if (smbp->com == 0x1d) {
9609 /* Special handling for Write Raw */
9610 raw_write_cont_t rwc;
9612 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9613 if (rwc.code == 0) {
9614 EVENT_HANDLE rwevent;
9615 char eventName[MAX_PATH];
9617 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9618 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9619 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9620 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9622 ncbp->ncb_command = NCBRECV | ASYNCH;
9623 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9624 ncbp->ncb_lana_num = vcp->lana;
9625 ncbp->ncb_buffer = rwc.buf;
9626 ncbp->ncb_length = 65535;
9627 ncbp->ncb_event = rwevent;
9629 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9630 thrd_CloseHandle(rwevent);
9632 thrd_SetEvent(SessionEvents[idx_session]);
9634 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9636 else if (smbp->com == 0xa0) {
9638 * Serialize the handling for NT Transact
9641 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9642 thrd_SetEvent(SessionEvents[idx_session]);
9644 thrd_SetEvent(SessionEvents[idx_session]);
9645 /* TODO: what else needs to be serialized? */
9646 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9650 __except( smb_ServerExceptionFilter() ) {
9654 if (smb_monitorReqs) {
9655 smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9657 smb_concurrentCalls--;
9660 thrd_SetEvent(NCBavails[idx_NCB]);
9665 smb_FreePacket(outbufp);
9667 smb_FreeNCB(outncbp);
9671 * Exception filter for the server threads. If an exception occurs in the
9672 * dispatch routines, which is where exceptions are most common, then do a
9673 * force trace and give control to upstream exception handlers. Useful for
9676 DWORD smb_ServerExceptionFilter(void) {
9677 /* While this is not the best time to do a trace, if it succeeds, then
9678 * we have a trace (assuming tracing was enabled). Otherwise, this should
9679 * throw a second exception.
9681 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9682 afsd_ForceTrace(TRUE);
9683 buf_ForceTrace(TRUE);
9684 return EXCEPTION_CONTINUE_SEARCH;
9688 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9689 * If the number of server threads is M, and the number of live sessions is
9690 * N, then the number of NCB's in use at any time either waiting for, or
9691 * holding, received messages is M + N, so that is how many NCB's get created.
9693 void InitNCBslot(int idx)
9695 struct smb_packet *bufp;
9696 EVENT_HANDLE retHandle;
9698 char eventName[MAX_PATH];
9700 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9702 NCBs[idx] = smb_GetNCB();
9703 sprintf(eventName,"NCBavails[%d]", idx);
9704 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9705 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9706 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9707 sprintf(eventName,"NCBevents[%d]", idx);
9708 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9709 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9710 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9711 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9712 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9713 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9714 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9715 for (i=0; i<smb_NumServerThreads; i++)
9716 NCBreturns[i][idx] = retHandle;
9717 bufp = smb_GetPacket();
9718 bufp->spacep = cm_GetSpace();
9722 /* listen for new connections */
9723 void smb_Listener(void *parmp)
9729 afs_uint32 session, thread;
9730 smb_vc_t *vcp = NULL;
9732 char rname[NCBNAMSZ+1];
9733 char cname[MAX_COMPUTERNAME_LENGTH+1];
9734 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9735 INT_PTR lana = (INT_PTR) parmp;
9736 char eventName[MAX_PATH];
9737 int bridgeCount = 0;
9738 int nowildCount = 0;
9740 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9741 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9742 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9743 thrd_ResetEvent(ListenerShutdown[lana]);
9745 ncbp = smb_GetNCB();
9747 /* retrieve computer name */
9748 GetComputerName(cname, &cnamelen);
9751 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9752 memset(ncbp, 0, sizeof(NCB));
9755 ncbp->ncb_command = NCBLISTEN;
9756 ncbp->ncb_rto = 0; /* No receive timeout */
9757 ncbp->ncb_sto = 0; /* No send timeout */
9759 /* pad out with spaces instead of null termination */
9760 len = (long)strlen(smb_localNamep);
9761 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9762 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9764 strcpy(ncbp->ncb_callname, "*");
9765 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9767 ncbp->ncb_lana_num = (UCHAR)lana;
9769 code = Netbios(ncbp);
9771 if (code == NRC_NAMERR) {
9772 /* An smb shutdown or Vista resume must have taken place */
9774 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9775 ncbp->ncb_lana_num);
9776 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9778 if (lock_TryMutex(&smb_StartedLock)) {
9779 lana_list.lana[i] = LANA_INVALID;
9780 lock_ReleaseMutex(&smb_StartedLock);
9783 } else if (code == NRC_BRIDGE || code != 0) {
9784 int lanaRemaining = 0;
9786 if (code == NRC_BRIDGE) {
9787 if (++bridgeCount <= 5) {
9788 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9791 } else if (code == NRC_NOWILD) {
9792 if (++nowildCount <= 5) {
9793 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9795 if (bridgeCount > 0) {
9796 memset(ncbp, 0, sizeof(*ncbp));
9797 ncbp->ncb_command = NCBADDNAME;
9798 ncbp->ncb_lana_num = (UCHAR)lana;
9799 /* pad out with spaces instead of null termination */
9800 len = (long)strlen(smb_localNamep);
9801 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9802 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9803 code = Netbios(ncbp);
9809 while (!lock_TryMutex(&smb_StartedLock)) {
9810 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9816 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9817 ncbp->ncb_lana_num, ncb_error_string(code));
9818 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9819 ncbp->ncb_lana_num, ncb_error_string(code));
9821 for (i = 0; i < lana_list.length; i++) {
9822 if (lana_list.lana[i] == lana) {
9823 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9824 lana_list.lana[i] = LANA_INVALID;
9826 if (lana_list.lana[i] != LANA_INVALID)
9830 if (lanaRemaining == 0) {
9831 cm_VolStatus_Network_Stopped(cm_NetbiosName
9836 smb_ListenerState = SMB_LISTENER_STOPPED;
9837 smb_LANadapter = LANA_INVALID;
9838 lana_list.length = 0;
9840 lock_ReleaseMutex(&smb_StartedLock);
9844 /* a successful packet received. clear bridge error count */
9848 /* check for remote conns */
9849 /* first get remote name and insert null terminator */
9850 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9851 for (i=NCBNAMSZ; i>0; i--) {
9852 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9858 /* compare with local name */
9860 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9861 flags |= SMB_VCFLAG_REMOTECONN;
9864 lock_ObtainMutex(&smb_ListenerLock);
9866 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9867 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9869 /* now ncbp->ncb_lsn is the connection ID */
9870 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9871 if (vcp->session == 0) {
9872 /* New generation */
9873 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9876 /* Log session startup */
9878 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9879 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9880 #endif /* NOTSERVICE */
9881 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9882 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9884 if (reportSessionStartups) {
9885 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9888 lock_ObtainMutex(&vcp->mx);
9889 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9890 vcp->flags |= flags;
9891 lock_ReleaseMutex(&vcp->mx);
9893 /* Allocate slot in session arrays */
9894 /* Re-use dead session if possible, otherwise add one more */
9895 /* But don't look at session[0], it is reserved */
9896 lock_ObtainWrite(&smb_globalLock);
9897 for (session = 1; session < numSessions; session++) {
9898 if (dead_sessions[session]) {
9899 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9900 dead_sessions[session] = FALSE;
9904 lock_ReleaseWrite(&smb_globalLock);
9906 /* We are re-using an existing VC because the lsn and lana
9908 session = vcp->session;
9910 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9912 /* Log session startup */
9914 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9915 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9916 #endif /* NOTSERVICE */
9917 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9918 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9920 if (reportSessionStartups) {
9921 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9925 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9926 unsigned long code = CM_ERROR_ALLBUSY;
9927 smb_packet_t * outp = smb_GetPacket();
9928 unsigned char *outWctp;
9931 smb_FormatResponsePacket(vcp, NULL, outp);
9934 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9935 unsigned long NTStatus;
9936 smb_MapNTError(code, &NTStatus, FALSE);
9937 outWctp = outp->wctp;
9938 smbp = (smb_t *) &outp->data;
9942 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9943 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9944 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9945 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9946 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9948 unsigned short errCode;
9949 unsigned char errClass;
9950 smb_MapCoreError(code, vcp, &errCode, &errClass);
9951 outWctp = outp->wctp;
9952 smbp = (smb_t *) &outp->data;
9956 smbp->errLow = (unsigned char) (errCode & 0xff);
9957 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9958 smbp->rcls = errClass;
9961 smb_SendPacket(vcp, outp);
9962 smb_FreePacket(outp);
9964 lock_ObtainMutex(&vcp->mx);
9965 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9966 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9968 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9969 lock_ReleaseMutex(&vcp->mx);
9970 lock_ObtainWrite(&smb_globalLock);
9971 dead_sessions[vcp->session] = TRUE;
9972 lock_ReleaseWrite(&smb_globalLock);
9973 smb_CleanupDeadVC(vcp);
9975 lock_ReleaseMutex(&vcp->mx);
9978 /* assert that we do not exceed the maximum number of sessions or NCBs.
9979 * we should probably want to wait for a session to be freed in case
9982 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9983 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9985 lock_ObtainMutex(&vcp->mx);
9986 vcp->session = session;
9987 lock_ReleaseMutex(&vcp->mx);
9988 lock_ObtainWrite(&smb_globalLock);
9989 LSNs[session] = ncbp->ncb_lsn;
9990 lanas[session] = ncbp->ncb_lana_num;
9991 lock_ReleaseWrite(&smb_globalLock);
9993 if (session == numSessions) {
9994 /* Add new NCB for new session */
9995 char eventName[MAX_PATH];
9997 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9999 InitNCBslot(numNCBs);
10000 lock_ObtainWrite(&smb_globalLock);
10002 lock_ReleaseWrite(&smb_globalLock);
10003 thrd_SetEvent(NCBavails[0]);
10004 thrd_SetEvent(NCBevents[0]);
10005 for (thread = 0; thread < smb_NumServerThreads; thread++)
10006 thrd_SetEvent(NCBreturns[thread][0]);
10007 /* Also add new session event */
10008 sprintf(eventName, "SessionEvents[%d]", session);
10009 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
10010 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10011 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
10012 lock_ObtainWrite(&smb_globalLock);
10014 lock_ReleaseWrite(&smb_globalLock);
10015 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
10016 thrd_SetEvent(SessionEvents[0]);
10018 thrd_SetEvent(SessionEvents[session]);
10021 smb_ReleaseVC(vcp);
10024 lock_ReleaseMutex(&smb_ListenerLock);
10025 } /* dispatch while loop */
10029 thrd_SetEvent(ListenerShutdown[lana]);
10034 smb_configureBackConnectionHostNames(int bEnable)
10036 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
10037 * there is a restriction on the use of SMB authentication on loopback connections.
10038 * There are two work arounds available:
10040 * (1) We can disable the check for matching host names. This does not
10041 * require a reboot:
10042 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
10043 * "DisableLoopbackCheck"=dword:00000001
10045 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
10046 * does require a reboot:
10047 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
10048 * "BackConnectionHostNames"=multi-sz
10050 * The algorithm will be:
10051 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
10052 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
10053 * (2b1) and check to see if DisableLoopbackCheck is set.
10054 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
10055 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
10056 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
10057 * check for the UnsetDisableLoopbackCheck value.
10058 * If set, set the DisableLoopbackCheck flag to 0x0
10059 * and delete the UnsetDisableLoopbackCheck value
10061 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
10062 * force Windows to use the loopback authentication mechanism for the specified
10065 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
10066 * service session that set it.
10072 DWORD dwSize, dwAllocSize;
10074 PBYTE pHostNames = NULL, pName = NULL;
10075 PBYTE pOrigNames = NULL, pOrig = NULL;
10076 BOOL bNameFound = FALSE;
10077 DWORD dwLoopbackCheckDisabled;
10078 DWORD dwszBackConnectionHostNames;
10079 size_t nbsize = strlen(cm_NetbiosName) + 2;
10081 static BOOL bLoopbackCheckDisabled = FALSE;
10083 /* DisableLoopbackCheck */
10084 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10085 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10087 KEY_READ|KEY_WRITE,
10088 &hkLsa) == ERROR_SUCCESS )
10090 dwSize = sizeof(DWORD);
10091 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwLoopbackCheckDisabled, &dwSize) != ERROR_SUCCESS)
10093 dwLoopbackCheckDisabled = 0;
10096 hkLsa = INVALID_HANDLE_VALUE;
10099 /* BackConnectionHostNames */
10100 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10101 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
10103 KEY_READ|KEY_WRITE,
10104 &hkMSV10) == ERROR_SUCCESS )
10106 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
10107 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10108 (dwType == REG_MULTI_SZ))
10110 dwAllocSize += 1 /* in case the source string is not nul terminated */
10111 + (DWORD)strlen(cm_NetbiosName) + 2;
10112 pHostNames = malloc(dwAllocSize);
10113 dwszBackConnectionHostNames = dwAllocSize;
10114 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
10115 pHostNames, &dwszBackConnectionHostNames) == ERROR_SUCCESS)
10117 for (pName = pHostNames;
10118 (pName - pHostNames < (int) dwszBackConnectionHostNames) && *pName ;
10119 pName += strlen(pName) + 1)
10121 if ( !stricmp(pName, cm_NetbiosName) ) {
10130 if ( !bNameFound ) {
10131 size_t size = strlen(cm_NetbiosName) + 2;
10132 if ( !pHostNames ) {
10133 pHostNames = malloc(size);
10134 pName = pHostNames;
10136 StringCbCopyA(pName, size, cm_NetbiosName);
10138 *pName = '\0'; /* add a second nul terminator */
10140 dwType = REG_MULTI_SZ;
10141 dwSize = (DWORD)(pName - pHostNames + 1);
10142 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10144 if ( hkLsa != INVALID_HANDLE_VALUE && !dwLoopbackCheckDisabled)
10146 dwType = REG_DWORD;
10147 dwSize = sizeof(DWORD);
10148 dwLoopbackCheckDisabled = 1;
10149 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwLoopbackCheckDisabled, dwSize);
10151 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10152 AFSREG_CLT_OPENAFS_SUBKEY,
10155 REG_OPTION_NON_VOLATILE,
10156 KEY_READ|KEY_WRITE,
10159 NULL) == ERROR_SUCCESS) {
10161 dwType = REG_DWORD;
10162 dwSize = sizeof(DWORD);
10164 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10165 bLoopbackCheckDisabled = TRUE;
10166 RegCloseKey(hkClient);
10169 } else if (!bLoopbackCheckDisabled && hkLsa != INVALID_HANDLE_VALUE) {
10170 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10171 AFSREG_CLT_OPENAFS_SUBKEY,
10174 REG_OPTION_NON_VOLATILE,
10175 KEY_READ|KEY_WRITE,
10178 NULL) == ERROR_SUCCESS) {
10180 dwSize = sizeof(DWORD);
10181 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10183 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10186 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10187 RegCloseKey(hkClient);
10191 * Disable SMB. Start by removing the DisableLoopbackCheck value if present.
10193 if (hkLsa != INVALID_HANDLE_VALUE) {
10194 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10195 AFSREG_CLT_OPENAFS_SUBKEY,
10198 REG_OPTION_NON_VOLATILE,
10199 KEY_READ|KEY_WRITE,
10202 NULL) == ERROR_SUCCESS) {
10204 dwSize = sizeof(DWORD);
10205 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10207 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10210 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10211 RegCloseKey(hkClient);
10214 /* Then remove our NetbiosName from the BackConnectionHostNames list */
10215 if ( bNameFound ) {
10217 * we found our name so if the size of the value is smaller
10218 * or equal to the length of our name alone, we are done.
10220 if ( dwszBackConnectionHostNames <= nbsize ) {
10221 RegDeleteValue( hkMSV10, "BackConnectionHostNames");
10223 pOrigNames = pHostNames;
10224 pHostNames = malloc(dwAllocSize);
10226 pOrig = pOrigNames;
10227 pName = pHostNames;
10228 while (pOrig - pOrigNames < dwszBackConnectionHostNames) {
10229 len = strlen(pOrig);
10230 if ( stricmp(pOrig, cm_NetbiosName)) {
10232 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10237 *pName = '\0'; /* add a second nul terminator */
10240 dwType = REG_MULTI_SZ;
10241 dwSize = (DWORD)(pName - pHostNames + 1);
10242 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10257 RegCloseKey(hkMSV10);
10260 if ( hkLsa != INVALID_HANDLE_VALUE ) {
10261 RegCloseKey(hkLsa);
10267 smb_configureExtendedSMBSessionTimeouts(int bEnable)
10270 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10271 * new functionality:
10273 * [HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters]
10274 * "ReconnectableServers" REG_MULTI_SZ
10275 * "ExtendedSessTimeout" REG_DWORD (seconds)
10276 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
10278 * These values can be used to prevent the smb redirector from timing out
10279 * smb connection to the afs smb server prematurely.
10283 DWORD dwSize, dwAllocSize;
10285 PBYTE pHostNames = NULL, pOrigNames = NULL, pName = NULL, pOrig = NULL;
10286 BOOL bNameFound = FALSE;
10287 DWORD dwszReconnectableServers;
10288 DWORD dwszServersWithExtendedSessTimeout;
10289 size_t nbsize = strlen(cm_NetbiosName) + 2;
10292 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10293 "SYSTEM\\CurrentControlSet\\Services\\LanmanWorkstation\\Parameters",
10295 KEY_READ|KEY_WRITE,
10296 &hkLanman) == ERROR_SUCCESS )
10298 if ((RegQueryValueEx( hkLanman, "ReconnectableServers", 0,
10299 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10300 (dwType == REG_MULTI_SZ))
10302 dwAllocSize += 1 /* in case the source string is not nul terminated */
10303 + (DWORD)strlen(cm_NetbiosName) + 2;
10304 pHostNames = malloc(dwAllocSize);
10305 dwszReconnectableServers = dwAllocSize;
10306 if (RegQueryValueEx( hkLanman, "ReconnectableServers", 0, &dwType,
10307 pHostNames, &dwszReconnectableServers) == ERROR_SUCCESS)
10309 for (pName = pHostNames;
10310 (pName - pHostNames < (int) dwszReconnectableServers) && *pName ;
10311 pName += strlen(pName) + 1)
10313 if ( !stricmp(pName, cm_NetbiosName) ) {
10322 * If our name was not found and we are enabling SMB,
10323 * add our name to the current value.
10325 if ( bEnable && !bNameFound ) {
10326 if ( !pHostNames ) {
10327 pHostNames = malloc(nbsize);
10328 pName = pHostNames;
10330 StringCbCopyA(pName, nbsize, cm_NetbiosName);
10331 pName += nbsize - 1;
10332 *pName = '\0'; /* add a second nul terminator */
10334 dwType = REG_MULTI_SZ;
10335 dwSize = (DWORD)(pName - pHostNames + 1);
10336 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10340 * If our name was found and we are disabling SMB,
10341 * remove our name from the list and update the value.
10342 * If our name is the only entry, remove the value.
10344 if ( !bEnable && bNameFound ) {
10346 * we found our name so if the size of the value is smaller
10347 * or equal to the length of our name alone, we are done.
10349 if ( dwszReconnectableServers <= nbsize ) {
10350 RegDeleteValue( hkLanman, "ReconnectableServers");
10352 pOrigNames = pHostNames;
10353 pHostNames = malloc(dwAllocSize);
10355 pOrig = pOrigNames;
10356 pName = pHostNames;
10357 while (pOrig - pOrigNames <dwszReconnectableServers ) {
10358 len = strlen(pOrig);
10359 if ( stricmp(pOrig, cm_NetbiosName)) {
10361 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10366 *pName = '\0'; /* add a second nul terminator */
10369 dwType = REG_MULTI_SZ;
10370 dwSize = (DWORD)(pName - pHostNames + 1);
10371 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10385 if ((RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0,
10386 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10387 (dwType == REG_MULTI_SZ))
10389 dwAllocSize += 1 /* in case the source string is not nul terminated */
10390 + (DWORD)strlen(cm_NetbiosName) + 2;
10391 pHostNames = malloc(dwAllocSize);
10392 dwszServersWithExtendedSessTimeout = dwAllocSize;
10393 if (RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, &dwType,
10394 pHostNames, &dwszServersWithExtendedSessTimeout) == ERROR_SUCCESS)
10396 for (pName = pHostNames;
10397 (pName - pHostNames < (int) dwszServersWithExtendedSessTimeout) && *pName ;
10398 pName += strlen(pName) + 1)
10400 if ( !stricmp(pName, cm_NetbiosName) ) {
10409 * If our name was not found and we are enabling SMB,
10410 * add our name to the current value.
10412 if ( bEnable && !bNameFound ) {
10413 size_t size = strlen(cm_NetbiosName) + 2;
10414 if ( !pHostNames ) {
10415 pHostNames = malloc(size);
10416 pName = pHostNames;
10418 StringCbCopyA(pName, size, cm_NetbiosName);
10420 *pName = '\0'; /* add a second nul terminator */
10422 dwType = REG_MULTI_SZ;
10423 dwSize = (DWORD)(pName - pHostNames + 1);
10424 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10428 * If our name was found and we are disabling SMB,
10429 * remove our name from the list and update the value.
10430 * If our name is the only entry, remove the value.
10432 if ( !bEnable && bNameFound ) {
10434 * we found our name so if the size of the value is smaller
10435 * or equal to the length of our name alone, we are done.
10437 if ( dwszServersWithExtendedSessTimeout <= nbsize ) {
10438 RegDeleteValue( hkLanman, "ServersWithExtendedSessTimeout");
10440 pOrigNames = pHostNames;
10441 pHostNames = malloc(dwAllocSize);
10443 pOrig = pOrigNames;
10444 pName = pHostNames;
10445 while (pOrig - pOrigNames < dwszServersWithExtendedSessTimeout) {
10446 len = strlen(pOrig);
10447 if ( stricmp(pOrig, cm_NetbiosName)) {
10449 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10454 *pName = '\0'; /* add a second nul terminator */
10457 dwType = REG_MULTI_SZ;
10458 dwSize = (DWORD)(pName - pHostNames + 1);
10459 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10474 if ((RegQueryValueEx( hkLanman, "ExtendedSessTimeout", 0,
10475 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10476 (dwType != REG_DWORD))
10478 dwType = REG_DWORD;
10479 dwSize = sizeof(dwValue);
10480 dwValue = 300; /* 5 minutes */
10481 RegSetValueEx( hkLanman, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10484 RegCloseKey(hkLanman);
10489 smb_LanAdapterChangeThread(void *param)
10492 * Give the IPAddrDaemon thread a chance
10493 * to block before we trigger.
10496 smb_LanAdapterChange(0);
10499 void smb_SetLanAdapterChangeDetected(void)
10504 lock_ObtainMutex(&smb_StartedLock);
10506 if (!powerStateSuspended) {
10507 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10508 NULL, 0, &lpid, "smb_LanAdapterChange");
10509 if (phandle == NULL) {
10513 gle = GetLastError();
10514 StringCchPrintf( msg, sizeof(msg)/sizeof(msg[0]),
10515 "smb_LanAdapterChangeThread thread creation failure - gle 0x%x",
10517 osi_assertx(TRUE, msg);
10519 thrd_CloseHandle(phandle);
10522 smb_LanAdapterChangeDetected = 1;
10523 lock_ReleaseMutex(&smb_StartedLock);
10526 void smb_LanAdapterChange(int locked) {
10527 lana_number_t lanaNum;
10529 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
10531 LANA_ENUM temp_list;
10536 afsi_log("smb_LanAdapterChange");
10539 lock_ObtainMutex(&smb_StartedLock);
10541 smb_LanAdapterChangeDetected = 0;
10543 if (!powerStateSuspended &&
10544 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10545 LANA_NETBIOS_NAME_FULL | LANA_NETBIOS_NO_RESET)) &&
10546 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10547 if ( isGateway != bGateway ) {
10548 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10549 smb_LANadapter, lanaNum, isGateway, bGateway);
10551 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10552 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10553 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10556 NCB *ncbp = smb_GetNCB();
10557 ncbp->ncb_command = NCBENUM;
10558 ncbp->ncb_buffer = (PUCHAR)&temp_list;
10559 ncbp->ncb_length = sizeof(temp_list);
10560 code = Netbios(ncbp);
10562 if (temp_list.length != lana_list.length) {
10563 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10564 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10567 for (i=0; i<lana_list.length; i++) {
10568 if ( temp_list.lana[i] != lana_list.lana[i] ) {
10569 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10570 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10582 smb_StopListeners(1);
10583 smb_RestartListeners(1);
10586 lock_ReleaseMutex(&smb_StartedLock);
10589 /* initialize Netbios */
10590 int smb_NetbiosInit(int locked)
10593 int i, lana, code, l;
10595 int delname_tried=0;
10597 int lana_found = 0;
10598 lana_number_t lanaNum;
10604 lock_ObtainMutex(&smb_StartedLock);
10606 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10607 smb_ListenerState != SMB_LISTENER_STOPPED) {
10610 lock_ReleaseMutex(&smb_StartedLock);
10613 /* setup the NCB system */
10614 ncbp = smb_GetNCB();
10617 * Call lanahelper to get Netbios name, lan adapter number and gateway flag
10618 * This will reset all of the network adapter's netbios state.
10620 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10621 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10623 if (smb_LANadapter != LANA_INVALID)
10624 afsi_log("LAN adapter number %d", smb_LANadapter);
10626 afsi_log("LAN adapter number not determined");
10629 afsi_log("Set for gateway service");
10631 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10633 /* something went horribly wrong. We can't proceed without a netbios name */
10635 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10636 osi_panic(buf, __FILE__, __LINE__);
10639 /* remember the name */
10640 len = (int)strlen(cm_NetbiosName);
10641 if (smb_localNamep)
10642 free(smb_localNamep);
10643 smb_localNamep = malloc(len+1);
10644 strcpy(smb_localNamep, cm_NetbiosName);
10645 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10647 /* Also copy the value to the client character encoded string */
10648 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10650 if (smb_LANadapter == LANA_INVALID) {
10651 ncbp->ncb_command = NCBENUM;
10652 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10653 ncbp->ncb_length = sizeof(lana_list);
10654 code = Netbios(ncbp);
10656 afsi_log("Netbios NCBENUM error code %d", code);
10657 osi_panic(s, __FILE__, __LINE__);
10661 lana_list.length = 1;
10662 lana_list.lana[0] = smb_LANadapter;
10665 for (i = 0; i < lana_list.length; i++) {
10666 /* reset the adaptor: in Win32, this is required for every process, and
10667 * acts as an init call, not as a real hardware reset.
10669 ncbp->ncb_command = NCBRESET;
10670 ncbp->ncb_callname[0] = 100;
10671 ncbp->ncb_callname[2] = 100;
10672 ncbp->ncb_lana_num = lana_list.lana[i];
10673 code = Netbios(ncbp);
10675 code = ncbp->ncb_retcode;
10677 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10678 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10680 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10684 /* and declare our name so we can receive connections */
10685 memset(ncbp, 0, sizeof(*ncbp));
10686 len=lstrlen(smb_localNamep);
10687 memset(smb_sharename,' ',NCBNAMSZ);
10688 memcpy(smb_sharename,smb_localNamep,len);
10689 afsi_log("lana_list.length %d", lana_list.length);
10691 /* Keep the name so we can unregister it later */
10692 for (l = 0; l < lana_list.length; l++) {
10693 lana = lana_list.lana[l];
10695 ncbp->ncb_command = NCBADDNAME;
10696 ncbp->ncb_lana_num = lana;
10697 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10698 code = Netbios(ncbp);
10700 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10701 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10703 char name[NCBNAMSZ+1];
10705 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10706 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10710 code = ncbp->ncb_retcode;
10713 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10716 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10717 if (code == NRC_BRIDGE) { /* invalid LANA num */
10718 lana_list.lana[l] = LANA_INVALID;
10721 else if (code == NRC_DUPNAME) {
10722 afsi_log("Name already exists; try to delete it");
10723 memset(ncbp, 0, sizeof(*ncbp));
10724 ncbp->ncb_command = NCBDELNAME;
10725 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10726 ncbp->ncb_lana_num = lana;
10727 code = Netbios(ncbp);
10729 code = ncbp->ncb_retcode;
10731 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10733 if (code != 0 || delname_tried) {
10734 lana_list.lana[l] = LANA_INVALID;
10736 else if (code == 0) {
10737 if (!delname_tried) {
10745 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10746 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10750 smb_LANadapter = lana;
10751 lana_found = 1; /* at least one worked */
10755 osi_assertx(lana_list.length >= 0, "empty lana list");
10757 afsi_log("No valid LANA numbers found!");
10758 lana_list.length = 0;
10759 smb_LANadapter = LANA_INVALID;
10760 smb_ListenerState = SMB_LISTENER_STOPPED;
10761 cm_VolStatus_Network_Stopped(cm_NetbiosName
10768 /* we're done with the NCB now */
10771 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10772 if (lana_list.length > 0)
10773 osi_assert(smb_LANadapter != LANA_INVALID);
10776 lock_ReleaseMutex(&smb_StartedLock);
10778 return (lana_list.length > 0 ? 1 : 0);
10781 void smb_StartListeners(int locked)
10791 lock_ObtainMutex(&smb_StartedLock);
10793 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10795 lock_ReleaseMutex(&smb_StartedLock);
10799 afsi_log("smb_StartListeners");
10800 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10801 smb_configureBackConnectionHostNames(TRUE);
10803 /* Configure Extended SMB Session Timeouts */
10804 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10805 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10806 smb_configureExtendedSMBSessionTimeouts(TRUE);
10809 smb_ListenerState = SMB_LISTENER_STARTED;
10810 cm_VolStatus_Network_Started(cm_NetbiosName
10816 for (i = 0; i < lana_list.length; i++) {
10817 if (lana_list.lana[i] == LANA_INVALID)
10819 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10820 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10821 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10822 thrd_CloseHandle(phandle);
10825 lock_ReleaseMutex(&smb_StartedLock);
10828 void smb_RestartListeners(int locked)
10834 lock_ObtainMutex(&smb_StartedLock);
10836 if (powerStateSuspended)
10837 afsi_log("smb_RestartListeners called while suspended");
10839 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10840 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10841 if (smb_NetbiosInit(1))
10842 smb_StartListeners(1);
10843 } else if (smb_LanAdapterChangeDetected) {
10844 smb_LanAdapterChange(1);
10848 lock_ReleaseMutex(&smb_StartedLock);
10851 void smb_StopListener(NCB *ncbp, int lana, int wait)
10855 memset(ncbp, 0, sizeof(*ncbp));
10856 ncbp->ncb_command = NCBDELNAME;
10857 ncbp->ncb_lana_num = lana;
10858 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10859 code = Netbios(ncbp);
10861 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10862 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10864 /* and then reset the LANA; this will cause the listener threads to exit */
10865 ncbp->ncb_command = NCBRESET;
10866 ncbp->ncb_callname[0] = 100;
10867 ncbp->ncb_callname[2] = 100;
10868 ncbp->ncb_lana_num = lana;
10869 code = Netbios(ncbp);
10871 code = ncbp->ncb_retcode;
10873 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10875 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10879 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10882 void smb_StopListeners(int locked)
10891 lock_ObtainMutex(&smb_StartedLock);
10893 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10895 lock_ReleaseMutex(&smb_StartedLock);
10899 afsi_log("smb_StopListeners");
10900 smb_ListenerState = SMB_LISTENER_STOPPED;
10901 cm_VolStatus_Network_Stopped(cm_NetbiosName
10907 ncbp = smb_GetNCB();
10909 /* Unregister the SMB name */
10910 for (l = 0; l < lana_list.length; l++) {
10911 lana = lana_list.lana[l];
10913 if (lana != LANA_INVALID) {
10914 smb_StopListener(ncbp, lana, TRUE);
10916 /* mark the adapter invalid */
10917 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10921 /* force a re-evaluation of the network adapters */
10922 lana_list.length = 0;
10923 smb_LANadapter = LANA_INVALID;
10926 lock_ReleaseMutex(&smb_StartedLock);
10929 void smb_Init(osi_log_t *logp, int useV3,
10939 EVENT_HANDLE retHandle;
10940 char eventName[MAX_PATH];
10941 int startListeners = 0;
10946 smb_MBfunc = aMBfunc;
10950 /* Initialize smb_localZero */
10951 myTime.tm_isdst = -1; /* compute whether on DST or not */
10952 myTime.tm_year = 70;
10954 myTime.tm_mday = 1;
10955 myTime.tm_hour = 0;
10958 smb_localZero = mktime(&myTime);
10960 #ifdef AFS_FREELANCE_CLIENT
10961 /* Make sure the root.afs volume has the correct time */
10962 cm_noteLocalMountPointChange(FALSE);
10965 /* initialize the remote debugging log */
10968 /* and the global lock */
10969 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10970 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10972 /* Raw I/O data structures */
10973 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10975 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10976 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10978 /* 4 Raw I/O buffers */
10979 smb_RawBufs = calloc(65536,1);
10980 *((char **)smb_RawBufs) = NULL;
10981 for (i=0; i<3; i++) {
10982 char *rawBuf = calloc(65536,1);
10983 *((char **)rawBuf) = smb_RawBufs;
10984 smb_RawBufs = rawBuf;
10987 /* global free lists */
10988 smb_ncbFreeListp = NULL;
10989 smb_packetFreeListp = NULL;
10991 lock_ObtainMutex(&smb_StartedLock);
10992 startListeners = smb_NetbiosInit(1);
10994 /* Initialize listener and server structures */
10996 memset(dead_sessions, 0, sizeof(dead_sessions));
10997 sprintf(eventName, "SessionEvents[0]");
10998 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10999 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11000 afsi_log("Event Object Already Exists: %s", eventName);
11002 smb_NumServerThreads = nThreads;
11003 sprintf(eventName, "NCBavails[0]");
11004 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11005 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11006 afsi_log("Event Object Already Exists: %s", eventName);
11007 sprintf(eventName, "NCBevents[0]");
11008 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11009 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11010 afsi_log("Event Object Already Exists: %s", eventName);
11011 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
11012 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
11013 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11014 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11015 afsi_log("Event Object Already Exists: %s", eventName);
11016 for (i = 0; i < smb_NumServerThreads; i++) {
11017 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
11018 NCBreturns[i][0] = retHandle;
11021 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
11022 for (i = 0; i < smb_NumServerThreads; i++) {
11023 sprintf(eventName, "smb_ServerShutdown[%d]", i);
11024 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11025 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11026 afsi_log("Event Object Already Exists: %s", eventName);
11027 InitNCBslot((int)(i+1));
11029 numNCBs = smb_NumServerThreads + 1;
11031 /* Initialize dispatch table */
11032 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
11033 /* Prepare the table for unknown operations */
11034 for(i=0; i<= SMB_NOPCODES; i++) {
11035 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
11037 /* Fill in the ones we do know */
11038 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
11039 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
11040 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
11041 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
11042 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
11043 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
11044 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
11045 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
11046 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
11047 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
11048 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
11049 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
11050 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
11051 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
11052 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
11053 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
11054 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
11055 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
11056 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
11057 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
11058 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
11059 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11060 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
11061 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
11062 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
11063 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
11064 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
11065 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
11066 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11067 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
11068 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11069 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
11070 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
11071 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
11072 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11073 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
11074 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
11075 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
11076 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
11077 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
11078 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
11079 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
11080 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11081 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
11082 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11083 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
11084 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
11085 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
11086 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
11087 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
11088 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
11089 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
11090 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
11091 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
11092 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
11093 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
11094 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
11095 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
11096 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
11097 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
11098 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
11099 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
11100 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
11101 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
11102 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
11103 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11104 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
11105 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
11106 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
11107 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
11108 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
11109 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
11110 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
11111 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
11113 /* setup tran 2 dispatch table */
11114 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
11115 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
11116 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
11117 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
11118 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
11119 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
11120 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
11121 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
11122 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
11123 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
11124 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
11125 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
11126 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
11127 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
11128 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
11129 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
11130 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
11131 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
11133 /* setup the rap dispatch table */
11134 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
11135 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
11136 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
11137 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
11138 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
11142 /* if we are doing SMB authentication we have register outselves as a logon process */
11143 if (smb_authType != SMB_AUTH_NONE) {
11144 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
11145 LSA_STRING afsProcessName;
11146 LSA_OPERATIONAL_MODE dummy; /*junk*/
11148 afsProcessName.Buffer = "OpenAFSClientDaemon";
11149 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
11150 afsProcessName.MaximumLength = afsProcessName.Length + 1;
11152 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
11154 if (nts == STATUS_SUCCESS) {
11155 LSA_STRING packageName;
11156 /* we are registered. Find out the security package id */
11157 packageName.Buffer = MSV1_0_PACKAGE_NAME;
11158 packageName.Length = (USHORT)strlen(packageName.Buffer);
11159 packageName.MaximumLength = packageName.Length + 1;
11160 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
11161 if (nts == STATUS_SUCCESS) {
11163 * This code forces Windows to authenticate against the Logon Cache
11164 * first instead of attempting to authenticate against the Domain
11165 * Controller. When the Windows logon cache is enabled this improves
11166 * performance by removing the network access and works around a bug
11167 * seen at sites which are using a MIT Kerberos principal to login
11168 * to machines joined to a non-root domain in a multi-domain forest.
11169 * MsV1_0SetProcessOption was added in Windows XP.
11171 PVOID pResponse = NULL;
11172 ULONG cbResponse = 0;
11173 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
11175 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
11176 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
11177 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
11178 OptionsRequest.DisableOptions = FALSE;
11180 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
11183 sizeof(OptionsRequest),
11189 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
11190 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
11193 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
11195 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
11196 afsi_log("MsV1_0SetProcessOption success");
11198 /* END - code from Larry */
11200 smb_lsaLogonOrigin.Buffer = "OpenAFS";
11201 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
11202 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
11204 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
11206 /* something went wrong. We report the error and revert back to no authentication
11207 because we can't perform any auth requests without a successful lsa handle
11208 or sec package id. */
11209 afsi_log("Reverting to NO SMB AUTH");
11210 smb_authType = SMB_AUTH_NONE;
11213 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
11215 /* something went wrong. We report the error and revert back to no authentication
11216 because we can't perform any auth requests without a successful lsa handle
11217 or sec package id. */
11218 afsi_log("Reverting to NO SMB AUTH");
11219 smb_authType = SMB_AUTH_NONE;
11223 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
11224 * time prevents the failure of authentication when logged into Windows with an
11225 * external Kerberos principal mapped to a local account.
11227 else if ( smb_authType == SMB_AUTH_EXTENDED) {
11228 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
11229 * then the only option is NTLMSSP anyway; so just fallback.
11234 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
11235 if (secBlobLength == 0) {
11236 smb_authType = SMB_AUTH_NTLM;
11237 afsi_log("Reverting to SMB AUTH NTLM");
11246 /* Now get ourselves a domain name. */
11247 /* For now we are using the local computer name as the domain name.
11248 * It is actually the domain for local logins, and we are acting as
11249 * a local SMB server.
11251 bufsize = lengthof(smb_ServerDomainName) - 1;
11252 GetComputerNameW(smb_ServerDomainName, &bufsize);
11253 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
11254 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
11257 /* Start listeners, waiters, servers, and daemons */
11258 if (startListeners)
11259 smb_StartListeners(1);
11261 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
11262 NULL, 0, &lpid, "smb_ClientWaiter");
11263 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
11264 thrd_CloseHandle(phandle);
11266 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
11267 NULL, 0, &lpid, "smb_ServerWaiter");
11268 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
11269 thrd_CloseHandle(phandle);
11271 for (i=0; i<smb_NumServerThreads; i++) {
11272 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
11273 (void *) i, 0, &lpid, "smb_Server");
11274 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
11275 thrd_CloseHandle(phandle);
11278 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
11279 NULL, 0, &lpid, "smb_Daemon");
11280 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
11281 thrd_CloseHandle(phandle);
11283 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
11284 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
11285 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
11286 thrd_CloseHandle(phandle);
11288 if (smb_monitorReqs) {
11289 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
11290 NULL, 0, &lpid, "smb_ServerMonitor");
11291 osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
11292 thrd_CloseHandle(phandle);
11295 lock_ReleaseMutex(&smb_StartedLock);
11299 void smb_Shutdown(void)
11309 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11311 /* setup the NCB system */
11312 ncbp = smb_GetNCB();
11314 /* Block new sessions by setting shutdown flag */
11315 smbShutdownFlag = 1;
11317 /* Hang up all sessions */
11318 memset(ncbp, 0, sizeof(NCB));
11319 for (i = 1; i < numSessions; i++)
11321 if (dead_sessions[i])
11324 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11325 ncbp->ncb_command = NCBHANGUP;
11326 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
11327 ncbp->ncb_lsn = (UCHAR)LSNs[i];
11328 code = Netbios(ncbp);
11329 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11330 if (code == 0) code = ncbp->ncb_retcode;
11332 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11333 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11337 /* Trigger the shutdown of all SMB threads */
11338 for (i = 0; i < smb_NumServerThreads; i++)
11339 thrd_SetEvent(NCBreturns[i][0]);
11341 thrd_SetEvent(NCBevents[0]);
11342 thrd_SetEvent(SessionEvents[0]);
11343 thrd_SetEvent(NCBavails[0]);
11345 for (i = 0;i < smb_NumServerThreads; i++) {
11346 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11347 if (code == WAIT_OBJECT_0) {
11350 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11351 thrd_SetEvent(NCBreturns[i--][0]);
11355 /* Delete Netbios name */
11356 memset(ncbp, 0, sizeof(NCB));
11357 for (i = 0; i < lana_list.length; i++) {
11358 if (lana_list.lana[i] == LANA_INVALID) continue;
11359 ncbp->ncb_command = NCBDELNAME;
11360 ncbp->ncb_lana_num = lana_list.lana[i];
11361 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11362 code = Netbios(ncbp);
11364 code = ncbp->ncb_retcode;
11366 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11367 ncbp->ncb_lana_num, code);
11372 /* Release the reference counts held by the VCs */
11373 lock_ObtainWrite(&smb_rctLock);
11374 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11379 if (vcp->magic != SMB_VC_MAGIC)
11380 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11381 __FILE__, __LINE__);
11383 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11385 if (fidp->scp != NULL) {
11388 lock_ReleaseWrite(&smb_rctLock);
11389 lock_ObtainMutex(&fidp->mx);
11390 if (fidp->scp != NULL) {
11393 lock_ObtainWrite(&scp->rw);
11394 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11395 lock_ReleaseWrite(&scp->rw);
11396 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11397 cm_ReleaseSCache(scp);
11399 lock_ReleaseMutex(&fidp->mx);
11400 lock_ObtainWrite(&smb_rctLock);
11404 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11406 smb_ReleaseVCNoLock(tidp->vcp);
11408 cm_user_t *userp = tidp->userp;
11409 tidp->userp = NULL;
11410 cm_ReleaseUser(userp);
11414 lock_ReleaseWrite(&smb_rctLock);
11417 if (smb_monitorReqs) {
11418 smb_ShutdownMonitor();
11422 /* Get the UNC \\<servername>\<sharename> prefix. */
11423 char *smb_GetSharename()
11428 /* Make sure we have been properly initialized. */
11429 if (smb_localNamep == NULL)
11432 /* Allocate space for \\<servername>\<sharename>, plus the
11435 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11436 name = malloc(len);
11437 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11443 void smb_LogPacket(smb_packet_t *packet)
11447 unsigned length, paramlen, datalen, i, j;
11449 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11451 if (!packet) return;
11453 osi_Log0(smb_logp, "*** SMB packet dump ***");
11455 smbp = (smb_t *) packet->data;
11456 vp = (BYTE *) packet->data;
11458 paramlen = smbp->wct * 2;
11459 datalen = *((WORD *) (smbp->vdata + paramlen));
11460 length = sizeof(*smbp) + paramlen + 1 + datalen;
11462 for (i=0;i < length; i+=16)
11464 memset( buf, ' ', 80 );
11467 itoa( i, buf, 16 );
11469 buf[strlen(buf)] = ' ';
11471 cp = (BYTE*) buf + 7;
11473 for (j=0;j < 16 && (i+j)<length; j++)
11475 *(cp++) = hex[vp[i+j] >> 4];
11476 *(cp++) = hex[vp[i+j] & 0xf];
11486 for (j=0;j < 16 && (i+j)<length;j++)
11488 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11499 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11502 osi_Log0(smb_logp, "*** End SMB packet dump ***");
11504 #endif /* LOG_PACKET */
11507 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11513 smb_username_t *unp;
11514 smb_waitingLockRequest_t *wlrp;
11517 lock_ObtainRead(&smb_rctLock);
11519 sprintf(output, "begin dumping smb_username_t\r\n");
11520 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11521 for (unp = usernamesp; unp; unp=unp->nextp)
11523 cm_ucell_t *ucellp;
11525 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11526 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11527 unp->name ? unp->name : _C("NULL"),
11528 unp->machine ? unp->machine : _C("NULL"));
11529 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11531 sprintf(output, " begin dumping cm_ucell_t\r\n");
11532 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11534 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11535 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",
11536 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11537 ucellp->expirationTime, ucellp->gen,
11539 ucellp->cellp ? ucellp->cellp->name : "<null>");
11540 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11543 sprintf(output, " done dumping cm_ucell_t\r\n");
11544 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11547 sprintf(output, "done dumping smb_username_t\r\n");
11548 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11554 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11555 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11557 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11558 smb_waitingLock_t *lockp;
11560 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11561 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11562 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11564 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
11565 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11566 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11567 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11568 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11569 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11571 sprintf(output, " done dumping smb_waitingLock_t\r\n");
11572 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11575 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11576 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11578 sprintf(output, "begin dumping smb_vc_t\r\n");
11579 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11581 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11587 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11588 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11589 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11591 sprintf(output, " begin dumping smb_user_t\r\n");
11592 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11593 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11594 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11595 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11596 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11598 sprintf(output, " done dumping smb_user_t\r\n");
11599 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11601 sprintf(output, " begin dumping smb_tid_t\r\n");
11602 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11603 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11604 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",
11605 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11606 tidp->pathname ? tidp->pathname : _C("NULL"));
11607 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11609 sprintf(output, " done dumping smb_tid_t\r\n");
11610 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11612 sprintf(output, " begin dumping smb_fid_t\r\n");
11613 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11615 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11617 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",
11618 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11619 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11620 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11621 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11624 sprintf(output, " done dumping smb_fid_t\r\n");
11625 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11628 sprintf(output, "done dumping smb_vc_t\r\n");
11629 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11631 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11632 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11634 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11640 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11641 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11642 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11644 sprintf(output, " begin dumping smb_user_t\r\n");
11645 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11646 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11647 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11648 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11649 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11651 sprintf(output, " done dumping smb_user_t\r\n");
11652 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11654 sprintf(output, " begin dumping smb_tid_t\r\n");
11655 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11656 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11657 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",
11658 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11659 tidp->pathname ? tidp->pathname : _C("NULL"));
11660 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11662 sprintf(output, " done dumping smb_tid_t\r\n");
11663 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11665 sprintf(output, " begin dumping smb_fid_t\r\n");
11666 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11668 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11670 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",
11671 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11672 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11673 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11674 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11677 sprintf(output, " done dumping smb_fid_t\r\n");
11678 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11681 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11682 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11686 lock_ReleaseRead(&smb_rctLock);
11690 long smb_IsNetworkStarted(void)
11697 lock_ObtainWrite(&smb_globalLock);
11698 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11699 lock_ReleaseWrite(&smb_globalLock);