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 <afs/param.h>
15 #pragma warning(disable: 4005)
29 #include <rx/rx_prototypes.h>
30 #include <WINNT\afsreg.h>
34 #include "lanahelper.h"
36 #define STRSAFE_NO_DEPRECATE
39 /* These characters are illegal in Windows filenames */
40 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
42 static int smbShutdownFlag = 0;
43 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
45 int smb_LogoffTokenTransfer;
46 time_t smb_LogoffTransferTimeout;
48 int smb_StoreAnsiFilenames = 0;
50 DWORD last_msg_time = 0;
54 unsigned int sessionGen = 0;
56 extern void afsi_log(char *pattern, ...);
57 extern HANDLE afsi_file;
58 extern int powerStateSuspended;
60 osi_hyper_t hzero = {0, 0};
61 osi_hyper_t hones = {0xFFFFFFFF, -1};
64 osi_rwlock_t smb_globalLock;
65 osi_rwlock_t smb_rctLock;
66 osi_mutex_t smb_ListenerLock;
67 osi_mutex_t smb_StartedLock;
69 unsigned char smb_LANadapter = LANA_INVALID;
70 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
71 int smb_LanAdapterChangeDetected = 0;
72 afs_uint32 smb_AsyncStore = 1;
73 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
75 BOOL isGateway = FALSE;
78 long smb_maxObsConcurrentCalls=0;
79 long smb_concurrentCalls=0;
81 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
83 smb_packet_t *smb_packetFreeListp;
84 smb_ncb_t *smb_ncbFreeListp;
86 afs_uint32 smb_NumServerThreads;
88 afs_uint32 numNCBs, numSessions, numVCs;
90 int smb_maxVCPerServer;
91 int smb_maxMpxRequests;
93 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
95 ULONG smb_lsaSecPackage;
96 LSA_STRING smb_lsaLogonOrigin;
98 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
99 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
100 EVENT_HANDLE **NCBreturns;
101 EVENT_HANDLE **NCBShutdown;
102 EVENT_HANDLE *smb_ServerShutdown;
103 EVENT_HANDLE ListenerShutdown[256];
104 DWORD NCBsessions[NCB_MAX];
106 struct smb_packet *bufs[NCB_MAX];
108 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
109 EVENT_HANDLE SessionEvents[SESSION_MAX];
110 unsigned short LSNs[SESSION_MAX];
111 int lanas[SESSION_MAX];
112 BOOL dead_sessions[SESSION_MAX];
115 osi_mutex_t smb_RawBufLock;
118 #define SMB_MASKFLAG_TILDE 1
119 #define SMB_MASKFLAG_CASEFOLD 2
121 #define RAWTIMEOUT INFINITE
124 typedef struct raw_write_cont {
133 /* dir search stuff */
134 long smb_dirSearchCounter = 1;
135 smb_dirSearch_t *smb_firstDirSearchp;
136 smb_dirSearch_t *smb_lastDirSearchp;
138 /* Initial mode bits for files and directories. Set to 0 to use
140 int smb_unixModeDefaultFile = 0666;
141 int smb_unixModeDefaultDir = 0777;
143 /* hide dot files? */
144 int smb_hideDotFiles;
146 /* Negotiate Unicode support? */
149 /* global state about V3 protocols */
150 int smb_useV3; /* try to negotiate V3 */
152 static int showErrors = 0;
153 /* MessageBox or something like it */
154 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
158 * Time in Unix format of midnight, 1/1/1970 local time.
159 * When added to dosUTime, gives Unix (AFS) time.
161 time_t smb_localZero = 0;
163 char *smb_localNamep = NULL;
165 smb_vc_t *smb_allVCsp;
166 smb_vc_t *smb_deadVCsp;
168 smb_username_t *usernamesp = NULL;
170 smb_waitingLockRequest_t *smb_allWaitingLocks;
173 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
174 NCB *ncbp, raw_write_cont_t *rwcp);
175 int smb_NetbiosInit(int);
178 void smb_LogPacket(smb_packet_t *packet);
179 #endif /* LOG_PACKET */
181 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
182 int smb_ServerDomainNameLength = 0;
183 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
184 int smb_ServerOSLength = lengthof(smb_ServerOS);
185 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
186 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
188 /* Faux server GUID. This is never checked. */
189 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
191 void smb_InitReq(cm_req_t *reqp)
194 reqp->flags |= CM_REQ_SOURCE_SMB;
197 const char * ncb_error_string(int code)
201 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
202 case 0x03: s = "NRC_ILLCMD illegal command"; break;
203 case 0x05: s = "NRC_CMDTMO command timed out"; break;
204 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
205 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
206 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
207 case 0x09: s = "NRC_NORES no resource available"; break;
208 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
209 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
210 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
211 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
212 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
213 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
214 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
215 case 0x13: s = "NRC_ILLNN illegal name number"; break;
216 case 0x14: s = "NRC_NOCALL no callname"; break;
217 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
218 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
219 case 0x17: s = "NRC_NAMERR name deleted"; break;
220 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
221 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
222 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
223 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
224 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
225 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
226 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
227 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
228 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
229 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
230 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
231 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
232 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
233 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
234 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
235 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
236 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
237 case 0x40: s = "NRC_SYSTEM system error"; break;
238 default: s = "unknown error";
244 char * myCrt_Dispatch(int i)
249 return "(00)ReceiveCoreMakeDir";
251 return "(01)ReceiveCoreRemoveDir";
253 return "(02)ReceiveCoreOpen";
255 return "(03)ReceiveCoreCreate";
257 return "(04)ReceiveCoreClose";
259 return "(05)ReceiveCoreFlush";
261 return "(06)ReceiveCoreUnlink";
263 return "(07)ReceiveCoreRename";
265 return "(08)ReceiveCoreGetFileAttributes";
267 return "(09)ReceiveCoreSetFileAttributes";
269 return "(0a)ReceiveCoreRead";
271 return "(0b)ReceiveCoreWrite";
273 return "(0c)ReceiveCoreLockRecord";
275 return "(0d)ReceiveCoreUnlockRecord";
277 return "(0e)SendCoreBadOp";
279 return "(0f)ReceiveCoreCreate";
281 return "(10)ReceiveCoreCheckPath";
283 return "(11)SendCoreBadOp";
285 return "(12)ReceiveCoreSeek";
287 return "(1a)ReceiveCoreReadRaw";
289 return "(1d)ReceiveCoreWriteRawDummy";
291 return "(22)ReceiveV3SetAttributes";
293 return "(23)ReceiveV3GetAttributes";
295 return "(24)ReceiveV3LockingX";
297 return "(25)ReceiveV3Trans";
299 return "(26)ReceiveV3Trans[aux]";
301 return "(29)SendCoreBadOp";
303 return "(2b)ReceiveCoreEcho";
305 return "(2d)ReceiveV3OpenX";
307 return "(2e)ReceiveV3ReadX";
309 return "(2f)ReceiveV3WriteX";
311 return "(32)ReceiveV3Tran2A";
313 return "(33)ReceiveV3Tran2A[aux]";
315 return "(34)ReceiveV3FindClose";
317 return "(35)ReceiveV3FindNotifyClose";
319 return "(70)ReceiveCoreTreeConnect";
321 return "(71)ReceiveCoreTreeDisconnect";
323 return "(72)ReceiveNegotiate";
325 return "(73)ReceiveV3SessionSetupX";
327 return "(74)ReceiveV3UserLogoffX";
329 return "(75)ReceiveV3TreeConnectX";
331 return "(80)ReceiveCoreGetDiskAttributes";
333 return "(81)ReceiveCoreSearchDir";
337 return "(83)FindUnique";
339 return "(84)FindClose";
341 return "(A0)ReceiveNTTransact";
343 return "(A2)ReceiveNTCreateX";
345 return "(A4)ReceiveNTCancel";
347 return "(A5)ReceiveNTRename";
349 return "(C0)OpenPrintFile";
351 return "(C1)WritePrintFile";
353 return "(C2)ClosePrintFile";
355 return "(C3)GetPrintQueue";
357 return "(D8)ReadBulk";
359 return "(D9)WriteBulk";
361 return "(DA)WriteBulkData";
363 return "unknown SMB op";
367 char * myCrt_2Dispatch(int i)
372 return "unknown SMB op-2";
374 return "S(00)CreateFile_ReceiveTran2Open";
376 return "S(01)FindFirst_ReceiveTran2SearchDir";
378 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
380 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
382 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
384 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
386 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
388 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
390 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
392 return "S(09)_ReceiveTran2FSCTL";
394 return "S(0a)_ReceiveTran2IOCTL";
396 return "S(0b)_ReceiveTran2FindNotifyFirst";
398 return "S(0c)_ReceiveTran2FindNotifyNext";
400 return "S(0d)_ReceiveTran2CreateDirectory";
402 return "S(0e)_ReceiveTran2SessionSetup";
404 return "S(0f)_QueryFileSystemInformationFid";
406 return "S(10)_ReceiveTran2GetDfsReferral";
408 return "S(11)_ReceiveTran2ReportDfsInconsistency";
412 char * myCrt_RapDispatch(int i)
417 return "unknown RAP OP";
419 return "RAP(0)NetShareEnum";
421 return "RAP(1)NetShareGetInfo";
423 return "RAP(13)NetServerGetInfo";
425 return "RAP(63)NetWkStaGetInfo";
429 char * myCrt_NmpipeDispatch(int i)
432 case SMB_TRANS_SET_NMPIPE_STATE:
433 return "SET NMPIPE STATE";
435 case SMB_TRANS_RAW_READ_NMPIPE:
436 return "RAW READ NMPIPE";
438 case SMB_TRANS_QUERY_NMPIPE_STATE:
439 return "QUERY NMPIPE STATE";
441 case SMB_TRANS_QUERY_NMPIPE_INFO:
442 return "QUERY NMPIPE INFO";
444 case SMB_TRANS_PEEK_NMPIPE:
445 return "PEEK NMPIPE";
447 case SMB_TRANS_TRANSACT_NMPIPE:
448 return "TRANSACT NMPIPE";
450 case SMB_TRANS_RAW_WRITE_NMPIPE:
451 return "WRITE NMPIPE";
453 case SMB_TRANS_READ_NMPIPE:
454 return "READ NMPIPE";
456 case SMB_TRANS_WRITE_NMPIPE:
457 return "WRITE NMPIPE";
459 case SMB_TRANS_WAIT_NMPIPE:
460 return "WAIT NMPIPE";
462 case SMB_TRANS_CALL_NMPIPE:
463 return "CALL NMPIPE";
468 /* scache must be locked */
469 unsigned int smb_Attributes(cm_scache_t *scp)
473 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
474 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
475 scp->fileType == CM_SCACHETYPE_INVALID)
477 attrs = SMB_ATTR_DIRECTORY;
478 #ifdef SPECIAL_FOLDERS
479 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
480 #endif /* SPECIAL_FOLDERS */
481 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
482 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
487 * We used to mark a file RO if it was in an RO volume, but that
488 * turns out to be impolitic in NT. See defect 10007.
491 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
492 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
494 if ((scp->unixModeBits & 0200) == 0)
495 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
501 void smb_SetInitialModeBitsForFile(int smb_attr, cm_attr_t * attr)
503 if (smb_unixModeDefaultFile != 0) {
504 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
505 attr->unixModeBits = smb_unixModeDefaultFile;
506 if (smb_attr & SMB_ATTR_READONLY)
507 attr->unixModeBits &= ~0222;
511 void smb_SetInitialModeBitsForDir(int smb_attr, cm_attr_t * attr)
513 if (smb_unixModeDefaultDir != 0) {
514 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
515 attr->unixModeBits = smb_unixModeDefaultDir;
519 /* Check if the named file/dir is a dotfile/dotdir */
520 /* String pointed to by lastComp can have leading slashes, but otherwise should have
521 no other patch components */
522 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
526 /* skip over slashes */
527 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
532 /* nulls, curdir and parent dir doesn't count */
538 if(*(s+1) == _C('.') && !*(s + 2))
545 static int ExtractBits(WORD bits, short start, short len)
552 num = bits << (16 - end);
553 num = num >> ((16 - end) + start);
558 void ShowUnixTime(char *FuncName, time_t unixTime)
563 cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
565 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
566 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
568 int day, month, year, sec, min, hour;
571 day = ExtractBits(wDate, 0, 5);
572 month = ExtractBits(wDate, 5, 4);
573 year = ExtractBits(wDate, 9, 7) + 1980;
575 sec = ExtractBits(wTime, 0, 5);
576 min = ExtractBits(wTime, 5, 6);
577 hour = ExtractBits(wTime, 11, 5);
579 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
580 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
584 /* Determine if we are observing daylight savings time */
585 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
587 TIME_ZONE_INFORMATION timeZoneInformation;
588 SYSTEMTIME utc, local, localDST;
590 /* Get the time zone info. NT uses this to calc if we are in DST. */
591 GetTimeZoneInformation(&timeZoneInformation);
593 /* Return the daylight bias */
594 *pDstBias = timeZoneInformation.DaylightBias;
596 /* Return the bias */
597 *pBias = timeZoneInformation.Bias;
599 /* Now determine if DST is being observed */
601 /* Get the UTC (GMT) time */
604 /* Convert UTC time to local time using the time zone info. If we are
605 observing DST, the calculated local time will include this.
607 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
609 /* Set the daylight bias to 0. The daylight bias is the amount of change
610 * in time that we use for daylight savings time. By setting this to 0
611 * we cause there to be no change in time during daylight savings time.
613 timeZoneInformation.DaylightBias = 0;
615 /* Convert the utc time to local time again, but this time without any
616 adjustment for daylight savings time.
618 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
620 /* If the two times are different, then it means that the localDST that
621 we calculated includes the daylight bias, and therefore we are
622 observing daylight savings time.
624 *pDST = localDST.wHour != local.wHour;
628 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
630 BOOL dst; /* Will be TRUE if observing DST */
631 LONG dstBias; /* Offset from local time if observing DST */
632 LONG bias; /* Offset from GMT for local time */
635 * This function will adjust the last write time to compensate
636 * for two bugs in the smb client:
638 * 1) During Daylight Savings Time, the LastWriteTime is ahead
639 * in time by the DaylightBias (ignoring the sign - the
640 * DaylightBias is always stored as a negative number). If
641 * the DaylightBias is -60, then the LastWriteTime will be
642 * ahead by 60 minutes.
644 * 2) If the local time zone is a positive offset from GMT, then
645 * the LastWriteTime will be the correct local time plus the
646 * Bias (ignoring the sign - a positive offset from GMT is
647 * always stored as a negative Bias). If the Bias is -120,
648 * then the LastWriteTime will be ahead by 120 minutes.
650 * These bugs can occur at the same time.
653 GetTimeZoneInfo(&dst, &dstBias, &bias);
655 /* First adjust for DST */
657 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
659 /* Now adjust for a positive offset from GMT (a negative bias). */
661 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
664 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
666 time_t diff_t = unixTime - smb_localZero;
667 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
668 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
670 *dosUTimep = (afs_uint32)diff_t;
673 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
675 *unixTimep = dosTime + smb_localZero;
678 void smb_MarkAllVCsDead(smb_vc_t * exclude)
681 smb_vc_t **vcp_to_cleanup = NULL;
682 int n_to_cleanup = 0;
685 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
687 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
688 lock_ObtainWrite(&smb_rctLock);
689 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
691 if (vcp->magic != SMB_VC_MAGIC)
692 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
698 lock_ObtainMutex(&vcp->mx);
699 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
700 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
701 lock_ReleaseMutex(&vcp->mx);
702 dead_sessions[vcp->session] = TRUE;
704 lock_ReleaseMutex(&vcp->mx);
709 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
711 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
715 vcp_to_cleanup[i++] = vcp;
716 smb_HoldVCNoLock(vcp);
719 osi_assert(i == n_to_cleanup);
721 lock_ReleaseWrite(&smb_rctLock);
722 lock_ReleaseWrite(&smb_globalLock);
724 for (i=0; i < n_to_cleanup; i++) {
725 smb_CleanupDeadVC(vcp_to_cleanup[i]);
726 smb_ReleaseVC(vcp_to_cleanup[i]);
727 vcp_to_cleanup[i] = 0;
730 free(vcp_to_cleanup);
733 #ifdef DEBUG_SMB_REFCOUNT
734 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
736 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
741 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
742 lock_ObtainWrite(&smb_rctLock);
743 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
744 if (vcp->magic != SMB_VC_MAGIC)
745 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
748 lock_ObtainMutex(&vcp->mx);
749 if (lsn == vcp->lsn && lana == vcp->lana &&
750 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
751 lock_ReleaseMutex(&vcp->mx);
752 smb_HoldVCNoLock(vcp);
755 lock_ReleaseMutex(&vcp->mx);
757 if (!vcp && (flags & SMB_FLAG_CREATE)) {
758 vcp = malloc(sizeof(*vcp));
759 memset(vcp, 0, sizeof(*vcp));
760 vcp->vcID = ++numVCs;
761 vcp->magic = SMB_VC_MAGIC;
762 vcp->refCount = 2; /* smb_allVCsp and caller */
765 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
766 vcp->nextp = smb_allVCsp;
768 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
773 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
774 /* We must obtain a challenge for extended auth
775 * in case the client negotiates smb v3
777 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
778 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
779 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
780 ULONG lsaRespSize = 0;
782 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
784 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
791 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
792 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
793 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
794 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
795 nts, ntsEx, lsaRespSize);
797 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
799 if (ntsEx == STATUS_SUCCESS) {
800 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
803 * This will cause the subsequent authentication to fail but
804 * that is better than us dereferencing a NULL pointer and
807 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
810 LsaFreeReturnBuffer(lsaResp);
813 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
815 if (numVCs >= CM_SESSION_RESERVED) {
817 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
820 #ifdef DEBUG_SMB_REFCOUNT
822 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
823 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
826 lock_ReleaseWrite(&smb_rctLock);
827 lock_ReleaseWrite(&smb_globalLock);
831 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
836 for(i=0; i<11; i++) {
838 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
844 static int smb_IsStarMask(clientchar_t *maskp)
850 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
856 #ifdef DEBUG_SMB_REFCOUNT
857 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
858 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
860 void smb_ReleaseVCInternal(smb_vc_t *vcp)
866 lock_AssertWrite(&smb_rctLock);
869 if (vcp->refCount == 0) {
870 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
871 #ifdef DEBUG_SMB_REFCOUNT
872 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
873 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
875 /* remove VCP from smb_deadVCsp */
876 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
882 lock_FinalizeMutex(&vcp->mx);
883 memset(vcp,0,sizeof(smb_vc_t));
886 #ifdef DEBUG_SMB_REFCOUNT
887 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
889 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
893 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
894 avcp?"":"not ",vcp, vcp->refCount);
896 /* This is a wrong. However, I suspect that there is an undercount
897 * and I don't want to release 1.4.1 in a state that will allow
898 * smb_vc_t objects to be deallocated while still in the
899 * smb_allVCsp list. The list is supposed to keep a reference
900 * to the smb_vc_t. Put it back.
904 #ifdef DEBUG_SMB_REFCOUNT
905 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
906 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
910 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
911 /* The reference count is non-zero but the VC is dead.
912 * This implies that some FIDs, TIDs, etc on the VC have yet to
913 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
914 * add a reference that will be dropped by
915 * smb_CleanupDeadVC() and try to cleanup the VC again.
916 * Eventually the refCount will drop to zero when all of the
917 * active threads working with the VC end their task.
919 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
920 vcp->refCount++; /* put the refCount back */
921 lock_ReleaseWrite(&smb_rctLock);
922 smb_CleanupDeadVC(vcp);
923 #ifdef DEBUG_SMB_REFCOUNT
924 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
925 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
927 lock_ObtainWrite(&smb_rctLock);
930 #ifdef DEBUG_SMB_REFCOUNT
931 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
932 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
937 #ifdef DEBUG_SMB_REFCOUNT
938 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
940 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
943 lock_AssertWrite(&smb_rctLock);
944 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
945 smb_ReleaseVCInternal(vcp);
948 #ifdef DEBUG_SMB_REFCOUNT
949 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
951 void smb_ReleaseVC(smb_vc_t *vcp)
954 lock_ObtainWrite(&smb_rctLock);
955 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
956 smb_ReleaseVCInternal(vcp);
957 lock_ReleaseWrite(&smb_rctLock);
960 #ifdef DEBUG_SMB_REFCOUNT
961 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
963 void smb_HoldVCNoLock(smb_vc_t *vcp)
966 lock_AssertWrite(&smb_rctLock);
968 #ifdef DEBUG_SMB_REFCOUNT
969 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
970 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
972 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
976 #ifdef DEBUG_SMB_REFCOUNT
977 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
979 void smb_HoldVC(smb_vc_t *vcp)
982 lock_ObtainWrite(&smb_rctLock);
984 #ifdef DEBUG_SMB_REFCOUNT
985 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
986 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
988 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
990 lock_ReleaseWrite(&smb_rctLock);
993 void smb_CleanupDeadVC(smb_vc_t *vcp)
1001 smb_user_t *uidpIter;
1002 smb_user_t *uidpNext;
1004 afs_uint32 refCount = 0;
1006 lock_ObtainMutex(&vcp->mx);
1007 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1008 lock_ReleaseMutex(&vcp->mx);
1009 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1012 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1013 lock_ReleaseMutex(&vcp->mx);
1014 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1016 lock_ObtainWrite(&smb_rctLock);
1017 /* remove VCP from smb_allVCsp */
1018 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1019 if ((*vcpp)->magic != SMB_VC_MAGIC)
1020 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1021 __FILE__, __LINE__);
1024 vcp->nextp = smb_deadVCsp;
1026 /* Hold onto the reference until we are done with this function */
1031 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1032 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1034 if (fidpIter->deleteOk)
1037 fid = fidpIter->fid;
1038 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1040 smb_HoldFIDNoLock(fidpIter);
1041 lock_ReleaseWrite(&smb_rctLock);
1043 smb_CloseFID(vcp, fidpIter, NULL, 0);
1044 smb_ReleaseFID(fidpIter);
1046 lock_ObtainWrite(&smb_rctLock);
1047 fidpNext = vcp->fidsp;
1050 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1051 tidpNext = tidpIter->nextp;
1052 if (tidpIter->deleteOk)
1054 tidpIter->deleteOk = 1;
1056 tid = tidpIter->tid;
1057 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1059 smb_HoldTIDNoLock(tidpIter);
1060 smb_ReleaseTID(tidpIter, TRUE);
1061 tidpNext = vcp->tidsp;
1064 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1065 uidpNext = uidpIter->nextp;
1066 if (uidpIter->deleteOk)
1068 uidpIter->deleteOk = 1;
1070 /* do not add an additional reference count for the smb_user_t
1071 * as the smb_vc_t already is holding a reference */
1072 lock_ReleaseWrite(&smb_rctLock);
1074 smb_ReleaseUID(uidpIter);
1076 lock_ObtainWrite(&smb_rctLock);
1077 uidpNext = vcp->usersp;
1080 /* The vcp is now on the deadVCsp list. We intentionally drop the
1081 * reference so that the refcount can reach 0 and we can delete it
1083 * If the refCount == 1 going into the ReleaseVCNoLock call
1084 * the object will be freed and it won't be safe to clear
1087 refCount = vcp->refCount;
1088 smb_ReleaseVCNoLock(vcp);
1090 lock_ObtainMutex(&vcp->mx);
1091 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1092 lock_ReleaseMutex(&vcp->mx);
1095 lock_ReleaseWrite(&smb_rctLock);
1096 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1099 #ifdef DEBUG_SMB_REFCOUNT
1100 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1102 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1107 lock_ObtainWrite(&smb_rctLock);
1109 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1110 if (tidp->refCount == 0 && tidp->deleteOk) {
1112 smb_ReleaseTID(tidp, TRUE);
1116 if (tid == tidp->tid) {
1121 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1122 tidp = malloc(sizeof(*tidp));
1123 memset(tidp, 0, sizeof(*tidp));
1124 tidp->nextp = vcp->tidsp;
1127 smb_HoldVCNoLock(vcp);
1129 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1132 #ifdef DEBUG_SMB_REFCOUNT
1134 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1135 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1138 lock_ReleaseWrite(&smb_rctLock);
1142 #ifdef DEBUG_SMB_REFCOUNT
1143 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1145 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1148 lock_AssertWrite(&smb_rctLock);
1150 #ifdef DEBUG_SMB_REFCOUNT
1151 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1152 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1156 #ifdef DEBUG_SMB_REFCOUNT
1157 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1159 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1164 cm_user_t *userp = NULL;
1165 smb_vc_t *vcp = NULL;
1168 lock_ObtainWrite(&smb_rctLock);
1170 lock_AssertWrite(&smb_rctLock);
1172 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1173 #ifdef DEBUG_SMB_REFCOUNT
1174 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1175 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1177 if (tidp->refCount == 0) {
1178 if (tidp->deleteOk) {
1179 ltpp = &tidp->vcp->tidsp;
1180 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1184 osi_assertx(tp != NULL, "null smb_tid_t");
1186 lock_FinalizeMutex(&tidp->mx);
1187 userp = tidp->userp; /* remember to drop ref later */
1195 smb_ReleaseVCNoLock(vcp);
1197 lock_ReleaseWrite(&smb_rctLock);
1199 cm_ReleaseUser(userp);
1202 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1204 smb_user_t *uidp = NULL;
1206 lock_ObtainWrite(&smb_rctLock);
1207 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1208 if (uid == uidp->userID) {
1210 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1212 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1216 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1217 uidp = malloc(sizeof(*uidp));
1218 memset(uidp, 0, sizeof(*uidp));
1219 uidp->nextp = vcp->usersp;
1220 uidp->refCount = 2; /* one for the vcp and one for the caller */
1222 smb_HoldVCNoLock(vcp);
1224 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1226 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1228 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1230 lock_ReleaseWrite(&smb_rctLock);
1234 afs_int32 smb_userIsLocalSystem(smb_user_t *uidp)
1237 DWORD dwSize1 = 0, dwSize2 = 0;
1238 wchar_t *pszRefDomain = NULL;
1239 SID_NAME_USE snu = SidTypeGroup;
1240 clientchar_t * secSidString = NULL;
1242 afs_int32 isSystem = 0;
1245 * The input name is probably not a SID for the user which is how
1246 * the user is now being identified as a result of the SMB
1247 * extended authentication. See if we can obtain the SID for the
1248 * specified name. If we can, use that instead of the name
1252 LookupAccountNameW( NULL /* System Name to begin Search */,
1257 gle = GetLastError();
1258 if (gle == ERROR_INSUFFICIENT_BUFFER) {
1259 pSid = malloc(dwSize1);
1261 * Although dwSize2 is supposed to include the terminating
1262 * NUL character, on Win7 it does not.
1264 pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
1267 if ( pSid && pszRefDomain ) {
1268 memset(pSid, 0, dwSize1);
1270 if (LookupAccountNameW( NULL /* System Name to begin Search */,
1273 pszRefDomain, &dwSize2,
1275 ConvertSidToStringSidW(pSid, &secSidString);
1279 isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, secSidString);
1280 LocalFree(secSidString);
1291 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1294 smb_username_t *unp= NULL;
1296 lock_ObtainWrite(&smb_rctLock);
1297 for(unp = usernamesp; unp; unp = unp->nextp) {
1298 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1299 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1304 if (!unp && (flags & SMB_FLAG_CREATE)) {
1305 unp = malloc(sizeof(*unp));
1306 memset(unp, 0, sizeof(*unp));
1308 unp->nextp = usernamesp;
1309 unp->name = cm_ClientStrDup(usern);
1310 unp->machine = cm_ClientStrDup(machine);
1312 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1313 if (flags & SMB_FLAG_AFSLOGON)
1314 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1317 lock_ReleaseWrite(&smb_rctLock);
1321 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1323 smb_user_t *uidp= NULL;
1325 lock_ObtainWrite(&smb_rctLock);
1326 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1329 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1331 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1332 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1337 lock_ReleaseWrite(&smb_rctLock);
1341 void smb_ReleaseUsername(smb_username_t *unp)
1344 smb_username_t **lupp;
1345 cm_user_t *userp = NULL;
1346 time_t now = osi_Time();
1348 lock_ObtainWrite(&smb_rctLock);
1349 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1350 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1351 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1353 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1357 osi_assertx(up != NULL, "null smb_username_t");
1359 up->nextp = NULL; /* do not remove this */
1360 lock_FinalizeMutex(&unp->mx);
1366 lock_ReleaseWrite(&smb_rctLock);
1368 cm_ReleaseUser(userp);
1371 void smb_HoldUIDNoLock(smb_user_t *uidp)
1373 lock_AssertWrite(&smb_rctLock);
1377 void smb_ReleaseUID(smb_user_t *uidp)
1381 smb_username_t *unp = NULL;
1383 lock_ObtainWrite(&smb_rctLock);
1384 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1385 if (uidp->refCount == 0) {
1386 lupp = &uidp->vcp->usersp;
1387 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1391 osi_assertx(up != NULL, "null smb_user_t");
1393 lock_FinalizeMutex(&uidp->mx);
1395 smb_ReleaseVCNoLock(uidp->vcp);
1399 lock_ReleaseWrite(&smb_rctLock);
1403 cm_ReleaseUserVCRef(unp->userp);
1404 smb_ReleaseUsername(unp);
1408 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1410 cm_user_t *up = NULL;
1415 lock_ObtainMutex(&uidp->mx);
1417 up = uidp->unp->userp;
1420 lock_ReleaseMutex(&uidp->mx);
1426 /* retrieve a held reference to a user structure corresponding to an incoming
1428 * corresponding release function is cm_ReleaseUser.
1430 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1433 cm_user_t *up = NULL;
1436 smbp = (smb_t *) inp;
1437 uidp = smb_FindUID(vcp, smbp->uid, 0);
1441 up = smb_GetUserFromUID(uidp);
1443 smb_ReleaseUID(uidp);
1448 * Return a pointer to a pathname extracted from a TID structure. The
1449 * TID structure is not held; assume it won't go away.
1451 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1456 tidp = smb_FindTID(vcp, tid, 0);
1460 if (tidp->flags & SMB_TIDFLAG_IPC) {
1461 code = CM_ERROR_TIDIPC;
1462 /* tidp->pathname would be NULL, but that's fine */
1464 *treepath = tidp->pathname;
1465 smb_ReleaseTID(tidp, FALSE);
1470 /* check to see if we have a chained fid, that is, a fid that comes from an
1471 * OpenAndX message that ran earlier in this packet. In this case, the fid
1472 * field in a read, for example, request, isn't set, since the value is
1473 * supposed to be inherited from the openAndX call.
1475 int smb_ChainFID(int fid, smb_packet_t *inp)
1477 if (inp->fid == 0 || inp->inCount == 0)
1483 /* are we a priv'd user? What does this mean on NT? */
1484 int smb_SUser(cm_user_t *userp)
1489 /* find a file ID. If we pass in 0 we select an unused File ID.
1490 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1491 * smb_fid_t data structure if desired File ID cannot be found.
1493 #ifdef DEBUG_SMB_REFCOUNT
1494 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1496 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1503 if (!(flags & SMB_FLAG_CREATE))
1508 lock_ObtainWrite(&smb_rctLock);
1510 fid = vcp->fidCounter;
1513 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1514 if (fidp->refCount == 0 && fidp->deleteOk) {
1516 lock_ReleaseWrite(&smb_rctLock);
1517 smb_ReleaseFID(fidp);
1518 lock_ObtainWrite(&smb_rctLock);
1520 * We dropped the smb_rctLock so the fid value we are using
1521 * may now be used by another thread. Start over with the
1522 * current vcp->fidCounter.
1525 fid = vcp->fidCounter;
1528 if (fid == fidp->fid) {
1530 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1532 if (fid == 0xFFFF) {
1534 "New FID number wraps on vcp 0x%x", vcp);
1544 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1545 char eventName[MAX_PATH];
1549 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1551 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1553 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1554 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1555 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1556 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1557 thrd_CloseHandle(event);
1559 if (fid == 0xFFFF) {
1560 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1566 fidp = malloc(sizeof(*fidp));
1567 memset(fidp, 0, sizeof(*fidp));
1568 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1571 smb_HoldVCNoLock(vcp);
1572 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1574 fidp->curr_chunk = fidp->prev_chunk = -2;
1575 fidp->raw_write_event = event;
1577 vcp->fidCounter = fid+1;
1578 if (vcp->fidCounter == 0xFFFF) {
1579 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1581 vcp->fidCounter = 1;
1586 #ifdef DEBUG_SMB_REFCOUNT
1588 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1589 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1592 lock_ReleaseWrite(&smb_rctLock);
1597 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1598 #ifdef DEBUG_SMB_REFCOUNT
1599 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1601 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1604 smb_fid_t *fidp = NULL, *nextp = NULL;
1610 * If the fidp->scp changes out from under us then
1611 * we must not grab a refCount. It means the *fidp
1612 * was processed by smb_CloseFID() and the *fidp is
1613 * no longer valid for use.
1615 lock_ObtainWrite(&smb_rctLock);
1616 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1617 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1621 if (scp == fidp->scp) {
1622 lock_ReleaseWrite(&smb_rctLock);
1623 lock_ObtainMutex(&fidp->mx);
1624 lock_ObtainWrite(&smb_rctLock);
1625 if (scp == fidp->scp) {
1626 lock_ReleaseMutex(&fidp->mx);
1629 lock_ReleaseMutex(&fidp->mx);
1632 if (fidp->refCount > 1) {
1635 lock_ReleaseWrite(&smb_rctLock);
1636 smb_ReleaseFID(fidp);
1637 lock_ObtainWrite(&smb_rctLock);
1642 if (nextp->refCount > 1) {
1645 lock_ReleaseWrite(&smb_rctLock);
1646 smb_ReleaseFID(nextp);
1647 lock_ObtainWrite(&smb_rctLock);
1651 #ifdef DEBUG_SMB_REFCOUNT
1653 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1654 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1657 lock_ReleaseWrite(&smb_rctLock);
1661 #ifdef DEBUG_SMB_REFCOUNT
1662 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1664 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1667 lock_AssertWrite(&smb_rctLock);
1669 #ifdef DEBUG_SMB_REFCOUNT
1670 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1671 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1676 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1677 /* the smb_fid_t->mx and smb_rctLock must not be held */
1678 #ifdef DEBUG_SMB_REFCOUNT
1679 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1681 void smb_ReleaseFID(smb_fid_t *fidp)
1684 cm_scache_t *scp = NULL;
1685 cm_user_t *userp = NULL;
1686 smb_vc_t *vcp = NULL;
1687 smb_ioctl_t *ioctlp;
1689 lock_ObtainMutex(&fidp->mx);
1690 lock_ObtainWrite(&smb_rctLock);
1691 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1692 #ifdef DEBUG_SMB_REFCOUNT
1693 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1694 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1696 if (fidp->refCount == 0) {
1697 if (fidp->deleteOk) {
1700 scp = fidp->scp; /* release after lock is released */
1702 lock_ObtainWrite(&scp->rw);
1703 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1704 lock_ReleaseWrite(&scp->rw);
1705 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1708 userp = fidp->userp;
1712 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1713 thrd_CloseHandle(fidp->raw_write_event);
1715 /* and see if there is ioctl stuff to free */
1716 ioctlp = fidp->ioctlp;
1719 cm_FreeSpace(ioctlp->prefix);
1720 if (ioctlp->ioctl.inAllocp)
1721 free(ioctlp->ioctl.inAllocp);
1722 if (ioctlp->ioctl.outAllocp)
1723 free(ioctlp->ioctl.outAllocp);
1727 smb_CleanupRPCFid(fidp);
1729 lock_ReleaseMutex(&fidp->mx);
1730 lock_FinalizeMutex(&fidp->mx);
1735 smb_ReleaseVCNoLock(vcp);
1739 lock_ReleaseMutex(&fidp->mx);
1741 lock_ReleaseWrite(&smb_rctLock);
1743 /* now release the scache structure */
1745 cm_ReleaseSCache(scp);
1748 cm_ReleaseUser(userp);
1752 * Case-insensitive search for one string in another;
1753 * used to find variable names in submount pathnames.
1755 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1757 clientchar_t *cursor;
1759 for (cursor = str1; *cursor; cursor++)
1760 if (cm_ClientStrCmpI(cursor, str2) == 0)
1767 * Substitute a variable value for its name in a submount pathname. Variable
1768 * name has been identified by smb_stristr() and is in substr. Variable name
1769 * length (plus one) is in substr_size. Variable value is in newstr.
1771 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1772 unsigned int substr_size, clientchar_t *newstr)
1774 clientchar_t temp[1024];
1776 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1777 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1778 cm_ClientStrCat(str1, cchstr1, temp);
1781 clientchar_t VNUserName[] = _C("%USERNAME%");
1782 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1783 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1784 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1786 typedef struct smb_findShare_rock {
1787 clientchar_t * shareName;
1788 clientchar_t * match;
1790 } smb_findShare_rock_t;
1792 #define SMB_FINDSHARE_EXACT_MATCH 1
1793 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1795 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1799 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1800 normchar_t normName[MAX_PATH];
1802 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1803 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1804 osi_LogSaveString(smb_logp, dep->name));
1808 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1809 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1810 matchType = SMB_FINDSHARE_EXACT_MATCH;
1812 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1815 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1816 vrock->matchType = matchType;
1818 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1819 return CM_ERROR_STOPNOW;
1825 /* find a shareName in the table of submounts */
1826 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1827 clientchar_t *shareName,
1828 clientchar_t **pathNamep)
1832 clientchar_t pathName[1024];
1835 clientchar_t *p, *q;
1836 fschar_t *cellname = NULL;
1839 DWORD allSubmount = 1;
1841 /* if allSubmounts == 0, only return the //mountRoot/all share
1842 * if in fact it has been been created in the subMounts table.
1843 * This is to allow sites that want to restrict access to the
1846 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1847 0, KEY_QUERY_VALUE, &parmKey);
1848 if (code == ERROR_SUCCESS) {
1849 cblen = sizeof(allSubmount);
1850 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1851 (BYTE *) &allSubmount, &cblen);
1852 if (code != ERROR_SUCCESS) {
1855 RegCloseKey (parmKey);
1858 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1863 /* In case, the all share is disabled we need to still be able
1864 * to handle ioctl requests
1866 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1867 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1871 if (MSRPC_IsWellKnownService(shareName) ||
1872 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1873 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1879 /* Check for volume references
1881 * They look like <cell>{%,#}<volume>
1883 if (cm_ClientStrChr(shareName, '%') != NULL ||
1884 cm_ClientStrChr(shareName, '#') != NULL) {
1885 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1886 /* make room for '/@vol:' + mountchar + NULL terminator*/
1888 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1889 osi_LogSaveClientString(smb_logp, shareName));
1891 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1892 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1893 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1895 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1897 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1898 cm_ClientStrLwr(*pathNamep);
1899 osi_Log1(smb_logp, " returning pathname [%S]",
1900 osi_LogSaveClientString(smb_logp, *pathNamep));
1908 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1909 0, KEY_QUERY_VALUE, &parmKey);
1910 if (code == ERROR_SUCCESS) {
1911 cblen = sizeof(pathName);
1912 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1913 (BYTE *) pathName, &cblen);
1914 if (code != ERROR_SUCCESS)
1916 RegCloseKey (parmKey);
1920 cchlen = cblen / sizeof(clientchar_t);
1921 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1922 /* We can accept either unix or PC style AFS pathnames. Convert
1923 * Unix-style to PC style here for internal use.
1926 cchlen = lengthof(pathName);
1928 /* within this code block, we maintain, cchlen = writeable
1929 buffer length of p */
1931 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1932 p += cm_mountRootCLen; /* skip mount path */
1933 cchlen -= (DWORD)(p - pathName);
1938 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1944 clientchar_t temp[1024];
1946 if (var = smb_stristr(p, VNUserName)) {
1947 if (uidp && uidp->unp)
1948 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1950 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1952 else if (var = smb_stristr(p, VNLCUserName))
1954 if (uidp && uidp->unp)
1955 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1957 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1958 cm_ClientStrLwr(temp);
1959 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1961 else if (var = smb_stristr(p, VNComputerName))
1963 sizeTemp = lengthof(temp);
1964 GetComputerNameW(temp, &sizeTemp);
1965 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1967 else if (var = smb_stristr(p, VNLCComputerName))
1969 sizeTemp = lengthof(temp);
1970 GetComputerName((LPTSTR)temp, &sizeTemp);
1971 cm_ClientStrLwr(temp);
1972 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1977 *pathNamep = cm_ClientStrDup(p);
1982 /* First lookup shareName in root.afs */
1984 smb_findShare_rock_t vrock;
1986 fschar_t ftemp[1024];
1987 clientchar_t * p = shareName;
1992 /* attempt to locate a partial match in root.afs. This is because
1993 when using the ANSI RAP calls, the share name is limited to 13 chars
1994 and hence is truncated. Of course we prefer exact matches. */
1996 thyper.HighPart = 0;
1999 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2000 if (vrock.shareName == NULL)
2003 vrock.matchType = 0;
2005 userp = (uidp? (uidp->unp ? uidp->unp->userp : cm_rootUserp) : cm_rootUserp);
2006 rscp = cm_RootSCachep(userp, &req);
2007 cm_HoldSCache(rscp);
2008 code = cm_ApplyDir(rscp, smb_FindShareProc, &vrock, &thyper,
2010 cm_ReleaseSCache(rscp);
2012 free(vrock.shareName);
2013 vrock.shareName = NULL;
2015 if (vrock.matchType) {
2016 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2017 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2022 /* if we get here, there was no match for the share in root.afs */
2023 /* so try to create \\<netbiosName>\<cellname> */
2028 /* Get the full name for this cell */
2029 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2030 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2031 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2032 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2033 if (code && cm_dnsEnabled) {
2035 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2040 /* construct the path */
2042 clientchar_t temp[1024];
2044 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2045 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2046 rw ? _C("/.%S/") : _C("/%S/"), temp);
2047 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2057 /* Client-side offline caching policy types */
2058 #define CSC_POLICY_MANUAL 0
2059 #define CSC_POLICY_DOCUMENTS 1
2060 #define CSC_POLICY_PROGRAMS 2
2061 #define CSC_POLICY_DISABLE 3
2063 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2066 clientchar_t policy[1024];
2069 int retval = CSC_POLICY_MANUAL;
2071 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2072 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2075 REG_OPTION_NON_VOLATILE,
2079 NULL ) != ERROR_SUCCESS)
2080 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2082 len = sizeof(policy);
2083 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2085 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2087 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2089 retval = CSC_POLICY_MANUAL;
2091 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2093 retval = CSC_POLICY_DOCUMENTS;
2095 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2097 retval = CSC_POLICY_PROGRAMS;
2099 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2101 retval = CSC_POLICY_DISABLE;
2104 RegCloseKey(hkCSCPolicy);
2108 /* find a dir search structure by cookie value, and return it held.
2109 * Must be called with smb_globalLock held.
2111 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2113 smb_dirSearch_t *dsp;
2115 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2116 if (dsp->cookie == cookie) {
2117 if (dsp != smb_firstDirSearchp) {
2118 /* move to head of LRU queue, too, if we're not already there */
2119 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2120 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2121 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2122 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2123 if (!smb_lastDirSearchp)
2124 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2132 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2133 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2134 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2140 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2142 lock_ObtainMutex(&dsp->mx);
2143 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2144 dsp->cookie, dsp, dsp->scp);
2145 dsp->flags |= SMB_DIRSEARCH_DELETE;
2146 if (dsp->scp != NULL) {
2147 lock_ObtainWrite(&dsp->scp->rw);
2148 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2149 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2150 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2151 dsp->scp->bulkStatProgress = hzero;
2153 lock_ReleaseWrite(&dsp->scp->rw);
2155 lock_ReleaseMutex(&dsp->mx);
2158 /* Must be called with the smb_globalLock held */
2159 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2161 cm_scache_t *scp = NULL;
2163 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2164 if (dsp->refCount == 0) {
2165 lock_ObtainMutex(&dsp->mx);
2166 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2167 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2168 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2169 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2170 lock_ReleaseMutex(&dsp->mx);
2171 lock_FinalizeMutex(&dsp->mx);
2173 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2174 dsp->cookie, dsp, scp);
2177 lock_ReleaseMutex(&dsp->mx);
2180 /* do this now to avoid spurious locking hierarchy creation */
2182 cm_ReleaseSCache(scp);
2185 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2187 lock_ObtainWrite(&smb_globalLock);
2188 smb_ReleaseDirSearchNoLock(dsp);
2189 lock_ReleaseWrite(&smb_globalLock);
2192 /* find a dir search structure by cookie value, and return it held */
2193 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2195 smb_dirSearch_t *dsp;
2197 lock_ObtainWrite(&smb_globalLock);
2198 dsp = smb_FindDirSearchNoLock(cookie);
2199 lock_ReleaseWrite(&smb_globalLock);
2203 /* GC some dir search entries, in the address space expected by the specific protocol.
2204 * Must be called with smb_globalLock held; release the lock temporarily.
2206 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2207 void smb_GCDirSearches(int isV3)
2209 smb_dirSearch_t *prevp;
2210 smb_dirSearch_t *dsp;
2211 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2215 victimCount = 0; /* how many have we got so far */
2216 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2217 /* we'll move tp from queue, so
2220 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2221 /* if no one is using this guy, and we're either in the new protocol,
2222 * or we're in the old one and this is a small enough ID to be useful
2223 * to the old protocol, GC this guy.
2225 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2226 /* hold and delete */
2227 lock_ObtainMutex(&dsp->mx);
2228 dsp->flags |= SMB_DIRSEARCH_DELETE;
2229 lock_ReleaseMutex(&dsp->mx);
2230 victimsp[victimCount++] = dsp;
2234 /* don't do more than this */
2235 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2239 /* now release them */
2240 for (i = 0; i < victimCount; i++) {
2241 smb_ReleaseDirSearchNoLock(victimsp[i]);
2245 /* function for allocating a dir search entry. We need these to remember enough context
2246 * since we don't get passed the path from call to call during a directory search.
2248 * Returns a held dir search structure, and bumps the reference count on the vnode,
2249 * since it saves a pointer to the vnode.
2251 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2253 smb_dirSearch_t *dsp;
2259 lock_ObtainWrite(&smb_globalLock);
2262 /* what's the biggest ID allowed in this version of the protocol */
2263 /* TODO: do we really want a non v3 dir search request to wrap
2264 smb_dirSearchCounter? */
2265 maxAllowed = isV3 ? 65535 : 255;
2266 if (smb_dirSearchCounter > maxAllowed)
2267 smb_dirSearchCounter = 1;
2269 start = smb_dirSearchCounter;
2272 /* twice so we have enough tries to find guys we GC after one pass;
2273 * 10 extra is just in case I mis-counted.
2275 if (++counter > 2*maxAllowed+10)
2276 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2278 if (smb_dirSearchCounter > maxAllowed) {
2279 smb_dirSearchCounter = 1;
2281 if (smb_dirSearchCounter == start) {
2283 smb_GCDirSearches(isV3);
2286 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2288 /* don't need to watch for refcount zero and deleted, since
2289 * we haven't dropped the global lock.
2292 ++smb_dirSearchCounter;
2296 dsp = malloc(sizeof(*dsp));
2297 memset(dsp, 0, sizeof(*dsp));
2298 dsp->cookie = smb_dirSearchCounter;
2299 ++smb_dirSearchCounter;
2301 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2302 dsp->lastTime = osi_Time();
2303 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2304 if (!smb_lastDirSearchp)
2305 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2307 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2311 lock_ReleaseWrite(&smb_globalLock);
2315 static smb_packet_t *smb_GetPacket(void)
2319 lock_ObtainWrite(&smb_globalLock);
2320 tbp = smb_packetFreeListp;
2322 smb_packetFreeListp = tbp->nextp;
2323 lock_ReleaseWrite(&smb_globalLock);
2325 tbp = calloc(sizeof(*tbp),1);
2326 tbp->magic = SMB_PACKETMAGIC;
2329 tbp->resumeCode = 0;
2335 tbp->ncb_length = 0;
2338 tbp->stringsp = NULL;
2340 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2345 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2348 tbp = smb_GetPacket();
2349 memcpy(tbp, pkt, sizeof(smb_packet_t));
2350 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2351 tbp->stringsp = NULL;
2353 smb_HoldVC(tbp->vcp);
2357 static NCB *smb_GetNCB(void)
2362 lock_ObtainWrite(&smb_globalLock);
2363 tbp = smb_ncbFreeListp;
2365 smb_ncbFreeListp = tbp->nextp;
2366 lock_ReleaseWrite(&smb_globalLock);
2368 tbp = calloc(sizeof(*tbp),1);
2369 tbp->magic = SMB_NCBMAGIC;
2372 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2374 memset(&tbp->ncb, 0, sizeof(NCB));
2379 static void FreeSMBStrings(smb_packet_t * pkt)
2384 for (s = pkt->stringsp; s; s = ns) {
2388 pkt->stringsp = NULL;
2391 void smb_FreePacket(smb_packet_t *tbp)
2393 smb_vc_t * vcp = NULL;
2394 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2396 lock_ObtainWrite(&smb_globalLock);
2397 tbp->nextp = smb_packetFreeListp;
2398 smb_packetFreeListp = tbp;
2399 tbp->magic = SMB_PACKETMAGIC;
2403 tbp->resumeCode = 0;
2409 tbp->ncb_length = 0;
2411 FreeSMBStrings(tbp);
2412 lock_ReleaseWrite(&smb_globalLock);
2418 static void smb_FreeNCB(NCB *bufferp)
2422 tbp = (smb_ncb_t *) bufferp;
2423 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2425 lock_ObtainWrite(&smb_globalLock);
2426 tbp->nextp = smb_ncbFreeListp;
2427 smb_ncbFreeListp = tbp;
2428 lock_ReleaseWrite(&smb_globalLock);
2431 /* get a ptr to the data part of a packet, and its count */
2432 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2436 unsigned char *afterParmsp;
2438 parmBytes = *smbp->wctp << 1;
2439 afterParmsp = smbp->wctp + parmBytes + 1;
2441 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2442 if (nbytesp) *nbytesp = dataBytes;
2444 /* don't forget to skip the data byte count, since it follows
2445 * the parameters; that's where the "2" comes from below.
2447 return (unsigned char *) (afterParmsp + 2);
2450 /* must set all the returned parameters before playing around with the
2451 * data region, since the data region is located past the end of the
2452 * variable number of parameters.
2454 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2456 unsigned char *afterParmsp;
2458 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2460 *afterParmsp++ = dsize & 0xff;
2461 *afterParmsp = (dsize>>8) & 0xff;
2464 /* return the parm'th parameter in the smbp packet */
2465 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2468 unsigned char *parmDatap;
2470 parmCount = *smbp->wctp;
2472 if (parm >= parmCount) {
2475 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2476 parm, parmCount, smbp->ncb_length);
2477 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2478 parm, parmCount, smbp->ncb_length);
2479 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2480 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2481 osi_panic(s, __FILE__, __LINE__);
2483 parmDatap = smbp->wctp + (2*parm) + 1;
2485 return parmDatap[0] + (parmDatap[1] << 8);
2488 /* return the parm'th parameter in the smbp packet */
2489 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2492 unsigned char *parmDatap;
2494 parmCount = *smbp->wctp;
2496 if (parm >= parmCount) {
2499 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2500 parm, parmCount, smbp->ncb_length);
2501 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2502 parm, parmCount, smbp->ncb_length);
2503 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2504 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2505 osi_panic(s, __FILE__, __LINE__);
2507 parmDatap = smbp->wctp + (2*parm) + 1;
2509 return parmDatap[0];
2512 /* return the parm'th parameter in the smbp packet */
2513 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2516 unsigned char *parmDatap;
2518 parmCount = *smbp->wctp;
2520 if (parm + 1 >= parmCount) {
2523 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2524 parm, parmCount, smbp->ncb_length);
2525 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2526 parm, parmCount, smbp->ncb_length);
2527 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2528 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2529 osi_panic(s, __FILE__, __LINE__);
2531 parmDatap = smbp->wctp + (2*parm) + 1;
2533 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2536 /* return the parm'th parameter in the smbp packet */
2537 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2540 unsigned char *parmDatap;
2542 parmCount = *smbp->wctp;
2544 if (parm * 2 + offset >= parmCount * 2) {
2547 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2548 parm, offset, parmCount, smbp->ncb_length);
2549 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2550 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2551 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2552 parm, offset, parmCount, smbp->ncb_length);
2553 osi_panic(s, __FILE__, __LINE__);
2555 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2557 return parmDatap[0] + (parmDatap[1] << 8);
2560 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2562 unsigned char *parmDatap;
2564 /* make sure we have enough slots */
2565 if (*smbp->wctp <= slot)
2566 *smbp->wctp = slot+1;
2568 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2569 *parmDatap++ = parmValue & 0xff;
2570 *parmDatap = (parmValue>>8) & 0xff;
2573 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2575 unsigned char *parmDatap;
2577 /* make sure we have enough slots */
2578 if (*smbp->wctp <= slot)
2579 *smbp->wctp = slot+2;
2581 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2582 *parmDatap++ = parmValue & 0xff;
2583 *parmDatap++ = (parmValue>>8) & 0xff;
2584 *parmDatap++ = (parmValue>>16) & 0xff;
2585 *parmDatap = (parmValue>>24) & 0xff;
2588 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2590 unsigned char *parmDatap;
2593 /* make sure we have enough slots */
2594 if (*smbp->wctp <= slot)
2595 *smbp->wctp = slot+4;
2597 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2599 *parmDatap++ = *parmValuep++;
2602 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2604 unsigned char *parmDatap;
2606 /* make sure we have enough slots */
2607 if (*smbp->wctp <= slot) {
2608 if (smbp->oddByte) {
2610 *smbp->wctp = slot+1;
2615 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2616 *parmDatap++ = parmValue & 0xff;
2621 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2622 clientchar_t *inPathp)
2624 clientchar_t *lastSlashp;
2625 clientchar_t *streamp = NULL;
2626 clientchar_t *typep = NULL;
2628 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2629 if (lastComponentp) {
2630 *lastComponentp = lastSlashp;
2634 * If the name contains a stream name and a type
2635 * and the stream name is the nul-string and the
2636 * type is $DATA, then strip "::$DATA" from the
2637 * last component string that is returned.
2639 * Otherwise, return the full path name and allow
2640 * the file name to be rejected because it contains
2643 typep = cm_ClientStrRChr(lastSlashp, L':');
2644 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2646 streamp = cm_ClientStrRChr(lastSlashp, L':');
2647 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2651 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2652 osi_LogSaveClientString(smb_logp,streamp),
2653 osi_LogSaveClientString(smb_logp,typep));
2657 if (inPathp == lastSlashp)
2659 *outPathp++ = *inPathp++;
2668 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2669 char **chainpp, int flags)
2672 afs_uint32 type = *inp++;
2675 * The first byte specifies the type of the input string.
2676 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2680 /* Length Counted */
2681 case 0x1: /* Data Block */
2682 case 0x5: /* Variable Block */
2683 cb = *inp++ << 16 | *inp++;
2686 /* Null-terminated string */
2687 case 0x4: /* ASCII */
2688 case 0x3: /* Pathname */
2689 case 0x2: /* Dialect */
2690 cb = sizeof(pktp->data) - (inp - pktp->data);
2691 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2692 #ifdef DEBUG_UNICODE
2695 cb = sizeof(pktp->data);
2700 return NULL; /* invalid input */
2704 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2705 flags |= SMB_STRF_FORCEASCII;
2708 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2711 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2712 char ** chainpp, int flags)
2717 if (!WANTS_UNICODE(pktp))
2718 flags |= SMB_STRF_FORCEASCII;
2721 cb = sizeof(pktp->data) - (inp - pktp->data);
2722 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2723 #ifdef DEBUG_UNICODE
2726 cb = sizeof(pktp->data);
2728 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2729 flags | SMB_STRF_SRCNULTERM);
2732 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2733 size_t cb, char ** chainpp, int flags)
2736 if (!WANTS_UNICODE(pktp))
2737 flags |= SMB_STRF_FORCEASCII;
2740 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2743 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2744 size_t cch, char ** chainpp, int flags)
2749 if (!WANTS_UNICODE(pktp))
2750 flags |= SMB_STRF_FORCEASCII;
2752 cb = cch * sizeof(wchar_t);
2755 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2759 smb_ParseStringBuf(const unsigned char * bufbase,
2760 cm_space_t ** stringspp,
2761 unsigned char *inp, size_t *pcb_max,
2762 char **chainpp, int flags)
2765 if (!(flags & SMB_STRF_FORCEASCII)) {
2767 cm_space_t * spacep;
2770 if (bufbase && ((inp - bufbase) % 2) != 0) {
2771 inp++; /* unicode strings are always word aligned */
2775 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2777 cch_src = *pcb_max / sizeof(wchar_t);
2781 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2788 spacep = cm_GetSpace();
2789 spacep->nextp = *stringspp;
2790 *stringspp = spacep;
2794 *chainpp = inp + sizeof(wchar_t);
2797 *(spacep->wdata) = 0;
2798 return spacep->wdata;
2801 StringCchCopyNW(spacep->wdata,
2802 lengthof(spacep->wdata),
2803 (const clientchar_t *) inp, cch_src);
2806 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2808 return spacep->wdata;
2812 cm_space_t * spacep;
2815 /* Not using Unicode */
2817 *chainpp = inp + strlen(inp) + 1;
2820 spacep = cm_GetSpace();
2821 spacep->nextp = *stringspp;
2822 *stringspp = spacep;
2824 cchdest = lengthof(spacep->wdata);
2825 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2826 spacep->wdata, cchdest);
2828 return spacep->wdata;
2834 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2836 size_t * plen, int flags)
2842 /* we are only calculating the required size */
2849 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2851 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2852 if (!(flags & SMB_STRF_IGNORENUL))
2853 *plen += sizeof(wchar_t);
2855 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2865 cch_str = cm_ClientStrLen(str);
2866 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2869 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2877 /* if outp != NULL ... */
2879 /* Number of bytes left in the buffer.
2881 If outp lies inside the packet data buffer, we assume that the
2882 buffer is the packet data buffer. Otherwise we assume that the
2883 buffer is sizeof(packet->data).
2886 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2887 align = (int)((outp - pktp->data) % 2);
2888 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2890 align = (int)(((size_t) outp) % 2);
2891 buffersize = (int)sizeof(pktp->data);
2896 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2902 if (*str == _C('\0')) {
2904 if (buffersize < sizeof(wchar_t))
2907 *((wchar_t *) outp) = L'\0';
2908 if (plen && !(flags & SMB_STRF_IGNORENUL))
2909 *plen += sizeof(wchar_t);
2910 return outp + sizeof(wchar_t);
2913 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2915 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2916 osi_LogSaveClientString(smb_logp, str),
2922 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2924 return outp + sizeof(wchar_t) * nchars;
2932 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2935 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2937 return outp + cch_dest;
2941 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2947 tlen = inp[0] + (inp[1]<<8);
2948 inp += 2; /* skip length field */
2951 *chainpp = inp + tlen;
2960 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2964 if (*inp++ != 0x1) return NULL;
2965 tlen = inp[0] + (inp[1]<<8);
2966 inp += 2; /* skip length field */
2969 *chainpp = inp + tlen;
2972 if (lengthp) *lengthp = tlen;
2977 /* format a packet as a response */
2978 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2983 outp = (smb_t *) op;
2985 /* zero the basic structure through the smb_wct field, and zero the data
2986 * size field, assuming that wct stays zero; otherwise, you have to
2987 * explicitly set the data size field, too.
2989 inSmbp = (smb_t *) inp;
2990 memset(outp, 0, sizeof(smb_t)+2);
2996 outp->com = inSmbp->com;
2997 outp->tid = inSmbp->tid;
2998 outp->pid = inSmbp->pid;
2999 outp->uid = inSmbp->uid;
3000 outp->mid = inSmbp->mid;
3001 outp->res[0] = inSmbp->res[0];
3002 outp->res[1] = inSmbp->res[1];
3003 op->inCom = inSmbp->com;
3005 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3006 #ifdef SEND_CANONICAL_PATHNAMES
3007 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3009 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3011 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3012 outp->flg2 |= SMB_FLAGS2_UNICODE;
3015 /* copy fields in generic packet area */
3016 op->wctp = &outp->wct;
3019 /* send a (probably response) packet; vcp tells us to whom to send it.
3020 * we compute the length by looking at wct and bcc fields.
3022 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3032 ncbp = smb_GetNCB();
3036 memset(ncbp, 0, sizeof(NCB));
3038 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
3039 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
3040 extra += tp[0] + (tp[1]<<8);
3041 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
3042 extra += 3; /* wct and length fields */
3044 ncbp->ncb_length = extra; /* bytes to send */
3045 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
3046 ncbp->ncb_lana_num = vcp->lana;
3047 ncbp->ncb_command = NCBSEND; /* op means send data */
3048 ncbp->ncb_buffer = (char *) inp;/* packet */
3049 code = Netbios(ncbp);
3052 const char * s = ncb_error_string(code);
3053 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3054 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3056 lock_ObtainMutex(&vcp->mx);
3057 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3058 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3060 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3061 lock_ReleaseMutex(&vcp->mx);
3062 lock_ObtainWrite(&smb_globalLock);
3063 dead_sessions[vcp->session] = TRUE;
3064 lock_ReleaseWrite(&smb_globalLock);
3065 smb_CleanupDeadVC(vcp);
3067 lock_ReleaseMutex(&vcp->mx);
3075 void smb_MapNTError(long code, unsigned long *NTStatusp)
3077 unsigned long NTStatus;
3079 /* map CM_ERROR_* errors to NT 32-bit status codes */
3080 /* NT Status codes are listed in ntstatus.h not winerror.h */
3084 else if (code == CM_ERROR_NOSUCHCELL) {
3085 NTStatus = 0xC0000034L; /* Name not found */
3087 else if (code == CM_ERROR_NOSUCHVOLUME) {
3088 NTStatus = 0xC0000034L; /* Name not found */
3090 else if (code == CM_ERROR_TIMEDOUT) {
3092 NTStatus = 0xC00000CFL; /* Sharing Paused */
3094 /* Do not send Timeout to the SMB redirector.
3095 * It causes the redirector to drop the connection */
3096 NTStatus = 0x00000102L; /* Timeout */
3097 /* do not send Retry to the SMB redirector.
3098 * It believes the error comes from the transport
3099 * layer not from the SMB server. */
3100 NTStatus = 0xC000022DL; /* Retry */
3102 NTStatus = 0xC00000B5L; /* I/O Timeout */
3105 else if (code == CM_ERROR_RETRY) {
3107 NTStatus = 0xC000022DL; /* Retry */
3109 NTStatus = 0xC00000B5L; /* I/O Timeout */
3112 else if (code == CM_ERROR_NOACCESS) {
3113 NTStatus = 0xC0000022L; /* Access denied */
3115 else if (code == CM_ERROR_READONLY) {
3116 NTStatus = 0xC00000A2L; /* Write protected */
3118 else if (code == CM_ERROR_NOSUCHFILE ||
3119 code == CM_ERROR_BPLUS_NOMATCH) {
3120 NTStatus = 0xC0000034L; /* Name not found */
3122 else if (code == CM_ERROR_NOSUCHPATH) {
3123 NTStatus = 0xC000003AL; /* Object path not found */
3125 else if (code == CM_ERROR_TOOBIG) {
3126 NTStatus = 0xC000007BL; /* Invalid image format */
3128 else if (code == CM_ERROR_INVAL) {
3129 NTStatus = 0xC000000DL; /* Invalid parameter */
3131 else if (code == CM_ERROR_BADFD) {
3132 NTStatus = 0xC0000008L; /* Invalid handle */
3134 else if (code == CM_ERROR_BADFDOP) {
3135 NTStatus = 0xC0000022L; /* Access denied */
3137 else if (code == CM_ERROR_UNKNOWN) {
3138 NTStatus = 0xC0000022L; /* Access denied */
3140 else if (code == CM_ERROR_EXISTS) {
3141 NTStatus = 0xC0000035L; /* Object name collision */
3143 else if (code == CM_ERROR_NOTEMPTY) {
3144 NTStatus = 0xC0000101L; /* Directory not empty */
3146 else if (code == CM_ERROR_CROSSDEVLINK) {
3147 NTStatus = 0xC00000D4L; /* Not same device */
3149 else if (code == CM_ERROR_NOTDIR) {
3150 NTStatus = 0xC0000103L; /* Not a directory */
3152 else if (code == CM_ERROR_ISDIR) {
3153 NTStatus = 0xC00000BAL; /* File is a directory */
3155 else if (code == CM_ERROR_BADOP) {
3157 /* I have no idea where this comes from */
3158 NTStatus = 0xC09820FFL; /* SMB no support */
3160 NTStatus = 0xC00000BBL; /* Not supported */
3161 #endif /* COMMENT */
3163 else if (code == CM_ERROR_BADSHARENAME) {
3164 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3166 else if (code == CM_ERROR_NOIPC) {
3168 NTStatus = 0xC0000022L; /* Access Denied */
3170 NTStatus = 0xC000013DL; /* Remote Resources */
3173 else if (code == CM_ERROR_CLOCKSKEW ||
3174 code == RXKADNOAUTH) {
3175 NTStatus = 0xC0000133L; /* Time difference at DC */
3177 else if (code == CM_ERROR_BADTID) {
3178 NTStatus = 0xC0982005L; /* SMB bad TID */
3180 else if (code == CM_ERROR_USESTD) {
3181 NTStatus = 0xC09820FBL; /* SMB use standard */
3183 else if (code == CM_ERROR_QUOTA) {
3184 NTStatus = 0xC0000044L; /* Quota exceeded */
3186 else if (code == CM_ERROR_SPACE) {
3187 NTStatus = 0xC000007FL; /* Disk full */
3189 else if (code == CM_ERROR_ATSYS) {
3190 NTStatus = 0xC0000033L; /* Object name invalid */
3192 else if (code == CM_ERROR_BADNTFILENAME) {
3193 NTStatus = 0xC0000033L; /* Object name invalid */
3195 else if (code == CM_ERROR_WOULDBLOCK) {
3196 NTStatus = 0xC00000D8L; /* Can't wait */
3198 else if (code == CM_ERROR_SHARING_VIOLATION) {
3199 NTStatus = 0xC0000043L; /* Sharing violation */
3201 else if (code == CM_ERROR_LOCK_CONFLICT) {
3202 NTStatus = 0xC0000054L; /* Lock conflict */
3204 else if (code == CM_ERROR_PARTIALWRITE) {
3205 NTStatus = 0xC000007FL; /* Disk full */
3207 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3208 NTStatus = 0xC0000023L; /* Buffer too small */
3210 else if (code == CM_ERROR_BUFFER_OVERFLOW) {
3211 NTStatus = 0x80000005L; /* Buffer overflow */
3213 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3214 NTStatus = 0xC0000035L; /* Object name collision */
3216 else if (code == CM_ERROR_BADPASSWORD) {
3217 NTStatus = 0xC000006DL; /* unknown username or bad password */
3219 else if (code == CM_ERROR_BADLOGONTYPE) {
3220 NTStatus = 0xC000015BL; /* logon type not granted */
3222 else if (code == CM_ERROR_GSSCONTINUE) {
3223 NTStatus = 0xC0000016L; /* more processing required */
3225 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3227 NTStatus = 0xC0000280L; /* reparse point not resolved */
3229 NTStatus = 0xC0000022L; /* Access Denied */
3232 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3233 NTStatus = 0xC0000257L; /* Path Not Covered */
3235 else if (code == CM_ERROR_ALLBUSY) {
3237 NTStatus = 0xC000022DL; /* Retry */
3239 NTStatus = 0xC00000B5L; /* I/O Timeout */
3242 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3243 NTStatus = 0xC000003AL; /* Path not found */
3245 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3246 NTStatus = 0xC0000322L; /* No Kerberos key */
3248 else if (code == CM_ERROR_BAD_LEVEL) {
3249 NTStatus = 0xC0000148L; /* Invalid Level */
3251 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3252 NTStatus = 0xC000007EL; /* Range Not Locked */
3254 else if (code == CM_ERROR_NOSUCHDEVICE) {
3255 NTStatus = 0xC000000EL; /* No Such Device */
3257 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3258 NTStatus = 0xC0000055L; /* Lock Not Granted */
3260 else if (code == ENOMEM) {
3261 NTStatus = 0xC0000017L; /* Out of Memory */
3263 else if (code == CM_ERROR_RPC_MOREDATA) {
3264 NTStatus = 0x80000005L; /* Buffer overflow */
3267 NTStatus = 0xC0982001L; /* SMB non-specific error */
3270 *NTStatusp = NTStatus;
3271 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3275 * NTSTATUS <-> Win32 Error Translation
3276 * http://support.microsoft.com/kb/113996
3278 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3280 unsigned long Win32E;
3282 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3286 else if (code == CM_ERROR_NOSUCHCELL) {
3287 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3289 else if (code == CM_ERROR_NOSUCHVOLUME) {
3290 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3292 else if (code == CM_ERROR_TIMEDOUT) {
3294 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3296 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3299 else if (code == CM_ERROR_RETRY) {
3300 Win32E = ERROR_RETRY; /* Retry */
3302 else if (code == CM_ERROR_NOACCESS) {
3303 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3305 else if (code == CM_ERROR_READONLY) {
3306 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3308 else if (code == CM_ERROR_NOSUCHFILE ||
3309 code == CM_ERROR_BPLUS_NOMATCH) {
3310 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3312 else if (code == CM_ERROR_NOSUCHPATH) {
3313 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3315 else if (code == CM_ERROR_TOOBIG) {
3316 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3318 else if (code == CM_ERROR_INVAL) {
3319 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3321 else if (code == CM_ERROR_BADFD) {
3322 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3324 else if (code == CM_ERROR_BADFDOP) {
3325 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3327 else if (code == CM_ERROR_UNKNOWN) {
3328 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3330 else if (code == CM_ERROR_EXISTS) {
3331 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3333 else if (code == CM_ERROR_NOTEMPTY) {
3334 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3336 else if (code == CM_ERROR_CROSSDEVLINK) {
3337 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3339 else if (code == CM_ERROR_NOTDIR) {
3340 Win32E = ERROR_DIRECTORY; /* Not a directory */
3342 else if (code == CM_ERROR_ISDIR) {
3343 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3345 else if (code == CM_ERROR_BADOP) {
3346 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3348 else if (code == CM_ERROR_BADSHARENAME) {
3349 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3351 else if (code == CM_ERROR_NOIPC) {
3353 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3355 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3358 else if (code == CM_ERROR_CLOCKSKEW ||
3359 code == RXKADNOAUTH) {
3360 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3362 else if (code == CM_ERROR_BADTID) {
3363 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3365 else if (code == CM_ERROR_USESTD) {
3366 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3368 else if (code == CM_ERROR_QUOTA) {
3369 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3371 else if (code == CM_ERROR_SPACE) {
3372 Win32E = ERROR_DISK_FULL; /* Disk full */
3374 else if (code == CM_ERROR_ATSYS) {
3375 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3377 else if (code == CM_ERROR_BADNTFILENAME) {
3378 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3380 else if (code == CM_ERROR_WOULDBLOCK) {
3381 Win32E = WAIT_TIMEOUT; /* Can't wait */
3383 else if (code == CM_ERROR_SHARING_VIOLATION) {
3384 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3386 else if (code == CM_ERROR_LOCK_CONFLICT) {
3387 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3389 else if (code == CM_ERROR_PARTIALWRITE) {
3390 Win32E = ERROR_DISK_FULL; /* Disk full */
3392 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3393 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3395 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3396 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3398 else if (code == CM_ERROR_BADPASSWORD) {
3399 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3401 else if (code == CM_ERROR_BADLOGONTYPE) {
3402 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3404 else if (code == CM_ERROR_GSSCONTINUE) {
3405 Win32E = ERROR_MORE_DATA; /* more processing required */
3407 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3409 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3411 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3414 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3415 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3417 else if (code == CM_ERROR_ALLBUSY) {
3418 Win32E = ERROR_RETRY; /* Retry */
3420 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3421 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3423 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3424 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3426 else if (code == CM_ERROR_BAD_LEVEL) {
3427 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3429 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3430 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3432 else if (code == CM_ERROR_NOSUCHDEVICE) {
3433 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3435 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3436 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3438 else if (code == ENOMEM) {
3439 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3441 else if (code == CM_ERROR_RPC_MOREDATA) {
3442 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3445 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3449 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3452 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3453 unsigned char *classp)
3455 unsigned char class;
3456 unsigned short error;
3458 /* map CM_ERROR_* errors to SMB errors */
3459 if (code == CM_ERROR_NOSUCHCELL) {
3461 error = 3; /* bad path */
3463 else if (code == CM_ERROR_NOSUCHVOLUME) {
3465 error = 3; /* bad path */
3467 else if (code == CM_ERROR_TIMEDOUT) {
3469 error = 81; /* server is paused */
3471 else if (code == CM_ERROR_RETRY) {
3472 class = 2; /* shouldn't happen */
3475 else if (code == CM_ERROR_NOACCESS) {
3477 error = 4; /* bad access */
3479 else if (code == CM_ERROR_READONLY) {
3481 error = 19; /* read only */
3483 else if (code == CM_ERROR_NOSUCHFILE ||
3484 code == CM_ERROR_BPLUS_NOMATCH) {
3486 error = 2; /* ENOENT! */
3488 else if (code == CM_ERROR_NOSUCHPATH) {
3490 error = 3; /* Bad path */
3492 else if (code == CM_ERROR_TOOBIG) {
3494 error = 11; /* bad format */
3496 else if (code == CM_ERROR_INVAL) {
3497 class = 2; /* server non-specific error code */
3500 else if (code == CM_ERROR_BADFD) {
3502 error = 6; /* invalid file handle */
3504 else if (code == CM_ERROR_BADFDOP) {
3505 class = 1; /* invalid op on FD */
3508 else if (code == CM_ERROR_EXISTS) {
3510 error = 80; /* file already exists */
3512 else if (code == CM_ERROR_NOTEMPTY) {
3514 error = 5; /* delete directory not empty */
3516 else if (code == CM_ERROR_CROSSDEVLINK) {
3518 error = 17; /* EXDEV */
3520 else if (code == CM_ERROR_NOTDIR) {
3521 class = 1; /* bad path */
3524 else if (code == CM_ERROR_ISDIR) {
3525 class = 1; /* access denied; DOS doesn't have a good match */
3528 else if (code == CM_ERROR_BADOP) {
3532 else if (code == CM_ERROR_BADSHARENAME) {
3536 else if (code == CM_ERROR_NOIPC) {
3538 error = 4; /* bad access */
3540 else if (code == CM_ERROR_CLOCKSKEW) {
3541 class = 1; /* invalid function */
3544 else if (code == CM_ERROR_BADTID) {
3548 else if (code == CM_ERROR_USESTD) {
3552 else if (code == CM_ERROR_REMOTECONN) {
3556 else if (code == CM_ERROR_QUOTA) {
3557 if (vcp->flags & SMB_VCFLAG_USEV3) {
3559 error = 39; /* disk full */
3563 error = 5; /* access denied */
3566 else if (code == CM_ERROR_SPACE) {
3567 if (vcp->flags & SMB_VCFLAG_USEV3) {
3569 error = 39; /* disk full */
3573 error = 5; /* access denied */
3576 else if (code == CM_ERROR_PARTIALWRITE) {
3578 error = 39; /* disk full */
3580 else if (code == CM_ERROR_ATSYS) {
3582 error = 2; /* ENOENT */
3584 else if (code == CM_ERROR_WOULDBLOCK) {
3586 error = 33; /* lock conflict */
3588 else if (code == CM_ERROR_LOCK_CONFLICT) {
3590 error = 33; /* lock conflict */
3592 else if (code == CM_ERROR_SHARING_VIOLATION) {
3594 error = 33; /* lock conflict */
3596 else if (code == CM_ERROR_NOFILES) {
3598 error = 18; /* no files in search */
3600 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3602 error = 183; /* Samba uses this */
3604 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3605 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3607 error = 2; /* bad password */
3609 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3611 error = 3; /* bad path */
3620 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3623 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3625 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3626 return CM_ERROR_BADOP;
3630 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3632 unsigned short EchoCount, i;
3633 char *data, *outdata;
3636 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3638 for (i=1; i<=EchoCount; i++) {
3639 data = smb_GetSMBData(inp, &dataSize);
3640 smb_SetSMBParm(outp, 0, i);
3641 smb_SetSMBDataLength(outp, dataSize);
3642 outdata = smb_GetSMBData(outp, NULL);
3643 memcpy(outdata, data, dataSize);
3644 smb_SendPacket(vcp, outp);
3650 /* SMB_COM_READ_RAW */
3651 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3654 long count, minCount, finalCount;
3658 smb_t *smbp = (smb_t*) inp;
3660 cm_user_t *userp = NULL;
3663 char *rawBuf = NULL;
3668 fd = smb_GetSMBParm(inp, 0);
3669 count = smb_GetSMBParm(inp, 3);
3670 minCount = smb_GetSMBParm(inp, 4);
3671 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3673 if (*inp->wctp == 10) {
3674 /* we were sent a request with 64-bit file offsets */
3675 #ifdef AFS_LARGEFILES
3676 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3678 if (LargeIntegerLessThanZero(offset)) {
3679 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3683 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3684 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3687 offset.HighPart = 0;
3691 /* we were sent a request with 32-bit file offsets */
3692 offset.HighPart = 0;
3695 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3696 fd, offset.HighPart, offset.LowPart, count);
3698 fidp = smb_FindFID(vcp, fd, 0);
3700 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3704 lock_ObtainMutex(&fidp->mx);
3706 lock_ReleaseMutex(&fidp->mx);
3707 smb_ReleaseFID(fidp);
3708 return CM_ERROR_BADFD;
3711 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3712 lock_ReleaseMutex(&fidp->mx);
3713 smb_CloseFID(vcp, fidp, NULL, 0);
3714 code = CM_ERROR_NOSUCHFILE;
3720 LARGE_INTEGER LOffset, LLength;
3723 key = cm_GenerateKey(vcp->vcID, pid, fd);
3725 LOffset.HighPart = offset.HighPart;
3726 LOffset.LowPart = offset.LowPart;
3727 LLength.HighPart = 0;
3728 LLength.LowPart = count;
3730 lock_ObtainWrite(&fidp->scp->rw);
3731 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3732 lock_ReleaseWrite(&fidp->scp->rw);
3735 lock_ReleaseMutex(&fidp->mx);
3739 lock_ObtainMutex(&smb_RawBufLock);
3741 /* Get a raw buf, from head of list */
3742 rawBuf = smb_RawBufs;
3743 smb_RawBufs = *(char **)smb_RawBufs;
3745 lock_ReleaseMutex(&smb_RawBufLock);
3747 lock_ReleaseMutex(&fidp->mx);
3751 if (fidp->flags & SMB_FID_IOCTL)
3753 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3755 /* Give back raw buffer */
3756 lock_ObtainMutex(&smb_RawBufLock);
3757 *((char **) rawBuf) = smb_RawBufs;
3759 smb_RawBufs = rawBuf;
3760 lock_ReleaseMutex(&smb_RawBufLock);
3763 lock_ReleaseMutex(&fidp->mx);
3764 smb_ReleaseFID(fidp);
3767 lock_ReleaseMutex(&fidp->mx);
3769 userp = smb_GetUserFromVCP(vcp, inp);
3771 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3777 cm_ReleaseUser(userp);
3780 smb_ReleaseFID(fidp);
3784 memset(ncbp, 0, sizeof(NCB));
3786 ncbp->ncb_length = (unsigned short) finalCount;
3787 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3788 ncbp->ncb_lana_num = vcp->lana;
3789 ncbp->ncb_command = NCBSEND;
3790 ncbp->ncb_buffer = rawBuf;
3792 code = Netbios(ncbp);
3794 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3797 /* Give back raw buffer */
3798 lock_ObtainMutex(&smb_RawBufLock);
3799 *((char **) rawBuf) = smb_RawBufs;
3801 smb_RawBufs = rawBuf;
3802 lock_ReleaseMutex(&smb_RawBufLock);
3808 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3810 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3815 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3817 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3822 /* SMB_COM_NEGOTIATE */
3823 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3830 int VistaProtoIndex;
3831 int protoIndex; /* index we're using */
3836 char protocol_array[10][1024]; /* protocol signature of the client */
3837 int caps; /* capabilities */
3840 TIME_ZONE_INFORMATION tzi;
3842 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3845 namep = smb_GetSMBData(inp, &dbytes);
3848 coreProtoIndex = -1; /* not found */
3851 VistaProtoIndex = -1;
3852 while(namex < dbytes) {
3853 osi_Log1(smb_logp, "Protocol %s",
3854 osi_LogSaveString(smb_logp, namep+1));
3855 strcpy(protocol_array[tcounter], namep+1);
3857 /* namep points at the first protocol, or really, a 0x02
3858 * byte preceding the null-terminated ASCII name.
3860 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3861 coreProtoIndex = tcounter;
3863 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3864 v3ProtoIndex = tcounter;
3866 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3867 NTProtoIndex = tcounter;
3869 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3870 VistaProtoIndex = tcounter;
3873 /* compute size of protocol entry */
3874 entryLength = (int)strlen(namep+1);
3875 entryLength += 2; /* 0x02 bytes and null termination */
3877 /* advance over this protocol entry */
3878 namex += entryLength;
3879 namep += entryLength;
3880 tcounter++; /* which proto entry we're looking at */
3883 lock_ObtainMutex(&vcp->mx);
3885 if (VistaProtoIndex != -1) {
3886 protoIndex = VistaProtoIndex;
3887 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3890 if (NTProtoIndex != -1) {
3891 protoIndex = NTProtoIndex;
3892 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3894 else if (v3ProtoIndex != -1) {
3895 protoIndex = v3ProtoIndex;
3896 vcp->flags |= SMB_VCFLAG_USEV3;
3898 else if (coreProtoIndex != -1) {
3899 protoIndex = coreProtoIndex;
3900 vcp->flags |= SMB_VCFLAG_USECORE;
3902 else protoIndex = -1;
3903 lock_ReleaseMutex(&vcp->mx);
3905 if (protoIndex == -1)
3906 return CM_ERROR_INVAL;
3907 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3908 smb_SetSMBParm(outp, 0, protoIndex);
3909 if (smb_authType != SMB_AUTH_NONE) {
3910 smb_SetSMBParmByte(outp, 1,
3911 NEGOTIATE_SECURITY_USER_LEVEL |
3912 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3914 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3916 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3917 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3918 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3919 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3920 /* The session key is not a well documented field however most clients
3921 * will echo back the session key to the server. Currently we are using
3922 * the same value for all sessions. We should generate a random value
3923 * and store it into the vcp
3925 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3926 smb_SetSMBParm(outp, 8, 1);
3928 * Tried changing the capabilities to support for W2K - defect 117695
3929 * Maybe something else needs to be changed here?
3933 smb_SetSMBParmLong(outp, 9, 0x43fd);
3935 smb_SetSMBParmLong(outp, 9, 0x251);
3938 * 32-bit error codes *
3944 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3946 NTNEGOTIATE_CAPABILITY_DFS |
3948 #ifdef AFS_LARGEFILES
3949 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3951 NTNEGOTIATE_CAPABILITY_NTFIND |
3952 NTNEGOTIATE_CAPABILITY_RAWMODE |
3953 NTNEGOTIATE_CAPABILITY_NTSMB;
3955 if ( smb_authType == SMB_AUTH_EXTENDED )
3956 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3959 if ( smb_UseUnicode ) {
3960 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3964 smb_SetSMBParmLong(outp, 9, caps);
3966 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3967 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3968 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3970 GetTimeZoneInformation(&tzi);
3971 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3973 if (smb_authType == SMB_AUTH_NTLM) {
3974 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3975 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3976 /* paste in encryption key */
3977 datap = smb_GetSMBData(outp, NULL);
3978 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3979 /* and the faux domain name */
3980 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3981 datap + MSV1_0_CHALLENGE_LENGTH,
3982 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3983 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3987 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3989 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3991 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3993 datap = smb_GetSMBData(outp, NULL);
3994 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3997 datap += sizeof(smb_ServerGUID);
3998 memcpy(datap, secBlob, secBlobLength);
4002 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
4003 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
4006 else if (v3ProtoIndex != -1) {
4007 smb_SetSMBParm(outp, 0, protoIndex);
4009 /* NOTE: Extended authentication cannot be negotiated with v3
4010 * therefore we fail over to NTLM
4012 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4013 smb_SetSMBParm(outp, 1,
4014 NEGOTIATE_SECURITY_USER_LEVEL |
4015 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
4017 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4019 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4020 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
4021 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
4022 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
4023 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
4024 smb_SetSMBParm(outp, 7, 1);
4026 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
4027 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
4028 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
4030 GetTimeZoneInformation(&tzi);
4031 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
4033 /* NOTE: Extended authentication cannot be negotiated with v3
4034 * therefore we fail over to NTLM
4036 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4037 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
4038 smb_SetSMBParm(outp, 12, 0); /* resvd */
4039 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
4040 datap = smb_GetSMBData(outp, NULL);
4041 /* paste in a new encryption key */
4042 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4043 /* and the faux domain name */
4044 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4045 datap + MSV1_0_CHALLENGE_LENGTH,
4046 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4048 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4049 smb_SetSMBParm(outp, 12, 0); /* resvd */
4050 smb_SetSMBDataLength(outp, 0);
4053 else if (coreProtoIndex != -1) { /* not really supported anymore */
4054 smb_SetSMBParm(outp, 0, protoIndex);
4055 smb_SetSMBDataLength(outp, 0);
4060 void smb_CheckVCs(void)
4062 smb_vc_t * vcp, *nextp;
4063 smb_packet_t * outp = smb_GetPacket();
4066 lock_ObtainWrite(&smb_rctLock);
4067 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4069 if (vcp->magic != SMB_VC_MAGIC)
4070 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4071 __FILE__, __LINE__);
4073 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4075 smb_HoldVCNoLock(vcp);
4078 * obtain a reference to 'nextp' now because we drop the
4079 * smb_rctLock later and the list contents could change
4080 * or 'vcp' could be destroyed when released.
4084 smb_HoldVCNoLock(nextp);
4086 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4087 smb_ReleaseVCNoLock(vcp);
4091 smb_FormatResponsePacket(vcp, NULL, outp);
4092 smbp = (smb_t *)outp;
4093 outp->inCom = smbp->com = 0x2b /* Echo */;
4101 smb_SetSMBParm(outp, 0, 0);
4102 smb_SetSMBDataLength(outp, 0);
4103 lock_ReleaseWrite(&smb_rctLock);
4105 smb_SendPacket(vcp, outp);
4107 lock_ObtainWrite(&smb_rctLock);
4108 smb_ReleaseVCNoLock(vcp);
4110 lock_ReleaseWrite(&smb_rctLock);
4111 smb_FreePacket(outp);
4114 void smb_Daemon(void *parmp)
4116 afs_uint32 count = 0;
4117 smb_username_t **unpp;
4120 while(smbShutdownFlag == 0) {
4124 if (smbShutdownFlag == 1)
4127 if ((count % 72) == 0) { /* every five minutes */
4129 time_t old_localZero = smb_localZero;
4131 /* Initialize smb_localZero */
4132 myTime.tm_isdst = -1; /* compute whether on DST or not */
4133 myTime.tm_year = 70;
4139 smb_localZero = mktime(&myTime);
4141 #ifdef AFS_FREELANCE
4142 if ( smb_localZero != old_localZero )
4143 cm_noteLocalMountPointChange(FALSE);
4149 /* GC smb_username_t objects that will no longer be used */
4151 lock_ObtainWrite(&smb_rctLock);
4152 for ( unpp=&usernamesp; *unpp; ) {
4154 smb_username_t *unp;
4156 lock_ObtainMutex(&(*unpp)->mx);
4157 if ( (*unpp)->refCount > 0 ||
4158 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4159 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4161 else if (!smb_LogoffTokenTransfer ||
4162 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4164 lock_ReleaseMutex(&(*unpp)->mx);
4172 lock_FinalizeMutex(&unp->mx);
4178 cm_ReleaseUser(userp);
4180 unpp = &(*unpp)->nextp;
4183 lock_ReleaseWrite(&smb_rctLock);
4185 /* XXX GC dir search entries */
4189 void smb_WaitingLocksDaemon()
4191 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4192 smb_waitingLock_t *wl, *wlNext;
4195 smb_packet_t *inp, *outp;
4199 while (smbShutdownFlag == 0) {
4200 lock_ObtainWrite(&smb_globalLock);
4201 nwlRequest = smb_allWaitingLocks;
4202 if (nwlRequest == NULL) {
4203 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4208 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4215 lock_ObtainWrite(&smb_globalLock);
4217 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4219 wlRequest = nwlRequest;
4220 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4221 lock_ReleaseWrite(&smb_globalLock);
4225 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4226 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4229 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4230 code = CM_ERROR_LOCK_NOT_GRANTED;
4234 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4236 /* wl->state is either _DONE or _WAITING. _ERROR
4237 would no longer be on the queue. */
4238 code = cm_RetryLock( wl->lockp,
4239 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4242 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4243 } else if (code != CM_ERROR_WOULDBLOCK) {
4244 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4249 if (code == CM_ERROR_WOULDBLOCK) {
4252 if (wlRequest->msTimeout != 0xffffffff
4253 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4265 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4268 scp = wlRequest->scp;
4269 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4273 lock_ObtainWrite(&scp->rw);
4275 for (wl = wlRequest->locks; wl; wl = wlNext) {
4276 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4278 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4279 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4280 wl->LLength, wl->key, 0, NULL, &req);
4282 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4287 lock_ReleaseWrite(&scp->rw);
4291 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4294 for (wl = wlRequest->locks; wl; wl = wlNext) {
4295 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4296 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4301 vcp = wlRequest->vcp;
4302 inp = wlRequest->inp;
4303 outp = wlRequest->outp;
4304 ncbp = smb_GetNCB();
4305 ncbp->ncb_length = inp->ncb_length;
4306 inp->spacep = cm_GetSpace();
4308 /* Remove waitingLock from list */
4309 lock_ObtainWrite(&smb_globalLock);
4310 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4312 lock_ReleaseWrite(&smb_globalLock);
4314 /* Resume packet processing */
4316 smb_SetSMBDataLength(outp, 0);
4317 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4318 outp->resumeCode = code;
4320 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4323 cm_FreeSpace(inp->spacep);
4324 smb_FreePacket(inp);
4325 smb_FreePacket(outp);
4327 cm_ReleaseSCache(wlRequest->scp);
4330 } while (nwlRequest && smbShutdownFlag == 0);
4335 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4337 osi_Log0(smb_logp, "SMB receive get disk attributes");
4339 smb_SetSMBParm(outp, 0, 32000);
4340 smb_SetSMBParm(outp, 1, 64);
4341 smb_SetSMBParm(outp, 2, 1024);
4342 smb_SetSMBParm(outp, 3, 30000);
4343 smb_SetSMBParm(outp, 4, 0);
4344 smb_SetSMBDataLength(outp, 0);
4348 /* SMB_COM_TREE_CONNECT */
4349 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4353 unsigned short newTid;
4354 clientchar_t shareName[AFSPATHMAX];
4355 clientchar_t *sharePath;
4358 clientchar_t *pathp;
4361 osi_Log0(smb_logp, "SMB receive tree connect");
4363 /* parse input parameters */
4366 tbp = smb_GetSMBData(inp, NULL);
4367 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4369 return CM_ERROR_BADSMB;
4371 tp = cm_ClientStrRChr(pathp, '\\');
4373 return CM_ERROR_BADSMB;
4374 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4376 lock_ObtainMutex(&vcp->mx);
4377 newTid = vcp->tidCounter++;
4378 lock_ReleaseMutex(&vcp->mx);
4380 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4381 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4383 return CM_ERROR_BADSMB;
4384 userp = smb_GetUserFromUID(uidp);
4385 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4386 smb_ReleaseUID(uidp);
4388 smb_ReleaseTID(tidp, FALSE);
4389 return CM_ERROR_BADSHARENAME;
4391 lock_ObtainMutex(&tidp->mx);
4392 tidp->userp = userp;
4393 tidp->pathname = sharePath;
4394 lock_ReleaseMutex(&tidp->mx);
4395 smb_ReleaseTID(tidp, FALSE);
4397 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4398 smb_SetSMBParm(rsp, 1, newTid);
4399 smb_SetSMBDataLength(rsp, 0);
4401 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4405 /* set maskp to the mask part of the incoming path.
4406 * Mask is 11 bytes long (8.3 with the dot elided).
4407 * Returns true if succeeds with a valid name, otherwise it does
4408 * its best, but returns false.
4410 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4418 /* starts off valid */
4421 /* mask starts out all blanks */
4422 memset(maskp, ' ', 11);
4425 /* find last backslash, or use whole thing if there is none */
4426 tp = cm_ClientStrRChr(pathp, '\\');
4430 tp++; /* skip slash */
4434 /* names starting with a dot are illegal */
4442 if (tc == '.' || tc == '"')
4450 /* if we get here, tp point after the dot */
4451 up = maskp+8; /* ext goes here */
4458 if (tc == '.' || tc == '"')
4461 /* copy extension if not too long */
4471 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4473 clientchar_t umask[11];
4481 /* XXX redo this, calling cm_MatchMask with a converted mask */
4483 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4487 /* otherwise, we have a valid 8.3 name; see if we have a match,
4488 * treating '?' as a wildcard in maskp (but not in the file name).
4490 tp1 = umask; /* real name, in mask format */
4491 tp2 = maskp; /* mask, in mask format */
4492 for(i=0; i<11; i++) {
4493 tc1 = *tp1++; /* clientchar_t from real name */
4494 tc2 = *tp2++; /* clientchar_t from mask */
4495 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4496 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4499 if (tc2 == '?' && tc1 != ' ')
4506 /* we got a match */
4510 clientchar_t *smb_FindMask(clientchar_t *pathp)
4514 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4517 return tp+1; /* skip the slash */
4519 return pathp; /* no slash, return the entire path */
4522 /* SMB_COM_SEARCH for a volume label
4524 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4525 dispatch function.) */
4526 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4528 clientchar_t *pathp;
4530 clientchar_t mask[12];
4531 unsigned char *statBlockp;
4532 unsigned char initStatBlock[21];
4535 osi_Log0(smb_logp, "SMB receive search volume");
4537 /* pull pathname and stat block out of request */
4538 tp = smb_GetSMBData(inp, NULL);
4539 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4540 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4542 return CM_ERROR_BADSMB;
4543 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4544 osi_assertx(statBlockp != NULL, "null statBlock");
4546 statBlockp = initStatBlock;
4550 /* for returning to caller */
4551 smb_Get8Dot3MaskFromPath(mask, pathp);
4553 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4554 tp = smb_GetSMBData(outp, NULL);
4556 *tp++ = 43; /* bytes in a dir entry */
4557 *tp++ = 0; /* high byte in counter */
4559 /* now marshall the dir entry, starting with the search status */
4560 *tp++ = statBlockp[0]; /* Reserved */
4561 memcpy(tp, mask, 11); tp += 11; /* FileName */
4563 /* now pass back server use info, with 1st byte non-zero */
4565 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4567 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4569 *tp++ = 0x8; /* attribute: volume */
4579 /* 4 byte file size */
4585 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4588 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4589 memset(tp, ' ', 13);
4592 /* set the length of the data part of the packet to 43 + 3, for the dir
4593 * entry plus the 5 and the length fields.
4595 smb_SetSMBDataLength(outp, 46);
4600 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4601 clientchar_t * tidPathp, clientchar_t * relPathp,
4602 cm_user_t *userp, cm_req_t *reqp)
4610 smb_dirListPatch_t *patchp;
4611 smb_dirListPatch_t *npatchp;
4612 clientchar_t path[AFSPATHMAX];
4614 afs_int32 mustFake = 0;
4616 code = cm_FindACLCache(dscp, userp, &rights);
4618 lock_ObtainWrite(&dscp->rw);
4619 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4620 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4621 lock_ReleaseWrite(&dscp->rw);
4622 if (code == CM_ERROR_NOACCESS) {
4630 if (!mustFake) { /* Bulk Stat */
4632 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4634 memset(bsp, 0, sizeof(cm_bulkStat_t));
4636 for (patchp = *dirPatchespp, count=0;
4638 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4639 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4643 if (lock_TryWrite(&tscp->rw)) {
4644 /* we have an entry that we can look at */
4645 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4646 /* we have a callback on it. Don't bother
4647 * fetching this stat entry, since we're happy
4648 * with the info we have.
4650 lock_ReleaseWrite(&tscp->rw);
4651 cm_ReleaseSCache(tscp);
4654 lock_ReleaseWrite(&tscp->rw);
4656 cm_ReleaseSCache(tscp);
4660 bsp->fids[i].Volume = patchp->fid.volume;
4661 bsp->fids[i].Vnode = patchp->fid.vnode;
4662 bsp->fids[i].Unique = patchp->fid.unique;
4664 if (bsp->counter == AFSCBMAX) {
4665 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4666 memset(bsp, 0, sizeof(cm_bulkStat_t));
4670 if (bsp->counter > 0)
4671 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4676 for (patchp = *dirPatchespp; patchp; patchp =
4677 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4679 dptr = patchp->dptr;
4681 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4682 relPathp ? relPathp : _C(""), patchp->dep->name);
4683 reqp->relPathp = path;
4684 reqp->tidPathp = tidPathp;
4686 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4687 reqp->relPathp = reqp->tidPathp = NULL;
4690 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4691 *dptr++ = SMB_ATTR_HIDDEN;
4694 lock_ObtainWrite(&scp->rw);
4695 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4696 lock_ReleaseWrite(&scp->rw);
4698 /* set the attribute */
4699 switch (scp->fileType) {
4700 case CM_SCACHETYPE_DIRECTORY:
4701 case CM_SCACHETYPE_MOUNTPOINT:
4702 case CM_SCACHETYPE_INVALID:
4703 attr = SMB_ATTR_DIRECTORY;
4705 case CM_SCACHETYPE_SYMLINK:
4706 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4707 attr = SMB_ATTR_DIRECTORY;
4709 attr = SMB_ATTR_NORMAL;
4712 /* if we get here we either have a normal file
4713 * or we have a file for which we have never
4714 * received status info. In this case, we can
4715 * check the even/odd value of the entry's vnode.
4716 * odd means it is to be treated as a directory
4717 * and even means it is to be treated as a file.
4719 if (mustFake && (scp->fid.vnode & 0x1))
4720 attr = SMB_ATTR_DIRECTORY;
4722 attr = SMB_ATTR_NORMAL;
4726 /* 1969-12-31 23:59:58 +00*/
4727 dosTime = 0xEBBFBF7D;
4730 shortTemp = (unsigned short) (dosTime & 0xffff);
4731 *((u_short *)dptr) = shortTemp;
4734 /* and copy out date */
4735 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4736 *((u_short *)dptr) = shortTemp;
4739 /* copy out file length */
4740 *((u_long *)dptr) = 0;
4743 lock_ConvertWToR(&scp->rw);
4744 attr = smb_Attributes(scp);
4745 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4746 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4747 attr |= SMB_ATTR_HIDDEN;
4751 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4754 shortTemp = (unsigned short) (dosTime & 0xffff);
4755 *((u_short *)dptr) = shortTemp;
4758 /* and copy out date */
4759 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4760 *((u_short *)dptr) = shortTemp;
4763 /* copy out file length */
4764 *((u_long *)dptr) = scp->length.LowPart;
4766 lock_ReleaseRead(&scp->rw);
4768 cm_ReleaseSCache(scp);
4771 /* now free the patches */
4772 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4773 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4777 /* and mark the list as empty */
4778 *dirPatchespp = NULL;
4784 /* SMB_COM_SEARCH */
4785 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4791 clientchar_t *pathp;
4792 cm_dirEntry_t *dep = 0;
4794 smb_dirListPatch_t *dirListPatchesp;
4795 smb_dirListPatch_t *curPatchp;
4799 osi_hyper_t dirLength;
4800 osi_hyper_t bufferOffset;
4801 osi_hyper_t curOffset;
4803 unsigned char *inCookiep;
4804 smb_dirSearch_t *dsp;
4808 unsigned long clientCookie;
4809 cm_pageHeader_t *pageHeaderp;
4810 cm_user_t *userp = NULL;
4812 clientchar_t mask[12];
4814 long nextEntryCookie;
4815 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4816 char resByte; /* reserved byte from the cookie */
4817 char *op; /* output data ptr */
4818 char *origOp; /* original value of op */
4819 cm_space_t *spacep; /* for pathname buffer */
4823 clientchar_t *tidPathp = 0;
4830 maxCount = smb_GetSMBParm(inp, 0);
4832 dirListPatchesp = NULL;
4834 caseFold = CM_FLAG_CASEFOLD;
4836 tp = smb_GetSMBData(inp, NULL);
4837 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4838 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4840 return CM_ERROR_BADSMB;
4842 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4844 return CM_ERROR_BADSMB;
4846 /* We can handle long names */
4847 if (vcp->flags & SMB_VCFLAG_USENT)
4848 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4850 /* make sure we got a whole search status */
4851 if (dataLength < 21) {
4852 nextCookie = 0; /* start at the beginning of the dir */
4855 attribute = smb_GetSMBParm(inp, 1);
4857 /* handle volume info in another function */
4858 if (attribute & 0x8)
4859 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4861 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4862 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4864 if (*pathp == 0) { /* null pathp, treat as root dir */
4865 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4866 return CM_ERROR_NOFILES;
4870 dsp = smb_NewDirSearch(0);
4871 dsp->attribute = attribute;
4872 smb_Get8Dot3MaskFromPath(mask, pathp);
4873 memcpy(dsp->mask, mask, 12);
4875 /* track if this is likely to match a lot of entries */
4876 if (smb_Is8Dot3StarMask(mask))
4881 /* pull the next cookie value out of the search status block */
4882 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4883 + (inCookiep[16]<<24);
4884 dsp = smb_FindDirSearch(inCookiep[12]);
4886 /* can't find dir search status; fatal error */
4887 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4888 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4889 return CM_ERROR_BADFD;
4891 attribute = dsp->attribute;
4892 resByte = inCookiep[0];
4894 /* copy out client cookie, in host byte order. Don't bother
4895 * interpreting it, since we're just passing it through, anyway.
4897 memcpy(&clientCookie, &inCookiep[17], 4);
4899 memcpy(mask, dsp->mask, 12);
4901 /* assume we're doing a star match if it has continued for more
4907 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4908 nextCookie, dsp->cookie, attribute);
4910 userp = smb_GetUserFromVCP(vcp, inp);
4912 /* try to get the vnode for the path name next */
4913 lock_ObtainMutex(&dsp->mx);
4916 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4920 spacep = inp->spacep;
4921 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4922 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4924 lock_ReleaseMutex(&dsp->mx);
4925 cm_ReleaseUser(userp);
4926 smb_DeleteDirSearch(dsp);
4927 smb_ReleaseDirSearch(dsp);
4928 return CM_ERROR_NOFILES;
4930 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4931 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4933 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
4934 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4937 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4940 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4941 cm_ReleaseSCache(scp);
4942 lock_ReleaseMutex(&dsp->mx);
4943 cm_ReleaseUser(userp);
4944 smb_DeleteDirSearch(dsp);
4945 smb_ReleaseDirSearch(dsp);
4946 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4947 return CM_ERROR_PATH_NOT_COVERED;
4949 return CM_ERROR_NOSUCHPATH;
4951 #endif /* DFS_SUPPORT */
4954 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4955 /* we need one hold for the entry we just stored into,
4956 * and one for our own processing. When we're done with this
4957 * function, we'll drop the one for our own processing.
4958 * We held it once from the namei call, and so we do another hold
4962 lock_ObtainWrite(&scp->rw);
4963 dsp->flags |= SMB_DIRSEARCH_BULKST;
4964 lock_ReleaseWrite(&scp->rw);
4967 lock_ReleaseMutex(&dsp->mx);
4969 cm_ReleaseUser(userp);
4970 smb_DeleteDirSearch(dsp);
4971 smb_ReleaseDirSearch(dsp);
4975 /* reserves space for parameter; we'll adjust it again later to the
4976 * real count of the # of entries we returned once we've actually
4977 * assembled the directory listing.
4979 smb_SetSMBParm(outp, 0, 0);
4981 /* get the directory size */
4982 lock_ObtainWrite(&scp->rw);
4983 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4984 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4986 lock_ReleaseWrite(&scp->rw);
4987 cm_ReleaseSCache(scp);
4988 cm_ReleaseUser(userp);
4989 smb_DeleteDirSearch(dsp);
4990 smb_ReleaseDirSearch(dsp);
4994 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4996 dirLength = scp->length;
4998 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4999 curOffset.HighPart = 0;
5000 curOffset.LowPart = nextCookie;
5001 origOp = op = smb_GetSMBData(outp, NULL);
5002 /* and write out the basic header */
5003 *op++ = 5; /* variable block */
5004 op += 2; /* skip vbl block length; we'll fill it in later */
5008 clientchar_t *actualName = NULL;
5009 int free_actualName = 0;
5010 clientchar_t shortName[13];
5011 clientchar_t *shortNameEnd;
5013 /* make sure that curOffset.LowPart doesn't point to the first
5014 * 32 bytes in the 2nd through last dir page, and that it doesn't
5015 * point at the first 13 32-byte chunks in the first dir page,
5016 * since those are dir and page headers, and don't contain useful
5019 temp = curOffset.LowPart & (2048-1);
5020 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5021 /* we're in the first page */
5022 if (temp < 13*32) temp = 13*32;
5025 /* we're in a later dir page */
5026 if (temp < 32) temp = 32;
5029 /* make sure the low order 5 bits are zero */
5032 /* now put temp bits back ito curOffset.LowPart */
5033 curOffset.LowPart &= ~(2048-1);
5034 curOffset.LowPart |= temp;
5036 /* check if we've returned all the names that will fit in the
5039 if (returnedNames >= maxCount) {
5040 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5041 returnedNames, maxCount);
5045 /* check if we've passed the dir's EOF */
5046 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5048 /* see if we can use the bufferp we have now; compute in which page
5049 * the current offset would be, and check whether that's the offset
5050 * of the buffer we have. If not, get the buffer.
5052 thyper.HighPart = curOffset.HighPart;
5053 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5054 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5057 buf_Release(bufferp);
5060 lock_ReleaseWrite(&scp->rw);
5061 code = buf_Get(scp, &thyper, &req, &bufferp);
5062 lock_ObtainMutex(&dsp->mx);
5064 /* now, if we're doing a star match, do bulk fetching of all of
5065 * the status info for files in the dir.
5068 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5070 lock_ObtainWrite(&scp->rw);
5071 lock_ReleaseMutex(&dsp->mx);
5073 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5077 bufferOffset = thyper;
5079 /* now get the data in the cache */
5081 code = cm_SyncOp(scp, bufferp, userp, &req,
5083 CM_SCACHESYNC_NEEDCALLBACK |
5084 CM_SCACHESYNC_READ);
5086 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5090 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5092 if (cm_HaveBuffer(scp, bufferp, 0)) {
5093 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5097 /* otherwise, load the buffer and try again */
5098 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5100 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5101 scp, bufferp, code);
5106 buf_Release(bufferp);
5110 } /* if (wrong buffer) ... */
5112 /* now we have the buffer containing the entry we're interested in; copy
5113 * it out if it represents a non-deleted entry.
5115 entryInDir = curOffset.LowPart & (2048-1);
5116 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5118 /* page header will help tell us which entries are free. Page header
5119 * can change more often than once per buffer, since AFS 3 dir page size
5120 * may be less than (but not more than a buffer package buffer.
5122 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5123 temp &= ~(2048 - 1); /* turn off intra-page bits */
5124 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5126 /* now determine which entry we're looking at in the page. If it is
5127 * free (there's a free bitmap at the start of the dir), we should
5128 * skip these 32 bytes.
5130 slotInPage = (entryInDir & 0x7e0) >> 5;
5131 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5132 /* this entry is free */
5133 numDirChunks = 1; /* only skip this guy */
5137 tp = bufferp->datap + entryInBuffer;
5138 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5140 /* while we're here, compute the next entry's location, too,
5141 * since we'll need it when writing out the cookie into the dir
5144 * XXXX Probably should do more sanity checking.
5146 numDirChunks = cm_NameEntries(dep->name, NULL);
5148 /* compute the offset of the cookie representing the next entry */
5149 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5151 /* Compute 8.3 name if necessary */
5152 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5153 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5156 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5157 actualName = shortName;
5158 free_actualName = 0;
5160 free_actualName = 1;
5163 if (actualName == NULL) {
5164 /* Couldn't convert the name for some reason */
5165 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5166 osi_LogSaveString(smb_logp, dep->name));
5170 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5171 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5172 osi_LogSaveClientString(smb_logp, actualName));
5174 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5175 /* this is one of the entries to use: it is not deleted
5176 * and it matches the star pattern we're looking for.
5179 /* Eliminate entries that don't match requested
5182 /* no hidden files */
5183 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5184 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5188 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5190 /* We have already done the cm_TryBulkStat above */
5191 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5192 fileType = cm_FindFileType(&fid);
5193 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5194 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5196 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5197 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5198 fileType == CM_SCACHETYPE_DFSLINK ||
5199 fileType == CM_SCACHETYPE_INVALID)
5200 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5205 memcpy(op, mask, 11); op += 11;
5206 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5207 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5208 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5209 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5210 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5211 memcpy(op, &clientCookie, 4); op += 4;
5213 /* now we emit the attribute. This is sort of tricky,
5214 * since we need to really stat the file to find out
5215 * what type of entry we've got. Right now, we're
5216 * copying out data from a buffer, while holding the
5217 * scp locked, so it isn't really convenient to stat
5218 * something now. We'll put in a place holder now,
5219 * and make a second pass before returning this to get
5220 * the real attributes. So, we just skip the data for
5221 * now, and adjust it later. We allocate a patch
5222 * record to make it easy to find this point later.
5223 * The replay will happen at a time when it is safe to
5224 * unlock the directory.
5226 curPatchp = malloc(sizeof(*curPatchp));
5227 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5228 curPatchp->dptr = op;
5229 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5231 /* do hidden attribute here since name won't be around when applying
5235 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5236 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5238 curPatchp->flags = 0;
5240 op += 9; /* skip attr, time, date and size */
5242 /* zero out name area. The spec says to pad with
5243 * spaces, but Samba doesn't, and neither do we.
5247 /* finally, we get to copy out the name; we know that
5248 * it fits in 8.3 or the pattern wouldn't match, but it
5249 * never hurts to be sure.
5251 cm_ClientStringToUtf8(actualName, -1, op, 13);
5252 if (smb_StoreAnsiFilenames)
5254 /* This is a UCHAR field, which is ASCII even if Unicode
5257 /* Uppercase if requested by client */
5258 if (!KNOWS_LONG_NAMES(inp))
5263 /* now, adjust the # of entries copied */
5265 } /* if we're including this name */
5268 if (free_actualName && actualName) {
5273 /* and adjust curOffset to be where the new cookie is */
5274 thyper.HighPart = 0;
5275 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5276 curOffset = LargeIntegerAdd(thyper, curOffset);
5277 } /* while copying data for dir listing */
5279 /* release the mutex */
5280 lock_ReleaseWrite(&scp->rw);
5282 buf_Release(bufferp);
5286 /* apply and free last set of patches; if not doing a star match, this
5287 * will be empty, but better safe (and freeing everything) than sorry.
5289 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5291 /* special return code for unsuccessful search */
5292 if (code == 0 && dataLength < 21 && returnedNames == 0)
5293 code = CM_ERROR_NOFILES;
5295 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5296 returnedNames, code);
5299 smb_DeleteDirSearch(dsp);
5300 smb_ReleaseDirSearch(dsp);
5301 cm_ReleaseSCache(scp);
5302 cm_ReleaseUser(userp);
5306 /* finalize the output buffer */
5307 smb_SetSMBParm(outp, 0, returnedNames);
5308 temp = (long) (op - origOp);
5309 smb_SetSMBDataLength(outp, temp);
5311 /* the data area is a variable block, which has a 5 (already there)
5312 * followed by the length of the # of data bytes. We now know this to
5313 * be "temp," although that includes the 3 bytes of vbl block header.
5314 * Deduct for them and fill in the length field.
5316 temp -= 3; /* deduct vbl block info */
5317 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5318 origOp[1] = (unsigned char)(temp & 0xff);
5319 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5320 if (returnedNames == 0)
5321 smb_DeleteDirSearch(dsp);
5322 smb_ReleaseDirSearch(dsp);
5323 cm_ReleaseSCache(scp);
5324 cm_ReleaseUser(userp);
5329 /* verify that this is a valid path to a directory. I don't know why they
5330 * don't use the get file attributes call.
5332 * SMB_COM_CHECK_DIRECTORY
5334 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5336 clientchar_t *pathp;
5338 cm_scache_t *rootScp;
5339 cm_scache_t *newScp;
5343 clientchar_t *tidPathp;
5349 pdata = smb_GetSMBData(inp, NULL);
5350 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5352 return CM_ERROR_BADSMB;
5353 osi_Log1(smb_logp, "SMB receive check path %S",
5354 osi_LogSaveClientString(smb_logp, pathp));
5356 userp = smb_GetUserFromVCP(vcp, inp);
5358 rootScp = cm_RootSCachep(userp, &req);
5360 caseFold = CM_FLAG_CASEFOLD;
5362 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5364 cm_ReleaseUser(userp);
5365 return CM_ERROR_NOSUCHPATH;
5367 code = cm_NameI(rootScp, pathp,
5368 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5369 userp, tidPathp, &req, &newScp);
5372 cm_ReleaseUser(userp);
5377 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5378 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5379 cm_ReleaseSCache(newScp);
5380 cm_ReleaseUser(userp);
5381 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5382 return CM_ERROR_PATH_NOT_COVERED;
5384 return CM_ERROR_NOSUCHPATH;
5386 #endif /* DFS_SUPPORT */
5388 /* now lock the vnode with a callback; returns with newScp locked */
5389 lock_ObtainWrite(&newScp->rw);
5390 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5391 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5393 if (code != CM_ERROR_NOACCESS) {
5394 lock_ReleaseWrite(&newScp->rw);
5395 cm_ReleaseSCache(newScp);
5396 cm_ReleaseUser(userp);
5400 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5403 attrs = smb_Attributes(newScp);
5405 if (!(attrs & SMB_ATTR_DIRECTORY))
5406 code = CM_ERROR_NOTDIR;
5408 lock_ReleaseWrite(&newScp->rw);
5410 cm_ReleaseSCache(newScp);
5411 cm_ReleaseUser(userp);
5415 /* SMB_COM_SET_INFORMATION */
5416 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5418 clientchar_t *pathp;
5420 cm_scache_t *rootScp;
5421 unsigned short attribute;
5423 cm_scache_t *newScp;
5427 clientchar_t *tidPathp;
5433 /* decode basic attributes we're passed */
5434 attribute = smb_GetSMBParm(inp, 0);
5435 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5437 datap = smb_GetSMBData(inp, NULL);
5438 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5440 return CM_ERROR_BADSMB;
5442 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5443 dosTime, attribute);
5445 userp = smb_GetUserFromVCP(vcp, inp);
5447 rootScp = cm_RootSCachep(userp, &req);
5449 caseFold = CM_FLAG_CASEFOLD;
5451 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5453 cm_ReleaseUser(userp);
5454 return CM_ERROR_NOSUCHFILE;
5456 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5457 tidPathp, &req, &newScp);
5460 cm_ReleaseUser(userp);
5465 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5466 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5467 cm_ReleaseSCache(newScp);
5468 cm_ReleaseUser(userp);
5469 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5470 return CM_ERROR_PATH_NOT_COVERED;
5472 return CM_ERROR_NOSUCHPATH;
5474 #endif /* DFS_SUPPORT */
5476 /* now lock the vnode with a callback; returns with newScp locked; we
5477 * need the current status to determine what the new status is, in some
5480 lock_ObtainWrite(&newScp->rw);
5481 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5482 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5484 lock_ReleaseWrite(&newScp->rw);
5485 cm_ReleaseSCache(newScp);
5486 cm_ReleaseUser(userp);
5490 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5492 /* Check for RO volume */
5493 if (newScp->flags & CM_SCACHEFLAG_RO) {
5494 lock_ReleaseWrite(&newScp->rw);
5495 cm_ReleaseSCache(newScp);
5496 cm_ReleaseUser(userp);
5497 return CM_ERROR_READONLY;
5500 /* prepare for setattr call */
5503 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5504 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5506 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5507 /* we're told to make a writable file read-only */
5508 attr.unixModeBits = newScp->unixModeBits & ~0222;
5509 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5511 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5512 /* we're told to make a read-only file writable */
5513 attr.unixModeBits = newScp->unixModeBits | 0222;
5514 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5516 lock_ReleaseWrite(&newScp->rw);
5518 /* now call setattr */
5520 code = cm_SetAttr(newScp, &attr, userp, &req);
5524 cm_ReleaseSCache(newScp);
5525 cm_ReleaseUser(userp);
5531 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5533 clientchar_t *pathp;
5535 cm_scache_t *rootScp;
5536 cm_scache_t *newScp, *dscp;
5541 clientchar_t *tidPathp;
5543 clientchar_t *lastComp;
5549 datap = smb_GetSMBData(inp, NULL);
5550 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5552 return CM_ERROR_BADSMB;
5554 if (*pathp == 0) /* null path */
5557 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5558 osi_LogSaveClientString(smb_logp, pathp));
5560 userp = smb_GetUserFromVCP(vcp, inp);
5562 rootScp = cm_RootSCachep(userp, &req);
5564 /* we shouldn't need this for V3 requests, but we seem to */
5565 caseFold = CM_FLAG_CASEFOLD;
5567 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5569 cm_ReleaseUser(userp);
5570 return CM_ERROR_NOSUCHFILE;
5574 * XXX Strange hack XXX
5576 * As of Patch 5 (16 July 97), we are having the following problem:
5577 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5578 * requests to look up "desktop.ini" in all the subdirectories.
5579 * This can cause zillions of timeouts looking up non-existent cells
5580 * and volumes, especially in the top-level directory.
5582 * We have not found any way to avoid this or work around it except
5583 * to explicitly ignore the requests for mount points that haven't
5584 * yet been evaluated and for directories that haven't yet been
5587 * We should modify this hack to provide a fake desktop.ini file
5588 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5590 spacep = inp->spacep;
5591 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5592 #ifndef SPECIAL_FOLDERS
5593 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5594 code = cm_NameI(rootScp, spacep->wdata,
5595 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5596 userp, tidPathp, &req, &dscp);
5599 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5600 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5602 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5603 return CM_ERROR_PATH_NOT_COVERED;
5605 return CM_ERROR_NOSUCHPATH;
5607 #endif /* DFS_SUPPORT */
5608 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5609 code = CM_ERROR_NOSUCHFILE;
5610 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5611 cm_buf_t *bp = buf_Find(dscp, &hzero);
5616 code = CM_ERROR_NOSUCHFILE;
5618 cm_ReleaseSCache(dscp);
5620 cm_ReleaseUser(userp);
5625 #endif /* SPECIAL_FOLDERS */
5627 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5628 tidPathp, &req, &newScp);
5630 cm_ReleaseUser(userp);
5635 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5636 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5637 cm_ReleaseSCache(newScp);
5638 cm_ReleaseUser(userp);
5639 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5640 return CM_ERROR_PATH_NOT_COVERED;
5642 return CM_ERROR_NOSUCHPATH;
5644 #endif /* DFS_SUPPORT */
5646 /* now lock the vnode with a callback; returns with newScp locked */
5647 lock_ObtainWrite(&newScp->rw);
5648 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5649 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5651 lock_ReleaseWrite(&newScp->rw);
5652 cm_ReleaseSCache(newScp);
5653 cm_ReleaseUser(userp);
5657 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5659 attrs = smb_Attributes(newScp);
5661 smb_SetSMBParm(outp, 0, attrs);
5663 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5664 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5665 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5666 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5667 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5668 smb_SetSMBParm(outp, 5, 0);
5669 smb_SetSMBParm(outp, 6, 0);
5670 smb_SetSMBParm(outp, 7, 0);
5671 smb_SetSMBParm(outp, 8, 0);
5672 smb_SetSMBParm(outp, 9, 0);
5673 smb_SetSMBDataLength(outp, 0);
5674 lock_ReleaseWrite(&newScp->rw);
5676 cm_ReleaseSCache(newScp);
5677 cm_ReleaseUser(userp);
5682 /* SMB_COM_TREE_DISCONNECT */
5683 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5687 osi_Log0(smb_logp, "SMB receive tree disconnect");
5689 /* find the tree and free it */
5690 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5692 lock_ObtainWrite(&smb_rctLock);
5694 smb_ReleaseTID(tidp, TRUE);
5695 lock_ReleaseWrite(&smb_rctLock);
5702 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5705 clientchar_t *pathp;
5706 clientchar_t *lastNamep;
5715 clientchar_t *tidPathp;
5721 datap = smb_GetSMBData(inp, NULL);
5722 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5724 return CM_ERROR_BADSMB;
5726 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5728 #ifdef DEBUG_VERBOSE
5732 hexpath = osi_HexifyString( pathp );
5733 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5738 share = smb_GetSMBParm(inp, 0);
5739 attribute = smb_GetSMBParm(inp, 1);
5741 spacep = inp->spacep;
5742 /* smb_StripLastComponent will strip "::$DATA" if present */
5743 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5745 if (!cm_IsValidClientString(pathp)) {
5747 clientchar_t * hexp;
5749 hexp = cm_GetRawCharsAlloc(pathp, -1);
5750 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5751 osi_LogSaveClientString(smb_logp, hexp));
5755 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5757 return CM_ERROR_BADNTFILENAME;
5760 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5761 /* special case magic file name for receiving IOCTL requests
5762 * (since IOCTL calls themselves aren't getting through).
5764 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5765 smb_SetupIoctlFid(fidp, spacep);
5766 smb_SetSMBParm(outp, 0, fidp->fid);
5767 smb_SetSMBParm(outp, 1, 0); /* attrs */
5768 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5769 smb_SetSMBParm(outp, 3, 0);
5770 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5771 smb_SetSMBParm(outp, 5, 0x7fff);
5772 /* pass the open mode back */
5773 smb_SetSMBParm(outp, 6, (share & 0xf));
5774 smb_SetSMBDataLength(outp, 0);
5775 smb_ReleaseFID(fidp);
5779 userp = smb_GetUserFromVCP(vcp, inp);
5781 caseFold = CM_FLAG_CASEFOLD;
5783 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5785 cm_ReleaseUser(userp);
5786 return CM_ERROR_NOSUCHPATH;
5788 code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
5789 tidPathp, &req, &scp);
5792 cm_ReleaseUser(userp);
5797 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5798 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5799 cm_ReleaseSCache(scp);
5800 cm_ReleaseUser(userp);
5801 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5802 return CM_ERROR_PATH_NOT_COVERED;
5804 return CM_ERROR_NOSUCHPATH;
5806 #endif /* DFS_SUPPORT */
5808 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5810 cm_ReleaseSCache(scp);
5811 cm_ReleaseUser(userp);
5815 /* don't need callback to check file type, since file types never
5816 * change, and namei and cm_Lookup all stat the object at least once on
5817 * a successful return.
5819 if (scp->fileType != CM_SCACHETYPE_FILE) {
5820 cm_ReleaseSCache(scp);
5821 cm_ReleaseUser(userp);
5822 return CM_ERROR_ISDIR;
5825 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5826 osi_assertx(fidp, "null smb_fid_t");
5828 lock_ObtainMutex(&fidp->mx);
5829 if ((share & 0xf) == 0)
5830 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5831 else if ((share & 0xf) == 1)
5832 fidp->flags |= SMB_FID_OPENWRITE;
5834 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5838 fidp->userp = userp;
5840 /* and a pointer to the vnode */
5842 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5843 lock_ObtainWrite(&scp->rw);
5844 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5846 smb_SetSMBParm(outp, 0, fidp->fid);
5847 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5848 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5849 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5850 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5851 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5852 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5853 /* pass the open mode back; XXXX add access checks */
5854 smb_SetSMBParm(outp, 6, (share & 0xf));
5855 smb_SetSMBDataLength(outp, 0);
5856 lock_ReleaseMutex(&fidp->mx);
5857 lock_ReleaseRead(&scp->rw);
5860 cm_Open(scp, 0, userp);
5862 /* send and free packet */
5863 smb_ReleaseFID(fidp);
5864 cm_ReleaseUser(userp);
5865 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5869 typedef struct smb_unlinkRock {
5874 clientchar_t *maskp; /* pointer to the star pattern */
5877 cm_dirEntryList_t * matches;
5880 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5883 smb_unlinkRock_t *rockp;
5886 normchar_t matchName[MAX_PATH];
5890 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5891 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5892 caseFold |= CM_FLAG_8DOT3;
5894 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5895 /* Can't convert name */
5896 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5897 osi_LogSaveString(smb_logp, dep->name));
5901 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5903 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5904 !cm_Is8Dot3(matchName)) {
5905 cm_Gen8Dot3Name(dep, matchName, NULL);
5906 /* 8.3 matches are always case insensitive */
5907 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5910 osi_Log1(smb_logp, "Found match %S",
5911 osi_LogSaveClientString(smb_logp, matchName));
5913 cm_DirEntryListAdd(dep->name, &rockp->matches);
5917 /* If we made a case sensitive exact match, we might as well quit now. */
5918 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5919 code = CM_ERROR_STOPNOW;
5928 /* SMB_COM_DELETE */
5929 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5933 clientchar_t *pathp;
5937 clientchar_t *lastNamep;
5938 smb_unlinkRock_t rock;
5942 clientchar_t *tidPathp;
5946 memset(&rock, 0, sizeof(rock));
5948 attribute = smb_GetSMBParm(inp, 0);
5950 tp = smb_GetSMBData(inp, NULL);
5951 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5953 return CM_ERROR_BADSMB;
5955 osi_Log1(smb_logp, "SMB receive unlink %S",
5956 osi_LogSaveClientString(smb_logp, pathp));
5958 spacep = inp->spacep;
5959 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5961 userp = smb_GetUserFromVCP(vcp, inp);
5963 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5965 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5967 cm_ReleaseUser(userp);
5968 return CM_ERROR_NOSUCHPATH;
5970 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
5973 cm_ReleaseUser(userp);
5978 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5979 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5980 cm_ReleaseSCache(dscp);
5981 cm_ReleaseUser(userp);
5982 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5983 return CM_ERROR_PATH_NOT_COVERED;
5985 return CM_ERROR_NOSUCHPATH;
5987 #endif /* DFS_SUPPORT */
5989 /* otherwise, scp points to the parent directory. */
5996 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5998 code = CM_ERROR_NOSUCHFILE;
6001 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6004 thyper.HighPart = 0;
6009 rock.matches = NULL;
6011 /* Now, if we aren't dealing with a wildcard match, we first try an exact
6012 * match. If that fails, we do a case insensitve match.
6014 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6015 !smb_IsStarMask(rock.maskp)) {
6016 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6019 thyper.HighPart = 0;
6020 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6025 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6027 if (code == CM_ERROR_STOPNOW)
6030 if (code == 0 && rock.matches) {
6031 cm_dirEntryList_t * entry;
6033 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6034 normchar_t normalizedName[MAX_PATH];
6036 /* Note: entry->name is a non-normalized name */
6038 osi_Log1(smb_logp, "Unlinking %s",
6039 osi_LogSaveString(smb_logp, entry->name));
6041 /* We assume this works because entry->name was
6042 successfully converted in smb_UnlinkProc() once. */
6043 cm_FsStringToNormString(entry->name, -1,
6044 normalizedName, lengthof(normalizedName));
6046 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6048 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6049 smb_NotifyChange(FILE_ACTION_REMOVED,
6050 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6051 dscp, normalizedName, NULL, TRUE);
6055 cm_DirEntryListFree(&rock.matches);
6059 cm_ReleaseUser(userp);
6062 cm_ReleaseSCache(dscp);
6067 if (code == 0 && !rock.any)
6068 code = CM_ERROR_NOSUCHFILE;
6072 typedef struct smb_renameRock {
6073 cm_scache_t *odscp; /* old dir */
6074 cm_scache_t *ndscp; /* new dir */
6075 cm_user_t *userp; /* user */
6076 cm_req_t *reqp; /* request struct */
6077 smb_vc_t *vcp; /* virtual circuit */
6078 normchar_t *maskp; /* pointer to star pattern of old file name */
6079 int flags; /* tilde, casefold, etc */
6080 clientchar_t *newNamep; /* ptr to the new file's name */
6081 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6082 clientchar_t clOldName[MAX_PATH]; /* client name */
6086 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6089 smb_renameRock_t *rockp;
6092 normchar_t matchName[MAX_PATH];
6094 rockp = (smb_renameRock_t *) vrockp;
6096 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6097 /* Can't convert string */
6098 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6099 osi_LogSaveString(smb_logp, dep->name));
6103 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6104 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6105 caseFold |= CM_FLAG_8DOT3;
6107 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6109 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6110 !cm_Is8Dot3(matchName)) {
6111 cm_Gen8Dot3Name(dep, matchName, NULL);
6112 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6117 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6118 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6120 code = CM_ERROR_STOPNOW;
6130 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6133 cm_space_t *spacep = NULL;
6134 smb_renameRock_t rock;
6135 cm_scache_t *oldDscp = NULL;
6136 cm_scache_t *newDscp = NULL;
6137 cm_scache_t *tmpscp= NULL;
6138 cm_scache_t *tmpscp2 = NULL;
6139 clientchar_t *oldLastNamep;
6140 clientchar_t *newLastNamep;
6144 clientchar_t *tidPathp;
6148 userp = smb_GetUserFromVCP(vcp, inp);
6149 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6151 cm_ReleaseUser(userp);
6152 return CM_ERROR_NOSUCHPATH;
6156 memset(&rock, 0, sizeof(rock));
6158 spacep = inp->spacep;
6159 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6161 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6162 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6163 userp, tidPathp, &req, &oldDscp);
6165 cm_ReleaseUser(userp);
6170 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6171 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6172 cm_ReleaseSCache(oldDscp);
6173 cm_ReleaseUser(userp);
6174 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6175 return CM_ERROR_PATH_NOT_COVERED;
6177 return CM_ERROR_NOSUCHPATH;
6179 #endif /* DFS_SUPPORT */
6181 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6182 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6183 userp, tidPathp, &req, &newDscp);
6186 cm_ReleaseSCache(oldDscp);
6187 cm_ReleaseUser(userp);
6192 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6193 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6194 cm_ReleaseSCache(oldDscp);
6195 cm_ReleaseSCache(newDscp);
6196 cm_ReleaseUser(userp);
6197 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6198 return CM_ERROR_PATH_NOT_COVERED;
6200 return CM_ERROR_NOSUCHPATH;
6202 #endif /* DFS_SUPPORT */
6205 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6206 * next, get the component names, and lower case them.
6209 /* handle the old name first */
6211 oldLastNamep = oldPathp;
6215 /* and handle the new name, too */
6217 newLastNamep = newPathp;
6221 /* TODO: The old name could be a wildcard. The new name must not be */
6223 /* Check if the file already exists; if so return error */
6224 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6225 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6226 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6228 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6229 osi_LogSaveClientString(smb_logp, newLastNamep));
6231 /* Check if the old and the new names differ only in case. If so return
6232 * success, else return CM_ERROR_EXISTS
6234 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6236 /* This would be a success only if the old file is *as same as* the new file */
6237 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6239 if (tmpscp == tmpscp2)
6242 code = CM_ERROR_EXISTS;
6243 cm_ReleaseSCache(tmpscp2);
6246 code = CM_ERROR_NOSUCHFILE;
6249 /* file exist, do not rename, also fixes move */
6250 osi_Log0(smb_logp, "Can't rename. Target already exists");
6251 code = CM_ERROR_EXISTS;
6256 /* do the vnode call */
6257 rock.odscp = oldDscp;
6258 rock.ndscp = newDscp;
6262 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6264 code = CM_ERROR_NOSUCHFILE;
6267 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6268 rock.newNamep = newLastNamep;
6269 rock.fsOldName[0] = '\0';
6270 rock.clOldName[0] = '\0';
6273 /* Now search the directory for the pattern, and do the appropriate rename when found */
6274 thyper.LowPart = 0; /* search dir from here */
6275 thyper.HighPart = 0;
6277 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6278 if (code == 0 && !rock.any) {
6280 thyper.HighPart = 0;
6281 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6282 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6284 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6286 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6287 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6288 rock.ndscp, rock.newNamep, rock.userp,
6290 /* if the call worked, stop doing the search now, since we
6291 * really only want to rename one file.
6294 osi_Log0(smb_logp, "cm_Rename failure");
6295 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6296 } else if (code == 0) {
6297 code = CM_ERROR_NOSUCHFILE;
6300 /* Handle Change Notification */
6302 * Being lazy, not distinguishing between files and dirs in this
6303 * filter, since we'd have to do a lookup.
6306 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6307 if (oldDscp == newDscp) {
6308 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6309 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6310 filter, oldDscp, rock.clOldName,
6311 newLastNamep, TRUE);
6313 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6314 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6315 filter, oldDscp, rock.clOldName,
6317 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6318 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6319 filter, newDscp, newLastNamep,
6326 cm_ReleaseSCache(tmpscp);
6328 cm_ReleaseUser(userp);
6330 cm_ReleaseSCache(oldDscp);
6332 cm_ReleaseSCache(newDscp);
6340 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6343 cm_space_t *spacep = NULL;
6344 cm_scache_t *oldDscp = NULL;
6345 cm_scache_t *newDscp = NULL;
6346 cm_scache_t *tmpscp= NULL;
6347 cm_scache_t *tmpscp2 = NULL;
6348 cm_scache_t *sscp = NULL;
6349 clientchar_t *oldLastNamep;
6350 clientchar_t *newLastNamep;
6353 clientchar_t *tidPathp;
6357 userp = smb_GetUserFromVCP(vcp, inp);
6359 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6361 cm_ReleaseUser(userp);
6362 return CM_ERROR_NOSUCHPATH;
6367 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6369 spacep = inp->spacep;
6370 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6372 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6373 userp, tidPathp, &req, &oldDscp);
6375 cm_ReleaseUser(userp);
6380 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6381 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6382 cm_ReleaseSCache(oldDscp);
6383 cm_ReleaseUser(userp);
6384 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6385 return CM_ERROR_PATH_NOT_COVERED;
6387 return CM_ERROR_NOSUCHPATH;
6389 #endif /* DFS_SUPPORT */
6391 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6392 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6393 userp, tidPathp, &req, &newDscp);
6395 cm_ReleaseSCache(oldDscp);
6396 cm_ReleaseUser(userp);
6401 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6402 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6403 cm_ReleaseSCache(newDscp);
6404 cm_ReleaseSCache(oldDscp);
6405 cm_ReleaseUser(userp);
6406 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6407 return CM_ERROR_PATH_NOT_COVERED;
6409 return CM_ERROR_NOSUCHPATH;
6411 #endif /* DFS_SUPPORT */
6413 /* Now, although we did two lookups for the two directories (because the same
6414 * directory can be referenced through different paths), we only allow hard links
6415 * within the same directory. */
6416 if (oldDscp != newDscp) {
6417 cm_ReleaseSCache(oldDscp);
6418 cm_ReleaseSCache(newDscp);
6419 cm_ReleaseUser(userp);
6420 return CM_ERROR_CROSSDEVLINK;
6423 /* handle the old name first */
6425 oldLastNamep = oldPathp;
6429 /* and handle the new name, too */
6431 newLastNamep = newPathp;
6435 /* now lookup the old name */
6436 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6437 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6439 cm_ReleaseSCache(oldDscp);
6440 cm_ReleaseSCache(newDscp);
6441 cm_ReleaseUser(userp);
6445 /* Check if the file already exists; if so return error */
6446 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6447 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6448 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6450 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6451 osi_LogSaveClientString(smb_logp, newLastNamep));
6453 /* if the existing link is to the same file, then we return success */
6455 if(sscp == tmpscp) {
6458 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6459 code = CM_ERROR_EXISTS;
6464 cm_ReleaseSCache(tmpscp);
6465 cm_ReleaseSCache(sscp);
6466 cm_ReleaseSCache(newDscp);
6467 cm_ReleaseSCache(oldDscp);
6468 cm_ReleaseUser(userp);
6472 /* now create the hardlink */
6473 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6474 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6475 osi_Log1(smb_logp," Link returns 0x%x", code);
6477 /* Handle Change Notification */
6479 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6480 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6481 smb_NotifyChange(FILE_ACTION_ADDED,
6482 filter, newDscp, newLastNamep,
6487 cm_ReleaseSCache(tmpscp);
6488 cm_ReleaseUser(userp);
6489 cm_ReleaseSCache(sscp);
6490 cm_ReleaseSCache(oldDscp);
6491 cm_ReleaseSCache(newDscp);
6495 /* SMB_COM_RENAME */
6497 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6499 clientchar_t *oldPathp;
6500 clientchar_t *newPathp;
6504 tp = smb_GetSMBData(inp, NULL);
6505 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6507 return CM_ERROR_BADSMB;
6508 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6510 return CM_ERROR_BADSMB;
6512 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6513 osi_LogSaveClientString(smb_logp, oldPathp),
6514 osi_LogSaveClientString(smb_logp, newPathp));
6516 if (!cm_IsValidClientString(newPathp)) {
6518 clientchar_t * hexp;
6520 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6521 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6522 osi_LogSaveClientString(smb_logp, hexp));
6526 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6528 return CM_ERROR_BADNTFILENAME;
6531 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6533 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6539 typedef struct smb_rmdirRock {
6543 normchar_t *maskp; /* pointer to the star pattern */
6546 cm_dirEntryList_t * matches;
6549 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6552 smb_rmdirRock_t *rockp;
6554 normchar_t matchName[MAX_PATH];
6556 rockp = (smb_rmdirRock_t *) vrockp;
6558 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6559 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6560 osi_LogSaveString(smb_logp, dep->name));
6564 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6565 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6567 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6569 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6570 !cm_Is8Dot3(matchName)) {
6571 cm_Gen8Dot3Name(dep, matchName, NULL);
6572 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6577 cm_DirEntryListAdd(dep->name, &rockp->matches);
6584 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6587 clientchar_t *pathp;
6591 clientchar_t *lastNamep;
6592 smb_rmdirRock_t rock;
6596 clientchar_t *tidPathp;
6600 memset(&rock, 0, sizeof(rock));
6602 tp = smb_GetSMBData(inp, NULL);
6603 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6605 return CM_ERROR_BADSMB;
6607 spacep = inp->spacep;
6608 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6610 userp = smb_GetUserFromVCP(vcp, inp);
6612 caseFold = CM_FLAG_CASEFOLD;
6614 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6616 cm_ReleaseUser(userp);
6617 return CM_ERROR_NOSUCHPATH;
6619 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6620 userp, tidPathp, &req, &dscp);
6623 cm_ReleaseUser(userp);
6628 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6629 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6630 cm_ReleaseSCache(dscp);
6631 cm_ReleaseUser(userp);
6632 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6633 return CM_ERROR_PATH_NOT_COVERED;
6635 return CM_ERROR_NOSUCHPATH;
6637 #endif /* DFS_SUPPORT */
6639 /* otherwise, scp points to the parent directory. */
6646 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6648 code = CM_ERROR_NOSUCHFILE;
6651 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6654 thyper.HighPart = 0;
6658 rock.matches = NULL;
6660 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6661 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6662 if (code == 0 && !rock.any) {
6664 thyper.HighPart = 0;
6665 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6666 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6669 if (code == 0 && rock.matches) {
6670 cm_dirEntryList_t * entry;
6672 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6673 clientchar_t clientName[MAX_PATH];
6675 /* We assume this will succeed because smb_RmdirProc()
6676 successfully converted entry->name once above. */
6677 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6679 osi_Log1(smb_logp, "Removing directory %s",
6680 osi_LogSaveString(smb_logp, entry->name));
6682 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6684 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6685 smb_NotifyChange(FILE_ACTION_REMOVED,
6686 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6687 dscp, clientName, NULL, TRUE);
6693 cm_DirEntryListFree(&rock.matches);
6696 cm_ReleaseUser(userp);
6699 cm_ReleaseSCache(dscp);
6701 if (code == 0 && !rock.any)
6702 code = CM_ERROR_NOSUCHFILE;
6711 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6721 fid = smb_GetSMBParm(inp, 0);
6723 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6725 fid = smb_ChainFID(fid, inp);
6726 fidp = smb_FindFID(vcp, fid, 0);
6728 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6730 return CM_ERROR_BADFD;
6732 userp = smb_GetUserFromVCP(vcp, inp);
6734 lock_ObtainMutex(&fidp->mx);
6735 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6736 cm_ReleaseUser(userp);
6737 lock_ReleaseMutex(&fidp->mx);
6738 smb_ReleaseFID(fidp);
6739 return CM_ERROR_BADFD;
6742 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6743 lock_ReleaseMutex(&fidp->mx);
6744 cm_ReleaseUser(userp);
6745 smb_CloseFID(vcp, fidp, NULL, 0);
6746 smb_ReleaseFID(fidp);
6747 return CM_ERROR_NOSUCHFILE;
6750 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6751 cm_scache_t * scp = fidp->scp;
6753 lock_ReleaseMutex(&fidp->mx);
6754 code = cm_FSync(scp, userp, &req, FALSE);
6755 cm_ReleaseSCache(scp);
6757 lock_ReleaseMutex(&fidp->mx);
6761 cm_ReleaseUser(userp);
6762 smb_ReleaseFID(fidp);
6766 struct smb_FullNameRock {
6769 clientchar_t *fullName;
6770 fschar_t *originalName;
6773 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6776 normchar_t matchName[MAX_PATH];
6777 struct smb_FullNameRock *vrockp;
6779 vrockp = (struct smb_FullNameRock *)rockp;
6781 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6782 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6783 osi_LogSaveString(smb_logp, dep->name));
6787 if (!cm_Is8Dot3(matchName)) {
6788 clientchar_t shortName[13];
6790 cm_Gen8Dot3Name(dep, shortName, NULL);
6792 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6793 vrockp->fullName = cm_ClientStrDup(matchName);
6794 vrockp->originalName = cm_FsStrDup(dep->name);
6795 return CM_ERROR_STOPNOW;
6798 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6799 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6800 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6801 vrockp->fullName = cm_ClientStrDup(matchName);
6802 vrockp->originalName = cm_FsStrDup(dep->name);
6803 return CM_ERROR_STOPNOW;
6808 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6809 clientchar_t **newPathp, fschar_t ** originalPathp,
6810 cm_user_t *userp, cm_req_t *reqp)
6812 struct smb_FullNameRock rock;
6815 memset(&rock, 0, sizeof(rock));
6819 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6820 if (code == CM_ERROR_STOPNOW) {
6821 *newPathp = rock.fullName;
6822 *originalPathp = rock.originalName;
6824 *newPathp = cm_ClientStrDup(pathp);
6825 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6829 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6830 afs_uint32 dosTime) {
6833 cm_scache_t *dscp = NULL;
6834 clientchar_t *pathp = NULL;
6835 cm_scache_t * scp = NULL;
6836 cm_scache_t *delscp = NULL;
6837 int nullcreator = 0;
6839 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6840 fidp, fidp->fid, scp, vcp);
6843 lock_ObtainMutex(&fidp->mx);
6844 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6846 lock_ReleaseMutex(&fidp->mx);
6847 osi_Log0(smb_logp, " No user specified. Not closing fid");
6848 return CM_ERROR_BADFD;
6851 userp = fidp->userp; /* no hold required since fidp is held
6852 throughout the function */
6853 lock_ReleaseMutex(&fidp->mx);
6858 lock_ObtainWrite(&smb_rctLock);
6859 if (fidp->deleteOk) {
6860 osi_Log0(smb_logp, " Fid already closed.");
6861 lock_ReleaseWrite(&smb_rctLock);
6862 return CM_ERROR_BADFD;
6865 lock_ReleaseWrite(&smb_rctLock);
6867 lock_ObtainMutex(&fidp->mx);
6868 if (fidp->NTopen_dscp) {
6869 dscp = fidp->NTopen_dscp;
6870 cm_HoldSCache(dscp);
6873 if (fidp->NTopen_pathp)
6874 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6881 /* Don't jump the gun on an async raw write */
6882 while (fidp->raw_writers) {
6883 lock_ReleaseMutex(&fidp->mx);
6884 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6885 lock_ObtainMutex(&fidp->mx);
6888 /* watch for ioctl closes, and read-only opens */
6890 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6891 == SMB_FID_OPENWRITE) {
6892 if (dosTime != 0 && dosTime != -1) {
6893 lock_ObtainWrite(&fidp->scp->rw);
6894 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6895 /* This fixes defect 10958 */
6896 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6897 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6898 lock_ReleaseWrite(&fidp->scp->rw);
6900 if (smb_AsyncStore != 2) {
6901 lock_ReleaseMutex(&fidp->mx);
6902 code = cm_FSync(scp, userp, &req, FALSE);
6903 lock_ObtainMutex(&fidp->mx);
6909 /* unlock any pending locks */
6910 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6911 scp->fileType == CM_SCACHETYPE_FILE) {
6915 lock_ReleaseMutex(&fidp->mx);
6917 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6919 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6920 lock_ObtainWrite(&scp->rw);
6922 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6923 CM_SCACHESYNC_NEEDCALLBACK
6924 | CM_SCACHESYNC_GETSTATUS
6925 | CM_SCACHESYNC_LOCK);
6929 "smb CoreClose SyncOp failure code 0x%x", tcode);
6930 goto post_syncopdone;
6933 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6935 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6939 lock_ReleaseWrite(&scp->rw);
6940 lock_ObtainMutex(&fidp->mx);
6943 if (fidp->flags & SMB_FID_DELONCLOSE) {
6944 clientchar_t *fullPathp = NULL;
6945 fschar_t *originalNamep = NULL;
6947 lock_ReleaseMutex(&fidp->mx);
6949 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6954 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6955 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6956 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6958 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6959 smb_NotifyChange(FILE_ACTION_REMOVED,
6960 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6961 dscp, fullPathp, NULL, TRUE);
6964 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6966 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6967 smb_NotifyChange(FILE_ACTION_REMOVED,
6968 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6969 dscp, fullPathp, NULL, TRUE);
6976 free(originalNamep);
6978 lock_ObtainMutex(&fidp->mx);
6979 fidp->flags &= ~SMB_FID_DELONCLOSE;
6982 /* if this was a newly created file, then clear the creator
6983 * in the stat cache entry. */
6984 if (fidp->flags & SMB_FID_CREATED) {
6986 fidp->flags &= ~SMB_FID_CREATED;
6989 if (fidp->flags & SMB_FID_NTOPEN) {
6990 cm_ReleaseSCache(fidp->NTopen_dscp);
6991 fidp->NTopen_dscp = NULL;
6992 free(fidp->NTopen_pathp);
6993 fidp->NTopen_pathp = NULL;
6994 fidp->flags &= ~SMB_FID_NTOPEN;
6996 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6997 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7000 if (fidp->NTopen_wholepathp) {
7001 free(fidp->NTopen_wholepathp);
7002 fidp->NTopen_wholepathp = NULL;
7006 cm_ReleaseSCache(fidp->scp);
7009 lock_ReleaseMutex(&fidp->mx);
7012 cm_ReleaseSCache(dscp);
7015 cm_ReleaseSCache(delscp);
7019 lock_ObtainWrite(&scp->rw);
7020 if (nullcreator && scp->creator == userp)
7021 scp->creator = NULL;
7022 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7023 lock_ReleaseWrite(&scp->rw);
7024 cm_ReleaseSCache(scp);
7034 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7042 fid = smb_GetSMBParm(inp, 0);
7043 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7045 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7047 fid = smb_ChainFID(fid, inp);
7048 fidp = smb_FindFID(vcp, fid, 0);
7050 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
7052 return CM_ERROR_BADFD;
7055 userp = smb_GetUserFromVCP(vcp, inp);
7057 code = smb_CloseFID(vcp, fidp, userp, dosTime);
7059 smb_ReleaseFID(fidp);
7060 cm_ReleaseUser(userp);
7065 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7067 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7068 cm_user_t *userp, long *readp)
7074 osi_hyper_t fileLength;
7076 osi_hyper_t lastByte;
7077 osi_hyper_t bufferOffset;
7081 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7084 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7085 fidp->fid, offsetp->LowPart, count);
7089 lock_ObtainMutex(&fidp->mx);
7090 /* make sure we have a readable FD */
7091 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7092 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7093 fidp->fid, fidp->flags);
7094 lock_ReleaseMutex(&fidp->mx);
7095 code = CM_ERROR_BADFDOP;
7100 lock_ReleaseMutex(&fidp->mx);
7101 code = CM_ERROR_BADFD;
7112 lock_ObtainWrite(&scp->rw);
7114 if (offset.HighPart == 0) {
7115 chunk = offset.LowPart >> cm_logChunkSize;
7116 if (chunk != fidp->curr_chunk) {
7117 fidp->prev_chunk = fidp->curr_chunk;
7118 fidp->curr_chunk = chunk;
7120 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7123 lock_ReleaseMutex(&fidp->mx);
7125 /* start by looking up the file's end */
7126 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7127 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7131 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7133 /* now we have the entry locked, look up the length */
7134 fileLength = scp->length;
7136 /* adjust count down so that it won't go past EOF */
7137 thyper.LowPart = count;
7138 thyper.HighPart = 0;
7139 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7141 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7142 /* we'd read past EOF, so just stop at fileLength bytes.
7143 * Start by computing how many bytes remain in the file.
7145 thyper = LargeIntegerSubtract(fileLength, offset);
7147 /* if we are past EOF, read 0 bytes */
7148 if (LargeIntegerLessThanZero(thyper))
7151 count = thyper.LowPart;
7156 /* now, copy the data one buffer at a time,
7157 * until we've filled the request packet
7160 /* if we've copied all the data requested, we're done */
7161 if (count <= 0) break;
7163 /* otherwise, load up a buffer of data */
7164 thyper.HighPart = offset.HighPart;
7165 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7166 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7169 buf_Release(bufferp);
7172 lock_ReleaseWrite(&scp->rw);
7174 code = buf_Get(scp, &thyper, &req, &bufferp);
7176 lock_ObtainWrite(&scp->rw);
7177 if (code) goto done;
7178 bufferOffset = thyper;
7180 /* now get the data in the cache */
7182 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7183 CM_SCACHESYNC_NEEDCALLBACK |
7184 CM_SCACHESYNC_READ);
7188 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7190 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7192 /* otherwise, load the buffer and try again */
7193 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7197 buf_Release(bufferp);
7201 } /* if (wrong buffer) ... */
7203 /* now we have the right buffer loaded. Copy out the
7204 * data from here to the user's buffer.
7206 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7208 /* and figure out how many bytes we want from this buffer */
7209 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7210 if (nbytes > count) nbytes = count; /* don't go past EOF */
7212 /* now copy the data */
7213 memcpy(op, bufferp->datap + bufIndex, nbytes);
7215 /* adjust counters, pointers, etc. */
7218 thyper.LowPart = nbytes;
7219 thyper.HighPart = 0;
7220 offset = LargeIntegerAdd(thyper, offset);
7224 lock_ReleaseWrite(&scp->rw);
7226 buf_Release(bufferp);
7228 if (code == 0 && sequential)
7229 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7231 cm_ReleaseSCache(scp);
7234 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7235 fidp->fid, code, *readp);
7240 * smb_WriteData -- common code for Write and Raw Write
7242 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7243 cm_user_t *userp, long *writtenp)
7245 osi_hyper_t offset = *offsetp;
7248 cm_scache_t *scp = NULL;
7249 osi_hyper_t fileLength; /* file's length at start of write */
7250 osi_hyper_t minLength; /* don't read past this */
7251 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7252 cm_buf_t *bufferp = NULL;
7253 osi_hyper_t thyper; /* hyper tmp variable */
7254 osi_hyper_t bufferOffset;
7255 afs_uint32 bufIndex; /* index in buffer where our data is */
7256 int doWriteBack = 0;
7257 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7260 int needSyncOpDone = 0;
7262 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7263 fidp->fid, offsetp->LowPart, count);
7267 lock_ObtainMutex(&fidp->mx);
7268 /* make sure we have a writable FD */
7269 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7270 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7271 fidp->fid, fidp->flags);
7272 lock_ReleaseMutex(&fidp->mx);
7273 code = CM_ERROR_BADFDOP;
7281 lock_ReleaseMutex(&fidp->mx);
7283 lock_ObtainWrite(&scp->rw);
7284 /* start by looking up the file's end */
7285 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7286 CM_SCACHESYNC_NEEDCALLBACK
7287 | CM_SCACHESYNC_SETSTATUS
7288 | CM_SCACHESYNC_GETSTATUS);
7292 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7294 /* now we have the entry locked, look up the length */
7295 fileLength = scp->length;
7296 minLength = fileLength;
7297 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7298 minLength = scp->serverLength;
7300 /* adjust file length if we extend past EOF */
7301 thyper.LowPart = count;
7302 thyper.HighPart = 0;
7303 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7304 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7305 /* we'd write past EOF, so extend the file */
7306 scp->mask |= CM_SCACHEMASK_LENGTH;
7307 scp->length = thyper;
7308 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7310 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7312 /* now, if the new position (thyper) and the old (offset) are in
7313 * different storeback windows, remember to store back the previous
7314 * storeback window when we're done with the write.
7316 * the purpose of this logic is to slow down the CIFS client
7317 * in order to avoid the client disconnecting during the CLOSE
7318 * operation if there are too many dirty buffers left to write
7319 * than can be accomplished during 45 seconds. This used to be
7320 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7321 * so that we can read larger amounts of data at a time.
7323 if (smb_AsyncStore == 1 &&
7324 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7325 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7326 /* they're different */
7328 writeBackOffset.HighPart = offset.HighPart;
7329 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7334 /* now, copy the data one buffer at a time, until we've filled the
7336 while (count != 0) {
7338 /* handle over quota or out of space */
7339 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7340 *writtenp = written;
7341 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7345 /* otherwise, load up a buffer of data */
7346 thyper.HighPart = offset.HighPart;
7347 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7348 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7351 if (needSyncOpDone) {
7352 cm_SyncOpDone(scp, bufferp,
7353 CM_SCACHESYNC_NEEDCALLBACK
7354 | CM_SCACHESYNC_WRITE
7355 | CM_SCACHESYNC_BUFLOCKED);
7358 lock_ReleaseMutex(&bufferp->mx);
7359 buf_Release(bufferp);
7362 lock_ReleaseWrite(&scp->rw);
7364 code = buf_Get(scp, &thyper, &req, &bufferp);
7366 lock_ObtainMutex(&bufferp->mx);
7367 lock_ObtainWrite(&scp->rw);
7368 if (code) goto done;
7370 bufferOffset = thyper;
7372 /* now get the data in the cache */
7374 if (!needSyncOpDone) {
7375 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7376 CM_SCACHESYNC_NEEDCALLBACK
7377 | CM_SCACHESYNC_WRITE
7378 | CM_SCACHESYNC_BUFLOCKED);
7385 /* If we're overwriting the entire buffer, or
7386 * if we're writing at or past EOF, mark the
7387 * buffer as current so we don't call
7388 * cm_GetBuffer. This skips the fetch from the
7389 * server in those cases where we're going to
7390 * obliterate all the data in the buffer anyway,
7391 * or in those cases where there is no useful
7392 * data at the server to start with.
7394 * Use minLength instead of scp->length, since
7395 * the latter has already been updated by this
7398 * The scp lock has been dropped multiple times
7399 * so the minLength must be refreshed before it
7403 minLength = scp->length;
7404 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7405 minLength = scp->serverLength;
7407 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7408 || LargeIntegerEqualTo(offset, bufferp->offset)
7409 && (count >= cm_data.buf_blockSize
7410 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7411 ConvertLongToLargeInteger(count)),
7413 if (count < cm_data.buf_blockSize
7414 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7415 memset(bufferp->datap, 0,
7416 cm_data.buf_blockSize);
7417 bufferp->dataVersion = scp->dataVersion;
7420 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7422 /* otherwise, load the buffer and try again */
7423 cm_SyncOpDone(scp, bufferp,
7424 CM_SCACHESYNC_NEEDCALLBACK
7425 | CM_SCACHESYNC_WRITE
7426 | CM_SCACHESYNC_BUFLOCKED);
7429 lock_ReleaseMutex(&bufferp->mx);
7430 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7432 lock_ReleaseWrite(&scp->rw);
7433 lock_ObtainMutex(&bufferp->mx);
7434 lock_ObtainWrite(&scp->rw);
7438 } /* if (wrong buffer) ... */
7440 /* now we have the right buffer loaded. Copy out the
7441 * data from here to the user's buffer.
7443 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7445 /* and figure out how many bytes we want from this buffer */
7446 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7448 nbytes = count; /* don't go past end of request */
7450 /* now copy the data */
7451 memcpy(bufferp->datap + bufIndex, op, nbytes);
7452 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7454 /* adjust counters, pointers, etc. */
7458 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7459 } /* while count != 0 */
7462 if (bufferp && needSyncOpDone) {
7463 cm_SyncOpDone(scp, bufferp,
7464 CM_SCACHESYNC_NEEDCALLBACK
7465 | CM_SCACHESYNC_WRITE
7466 | CM_SCACHESYNC_BUFLOCKED);
7469 lock_ReleaseWrite(&scp->rw);
7472 lock_ReleaseMutex(&bufferp->mx);
7473 buf_Release(bufferp);
7476 lock_ObtainMutex(&fidp->mx);
7477 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7478 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7480 lock_ReleaseMutex(&fidp->mx);
7481 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7482 fidp->NTopen_dscp, fidp->NTopen_pathp,
7485 lock_ReleaseMutex(&fidp->mx);
7489 if (smb_AsyncStore > 0) {
7493 lock_ObtainWrite(&scp->rw);
7494 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7496 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7497 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7499 lock_ReleaseWrite(&scp->rw);
7500 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7501 writeBackOffset.HighPart,
7502 smb_AsyncStoreSize, 0, userp);
7503 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7506 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7510 cm_ReleaseSCache(scp);
7513 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7514 fidp->fid, code, *writtenp);
7519 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7522 unsigned short count;
7524 unsigned short hint;
7525 long written = 0, total_written = 0;
7528 smb_t* smbp = (smb_t*) inp;
7532 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7534 int inDataBlockCount;
7536 fd = smb_GetSMBParm(inp, 0);
7537 count = smb_GetSMBParm(inp, 1);
7538 offset.HighPart = 0; /* too bad */
7539 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7540 hint = smb_GetSMBParm(inp, 4);
7542 op = smb_GetSMBData(inp, NULL);
7543 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7545 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7546 fd, offset.LowPart, count);
7548 fd = smb_ChainFID(fd, inp);
7549 fidp = smb_FindFID(vcp, fd, 0);
7551 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7553 return CM_ERROR_BADFD;
7556 lock_ObtainMutex(&fidp->mx);
7557 if (fidp->flags & SMB_FID_IOCTL) {
7558 lock_ReleaseMutex(&fidp->mx);
7559 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7560 smb_ReleaseFID(fidp);
7561 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7565 if (fidp->flags & SMB_FID_RPC) {
7566 lock_ReleaseMutex(&fidp->mx);
7567 code = smb_RPCWrite(fidp, vcp, inp, outp);
7568 smb_ReleaseFID(fidp);
7569 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7574 lock_ReleaseMutex(&fidp->mx);
7575 smb_ReleaseFID(fidp);
7576 return CM_ERROR_BADFD;
7579 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7580 lock_ReleaseMutex(&fidp->mx);
7581 smb_CloseFID(vcp, fidp, NULL, 0);
7582 smb_ReleaseFID(fidp);
7583 return CM_ERROR_NOSUCHFILE;
7588 lock_ReleaseMutex(&fidp->mx);
7589 userp = smb_GetUserFromVCP(vcp, inp);
7593 LARGE_INTEGER LOffset;
7594 LARGE_INTEGER LLength;
7597 key = cm_GenerateKey(vcp->vcID, pid, fd);
7599 LOffset.HighPart = offset.HighPart;
7600 LOffset.LowPart = offset.LowPart;
7601 LLength.HighPart = 0;
7602 LLength.LowPart = count;
7604 lock_ObtainWrite(&scp->rw);
7605 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7606 lock_ReleaseWrite(&scp->rw);
7609 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7614 /* special case: 0 bytes transferred means truncate to this position */
7618 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7622 truncAttr.mask = CM_ATTRMASK_LENGTH;
7623 truncAttr.length.LowPart = offset.LowPart;
7624 truncAttr.length.HighPart = 0;
7625 lock_ObtainMutex(&fidp->mx);
7626 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7627 fidp->flags |= SMB_FID_LENGTHSETDONE;
7628 lock_ReleaseMutex(&fidp->mx);
7629 smb_SetSMBParm(outp, 0, 0 /* count */);
7630 smb_SetSMBDataLength(outp, 0);
7635 * Work around bug in NT client
7637 * When copying a file, the NT client should first copy the data,
7638 * then copy the last write time. But sometimes the NT client does
7639 * these in the wrong order, so the data copies would inadvertently
7640 * cause the last write time to be overwritten. We try to detect this,
7641 * and don't set client mod time if we think that would go against the
7644 lock_ObtainMutex(&fidp->mx);
7645 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7646 lock_ObtainWrite(&fidp->scp->rw);
7647 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7648 fidp->scp->clientModTime = time(NULL);
7649 lock_ReleaseWrite(&fidp->scp->rw);
7651 lock_ReleaseMutex(&fidp->mx);
7654 while ( code == 0 && count > 0 ) {
7655 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7656 if (code == 0 && written == 0)
7657 code = CM_ERROR_PARTIALWRITE;
7659 offset = LargeIntegerAdd(offset,
7660 ConvertLongToLargeInteger(written));
7661 count -= (unsigned short)written;
7662 total_written += written;
7666 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7667 total_written, code);
7669 /* set the packet data length to 3 bytes for the data block header,
7670 * plus the size of the data.
7672 smb_SetSMBParm(outp, 0, total_written);
7673 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7674 smb_SetSMBParm(outp, 3, hint);
7675 smb_SetSMBDataLength(outp, 0);
7678 smb_ReleaseFID(fidp);
7679 cm_ReleaseUser(userp);
7680 cm_ReleaseSCache(scp);
7685 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7686 NCB *ncbp, raw_write_cont_t *rwcp)
7695 fd = smb_GetSMBParm(inp, 0);
7696 fidp = smb_FindFID(vcp, fd, 0);
7698 lock_ObtainMutex(&fidp->mx);
7700 lock_ReleaseMutex(&fidp->mx);
7701 smb_ReleaseFID(fidp);
7705 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7706 lock_ReleaseMutex(&fidp->mx);
7707 smb_CloseFID(vcp, fidp, NULL, 0);
7708 smb_ReleaseFID(fidp);
7711 lock_ReleaseMutex(&fidp->mx);
7713 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7714 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7716 userp = smb_GetUserFromVCP(vcp, inp);
7719 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7721 if (rwcp->writeMode & 0x1) { /* synchronous */
7724 smb_FormatResponsePacket(vcp, inp, outp);
7725 op = (smb_t *) outp;
7726 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7727 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7728 smb_SetSMBDataLength(outp, 0);
7729 smb_SendPacket(vcp, outp);
7730 smb_FreePacket(outp);
7732 else { /* asynchronous */
7733 lock_ObtainMutex(&fidp->mx);
7734 fidp->raw_writers--;
7735 if (fidp->raw_writers == 0)
7736 thrd_SetEvent(fidp->raw_write_event);
7737 lock_ReleaseMutex(&fidp->mx);
7740 /* Give back raw buffer */
7741 lock_ObtainMutex(&smb_RawBufLock);
7742 *((char **)rawBuf) = smb_RawBufs;
7743 smb_RawBufs = rawBuf;
7744 lock_ReleaseMutex(&smb_RawBufLock);
7746 smb_ReleaseFID(fidp);
7747 cm_ReleaseUser(userp);
7750 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7755 /* SMB_COM_WRITE_RAW */
7756 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7759 long count, written = 0, total_written = 0;
7763 smb_t *smbp = (smb_t*) inp;
7768 unsigned short writeMode;
7770 fd = smb_GetSMBParm(inp, 0);
7771 totalCount = smb_GetSMBParm(inp, 1);
7772 count = smb_GetSMBParm(inp, 10);
7773 writeMode = smb_GetSMBParm(inp, 7);
7775 op = (char *) inp->data;
7776 op += smb_GetSMBParm(inp, 11);
7778 offset.HighPart = 0;
7779 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7781 if (*inp->wctp == 14) {
7782 /* we received a 64-bit file offset */
7783 #ifdef AFS_LARGEFILES
7784 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7786 if (LargeIntegerLessThanZero(offset)) {
7788 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7789 offset.HighPart, offset.LowPart);
7790 return CM_ERROR_BADSMB;
7793 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7795 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7796 return CM_ERROR_BADSMB;
7799 offset.HighPart = 0;
7802 offset.HighPart = 0; /* 32-bit file offset */
7806 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7807 fd, offset.HighPart, offset.LowPart, count);
7809 " WriteRaw WriteMode 0x%x",
7812 fd = smb_ChainFID(fd, inp);
7813 fidp = smb_FindFID(vcp, fd, 0);
7815 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7817 return CM_ERROR_BADFD;
7819 lock_ObtainMutex(&fidp->mx);
7821 lock_ReleaseMutex(&fidp->mx);
7822 smb_ReleaseFID(fidp);
7823 return CM_ERROR_BADFD;
7826 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7827 lock_ReleaseMutex(&fidp->mx);
7828 smb_CloseFID(vcp, fidp, NULL, 0);
7829 smb_ReleaseFID(fidp);
7830 return CM_ERROR_NOSUCHFILE;
7835 lock_ReleaseMutex(&fidp->mx);
7840 LARGE_INTEGER LOffset;
7841 LARGE_INTEGER LLength;
7844 key = cm_GenerateKey(vcp->vcID, pid, fd);
7846 LOffset.HighPart = offset.HighPart;
7847 LOffset.LowPart = offset.LowPart;
7848 LLength.HighPart = 0;
7849 LLength.LowPart = count;
7851 lock_ObtainWrite(&scp->rw);
7852 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7853 lock_ReleaseWrite(&scp->rw);
7856 cm_ReleaseSCache(scp);
7857 smb_ReleaseFID(fidp);
7862 userp = smb_GetUserFromVCP(vcp, inp);
7865 * Work around bug in NT client
7867 * When copying a file, the NT client should first copy the data,
7868 * then copy the last write time. But sometimes the NT client does
7869 * these in the wrong order, so the data copies would inadvertently
7870 * cause the last write time to be overwritten. We try to detect this,
7871 * and don't set client mod time if we think that would go against the
7874 lock_ObtainMutex(&fidp->mx);
7875 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7876 lock_ObtainWrite(&fidp->scp->rw);
7877 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7878 fidp->scp->clientModTime = time(NULL);
7879 lock_ReleaseWrite(&fidp->scp->rw);
7881 lock_ReleaseMutex(&fidp->mx);
7884 while ( code == 0 && count > 0 ) {
7885 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7886 if (code == 0 && written == 0)
7887 code = CM_ERROR_PARTIALWRITE;
7889 offset = LargeIntegerAdd(offset,
7890 ConvertLongToLargeInteger(written));
7893 total_written += written;
7897 /* Get a raw buffer */
7900 lock_ObtainMutex(&smb_RawBufLock);
7902 /* Get a raw buf, from head of list */
7903 rawBuf = smb_RawBufs;
7904 smb_RawBufs = *(char **)smb_RawBufs;
7907 code = CM_ERROR_USESTD;
7909 lock_ReleaseMutex(&smb_RawBufLock);
7912 /* Don't allow a premature Close */
7913 if (code == 0 && (writeMode & 1) == 0) {
7914 lock_ObtainMutex(&fidp->mx);
7915 fidp->raw_writers++;
7916 thrd_ResetEvent(fidp->raw_write_event);
7917 lock_ReleaseMutex(&fidp->mx);
7920 smb_ReleaseFID(fidp);
7921 cm_ReleaseUser(userp);
7922 cm_ReleaseSCache(scp);
7925 smb_SetSMBParm(outp, 0, total_written);
7926 smb_SetSMBDataLength(outp, 0);
7927 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7932 offset = LargeIntegerAdd(offset,
7933 ConvertLongToLargeInteger(count));
7937 rwcp->offset.HighPart = offset.HighPart;
7938 rwcp->offset.LowPart = offset.LowPart;
7939 rwcp->count = totalCount - count;
7940 rwcp->writeMode = writeMode;
7941 rwcp->alreadyWritten = total_written;
7943 /* set the packet data length to 3 bytes for the data block header,
7944 * plus the size of the data.
7946 smb_SetSMBParm(outp, 0, 0xffff);
7947 smb_SetSMBDataLength(outp, 0);
7953 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7956 long count, finalCount;
7960 smb_t *smbp = (smb_t*) inp;
7966 fd = smb_GetSMBParm(inp, 0);
7967 count = smb_GetSMBParm(inp, 1);
7968 offset.HighPart = 0; /* too bad */
7969 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7971 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7972 fd, offset.LowPart, count);
7974 fd = smb_ChainFID(fd, inp);
7975 fidp = smb_FindFID(vcp, fd, 0);
7977 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7979 return CM_ERROR_BADFD;
7981 lock_ObtainMutex(&fidp->mx);
7982 if (fidp->flags & SMB_FID_IOCTL) {
7983 lock_ReleaseMutex(&fidp->mx);
7984 code = smb_IoctlRead(fidp, vcp, inp, outp);
7985 smb_ReleaseFID(fidp);
7989 if (fidp->flags & SMB_FID_RPC) {
7990 lock_ReleaseMutex(&fidp->mx);
7991 code = smb_RPCRead(fidp, vcp, inp, outp);
7992 smb_ReleaseFID(fidp);
7997 lock_ReleaseMutex(&fidp->mx);
7998 smb_ReleaseFID(fidp);
7999 return CM_ERROR_BADFD;
8002 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8003 lock_ReleaseMutex(&fidp->mx);
8004 smb_CloseFID(vcp, fidp, NULL, 0);
8005 smb_ReleaseFID(fidp);
8006 return CM_ERROR_NOSUCHFILE;
8011 lock_ReleaseMutex(&fidp->mx);
8014 LARGE_INTEGER LOffset, LLength;
8018 key = cm_GenerateKey(vcp->vcID, pid, fd);
8020 LOffset.HighPart = 0;
8021 LOffset.LowPart = offset.LowPart;
8022 LLength.HighPart = 0;
8023 LLength.LowPart = count;
8025 lock_ObtainWrite(&scp->rw);
8026 code = cm_LockCheckRead(scp, LOffset, LLength, key);
8027 lock_ReleaseWrite(&scp->rw);
8030 cm_ReleaseSCache(scp);
8031 smb_ReleaseFID(fidp);
8035 userp = smb_GetUserFromVCP(vcp, inp);
8037 /* remember this for final results */
8038 smb_SetSMBParm(outp, 0, count);
8039 smb_SetSMBParm(outp, 1, 0);
8040 smb_SetSMBParm(outp, 2, 0);
8041 smb_SetSMBParm(outp, 3, 0);
8042 smb_SetSMBParm(outp, 4, 0);
8044 /* set the packet data length to 3 bytes for the data block header,
8045 * plus the size of the data.
8047 smb_SetSMBDataLength(outp, count+3);
8049 /* get op ptr after putting in the parms, since otherwise we don't
8050 * know where the data really is.
8052 op = smb_GetSMBData(outp, NULL);
8054 /* now emit the data block header: 1 byte of type and 2 bytes of length */
8055 *op++ = 1; /* data block marker */
8056 *op++ = (unsigned char) (count & 0xff);
8057 *op++ = (unsigned char) ((count >> 8) & 0xff);
8059 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8061 /* fix some things up */
8062 smb_SetSMBParm(outp, 0, finalCount);
8063 smb_SetSMBDataLength(outp, finalCount+3);
8065 smb_ReleaseFID(fidp);
8067 cm_ReleaseUser(userp);
8068 cm_ReleaseSCache(scp);
8072 /* SMB_COM_CREATE_DIRECTORY */
8073 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8075 clientchar_t *pathp;
8080 cm_scache_t *dscp; /* dir we're dealing with */
8081 cm_scache_t *scp; /* file we're creating */
8083 int initialModeBits;
8084 clientchar_t *lastNamep;
8086 clientchar_t *tidPathp;
8093 /* compute initial mode bits based on read-only flag in attributes */
8094 initialModeBits = 0777;
8096 tp = smb_GetSMBData(inp, NULL);
8097 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8099 return CM_ERROR_BADSMB;
8101 spacep = inp->spacep;
8102 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8104 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8105 return CM_ERROR_EXISTS;
8107 userp = smb_GetUserFromVCP(vcp, inp);
8109 caseFold = CM_FLAG_CASEFOLD;
8111 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8113 cm_ReleaseUser(userp);
8114 return CM_ERROR_NOSUCHPATH;
8117 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
8118 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8119 userp, tidPathp, &req, &dscp);
8122 cm_ReleaseUser(userp);
8127 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8128 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8129 cm_ReleaseSCache(dscp);
8130 cm_ReleaseUser(userp);
8131 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8132 return CM_ERROR_PATH_NOT_COVERED;
8134 return CM_ERROR_NOSUCHPATH;
8136 #endif /* DFS_SUPPORT */
8138 /* otherwise, scp points to the parent directory. Do a lookup, and
8139 * fail if we find it. Otherwise, we do the create.
8145 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8146 if (scp) cm_ReleaseSCache(scp);
8147 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8148 if (code == 0) code = CM_ERROR_EXISTS;
8149 cm_ReleaseSCache(dscp);
8150 cm_ReleaseUser(userp);
8154 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8155 setAttr.clientModTime = time(NULL);
8156 smb_SetInitialModeBitsForDir(0, &setAttr);
8158 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8159 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8160 smb_NotifyChange(FILE_ACTION_ADDED,
8161 FILE_NOTIFY_CHANGE_DIR_NAME,
8162 dscp, lastNamep, NULL, TRUE);
8164 /* we don't need this any longer */
8165 cm_ReleaseSCache(dscp);
8168 /* something went wrong creating or truncating the file */
8169 cm_ReleaseUser(userp);
8173 /* otherwise we succeeded */
8174 smb_SetSMBDataLength(outp, 0);
8175 cm_ReleaseUser(userp);
8180 BOOL smb_IsLegalFilename(clientchar_t *filename)
8183 * Find the longest substring of filename that does not contain
8184 * any of the chars in illegalChars. If that substring is less
8185 * than the length of the whole string, then one or more of the
8186 * illegal chars is in filename.
8188 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8194 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8195 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8197 clientchar_t *pathp;
8203 cm_scache_t *dscp; /* dir we're dealing with */
8204 cm_scache_t *scp; /* file we're creating */
8208 clientchar_t *lastNamep;
8211 clientchar_t *tidPathp;
8213 int created = 0; /* the file was new */
8218 excl = (inp->inCom == 0x03)? 0 : 1;
8220 attributes = smb_GetSMBParm(inp, 0);
8221 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8223 tp = smb_GetSMBData(inp, NULL);
8224 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8226 return CM_ERROR_BADSMB;
8228 spacep = inp->spacep;
8229 /* smb_StripLastComponent will strip "::$DATA" if present */
8230 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8232 if (!cm_IsValidClientString(pathp)) {
8234 clientchar_t * hexp;
8236 hexp = cm_GetRawCharsAlloc(pathp, -1);
8237 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8238 osi_LogSaveClientString(smb_logp, hexp));
8242 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8244 return CM_ERROR_BADNTFILENAME;
8247 userp = smb_GetUserFromVCP(vcp, inp);
8249 caseFold = CM_FLAG_CASEFOLD;
8251 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8253 cm_ReleaseUser(userp);
8254 return CM_ERROR_NOSUCHPATH;
8256 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8257 userp, tidPathp, &req, &dscp);
8260 cm_ReleaseUser(userp);
8265 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8266 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8267 cm_ReleaseSCache(dscp);
8268 cm_ReleaseUser(userp);
8269 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8270 return CM_ERROR_PATH_NOT_COVERED;
8272 return CM_ERROR_NOSUCHPATH;
8274 #endif /* DFS_SUPPORT */
8276 /* otherwise, scp points to the parent directory. Do a lookup, and
8277 * truncate the file if we find it, otherwise we create the file.
8284 if (!smb_IsLegalFilename(lastNamep))
8285 return CM_ERROR_BADNTFILENAME;
8287 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8288 #ifdef DEBUG_VERBOSE
8291 hexp = osi_HexifyString( lastNamep );
8292 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8297 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8298 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8299 cm_ReleaseSCache(dscp);
8300 cm_ReleaseUser(userp);
8304 /* if we get here, if code is 0, the file exists and is represented by
8305 * scp. Otherwise, we have to create it.
8309 /* oops, file shouldn't be there */
8310 cm_ReleaseSCache(dscp);
8311 cm_ReleaseSCache(scp);
8312 cm_ReleaseUser(userp);
8313 return CM_ERROR_EXISTS;
8316 setAttr.mask = CM_ATTRMASK_LENGTH;
8317 setAttr.length.LowPart = 0;
8318 setAttr.length.HighPart = 0;
8319 code = cm_SetAttr(scp, &setAttr, userp, &req);
8322 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8323 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8324 smb_SetInitialModeBitsForFile(attributes, &setAttr);
8326 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8330 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8331 smb_NotifyChange(FILE_ACTION_ADDED,
8332 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8333 dscp, lastNamep, NULL, TRUE);
8334 } else if (!excl && code == CM_ERROR_EXISTS) {
8335 /* not an exclusive create, and someone else tried
8336 * creating it already, then we open it anyway. We
8337 * don't bother retrying after this, since if this next
8338 * fails, that means that the file was deleted after
8339 * we started this call.
8341 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8344 setAttr.mask = CM_ATTRMASK_LENGTH;
8345 setAttr.length.LowPart = 0;
8346 setAttr.length.HighPart = 0;
8347 code = cm_SetAttr(scp, &setAttr, userp, &req);
8352 /* we don't need this any longer */
8353 cm_ReleaseSCache(dscp);
8356 /* something went wrong creating or truncating the file */
8357 if (scp) cm_ReleaseSCache(scp);
8358 cm_ReleaseUser(userp);
8362 /* make sure we only open files */
8363 if (scp->fileType != CM_SCACHETYPE_FILE) {
8364 cm_ReleaseSCache(scp);
8365 cm_ReleaseUser(userp);
8366 return CM_ERROR_ISDIR;
8369 /* now all we have to do is open the file itself */
8370 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8371 osi_assertx(fidp, "null smb_fid_t");
8375 lock_ObtainMutex(&fidp->mx);
8376 /* always create it open for read/write */
8377 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8379 /* remember that the file was newly created */
8381 fidp->flags |= SMB_FID_CREATED;
8383 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8385 /* save a pointer to the vnode */
8387 lock_ObtainWrite(&scp->rw);
8388 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8389 lock_ReleaseWrite(&scp->rw);
8392 fidp->userp = userp;
8393 lock_ReleaseMutex(&fidp->mx);
8395 smb_SetSMBParm(outp, 0, fidp->fid);
8396 smb_SetSMBDataLength(outp, 0);
8398 cm_Open(scp, 0, userp);
8400 smb_ReleaseFID(fidp);
8401 cm_ReleaseUser(userp);
8402 /* leave scp held since we put it in fidp->scp */
8407 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8410 osi_hyper_t new_offset;
8421 fd = smb_GetSMBParm(inp, 0);
8422 whence = smb_GetSMBParm(inp, 1);
8423 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8425 /* try to find the file descriptor */
8426 fd = smb_ChainFID(fd, inp);
8427 fidp = smb_FindFID(vcp, fd, 0);
8429 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8431 return CM_ERROR_BADFD;
8433 lock_ObtainMutex(&fidp->mx);
8434 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8435 lock_ReleaseMutex(&fidp->mx);
8436 smb_ReleaseFID(fidp);
8437 return CM_ERROR_BADFD;
8440 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8441 lock_ReleaseMutex(&fidp->mx);
8442 smb_CloseFID(vcp, fidp, NULL, 0);
8443 smb_ReleaseFID(fidp);
8444 return CM_ERROR_NOSUCHFILE;
8447 lock_ReleaseMutex(&fidp->mx);
8449 userp = smb_GetUserFromVCP(vcp, inp);
8451 lock_ObtainMutex(&fidp->mx);
8454 lock_ReleaseMutex(&fidp->mx);
8455 lock_ObtainWrite(&scp->rw);
8456 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8457 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8459 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8461 /* offset from current offset */
8462 new_offset = LargeIntegerAdd(fidp->offset,
8463 ConvertLongToLargeInteger(offset));
8465 else if (whence == 2) {
8466 /* offset from current EOF */
8467 new_offset = LargeIntegerAdd(scp->length,
8468 ConvertLongToLargeInteger(offset));
8470 new_offset = ConvertLongToLargeInteger(offset);
8473 fidp->offset = new_offset;
8474 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8475 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8476 smb_SetSMBDataLength(outp, 0);
8478 lock_ReleaseWrite(&scp->rw);
8479 smb_ReleaseFID(fidp);
8480 cm_ReleaseSCache(scp);
8481 cm_ReleaseUser(userp);
8485 /* dispatch all of the requests received in a packet. Due to chaining, this may
8486 * be more than one request.
8488 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8489 NCB *ncbp, raw_write_cont_t *rwcp)
8493 unsigned long code = 0;
8494 unsigned char *outWctp;
8495 int nparms; /* # of bytes of parameters */
8497 int nbytes; /* bytes of data, excluding count */
8500 unsigned short errCode;
8501 unsigned long NTStatus;
8503 unsigned char errClass;
8504 unsigned int oldGen;
8505 DWORD oldTime, newTime;
8507 /* get easy pointer to the data */
8508 smbp = (smb_t *) inp->data;
8510 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8511 /* setup the basic parms for the initial request in the packet */
8512 inp->inCom = smbp->com;
8513 inp->wctp = &smbp->wct;
8515 inp->ncb_length = ncbp->ncb_length;
8520 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8521 /* log it and discard it */
8522 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8523 __FILE__, __LINE__, ncbp->ncb_length);
8524 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8528 /* We are an ongoing op */
8529 thrd_Increment(&ongoingOps);
8531 /* set up response packet for receiving output */
8532 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8533 smb_FormatResponsePacket(vcp, inp, outp);
8534 outWctp = outp->wctp;
8536 /* Remember session generation number and time */
8537 oldGen = sessionGen;
8538 oldTime = GetTickCount();
8540 while (inp->inCom != 0xff) {
8541 dp = &smb_dispatchTable[inp->inCom];
8543 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8544 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8545 code = outp->resumeCode;
8549 /* process each request in the packet; inCom, wctp and inCount
8550 * are already set up.
8552 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8555 /* now do the dispatch */
8556 /* start by formatting the response record a little, as a default */
8557 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8559 outWctp[1] = 0xff; /* no operation */
8560 outWctp[2] = 0; /* padding */
8565 /* not a chained request, this is a more reasonable default */
8566 outWctp[0] = 0; /* wct of zero */
8567 outWctp[1] = 0; /* and bcc (word) of zero */
8571 /* once set, stays set. Doesn't matter, since we never chain
8572 * "no response" calls.
8574 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8578 /* we have a recognized operation */
8579 char * opName = myCrt_Dispatch(inp->inCom);
8582 smbp = (smb_t *) inp;
8584 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8585 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8586 if (inp->inCom == 0x1d) {
8588 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8590 code = (*(dp->procp)) (vcp, inp, outp);
8592 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8593 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8595 newTime = GetTickCount();
8596 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8597 opName, smbp->mid, newTime - oldTime);
8600 if ( code == CM_ERROR_BADSMB ||
8601 code == CM_ERROR_BADOP )
8603 #endif /* LOG_PACKET */
8605 /* ReceiveV3Tran2A handles its own logging */
8606 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8609 clientchar_t *treepath = NULL; /* do not free */
8610 clientchar_t *pathname = NULL;
8611 cm_fid_t afid = {0,0,0,0,0};
8613 uidp = smb_FindUID(vcp, smbp->uid, 0);
8614 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8615 fidp = smb_FindFID(vcp, inp->fid, 0);
8618 lock_ObtainMutex(&fidp->mx);
8619 if (fidp->NTopen_pathp)
8620 pathname = fidp->NTopen_pathp;
8622 afid = fidp->scp->fid;
8624 if (inp->stringsp->wdata)
8625 pathname = inp->stringsp->wdata;
8628 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)",
8629 opName, newTime - oldTime,
8630 smbp->uid, uidp ? uidp->unp->name : NULL,
8631 smbp->pid, smbp->mid, smbp->tid,
8634 afid.cell, afid.volume, afid.vnode, afid.unique);
8637 lock_ReleaseMutex(&fidp->mx);
8640 smb_ReleaseUID(uidp);
8642 smb_ReleaseFID(fidp);
8645 if (oldGen != sessionGen) {
8646 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8647 newTime - oldTime, ncbp->ncb_length);
8648 osi_Log3(smb_logp, "Request %s straddled session startup, "
8649 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8652 FreeSMBStrings(inp);
8654 /* bad opcode, fail the request, after displaying it */
8655 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8658 #endif /* LOG_PACKET */
8661 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8662 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8663 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8664 if (code == IDCANCEL)
8667 code = CM_ERROR_BADOP;
8670 /* catastrophic failure: log as much as possible */
8671 if (code == CM_ERROR_BADSMB) {
8672 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8676 #endif /* LOG_PACKET */
8677 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8680 code = CM_ERROR_INVAL;
8683 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8684 thrd_Decrement(&ongoingOps);
8689 /* now, if we failed, turn the current response into an empty
8690 * one, and fill in the response packet's error code.
8693 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8694 smb_MapNTError(code, &NTStatus);
8695 outWctp = outp->wctp;
8696 smbp = (smb_t *) &outp->data;
8697 if (code != CM_ERROR_PARTIALWRITE
8698 && code != CM_ERROR_BUFFERTOOSMALL
8699 && code != CM_ERROR_GSSCONTINUE) {
8700 /* nuke wct and bcc. For a partial
8701 * write or an in-process authentication handshake,
8702 * assume they're OK.
8708 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8709 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8710 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8711 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8712 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8716 smb_MapCoreError(code, vcp, &errCode, &errClass);
8717 outWctp = outp->wctp;
8718 smbp = (smb_t *) &outp->data;
8719 if (code != CM_ERROR_PARTIALWRITE) {
8720 /* nuke wct and bcc. For a partial
8721 * write, assume they're OK.
8727 smbp->errLow = (unsigned char) (errCode & 0xff);
8728 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8729 smbp->rcls = errClass;
8732 } /* error occurred */
8734 /* if we're here, we've finished one request. Look to see if
8735 * this is a chained opcode. If it is, setup things to process
8736 * the chained request, and setup the output buffer to hold the
8737 * chained response. Start by finding the next input record.
8739 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8740 break; /* not a chained req */
8741 tp = inp->wctp; /* points to start of last request */
8742 /* in a chained request, the first two
8743 * parm fields are required, and are
8744 * AndXCommand/AndXReserved and
8746 if (tp[0] < 2) break;
8747 if (tp[1] == 0xff) break; /* no more chained opcodes */
8749 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8752 /* and now append the next output request to the end of this
8753 * last request. Begin by finding out where the last response
8754 * ends, since that's where we'll put our new response.
8756 outWctp = outp->wctp; /* ptr to out parameters */
8757 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8758 nparms = outWctp[0] << 1;
8759 tp = outWctp + nparms + 1; /* now points to bcc field */
8760 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8761 tp += 2 /* for the count itself */ + nbytes;
8762 /* tp now points to the new output record; go back and patch the
8763 * second parameter (off2) to point to the new record.
8765 temp = (unsigned int)(tp - outp->data);
8766 outWctp[3] = (unsigned char) (temp & 0xff);
8767 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8768 outWctp[2] = 0; /* padding */
8769 outWctp[1] = inp->inCom; /* next opcode */
8771 /* finally, setup for the next iteration */
8774 } /* while loop over all requests in the packet */
8776 /* now send the output packet, and return */
8778 smb_SendPacket(vcp, outp);
8779 thrd_Decrement(&ongoingOps);
8784 /* Wait for Netbios() calls to return, and make the results available to server
8785 * threads. Note that server threads can't wait on the NCBevents array
8786 * themselves, because NCB events are manual-reset, and the servers would race
8787 * each other to reset them.
8789 void smb_ClientWaiter(void *parmp)
8794 while (smbShutdownFlag == 0) {
8795 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8797 if (code == WAIT_OBJECT_0)
8800 /* error checking */
8801 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8803 int abandonIdx = code - WAIT_ABANDONED_0;
8804 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8807 if (code == WAIT_IO_COMPLETION)
8809 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8813 if (code == WAIT_TIMEOUT)
8815 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8818 if (code == WAIT_FAILED)
8820 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8823 idx = code - WAIT_OBJECT_0;
8825 /* check idx range! */
8826 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8828 /* this is fatal - log as much as possible */
8829 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8830 osi_assertx(0, "invalid index");
8833 thrd_ResetEvent(NCBevents[idx]);
8834 thrd_SetEvent(NCBreturns[0][idx]);
8839 * Try to have one NCBRECV request waiting for every live session. Not more
8840 * than one, because if there is more than one, it's hard to handle Write Raw.
8842 void smb_ServerWaiter(void *parmp)
8845 int idx_session, idx_NCB;
8848 while (smbShutdownFlag == 0) {
8850 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8852 if (code == WAIT_OBJECT_0)
8855 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8857 int abandonIdx = code - WAIT_ABANDONED_0;
8858 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8861 if (code == WAIT_IO_COMPLETION)
8863 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8867 if (code == WAIT_TIMEOUT)
8869 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8872 if (code == WAIT_FAILED)
8874 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8877 idx_session = code - WAIT_OBJECT_0;
8879 /* check idx range! */
8880 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8882 /* this is fatal - log as much as possible */
8883 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8884 osi_assertx(0, "invalid index");
8889 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8891 if (code == WAIT_OBJECT_0) {
8892 if (smbShutdownFlag == 1)
8898 /* error checking */
8899 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8901 int abandonIdx = code - WAIT_ABANDONED_0;
8902 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8905 if (code == WAIT_IO_COMPLETION)
8907 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8911 if (code == WAIT_TIMEOUT)
8913 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8916 if (code == WAIT_FAILED)
8918 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8921 idx_NCB = code - WAIT_OBJECT_0;
8923 /* check idx range! */
8924 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8926 /* this is fatal - log as much as possible */
8927 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8928 osi_assertx(0, "invalid index");
8931 /* Link them together */
8932 NCBsessions[idx_NCB] = idx_session;
8935 ncbp = NCBs[idx_NCB];
8936 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8937 ncbp->ncb_command = NCBRECV | ASYNCH;
8938 ncbp->ncb_lana_num = lanas[idx_session];
8939 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8940 ncbp->ncb_event = NCBevents[idx_NCB];
8941 ncbp->ncb_length = SMB_PACKETSIZE;
8946 typedef struct _monitored_task {
8949 LARGE_INTEGER start_time;
8951 BOOL trace_timer_hit;
8952 BOOL dump_timer_hit;
8955 typedef struct osi_queueHT {
8956 osi_queue_t * headp;
8957 osi_queue_t * tailp;
8960 static osi_queue_t *smb_monitored_tasks = NULL;
8961 static osi_queue_t *smb_free_monitored_tasks = NULL;
8963 static osi_mutex_t _monitor_mx;
8965 static HANDLE h_monitored_task_queue = NULL;
8966 static HANDLE h_monitored_task_shutdown = NULL;
8968 static time_t smb_last_dump_time = 0;
8970 DWORD smb_monitorReqs = 0;
8972 /* FILETIME comparison fuzz */
8973 #define MONITOR_FUZZ_TIMEOUT (1 * 10000000i64)
8975 /* Trace timeout is at 60 seconds */
8976 #define MONITOR_TRACE_TIMEOUT (60 * 10000000i64)
8978 /* Dump timeout is at 120 seconds */
8979 #define MONITOR_DUMP_TIMEOUT (120 * 10000000i64)
8981 /* Time before another dump is performed in seconds*/
8982 #define MONITOR_DUMP_RESET_TIMEOUT (600)
8984 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
8987 LARGE_INTEGER earliest;
8990 GetSystemTimeAsFileTime(&now);
8991 earliest.LowPart = now.dwLowDateTime;
8992 earliest.HighPart = now.dwHighDateTime;
8993 earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
8995 while ((t = (monitored_task *) taskmq->headp) != NULL &&
8997 (t->start_time.QuadPart < earliest.QuadPart ||
8999 t->dump_timer_hit)) {
9001 osi_QRemoveHT(&taskmq->headp,
9005 lock_ObtainMutex(&_monitor_mx);
9006 osi_QAdd(&smb_free_monitored_tasks, &t->q);
9007 lock_ReleaseMutex(&_monitor_mx);
9010 #ifdef INVARIANT_CHECK
9016 for (t = (monitored_task *) taskmq->headp;
9018 t = (monitored_task *) osi_QNext(&t->q)) {
9019 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9020 last.QuadPart = t->start_time.QuadPart;
9026 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
9028 monitored_task * task;
9029 monitored_task * tasks;
9031 lock_ObtainMutex(&_monitor_mx);
9032 tasks = (monitored_task *) smb_monitored_tasks;
9033 smb_monitored_tasks = NULL;
9034 lock_ReleaseMutex(&_monitor_mx);
9039 osi_QRemove((osi_queue_t **) &tasks, &task->q);
9041 if (task->started) {
9047 q.prevp = taskmq->tailp;
9049 /* Insertion sort by start_time. Earliest request is
9050 first. Since we are likely to receive new requests
9051 later, we start inserting from the back. */
9054 ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
9058 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
9059 else if (p->prevp == NULL)
9060 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
9062 osi_queue_t *o = p->prevp;
9064 osi_assert(o->nextp == p);
9068 p->prevp = &task->q;
9069 o->nextp = &task->q;
9073 /* Some task ending */
9077 for (p = taskmq->headp;
9081 monitored_task * mt = (monitored_task *) p;
9083 if (mt->task_id == task->task_id) {
9085 osi_QRemoveHT(&taskmq->headp,
9088 lock_ObtainMutex(&_monitor_mx);
9089 osi_QAdd(&smb_free_monitored_tasks, p);
9090 lock_ReleaseMutex(&_monitor_mx);
9096 lock_ObtainMutex(&_monitor_mx);
9097 osi_QAdd(&smb_free_monitored_tasks, &task->q);
9098 lock_ReleaseMutex(&_monitor_mx);
9102 #ifdef INVARIANT_CHECK
9109 for (t = (monitored_task *) taskmq->headp;
9111 t = (monitored_task *) osi_QNext(&t->q)) {
9112 osi_assert(last.QuadPart <= t->start_time.QuadPart);
9113 last.QuadPart = t->start_time.QuadPart;
9119 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9121 if (!task->trace_timer_hit) {
9123 task->trace_timer_hit = TRUE;
9125 osi_LogEnable(afsd_logp);
9126 rx_DebugOnOff(TRUE);
9128 } else if (!task->dump_timer_hit) {
9133 if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9134 task->dump_timer_hit = TRUE;
9135 smb_last_dump_time = now;
9137 GenerateMiniDump(NULL);
9143 * Server request monitoring
9145 * The server monitor runs in a separate thread and monitors server
9146 * requests for potential timeouts. It examines notifcations queued
9147 * by smb_NotifyRequestEvent() and waits for potential timeout events:
9149 * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9150 * enables trace logging.
9152 * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9153 * out a dump file that will hopefully contain enough evidence to
9154 * figure out why the timeout event occurred.
9157 void smb_ServerMonitor(VOID * parmp)
9159 osi_queueHT_t in_progress = { NULL, NULL };
9160 HANDLE h_timer = NULL;
9164 h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9165 h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9166 h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9168 lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9170 h_all[0] = h_monitored_task_queue;
9172 h_all[2] = h_monitored_task_shutdown;
9177 rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9179 if (rv == WAIT_OBJECT_0) {
9181 smb_SlurpNewTaskMonitors(&in_progress);
9183 } else if (rv == WAIT_OBJECT_0 + 1) {
9185 smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9193 /* refresh timers */
9197 smb_PurgeOldTaskMonitors(&in_progress);
9198 t = (monitored_task *) in_progress.headp;
9200 if (t && !t->trace_timer_hit) {
9203 due = t->start_time;
9204 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9206 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9207 } else if (t && !t->dump_timer_hit) {
9211 due = t->start_time;
9212 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9214 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9216 CancelWaitableTimer(h_timer);
9218 /* CancelWaitableTimer() doesn't reset the timer if it
9219 was already signalled. */
9220 WaitForSingleObject(h_timer, 0);
9228 h = h_monitored_task_queue;
9229 h_monitored_task_queue = NULL;
9232 h = h_monitored_task_shutdown;
9233 h_monitored_task_shutdown = NULL;
9236 CloseHandle(h_timer);
9238 lock_FinalizeMutex(&_monitor_mx);
9242 monitored_task * task;
9244 while (in_progress.headp) {
9245 task = (monitored_task *) in_progress.headp;
9246 osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9250 for (task = (monitored_task *) smb_free_monitored_tasks;
9251 task; task = (monitored_task *) smb_free_monitored_tasks) {
9252 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9256 for (task = (monitored_task *) smb_monitored_tasks;
9257 task; task = (monitored_task *) smb_monitored_tasks) {
9258 osi_QRemove(&smb_monitored_tasks, &task->q);
9264 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9266 monitored_task * task;
9268 lock_ObtainMutex(&_monitor_mx);
9269 task = (monitored_task *) smb_free_monitored_tasks;
9271 osi_QRemove(&smb_free_monitored_tasks, &task->q);
9272 lock_ReleaseMutex(&_monitor_mx);
9275 task = malloc(sizeof(monitored_task));
9276 memset(task, 0, sizeof(*task));
9278 task->task_id = task_id;
9279 task->started = started;
9284 GetSystemTimeAsFileTime(&now);
9285 task->start_time.HighPart = now.dwHighDateTime;
9286 task->start_time.LowPart = now.dwLowDateTime;
9289 lock_ObtainMutex(&_monitor_mx);
9290 osi_QAdd(&smb_monitored_tasks, &task->q);
9291 lock_ReleaseMutex(&_monitor_mx);
9293 SetEvent(h_monitored_task_queue);
9296 void smb_ShutdownMonitor()
9298 SetEvent(h_monitored_task_shutdown);
9302 * The top level loop for handling SMB request messages. Each server thread
9303 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9304 * NCB and buffer for the incoming request are loaned to us.
9306 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
9307 * to immediately send a request for the rest of the data. This must come
9308 * before any other traffic for that session, so we delay setting the session
9309 * event until that data has come in.
9311 void smb_Server(VOID *parmp)
9313 INT_PTR myIdx = (INT_PTR) parmp;
9317 smb_packet_t *outbufp;
9319 int idx_NCB, idx_session;
9321 smb_vc_t *vcp = NULL;
9323 extern void rx_StartClientThread(void);
9325 rx_StartClientThread();
9327 outncbp = smb_GetNCB();
9328 outbufp = smb_GetPacket();
9329 outbufp->ncbp = outncbp;
9337 cm_ResetServerPriority();
9339 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9342 /* terminate silently if shutdown flag is set */
9343 if (code == WAIT_OBJECT_0) {
9344 if (smbShutdownFlag == 1) {
9345 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9351 /* error checking */
9352 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9354 int abandonIdx = code - WAIT_ABANDONED_0;
9355 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9358 if (code == WAIT_IO_COMPLETION)
9360 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9364 if (code == WAIT_TIMEOUT)
9366 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9369 if (code == WAIT_FAILED)
9371 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9374 idx_NCB = code - WAIT_OBJECT_0;
9376 /* check idx range! */
9377 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9379 /* this is fatal - log as much as possible */
9380 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9381 osi_assertx(0, "invalid index");
9384 ncbp = NCBs[idx_NCB];
9385 idx_session = NCBsessions[idx_NCB];
9386 rc = ncbp->ncb_retcode;
9388 if (rc != NRC_PENDING && rc != NRC_GOODRET)
9389 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9393 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9397 /* Can this happen? Or is it just my UNIX paranoia? */
9398 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9403 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9406 /* Client closed session */
9407 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9409 lock_ObtainMutex(&vcp->mx);
9410 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9411 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9413 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9414 lock_ReleaseMutex(&vcp->mx);
9415 lock_ObtainWrite(&smb_globalLock);
9416 dead_sessions[vcp->session] = TRUE;
9417 lock_ReleaseWrite(&smb_globalLock);
9419 lock_ReleaseMutex(&vcp->mx);
9421 smb_CleanupDeadVC(vcp);
9428 /* Treat as transient error */
9429 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9432 "dispatch smb recv failed, message incomplete, ncb_length %d",
9435 "SMB message incomplete, "
9436 "length %d", ncbp->ncb_length);
9439 * We used to discard the packet.
9440 * Instead, try handling it normally.
9444 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9448 /* A weird error code. Log it, sleep, and continue. */
9449 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9451 lock_ObtainMutex(&vcp->mx);
9452 if (vcp->errorCount++ > 3) {
9453 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9454 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9455 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9457 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9458 lock_ReleaseMutex(&vcp->mx);
9459 lock_ObtainWrite(&smb_globalLock);
9460 dead_sessions[vcp->session] = TRUE;
9461 lock_ReleaseWrite(&smb_globalLock);
9463 lock_ReleaseMutex(&vcp->mx);
9465 smb_CleanupDeadVC(vcp);
9471 lock_ReleaseMutex(&vcp->mx);
9475 thrd_SetEvent(SessionEvents[idx_session]);
9481 /* Success, so now dispatch on all the data in the packet */
9483 smb_concurrentCalls++;
9484 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9485 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9488 * If at this point vcp is NULL (implies that packet was invalid)
9489 * then we are in big trouble. This means either :
9490 * a) we have the wrong NCB.
9491 * b) Netbios screwed up the call.
9492 * c) The VC was already marked dead before we were able to
9494 * Obviously this implies that
9495 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9496 * lanas[idx_session] != ncbp->ncb_lana_num )
9497 * Either way, we can't do anything with this packet.
9498 * Log, sleep and resume.
9501 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9505 ncbp->ncb_lana_num);
9507 /* Also log in the trace log. */
9508 osi_Log4(smb_logp, "Server: VCP does not exist!"
9509 "LSNs[idx_session]=[%d],"
9510 "lanas[idx_session]=[%d],"
9511 "ncbp->ncb_lsn=[%d],"
9512 "ncbp->ncb_lana_num=[%d]",
9516 ncbp->ncb_lana_num);
9518 /* thrd_Sleep(1000); Don't bother sleeping */
9519 thrd_SetEvent(SessionEvents[idx_session]);
9520 smb_concurrentCalls--;
9524 cm_SetRequestStartTime();
9525 if (smb_monitorReqs) {
9526 smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9529 vcp->errorCount = 0;
9530 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9531 smbp = (smb_t *)bufp->data;
9538 if (smbp->com == 0x1d) {
9539 /* Special handling for Write Raw */
9540 raw_write_cont_t rwc;
9542 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9543 if (rwc.code == 0) {
9544 EVENT_HANDLE rwevent;
9545 char eventName[MAX_PATH];
9547 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9548 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9549 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9550 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9552 ncbp->ncb_command = NCBRECV | ASYNCH;
9553 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9554 ncbp->ncb_lana_num = vcp->lana;
9555 ncbp->ncb_buffer = rwc.buf;
9556 ncbp->ncb_length = 65535;
9557 ncbp->ncb_event = rwevent;
9559 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9560 thrd_CloseHandle(rwevent);
9562 thrd_SetEvent(SessionEvents[idx_session]);
9564 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9566 else if (smbp->com == 0xa0) {
9568 * Serialize the handling for NT Transact
9571 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9572 thrd_SetEvent(SessionEvents[idx_session]);
9574 thrd_SetEvent(SessionEvents[idx_session]);
9575 /* TODO: what else needs to be serialized? */
9576 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9580 __except( smb_ServerExceptionFilter() ) {
9584 if (smb_monitorReqs) {
9585 smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9587 smb_concurrentCalls--;
9590 thrd_SetEvent(NCBavails[idx_NCB]);
9595 smb_FreePacket(outbufp);
9597 smb_FreeNCB(outncbp);
9601 * Exception filter for the server threads. If an exception occurs in the
9602 * dispatch routines, which is where exceptions are most common, then do a
9603 * force trace and give control to upstream exception handlers. Useful for
9606 DWORD smb_ServerExceptionFilter(void) {
9607 /* While this is not the best time to do a trace, if it succeeds, then
9608 * we have a trace (assuming tracing was enabled). Otherwise, this should
9609 * throw a second exception.
9611 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9612 afsd_ForceTrace(TRUE);
9613 buf_ForceTrace(TRUE);
9614 return EXCEPTION_CONTINUE_SEARCH;
9618 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9619 * If the number of server threads is M, and the number of live sessions is
9620 * N, then the number of NCB's in use at any time either waiting for, or
9621 * holding, received messages is M + N, so that is how many NCB's get created.
9623 void InitNCBslot(int idx)
9625 struct smb_packet *bufp;
9626 EVENT_HANDLE retHandle;
9628 char eventName[MAX_PATH];
9630 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9632 NCBs[idx] = smb_GetNCB();
9633 sprintf(eventName,"NCBavails[%d]", idx);
9634 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9635 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9636 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9637 sprintf(eventName,"NCBevents[%d]", idx);
9638 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9639 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9640 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9641 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9642 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9643 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9644 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9645 for (i=0; i<smb_NumServerThreads; i++)
9646 NCBreturns[i][idx] = retHandle;
9647 bufp = smb_GetPacket();
9648 bufp->spacep = cm_GetSpace();
9652 /* listen for new connections */
9653 void smb_Listener(void *parmp)
9659 afs_uint32 session, thread;
9660 smb_vc_t *vcp = NULL;
9662 char rname[NCBNAMSZ+1];
9663 char cname[MAX_COMPUTERNAME_LENGTH+1];
9664 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9665 INT_PTR lana = (INT_PTR) parmp;
9666 char eventName[MAX_PATH];
9667 int bridgeCount = 0;
9668 int nowildCount = 0;
9670 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9671 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9672 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9673 thrd_ResetEvent(ListenerShutdown[lana]);
9675 ncbp = smb_GetNCB();
9677 /* retrieve computer name */
9678 GetComputerName(cname, &cnamelen);
9681 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9682 memset(ncbp, 0, sizeof(NCB));
9685 ncbp->ncb_command = NCBLISTEN;
9686 ncbp->ncb_rto = 0; /* No receive timeout */
9687 ncbp->ncb_sto = 0; /* No send timeout */
9689 /* pad out with spaces instead of null termination */
9690 len = (long)strlen(smb_localNamep);
9691 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9692 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9694 strcpy(ncbp->ncb_callname, "*");
9695 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9697 ncbp->ncb_lana_num = (UCHAR)lana;
9699 code = Netbios(ncbp);
9701 if (code == NRC_NAMERR) {
9702 /* An smb shutdown or Vista resume must have taken place */
9704 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9705 ncbp->ncb_lana_num);
9706 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9708 if (lock_TryMutex(&smb_StartedLock)) {
9709 lana_list.lana[i] = LANA_INVALID;
9710 lock_ReleaseMutex(&smb_StartedLock);
9713 } else if (code == NRC_BRIDGE || code != 0) {
9714 int lanaRemaining = 0;
9716 if (code == NRC_BRIDGE) {
9717 if (++bridgeCount <= 5) {
9718 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9721 } else if (code == NRC_NOWILD) {
9722 if (++nowildCount <= 5) {
9723 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9725 if (bridgeCount > 0) {
9726 memset(ncbp, 0, sizeof(*ncbp));
9727 ncbp->ncb_command = NCBADDNAME;
9728 ncbp->ncb_lana_num = (UCHAR)lana;
9729 /* pad out with spaces instead of null termination */
9730 len = (long)strlen(smb_localNamep);
9731 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9732 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9733 code = Netbios(ncbp);
9739 while (!lock_TryMutex(&smb_StartedLock)) {
9740 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9746 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9747 ncbp->ncb_lana_num, ncb_error_string(code));
9748 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9749 ncbp->ncb_lana_num, ncb_error_string(code));
9751 for (i = 0; i < lana_list.length; i++) {
9752 if (lana_list.lana[i] == lana) {
9753 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9754 lana_list.lana[i] = LANA_INVALID;
9756 if (lana_list.lana[i] != LANA_INVALID)
9760 if (lanaRemaining == 0) {
9761 cm_VolStatus_Network_Stopped(cm_NetbiosName
9766 smb_ListenerState = SMB_LISTENER_STOPPED;
9767 smb_LANadapter = LANA_INVALID;
9768 lana_list.length = 0;
9770 lock_ReleaseMutex(&smb_StartedLock);
9774 else if (code != 0) {
9775 char tbuffer[AFSPATHMAX];
9777 /* terminate silently if shutdown flag is set */
9778 while (!lock_TryMutex(&smb_StartedLock)) {
9779 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9785 "NCBLISTEN lana=%d failed with code %d [%s]",
9786 ncbp->ncb_lana_num, code, ncb_error_string(code));
9788 "Client exiting due to network failure. Please restart client.\n");
9791 "Client exiting due to network failure. Please restart client.\n"
9792 "NCBLISTEN lana=%d failed with code %d [%s]",
9793 ncbp->ncb_lana_num, code, ncb_error_string(code));
9795 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9796 MB_OK|MB_SERVICE_NOTIFICATION);
9797 osi_panic(tbuffer, __FILE__, __LINE__);
9799 lock_ReleaseMutex(&smb_StartedLock);
9804 /* a successful packet received. clear bridge error count */
9808 /* check for remote conns */
9809 /* first get remote name and insert null terminator */
9810 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9811 for (i=NCBNAMSZ; i>0; i--) {
9812 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9818 /* compare with local name */
9820 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9821 flags |= SMB_VCFLAG_REMOTECONN;
9824 lock_ObtainMutex(&smb_ListenerLock);
9826 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9827 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9829 /* now ncbp->ncb_lsn is the connection ID */
9830 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9831 if (vcp->session == 0) {
9832 /* New generation */
9833 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9836 /* Log session startup */
9838 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9839 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9840 #endif /* NOTSERVICE */
9841 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9842 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9844 if (reportSessionStartups) {
9845 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9848 lock_ObtainMutex(&vcp->mx);
9849 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9850 vcp->flags |= flags;
9851 lock_ReleaseMutex(&vcp->mx);
9853 /* Allocate slot in session arrays */
9854 /* Re-use dead session if possible, otherwise add one more */
9855 /* But don't look at session[0], it is reserved */
9856 lock_ObtainWrite(&smb_globalLock);
9857 for (session = 1; session < numSessions; session++) {
9858 if (dead_sessions[session]) {
9859 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9860 dead_sessions[session] = FALSE;
9864 lock_ReleaseWrite(&smb_globalLock);
9866 /* We are re-using an existing VC because the lsn and lana
9868 session = vcp->session;
9870 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9872 /* Log session startup */
9874 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9875 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9876 #endif /* NOTSERVICE */
9877 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9878 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9880 if (reportSessionStartups) {
9881 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9885 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9886 unsigned long code = CM_ERROR_ALLBUSY;
9887 smb_packet_t * outp = smb_GetPacket();
9888 unsigned char *outWctp;
9891 smb_FormatResponsePacket(vcp, NULL, outp);
9894 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9895 unsigned long NTStatus;
9896 smb_MapNTError(code, &NTStatus);
9897 outWctp = outp->wctp;
9898 smbp = (smb_t *) &outp->data;
9902 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9903 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9904 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9905 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9906 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9908 unsigned short errCode;
9909 unsigned char errClass;
9910 smb_MapCoreError(code, vcp, &errCode, &errClass);
9911 outWctp = outp->wctp;
9912 smbp = (smb_t *) &outp->data;
9916 smbp->errLow = (unsigned char) (errCode & 0xff);
9917 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9918 smbp->rcls = errClass;
9921 smb_SendPacket(vcp, outp);
9922 smb_FreePacket(outp);
9924 lock_ObtainMutex(&vcp->mx);
9925 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9926 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9928 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9929 lock_ReleaseMutex(&vcp->mx);
9930 lock_ObtainWrite(&smb_globalLock);
9931 dead_sessions[vcp->session] = TRUE;
9932 lock_ReleaseWrite(&smb_globalLock);
9933 smb_CleanupDeadVC(vcp);
9935 lock_ReleaseMutex(&vcp->mx);
9938 /* assert that we do not exceed the maximum number of sessions or NCBs.
9939 * we should probably want to wait for a session to be freed in case
9942 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9943 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9945 lock_ObtainMutex(&vcp->mx);
9946 vcp->session = session;
9947 lock_ReleaseMutex(&vcp->mx);
9948 lock_ObtainWrite(&smb_globalLock);
9949 LSNs[session] = ncbp->ncb_lsn;
9950 lanas[session] = ncbp->ncb_lana_num;
9951 lock_ReleaseWrite(&smb_globalLock);
9953 if (session == numSessions) {
9954 /* Add new NCB for new session */
9955 char eventName[MAX_PATH];
9957 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9959 InitNCBslot(numNCBs);
9960 lock_ObtainWrite(&smb_globalLock);
9962 lock_ReleaseWrite(&smb_globalLock);
9963 thrd_SetEvent(NCBavails[0]);
9964 thrd_SetEvent(NCBevents[0]);
9965 for (thread = 0; thread < smb_NumServerThreads; thread++)
9966 thrd_SetEvent(NCBreturns[thread][0]);
9967 /* Also add new session event */
9968 sprintf(eventName, "SessionEvents[%d]", session);
9969 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9970 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9971 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9972 lock_ObtainWrite(&smb_globalLock);
9974 lock_ReleaseWrite(&smb_globalLock);
9975 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9976 thrd_SetEvent(SessionEvents[0]);
9978 thrd_SetEvent(SessionEvents[session]);
9984 lock_ReleaseMutex(&smb_ListenerLock);
9985 } /* dispatch while loop */
9989 thrd_SetEvent(ListenerShutdown[lana]);
9994 configureBackConnectionHostNames(void)
9996 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9997 * there is a restriction on the use of SMB authentication on loopback connections.
9998 * There are two work arounds available:
10000 * (1) We can disable the check for matching host names. This does not
10001 * require a reboot:
10002 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
10003 * "DisableLoopbackCheck"=dword:00000001
10005 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
10006 * does require a reboot:
10007 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
10008 * "BackConnectionHostNames"=multi-sz
10010 * The algorithm will be:
10011 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
10012 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
10013 * (2b1) and check to see if DisableLoopbackCheck is set.
10014 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
10015 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
10016 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
10017 * check for the UnsetDisableLoopbackCheck value.
10018 * If set, set the DisableLoopbackCheck flag to 0x0
10019 * and delete the UnsetDisableLoopbackCheck value
10021 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
10022 * force Windows to use the loopback authentication mechanism for the specified
10025 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
10026 * service session that set it.
10032 DWORD dwSize, dwAllocSize;
10034 PBYTE pHostNames = NULL, pName = NULL;
10035 BOOL bNameFound = FALSE;
10036 static BOOL bLoopbackCheckDisabled = FALSE;
10038 /* BackConnectionHostNames and DisableLoopbackCheck */
10039 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10040 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
10042 KEY_READ|KEY_WRITE,
10043 &hkMSV10) == ERROR_SUCCESS )
10045 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
10046 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10047 (dwType == REG_MULTI_SZ))
10049 dwAllocSize += 1 /* in case the source string is not nul terminated */
10050 + (DWORD)strlen(cm_NetbiosName) + 2;
10051 pHostNames = malloc(dwAllocSize);
10052 dwSize = dwAllocSize;
10053 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
10054 pHostNames, &dwSize) == ERROR_SUCCESS)
10056 for (pName = pHostNames;
10057 (pName - pHostNames < (int) dwSize) && *pName ;
10058 pName += strlen(pName) + 1)
10060 if ( !stricmp(pName, cm_NetbiosName) ) {
10068 if ( !bNameFound ) {
10069 size_t size = strlen(cm_NetbiosName) + 2;
10070 if ( !pHostNames ) {
10071 pHostNames = malloc(size);
10072 pName = pHostNames;
10074 StringCbCopyA(pName, size, cm_NetbiosName);
10076 *pName = '\0'; /* add a second nul terminator */
10078 dwType = REG_MULTI_SZ;
10079 dwSize = (DWORD)(pName - pHostNames + 1);
10080 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10082 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10083 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10085 KEY_READ|KEY_WRITE,
10086 &hkLsa) == ERROR_SUCCESS )
10088 dwSize = sizeof(DWORD);
10089 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
10091 dwType = REG_DWORD;
10092 dwSize = sizeof(DWORD);
10094 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10096 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10097 AFSREG_CLT_OPENAFS_SUBKEY,
10100 REG_OPTION_NON_VOLATILE,
10101 KEY_READ|KEY_WRITE,
10104 NULL) == ERROR_SUCCESS) {
10106 dwType = REG_DWORD;
10107 dwSize = sizeof(DWORD);
10109 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10110 bLoopbackCheckDisabled = TRUE;
10111 RegCloseKey(hkClient);
10113 RegCloseKey(hkLsa);
10116 } else if (!bLoopbackCheckDisabled) {
10117 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10118 AFSREG_CLT_OPENAFS_SUBKEY,
10121 REG_OPTION_NON_VOLATILE,
10122 KEY_READ|KEY_WRITE,
10125 NULL) == ERROR_SUCCESS) {
10127 dwSize = sizeof(DWORD);
10128 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10130 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10131 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10133 KEY_READ|KEY_WRITE,
10134 &hkLsa) == ERROR_SUCCESS )
10136 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10137 RegCloseKey(hkLsa);
10140 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10141 RegCloseKey(hkClient);
10150 RegCloseKey(hkMSV10);
10156 configureExtendedSMBSessionTimeouts(void)
10159 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10160 * new functionality:
10162 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
10163 * "ReconnectableServers" REG_MULTI_SZ
10164 * "ExtendedSessTimeout" REG_DWORD (seconds)
10165 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
10167 * These values can be used to prevent the smb redirector from timing out
10168 * smb connection to the afs smb server prematurely.
10172 DWORD dwSize, dwAllocSize;
10174 PBYTE pHostNames = NULL, pName = NULL;
10175 BOOL bNameFound = FALSE;
10177 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10178 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
10180 KEY_READ|KEY_WRITE,
10181 &hkLanMan) == ERROR_SUCCESS )
10183 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
10184 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10185 (dwType == REG_MULTI_SZ))
10187 dwAllocSize += 1 /* in case the source string is not nul terminated */
10188 + (DWORD)strlen(cm_NetbiosName) + 2;
10189 pHostNames = malloc(dwAllocSize);
10190 dwSize = dwAllocSize;
10191 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
10192 pHostNames, &dwSize) == ERROR_SUCCESS)
10194 for (pName = pHostNames;
10195 (pName - pHostNames < (int) dwSize) && *pName ;
10196 pName += strlen(pName) + 1)
10198 if ( !stricmp(pName, cm_NetbiosName) ) {
10206 if ( !bNameFound ) {
10207 size_t size = strlen(cm_NetbiosName) + 2;
10208 if ( !pHostNames ) {
10209 pHostNames = malloc(size);
10210 pName = pHostNames;
10212 StringCbCopyA(pName, size, cm_NetbiosName);
10214 *pName = '\0'; /* add a second nul terminator */
10216 dwType = REG_MULTI_SZ;
10217 dwSize = (DWORD)(pName - pHostNames + 1);
10218 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10226 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
10227 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10228 (dwType == REG_MULTI_SZ))
10230 dwAllocSize += 1 /* in case the source string is not nul terminated */
10231 + (DWORD)strlen(cm_NetbiosName) + 2;
10232 pHostNames = malloc(dwAllocSize);
10233 dwSize = dwAllocSize;
10234 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
10235 pHostNames, &dwSize) == ERROR_SUCCESS)
10237 for (pName = pHostNames;
10238 (pName - pHostNames < (int) dwSize) && *pName ;
10239 pName += strlen(pName) + 1)
10241 if ( !stricmp(pName, cm_NetbiosName) ) {
10249 if ( !bNameFound ) {
10250 size_t size = strlen(cm_NetbiosName) + 2;
10251 if ( !pHostNames ) {
10252 pHostNames = malloc(size);
10253 pName = pHostNames;
10255 StringCbCopyA(pName, size, cm_NetbiosName);
10257 *pName = '\0'; /* add a second nul terminator */
10259 dwType = REG_MULTI_SZ;
10260 dwSize = (DWORD)(pName - pHostNames + 1);
10261 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10269 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
10270 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10271 (dwType != REG_DWORD))
10273 dwType = REG_DWORD;
10274 dwSize = sizeof(dwValue);
10275 dwValue = 300; /* 5 minutes */
10276 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10278 RegCloseKey(hkLanMan);
10283 smb_LanAdapterChangeThread(void *param)
10286 * Give the IPAddrDaemon thread a chance
10287 * to block before we trigger.
10290 smb_LanAdapterChange(0);
10293 void smb_SetLanAdapterChangeDetected(void)
10298 lock_ObtainMutex(&smb_StartedLock);
10300 if (!powerStateSuspended) {
10301 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10302 NULL, 0, &lpid, "smb_LanAdapterChange");
10303 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
10304 thrd_CloseHandle(phandle);
10307 smb_LanAdapterChangeDetected = 1;
10308 lock_ReleaseMutex(&smb_StartedLock);
10311 void smb_LanAdapterChange(int locked) {
10312 lana_number_t lanaNum;
10314 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
10316 LANA_ENUM temp_list;
10321 afsi_log("smb_LanAdapterChange");
10324 lock_ObtainMutex(&smb_StartedLock);
10326 smb_LanAdapterChangeDetected = 0;
10328 if (!powerStateSuspended &&
10329 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10330 LANA_NETBIOS_NAME_FULL)) &&
10331 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10332 if ( isGateway != bGateway ) {
10333 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10334 smb_LANadapter, lanaNum, isGateway, bGateway);
10336 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10337 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10338 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10341 NCB *ncbp = smb_GetNCB();
10342 ncbp->ncb_command = NCBENUM;
10343 ncbp->ncb_buffer = (PUCHAR)&temp_list;
10344 ncbp->ncb_length = sizeof(temp_list);
10345 code = Netbios(ncbp);
10347 if (temp_list.length != lana_list.length) {
10348 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10349 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10352 for (i=0; i<lana_list.length; i++) {
10353 if ( temp_list.lana[i] != lana_list.lana[i] ) {
10354 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10355 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10367 smb_StopListeners(1);
10368 smb_RestartListeners(1);
10371 lock_ReleaseMutex(&smb_StartedLock);
10374 /* initialize Netbios */
10375 int smb_NetbiosInit(int locked)
10378 int i, lana, code, l;
10380 int delname_tried=0;
10382 int lana_found = 0;
10383 lana_number_t lanaNum;
10386 lock_ObtainMutex(&smb_StartedLock);
10388 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10389 smb_ListenerState != SMB_LISTENER_STOPPED) {
10392 lock_ReleaseMutex(&smb_StartedLock);
10395 /* setup the NCB system */
10396 ncbp = smb_GetNCB();
10398 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
10399 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10400 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10402 if (smb_LANadapter != LANA_INVALID)
10403 afsi_log("LAN adapter number %d", smb_LANadapter);
10405 afsi_log("LAN adapter number not determined");
10408 afsi_log("Set for gateway service");
10410 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10412 /* something went horribly wrong. We can't proceed without a netbios name */
10414 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10415 osi_panic(buf, __FILE__, __LINE__);
10418 /* remember the name */
10419 len = (int)strlen(cm_NetbiosName);
10420 if (smb_localNamep)
10421 free(smb_localNamep);
10422 smb_localNamep = malloc(len+1);
10423 strcpy(smb_localNamep, cm_NetbiosName);
10424 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10426 /* Also copy the value to the client character encoded string */
10427 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10429 if (smb_LANadapter == LANA_INVALID) {
10430 ncbp->ncb_command = NCBENUM;
10431 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10432 ncbp->ncb_length = sizeof(lana_list);
10433 code = Netbios(ncbp);
10435 afsi_log("Netbios NCBENUM error code %d", code);
10436 osi_panic(s, __FILE__, __LINE__);
10440 lana_list.length = 1;
10441 lana_list.lana[0] = smb_LANadapter;
10444 for (i = 0; i < lana_list.length; i++) {
10445 /* reset the adaptor: in Win32, this is required for every process, and
10446 * acts as an init call, not as a real hardware reset.
10448 ncbp->ncb_command = NCBRESET;
10449 ncbp->ncb_callname[0] = 100;
10450 ncbp->ncb_callname[2] = 100;
10451 ncbp->ncb_lana_num = lana_list.lana[i];
10452 code = Netbios(ncbp);
10454 code = ncbp->ncb_retcode;
10456 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10457 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10459 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10463 /* and declare our name so we can receive connections */
10464 memset(ncbp, 0, sizeof(*ncbp));
10465 len=lstrlen(smb_localNamep);
10466 memset(smb_sharename,' ',NCBNAMSZ);
10467 memcpy(smb_sharename,smb_localNamep,len);
10468 afsi_log("lana_list.length %d", lana_list.length);
10470 /* Keep the name so we can unregister it later */
10471 for (l = 0; l < lana_list.length; l++) {
10472 lana = lana_list.lana[l];
10474 ncbp->ncb_command = NCBADDNAME;
10475 ncbp->ncb_lana_num = lana;
10476 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10477 code = Netbios(ncbp);
10479 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10480 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10482 char name[NCBNAMSZ+1];
10484 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10485 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10489 code = ncbp->ncb_retcode;
10492 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10495 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10496 if (code == NRC_BRIDGE) { /* invalid LANA num */
10497 lana_list.lana[l] = LANA_INVALID;
10500 else if (code == NRC_DUPNAME) {
10501 afsi_log("Name already exists; try to delete it");
10502 memset(ncbp, 0, sizeof(*ncbp));
10503 ncbp->ncb_command = NCBDELNAME;
10504 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10505 ncbp->ncb_lana_num = lana;
10506 code = Netbios(ncbp);
10508 code = ncbp->ncb_retcode;
10510 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10512 if (code != 0 || delname_tried) {
10513 lana_list.lana[l] = LANA_INVALID;
10515 else if (code == 0) {
10516 if (!delname_tried) {
10524 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10525 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10529 smb_LANadapter = lana;
10530 lana_found = 1; /* at least one worked */
10534 osi_assertx(lana_list.length >= 0, "empty lana list");
10536 afsi_log("No valid LANA numbers found!");
10537 lana_list.length = 0;
10538 smb_LANadapter = LANA_INVALID;
10539 smb_ListenerState = SMB_LISTENER_STOPPED;
10540 cm_VolStatus_Network_Stopped(cm_NetbiosName
10547 /* we're done with the NCB now */
10550 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10551 if (lana_list.length > 0)
10552 osi_assert(smb_LANadapter != LANA_INVALID);
10555 lock_ReleaseMutex(&smb_StartedLock);
10557 return (lana_list.length > 0 ? 1 : 0);
10560 void smb_StartListeners(int locked)
10567 lock_ObtainMutex(&smb_StartedLock);
10569 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10571 lock_ReleaseMutex(&smb_StartedLock);
10575 afsi_log("smb_StartListeners");
10576 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10577 configureBackConnectionHostNames();
10579 /* Configure Extended SMB Session Timeouts */
10580 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10581 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10582 configureExtendedSMBSessionTimeouts();
10585 smb_ListenerState = SMB_LISTENER_STARTED;
10586 cm_VolStatus_Network_Started(cm_NetbiosName
10592 for (i = 0; i < lana_list.length; i++) {
10593 if (lana_list.lana[i] == LANA_INVALID)
10595 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10596 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10597 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10598 thrd_CloseHandle(phandle);
10601 lock_ReleaseMutex(&smb_StartedLock);
10604 void smb_RestartListeners(int locked)
10607 lock_ObtainMutex(&smb_StartedLock);
10609 if (powerStateSuspended)
10610 afsi_log("smb_RestartListeners called while suspended");
10612 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10613 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10614 if (smb_NetbiosInit(1))
10615 smb_StartListeners(1);
10616 } else if (smb_LanAdapterChangeDetected) {
10617 smb_LanAdapterChange(1);
10621 lock_ReleaseMutex(&smb_StartedLock);
10624 void smb_StopListener(NCB *ncbp, int lana, int wait)
10628 memset(ncbp, 0, sizeof(*ncbp));
10629 ncbp->ncb_command = NCBDELNAME;
10630 ncbp->ncb_lana_num = lana;
10631 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10632 code = Netbios(ncbp);
10634 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10635 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10637 /* and then reset the LANA; this will cause the listener threads to exit */
10638 ncbp->ncb_command = NCBRESET;
10639 ncbp->ncb_callname[0] = 100;
10640 ncbp->ncb_callname[2] = 100;
10641 ncbp->ncb_lana_num = lana;
10642 code = Netbios(ncbp);
10644 code = ncbp->ncb_retcode;
10646 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10648 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10652 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10655 void smb_StopListeners(int locked)
10661 lock_ObtainMutex(&smb_StartedLock);
10663 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10665 lock_ReleaseMutex(&smb_StartedLock);
10669 afsi_log("smb_StopListeners");
10670 smb_ListenerState = SMB_LISTENER_STOPPED;
10671 cm_VolStatus_Network_Stopped(cm_NetbiosName
10677 ncbp = smb_GetNCB();
10679 /* Unregister the SMB name */
10680 for (l = 0; l < lana_list.length; l++) {
10681 lana = lana_list.lana[l];
10683 if (lana != LANA_INVALID) {
10684 smb_StopListener(ncbp, lana, TRUE);
10686 /* mark the adapter invalid */
10687 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10691 /* force a re-evaluation of the network adapters */
10692 lana_list.length = 0;
10693 smb_LANadapter = LANA_INVALID;
10696 lock_ReleaseMutex(&smb_StartedLock);
10699 void smb_Init(osi_log_t *logp, int useV3,
10709 EVENT_HANDLE retHandle;
10710 char eventName[MAX_PATH];
10711 int startListeners = 0;
10713 smb_MBfunc = aMBfunc;
10717 /* Initialize smb_localZero */
10718 myTime.tm_isdst = -1; /* compute whether on DST or not */
10719 myTime.tm_year = 70;
10721 myTime.tm_mday = 1;
10722 myTime.tm_hour = 0;
10725 smb_localZero = mktime(&myTime);
10727 #ifdef AFS_FREELANCE_CLIENT
10728 /* Make sure the root.afs volume has the correct time */
10729 cm_noteLocalMountPointChange(FALSE);
10732 /* initialize the remote debugging log */
10735 /* and the global lock */
10736 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10737 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10739 /* Raw I/O data structures */
10740 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10742 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10743 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10745 /* 4 Raw I/O buffers */
10746 smb_RawBufs = calloc(65536,1);
10747 *((char **)smb_RawBufs) = NULL;
10748 for (i=0; i<3; i++) {
10749 char *rawBuf = calloc(65536,1);
10750 *((char **)rawBuf) = smb_RawBufs;
10751 smb_RawBufs = rawBuf;
10754 /* global free lists */
10755 smb_ncbFreeListp = NULL;
10756 smb_packetFreeListp = NULL;
10758 lock_ObtainMutex(&smb_StartedLock);
10759 startListeners = smb_NetbiosInit(1);
10761 /* Initialize listener and server structures */
10763 memset(dead_sessions, 0, sizeof(dead_sessions));
10764 sprintf(eventName, "SessionEvents[0]");
10765 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10766 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10767 afsi_log("Event Object Already Exists: %s", eventName);
10769 smb_NumServerThreads = nThreads;
10770 sprintf(eventName, "NCBavails[0]");
10771 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10772 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10773 afsi_log("Event Object Already Exists: %s", eventName);
10774 sprintf(eventName, "NCBevents[0]");
10775 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10776 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10777 afsi_log("Event Object Already Exists: %s", eventName);
10778 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10779 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10780 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10781 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10782 afsi_log("Event Object Already Exists: %s", eventName);
10783 for (i = 0; i < smb_NumServerThreads; i++) {
10784 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10785 NCBreturns[i][0] = retHandle;
10788 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10789 for (i = 0; i < smb_NumServerThreads; i++) {
10790 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10791 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10792 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10793 afsi_log("Event Object Already Exists: %s", eventName);
10794 InitNCBslot((int)(i+1));
10796 numNCBs = smb_NumServerThreads + 1;
10798 /* Initialize dispatch table */
10799 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10800 /* Prepare the table for unknown operations */
10801 for(i=0; i<= SMB_NOPCODES; i++) {
10802 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10804 /* Fill in the ones we do know */
10805 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10806 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10807 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10808 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10809 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10810 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10811 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10812 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10813 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10814 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10815 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10816 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10817 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10818 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10819 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10820 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10821 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10822 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10823 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10824 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10825 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10826 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10827 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10828 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10829 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10830 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10831 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10832 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10833 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10834 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10835 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10836 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10837 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10838 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10839 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10840 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10841 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10842 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10843 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10844 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10845 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10846 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10847 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10848 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10849 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10850 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10851 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10852 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10853 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10854 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10855 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10856 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10857 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10858 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10859 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10860 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10861 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10862 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10863 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10864 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10865 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10866 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10867 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10868 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10869 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10870 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10871 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10872 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10873 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10874 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10875 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10876 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10877 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10878 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10880 /* setup tran 2 dispatch table */
10881 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10882 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10883 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10884 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10885 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10886 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10887 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10888 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10889 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10890 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10891 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10892 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10893 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10894 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10895 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10896 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10897 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10898 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10900 /* setup the rap dispatch table */
10901 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10902 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10903 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10904 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10905 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10909 /* if we are doing SMB authentication we have register outselves as a logon process */
10910 if (smb_authType != SMB_AUTH_NONE) {
10911 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10912 LSA_STRING afsProcessName;
10913 LSA_OPERATIONAL_MODE dummy; /*junk*/
10915 afsProcessName.Buffer = "OpenAFSClientDaemon";
10916 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10917 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10919 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10921 if (nts == STATUS_SUCCESS) {
10922 LSA_STRING packageName;
10923 /* we are registered. Find out the security package id */
10924 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10925 packageName.Length = (USHORT)strlen(packageName.Buffer);
10926 packageName.MaximumLength = packageName.Length + 1;
10927 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10928 if (nts == STATUS_SUCCESS) {
10930 * This code forces Windows to authenticate against the Logon Cache
10931 * first instead of attempting to authenticate against the Domain
10932 * Controller. When the Windows logon cache is enabled this improves
10933 * performance by removing the network access and works around a bug
10934 * seen at sites which are using a MIT Kerberos principal to login
10935 * to machines joined to a non-root domain in a multi-domain forest.
10936 * MsV1_0SetProcessOption was added in Windows XP.
10938 PVOID pResponse = NULL;
10939 ULONG cbResponse = 0;
10940 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10942 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10943 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10944 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10945 OptionsRequest.DisableOptions = FALSE;
10947 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10950 sizeof(OptionsRequest),
10956 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10957 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10960 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10962 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10963 afsi_log("MsV1_0SetProcessOption success");
10965 /* END - code from Larry */
10967 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10968 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10969 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10971 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10973 /* something went wrong. We report the error and revert back to no authentication
10974 because we can't perform any auth requests without a successful lsa handle
10975 or sec package id. */
10976 afsi_log("Reverting to NO SMB AUTH");
10977 smb_authType = SMB_AUTH_NONE;
10980 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10982 /* something went wrong. We report the error and revert back to no authentication
10983 because we can't perform any auth requests without a successful lsa handle
10984 or sec package id. */
10985 afsi_log("Reverting to NO SMB AUTH");
10986 smb_authType = SMB_AUTH_NONE;
10990 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10991 * time prevents the failure of authentication when logged into Windows with an
10992 * external Kerberos principal mapped to a local account.
10994 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10995 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10996 * then the only option is NTLMSSP anyway; so just fallback.
11001 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
11002 if (secBlobLength == 0) {
11003 smb_authType = SMB_AUTH_NTLM;
11004 afsi_log("Reverting to SMB AUTH NTLM");
11013 /* Now get ourselves a domain name. */
11014 /* For now we are using the local computer name as the domain name.
11015 * It is actually the domain for local logins, and we are acting as
11016 * a local SMB server.
11018 bufsize = lengthof(smb_ServerDomainName) - 1;
11019 GetComputerNameW(smb_ServerDomainName, &bufsize);
11020 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
11021 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
11024 /* Start listeners, waiters, servers, and daemons */
11025 if (startListeners)
11026 smb_StartListeners(1);
11028 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
11029 NULL, 0, &lpid, "smb_ClientWaiter");
11030 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
11031 thrd_CloseHandle(phandle);
11033 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
11034 NULL, 0, &lpid, "smb_ServerWaiter");
11035 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
11036 thrd_CloseHandle(phandle);
11038 for (i=0; i<smb_NumServerThreads; i++) {
11039 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
11040 (void *) i, 0, &lpid, "smb_Server");
11041 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
11042 thrd_CloseHandle(phandle);
11045 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
11046 NULL, 0, &lpid, "smb_Daemon");
11047 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
11048 thrd_CloseHandle(phandle);
11050 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
11051 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
11052 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
11053 thrd_CloseHandle(phandle);
11055 if (smb_monitorReqs) {
11056 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
11057 NULL, 0, &lpid, "smb_ServerMonitor");
11058 osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
11059 thrd_CloseHandle(phandle);
11062 lock_ReleaseMutex(&smb_StartedLock);
11066 void smb_Shutdown(void)
11073 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11075 /* setup the NCB system */
11076 ncbp = smb_GetNCB();
11078 /* Block new sessions by setting shutdown flag */
11079 smbShutdownFlag = 1;
11081 /* Hang up all sessions */
11082 memset(ncbp, 0, sizeof(NCB));
11083 for (i = 1; i < numSessions; i++)
11085 if (dead_sessions[i])
11088 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11089 ncbp->ncb_command = NCBHANGUP;
11090 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
11091 ncbp->ncb_lsn = (UCHAR)LSNs[i];
11092 code = Netbios(ncbp);
11093 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11094 if (code == 0) code = ncbp->ncb_retcode;
11096 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11097 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11101 /* Trigger the shutdown of all SMB threads */
11102 for (i = 0; i < smb_NumServerThreads; i++)
11103 thrd_SetEvent(NCBreturns[i][0]);
11105 thrd_SetEvent(NCBevents[0]);
11106 thrd_SetEvent(SessionEvents[0]);
11107 thrd_SetEvent(NCBavails[0]);
11109 for (i = 0;i < smb_NumServerThreads; i++) {
11110 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11111 if (code == WAIT_OBJECT_0) {
11114 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11115 thrd_SetEvent(NCBreturns[i--][0]);
11119 /* Delete Netbios name */
11120 memset(ncbp, 0, sizeof(NCB));
11121 for (i = 0; i < lana_list.length; i++) {
11122 if (lana_list.lana[i] == LANA_INVALID) continue;
11123 ncbp->ncb_command = NCBDELNAME;
11124 ncbp->ncb_lana_num = lana_list.lana[i];
11125 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11126 code = Netbios(ncbp);
11128 code = ncbp->ncb_retcode;
11130 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11131 ncbp->ncb_lana_num, code);
11136 /* Release the reference counts held by the VCs */
11137 lock_ObtainWrite(&smb_rctLock);
11138 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11143 if (vcp->magic != SMB_VC_MAGIC)
11144 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11145 __FILE__, __LINE__);
11147 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11149 if (fidp->scp != NULL) {
11152 lock_ReleaseWrite(&smb_rctLock);
11153 lock_ObtainMutex(&fidp->mx);
11154 if (fidp->scp != NULL) {
11157 lock_ObtainWrite(&scp->rw);
11158 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11159 lock_ReleaseWrite(&scp->rw);
11160 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11161 cm_ReleaseSCache(scp);
11163 lock_ReleaseMutex(&fidp->mx);
11164 lock_ObtainWrite(&smb_rctLock);
11168 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11170 smb_ReleaseVCNoLock(tidp->vcp);
11172 cm_user_t *userp = tidp->userp;
11173 tidp->userp = NULL;
11174 cm_ReleaseUser(userp);
11178 lock_ReleaseWrite(&smb_rctLock);
11181 if (smb_monitorReqs) {
11182 smb_ShutdownMonitor();
11186 /* Get the UNC \\<servername>\<sharename> prefix. */
11187 char *smb_GetSharename()
11192 /* Make sure we have been properly initialized. */
11193 if (smb_localNamep == NULL)
11196 /* Allocate space for \\<servername>\<sharename>, plus the
11199 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11200 name = malloc(len);
11201 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11207 void smb_LogPacket(smb_packet_t *packet)
11211 unsigned length, paramlen, datalen, i, j;
11213 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11215 if (!packet) return;
11217 osi_Log0(smb_logp, "*** SMB packet dump ***");
11219 smbp = (smb_t *) packet->data;
11220 vp = (BYTE *) packet->data;
11222 paramlen = smbp->wct * 2;
11223 datalen = *((WORD *) (smbp->vdata + paramlen));
11224 length = sizeof(*smbp) + paramlen + 1 + datalen;
11226 for (i=0;i < length; i+=16)
11228 memset( buf, ' ', 80 );
11231 itoa( i, buf, 16 );
11233 buf[strlen(buf)] = ' ';
11235 cp = (BYTE*) buf + 7;
11237 for (j=0;j < 16 && (i+j)<length; j++)
11239 *(cp++) = hex[vp[i+j] >> 4];
11240 *(cp++) = hex[vp[i+j] & 0xf];
11250 for (j=0;j < 16 && (i+j)<length;j++)
11252 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11263 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11266 osi_Log0(smb_logp, "*** End SMB packet dump ***");
11268 #endif /* LOG_PACKET */
11271 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11277 smb_username_t *unp;
11278 smb_waitingLockRequest_t *wlrp;
11281 lock_ObtainRead(&smb_rctLock);
11283 sprintf(output, "begin dumping smb_username_t\r\n");
11284 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11285 for (unp = usernamesp; unp; unp=unp->nextp)
11287 cm_ucell_t *ucellp;
11289 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11290 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11291 unp->name ? unp->name : _C("NULL"),
11292 unp->machine ? unp->machine : _C("NULL"));
11293 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11295 sprintf(output, " begin dumping cm_ucell_t\r\n");
11296 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11298 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11299 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",
11300 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11301 ucellp->expirationTime, ucellp->gen,
11303 ucellp->cellp->name);
11304 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11307 sprintf(output, " done dumping cm_ucell_t\r\n");
11308 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11311 sprintf(output, "done dumping smb_username_t\r\n");
11312 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11315 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11316 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11319 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11320 smb_waitingLock_t *lockp;
11322 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11323 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11324 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11326 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
11327 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11328 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11329 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11330 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11331 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11333 sprintf(output, " done dumping smb_waitingLock_t\r\n");
11334 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11337 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11338 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11340 sprintf(output, "begin dumping smb_vc_t\r\n");
11341 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11343 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11349 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11350 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11351 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11353 sprintf(output, " begin dumping smb_user_t\r\n");
11354 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11355 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11356 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11357 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11358 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11360 sprintf(output, " done dumping smb_user_t\r\n");
11361 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11363 sprintf(output, " begin dumping smb_tid_t\r\n");
11364 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11365 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11366 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",
11367 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11368 tidp->pathname ? tidp->pathname : _C("NULL"));
11369 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11371 sprintf(output, " done dumping smb_tid_t\r\n");
11372 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11374 sprintf(output, " begin dumping smb_fid_t\r\n");
11375 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11377 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11379 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",
11380 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11381 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11382 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11383 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11386 sprintf(output, " done dumping smb_fid_t\r\n");
11387 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11390 sprintf(output, "done dumping smb_vc_t\r\n");
11391 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11393 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11394 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11396 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11402 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11403 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11404 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11406 sprintf(output, " begin dumping smb_user_t\r\n");
11407 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11408 for (userp = vcp->usersp; userp; userp = userp->nextp) {
11409 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11410 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11411 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11413 sprintf(output, " done dumping smb_user_t\r\n");
11414 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11416 sprintf(output, " begin dumping smb_tid_t\r\n");
11417 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11418 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11419 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",
11420 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11421 tidp->pathname ? tidp->pathname : _C("NULL"));
11422 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11424 sprintf(output, " done dumping smb_tid_t\r\n");
11425 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11427 sprintf(output, " begin dumping smb_fid_t\r\n");
11428 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11430 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11432 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",
11433 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11434 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11435 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11436 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11439 sprintf(output, " done dumping smb_fid_t\r\n");
11440 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11443 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11444 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11447 lock_ReleaseRead(&smb_rctLock);
11451 long smb_IsNetworkStarted(void)
11454 lock_ObtainWrite(&smb_globalLock);
11455 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11456 lock_ReleaseWrite(&smb_globalLock);