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);
3912 if (VistaProtoIndex != -1) {
3913 protoIndex = VistaProtoIndex;
3914 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3917 if (NTProtoIndex != -1) {
3918 protoIndex = NTProtoIndex;
3919 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3921 else if (v3ProtoIndex != -1) {
3922 protoIndex = v3ProtoIndex;
3923 vcp->flags |= SMB_VCFLAG_USEV3;
3925 else if (coreProtoIndex != -1) {
3926 protoIndex = coreProtoIndex;
3927 vcp->flags |= SMB_VCFLAG_USECORE;
3929 else protoIndex = -1;
3930 lock_ReleaseMutex(&vcp->mx);
3932 if (protoIndex == -1)
3933 return CM_ERROR_INVAL;
3934 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3935 smb_SetSMBParm(outp, 0, protoIndex);
3936 if (smb_authType != SMB_AUTH_NONE) {
3937 smb_SetSMBParmByte(outp, 1,
3938 NEGOTIATE_SECURITY_USER_LEVEL |
3939 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3941 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3943 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3944 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3945 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3946 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3947 /* The session key is not a well documented field however most clients
3948 * will echo back the session key to the server. Currently we are using
3949 * the same value for all sessions. We should generate a random value
3950 * and store it into the vcp
3952 smb_SetSMBParmLong(outp, 7, 0x1a2b3c4d); /* session key */
3954 * Tried changing the capabilities to support for W2K - defect 117695
3955 * Maybe something else needs to be changed here?
3959 smb_SetSMBParmLong(outp, 9, 0x43fd);
3961 smb_SetSMBParmLong(outp, 9, 0x251);
3964 * 32-bit error codes *
3970 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3972 NTNEGOTIATE_CAPABILITY_DFS |
3974 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3975 NTNEGOTIATE_CAPABILITY_NTFIND |
3976 NTNEGOTIATE_CAPABILITY_RAWMODE |
3977 NTNEGOTIATE_CAPABILITY_NTSMB;
3979 if ( smb_authType == SMB_AUTH_EXTENDED )
3980 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3983 if ( smb_UseUnicode ) {
3984 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3988 smb_SetSMBParmLong(outp, 9, caps);
3990 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3991 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3992 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3994 GetTimeZoneInformation(&tzi);
3995 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3997 if (smb_authType == SMB_AUTH_NTLM) {
3998 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3999 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
4000 /* paste in encryption key */
4001 datap = smb_GetSMBData(outp, NULL);
4002 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
4003 /* and the faux domain name */
4004 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4005 datap + MSV1_0_CHALLENGE_LENGTH,
4006 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4007 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
4008 void * secBlob = NULL;
4009 int secBlobLength = 0;
4011 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
4014 * The SMB specification permits the server to save a round trip
4015 * in the GSS negotiation by sending an initial security blob.
4016 * Unfortunately, doing so trips a bug in Windows 7 and Server 2008 R2
4017 * whereby the SMB 1.x redirector drops the blob on the floor after
4018 * the first connection to the server and simply attempts to reuse
4019 * the previous authentication context. This bug can be avoided by
4020 * the server sending no security blob in the SMB_COM_NEGOTIATE
4021 * response. This forces the client to send an initial GSS init_sec_context
4022 * blob under all circumstances which works around the bug in Microsoft's
4025 * Do not call smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
4028 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
4029 datap = smb_GetSMBData(outp, NULL);
4031 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
4032 datap += sizeof(smb_ServerGUID);
4035 memcpy(datap, secBlob, secBlobLength);
4037 datap += sizeof(secBlobLength);
4040 smb_SetSMBParmByte(outp, 16, 0);/* Challenge length */
4041 smb_SetSMBDataLength(outp, smb_ServerDomainNameLength);
4042 datap = smb_GetSMBData(outp, NULL);
4043 /* the faux domain name */
4044 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4046 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4049 else if (v3ProtoIndex != -1) {
4050 smb_SetSMBParm(outp, 0, protoIndex);
4052 /* NOTE: Extended authentication cannot be negotiated with v3
4053 * therefore we fail over to NTLM
4055 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4056 smb_SetSMBParm(outp, 1,
4057 NEGOTIATE_SECURITY_USER_LEVEL |
4058 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
4060 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4062 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4063 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
4064 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
4065 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
4066 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
4067 smb_SetSMBParm(outp, 7, 1);
4069 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
4070 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
4071 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
4073 GetTimeZoneInformation(&tzi);
4074 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
4076 /* NOTE: Extended authentication cannot be negotiated with v3
4077 * therefore we fail over to NTLM
4079 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4080 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
4081 smb_SetSMBParm(outp, 12, 0); /* resvd */
4082 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
4083 datap = smb_GetSMBData(outp, NULL);
4084 /* paste in a new encryption key */
4085 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4086 /* and the faux domain name */
4087 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4088 datap + MSV1_0_CHALLENGE_LENGTH,
4089 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4091 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4092 smb_SetSMBParm(outp, 12, 0); /* resvd */
4093 smb_SetSMBDataLength(outp, 0);
4096 else if (coreProtoIndex != -1) { /* not really supported anymore */
4097 smb_SetSMBParm(outp, 0, protoIndex);
4098 smb_SetSMBDataLength(outp, 0);
4103 void smb_CheckVCs(void)
4105 smb_vc_t * vcp, *nextp;
4106 smb_packet_t * outp = smb_GetPacket();
4109 lock_ObtainWrite(&smb_rctLock);
4110 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4112 if (vcp->magic != SMB_VC_MAGIC)
4113 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4114 __FILE__, __LINE__);
4116 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4118 smb_HoldVCNoLock(vcp);
4121 * obtain a reference to 'nextp' now because we drop the
4122 * smb_rctLock later and the list contents could change
4123 * or 'vcp' could be destroyed when released.
4127 smb_HoldVCNoLock(nextp);
4129 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4130 smb_ReleaseVCNoLock(vcp);
4134 smb_FormatResponsePacket(vcp, NULL, outp);
4135 smbp = (smb_t *)outp;
4136 outp->inCom = smbp->com = 0x2b /* Echo */;
4144 smb_SetSMBParm(outp, 0, 0);
4145 smb_SetSMBDataLength(outp, 0);
4146 lock_ReleaseWrite(&smb_rctLock);
4148 smb_SendPacket(vcp, outp);
4150 lock_ObtainWrite(&smb_rctLock);
4151 smb_ReleaseVCNoLock(vcp);
4153 lock_ReleaseWrite(&smb_rctLock);
4154 smb_FreePacket(outp);
4157 void smb_Daemon(void *parmp)
4159 afs_uint32 count = 0;
4160 smb_username_t **unpp;
4163 while(smbShutdownFlag == 0) {
4167 if (smbShutdownFlag == 1)
4170 if ((count % 72) == 0) { /* every five minutes */
4172 time_t old_localZero = smb_localZero;
4174 /* Initialize smb_localZero */
4175 myTime.tm_isdst = -1; /* compute whether on DST or not */
4176 myTime.tm_year = 70;
4182 smb_localZero = mktime(&myTime);
4184 #ifdef AFS_FREELANCE
4185 if ( smb_localZero != old_localZero )
4186 cm_noteLocalMountPointChange(FALSE);
4192 /* GC smb_username_t objects that will no longer be used */
4194 lock_ObtainWrite(&smb_rctLock);
4195 for ( unpp=&usernamesp; *unpp; ) {
4197 smb_username_t *unp;
4199 lock_ObtainMutex(&(*unpp)->mx);
4200 if ( (*unpp)->refCount > 0 ||
4201 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4202 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4204 else if (!smb_LogoffTokenTransfer ||
4205 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4207 lock_ReleaseMutex(&(*unpp)->mx);
4215 lock_FinalizeMutex(&unp->mx);
4221 cm_ReleaseUser(userp);
4223 unpp = &(*unpp)->nextp;
4226 lock_ReleaseWrite(&smb_rctLock);
4228 /* XXX GC dir search entries */
4232 void smb_WaitingLocksDaemon()
4234 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4235 smb_waitingLock_t *wl, *wlNext;
4238 smb_packet_t *inp, *outp;
4242 while (smbShutdownFlag == 0) {
4243 lock_ObtainWrite(&smb_globalLock);
4244 nwlRequest = smb_allWaitingLocks;
4245 if (nwlRequest == NULL) {
4246 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4251 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4258 lock_ObtainWrite(&smb_globalLock);
4260 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4262 wlRequest = nwlRequest;
4263 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4264 lock_ReleaseWrite(&smb_globalLock);
4268 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4269 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4272 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4273 code = CM_ERROR_LOCK_NOT_GRANTED;
4277 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4279 /* wl->state is either _DONE or _WAITING. _ERROR
4280 would no longer be on the queue. */
4281 code = cm_RetryLock( wl->lockp,
4282 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4285 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4286 } else if (code != CM_ERROR_WOULDBLOCK) {
4287 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4292 if (code == CM_ERROR_WOULDBLOCK) {
4295 if (wlRequest->msTimeout != 0xffffffff
4296 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4308 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4311 scp = wlRequest->scp;
4312 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4316 lock_ObtainWrite(&scp->rw);
4318 for (wl = wlRequest->locks; wl; wl = wlNext) {
4319 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4321 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4322 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4323 wl->LLength, wl->key, 0, NULL, &req);
4325 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4330 lock_ReleaseWrite(&scp->rw);
4334 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4337 for (wl = wlRequest->locks; wl; wl = wlNext) {
4338 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4339 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4344 vcp = wlRequest->vcp;
4345 inp = wlRequest->inp;
4346 outp = wlRequest->outp;
4347 ncbp = smb_GetNCB();
4348 ncbp->ncb_length = inp->ncb_length;
4349 inp->spacep = cm_GetSpace();
4351 /* Remove waitingLock from list */
4352 lock_ObtainWrite(&smb_globalLock);
4353 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4355 lock_ReleaseWrite(&smb_globalLock);
4357 /* Resume packet processing */
4359 smb_SetSMBDataLength(outp, 0);
4360 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4361 outp->resumeCode = code;
4363 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4366 cm_FreeSpace(inp->spacep);
4367 smb_FreePacket(inp);
4368 smb_FreePacket(outp);
4370 cm_ReleaseSCache(wlRequest->scp);
4373 } while (nwlRequest && smbShutdownFlag == 0);
4378 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4380 osi_Log0(smb_logp, "SMB receive get disk attributes");
4382 smb_SetSMBParm(outp, 0, 32000);
4383 smb_SetSMBParm(outp, 1, 64);
4384 smb_SetSMBParm(outp, 2, 1024);
4385 smb_SetSMBParm(outp, 3, 30000);
4386 smb_SetSMBParm(outp, 4, 0);
4387 smb_SetSMBDataLength(outp, 0);
4391 /* SMB_COM_TREE_CONNECT */
4392 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4396 unsigned short newTid;
4397 clientchar_t shareName[AFSPATHMAX];
4398 clientchar_t *sharePath;
4401 clientchar_t *pathp;
4404 osi_Log0(smb_logp, "SMB receive tree connect");
4406 /* parse input parameters */
4409 tbp = smb_GetSMBData(inp, NULL);
4410 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4412 return CM_ERROR_BADSMB;
4414 tp = cm_ClientStrRChr(pathp, '\\');
4416 return CM_ERROR_BADSMB;
4417 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4419 lock_ObtainMutex(&vcp->mx);
4420 newTid = vcp->tidCounter++;
4421 lock_ReleaseMutex(&vcp->mx);
4423 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4424 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4426 return CM_ERROR_BADSMB;
4427 userp = smb_GetUserFromUID(uidp);
4428 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4429 smb_ReleaseUID(uidp);
4431 smb_ReleaseTID(tidp, FALSE);
4432 return CM_ERROR_BADSHARENAME;
4434 lock_ObtainMutex(&tidp->mx);
4435 tidp->userp = userp;
4436 tidp->pathname = sharePath;
4437 lock_ReleaseMutex(&tidp->mx);
4438 smb_ReleaseTID(tidp, FALSE);
4440 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4441 smb_SetSMBParm(rsp, 1, newTid);
4442 smb_SetSMBDataLength(rsp, 0);
4444 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4448 /* set maskp to the mask part of the incoming path.
4449 * Mask is 11 bytes long (8.3 with the dot elided).
4450 * Returns true if succeeds with a valid name, otherwise it does
4451 * its best, but returns false.
4453 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4461 /* starts off valid */
4464 /* mask starts out all blanks */
4465 memset(maskp, ' ', 11);
4468 /* find last backslash, or use whole thing if there is none */
4469 tp = cm_ClientStrRChr(pathp, '\\');
4473 tp++; /* skip slash */
4477 /* names starting with a dot are illegal */
4485 if (tc == '.' || tc == '"')
4493 /* if we get here, tp point after the dot */
4494 up = maskp+8; /* ext goes here */
4501 if (tc == '.' || tc == '"')
4504 /* copy extension if not too long */
4514 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4516 clientchar_t umask[11];
4524 /* XXX redo this, calling cm_MatchMask with a converted mask */
4526 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4530 /* otherwise, we have a valid 8.3 name; see if we have a match,
4531 * treating '?' as a wildcard in maskp (but not in the file name).
4533 tp1 = umask; /* real name, in mask format */
4534 tp2 = maskp; /* mask, in mask format */
4535 for(i=0; i<11; i++) {
4536 tc1 = *tp1++; /* clientchar_t from real name */
4537 tc2 = *tp2++; /* clientchar_t from mask */
4538 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4539 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4542 if (tc2 == '?' && tc1 != ' ')
4549 /* we got a match */
4553 clientchar_t *smb_FindMask(clientchar_t *pathp)
4557 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4560 return tp+1; /* skip the slash */
4562 return pathp; /* no slash, return the entire path */
4565 /* SMB_COM_SEARCH for a volume label
4567 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4568 dispatch function.) */
4569 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4571 clientchar_t *pathp;
4573 clientchar_t mask[12];
4574 unsigned char *statBlockp;
4575 unsigned char initStatBlock[21];
4578 osi_Log0(smb_logp, "SMB receive search volume");
4580 /* pull pathname and stat block out of request */
4581 tp = smb_GetSMBData(inp, NULL);
4582 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4583 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4585 return CM_ERROR_BADSMB;
4586 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4587 osi_assertx(statBlockp != NULL, "null statBlock");
4589 statBlockp = initStatBlock;
4593 /* for returning to caller */
4594 smb_Get8Dot3MaskFromPath(mask, pathp);
4596 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4597 tp = smb_GetSMBData(outp, NULL);
4599 *tp++ = 43; /* bytes in a dir entry */
4600 *tp++ = 0; /* high byte in counter */
4602 /* now marshall the dir entry, starting with the search status */
4603 *tp++ = statBlockp[0]; /* Reserved */
4604 memcpy(tp, mask, 11); tp += 11; /* FileName */
4606 /* now pass back server use info, with 1st byte non-zero */
4608 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4610 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4612 *tp++ = 0x8; /* attribute: volume */
4622 /* 4 byte file size */
4628 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4631 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4632 memset(tp, ' ', 13);
4635 /* set the length of the data part of the packet to 43 + 3, for the dir
4636 * entry plus the 5 and the length fields.
4638 smb_SetSMBDataLength(outp, 46);
4643 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4644 clientchar_t * tidPathp, clientchar_t * relPathp,
4645 cm_user_t *userp, cm_req_t *reqp)
4653 smb_dirListPatch_t *patchp;
4654 smb_dirListPatch_t *npatchp;
4655 clientchar_t path[AFSPATHMAX];
4657 afs_int32 mustFake = 0;
4658 afs_int32 nobulkstat = 0;
4660 lock_ObtainWrite(&dscp->rw);
4661 code = cm_FindACLCache(dscp, userp, &rights);
4663 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4664 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4665 if (code == CM_ERROR_NOACCESS) {
4670 lock_ReleaseWrite(&dscp->rw);
4674 if (!mustFake) { /* Bulk Stat */
4676 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4678 memset(bsp, 0, sizeof(cm_bulkStat_t));
4682 for (patchp = *dirPatchespp, count=0;
4684 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4685 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4689 if (lock_TryWrite(&tscp->rw)) {
4690 /* we have an entry that we can look at */
4691 if (!cm_EAccesFindEntry(userp, &tscp->fid) && cm_HaveCallback(tscp)) {
4692 /* we have a callback on it. Don't bother
4693 * fetching this stat entry, since we're happy
4694 * with the info we have.
4696 lock_ReleaseWrite(&tscp->rw);
4697 cm_ReleaseSCache(tscp);
4702 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4703 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4704 lock_ReleaseWrite(&tscp->rw);
4705 cm_ReleaseSCache(tscp);
4709 lock_ReleaseWrite(&tscp->rw);
4711 cm_ReleaseSCache(tscp);
4715 bsp->fids[i].Volume = patchp->fid.volume;
4716 bsp->fids[i].Vnode = patchp->fid.vnode;
4717 bsp->fids[i].Unique = patchp->fid.unique;
4719 if (bsp->counter == AFSCBMAX) {
4720 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4721 memset(bsp, 0, sizeof(cm_bulkStat_t));
4724 if (code == CM_ERROR_BULKSTAT_FAILURE) {
4726 * If bulk stat cannot be used for this directory
4727 * we must perform individual fetch status calls.
4728 * Restart from the beginning of the patch series.
4731 goto restart_patchset;
4736 if (bsp->counter > 0)
4737 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4742 for (patchp = *dirPatchespp; patchp; patchp =
4743 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4745 dptr = patchp->dptr;
4747 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4748 relPathp ? relPathp : _C(""), patchp->dep->name);
4749 reqp->relPathp = path;
4750 reqp->tidPathp = tidPathp;
4752 code = cm_GetSCache(&patchp->fid, &dscp->fid, &scp, userp, reqp);
4753 reqp->relPathp = reqp->tidPathp = NULL;
4756 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4757 *dptr++ = SMB_ATTR_HIDDEN;
4760 lock_ObtainWrite(&scp->rw);
4761 if (mustFake || cm_EAccesFindEntry(userp, &scp->fid) || !cm_HaveCallback(scp)) {
4762 lock_ReleaseWrite(&scp->rw);
4764 /* set the attribute */
4765 switch (scp->fileType) {
4766 case CM_SCACHETYPE_DIRECTORY:
4767 case CM_SCACHETYPE_MOUNTPOINT:
4768 case CM_SCACHETYPE_INVALID:
4769 attr = SMB_ATTR_DIRECTORY;
4771 case CM_SCACHETYPE_SYMLINK:
4772 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4773 attr = SMB_ATTR_DIRECTORY;
4775 attr = SMB_ATTR_NORMAL;
4778 /* if we get here we either have a normal file
4779 * or we have a file for which we have never
4780 * received status info. In this case, we can
4781 * check the even/odd value of the entry's vnode.
4782 * odd means it is to be treated as a directory
4783 * and even means it is to be treated as a file.
4785 if (mustFake && (scp->fid.vnode & 0x1))
4786 attr = SMB_ATTR_DIRECTORY;
4788 attr = SMB_ATTR_NORMAL;
4792 /* 1969-12-31 23:59:58 +00*/
4793 dosTime = 0xEBBFBF7D;
4796 shortTemp = (unsigned short) (dosTime & 0xffff);
4797 *((u_short *)dptr) = shortTemp;
4800 /* and copy out date */
4801 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4802 *((u_short *)dptr) = shortTemp;
4805 /* copy out file length */
4806 *((u_long *)dptr) = 0;
4809 lock_ConvertWToR(&scp->rw);
4810 attr = smb_Attributes(scp);
4811 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4812 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4813 attr |= SMB_ATTR_HIDDEN;
4817 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4820 shortTemp = (unsigned short) (dosTime & 0xffff);
4821 *((u_short *)dptr) = shortTemp;
4824 /* and copy out date */
4825 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4826 *((u_short *)dptr) = shortTemp;
4829 /* copy out file length */
4830 *((u_long *)dptr) = scp->length.LowPart;
4832 lock_ReleaseRead(&scp->rw);
4834 cm_ReleaseSCache(scp);
4837 /* now free the patches */
4838 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4839 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4843 /* and mark the list as empty */
4844 *dirPatchespp = NULL;
4850 /* SMB_COM_SEARCH */
4851 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4857 clientchar_t *pathp;
4858 cm_dirEntry_t *dep = 0;
4860 smb_dirListPatch_t *dirListPatchesp;
4861 smb_dirListPatch_t *curPatchp;
4865 osi_hyper_t dirLength;
4866 osi_hyper_t bufferOffset;
4867 osi_hyper_t curOffset;
4869 unsigned char *inCookiep;
4870 smb_dirSearch_t *dsp;
4874 unsigned long clientCookie;
4875 cm_pageHeader_t *pageHeaderp;
4876 cm_user_t *userp = NULL;
4878 clientchar_t mask[12];
4880 long nextEntryCookie;
4881 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4882 char resByte; /* reserved byte from the cookie */
4883 char *op; /* output data ptr */
4884 char *origOp; /* original value of op */
4885 cm_space_t *spacep; /* for pathname buffer */
4889 clientchar_t *tidPathp = 0;
4896 maxCount = smb_GetSMBParm(inp, 0);
4898 dirListPatchesp = NULL;
4900 caseFold = CM_FLAG_CASEFOLD;
4902 tp = smb_GetSMBData(inp, NULL);
4903 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4904 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4906 return CM_ERROR_BADSMB;
4908 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4910 return CM_ERROR_BADSMB;
4912 /* We can handle long names */
4913 if (vcp->flags & SMB_VCFLAG_USENT)
4914 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4916 /* make sure we got a whole search status */
4917 if (dataLength < 21) {
4918 nextCookie = 0; /* start at the beginning of the dir */
4921 attribute = smb_GetSMBParm(inp, 1);
4923 /* handle volume info in another function */
4924 if (attribute & 0x8)
4925 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4927 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4928 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4930 if (*pathp == 0) { /* null pathp, treat as root dir */
4931 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4932 return CM_ERROR_NOFILES;
4936 dsp = smb_NewDirSearch(0);
4937 dsp->attribute = attribute;
4938 smb_Get8Dot3MaskFromPath(mask, pathp);
4939 memcpy(dsp->mask, mask, 12);
4941 /* track if this is likely to match a lot of entries */
4942 if (smb_Is8Dot3StarMask(mask))
4947 /* pull the next cookie value out of the search status block */
4948 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4949 + (inCookiep[16]<<24);
4950 dsp = smb_FindDirSearch(inCookiep[12]);
4952 /* can't find dir search status; fatal error */
4953 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4954 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4955 return CM_ERROR_BADFD;
4957 attribute = dsp->attribute;
4958 resByte = inCookiep[0];
4960 /* copy out client cookie, in host byte order. Don't bother
4961 * interpreting it, since we're just passing it through, anyway.
4963 memcpy(&clientCookie, &inCookiep[17], 4);
4965 memcpy(mask, dsp->mask, 12);
4967 /* assume we're doing a star match if it has continued for more
4973 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4974 nextCookie, dsp->cookie, attribute);
4976 userp = smb_GetUserFromVCP(vcp, inp);
4978 /* try to get the vnode for the path name next */
4979 lock_ObtainMutex(&dsp->mx);
4982 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4986 spacep = inp->spacep;
4987 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4988 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4990 lock_ReleaseMutex(&dsp->mx);
4991 cm_ReleaseUser(userp);
4992 smb_DeleteDirSearch(dsp);
4993 smb_ReleaseDirSearch(dsp);
4994 return CM_ERROR_NOFILES;
4996 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4997 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4999 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5000 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
5003 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5006 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
5007 cm_ReleaseSCache(scp);
5008 lock_ReleaseMutex(&dsp->mx);
5009 cm_ReleaseUser(userp);
5010 smb_DeleteDirSearch(dsp);
5011 smb_ReleaseDirSearch(dsp);
5012 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5013 return CM_ERROR_PATH_NOT_COVERED;
5015 return CM_ERROR_NOSUCHPATH;
5017 #endif /* DFS_SUPPORT */
5020 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
5021 /* we need one hold for the entry we just stored into,
5022 * and one for our own processing. When we're done with this
5023 * function, we'll drop the one for our own processing.
5024 * We held it once from the namei call, and so we do another hold
5028 lock_ObtainWrite(&scp->rw);
5029 dsp->flags |= SMB_DIRSEARCH_BULKST;
5030 lock_ReleaseWrite(&scp->rw);
5033 lock_ReleaseMutex(&dsp->mx);
5035 cm_ReleaseUser(userp);
5036 smb_DeleteDirSearch(dsp);
5037 smb_ReleaseDirSearch(dsp);
5041 /* reserves space for parameter; we'll adjust it again later to the
5042 * real count of the # of entries we returned once we've actually
5043 * assembled the directory listing.
5045 smb_SetSMBParm(outp, 0, 0);
5047 /* get the directory size */
5048 lock_ObtainWrite(&scp->rw);
5049 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5050 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5052 lock_ReleaseWrite(&scp->rw);
5053 cm_ReleaseSCache(scp);
5054 cm_ReleaseUser(userp);
5055 smb_DeleteDirSearch(dsp);
5056 smb_ReleaseDirSearch(dsp);
5060 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5062 dirLength = scp->length;
5064 bufferOffset.LowPart = bufferOffset.HighPart = 0;
5065 curOffset.HighPart = 0;
5066 curOffset.LowPart = nextCookie;
5067 origOp = op = smb_GetSMBData(outp, NULL);
5068 /* and write out the basic header */
5069 *op++ = 5; /* variable block */
5070 op += 2; /* skip vbl block length; we'll fill it in later */
5074 clientchar_t *actualName = NULL;
5075 int free_actualName = 0;
5076 clientchar_t shortName[13];
5077 clientchar_t *shortNameEnd;
5079 /* make sure that curOffset.LowPart doesn't point to the first
5080 * 32 bytes in the 2nd through last dir page, and that it doesn't
5081 * point at the first 13 32-byte chunks in the first dir page,
5082 * since those are dir and page headers, and don't contain useful
5085 temp = curOffset.LowPart & (2048-1);
5086 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5087 /* we're in the first page */
5088 if (temp < 13*32) temp = 13*32;
5091 /* we're in a later dir page */
5092 if (temp < 32) temp = 32;
5095 /* make sure the low order 5 bits are zero */
5098 /* now put temp bits back ito curOffset.LowPart */
5099 curOffset.LowPart &= ~(2048-1);
5100 curOffset.LowPart |= temp;
5102 /* check if we've returned all the names that will fit in the
5105 if (returnedNames >= maxCount) {
5106 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5107 returnedNames, maxCount);
5111 /* check if we've passed the dir's EOF */
5112 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5114 /* see if we can use the bufferp we have now; compute in which page
5115 * the current offset would be, and check whether that's the offset
5116 * of the buffer we have. If not, get the buffer.
5118 thyper.HighPart = curOffset.HighPart;
5119 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5120 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5123 buf_Release(bufferp);
5126 lock_ReleaseWrite(&scp->rw);
5127 code = buf_Get(scp, &thyper, &req, &bufferp);
5128 lock_ObtainMutex(&dsp->mx);
5130 /* now, if we're doing a star match, do bulk fetching of all of
5131 * the status info for files in the dir.
5134 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5136 lock_ObtainWrite(&scp->rw);
5137 lock_ReleaseMutex(&dsp->mx);
5139 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5143 bufferOffset = thyper;
5145 /* now get the data in the cache */
5147 code = cm_SyncOp(scp, bufferp, userp, &req,
5149 CM_SCACHESYNC_NEEDCALLBACK |
5150 CM_SCACHESYNC_READ);
5152 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5156 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5158 if (cm_HaveBuffer(scp, bufferp, 0)) {
5159 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5163 /* otherwise, load the buffer and try again */
5164 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5166 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5167 scp, bufferp, code);
5172 buf_Release(bufferp);
5176 } /* if (wrong buffer) ... */
5178 /* now we have the buffer containing the entry we're interested in; copy
5179 * it out if it represents a non-deleted entry.
5181 entryInDir = curOffset.LowPart & (2048-1);
5182 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5184 /* page header will help tell us which entries are free. Page header
5185 * can change more often than once per buffer, since AFS 3 dir page size
5186 * may be less than (but not more than a buffer package buffer.
5188 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5189 temp &= ~(2048 - 1); /* turn off intra-page bits */
5190 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5192 /* now determine which entry we're looking at in the page. If it is
5193 * free (there's a free bitmap at the start of the dir), we should
5194 * skip these 32 bytes.
5196 slotInPage = (entryInDir & 0x7e0) >> 5;
5197 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5198 /* this entry is free */
5199 numDirChunks = 1; /* only skip this guy */
5203 tp = bufferp->datap + entryInBuffer;
5204 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5206 /* while we're here, compute the next entry's location, too,
5207 * since we'll need it when writing out the cookie into the dir
5210 * XXXX Probably should do more sanity checking.
5212 numDirChunks = cm_NameEntries(dep->name, NULL);
5214 /* compute the offset of the cookie representing the next entry */
5215 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5217 /* Compute 8.3 name if necessary */
5218 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5219 if (dep->fid.vnode != 0 && cm_shortNames && !cm_Is8Dot3(actualName)) {
5222 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5223 actualName = shortName;
5224 free_actualName = 0;
5226 free_actualName = 1;
5229 if (actualName == NULL) {
5230 /* Couldn't convert the name for some reason */
5231 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5232 osi_LogSaveString(smb_logp, dep->name));
5236 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5237 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5238 osi_LogSaveClientString(smb_logp, actualName));
5240 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5241 /* this is one of the entries to use: it is not deleted
5242 * and it matches the star pattern we're looking for.
5245 /* Eliminate entries that don't match requested
5248 /* no hidden files */
5249 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5250 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5254 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5256 /* We have already done the cm_TryBulkStat above */
5257 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5258 fileType = cm_FindFileType(&fid);
5259 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5260 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5262 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5263 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5264 fileType == CM_SCACHETYPE_DFSLINK ||
5265 fileType == CM_SCACHETYPE_INVALID)
5266 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5271 memcpy(op, mask, 11); op += 11;
5272 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5273 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5274 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5275 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5276 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5277 memcpy(op, &clientCookie, 4); op += 4;
5279 /* now we emit the attribute. This is sort of tricky,
5280 * since we need to really stat the file to find out
5281 * what type of entry we've got. Right now, we're
5282 * copying out data from a buffer, while holding the
5283 * scp locked, so it isn't really convenient to stat
5284 * something now. We'll put in a place holder now,
5285 * and make a second pass before returning this to get
5286 * the real attributes. So, we just skip the data for
5287 * now, and adjust it later. We allocate a patch
5288 * record to make it easy to find this point later.
5289 * The replay will happen at a time when it is safe to
5290 * unlock the directory.
5292 curPatchp = malloc(sizeof(*curPatchp));
5293 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5294 curPatchp->dptr = op;
5295 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5297 /* do hidden attribute here since name won't be around when applying
5301 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5302 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5304 curPatchp->flags = 0;
5306 op += 9; /* skip attr, time, date and size */
5308 /* zero out name area. The spec says to pad with
5309 * spaces, but Samba doesn't, and neither do we.
5313 /* finally, we get to copy out the name; we know that
5314 * it fits in 8.3 or the pattern wouldn't match, but it
5315 * never hurts to be sure.
5317 cm_ClientStringToUtf8(actualName, -1, op, 13);
5318 if (smb_StoreAnsiFilenames)
5320 /* This is a UCHAR field, which is ASCII even if Unicode
5323 /* Uppercase if requested by client */
5324 if (!KNOWS_LONG_NAMES(inp))
5329 /* now, adjust the # of entries copied */
5331 } /* if we're including this name */
5334 if (free_actualName && actualName) {
5339 /* and adjust curOffset to be where the new cookie is */
5340 thyper.HighPart = 0;
5341 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5342 curOffset = LargeIntegerAdd(thyper, curOffset);
5343 } /* while copying data for dir listing */
5345 /* release the mutex */
5346 lock_ReleaseWrite(&scp->rw);
5348 buf_Release(bufferp);
5352 /* apply and free last set of patches; if not doing a star match, this
5353 * will be empty, but better safe (and freeing everything) than sorry.
5355 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5357 /* special return code for unsuccessful search */
5358 if (code == 0 && dataLength < 21 && returnedNames == 0)
5359 code = CM_ERROR_NOFILES;
5361 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5362 returnedNames, code);
5365 smb_DeleteDirSearch(dsp);
5366 smb_ReleaseDirSearch(dsp);
5367 cm_ReleaseSCache(scp);
5368 cm_ReleaseUser(userp);
5372 /* finalize the output buffer */
5373 smb_SetSMBParm(outp, 0, returnedNames);
5374 temp = (long) (op - origOp);
5375 smb_SetSMBDataLength(outp, temp);
5377 /* the data area is a variable block, which has a 5 (already there)
5378 * followed by the length of the # of data bytes. We now know this to
5379 * be "temp," although that includes the 3 bytes of vbl block header.
5380 * Deduct for them and fill in the length field.
5382 temp -= 3; /* deduct vbl block info */
5383 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5384 origOp[1] = (unsigned char)(temp & 0xff);
5385 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5386 if (returnedNames == 0)
5387 smb_DeleteDirSearch(dsp);
5388 smb_ReleaseDirSearch(dsp);
5389 cm_ReleaseSCache(scp);
5390 cm_ReleaseUser(userp);
5395 /* verify that this is a valid path to a directory. I don't know why they
5396 * don't use the get file attributes call.
5398 * SMB_COM_CHECK_DIRECTORY
5400 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5402 clientchar_t *pathp;
5404 cm_scache_t *rootScp;
5405 cm_scache_t *newScp;
5409 clientchar_t *tidPathp;
5415 pdata = smb_GetSMBData(inp, NULL);
5416 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5418 return CM_ERROR_BADSMB;
5419 osi_Log1(smb_logp, "SMB receive check path %S",
5420 osi_LogSaveClientString(smb_logp, pathp));
5422 userp = smb_GetUserFromVCP(vcp, inp);
5424 rootScp = cm_RootSCachep(userp, &req);
5426 caseFold = CM_FLAG_CASEFOLD;
5428 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5430 cm_ReleaseUser(userp);
5431 return CM_ERROR_NOSUCHPATH;
5433 code = cm_NameI(rootScp, pathp,
5434 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5435 userp, tidPathp, &req, &newScp);
5438 cm_ReleaseUser(userp);
5443 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5444 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5445 cm_ReleaseSCache(newScp);
5446 cm_ReleaseUser(userp);
5447 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5448 return CM_ERROR_PATH_NOT_COVERED;
5450 return CM_ERROR_NOSUCHPATH;
5452 #endif /* DFS_SUPPORT */
5454 /* now lock the vnode with a callback; returns with newScp locked */
5455 lock_ObtainWrite(&newScp->rw);
5456 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5457 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5459 if (code != CM_ERROR_NOACCESS) {
5460 lock_ReleaseWrite(&newScp->rw);
5461 cm_ReleaseSCache(newScp);
5462 cm_ReleaseUser(userp);
5466 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5469 attrs = smb_Attributes(newScp);
5471 if (!(attrs & SMB_ATTR_DIRECTORY))
5472 code = CM_ERROR_NOTDIR;
5474 lock_ReleaseWrite(&newScp->rw);
5476 cm_ReleaseSCache(newScp);
5477 cm_ReleaseUser(userp);
5481 /* SMB_COM_SET_INFORMATION */
5482 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5484 clientchar_t *pathp;
5486 cm_scache_t *rootScp;
5487 unsigned short attribute;
5489 cm_scache_t *newScp;
5493 clientchar_t *tidPathp;
5499 /* decode basic attributes we're passed */
5500 attribute = smb_GetSMBParm(inp, 0);
5501 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5503 datap = smb_GetSMBData(inp, NULL);
5504 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5506 return CM_ERROR_BADSMB;
5508 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5509 dosTime, attribute);
5511 userp = smb_GetUserFromVCP(vcp, inp);
5513 rootScp = cm_RootSCachep(userp, &req);
5515 caseFold = CM_FLAG_CASEFOLD;
5517 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5519 cm_ReleaseUser(userp);
5520 return CM_ERROR_NOSUCHFILE;
5522 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5523 tidPathp, &req, &newScp);
5526 cm_ReleaseUser(userp);
5531 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5532 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5533 cm_ReleaseSCache(newScp);
5534 cm_ReleaseUser(userp);
5535 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5536 return CM_ERROR_PATH_NOT_COVERED;
5538 return CM_ERROR_NOSUCHPATH;
5540 #endif /* DFS_SUPPORT */
5542 /* now lock the vnode with a callback; returns with newScp locked; we
5543 * need the current status to determine what the new status is, in some
5546 lock_ObtainWrite(&newScp->rw);
5547 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5548 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5550 lock_ReleaseWrite(&newScp->rw);
5551 cm_ReleaseSCache(newScp);
5552 cm_ReleaseUser(userp);
5556 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5558 /* Check for RO volume */
5559 if (newScp->flags & CM_SCACHEFLAG_RO) {
5560 lock_ReleaseWrite(&newScp->rw);
5561 cm_ReleaseSCache(newScp);
5562 cm_ReleaseUser(userp);
5563 return CM_ERROR_READONLY;
5566 /* prepare for setattr call */
5569 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5570 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5572 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5573 /* we're told to make a writable file read-only */
5574 attr.unixModeBits = newScp->unixModeBits & ~0222;
5575 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5577 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5578 /* we're told to make a read-only file writable */
5579 attr.unixModeBits = newScp->unixModeBits | 0222;
5580 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5582 lock_ReleaseWrite(&newScp->rw);
5584 /* now call setattr */
5586 code = cm_SetAttr(newScp, &attr, userp, &req);
5590 cm_ReleaseSCache(newScp);
5591 cm_ReleaseUser(userp);
5597 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5599 clientchar_t *pathp;
5601 cm_scache_t *rootScp;
5602 cm_scache_t *newScp, *dscp;
5607 clientchar_t *tidPathp;
5609 clientchar_t *lastComp;
5615 datap = smb_GetSMBData(inp, NULL);
5616 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5618 return CM_ERROR_BADSMB;
5620 if (*pathp == 0) /* null path */
5623 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5624 osi_LogSaveClientString(smb_logp, pathp));
5626 userp = smb_GetUserFromVCP(vcp, inp);
5628 rootScp = cm_RootSCachep(userp, &req);
5630 /* we shouldn't need this for V3 requests, but we seem to */
5631 caseFold = CM_FLAG_CASEFOLD;
5633 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5635 cm_ReleaseUser(userp);
5636 return CM_ERROR_NOSUCHFILE;
5640 * XXX Strange hack XXX
5642 * As of Patch 5 (16 July 97), we are having the following problem:
5643 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5644 * requests to look up "desktop.ini" in all the subdirectories.
5645 * This can cause zillions of timeouts looking up non-existent cells
5646 * and volumes, especially in the top-level directory.
5648 * We have not found any way to avoid this or work around it except
5649 * to explicitly ignore the requests for mount points that haven't
5650 * yet been evaluated and for directories that haven't yet been
5653 * We should modify this hack to provide a fake desktop.ini file
5654 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5656 spacep = inp->spacep;
5657 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5658 #ifndef SPECIAL_FOLDERS
5659 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5660 code = cm_NameI(rootScp, spacep->wdata,
5661 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5662 userp, tidPathp, &req, &dscp);
5665 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5666 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5668 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5669 return CM_ERROR_PATH_NOT_COVERED;
5671 return CM_ERROR_NOSUCHPATH;
5673 #endif /* DFS_SUPPORT */
5674 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5675 code = CM_ERROR_NOSUCHFILE;
5676 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5677 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
5682 code = CM_ERROR_NOSUCHFILE;
5684 cm_ReleaseSCache(dscp);
5686 cm_ReleaseUser(userp);
5690 else if (code != CM_ERROR_NOSUCHFILE &&
5691 code != CM_ERROR_NOSUCHPATH &&
5692 code != CM_ERROR_BPLUS_NOMATCH)
5694 cm_ReleaseUser(userp);
5698 #endif /* SPECIAL_FOLDERS */
5700 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5701 tidPathp, &req, &newScp);
5703 cm_ReleaseUser(userp);
5708 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5709 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5710 cm_ReleaseSCache(newScp);
5711 cm_ReleaseUser(userp);
5712 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5713 return CM_ERROR_PATH_NOT_COVERED;
5715 return CM_ERROR_NOSUCHPATH;
5717 #endif /* DFS_SUPPORT */
5719 /* now lock the vnode with a callback; returns with newScp locked */
5720 lock_ObtainWrite(&newScp->rw);
5721 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5722 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5724 lock_ReleaseWrite(&newScp->rw);
5725 cm_ReleaseSCache(newScp);
5726 cm_ReleaseUser(userp);
5730 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5732 attrs = smb_Attributes(newScp);
5734 smb_SetSMBParm(outp, 0, attrs);
5736 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5737 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5738 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5739 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5740 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5741 smb_SetSMBParm(outp, 5, 0);
5742 smb_SetSMBParm(outp, 6, 0);
5743 smb_SetSMBParm(outp, 7, 0);
5744 smb_SetSMBParm(outp, 8, 0);
5745 smb_SetSMBParm(outp, 9, 0);
5746 smb_SetSMBDataLength(outp, 0);
5747 lock_ReleaseWrite(&newScp->rw);
5749 cm_ReleaseSCache(newScp);
5750 cm_ReleaseUser(userp);
5755 /* SMB_COM_TREE_DISCONNECT */
5756 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5760 osi_Log0(smb_logp, "SMB receive tree disconnect");
5762 /* find the tree and free it */
5763 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5765 lock_ObtainWrite(&smb_rctLock);
5767 smb_ReleaseTID(tidp, TRUE);
5768 lock_ReleaseWrite(&smb_rctLock);
5775 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5778 clientchar_t *pathp;
5779 clientchar_t *lastNamep;
5788 clientchar_t *tidPathp;
5794 datap = smb_GetSMBData(inp, NULL);
5795 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5797 return CM_ERROR_BADSMB;
5799 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5801 #ifdef DEBUG_VERBOSE
5805 hexpath = osi_HexifyString( pathp );
5806 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5811 share = smb_GetSMBParm(inp, 0);
5812 attribute = smb_GetSMBParm(inp, 1);
5814 spacep = inp->spacep;
5815 /* smb_StripLastComponent will strip "::$DATA" if present */
5816 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5818 if (!cm_IsValidClientString(pathp)) {
5820 clientchar_t * hexp;
5822 hexp = cm_GetRawCharsAlloc(pathp, -1);
5823 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5824 osi_LogSaveClientString(smb_logp, hexp));
5828 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5830 return CM_ERROR_BADNTFILENAME;
5833 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5834 /* special case magic file name for receiving IOCTL requests
5835 * (since IOCTL calls themselves aren't getting through).
5837 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5838 smb_SetupIoctlFid(fidp, spacep);
5839 smb_SetSMBParm(outp, 0, fidp->fid);
5840 smb_SetSMBParm(outp, 1, 0); /* attrs */
5841 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5842 smb_SetSMBParm(outp, 3, 0);
5843 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5844 smb_SetSMBParm(outp, 5, 0x7fff);
5845 /* pass the open mode back */
5846 smb_SetSMBParm(outp, 6, (share & 0xf));
5847 smb_SetSMBDataLength(outp, 0);
5848 smb_ReleaseFID(fidp);
5852 userp = smb_GetUserFromVCP(vcp, inp);
5854 caseFold = CM_FLAG_CASEFOLD;
5856 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5858 cm_ReleaseUser(userp);
5859 return CM_ERROR_NOSUCHPATH;
5861 code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
5862 tidPathp, &req, &scp);
5865 cm_ReleaseUser(userp);
5870 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5871 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5872 cm_ReleaseSCache(scp);
5873 cm_ReleaseUser(userp);
5874 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5875 return CM_ERROR_PATH_NOT_COVERED;
5877 return CM_ERROR_NOSUCHPATH;
5879 #endif /* DFS_SUPPORT */
5881 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5883 cm_ReleaseSCache(scp);
5884 cm_ReleaseUser(userp);
5888 /* don't need callback to check file type, since file types never
5889 * change, and namei and cm_Lookup all stat the object at least once on
5890 * a successful return.
5892 if (scp->fileType != CM_SCACHETYPE_FILE) {
5893 cm_ReleaseSCache(scp);
5894 cm_ReleaseUser(userp);
5895 return CM_ERROR_ISDIR;
5898 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5899 osi_assertx(fidp, "null smb_fid_t");
5901 lock_ObtainMutex(&fidp->mx);
5902 if ((share & 0xf) == 0)
5903 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5904 else if ((share & 0xf) == 1)
5905 fidp->flags |= SMB_FID_OPENWRITE;
5907 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5911 fidp->userp = userp;
5913 /* and a pointer to the vnode */
5915 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5916 lock_ObtainWrite(&scp->rw);
5917 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5919 smb_SetSMBParm(outp, 0, fidp->fid);
5920 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5921 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5922 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5923 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5924 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5925 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5926 /* pass the open mode back; XXXX add access checks */
5927 smb_SetSMBParm(outp, 6, (share & 0xf));
5928 smb_SetSMBDataLength(outp, 0);
5929 lock_ReleaseMutex(&fidp->mx);
5930 lock_ReleaseRead(&scp->rw);
5933 cm_Open(scp, 0, userp);
5935 /* send and free packet */
5936 smb_ReleaseFID(fidp);
5937 cm_ReleaseUser(userp);
5938 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5942 typedef struct smb_unlinkRock {
5947 clientchar_t *maskp; /* pointer to the star pattern */
5950 cm_dirEntryList_t * matches;
5953 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5956 smb_unlinkRock_t *rockp;
5959 normchar_t matchName[MAX_PATH];
5963 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5964 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5965 caseFold |= CM_FLAG_8DOT3;
5967 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5968 /* Can't convert name */
5969 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5970 osi_LogSaveString(smb_logp, dep->name));
5974 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5976 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5978 !cm_Is8Dot3(matchName)) {
5979 cm_Gen8Dot3Name(dep, matchName, NULL);
5980 /* 8.3 matches are always case insensitive */
5981 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5984 osi_Log1(smb_logp, "Found match %S",
5985 osi_LogSaveClientString(smb_logp, matchName));
5987 cm_DirEntryListAdd(dep->name, &rockp->matches);
5991 /* If we made a case sensitive exact match, we might as well quit now. */
5992 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5993 code = CM_ERROR_STOPNOW;
6002 /* SMB_COM_DELETE */
6003 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6007 clientchar_t *pathp;
6011 clientchar_t *lastNamep;
6012 smb_unlinkRock_t rock;
6016 clientchar_t *tidPathp;
6020 memset(&rock, 0, sizeof(rock));
6022 attribute = smb_GetSMBParm(inp, 0);
6024 tp = smb_GetSMBData(inp, NULL);
6025 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6027 return CM_ERROR_BADSMB;
6029 osi_Log1(smb_logp, "SMB receive unlink %S",
6030 osi_LogSaveClientString(smb_logp, pathp));
6032 spacep = inp->spacep;
6033 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6035 userp = smb_GetUserFromVCP(vcp, inp);
6037 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6039 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6041 cm_ReleaseUser(userp);
6042 return CM_ERROR_NOSUCHPATH;
6044 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
6047 cm_ReleaseUser(userp);
6052 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6053 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6054 cm_ReleaseSCache(dscp);
6055 cm_ReleaseUser(userp);
6056 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6057 return CM_ERROR_PATH_NOT_COVERED;
6059 return CM_ERROR_NOSUCHPATH;
6061 #endif /* DFS_SUPPORT */
6063 /* otherwise, scp points to the parent directory. */
6070 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
6072 code = CM_ERROR_NOSUCHFILE;
6075 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6078 thyper.HighPart = 0;
6083 rock.matches = NULL;
6085 /* Now, if we aren't dealing with a wildcard match, we first try an exact
6086 * match. If that fails, we do a case insensitve match.
6088 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6089 !smb_IsStarMask(rock.maskp)) {
6090 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6093 thyper.HighPart = 0;
6094 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6099 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6101 if (code == CM_ERROR_STOPNOW)
6104 if (code == 0 && rock.matches) {
6105 cm_dirEntryList_t * entry;
6107 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6108 normchar_t normalizedName[MAX_PATH];
6110 /* Note: entry->name is a non-normalized name */
6112 osi_Log1(smb_logp, "Unlinking %s",
6113 osi_LogSaveString(smb_logp, entry->name));
6115 /* We assume this works because entry->name was
6116 successfully converted in smb_UnlinkProc() once. */
6117 cm_FsStringToNormString(entry->name, -1,
6118 normalizedName, lengthof(normalizedName));
6120 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6122 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6123 smb_NotifyChange(FILE_ACTION_REMOVED,
6124 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6125 dscp, normalizedName, NULL, TRUE);
6129 cm_DirEntryListFree(&rock.matches);
6133 cm_ReleaseUser(userp);
6136 cm_ReleaseSCache(dscp);
6141 if (code == 0 && !rock.any)
6142 code = CM_ERROR_NOSUCHFILE;
6146 typedef struct smb_renameRock {
6147 cm_scache_t *odscp; /* old dir */
6148 cm_scache_t *ndscp; /* new dir */
6149 cm_user_t *userp; /* user */
6150 cm_req_t *reqp; /* request struct */
6151 smb_vc_t *vcp; /* virtual circuit */
6152 normchar_t *maskp; /* pointer to star pattern of old file name */
6153 int flags; /* tilde, casefold, etc */
6154 clientchar_t *newNamep; /* ptr to the new file's name */
6155 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6156 clientchar_t clOldName[MAX_PATH]; /* client name */
6160 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6163 smb_renameRock_t *rockp;
6166 normchar_t matchName[MAX_PATH];
6168 rockp = (smb_renameRock_t *) vrockp;
6170 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6171 /* Can't convert string */
6172 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6173 osi_LogSaveString(smb_logp, dep->name));
6177 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6178 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6179 caseFold |= CM_FLAG_8DOT3;
6181 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6183 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6185 !cm_Is8Dot3(matchName)) {
6186 cm_Gen8Dot3Name(dep, matchName, NULL);
6187 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6192 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6193 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6195 code = CM_ERROR_STOPNOW;
6205 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6208 cm_space_t *spacep = NULL;
6209 smb_renameRock_t rock;
6210 cm_scache_t *oldDscp = NULL;
6211 cm_scache_t *newDscp = NULL;
6212 cm_scache_t *tmpscp= NULL;
6213 cm_scache_t *tmpscp2 = NULL;
6214 clientchar_t *oldLastNamep;
6215 clientchar_t *newLastNamep;
6219 clientchar_t *tidPathp;
6223 userp = smb_GetUserFromVCP(vcp, inp);
6224 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6226 cm_ReleaseUser(userp);
6227 return CM_ERROR_NOSUCHPATH;
6231 memset(&rock, 0, sizeof(rock));
6233 spacep = inp->spacep;
6234 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6236 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6237 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6238 userp, tidPathp, &req, &oldDscp);
6240 cm_ReleaseUser(userp);
6245 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6246 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6247 cm_ReleaseSCache(oldDscp);
6248 cm_ReleaseUser(userp);
6249 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6250 return CM_ERROR_PATH_NOT_COVERED;
6252 return CM_ERROR_NOSUCHPATH;
6254 #endif /* DFS_SUPPORT */
6256 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6257 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6258 userp, tidPathp, &req, &newDscp);
6261 cm_ReleaseSCache(oldDscp);
6262 cm_ReleaseUser(userp);
6267 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6268 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6269 cm_ReleaseSCache(oldDscp);
6270 cm_ReleaseSCache(newDscp);
6271 cm_ReleaseUser(userp);
6272 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6273 return CM_ERROR_PATH_NOT_COVERED;
6275 return CM_ERROR_NOSUCHPATH;
6277 #endif /* DFS_SUPPORT */
6280 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6281 * next, get the component names, and lower case them.
6284 /* handle the old name first */
6286 oldLastNamep = oldPathp;
6290 /* and handle the new name, too */
6292 newLastNamep = newPathp;
6296 /* TODO: The old name could be a wildcard. The new name must not be */
6298 /* Check if the file already exists; if so return error */
6299 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6300 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6301 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6303 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6304 osi_LogSaveClientString(smb_logp, newLastNamep));
6306 /* Check if the old and the new names differ only in case. If so return
6307 * success, else return CM_ERROR_EXISTS
6309 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6311 /* This would be a success only if the old file is *as same as* the new file */
6312 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6314 if (tmpscp == tmpscp2)
6317 code = CM_ERROR_EXISTS;
6318 cm_ReleaseSCache(tmpscp2);
6321 code = CM_ERROR_NOSUCHFILE;
6324 /* file exist, do not rename, also fixes move */
6325 osi_Log0(smb_logp, "Can't rename. Target already exists");
6326 code = CM_ERROR_EXISTS;
6331 /* do the vnode call */
6332 rock.odscp = oldDscp;
6333 rock.ndscp = newDscp;
6337 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6339 code = CM_ERROR_NOSUCHFILE;
6342 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6343 rock.newNamep = newLastNamep;
6344 rock.fsOldName[0] = '\0';
6345 rock.clOldName[0] = '\0';
6348 /* Now search the directory for the pattern, and do the appropriate rename when found */
6349 thyper.LowPart = 0; /* search dir from here */
6350 thyper.HighPart = 0;
6352 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6353 if (code == 0 && !rock.any) {
6355 thyper.HighPart = 0;
6356 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6357 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6359 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6361 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6362 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6363 rock.ndscp, rock.newNamep, rock.userp,
6365 /* if the call worked, stop doing the search now, since we
6366 * really only want to rename one file.
6369 osi_Log0(smb_logp, "cm_Rename failure");
6370 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6371 } else if (code == 0) {
6372 code = CM_ERROR_NOSUCHFILE;
6375 /* Handle Change Notification */
6377 * Being lazy, not distinguishing between files and dirs in this
6378 * filter, since we'd have to do a lookup.
6381 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6382 if (oldDscp == newDscp) {
6383 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6384 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6385 filter, oldDscp, rock.clOldName,
6386 newLastNamep, TRUE);
6388 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6389 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6390 filter, oldDscp, rock.clOldName,
6392 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6393 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6394 filter, newDscp, newLastNamep,
6401 cm_ReleaseSCache(tmpscp);
6403 cm_ReleaseUser(userp);
6405 cm_ReleaseSCache(oldDscp);
6407 cm_ReleaseSCache(newDscp);
6415 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6418 cm_space_t *spacep = NULL;
6419 cm_scache_t *oldDscp = NULL;
6420 cm_scache_t *newDscp = NULL;
6421 cm_scache_t *tmpscp= NULL;
6422 cm_scache_t *tmpscp2 = NULL;
6423 cm_scache_t *sscp = NULL;
6424 clientchar_t *oldLastNamep;
6425 clientchar_t *newLastNamep;
6428 clientchar_t *tidPathp;
6432 userp = smb_GetUserFromVCP(vcp, inp);
6434 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6436 cm_ReleaseUser(userp);
6437 return CM_ERROR_NOSUCHPATH;
6442 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6444 spacep = inp->spacep;
6445 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6447 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6448 userp, tidPathp, &req, &oldDscp);
6450 cm_ReleaseUser(userp);
6455 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6456 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6457 cm_ReleaseSCache(oldDscp);
6458 cm_ReleaseUser(userp);
6459 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6460 return CM_ERROR_PATH_NOT_COVERED;
6462 return CM_ERROR_NOSUCHPATH;
6464 #endif /* DFS_SUPPORT */
6466 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6467 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6468 userp, tidPathp, &req, &newDscp);
6470 cm_ReleaseSCache(oldDscp);
6471 cm_ReleaseUser(userp);
6476 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6477 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6478 cm_ReleaseSCache(newDscp);
6479 cm_ReleaseSCache(oldDscp);
6480 cm_ReleaseUser(userp);
6481 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6482 return CM_ERROR_PATH_NOT_COVERED;
6484 return CM_ERROR_NOSUCHPATH;
6486 #endif /* DFS_SUPPORT */
6488 /* Now, although we did two lookups for the two directories (because the same
6489 * directory can be referenced through different paths), we only allow hard links
6490 * within the same directory. */
6491 if (oldDscp != newDscp) {
6492 cm_ReleaseSCache(oldDscp);
6493 cm_ReleaseSCache(newDscp);
6494 cm_ReleaseUser(userp);
6495 return CM_ERROR_CROSSDEVLINK;
6498 /* handle the old name first */
6500 oldLastNamep = oldPathp;
6504 /* and handle the new name, too */
6506 newLastNamep = newPathp;
6510 /* now lookup the old name */
6511 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6512 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6514 cm_ReleaseSCache(oldDscp);
6515 cm_ReleaseSCache(newDscp);
6516 cm_ReleaseUser(userp);
6520 /* Check if the file already exists; if so return error */
6521 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6522 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6523 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6525 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6526 osi_LogSaveClientString(smb_logp, newLastNamep));
6528 /* if the existing link is to the same file, then we return success */
6530 if(sscp == tmpscp) {
6533 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6534 code = CM_ERROR_EXISTS;
6539 cm_ReleaseSCache(tmpscp);
6540 cm_ReleaseSCache(sscp);
6541 cm_ReleaseSCache(newDscp);
6542 cm_ReleaseSCache(oldDscp);
6543 cm_ReleaseUser(userp);
6547 /* now create the hardlink */
6548 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6549 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6550 osi_Log1(smb_logp," Link returns 0x%x", code);
6552 /* Handle Change Notification */
6554 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6555 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6556 smb_NotifyChange(FILE_ACTION_ADDED,
6557 filter, newDscp, newLastNamep,
6562 cm_ReleaseSCache(tmpscp);
6563 cm_ReleaseUser(userp);
6564 cm_ReleaseSCache(sscp);
6565 cm_ReleaseSCache(oldDscp);
6566 cm_ReleaseSCache(newDscp);
6570 /* SMB_COM_RENAME */
6572 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6574 clientchar_t *oldPathp;
6575 clientchar_t *newPathp;
6579 tp = smb_GetSMBData(inp, NULL);
6580 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6582 return CM_ERROR_BADSMB;
6583 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6585 return CM_ERROR_BADSMB;
6587 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6588 osi_LogSaveClientString(smb_logp, oldPathp),
6589 osi_LogSaveClientString(smb_logp, newPathp));
6591 if (!cm_IsValidClientString(newPathp)) {
6593 clientchar_t * hexp;
6595 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6596 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6597 osi_LogSaveClientString(smb_logp, hexp));
6601 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6603 return CM_ERROR_BADNTFILENAME;
6606 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6608 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6614 typedef struct smb_rmdirRock {
6618 normchar_t *maskp; /* pointer to the star pattern */
6621 cm_dirEntryList_t * matches;
6624 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6627 smb_rmdirRock_t *rockp;
6629 normchar_t matchName[MAX_PATH];
6631 rockp = (smb_rmdirRock_t *) vrockp;
6633 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6634 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6635 osi_LogSaveString(smb_logp, dep->name));
6639 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6640 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6642 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6644 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6646 !cm_Is8Dot3(matchName)) {
6647 cm_Gen8Dot3Name(dep, matchName, NULL);
6648 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6653 cm_DirEntryListAdd(dep->name, &rockp->matches);
6660 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6663 clientchar_t *pathp;
6667 clientchar_t *lastNamep;
6668 smb_rmdirRock_t rock;
6672 clientchar_t *tidPathp;
6676 memset(&rock, 0, sizeof(rock));
6678 tp = smb_GetSMBData(inp, NULL);
6679 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6681 return CM_ERROR_BADSMB;
6683 spacep = inp->spacep;
6684 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6686 userp = smb_GetUserFromVCP(vcp, inp);
6688 caseFold = CM_FLAG_CASEFOLD;
6690 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6692 cm_ReleaseUser(userp);
6693 return CM_ERROR_NOSUCHPATH;
6695 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6696 userp, tidPathp, &req, &dscp);
6699 cm_ReleaseUser(userp);
6704 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6705 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6706 cm_ReleaseSCache(dscp);
6707 cm_ReleaseUser(userp);
6708 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6709 return CM_ERROR_PATH_NOT_COVERED;
6711 return CM_ERROR_NOSUCHPATH;
6713 #endif /* DFS_SUPPORT */
6715 /* otherwise, scp points to the parent directory. */
6722 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6724 code = CM_ERROR_NOSUCHFILE;
6727 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6730 thyper.HighPart = 0;
6734 rock.matches = NULL;
6736 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6737 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6738 if (code == 0 && !rock.any) {
6740 thyper.HighPart = 0;
6741 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6742 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6745 if (code == 0 && rock.matches) {
6746 cm_dirEntryList_t * entry;
6748 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6749 clientchar_t clientName[MAX_PATH];
6751 /* We assume this will succeed because smb_RmdirProc()
6752 successfully converted entry->name once above. */
6753 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6755 osi_Log1(smb_logp, "Removing directory %s",
6756 osi_LogSaveString(smb_logp, entry->name));
6758 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6760 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6761 smb_NotifyChange(FILE_ACTION_REMOVED,
6762 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6763 dscp, clientName, NULL, TRUE);
6769 cm_DirEntryListFree(&rock.matches);
6772 cm_ReleaseUser(userp);
6775 cm_ReleaseSCache(dscp);
6777 if (code == 0 && !rock.any)
6778 code = CM_ERROR_NOSUCHFILE;
6787 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6797 fid = smb_GetSMBParm(inp, 0);
6799 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6801 fid = smb_ChainFID(fid, inp);
6802 fidp = smb_FindFID(vcp, fid, 0);
6804 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6806 return CM_ERROR_BADFD;
6808 userp = smb_GetUserFromVCP(vcp, inp);
6810 lock_ObtainMutex(&fidp->mx);
6811 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6812 cm_ReleaseUser(userp);
6813 lock_ReleaseMutex(&fidp->mx);
6814 smb_ReleaseFID(fidp);
6815 return CM_ERROR_BADFD;
6818 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6819 lock_ReleaseMutex(&fidp->mx);
6820 cm_ReleaseUser(userp);
6821 smb_CloseFID(vcp, fidp, NULL, 0);
6822 smb_ReleaseFID(fidp);
6823 return CM_ERROR_NOSUCHFILE;
6826 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6827 cm_scache_t * scp = fidp->scp;
6829 lock_ReleaseMutex(&fidp->mx);
6830 code = cm_FSync(scp, userp, &req, FALSE);
6831 cm_ReleaseSCache(scp);
6833 lock_ReleaseMutex(&fidp->mx);
6837 cm_ReleaseUser(userp);
6838 smb_ReleaseFID(fidp);
6842 struct smb_FullNameRock {
6845 clientchar_t *fullName;
6846 fschar_t *originalName;
6849 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6852 normchar_t matchName[MAX_PATH];
6853 struct smb_FullNameRock *vrockp;
6855 vrockp = (struct smb_FullNameRock *)rockp;
6857 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6858 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6859 osi_LogSaveString(smb_logp, dep->name));
6863 if (cm_shortNames && !cm_Is8Dot3(matchName)) {
6864 clientchar_t shortName[13];
6866 cm_Gen8Dot3Name(dep, shortName, NULL);
6868 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6869 vrockp->fullName = cm_ClientStrDup(matchName);
6870 vrockp->originalName = cm_FsStrDup(dep->name);
6871 return CM_ERROR_STOPNOW;
6874 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6875 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6876 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6877 vrockp->fullName = cm_ClientStrDup(matchName);
6878 vrockp->originalName = cm_FsStrDup(dep->name);
6879 return CM_ERROR_STOPNOW;
6884 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6885 clientchar_t **newPathp, fschar_t ** originalPathp,
6886 cm_user_t *userp, cm_req_t *reqp)
6888 struct smb_FullNameRock rock;
6891 memset(&rock, 0, sizeof(rock));
6895 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6896 if (code == CM_ERROR_STOPNOW) {
6897 *newPathp = rock.fullName;
6898 *originalPathp = rock.originalName;
6900 *newPathp = cm_ClientStrDup(pathp);
6901 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6905 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6906 afs_uint32 dosTime) {
6909 cm_scache_t *dscp = NULL;
6910 clientchar_t *pathp = NULL;
6911 cm_scache_t * scp = NULL;
6912 cm_scache_t *delscp = NULL;
6913 int nullcreator = 0;
6915 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6916 fidp, fidp->fid, scp, vcp);
6919 lock_ObtainMutex(&fidp->mx);
6920 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6922 lock_ReleaseMutex(&fidp->mx);
6923 osi_Log0(smb_logp, " No user specified. Not closing fid");
6924 return CM_ERROR_BADFD;
6927 userp = fidp->userp; /* no hold required since fidp is held
6928 throughout the function */
6929 lock_ReleaseMutex(&fidp->mx);
6934 lock_ObtainWrite(&smb_rctLock);
6935 if (fidp->deleteOk) {
6936 osi_Log0(smb_logp, " Fid already closed.");
6937 lock_ReleaseWrite(&smb_rctLock);
6938 return CM_ERROR_BADFD;
6941 lock_ReleaseWrite(&smb_rctLock);
6943 lock_ObtainMutex(&fidp->mx);
6944 if (fidp->NTopen_dscp) {
6945 dscp = fidp->NTopen_dscp;
6946 cm_HoldSCache(dscp);
6949 if (fidp->NTopen_pathp)
6950 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6957 /* Don't jump the gun on an async raw write */
6958 while (fidp->raw_writers) {
6959 lock_ReleaseMutex(&fidp->mx);
6960 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6961 lock_ObtainMutex(&fidp->mx);
6964 /* watch for ioctl closes, and read-only opens */
6966 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6967 == SMB_FID_OPENWRITE) {
6968 if (dosTime != 0 && dosTime != -1) {
6969 lock_ObtainWrite(&fidp->scp->rw);
6970 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6971 /* This fixes defect 10958 */
6972 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6973 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6974 lock_ReleaseWrite(&fidp->scp->rw);
6976 if (smb_AsyncStore != 2) {
6977 lock_ReleaseMutex(&fidp->mx);
6978 code = cm_FSync(scp, userp, &req, FALSE);
6979 lock_ObtainMutex(&fidp->mx);
6985 /* unlock any pending locks */
6986 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6987 scp->fileType == CM_SCACHETYPE_FILE) {
6991 lock_ReleaseMutex(&fidp->mx);
6994 * CM_UNLOCK_FLAG_BY_FID doesn't look at the process ID.
6997 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6998 lock_ObtainWrite(&scp->rw);
7000 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
7001 CM_SCACHESYNC_NEEDCALLBACK
7002 | CM_SCACHESYNC_GETSTATUS
7003 | CM_SCACHESYNC_LOCK);
7007 "smb CoreClose SyncOp failure code 0x%x", tcode);
7008 goto post_syncopdone;
7011 cm_UnlockByKey(scp, key, CM_UNLOCK_FLAG_BY_FID, userp, &req);
7013 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
7017 lock_ReleaseWrite(&scp->rw);
7018 lock_ObtainMutex(&fidp->mx);
7021 if (fidp->flags & SMB_FID_DELONCLOSE) {
7022 clientchar_t *fullPathp = NULL;
7023 fschar_t *originalNamep = NULL;
7025 lock_ReleaseMutex(&fidp->mx);
7027 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
7032 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
7033 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
7034 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
7036 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7037 smb_NotifyChange(FILE_ACTION_REMOVED,
7038 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
7039 dscp, fullPathp, NULL, TRUE);
7042 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
7044 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7045 smb_NotifyChange(FILE_ACTION_REMOVED,
7046 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7047 dscp, fullPathp, NULL, TRUE);
7054 free(originalNamep);
7056 lock_ObtainMutex(&fidp->mx);
7057 fidp->flags &= ~SMB_FID_DELONCLOSE;
7060 /* if this was a newly created file, then clear the creator
7061 * in the stat cache entry. */
7062 if (fidp->flags & SMB_FID_CREATED) {
7064 fidp->flags &= ~SMB_FID_CREATED;
7067 if (fidp->flags & SMB_FID_NTOPEN) {
7068 cm_ReleaseSCache(fidp->NTopen_dscp);
7069 fidp->NTopen_dscp = NULL;
7070 free(fidp->NTopen_pathp);
7071 fidp->NTopen_pathp = NULL;
7072 fidp->flags &= ~SMB_FID_NTOPEN;
7074 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
7075 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7078 if (fidp->NTopen_wholepathp) {
7079 free(fidp->NTopen_wholepathp);
7080 fidp->NTopen_wholepathp = NULL;
7084 cm_ReleaseSCache(fidp->scp);
7087 lock_ReleaseMutex(&fidp->mx);
7090 cm_ReleaseSCache(dscp);
7093 cm_ReleaseSCache(delscp);
7097 lock_ObtainWrite(&scp->rw);
7098 if (nullcreator && scp->creator == userp)
7099 scp->creator = NULL;
7100 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7101 lock_ReleaseWrite(&scp->rw);
7102 cm_ReleaseSCache(scp);
7112 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7120 fid = smb_GetSMBParm(inp, 0);
7121 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7123 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7125 fid = smb_ChainFID(fid, inp);
7126 fidp = smb_FindFID(vcp, fid, 0);
7128 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
7130 return CM_ERROR_BADFD;
7133 userp = smb_GetUserFromVCP(vcp, inp);
7135 code = smb_CloseFID(vcp, fidp, userp, dosTime);
7137 smb_ReleaseFID(fidp);
7138 cm_ReleaseUser(userp);
7143 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7145 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7146 cm_user_t *userp, long *readp)
7152 osi_hyper_t fileLength;
7154 osi_hyper_t lastByte;
7155 osi_hyper_t bufferOffset;
7159 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7162 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7163 fidp->fid, offsetp->LowPart, count);
7167 lock_ObtainMutex(&fidp->mx);
7168 /* make sure we have a readable FD */
7169 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7170 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7171 fidp->fid, fidp->flags);
7172 lock_ReleaseMutex(&fidp->mx);
7173 code = CM_ERROR_BADFDOP;
7178 lock_ReleaseMutex(&fidp->mx);
7179 code = CM_ERROR_BADFD;
7190 lock_ObtainWrite(&scp->rw);
7192 if (offset.HighPart == 0) {
7193 chunk = offset.LowPart >> cm_logChunkSize;
7194 if (chunk != fidp->curr_chunk) {
7195 fidp->prev_chunk = fidp->curr_chunk;
7196 fidp->curr_chunk = chunk;
7198 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7201 lock_ReleaseMutex(&fidp->mx);
7203 /* start by looking up the file's end */
7204 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7205 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7209 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7211 /* now we have the entry locked, look up the length */
7212 fileLength = scp->length;
7214 /* adjust count down so that it won't go past EOF */
7215 thyper.LowPart = count;
7216 thyper.HighPart = 0;
7217 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7219 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7220 /* we'd read past EOF, so just stop at fileLength bytes.
7221 * Start by computing how many bytes remain in the file.
7223 thyper = LargeIntegerSubtract(fileLength, offset);
7225 /* if we are past EOF, read 0 bytes */
7226 if (LargeIntegerLessThanZero(thyper))
7229 count = thyper.LowPart;
7234 /* now, copy the data one buffer at a time,
7235 * until we've filled the request packet
7238 /* if we've copied all the data requested, we're done */
7239 if (count <= 0) break;
7241 /* otherwise, load up a buffer of data */
7242 thyper.HighPart = offset.HighPart;
7243 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7244 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7247 buf_Release(bufferp);
7250 lock_ReleaseWrite(&scp->rw);
7252 code = buf_Get(scp, &thyper, &req, &bufferp);
7254 lock_ObtainWrite(&scp->rw);
7255 if (code) goto done;
7256 bufferOffset = thyper;
7258 /* now get the data in the cache */
7260 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7261 CM_SCACHESYNC_NEEDCALLBACK |
7262 CM_SCACHESYNC_READ);
7266 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7268 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7270 /* otherwise, load the buffer and try again */
7271 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7275 buf_Release(bufferp);
7279 } /* if (wrong buffer) ... */
7281 /* now we have the right buffer loaded. Copy out the
7282 * data from here to the user's buffer.
7284 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7286 /* and figure out how many bytes we want from this buffer */
7287 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7288 if (nbytes > count) nbytes = count; /* don't go past EOF */
7290 /* now copy the data */
7291 memcpy(op, bufferp->datap + bufIndex, nbytes);
7293 /* adjust counters, pointers, etc. */
7296 thyper.LowPart = nbytes;
7297 thyper.HighPart = 0;
7298 offset = LargeIntegerAdd(thyper, offset);
7302 lock_ReleaseWrite(&scp->rw);
7304 buf_Release(bufferp);
7306 if (code == 0 && sequential)
7307 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7309 cm_ReleaseSCache(scp);
7312 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7313 fidp->fid, code, *readp);
7318 * smb_WriteData -- common code for Write and Raw Write
7320 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7321 cm_user_t *userp, long *writtenp)
7323 osi_hyper_t offset = *offsetp;
7326 cm_scache_t *scp = NULL;
7327 osi_hyper_t fileLength; /* file's length at start of write */
7328 osi_hyper_t minLength; /* don't read past this */
7329 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7330 cm_buf_t *bufferp = NULL;
7331 osi_hyper_t thyper; /* hyper tmp variable */
7332 osi_hyper_t bufferOffset;
7333 afs_uint32 bufIndex; /* index in buffer where our data is */
7334 int doWriteBack = 0;
7335 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7338 int needSyncOpDone = 0;
7340 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7341 fidp->fid, offsetp->LowPart, count);
7345 lock_ObtainMutex(&fidp->mx);
7346 /* make sure we have a writable FD */
7347 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7348 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7349 fidp->fid, fidp->flags);
7350 lock_ReleaseMutex(&fidp->mx);
7351 code = CM_ERROR_BADFDOP;
7359 lock_ReleaseMutex(&fidp->mx);
7361 lock_ObtainWrite(&scp->rw);
7362 /* start by looking up the file's end */
7363 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7364 CM_SCACHESYNC_NEEDCALLBACK
7365 | CM_SCACHESYNC_SETSTATUS
7366 | CM_SCACHESYNC_GETSTATUS);
7370 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7372 /* now we have the entry locked, look up the length */
7373 fileLength = scp->length;
7374 minLength = fileLength;
7375 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7376 minLength = scp->serverLength;
7378 /* adjust file length if we extend past EOF */
7379 thyper.LowPart = count;
7380 thyper.HighPart = 0;
7381 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7382 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7383 /* we'd write past EOF, so extend the file */
7384 scp->mask |= CM_SCACHEMASK_LENGTH;
7385 scp->length = thyper;
7386 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7388 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7390 /* now, if the new position (thyper) and the old (offset) are in
7391 * different storeback windows, remember to store back the previous
7392 * storeback window when we're done with the write.
7394 * the purpose of this logic is to slow down the CIFS client
7395 * in order to avoid the client disconnecting during the CLOSE
7396 * operation if there are too many dirty buffers left to write
7397 * than can be accomplished during 45 seconds. This used to be
7398 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7399 * so that we can read larger amounts of data at a time.
7401 if (smb_AsyncStore == 1 &&
7402 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7403 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7404 /* they're different */
7406 writeBackOffset.HighPart = offset.HighPart;
7407 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7412 /* now, copy the data one buffer at a time, until we've filled the
7414 while (count != 0) {
7416 /* handle over quota or out of space */
7417 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7418 *writtenp = written;
7419 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7423 /* otherwise, load up a buffer of data */
7424 thyper.HighPart = offset.HighPart;
7425 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7426 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7429 if (needSyncOpDone) {
7430 cm_SyncOpDone(scp, bufferp,
7431 CM_SCACHESYNC_NEEDCALLBACK
7432 | CM_SCACHESYNC_WRITE
7433 | CM_SCACHESYNC_BUFLOCKED);
7436 lock_ReleaseMutex(&bufferp->mx);
7437 buf_Release(bufferp);
7440 lock_ReleaseWrite(&scp->rw);
7442 code = buf_Get(scp, &thyper, &req, &bufferp);
7444 lock_ObtainMutex(&bufferp->mx);
7445 lock_ObtainWrite(&scp->rw);
7446 if (code) goto done;
7448 bufferOffset = thyper;
7450 /* now get the data in the cache */
7452 if (!needSyncOpDone) {
7453 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7454 CM_SCACHESYNC_NEEDCALLBACK
7455 | CM_SCACHESYNC_WRITE
7456 | CM_SCACHESYNC_BUFLOCKED);
7463 /* If we're overwriting the entire buffer, or
7464 * if we're writing at or past EOF, mark the
7465 * buffer as current so we don't call
7466 * cm_GetBuffer. This skips the fetch from the
7467 * server in those cases where we're going to
7468 * obliterate all the data in the buffer anyway,
7469 * or in those cases where there is no useful
7470 * data at the server to start with.
7472 * Use minLength instead of scp->length, since
7473 * the latter has already been updated by this
7476 * The scp lock has been dropped multiple times
7477 * so the minLength must be refreshed before it
7481 minLength = scp->length;
7482 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7483 minLength = scp->serverLength;
7485 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7486 || LargeIntegerEqualTo(offset, bufferp->offset)
7487 && (count >= cm_data.buf_blockSize
7488 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7489 ConvertLongToLargeInteger(count)),
7491 if (count < cm_data.buf_blockSize
7492 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7493 memset(bufferp->datap, 0,
7494 cm_data.buf_blockSize);
7495 bufferp->dataVersion = scp->dataVersion;
7498 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7500 /* otherwise, load the buffer and try again */
7501 cm_SyncOpDone(scp, bufferp,
7502 CM_SCACHESYNC_NEEDCALLBACK
7503 | CM_SCACHESYNC_WRITE
7504 | CM_SCACHESYNC_BUFLOCKED);
7507 lock_ReleaseMutex(&bufferp->mx);
7508 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7510 lock_ReleaseWrite(&scp->rw);
7511 lock_ObtainMutex(&bufferp->mx);
7512 lock_ObtainWrite(&scp->rw);
7516 } /* if (wrong buffer) ... */
7518 /* now we have the right buffer loaded. Copy out the
7519 * data from here to the user's buffer.
7521 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7523 /* and figure out how many bytes we want from this buffer */
7524 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7526 nbytes = count; /* don't go past end of request */
7528 /* now copy the data */
7529 memcpy(bufferp->datap + bufIndex, op, nbytes);
7530 buf_SetDirty(bufferp, &req, bufIndex, nbytes, userp);
7532 /* adjust counters, pointers, etc. */
7536 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7537 } /* while count != 0 */
7540 if (bufferp && needSyncOpDone) {
7541 cm_SyncOpDone(scp, bufferp,
7542 CM_SCACHESYNC_NEEDCALLBACK
7543 | CM_SCACHESYNC_WRITE
7544 | CM_SCACHESYNC_BUFLOCKED);
7547 lock_ReleaseWrite(&scp->rw);
7550 lock_ReleaseMutex(&bufferp->mx);
7551 buf_Release(bufferp);
7554 lock_ObtainMutex(&fidp->mx);
7555 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7556 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7558 lock_ReleaseMutex(&fidp->mx);
7559 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7560 fidp->NTopen_dscp, fidp->NTopen_pathp,
7563 lock_ReleaseMutex(&fidp->mx);
7567 if (smb_AsyncStore > 0) {
7570 rock_BkgStore_t *rockp = malloc(sizeof(*rockp));
7573 lock_ObtainWrite(&scp->rw);
7574 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7576 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7577 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7579 lock_ReleaseWrite(&scp->rw);
7581 rockp->length = smb_AsyncStoreSize;
7582 rockp->offset = writeBackOffset;
7584 cm_QueueBKGRequest(scp, cm_BkgStore, rockp, userp, &req);
7585 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7586 /* rock is freed by cm_BkgDaemon */
7593 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7597 cm_ReleaseSCache(scp);
7600 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7601 fidp->fid, code, *writtenp);
7606 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7609 unsigned short count;
7611 unsigned short hint;
7612 long written = 0, total_written = 0;
7615 smb_t* smbp = (smb_t*) inp;
7619 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7621 int inDataBlockCount;
7623 fd = smb_GetSMBParm(inp, 0);
7624 count = smb_GetSMBParm(inp, 1);
7625 offset.HighPart = 0; /* too bad */
7626 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7627 hint = smb_GetSMBParm(inp, 4);
7629 op = smb_GetSMBData(inp, NULL);
7630 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7632 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7633 fd, offset.LowPart, count);
7635 fd = smb_ChainFID(fd, inp);
7636 fidp = smb_FindFID(vcp, fd, 0);
7638 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7640 return CM_ERROR_BADFD;
7643 lock_ObtainMutex(&fidp->mx);
7644 if (fidp->flags & SMB_FID_IOCTL) {
7645 lock_ReleaseMutex(&fidp->mx);
7646 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7647 smb_ReleaseFID(fidp);
7648 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7652 if (fidp->flags & SMB_FID_RPC) {
7653 lock_ReleaseMutex(&fidp->mx);
7654 code = smb_RPCWrite(fidp, vcp, inp, outp);
7655 smb_ReleaseFID(fidp);
7656 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7661 lock_ReleaseMutex(&fidp->mx);
7662 smb_ReleaseFID(fidp);
7663 return CM_ERROR_BADFD;
7666 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7667 lock_ReleaseMutex(&fidp->mx);
7668 smb_CloseFID(vcp, fidp, NULL, 0);
7669 smb_ReleaseFID(fidp);
7670 return CM_ERROR_NOSUCHFILE;
7675 lock_ReleaseMutex(&fidp->mx);
7676 userp = smb_GetUserFromVCP(vcp, inp);
7680 LARGE_INTEGER LOffset;
7681 LARGE_INTEGER LLength;
7684 key = cm_GenerateKey(vcp->vcID, pid, fd);
7686 LOffset.HighPart = offset.HighPart;
7687 LOffset.LowPart = offset.LowPart;
7688 LLength.HighPart = 0;
7689 LLength.LowPart = count;
7691 lock_ObtainWrite(&scp->rw);
7692 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7693 lock_ReleaseWrite(&scp->rw);
7696 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7701 /* special case: 0 bytes transferred means truncate to this position */
7705 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7709 truncAttr.mask = CM_ATTRMASK_LENGTH;
7710 truncAttr.length.LowPart = offset.LowPart;
7711 truncAttr.length.HighPart = 0;
7712 lock_ObtainMutex(&fidp->mx);
7713 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7714 fidp->flags |= SMB_FID_LENGTHSETDONE;
7715 lock_ReleaseMutex(&fidp->mx);
7716 smb_SetSMBParm(outp, 0, 0 /* count */);
7717 smb_SetSMBDataLength(outp, 0);
7722 * Work around bug in NT client
7724 * When copying a file, the NT client should first copy the data,
7725 * then copy the last write time. But sometimes the NT client does
7726 * these in the wrong order, so the data copies would inadvertently
7727 * cause the last write time to be overwritten. We try to detect this,
7728 * and don't set client mod time if we think that would go against the
7731 lock_ObtainMutex(&fidp->mx);
7732 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7733 lock_ObtainWrite(&fidp->scp->rw);
7734 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7735 fidp->scp->clientModTime = time(NULL);
7736 lock_ReleaseWrite(&fidp->scp->rw);
7738 lock_ReleaseMutex(&fidp->mx);
7741 while ( code == 0 && count > 0 ) {
7742 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7743 if (code == 0 && written == 0)
7744 code = CM_ERROR_PARTIALWRITE;
7746 offset = LargeIntegerAdd(offset,
7747 ConvertLongToLargeInteger(written));
7748 count -= (unsigned short)written;
7749 total_written += written;
7753 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7754 total_written, code);
7756 /* set the packet data length to 3 bytes for the data block header,
7757 * plus the size of the data.
7759 smb_SetSMBParm(outp, 0, total_written);
7760 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7761 smb_SetSMBParm(outp, 3, hint);
7762 smb_SetSMBDataLength(outp, 0);
7765 smb_ReleaseFID(fidp);
7766 cm_ReleaseUser(userp);
7767 cm_ReleaseSCache(scp);
7772 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7773 NCB *ncbp, raw_write_cont_t *rwcp)
7782 fd = smb_GetSMBParm(inp, 0);
7783 fidp = smb_FindFID(vcp, fd, 0);
7785 lock_ObtainMutex(&fidp->mx);
7787 lock_ReleaseMutex(&fidp->mx);
7788 smb_ReleaseFID(fidp);
7792 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7793 lock_ReleaseMutex(&fidp->mx);
7794 smb_CloseFID(vcp, fidp, NULL, 0);
7795 smb_ReleaseFID(fidp);
7798 lock_ReleaseMutex(&fidp->mx);
7800 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7801 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7803 userp = smb_GetUserFromVCP(vcp, inp);
7806 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7808 if (rwcp->writeMode & 0x1) { /* synchronous */
7811 smb_FormatResponsePacket(vcp, inp, outp);
7812 op = (smb_t *) outp;
7813 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7814 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7815 smb_SetSMBDataLength(outp, 0);
7816 smb_SendPacket(vcp, outp);
7817 smb_FreePacket(outp);
7819 else { /* asynchronous */
7820 lock_ObtainMutex(&fidp->mx);
7821 fidp->raw_writers--;
7822 if (fidp->raw_writers == 0)
7823 thrd_SetEvent(fidp->raw_write_event);
7824 lock_ReleaseMutex(&fidp->mx);
7827 /* Give back raw buffer */
7828 lock_ObtainMutex(&smb_RawBufLock);
7829 *((char **)rawBuf) = smb_RawBufs;
7830 smb_RawBufs = rawBuf;
7831 lock_ReleaseMutex(&smb_RawBufLock);
7833 smb_ReleaseFID(fidp);
7834 cm_ReleaseUser(userp);
7837 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7842 /* SMB_COM_WRITE_RAW */
7843 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7846 long count, written = 0, total_written = 0;
7850 smb_t *smbp = (smb_t*) inp;
7855 unsigned short writeMode;
7857 fd = smb_GetSMBParm(inp, 0);
7858 totalCount = smb_GetSMBParm(inp, 1);
7859 count = smb_GetSMBParm(inp, 10);
7860 writeMode = smb_GetSMBParm(inp, 7);
7862 op = (char *) inp->data;
7863 op += smb_GetSMBParm(inp, 11);
7865 offset.HighPart = 0;
7866 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7868 if (*inp->wctp == 14) {
7869 /* we received a 64-bit file offset */
7870 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7872 if (LargeIntegerLessThanZero(offset)) {
7874 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7875 offset.HighPart, offset.LowPart);
7876 return CM_ERROR_BADSMB;
7879 offset.HighPart = 0; /* 32-bit file offset */
7883 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7884 fd, offset.HighPart, offset.LowPart, count);
7886 " WriteRaw WriteMode 0x%x",
7889 fd = smb_ChainFID(fd, inp);
7890 fidp = smb_FindFID(vcp, fd, 0);
7892 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7894 return CM_ERROR_BADFD;
7896 lock_ObtainMutex(&fidp->mx);
7898 lock_ReleaseMutex(&fidp->mx);
7899 smb_ReleaseFID(fidp);
7900 return CM_ERROR_BADFD;
7903 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7904 lock_ReleaseMutex(&fidp->mx);
7905 smb_CloseFID(vcp, fidp, NULL, 0);
7906 smb_ReleaseFID(fidp);
7907 return CM_ERROR_NOSUCHFILE;
7912 lock_ReleaseMutex(&fidp->mx);
7917 LARGE_INTEGER LOffset;
7918 LARGE_INTEGER LLength;
7921 key = cm_GenerateKey(vcp->vcID, pid, fd);
7923 LOffset.HighPart = offset.HighPart;
7924 LOffset.LowPart = offset.LowPart;
7925 LLength.HighPart = 0;
7926 LLength.LowPart = count;
7928 lock_ObtainWrite(&scp->rw);
7929 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7930 lock_ReleaseWrite(&scp->rw);
7933 cm_ReleaseSCache(scp);
7934 smb_ReleaseFID(fidp);
7939 userp = smb_GetUserFromVCP(vcp, inp);
7942 * Work around bug in NT client
7944 * When copying a file, the NT client should first copy the data,
7945 * then copy the last write time. But sometimes the NT client does
7946 * these in the wrong order, so the data copies would inadvertently
7947 * cause the last write time to be overwritten. We try to detect this,
7948 * and don't set client mod time if we think that would go against the
7951 lock_ObtainMutex(&fidp->mx);
7952 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7953 lock_ObtainWrite(&fidp->scp->rw);
7954 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7955 fidp->scp->clientModTime = time(NULL);
7956 lock_ReleaseWrite(&fidp->scp->rw);
7958 lock_ReleaseMutex(&fidp->mx);
7961 while ( code == 0 && count > 0 ) {
7962 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7963 if (code == 0 && written == 0)
7964 code = CM_ERROR_PARTIALWRITE;
7966 offset = LargeIntegerAdd(offset,
7967 ConvertLongToLargeInteger(written));
7970 total_written += written;
7974 /* Get a raw buffer */
7977 lock_ObtainMutex(&smb_RawBufLock);
7979 /* Get a raw buf, from head of list */
7980 rawBuf = smb_RawBufs;
7981 smb_RawBufs = *(char **)smb_RawBufs;
7984 code = CM_ERROR_USESTD;
7986 lock_ReleaseMutex(&smb_RawBufLock);
7989 /* Don't allow a premature Close */
7990 if (code == 0 && (writeMode & 1) == 0) {
7991 lock_ObtainMutex(&fidp->mx);
7992 fidp->raw_writers++;
7993 thrd_ResetEvent(fidp->raw_write_event);
7994 lock_ReleaseMutex(&fidp->mx);
7997 smb_ReleaseFID(fidp);
7998 cm_ReleaseUser(userp);
7999 cm_ReleaseSCache(scp);
8002 smb_SetSMBParm(outp, 0, total_written);
8003 smb_SetSMBDataLength(outp, 0);
8004 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
8009 offset = LargeIntegerAdd(offset,
8010 ConvertLongToLargeInteger(count));
8014 rwcp->offset.HighPart = offset.HighPart;
8015 rwcp->offset.LowPart = offset.LowPart;
8016 rwcp->count = totalCount - count;
8017 rwcp->writeMode = writeMode;
8018 rwcp->alreadyWritten = total_written;
8020 /* set the packet data length to 3 bytes for the data block header,
8021 * plus the size of the data.
8023 smb_SetSMBParm(outp, 0, 0xffff);
8024 smb_SetSMBDataLength(outp, 0);
8030 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8033 long count, finalCount;
8037 smb_t *smbp = (smb_t*) inp;
8043 fd = smb_GetSMBParm(inp, 0);
8044 count = smb_GetSMBParm(inp, 1);
8045 offset.HighPart = 0; /* too bad */
8046 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8048 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
8049 fd, offset.LowPart, count);
8051 fd = smb_ChainFID(fd, inp);
8052 fidp = smb_FindFID(vcp, fd, 0);
8054 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
8056 return CM_ERROR_BADFD;
8058 lock_ObtainMutex(&fidp->mx);
8059 if (fidp->flags & SMB_FID_IOCTL) {
8060 lock_ReleaseMutex(&fidp->mx);
8061 code = smb_IoctlRead(fidp, vcp, inp, outp);
8062 smb_ReleaseFID(fidp);
8066 if (fidp->flags & SMB_FID_RPC) {
8067 lock_ReleaseMutex(&fidp->mx);
8068 code = smb_RPCRead(fidp, vcp, inp, outp);
8069 smb_ReleaseFID(fidp);
8074 lock_ReleaseMutex(&fidp->mx);
8075 smb_ReleaseFID(fidp);
8076 return CM_ERROR_BADFD;
8079 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8080 lock_ReleaseMutex(&fidp->mx);
8081 smb_CloseFID(vcp, fidp, NULL, 0);
8082 smb_ReleaseFID(fidp);
8083 return CM_ERROR_NOSUCHFILE;
8088 lock_ReleaseMutex(&fidp->mx);
8091 LARGE_INTEGER LOffset, LLength;
8095 key = cm_GenerateKey(vcp->vcID, pid, fd);
8097 LOffset.HighPart = 0;
8098 LOffset.LowPart = offset.LowPart;
8099 LLength.HighPart = 0;
8100 LLength.LowPart = count;
8102 lock_ObtainWrite(&scp->rw);
8103 code = cm_LockCheckRead(scp, LOffset, LLength, key);
8104 lock_ReleaseWrite(&scp->rw);
8107 cm_ReleaseSCache(scp);
8108 smb_ReleaseFID(fidp);
8112 userp = smb_GetUserFromVCP(vcp, inp);
8114 /* remember this for final results */
8115 smb_SetSMBParm(outp, 0, count);
8116 smb_SetSMBParm(outp, 1, 0);
8117 smb_SetSMBParm(outp, 2, 0);
8118 smb_SetSMBParm(outp, 3, 0);
8119 smb_SetSMBParm(outp, 4, 0);
8121 /* set the packet data length to 3 bytes for the data block header,
8122 * plus the size of the data.
8124 smb_SetSMBDataLength(outp, count+3);
8126 /* get op ptr after putting in the parms, since otherwise we don't
8127 * know where the data really is.
8129 op = smb_GetSMBData(outp, NULL);
8131 /* now emit the data block header: 1 byte of type and 2 bytes of length */
8132 *op++ = 1; /* data block marker */
8133 *op++ = (unsigned char) (count & 0xff);
8134 *op++ = (unsigned char) ((count >> 8) & 0xff);
8136 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8138 /* fix some things up */
8139 smb_SetSMBParm(outp, 0, finalCount);
8140 smb_SetSMBDataLength(outp, finalCount+3);
8142 smb_ReleaseFID(fidp);
8144 cm_ReleaseUser(userp);
8145 cm_ReleaseSCache(scp);
8149 /* SMB_COM_CREATE_DIRECTORY */
8150 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8152 clientchar_t *pathp;
8157 cm_scache_t *dscp; /* dir we're dealing with */
8158 cm_scache_t *scp; /* file we're creating */
8160 int initialModeBits;
8161 clientchar_t *lastNamep;
8163 clientchar_t *tidPathp;
8170 /* compute initial mode bits based on read-only flag in attributes */
8171 initialModeBits = 0777;
8173 tp = smb_GetSMBData(inp, NULL);
8174 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8176 return CM_ERROR_BADSMB;
8178 spacep = inp->spacep;
8179 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8181 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8182 return CM_ERROR_EXISTS;
8184 userp = smb_GetUserFromVCP(vcp, inp);
8186 caseFold = CM_FLAG_CASEFOLD;
8188 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8190 cm_ReleaseUser(userp);
8191 return CM_ERROR_NOSUCHPATH;
8194 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
8195 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8196 userp, tidPathp, &req, &dscp);
8199 cm_ReleaseUser(userp);
8204 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8205 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8206 cm_ReleaseSCache(dscp);
8207 cm_ReleaseUser(userp);
8208 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8209 return CM_ERROR_PATH_NOT_COVERED;
8211 return CM_ERROR_NOSUCHPATH;
8213 #endif /* DFS_SUPPORT */
8215 /* otherwise, scp points to the parent directory. Do a lookup, and
8216 * fail if we find it. Otherwise, we do the create.
8222 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8223 if (scp) cm_ReleaseSCache(scp);
8224 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8225 if (code == 0) code = CM_ERROR_EXISTS;
8226 cm_ReleaseSCache(dscp);
8227 cm_ReleaseUser(userp);
8231 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8232 setAttr.clientModTime = time(NULL);
8233 smb_SetInitialModeBitsForDir(0, &setAttr);
8235 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8236 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8237 smb_NotifyChange(FILE_ACTION_ADDED,
8238 FILE_NOTIFY_CHANGE_DIR_NAME,
8239 dscp, lastNamep, NULL, TRUE);
8241 /* we don't need this any longer */
8242 cm_ReleaseSCache(dscp);
8245 /* something went wrong creating or truncating the file */
8246 cm_ReleaseUser(userp);
8250 /* otherwise we succeeded */
8251 smb_SetSMBDataLength(outp, 0);
8252 cm_ReleaseUser(userp);
8257 BOOL smb_IsLegalFilename(clientchar_t *filename)
8260 * Find the longest substring of filename that does not contain
8261 * any of the chars in illegalChars. If that substring is less
8262 * than the length of the whole string, then one or more of the
8263 * illegal chars is in filename.
8265 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8271 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8272 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8274 clientchar_t *pathp;
8280 cm_scache_t *dscp; /* dir we're dealing with */
8281 cm_scache_t *scp; /* file we're creating */
8285 clientchar_t *lastNamep;
8288 clientchar_t *tidPathp;
8290 int created = 0; /* the file was new */
8295 excl = (inp->inCom == 0x03)? 0 : 1;
8297 attributes = smb_GetSMBParm(inp, 0);
8298 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8300 tp = smb_GetSMBData(inp, NULL);
8301 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8303 return CM_ERROR_BADSMB;
8305 spacep = inp->spacep;
8306 /* smb_StripLastComponent will strip "::$DATA" if present */
8307 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8309 if (!cm_IsValidClientString(pathp)) {
8311 clientchar_t * hexp;
8313 hexp = cm_GetRawCharsAlloc(pathp, -1);
8314 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8315 osi_LogSaveClientString(smb_logp, hexp));
8319 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8321 return CM_ERROR_BADNTFILENAME;
8324 userp = smb_GetUserFromVCP(vcp, inp);
8326 caseFold = CM_FLAG_CASEFOLD;
8328 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8330 cm_ReleaseUser(userp);
8331 return CM_ERROR_NOSUCHPATH;
8333 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8334 userp, tidPathp, &req, &dscp);
8337 cm_ReleaseUser(userp);
8342 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8343 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8344 cm_ReleaseSCache(dscp);
8345 cm_ReleaseUser(userp);
8346 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8347 return CM_ERROR_PATH_NOT_COVERED;
8349 return CM_ERROR_NOSUCHPATH;
8351 #endif /* DFS_SUPPORT */
8353 /* otherwise, scp points to the parent directory. Do a lookup, and
8354 * truncate the file if we find it, otherwise we create the file.
8361 if (!smb_IsLegalFilename(lastNamep))
8362 return CM_ERROR_BADNTFILENAME;
8364 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8365 #ifdef DEBUG_VERBOSE
8368 hexp = osi_HexifyString( lastNamep );
8369 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8374 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8375 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8376 cm_ReleaseSCache(dscp);
8377 cm_ReleaseUser(userp);
8381 /* if we get here, if code is 0, the file exists and is represented by
8382 * scp. Otherwise, we have to create it.
8386 /* oops, file shouldn't be there */
8387 cm_ReleaseSCache(dscp);
8388 cm_ReleaseSCache(scp);
8389 cm_ReleaseUser(userp);
8390 return CM_ERROR_EXISTS;
8393 setAttr.mask = CM_ATTRMASK_LENGTH;
8394 setAttr.length.LowPart = 0;
8395 setAttr.length.HighPart = 0;
8396 code = cm_SetAttr(scp, &setAttr, userp, &req);
8399 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8400 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8401 smb_SetInitialModeBitsForFile(attributes, &setAttr);
8403 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8407 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8408 smb_NotifyChange(FILE_ACTION_ADDED,
8409 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8410 dscp, lastNamep, NULL, TRUE);
8411 } else if (!excl && code == CM_ERROR_EXISTS) {
8412 /* not an exclusive create, and someone else tried
8413 * creating it already, then we open it anyway. We
8414 * don't bother retrying after this, since if this next
8415 * fails, that means that the file was deleted after
8416 * we started this call.
8418 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8421 setAttr.mask = CM_ATTRMASK_LENGTH;
8422 setAttr.length.LowPart = 0;
8423 setAttr.length.HighPart = 0;
8424 code = cm_SetAttr(scp, &setAttr, userp, &req);
8429 /* we don't need this any longer */
8430 cm_ReleaseSCache(dscp);
8433 /* something went wrong creating or truncating the file */
8434 if (scp) cm_ReleaseSCache(scp);
8435 cm_ReleaseUser(userp);
8439 /* make sure we only open files */
8440 if (scp->fileType != CM_SCACHETYPE_FILE) {
8441 cm_ReleaseSCache(scp);
8442 cm_ReleaseUser(userp);
8443 return CM_ERROR_ISDIR;
8446 /* now all we have to do is open the file itself */
8447 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8448 osi_assertx(fidp, "null smb_fid_t");
8452 lock_ObtainMutex(&fidp->mx);
8453 /* always create it open for read/write */
8454 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8456 /* remember that the file was newly created */
8458 fidp->flags |= SMB_FID_CREATED;
8460 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8462 /* save a pointer to the vnode */
8464 lock_ObtainWrite(&scp->rw);
8465 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8466 lock_ReleaseWrite(&scp->rw);
8469 fidp->userp = userp;
8470 lock_ReleaseMutex(&fidp->mx);
8472 smb_SetSMBParm(outp, 0, fidp->fid);
8473 smb_SetSMBDataLength(outp, 0);
8475 cm_Open(scp, 0, userp);
8477 smb_ReleaseFID(fidp);
8478 cm_ReleaseUser(userp);
8479 /* leave scp held since we put it in fidp->scp */
8484 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8487 osi_hyper_t new_offset;
8498 fd = smb_GetSMBParm(inp, 0);
8499 whence = smb_GetSMBParm(inp, 1);
8500 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8502 /* try to find the file descriptor */
8503 fd = smb_ChainFID(fd, inp);
8504 fidp = smb_FindFID(vcp, fd, 0);
8506 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8508 return CM_ERROR_BADFD;
8510 lock_ObtainMutex(&fidp->mx);
8511 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8512 lock_ReleaseMutex(&fidp->mx);
8513 smb_ReleaseFID(fidp);
8514 return CM_ERROR_BADFD;
8517 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8518 lock_ReleaseMutex(&fidp->mx);
8519 smb_CloseFID(vcp, fidp, NULL, 0);
8520 smb_ReleaseFID(fidp);
8521 return CM_ERROR_NOSUCHFILE;
8524 lock_ReleaseMutex(&fidp->mx);
8526 userp = smb_GetUserFromVCP(vcp, inp);
8528 lock_ObtainMutex(&fidp->mx);
8531 lock_ReleaseMutex(&fidp->mx);
8532 lock_ObtainWrite(&scp->rw);
8533 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8534 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8536 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8538 /* offset from current offset */
8539 new_offset = LargeIntegerAdd(fidp->offset,
8540 ConvertLongToLargeInteger(offset));
8542 else if (whence == 2) {
8543 /* offset from current EOF */
8544 new_offset = LargeIntegerAdd(scp->length,
8545 ConvertLongToLargeInteger(offset));
8547 new_offset = ConvertLongToLargeInteger(offset);
8550 fidp->offset = new_offset;
8551 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8552 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8553 smb_SetSMBDataLength(outp, 0);
8555 lock_ReleaseWrite(&scp->rw);
8556 smb_ReleaseFID(fidp);
8557 cm_ReleaseSCache(scp);
8558 cm_ReleaseUser(userp);
8562 /* dispatch all of the requests received in a packet. Due to chaining, this may
8563 * be more than one request.
8565 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8566 NCB *ncbp, raw_write_cont_t *rwcp)
8570 unsigned long code = 0;
8571 unsigned char *outWctp;
8572 int nparms; /* # of bytes of parameters */
8574 int nbytes; /* bytes of data, excluding count */
8577 unsigned short errCode;
8578 unsigned long NTStatus;
8580 unsigned char errClass;
8581 unsigned int oldGen;
8582 DWORD oldTime, newTime;
8584 /* get easy pointer to the data */
8585 smbp = (smb_t *) inp->data;
8587 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8588 /* setup the basic parms for the initial request in the packet */
8589 inp->inCom = smbp->com;
8590 inp->wctp = &smbp->wct;
8592 inp->ncb_length = ncbp->ncb_length;
8597 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8598 /* log it and discard it */
8599 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8600 __FILE__, __LINE__, ncbp->ncb_length);
8601 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8605 /* We are an ongoing op */
8606 thrd_Increment(&ongoingOps);
8608 /* set up response packet for receiving output */
8609 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8610 smb_FormatResponsePacket(vcp, inp, outp);
8611 outWctp = outp->wctp;
8613 /* Remember session generation number and time */
8614 oldGen = sessionGen;
8615 oldTime = GetTickCount();
8617 while (inp->inCom != 0xff) {
8618 dp = &smb_dispatchTable[inp->inCom];
8620 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8621 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8622 code = outp->resumeCode;
8626 /* process each request in the packet; inCom, wctp and inCount
8627 * are already set up.
8629 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8632 /* now do the dispatch */
8633 /* start by formatting the response record a little, as a default */
8634 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8636 outWctp[1] = 0xff; /* no operation */
8637 outWctp[2] = 0; /* padding */
8642 /* not a chained request, this is a more reasonable default */
8643 outWctp[0] = 0; /* wct of zero */
8644 outWctp[1] = 0; /* and bcc (word) of zero */
8648 /* once set, stays set. Doesn't matter, since we never chain
8649 * "no response" calls.
8651 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8655 /* we have a recognized operation */
8656 char * opName = myCrt_Dispatch(inp->inCom);
8659 smbp = (smb_t *) inp;
8661 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8662 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8663 if (inp->inCom == 0x1d) {
8665 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8667 code = (*(dp->procp)) (vcp, inp, outp);
8669 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8670 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8672 newTime = GetTickCount();
8673 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8674 opName, smbp->mid, newTime - oldTime);
8677 if ( code == CM_ERROR_BADSMB ||
8678 code == CM_ERROR_BADOP )
8680 #endif /* LOG_PACKET */
8682 /* ReceiveV3Tran2A handles its own logging */
8683 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8686 clientchar_t *treepath = NULL; /* do not free */
8687 clientchar_t *pathname = NULL;
8688 cm_fid_t afid = {0,0,0,0,0};
8690 uidp = smb_FindUID(vcp, smbp->uid, 0);
8691 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8692 fidp = smb_FindFID(vcp, inp->fid, 0);
8695 lock_ObtainMutex(&fidp->mx);
8696 if (fidp->NTopen_pathp)
8697 pathname = fidp->NTopen_pathp;
8699 afid = fidp->scp->fid;
8701 if (inp->stringsp->wdata)
8702 pathname = inp->stringsp->wdata;
8705 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)",
8706 opName, newTime - oldTime,
8707 smbp->uid, uidp ? uidp->unp->name : NULL,
8708 smbp->pid, smbp->mid, smbp->tid,
8711 afid.cell, afid.volume, afid.vnode, afid.unique);
8714 lock_ReleaseMutex(&fidp->mx);
8717 smb_ReleaseUID(uidp);
8719 smb_ReleaseFID(fidp);
8722 if (oldGen != sessionGen) {
8723 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8724 newTime - oldTime, ncbp->ncb_length);
8725 osi_Log3(smb_logp, "Request %s straddled session startup, "
8726 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8729 FreeSMBStrings(inp);
8731 /* bad opcode, fail the request, after displaying it */
8732 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8735 #endif /* LOG_PACKET */
8738 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8739 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8740 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8741 if (code == IDCANCEL)
8744 code = CM_ERROR_BADOP;
8747 /* catastrophic failure: log as much as possible */
8748 if (code == CM_ERROR_BADSMB) {
8749 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8753 #endif /* LOG_PACKET */
8754 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8757 code = CM_ERROR_INVAL;
8760 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8761 thrd_Decrement(&ongoingOps);
8766 /* now, if we failed, turn the current response into an empty
8767 * one, and fill in the response packet's error code.
8770 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8771 smb_MapNTError(code, &NTStatus, FALSE);
8772 outWctp = outp->wctp;
8773 smbp = (smb_t *) &outp->data;
8774 if (code != CM_ERROR_PARTIALWRITE
8775 && code != CM_ERROR_BUFFERTOOSMALL
8776 && code != CM_ERROR_GSSCONTINUE) {
8777 /* nuke wct and bcc. For a partial
8778 * write or an in-process authentication handshake,
8779 * assume they're OK.
8785 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8786 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8787 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8788 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8789 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8793 smb_MapCoreError(code, vcp, &errCode, &errClass);
8794 outWctp = outp->wctp;
8795 smbp = (smb_t *) &outp->data;
8796 if (code != CM_ERROR_PARTIALWRITE) {
8797 /* nuke wct and bcc. For a partial
8798 * write, assume they're OK.
8804 smbp->errLow = (unsigned char) (errCode & 0xff);
8805 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8806 smbp->rcls = errClass;
8809 } /* error occurred */
8811 /* if we're here, we've finished one request. Look to see if
8812 * this is a chained opcode. If it is, setup things to process
8813 * the chained request, and setup the output buffer to hold the
8814 * chained response. Start by finding the next input record.
8816 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8817 break; /* not a chained req */
8818 tp = inp->wctp; /* points to start of last request */
8819 /* in a chained request, the first two
8820 * parm fields are required, and are
8821 * AndXCommand/AndXReserved and
8823 if (tp[0] < 2) break;
8824 if (tp[1] == 0xff) break; /* no more chained opcodes */
8826 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8829 /* and now append the next output request to the end of this
8830 * last request. Begin by finding out where the last response
8831 * ends, since that's where we'll put our new response.
8833 outWctp = outp->wctp; /* ptr to out parameters */
8834 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8835 nparms = outWctp[0] << 1;
8836 tp = outWctp + nparms + 1; /* now points to bcc field */
8837 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8838 tp += 2 /* for the count itself */ + nbytes;
8839 /* tp now points to the new output record; go back and patch the
8840 * second parameter (off2) to point to the new record.
8842 temp = (unsigned int)(tp - outp->data);
8843 outWctp[3] = (unsigned char) (temp & 0xff);
8844 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8845 outWctp[2] = 0; /* padding */
8846 outWctp[1] = inp->inCom; /* next opcode */
8848 /* finally, setup for the next iteration */
8851 } /* while loop over all requests in the packet */
8853 /* now send the output packet, and return */
8855 smb_SendPacket(vcp, outp);
8856 thrd_Decrement(&ongoingOps);
8861 /* Wait for Netbios() calls to return, and make the results available to server
8862 * threads. Note that server threads can't wait on the NCBevents array
8863 * themselves, because NCB events are manual-reset, and the servers would race
8864 * each other to reset them.
8866 void smb_ClientWaiter(void *parmp)
8871 while (smbShutdownFlag == 0) {
8872 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8874 if (code == WAIT_OBJECT_0)
8877 /* error checking */
8878 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8880 int abandonIdx = code - WAIT_ABANDONED_0;
8881 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8884 if (code == WAIT_IO_COMPLETION)
8886 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8890 if (code == WAIT_TIMEOUT)
8892 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8895 if (code == WAIT_FAILED)
8897 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8900 idx = code - WAIT_OBJECT_0;
8902 /* check idx range! */
8903 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8905 /* this is fatal - log as much as possible */
8906 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8907 osi_assertx(0, "invalid index");
8910 thrd_ResetEvent(NCBevents[idx]);
8911 thrd_SetEvent(NCBreturns[0][idx]);
8916 * Try to have one NCBRECV request waiting for every live session. Not more
8917 * than one, because if there is more than one, it's hard to handle Write Raw.
8919 void smb_ServerWaiter(void *parmp)
8922 int idx_session, idx_NCB;
8925 while (smbShutdownFlag == 0) {
8927 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8929 if (code == WAIT_OBJECT_0)
8932 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8934 int abandonIdx = code - WAIT_ABANDONED_0;
8935 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8938 if (code == WAIT_IO_COMPLETION)
8940 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8944 if (code == WAIT_TIMEOUT)
8946 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8949 if (code == WAIT_FAILED)
8951 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8954 idx_session = code - WAIT_OBJECT_0;
8956 /* check idx range! */
8957 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8959 /* this is fatal - log as much as possible */
8960 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8961 osi_assertx(0, "invalid index");
8966 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8968 if (code == WAIT_OBJECT_0) {
8969 if (smbShutdownFlag == 1)
8975 /* error checking */
8976 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8978 int abandonIdx = code - WAIT_ABANDONED_0;
8979 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8982 if (code == WAIT_IO_COMPLETION)
8984 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8988 if (code == WAIT_TIMEOUT)
8990 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8993 if (code == WAIT_FAILED)
8995 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8998 idx_NCB = code - WAIT_OBJECT_0;
9000 /* check idx range! */
9001 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
9003 /* this is fatal - log as much as possible */
9004 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
9005 osi_assertx(0, "invalid index");
9008 /* Link them together */
9009 NCBsessions[idx_NCB] = idx_session;
9012 ncbp = NCBs[idx_NCB];
9013 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
9014 ncbp->ncb_command = NCBRECV | ASYNCH;
9015 ncbp->ncb_lana_num = lanas[idx_session];
9016 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
9017 ncbp->ncb_event = NCBevents[idx_NCB];
9018 ncbp->ncb_length = SMB_PACKETSIZE;
9023 typedef struct _monitored_task {
9026 LARGE_INTEGER start_time;
9028 BOOL trace_timer_hit;
9029 BOOL dump_timer_hit;
9032 typedef struct osi_queueHT {
9033 osi_queue_t * headp;
9034 osi_queue_t * tailp;
9037 static osi_queue_t *smb_monitored_tasks = NULL;
9038 static osi_queue_t *smb_free_monitored_tasks = NULL;
9040 static osi_mutex_t _monitor_mx;
9042 static HANDLE h_monitored_task_queue = NULL;
9043 static HANDLE h_monitored_task_shutdown = NULL;
9045 static time_t smb_last_dump_time = 0;
9047 DWORD smb_monitorReqs = 0;
9049 /* FILETIME comparison fuzz */
9050 #define MONITOR_FUZZ_TIMEOUT (1 * 10000000i64)
9052 /* Trace timeout is at 60 seconds */
9053 #define MONITOR_TRACE_TIMEOUT (60 * 10000000i64)
9055 /* Dump timeout is at 120 seconds */
9056 #define MONITOR_DUMP_TIMEOUT (120 * 10000000i64)
9058 /* Time before another dump is performed in seconds*/
9059 #define MONITOR_DUMP_RESET_TIMEOUT (600)
9061 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
9064 LARGE_INTEGER earliest;
9067 GetSystemTimeAsFileTime(&now);
9068 earliest.LowPart = now.dwLowDateTime;
9069 earliest.HighPart = now.dwHighDateTime;
9070 earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
9072 while ((t = (monitored_task *) taskmq->headp) != NULL &&
9074 (t->start_time.QuadPart < earliest.QuadPart ||
9076 t->dump_timer_hit)) {
9078 osi_QRemoveHT(&taskmq->headp,
9082 lock_ObtainMutex(&_monitor_mx);
9083 osi_QAdd(&smb_free_monitored_tasks, &t->q);
9084 lock_ReleaseMutex(&_monitor_mx);
9087 #ifdef INVARIANT_CHECK
9093 for (t = (monitored_task *) taskmq->headp;
9095 t = (monitored_task *) osi_QNext(&t->q)) {
9096 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9097 last.QuadPart = t->start_time.QuadPart;
9103 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
9105 monitored_task * task;
9106 monitored_task * tasks;
9108 lock_ObtainMutex(&_monitor_mx);
9109 tasks = (monitored_task *) smb_monitored_tasks;
9110 smb_monitored_tasks = NULL;
9111 lock_ReleaseMutex(&_monitor_mx);
9116 osi_QRemove((osi_queue_t **) &tasks, &task->q);
9118 if (task->started) {
9124 q.prevp = taskmq->tailp;
9126 /* Insertion sort by start_time. Earliest request is
9127 first. Since we are likely to receive new requests
9128 later, we start inserting from the back. */
9131 ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
9135 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
9136 else if (p->prevp == NULL)
9137 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
9139 osi_queue_t *o = p->prevp;
9141 osi_assert(o->nextp == p);
9145 p->prevp = &task->q;
9146 o->nextp = &task->q;
9150 /* Some task ending */
9154 for (p = taskmq->headp;
9158 monitored_task * mt = (monitored_task *) p;
9160 if (mt->task_id == task->task_id) {
9162 osi_QRemoveHT(&taskmq->headp,
9165 lock_ObtainMutex(&_monitor_mx);
9166 osi_QAdd(&smb_free_monitored_tasks, p);
9167 lock_ReleaseMutex(&_monitor_mx);
9173 lock_ObtainMutex(&_monitor_mx);
9174 osi_QAdd(&smb_free_monitored_tasks, &task->q);
9175 lock_ReleaseMutex(&_monitor_mx);
9179 #ifdef INVARIANT_CHECK
9186 for (t = (monitored_task *) taskmq->headp;
9188 t = (monitored_task *) osi_QNext(&t->q)) {
9189 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9190 last.QuadPart = t->start_time.QuadPart;
9196 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9198 if (!task->trace_timer_hit) {
9200 task->trace_timer_hit = TRUE;
9202 osi_LogEnable(afsd_logp);
9203 rx_DebugOnOff(TRUE);
9205 } else if (!task->dump_timer_hit) {
9210 if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9211 task->dump_timer_hit = TRUE;
9212 smb_last_dump_time = now;
9214 GenerateMiniDump(NULL);
9220 * Server request monitoring
9222 * The server monitor runs in a separate thread and monitors server
9223 * requests for potential timeouts. It examines notifcations queued
9224 * by smb_NotifyRequestEvent() and waits for potential timeout events:
9226 * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9227 * enables trace logging.
9229 * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9230 * out a dump file that will hopefully contain enough evidence to
9231 * figure out why the timeout event occurred.
9234 void smb_ServerMonitor(VOID * parmp)
9236 osi_queueHT_t in_progress = { NULL, NULL };
9237 HANDLE h_timer = NULL;
9241 h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9242 h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9243 h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9245 lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9247 h_all[0] = h_monitored_task_queue;
9249 h_all[2] = h_monitored_task_shutdown;
9254 rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9256 if (rv == WAIT_OBJECT_0) {
9258 smb_SlurpNewTaskMonitors(&in_progress);
9260 } else if (rv == WAIT_OBJECT_0 + 1) {
9262 smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9270 /* refresh timers */
9274 smb_PurgeOldTaskMonitors(&in_progress);
9275 t = (monitored_task *) in_progress.headp;
9277 if (t && !t->trace_timer_hit) {
9280 due = t->start_time;
9281 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9283 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9284 } else if (t && !t->dump_timer_hit) {
9288 due = t->start_time;
9289 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9291 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9293 CancelWaitableTimer(h_timer);
9295 /* CancelWaitableTimer() doesn't reset the timer if it
9296 was already signalled. */
9297 WaitForSingleObject(h_timer, 0);
9305 h = h_monitored_task_queue;
9306 h_monitored_task_queue = NULL;
9309 h = h_monitored_task_shutdown;
9310 h_monitored_task_shutdown = NULL;
9313 CloseHandle(h_timer);
9315 lock_FinalizeMutex(&_monitor_mx);
9319 monitored_task * task;
9321 while (in_progress.headp) {
9322 task = (monitored_task *) in_progress.headp;
9323 osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9327 for (task = (monitored_task *) smb_free_monitored_tasks;
9328 task; task = (monitored_task *) smb_free_monitored_tasks) {
9329 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9333 for (task = (monitored_task *) smb_monitored_tasks;
9334 task; task = (monitored_task *) smb_monitored_tasks) {
9335 osi_QRemove(&smb_monitored_tasks, &task->q);
9341 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9343 monitored_task * task;
9345 lock_ObtainMutex(&_monitor_mx);
9346 task = (monitored_task *) smb_free_monitored_tasks;
9348 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9349 lock_ReleaseMutex(&_monitor_mx);
9352 task = malloc(sizeof(monitored_task));
9353 memset(task, 0, sizeof(*task));
9355 task->task_id = task_id;
9356 task->started = started;
9361 GetSystemTimeAsFileTime(&now);
9362 task->start_time.HighPart = now.dwHighDateTime;
9363 task->start_time.LowPart = now.dwLowDateTime;
9366 lock_ObtainMutex(&_monitor_mx);
9367 osi_QAdd(&smb_monitored_tasks, &task->q);
9368 lock_ReleaseMutex(&_monitor_mx);
9370 SetEvent(h_monitored_task_queue);
9373 void smb_ShutdownMonitor()
9375 SetEvent(h_monitored_task_shutdown);
9379 * The top level loop for handling SMB request messages. Each server thread
9380 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9381 * NCB and buffer for the incoming request are loaned to us.
9383 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
9384 * to immediately send a request for the rest of the data. This must come
9385 * before any other traffic for that session, so we delay setting the session
9386 * event until that data has come in.
9388 void smb_Server(VOID *parmp)
9390 INT_PTR myIdx = (INT_PTR) parmp;
9394 smb_packet_t *outbufp;
9396 int idx_NCB, idx_session;
9398 smb_vc_t *vcp = NULL;
9401 rx_StartClientThread();
9403 outncbp = smb_GetNCB();
9404 outbufp = smb_GetPacket();
9405 outbufp->ncbp = outncbp;
9413 cm_ResetServerPriority();
9415 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9418 /* terminate silently if shutdown flag is set */
9419 if (code == WAIT_OBJECT_0) {
9420 if (smbShutdownFlag == 1) {
9421 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9427 /* error checking */
9428 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9430 int abandonIdx = code - WAIT_ABANDONED_0;
9431 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9434 if (code == WAIT_IO_COMPLETION)
9436 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9440 if (code == WAIT_TIMEOUT)
9442 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9445 if (code == WAIT_FAILED)
9447 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9450 idx_NCB = code - WAIT_OBJECT_0;
9452 /* check idx range! */
9453 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9455 /* this is fatal - log as much as possible */
9456 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9457 osi_assertx(0, "invalid index");
9460 ncbp = NCBs[idx_NCB];
9461 idx_session = NCBsessions[idx_NCB];
9462 rc = ncbp->ncb_retcode;
9464 if (rc != NRC_PENDING && rc != NRC_GOODRET)
9465 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9469 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9473 /* Can this happen? Or is it just my UNIX paranoia? */
9474 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9479 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9482 /* Client closed session */
9483 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9485 lock_ObtainMutex(&vcp->mx);
9486 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9487 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9489 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9490 lock_ReleaseMutex(&vcp->mx);
9491 lock_ObtainWrite(&smb_globalLock);
9492 dead_sessions[vcp->session] = TRUE;
9493 lock_ReleaseWrite(&smb_globalLock);
9495 lock_ReleaseMutex(&vcp->mx);
9497 smb_CleanupDeadVC(vcp);
9504 /* Treat as transient error */
9505 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9508 "dispatch smb recv failed, message incomplete, ncb_length %d",
9511 "SMB message incomplete, "
9512 "length %d", ncbp->ncb_length);
9515 * We used to discard the packet.
9516 * Instead, try handling it normally.
9520 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9524 /* A weird error code. Log it, sleep, and continue. */
9525 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9527 lock_ObtainMutex(&vcp->mx);
9528 if (vcp->errorCount++ > 3) {
9529 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9530 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9531 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9533 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9534 lock_ReleaseMutex(&vcp->mx);
9535 lock_ObtainWrite(&smb_globalLock);
9536 dead_sessions[vcp->session] = TRUE;
9537 lock_ReleaseWrite(&smb_globalLock);
9539 lock_ReleaseMutex(&vcp->mx);
9541 smb_CleanupDeadVC(vcp);
9547 lock_ReleaseMutex(&vcp->mx);
9551 thrd_SetEvent(SessionEvents[idx_session]);
9557 /* Success, so now dispatch on all the data in the packet */
9559 smb_concurrentCalls++;
9560 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9561 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9564 * If at this point vcp is NULL (implies that packet was invalid)
9565 * then we are in big trouble. This means either :
9566 * a) we have the wrong NCB.
9567 * b) Netbios screwed up the call.
9568 * c) The VC was already marked dead before we were able to
9570 * Obviously this implies that
9571 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9572 * lanas[idx_session] != ncbp->ncb_lana_num )
9573 * Either way, we can't do anything with this packet.
9574 * Log, sleep and resume.
9577 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9581 ncbp->ncb_lana_num);
9583 /* Also log in the trace log. */
9584 osi_Log4(smb_logp, "Server: VCP does not exist!"
9585 "LSNs[idx_session]=[%d],"
9586 "lanas[idx_session]=[%d],"
9587 "ncbp->ncb_lsn=[%d],"
9588 "ncbp->ncb_lana_num=[%d]",
9592 ncbp->ncb_lana_num);
9594 /* thrd_Sleep(1000); Don't bother sleeping */
9595 thrd_SetEvent(SessionEvents[idx_session]);
9596 smb_concurrentCalls--;
9600 cm_SetRequestStartTime();
9601 if (smb_monitorReqs) {
9602 smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9605 vcp->errorCount = 0;
9606 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9607 smbp = (smb_t *)bufp->data;
9614 if (smbp->com == 0x1d) {
9615 /* Special handling for Write Raw */
9616 raw_write_cont_t rwc;
9618 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9619 if (rwc.code == 0) {
9620 EVENT_HANDLE rwevent;
9621 char eventName[MAX_PATH];
9623 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9624 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9625 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9626 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9628 ncbp->ncb_command = NCBRECV | ASYNCH;
9629 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9630 ncbp->ncb_lana_num = vcp->lana;
9631 ncbp->ncb_buffer = rwc.buf;
9632 ncbp->ncb_length = 65535;
9633 ncbp->ncb_event = rwevent;
9635 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9636 thrd_CloseHandle(rwevent);
9638 thrd_SetEvent(SessionEvents[idx_session]);
9640 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9642 else if (smbp->com == 0xa0) {
9644 * Serialize the handling for NT Transact
9647 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9648 thrd_SetEvent(SessionEvents[idx_session]);
9650 thrd_SetEvent(SessionEvents[idx_session]);
9651 /* TODO: what else needs to be serialized? */
9652 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9656 __except( smb_ServerExceptionFilter() ) {
9660 if (smb_monitorReqs) {
9661 smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9663 smb_concurrentCalls--;
9666 thrd_SetEvent(NCBavails[idx_NCB]);
9671 smb_FreePacket(outbufp);
9673 smb_FreeNCB(outncbp);
9677 * Exception filter for the server threads. If an exception occurs in the
9678 * dispatch routines, which is where exceptions are most common, then do a
9679 * force trace and give control to upstream exception handlers. Useful for
9682 DWORD smb_ServerExceptionFilter(void) {
9683 /* While this is not the best time to do a trace, if it succeeds, then
9684 * we have a trace (assuming tracing was enabled). Otherwise, this should
9685 * throw a second exception.
9687 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9688 afsd_ForceTrace(TRUE);
9689 buf_ForceTrace(TRUE);
9690 return EXCEPTION_CONTINUE_SEARCH;
9694 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9695 * If the number of server threads is M, and the number of live sessions is
9696 * N, then the number of NCB's in use at any time either waiting for, or
9697 * holding, received messages is M + N, so that is how many NCB's get created.
9699 void InitNCBslot(int idx)
9701 struct smb_packet *bufp;
9702 EVENT_HANDLE retHandle;
9704 char eventName[MAX_PATH];
9706 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9708 NCBs[idx] = smb_GetNCB();
9709 sprintf(eventName,"NCBavails[%d]", idx);
9710 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9711 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9712 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9713 sprintf(eventName,"NCBevents[%d]", idx);
9714 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9715 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9716 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9717 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9718 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9719 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9720 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9721 for (i=0; i<smb_NumServerThreads; i++)
9722 NCBreturns[i][idx] = retHandle;
9723 bufp = smb_GetPacket();
9724 bufp->spacep = cm_GetSpace();
9728 /* listen for new connections */
9729 void smb_Listener(void *parmp)
9735 afs_uint32 session, thread;
9736 smb_vc_t *vcp = NULL;
9738 char rname[NCBNAMSZ+1];
9739 char cname[MAX_COMPUTERNAME_LENGTH+1];
9740 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9741 INT_PTR lana = (INT_PTR) parmp;
9742 char eventName[MAX_PATH];
9743 int bridgeCount = 0;
9744 int nowildCount = 0;
9746 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9747 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9748 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9749 thrd_ResetEvent(ListenerShutdown[lana]);
9751 ncbp = smb_GetNCB();
9753 /* retrieve computer name */
9754 GetComputerName(cname, &cnamelen);
9757 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9758 memset(ncbp, 0, sizeof(NCB));
9761 ncbp->ncb_command = NCBLISTEN;
9762 ncbp->ncb_rto = 0; /* No receive timeout */
9763 ncbp->ncb_sto = 0; /* No send timeout */
9765 /* pad out with spaces instead of null termination */
9766 len = (long)strlen(smb_localNamep);
9767 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9768 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9770 strcpy(ncbp->ncb_callname, "*");
9771 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9773 ncbp->ncb_lana_num = (UCHAR)lana;
9775 code = Netbios(ncbp);
9777 if (code == NRC_NAMERR) {
9778 /* An smb shutdown or Vista resume must have taken place */
9780 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9781 ncbp->ncb_lana_num);
9782 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9784 if (lock_TryMutex(&smb_StartedLock)) {
9785 lana_list.lana[i] = LANA_INVALID;
9786 lock_ReleaseMutex(&smb_StartedLock);
9789 } else if (code == NRC_BRIDGE || code != 0) {
9790 int lanaRemaining = 0;
9792 if (code == NRC_BRIDGE) {
9793 if (++bridgeCount <= 5) {
9794 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9797 } else if (code == NRC_NOWILD) {
9798 if (++nowildCount <= 5) {
9799 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9801 if (bridgeCount > 0) {
9802 memset(ncbp, 0, sizeof(*ncbp));
9803 ncbp->ncb_command = NCBADDNAME;
9804 ncbp->ncb_lana_num = (UCHAR)lana;
9805 /* pad out with spaces instead of null termination */
9806 len = (long)strlen(smb_localNamep);
9807 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9808 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9809 code = Netbios(ncbp);
9815 while (!lock_TryMutex(&smb_StartedLock)) {
9816 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9822 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9823 ncbp->ncb_lana_num, ncb_error_string(code));
9824 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9825 ncbp->ncb_lana_num, ncb_error_string(code));
9827 for (i = 0; i < lana_list.length; i++) {
9828 if (lana_list.lana[i] == lana) {
9829 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9830 lana_list.lana[i] = LANA_INVALID;
9832 if (lana_list.lana[i] != LANA_INVALID)
9836 if (lanaRemaining == 0) {
9837 cm_VolStatus_Network_Stopped(cm_NetbiosName
9842 smb_ListenerState = SMB_LISTENER_STOPPED;
9843 smb_LANadapter = LANA_INVALID;
9844 lana_list.length = 0;
9846 lock_ReleaseMutex(&smb_StartedLock);
9850 else if (code != 0) {
9851 char tbuffer[AFSPATHMAX];
9853 /* terminate silently if shutdown flag is set */
9854 while (!lock_TryMutex(&smb_StartedLock)) {
9855 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9861 "NCBLISTEN lana=%d failed with code %d [%s]",
9862 ncbp->ncb_lana_num, code, ncb_error_string(code));
9864 "Client exiting due to network failure. Please restart client.\n");
9867 "Client exiting due to network failure. Please restart client.\n"
9868 "NCBLISTEN lana=%d failed with code %d [%s]",
9869 ncbp->ncb_lana_num, code, ncb_error_string(code));
9871 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9872 MB_OK|MB_SERVICE_NOTIFICATION);
9873 osi_panic(tbuffer, __FILE__, __LINE__);
9875 lock_ReleaseMutex(&smb_StartedLock);
9880 /* a successful packet received. clear bridge error count */
9884 /* check for remote conns */
9885 /* first get remote name and insert null terminator */
9886 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9887 for (i=NCBNAMSZ; i>0; i--) {
9888 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9894 /* compare with local name */
9896 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9897 flags |= SMB_VCFLAG_REMOTECONN;
9900 lock_ObtainMutex(&smb_ListenerLock);
9902 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9903 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9905 /* now ncbp->ncb_lsn is the connection ID */
9906 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9907 if (vcp->session == 0) {
9908 /* New generation */
9909 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9912 /* Log session startup */
9914 fprintf(stderr, "New 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, "New 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);
9924 lock_ObtainMutex(&vcp->mx);
9925 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9926 vcp->flags |= flags;
9927 lock_ReleaseMutex(&vcp->mx);
9929 /* Allocate slot in session arrays */
9930 /* Re-use dead session if possible, otherwise add one more */
9931 /* But don't look at session[0], it is reserved */
9932 lock_ObtainWrite(&smb_globalLock);
9933 for (session = 1; session < numSessions; session++) {
9934 if (dead_sessions[session]) {
9935 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9936 dead_sessions[session] = FALSE;
9940 lock_ReleaseWrite(&smb_globalLock);
9942 /* We are re-using an existing VC because the lsn and lana
9944 session = vcp->session;
9946 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9948 /* Log session startup */
9950 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9951 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9952 #endif /* NOTSERVICE */
9953 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9954 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9956 if (reportSessionStartups) {
9957 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9961 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9962 unsigned long code = CM_ERROR_ALLBUSY;
9963 smb_packet_t * outp = smb_GetPacket();
9964 unsigned char *outWctp;
9967 smb_FormatResponsePacket(vcp, NULL, outp);
9970 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9971 unsigned long NTStatus;
9972 smb_MapNTError(code, &NTStatus, FALSE);
9973 outWctp = outp->wctp;
9974 smbp = (smb_t *) &outp->data;
9978 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9979 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9980 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9981 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9982 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9984 unsigned short errCode;
9985 unsigned char errClass;
9986 smb_MapCoreError(code, vcp, &errCode, &errClass);
9987 outWctp = outp->wctp;
9988 smbp = (smb_t *) &outp->data;
9992 smbp->errLow = (unsigned char) (errCode & 0xff);
9993 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9994 smbp->rcls = errClass;
9997 smb_SendPacket(vcp, outp);
9998 smb_FreePacket(outp);
10000 lock_ObtainMutex(&vcp->mx);
10001 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
10002 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
10004 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
10005 lock_ReleaseMutex(&vcp->mx);
10006 lock_ObtainWrite(&smb_globalLock);
10007 dead_sessions[vcp->session] = TRUE;
10008 lock_ReleaseWrite(&smb_globalLock);
10009 smb_CleanupDeadVC(vcp);
10011 lock_ReleaseMutex(&vcp->mx);
10014 /* assert that we do not exceed the maximum number of sessions or NCBs.
10015 * we should probably want to wait for a session to be freed in case
10018 osi_assertx(session < SESSION_MAX - 1, "invalid session");
10019 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
10021 lock_ObtainMutex(&vcp->mx);
10022 vcp->session = session;
10023 lock_ReleaseMutex(&vcp->mx);
10024 lock_ObtainWrite(&smb_globalLock);
10025 LSNs[session] = ncbp->ncb_lsn;
10026 lanas[session] = ncbp->ncb_lana_num;
10027 lock_ReleaseWrite(&smb_globalLock);
10029 if (session == numSessions) {
10030 /* Add new NCB for new session */
10031 char eventName[MAX_PATH];
10033 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
10035 InitNCBslot(numNCBs);
10036 lock_ObtainWrite(&smb_globalLock);
10038 lock_ReleaseWrite(&smb_globalLock);
10039 thrd_SetEvent(NCBavails[0]);
10040 thrd_SetEvent(NCBevents[0]);
10041 for (thread = 0; thread < smb_NumServerThreads; thread++)
10042 thrd_SetEvent(NCBreturns[thread][0]);
10043 /* Also add new session event */
10044 sprintf(eventName, "SessionEvents[%d]", session);
10045 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
10046 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10047 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
10048 lock_ObtainWrite(&smb_globalLock);
10050 lock_ReleaseWrite(&smb_globalLock);
10051 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
10052 thrd_SetEvent(SessionEvents[0]);
10054 thrd_SetEvent(SessionEvents[session]);
10057 smb_ReleaseVC(vcp);
10060 lock_ReleaseMutex(&smb_ListenerLock);
10061 } /* dispatch while loop */
10065 thrd_SetEvent(ListenerShutdown[lana]);
10070 smb_configureBackConnectionHostNames(int bEnable)
10072 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
10073 * there is a restriction on the use of SMB authentication on loopback connections.
10074 * There are two work arounds available:
10076 * (1) We can disable the check for matching host names. This does not
10077 * require a reboot:
10078 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
10079 * "DisableLoopbackCheck"=dword:00000001
10081 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
10082 * does require a reboot:
10083 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
10084 * "BackConnectionHostNames"=multi-sz
10086 * The algorithm will be:
10087 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
10088 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
10089 * (2b1) and check to see if DisableLoopbackCheck is set.
10090 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
10091 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
10092 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
10093 * check for the UnsetDisableLoopbackCheck value.
10094 * If set, set the DisableLoopbackCheck flag to 0x0
10095 * and delete the UnsetDisableLoopbackCheck value
10097 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
10098 * force Windows to use the loopback authentication mechanism for the specified
10101 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
10102 * service session that set it.
10108 DWORD dwSize, dwAllocSize;
10110 PBYTE pHostNames = NULL, pName = NULL;
10111 PBYTE pOrigNames = NULL, pOrig = NULL;
10112 BOOL bNameFound = FALSE;
10113 DWORD dwLoopbackCheckDisabled;
10114 DWORD dwszBackConnectionHostNames;
10115 size_t nbsize = strlen(cm_NetbiosName) + 2;
10117 static BOOL bLoopbackCheckDisabled = FALSE;
10119 /* DisableLoopbackCheck */
10120 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10121 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10123 KEY_READ|KEY_WRITE,
10124 &hkLsa) == ERROR_SUCCESS )
10126 dwSize = sizeof(DWORD);
10127 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwLoopbackCheckDisabled, &dwSize) != ERROR_SUCCESS)
10129 dwLoopbackCheckDisabled = 0;
10132 hkLsa = INVALID_HANDLE_VALUE;
10135 /* BackConnectionHostNames */
10136 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10137 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
10139 KEY_READ|KEY_WRITE,
10140 &hkMSV10) == ERROR_SUCCESS )
10142 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
10143 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10144 (dwType == REG_MULTI_SZ))
10146 dwAllocSize += 1 /* in case the source string is not nul terminated */
10147 + (DWORD)strlen(cm_NetbiosName) + 2;
10148 pHostNames = malloc(dwAllocSize);
10149 dwszBackConnectionHostNames = dwAllocSize;
10150 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
10151 pHostNames, &dwszBackConnectionHostNames) == ERROR_SUCCESS)
10153 for (pName = pHostNames;
10154 (pName - pHostNames < (int) dwszBackConnectionHostNames) && *pName ;
10155 pName += strlen(pName) + 1)
10157 if ( !stricmp(pName, cm_NetbiosName) ) {
10166 if ( !bNameFound ) {
10167 size_t size = strlen(cm_NetbiosName) + 2;
10168 if ( !pHostNames ) {
10169 pHostNames = malloc(size);
10170 pName = pHostNames;
10172 StringCbCopyA(pName, size, cm_NetbiosName);
10174 *pName = '\0'; /* add a second nul terminator */
10176 dwType = REG_MULTI_SZ;
10177 dwSize = (DWORD)(pName - pHostNames + 1);
10178 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10180 if ( hkLsa != INVALID_HANDLE_VALUE && !dwLoopbackCheckDisabled)
10182 dwType = REG_DWORD;
10183 dwSize = sizeof(DWORD);
10184 dwLoopbackCheckDisabled = 1;
10185 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwLoopbackCheckDisabled, dwSize);
10187 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10188 AFSREG_CLT_OPENAFS_SUBKEY,
10191 REG_OPTION_NON_VOLATILE,
10192 KEY_READ|KEY_WRITE,
10195 NULL) == ERROR_SUCCESS) {
10197 dwType = REG_DWORD;
10198 dwSize = sizeof(DWORD);
10200 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10201 bLoopbackCheckDisabled = TRUE;
10202 RegCloseKey(hkClient);
10205 } else if (!bLoopbackCheckDisabled && hkLsa != INVALID_HANDLE_VALUE) {
10206 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10207 AFSREG_CLT_OPENAFS_SUBKEY,
10210 REG_OPTION_NON_VOLATILE,
10211 KEY_READ|KEY_WRITE,
10214 NULL) == ERROR_SUCCESS) {
10216 dwSize = sizeof(DWORD);
10217 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10219 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10222 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10223 RegCloseKey(hkClient);
10227 * Disable SMB. Start by removing the DisableLoopbackCheck value if present.
10229 if (hkLsa != INVALID_HANDLE_VALUE) {
10230 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10231 AFSREG_CLT_OPENAFS_SUBKEY,
10234 REG_OPTION_NON_VOLATILE,
10235 KEY_READ|KEY_WRITE,
10238 NULL) == ERROR_SUCCESS) {
10240 dwSize = sizeof(DWORD);
10241 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10243 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10246 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10247 RegCloseKey(hkClient);
10250 /* Then remove our NetbiosName from the BackConnectionHostNames list */
10251 if ( bNameFound ) {
10253 * we found our name so if the size of the value is smaller
10254 * or equal to the length of our name alone, we are done.
10256 if ( dwszBackConnectionHostNames <= nbsize ) {
10257 RegDeleteValue( hkMSV10, "BackConnectionHostNames");
10259 pOrigNames = pHostNames;
10260 pHostNames = malloc(dwAllocSize);
10262 pOrig = pOrigNames;
10263 pName = pHostNames;
10264 while (pOrig - pOrigNames < dwszBackConnectionHostNames) {
10265 len = strlen(pOrig);
10266 if ( stricmp(pOrig, cm_NetbiosName)) {
10268 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10273 *pName = '\0'; /* add a second nul terminator */
10276 dwType = REG_MULTI_SZ;
10277 dwSize = (DWORD)(pName - pHostNames + 1);
10278 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10293 RegCloseKey(hkMSV10);
10296 if ( hkLsa != INVALID_HANDLE_VALUE ) {
10297 RegCloseKey(hkLsa);
10303 smb_configureExtendedSMBSessionTimeouts(int bEnable)
10306 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10307 * new functionality:
10309 * [HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters]
10310 * "ReconnectableServers" REG_MULTI_SZ
10311 * "ExtendedSessTimeout" REG_DWORD (seconds)
10312 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
10314 * These values can be used to prevent the smb redirector from timing out
10315 * smb connection to the afs smb server prematurely.
10319 DWORD dwSize, dwAllocSize;
10321 PBYTE pHostNames = NULL, pOrigNames = NULL, pName = NULL, pOrig = NULL;
10322 BOOL bNameFound = FALSE;
10323 DWORD dwszReconnectableServers;
10324 DWORD dwszServersWithExtendedSessTimeout;
10325 size_t nbsize = strlen(cm_NetbiosName) + 2;
10328 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10329 "SYSTEM\\CurrentControlSet\\Services\\LanmanWorkstation\\Parameters",
10331 KEY_READ|KEY_WRITE,
10332 &hkLanman) == ERROR_SUCCESS )
10334 if ((RegQueryValueEx( hkLanman, "ReconnectableServers", 0,
10335 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10336 (dwType == REG_MULTI_SZ))
10338 dwAllocSize += 1 /* in case the source string is not nul terminated */
10339 + (DWORD)strlen(cm_NetbiosName) + 2;
10340 pHostNames = malloc(dwAllocSize);
10341 dwszReconnectableServers = dwAllocSize;
10342 if (RegQueryValueEx( hkLanman, "ReconnectableServers", 0, &dwType,
10343 pHostNames, &dwszReconnectableServers) == ERROR_SUCCESS)
10345 for (pName = pHostNames;
10346 (pName - pHostNames < (int) dwszReconnectableServers) && *pName ;
10347 pName += strlen(pName) + 1)
10349 if ( !stricmp(pName, cm_NetbiosName) ) {
10358 * If our name was not found and we are enabling SMB,
10359 * add our name to the current value.
10361 if ( bEnable && !bNameFound ) {
10362 if ( !pHostNames ) {
10363 pHostNames = malloc(nbsize);
10364 pName = pHostNames;
10366 StringCbCopyA(pName, nbsize, cm_NetbiosName);
10367 pName += nbsize - 1;
10368 *pName = '\0'; /* add a second nul terminator */
10370 dwType = REG_MULTI_SZ;
10371 dwSize = (DWORD)(pName - pHostNames + 1);
10372 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10376 * If our name was found and we are disabling SMB,
10377 * remove our name from the list and update the value.
10378 * If our name is the only entry, remove the value.
10380 if ( !bEnable && bNameFound ) {
10382 * we found our name so if the size of the value is smaller
10383 * or equal to the length of our name alone, we are done.
10385 if ( dwszReconnectableServers <= nbsize ) {
10386 RegDeleteValue( hkLanman, "ReconnectableServers");
10388 pOrigNames = pHostNames;
10389 pHostNames = malloc(dwAllocSize);
10391 pOrig = pOrigNames;
10392 pName = pHostNames;
10393 while (pOrig - pOrigNames <dwszReconnectableServers ) {
10394 len = strlen(pOrig);
10395 if ( stricmp(pOrig, cm_NetbiosName)) {
10397 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10402 *pName = '\0'; /* add a second nul terminator */
10405 dwType = REG_MULTI_SZ;
10406 dwSize = (DWORD)(pName - pHostNames + 1);
10407 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10421 if ((RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0,
10422 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10423 (dwType == REG_MULTI_SZ))
10425 dwAllocSize += 1 /* in case the source string is not nul terminated */
10426 + (DWORD)strlen(cm_NetbiosName) + 2;
10427 pHostNames = malloc(dwAllocSize);
10428 dwszServersWithExtendedSessTimeout = dwAllocSize;
10429 if (RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, &dwType,
10430 pHostNames, &dwszServersWithExtendedSessTimeout) == ERROR_SUCCESS)
10432 for (pName = pHostNames;
10433 (pName - pHostNames < (int) dwszServersWithExtendedSessTimeout) && *pName ;
10434 pName += strlen(pName) + 1)
10436 if ( !stricmp(pName, cm_NetbiosName) ) {
10445 * If our name was not found and we are enabling SMB,
10446 * add our name to the current value.
10448 if ( bEnable && !bNameFound ) {
10449 size_t size = strlen(cm_NetbiosName) + 2;
10450 if ( !pHostNames ) {
10451 pHostNames = malloc(size);
10452 pName = pHostNames;
10454 StringCbCopyA(pName, size, cm_NetbiosName);
10456 *pName = '\0'; /* add a second nul terminator */
10458 dwType = REG_MULTI_SZ;
10459 dwSize = (DWORD)(pName - pHostNames + 1);
10460 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10464 * If our name was found and we are disabling SMB,
10465 * remove our name from the list and update the value.
10466 * If our name is the only entry, remove the value.
10468 if ( !bEnable && bNameFound ) {
10470 * we found our name so if the size of the value is smaller
10471 * or equal to the length of our name alone, we are done.
10473 if ( dwszServersWithExtendedSessTimeout <= nbsize ) {
10474 RegDeleteValue( hkLanman, "ServersWithExtendedSessTimeout");
10476 pOrigNames = pHostNames;
10477 pHostNames = malloc(dwAllocSize);
10479 pOrig = pOrigNames;
10480 pName = pHostNames;
10481 while (pOrig - pOrigNames < dwszServersWithExtendedSessTimeout) {
10482 len = strlen(pOrig);
10483 if ( stricmp(pOrig, cm_NetbiosName)) {
10485 StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10490 *pName = '\0'; /* add a second nul terminator */
10493 dwType = REG_MULTI_SZ;
10494 dwSize = (DWORD)(pName - pHostNames + 1);
10495 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10510 if ((RegQueryValueEx( hkLanman, "ExtendedSessTimeout", 0,
10511 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10512 (dwType != REG_DWORD))
10514 dwType = REG_DWORD;
10515 dwSize = sizeof(dwValue);
10516 dwValue = 300; /* 5 minutes */
10517 RegSetValueEx( hkLanman, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10520 RegCloseKey(hkLanman);
10525 smb_LanAdapterChangeThread(void *param)
10528 * Give the IPAddrDaemon thread a chance
10529 * to block before we trigger.
10532 smb_LanAdapterChange(0);
10535 void smb_SetLanAdapterChangeDetected(void)
10540 lock_ObtainMutex(&smb_StartedLock);
10542 if (!powerStateSuspended) {
10543 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10544 NULL, 0, &lpid, "smb_LanAdapterChange");
10545 if (phandle == NULL) {
10549 gle = GetLastError();
10550 StringCchPrintf( msg, sizeof(msg)/sizeof(msg[0]),
10551 "smb_LanAdapterChangeThread thread creation failure - gle 0x%x",
10553 osi_assertx(TRUE, msg);
10555 thrd_CloseHandle(phandle);
10558 smb_LanAdapterChangeDetected = 1;
10559 lock_ReleaseMutex(&smb_StartedLock);
10562 void smb_LanAdapterChange(int locked) {
10563 lana_number_t lanaNum;
10565 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
10567 LANA_ENUM temp_list;
10572 afsi_log("smb_LanAdapterChange");
10575 lock_ObtainMutex(&smb_StartedLock);
10577 smb_LanAdapterChangeDetected = 0;
10579 if (!powerStateSuspended &&
10580 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10581 LANA_NETBIOS_NAME_FULL | LANA_NETBIOS_NO_RESET)) &&
10582 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10583 if ( isGateway != bGateway ) {
10584 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10585 smb_LANadapter, lanaNum, isGateway, bGateway);
10587 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10588 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10589 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10592 NCB *ncbp = smb_GetNCB();
10593 ncbp->ncb_command = NCBENUM;
10594 ncbp->ncb_buffer = (PUCHAR)&temp_list;
10595 ncbp->ncb_length = sizeof(temp_list);
10596 code = Netbios(ncbp);
10598 if (temp_list.length != lana_list.length) {
10599 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10600 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10603 for (i=0; i<lana_list.length; i++) {
10604 if ( temp_list.lana[i] != lana_list.lana[i] ) {
10605 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10606 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10618 smb_StopListeners(1);
10619 smb_RestartListeners(1);
10622 lock_ReleaseMutex(&smb_StartedLock);
10625 /* initialize Netbios */
10626 int smb_NetbiosInit(int locked)
10629 int i, lana, code, l;
10631 int delname_tried=0;
10633 int lana_found = 0;
10634 lana_number_t lanaNum;
10640 lock_ObtainMutex(&smb_StartedLock);
10642 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10643 smb_ListenerState != SMB_LISTENER_STOPPED) {
10646 lock_ReleaseMutex(&smb_StartedLock);
10649 /* setup the NCB system */
10650 ncbp = smb_GetNCB();
10653 * Call lanahelper to get Netbios name, lan adapter number and gateway flag
10654 * This will reset all of the network adapter's netbios state.
10656 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10657 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10659 if (smb_LANadapter != LANA_INVALID)
10660 afsi_log("LAN adapter number %d", smb_LANadapter);
10662 afsi_log("LAN adapter number not determined");
10665 afsi_log("Set for gateway service");
10667 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10669 /* something went horribly wrong. We can't proceed without a netbios name */
10671 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10672 osi_panic(buf, __FILE__, __LINE__);
10675 /* remember the name */
10676 len = (int)strlen(cm_NetbiosName);
10677 if (smb_localNamep)
10678 free(smb_localNamep);
10679 smb_localNamep = malloc(len+1);
10680 strcpy(smb_localNamep, cm_NetbiosName);
10681 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10683 /* Also copy the value to the client character encoded string */
10684 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10686 if (smb_LANadapter == LANA_INVALID) {
10687 ncbp->ncb_command = NCBENUM;
10688 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10689 ncbp->ncb_length = sizeof(lana_list);
10690 code = Netbios(ncbp);
10692 afsi_log("Netbios NCBENUM error code %d", code);
10693 osi_panic(s, __FILE__, __LINE__);
10697 lana_list.length = 1;
10698 lana_list.lana[0] = smb_LANadapter;
10701 for (i = 0; i < lana_list.length; i++) {
10702 /* reset the adaptor: in Win32, this is required for every process, and
10703 * acts as an init call, not as a real hardware reset.
10705 ncbp->ncb_command = NCBRESET;
10706 ncbp->ncb_callname[0] = 100;
10707 ncbp->ncb_callname[2] = 100;
10708 ncbp->ncb_lana_num = lana_list.lana[i];
10709 code = Netbios(ncbp);
10711 code = ncbp->ncb_retcode;
10713 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10714 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10716 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10720 /* and declare our name so we can receive connections */
10721 memset(ncbp, 0, sizeof(*ncbp));
10722 len=lstrlen(smb_localNamep);
10723 memset(smb_sharename,' ',NCBNAMSZ);
10724 memcpy(smb_sharename,smb_localNamep,len);
10725 afsi_log("lana_list.length %d", lana_list.length);
10727 /* Keep the name so we can unregister it later */
10728 for (l = 0; l < lana_list.length; l++) {
10729 lana = lana_list.lana[l];
10731 ncbp->ncb_command = NCBADDNAME;
10732 ncbp->ncb_lana_num = lana;
10733 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10734 code = Netbios(ncbp);
10736 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10737 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10739 char name[NCBNAMSZ+1];
10741 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10742 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10746 code = ncbp->ncb_retcode;
10749 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10752 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10753 if (code == NRC_BRIDGE) { /* invalid LANA num */
10754 lana_list.lana[l] = LANA_INVALID;
10757 else if (code == NRC_DUPNAME) {
10758 afsi_log("Name already exists; try to delete it");
10759 memset(ncbp, 0, sizeof(*ncbp));
10760 ncbp->ncb_command = NCBDELNAME;
10761 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10762 ncbp->ncb_lana_num = lana;
10763 code = Netbios(ncbp);
10765 code = ncbp->ncb_retcode;
10767 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10769 if (code != 0 || delname_tried) {
10770 lana_list.lana[l] = LANA_INVALID;
10772 else if (code == 0) {
10773 if (!delname_tried) {
10781 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10782 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10786 smb_LANadapter = lana;
10787 lana_found = 1; /* at least one worked */
10791 osi_assertx(lana_list.length >= 0, "empty lana list");
10793 afsi_log("No valid LANA numbers found!");
10794 lana_list.length = 0;
10795 smb_LANadapter = LANA_INVALID;
10796 smb_ListenerState = SMB_LISTENER_STOPPED;
10797 cm_VolStatus_Network_Stopped(cm_NetbiosName
10804 /* we're done with the NCB now */
10807 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10808 if (lana_list.length > 0)
10809 osi_assert(smb_LANadapter != LANA_INVALID);
10812 lock_ReleaseMutex(&smb_StartedLock);
10814 return (lana_list.length > 0 ? 1 : 0);
10817 void smb_StartListeners(int locked)
10827 lock_ObtainMutex(&smb_StartedLock);
10829 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10831 lock_ReleaseMutex(&smb_StartedLock);
10835 afsi_log("smb_StartListeners");
10836 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10837 smb_configureBackConnectionHostNames(TRUE);
10839 /* Configure Extended SMB Session Timeouts */
10840 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10841 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10842 smb_configureExtendedSMBSessionTimeouts(TRUE);
10845 smb_ListenerState = SMB_LISTENER_STARTED;
10846 cm_VolStatus_Network_Started(cm_NetbiosName
10852 for (i = 0; i < lana_list.length; i++) {
10853 if (lana_list.lana[i] == LANA_INVALID)
10855 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10856 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10857 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10858 thrd_CloseHandle(phandle);
10861 lock_ReleaseMutex(&smb_StartedLock);
10864 void smb_RestartListeners(int locked)
10870 lock_ObtainMutex(&smb_StartedLock);
10872 if (powerStateSuspended)
10873 afsi_log("smb_RestartListeners called while suspended");
10875 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10876 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10877 if (smb_NetbiosInit(1))
10878 smb_StartListeners(1);
10879 } else if (smb_LanAdapterChangeDetected) {
10880 smb_LanAdapterChange(1);
10884 lock_ReleaseMutex(&smb_StartedLock);
10887 void smb_StopListener(NCB *ncbp, int lana, int wait)
10891 memset(ncbp, 0, sizeof(*ncbp));
10892 ncbp->ncb_command = NCBDELNAME;
10893 ncbp->ncb_lana_num = lana;
10894 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10895 code = Netbios(ncbp);
10897 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10898 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10900 /* and then reset the LANA; this will cause the listener threads to exit */
10901 ncbp->ncb_command = NCBRESET;
10902 ncbp->ncb_callname[0] = 100;
10903 ncbp->ncb_callname[2] = 100;
10904 ncbp->ncb_lana_num = lana;
10905 code = Netbios(ncbp);
10907 code = ncbp->ncb_retcode;
10909 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10911 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10915 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10918 void smb_StopListeners(int locked)
10927 lock_ObtainMutex(&smb_StartedLock);
10929 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10931 lock_ReleaseMutex(&smb_StartedLock);
10935 afsi_log("smb_StopListeners");
10936 smb_ListenerState = SMB_LISTENER_STOPPED;
10937 cm_VolStatus_Network_Stopped(cm_NetbiosName
10943 ncbp = smb_GetNCB();
10945 /* Unregister the SMB name */
10946 for (l = 0; l < lana_list.length; l++) {
10947 lana = lana_list.lana[l];
10949 if (lana != LANA_INVALID) {
10950 smb_StopListener(ncbp, lana, TRUE);
10952 /* mark the adapter invalid */
10953 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10957 /* force a re-evaluation of the network adapters */
10958 lana_list.length = 0;
10959 smb_LANadapter = LANA_INVALID;
10962 lock_ReleaseMutex(&smb_StartedLock);
10965 void smb_Init(osi_log_t *logp, int useV3,
10975 EVENT_HANDLE retHandle;
10976 char eventName[MAX_PATH];
10977 int startListeners = 0;
10982 smb_MBfunc = aMBfunc;
10986 /* Initialize smb_localZero */
10987 myTime.tm_isdst = -1; /* compute whether on DST or not */
10988 myTime.tm_year = 70;
10990 myTime.tm_mday = 1;
10991 myTime.tm_hour = 0;
10994 smb_localZero = mktime(&myTime);
10996 #ifdef AFS_FREELANCE_CLIENT
10997 /* Make sure the root.afs volume has the correct time */
10998 cm_noteLocalMountPointChange(FALSE);
11001 /* initialize the remote debugging log */
11004 /* and the global lock */
11005 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
11006 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
11008 /* Raw I/O data structures */
11009 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
11011 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
11012 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
11014 /* 4 Raw I/O buffers */
11015 smb_RawBufs = calloc(65536,1);
11016 *((char **)smb_RawBufs) = NULL;
11017 for (i=0; i<3; i++) {
11018 char *rawBuf = calloc(65536,1);
11019 *((char **)rawBuf) = smb_RawBufs;
11020 smb_RawBufs = rawBuf;
11023 /* global free lists */
11024 smb_ncbFreeListp = NULL;
11025 smb_packetFreeListp = NULL;
11027 lock_ObtainMutex(&smb_StartedLock);
11028 startListeners = smb_NetbiosInit(1);
11030 /* Initialize listener and server structures */
11032 memset(dead_sessions, 0, sizeof(dead_sessions));
11033 sprintf(eventName, "SessionEvents[0]");
11034 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11035 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11036 afsi_log("Event Object Already Exists: %s", eventName);
11038 smb_NumServerThreads = nThreads;
11039 sprintf(eventName, "NCBavails[0]");
11040 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11041 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11042 afsi_log("Event Object Already Exists: %s", eventName);
11043 sprintf(eventName, "NCBevents[0]");
11044 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11045 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11046 afsi_log("Event Object Already Exists: %s", eventName);
11047 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
11048 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
11049 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11050 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11051 afsi_log("Event Object Already Exists: %s", eventName);
11052 for (i = 0; i < smb_NumServerThreads; i++) {
11053 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
11054 NCBreturns[i][0] = retHandle;
11057 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
11058 for (i = 0; i < smb_NumServerThreads; i++) {
11059 sprintf(eventName, "smb_ServerShutdown[%d]", i);
11060 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11061 if ( GetLastError() == ERROR_ALREADY_EXISTS )
11062 afsi_log("Event Object Already Exists: %s", eventName);
11063 InitNCBslot((int)(i+1));
11065 numNCBs = smb_NumServerThreads + 1;
11067 /* Initialize dispatch table */
11068 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
11069 /* Prepare the table for unknown operations */
11070 for(i=0; i<= SMB_NOPCODES; i++) {
11071 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
11073 /* Fill in the ones we do know */
11074 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
11075 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
11076 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
11077 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
11078 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
11079 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
11080 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
11081 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
11082 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
11083 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
11084 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
11085 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
11086 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
11087 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
11088 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
11089 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
11090 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
11091 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
11092 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
11093 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
11094 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
11095 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11096 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
11097 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
11098 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
11099 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
11100 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
11101 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
11102 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11103 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
11104 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11105 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
11106 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
11107 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
11108 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11109 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
11110 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
11111 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
11112 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
11113 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
11114 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
11115 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
11116 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11117 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
11118 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11119 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
11120 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
11121 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
11122 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
11123 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
11124 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
11125 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
11126 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
11127 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
11128 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
11129 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
11130 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
11131 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
11132 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
11133 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
11134 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
11135 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
11136 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
11137 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
11138 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
11139 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11140 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
11141 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
11142 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
11143 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
11144 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
11145 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
11146 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
11147 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
11149 /* setup tran 2 dispatch table */
11150 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
11151 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
11152 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
11153 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
11154 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
11155 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
11156 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
11157 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
11158 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
11159 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
11160 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
11161 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
11162 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
11163 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
11164 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
11165 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
11166 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
11167 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
11169 /* setup the rap dispatch table */
11170 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
11171 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
11172 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
11173 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
11174 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
11178 /* if we are doing SMB authentication we have register outselves as a logon process */
11179 if (smb_authType != SMB_AUTH_NONE) {
11180 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
11181 LSA_STRING afsProcessName;
11182 LSA_OPERATIONAL_MODE dummy; /*junk*/
11184 afsProcessName.Buffer = "OpenAFSClientDaemon";
11185 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
11186 afsProcessName.MaximumLength = afsProcessName.Length + 1;
11188 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
11190 if (nts == STATUS_SUCCESS) {
11191 LSA_STRING packageName;
11192 /* we are registered. Find out the security package id */
11193 packageName.Buffer = MSV1_0_PACKAGE_NAME;
11194 packageName.Length = (USHORT)strlen(packageName.Buffer);
11195 packageName.MaximumLength = packageName.Length + 1;
11196 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
11197 if (nts == STATUS_SUCCESS) {
11199 * This code forces Windows to authenticate against the Logon Cache
11200 * first instead of attempting to authenticate against the Domain
11201 * Controller. When the Windows logon cache is enabled this improves
11202 * performance by removing the network access and works around a bug
11203 * seen at sites which are using a MIT Kerberos principal to login
11204 * to machines joined to a non-root domain in a multi-domain forest.
11205 * MsV1_0SetProcessOption was added in Windows XP.
11207 PVOID pResponse = NULL;
11208 ULONG cbResponse = 0;
11209 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
11211 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
11212 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
11213 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
11214 OptionsRequest.DisableOptions = FALSE;
11216 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
11219 sizeof(OptionsRequest),
11225 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
11226 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
11229 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
11231 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
11232 afsi_log("MsV1_0SetProcessOption success");
11234 /* END - code from Larry */
11236 smb_lsaLogonOrigin.Buffer = "OpenAFS";
11237 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
11238 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
11240 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
11242 /* something went wrong. We report the error and revert back to no authentication
11243 because we can't perform any auth requests without a successful lsa handle
11244 or sec package id. */
11245 afsi_log("Reverting to NO SMB AUTH");
11246 smb_authType = SMB_AUTH_NONE;
11249 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
11251 /* something went wrong. We report the error and revert back to no authentication
11252 because we can't perform any auth requests without a successful lsa handle
11253 or sec package id. */
11254 afsi_log("Reverting to NO SMB AUTH");
11255 smb_authType = SMB_AUTH_NONE;
11259 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
11260 * time prevents the failure of authentication when logged into Windows with an
11261 * external Kerberos principal mapped to a local account.
11263 else if ( smb_authType == SMB_AUTH_EXTENDED) {
11264 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
11265 * then the only option is NTLMSSP anyway; so just fallback.
11270 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
11271 if (secBlobLength == 0) {
11272 smb_authType = SMB_AUTH_NTLM;
11273 afsi_log("Reverting to SMB AUTH NTLM");
11282 /* Now get ourselves a domain name. */
11283 /* For now we are using the local computer name as the domain name.
11284 * It is actually the domain for local logins, and we are acting as
11285 * a local SMB server.
11287 bufsize = lengthof(smb_ServerDomainName) - 1;
11288 GetComputerNameW(smb_ServerDomainName, &bufsize);
11289 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
11290 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
11293 /* Start listeners, waiters, servers, and daemons */
11294 if (startListeners)
11295 smb_StartListeners(1);
11297 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
11298 NULL, 0, &lpid, "smb_ClientWaiter");
11299 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
11300 thrd_CloseHandle(phandle);
11302 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
11303 NULL, 0, &lpid, "smb_ServerWaiter");
11304 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
11305 thrd_CloseHandle(phandle);
11307 for (i=0; i<smb_NumServerThreads; i++) {
11308 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
11309 (void *) i, 0, &lpid, "smb_Server");
11310 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
11311 thrd_CloseHandle(phandle);
11314 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
11315 NULL, 0, &lpid, "smb_Daemon");
11316 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
11317 thrd_CloseHandle(phandle);
11319 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
11320 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
11321 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
11322 thrd_CloseHandle(phandle);
11324 if (smb_monitorReqs) {
11325 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
11326 NULL, 0, &lpid, "smb_ServerMonitor");
11327 osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
11328 thrd_CloseHandle(phandle);
11331 lock_ReleaseMutex(&smb_StartedLock);
11335 void smb_Shutdown(void)
11345 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11347 /* setup the NCB system */
11348 ncbp = smb_GetNCB();
11350 /* Block new sessions by setting shutdown flag */
11351 smbShutdownFlag = 1;
11353 /* Hang up all sessions */
11354 memset(ncbp, 0, sizeof(NCB));
11355 for (i = 1; i < numSessions; i++)
11357 if (dead_sessions[i])
11360 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11361 ncbp->ncb_command = NCBHANGUP;
11362 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
11363 ncbp->ncb_lsn = (UCHAR)LSNs[i];
11364 code = Netbios(ncbp);
11365 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11366 if (code == 0) code = ncbp->ncb_retcode;
11368 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11369 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11373 /* Trigger the shutdown of all SMB threads */
11374 for (i = 0; i < smb_NumServerThreads; i++)
11375 thrd_SetEvent(NCBreturns[i][0]);
11377 thrd_SetEvent(NCBevents[0]);
11378 thrd_SetEvent(SessionEvents[0]);
11379 thrd_SetEvent(NCBavails[0]);
11381 for (i = 0;i < smb_NumServerThreads; i++) {
11382 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11383 if (code == WAIT_OBJECT_0) {
11386 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11387 thrd_SetEvent(NCBreturns[i--][0]);
11391 /* Delete Netbios name */
11392 memset(ncbp, 0, sizeof(NCB));
11393 for (i = 0; i < lana_list.length; i++) {
11394 if (lana_list.lana[i] == LANA_INVALID) continue;
11395 ncbp->ncb_command = NCBDELNAME;
11396 ncbp->ncb_lana_num = lana_list.lana[i];
11397 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11398 code = Netbios(ncbp);
11400 code = ncbp->ncb_retcode;
11402 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11403 ncbp->ncb_lana_num, code);
11408 /* Release the reference counts held by the VCs */
11409 lock_ObtainWrite(&smb_rctLock);
11410 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11415 if (vcp->magic != SMB_VC_MAGIC)
11416 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11417 __FILE__, __LINE__);
11419 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11421 if (fidp->scp != NULL) {
11424 lock_ReleaseWrite(&smb_rctLock);
11425 lock_ObtainMutex(&fidp->mx);
11426 if (fidp->scp != NULL) {
11429 lock_ObtainWrite(&scp->rw);
11430 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11431 lock_ReleaseWrite(&scp->rw);
11432 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11433 cm_ReleaseSCache(scp);
11435 lock_ReleaseMutex(&fidp->mx);
11436 lock_ObtainWrite(&smb_rctLock);
11440 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11442 smb_ReleaseVCNoLock(tidp->vcp);
11444 cm_user_t *userp = tidp->userp;
11445 tidp->userp = NULL;
11446 cm_ReleaseUser(userp);
11450 lock_ReleaseWrite(&smb_rctLock);
11453 if (smb_monitorReqs) {
11454 smb_ShutdownMonitor();
11458 /* Get the UNC \\<servername>\<sharename> prefix. */
11459 char *smb_GetSharename()
11464 /* Make sure we have been properly initialized. */
11465 if (smb_localNamep == NULL)
11468 /* Allocate space for \\<servername>\<sharename>, plus the
11471 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11472 name = malloc(len);
11473 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11479 void smb_LogPacket(smb_packet_t *packet)
11483 unsigned length, paramlen, datalen, i, j;
11485 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11487 if (!packet) return;
11489 osi_Log0(smb_logp, "*** SMB packet dump ***");
11491 smbp = (smb_t *) packet->data;
11492 vp = (BYTE *) packet->data;
11494 paramlen = smbp->wct * 2;
11495 datalen = *((WORD *) (smbp->vdata + paramlen));
11496 length = sizeof(*smbp) + paramlen + 1 + datalen;
11498 for (i=0;i < length; i+=16)
11500 memset( buf, ' ', 80 );
11503 itoa( i, buf, 16 );
11505 buf[strlen(buf)] = ' ';
11507 cp = (BYTE*) buf + 7;
11509 for (j=0;j < 16 && (i+j)<length; j++)
11511 *(cp++) = hex[vp[i+j] >> 4];
11512 *(cp++) = hex[vp[i+j] & 0xf];
11522 for (j=0;j < 16 && (i+j)<length;j++)
11524 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11535 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11538 osi_Log0(smb_logp, "*** End SMB packet dump ***");
11540 #endif /* LOG_PACKET */
11543 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11549 smb_username_t *unp;
11550 smb_waitingLockRequest_t *wlrp;
11553 lock_ObtainRead(&smb_rctLock);
11555 sprintf(output, "begin dumping smb_username_t\r\n");
11556 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11557 for (unp = usernamesp; unp; unp=unp->nextp)
11559 cm_ucell_t *ucellp;
11561 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11562 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11563 unp->name ? unp->name : _C("NULL"),
11564 unp->machine ? unp->machine : _C("NULL"));
11565 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11567 sprintf(output, " begin dumping cm_ucell_t\r\n");
11568 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11570 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11571 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",
11572 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11573 ucellp->expirationTime, ucellp->gen,
11575 ucellp->cellp->name);
11576 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11579 sprintf(output, " done dumping cm_ucell_t\r\n");
11580 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11583 sprintf(output, "done dumping smb_username_t\r\n");
11584 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11590 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11591 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11593 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11594 smb_waitingLock_t *lockp;
11596 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11597 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11598 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11600 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
11601 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11602 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11603 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11604 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11605 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11607 sprintf(output, " done dumping smb_waitingLock_t\r\n");
11608 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11611 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11612 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11614 sprintf(output, "begin dumping smb_vc_t\r\n");
11615 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11617 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11623 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11624 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11625 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11627 sprintf(output, " begin dumping smb_user_t\r\n");
11628 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11629 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11630 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11631 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11632 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11634 sprintf(output, " done dumping smb_user_t\r\n");
11635 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11637 sprintf(output, " begin dumping smb_tid_t\r\n");
11638 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11639 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11640 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",
11641 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11642 tidp->pathname ? tidp->pathname : _C("NULL"));
11643 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11645 sprintf(output, " done dumping smb_tid_t\r\n");
11646 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11648 sprintf(output, " begin dumping smb_fid_t\r\n");
11649 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11651 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11653 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",
11654 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11655 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11656 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11657 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11660 sprintf(output, " done dumping smb_fid_t\r\n");
11661 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11664 sprintf(output, "done dumping smb_vc_t\r\n");
11665 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11667 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11668 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11670 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11676 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11677 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11678 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11680 sprintf(output, " begin dumping smb_user_t\r\n");
11681 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11682 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11683 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11684 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11685 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11687 sprintf(output, " done dumping smb_user_t\r\n");
11688 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11690 sprintf(output, " begin dumping smb_tid_t\r\n");
11691 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11692 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11693 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",
11694 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11695 tidp->pathname ? tidp->pathname : _C("NULL"));
11696 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11698 sprintf(output, " done dumping smb_tid_t\r\n");
11699 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11701 sprintf(output, " begin dumping smb_fid_t\r\n");
11702 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11704 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11706 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",
11707 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11708 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11709 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11710 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11713 sprintf(output, " done dumping smb_fid_t\r\n");
11714 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11717 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11718 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11722 lock_ReleaseRead(&smb_rctLock);
11726 long smb_IsNetworkStarted(void)
11733 lock_ObtainWrite(&smb_globalLock);
11734 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11735 lock_ReleaseWrite(&smb_globalLock);