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)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
33 #include "lanahelper.h"
35 #define STRSAFE_NO_DEPRECATE
38 /* These characters are illegal in Windows filenames */
39 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
41 static int smbShutdownFlag = 0;
42 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
44 int smb_LogoffTokenTransfer;
45 time_t smb_LogoffTransferTimeout;
47 int smb_StoreAnsiFilenames = 0;
49 DWORD last_msg_time = 0;
53 unsigned int sessionGen = 0;
55 extern void afsi_log(char *pattern, ...);
56 extern HANDLE afsi_file;
57 extern int powerStateSuspended;
59 osi_hyper_t hzero = {0, 0};
60 osi_hyper_t hones = {0xFFFFFFFF, -1};
63 osi_rwlock_t smb_globalLock;
64 osi_rwlock_t smb_rctLock;
65 osi_mutex_t smb_ListenerLock;
66 osi_mutex_t smb_StartedLock;
68 unsigned char smb_LANadapter = LANA_INVALID;
69 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
70 int smb_LanAdapterChangeDetected = 0;
71 afs_uint32 smb_AsyncStore = 1;
72 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
74 BOOL isGateway = FALSE;
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
85 afs_uint32 smb_NumServerThreads;
87 afs_uint32 numNCBs, numSessions, numVCs;
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
92 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
94 ULONG smb_lsaSecPackage;
95 LSA_STRING smb_lsaLogonOrigin;
97 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
99 EVENT_HANDLE **NCBreturns;
100 EVENT_HANDLE **NCBShutdown;
101 EVENT_HANDLE *smb_ServerShutdown;
102 EVENT_HANDLE ListenerShutdown[256];
103 DWORD NCBsessions[NCB_MAX];
105 struct smb_packet *bufs[NCB_MAX];
107 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
108 EVENT_HANDLE SessionEvents[SESSION_MAX];
109 unsigned short LSNs[SESSION_MAX];
110 int lanas[SESSION_MAX];
111 BOOL dead_sessions[SESSION_MAX];
114 osi_mutex_t smb_RawBufLock;
117 #define SMB_MASKFLAG_TILDE 1
118 #define SMB_MASKFLAG_CASEFOLD 2
120 #define RAWTIMEOUT INFINITE
123 typedef struct raw_write_cont {
132 /* dir search stuff */
133 long smb_dirSearchCounter = 1;
134 smb_dirSearch_t *smb_firstDirSearchp;
135 smb_dirSearch_t *smb_lastDirSearchp;
137 /* Initial mode bits for files and directories. Set to 0 to use
139 int smb_unixModeDefaultFile = 0666;
140 int smb_unixModeDefaultDir = 0777;
142 /* hide dot files? */
143 int smb_hideDotFiles;
145 /* Negotiate Unicode support? */
148 /* global state about V3 protocols */
149 int smb_useV3; /* try to negotiate V3 */
151 static int showErrors = 0;
152 /* MessageBox or something like it */
153 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
157 * Time in Unix format of midnight, 1/1/1970 local time.
158 * When added to dosUTime, gives Unix (AFS) time.
160 time_t smb_localZero = 0;
162 char *smb_localNamep = NULL;
164 smb_vc_t *smb_allVCsp;
165 smb_vc_t *smb_deadVCsp;
167 smb_username_t *usernamesp = NULL;
169 smb_waitingLockRequest_t *smb_allWaitingLocks;
172 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
173 NCB *ncbp, raw_write_cont_t *rwcp);
174 int smb_NetbiosInit(int);
177 void smb_LogPacket(smb_packet_t *packet);
178 #endif /* LOG_PACKET */
180 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
181 int smb_ServerDomainNameLength = 0;
182 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
183 int smb_ServerOSLength = lengthof(smb_ServerOS);
184 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
185 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
187 /* Faux server GUID. This is never checked. */
188 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
190 void smb_InitReq(cm_req_t *reqp)
193 reqp->flags |= CM_REQ_SOURCE_SMB;
196 const char * ncb_error_string(int code)
200 case 0x01: s = "NRC_BUFLEN llegal buffer length"; break;
201 case 0x03: s = "NRC_ILLCMD illegal command"; break;
202 case 0x05: s = "NRC_CMDTMO command timed out"; break;
203 case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
204 case 0x07: s = "NRC_BADDR illegal buffer address"; break;
205 case 0x08: s = "NRC_SNUMOUT session number out of range"; break;
206 case 0x09: s = "NRC_NORES no resource available"; break;
207 case 0x0a: s = "NRC_SCLOSED asession closed"; break;
208 case 0x0b: s = "NRC_CMDCAN command cancelled"; break;
209 case 0x0d: s = "NRC_DUPNAME duplicate name"; break;
210 case 0x0e: s = "NRC_NAMTFUL name table full"; break;
211 case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
212 case 0x11: s = "NRC_LOCTFUL local session table full"; break;
213 case 0x12: s = "NRC_REMTFUL remote session table full"; break;
214 case 0x13: s = "NRC_ILLNN illegal name number"; break;
215 case 0x14: s = "NRC_NOCALL no callname"; break;
216 case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME"; break;
217 case 0x16: s = "NRC_INUSE name in use on remote adapter"; break;
218 case 0x17: s = "NRC_NAMERR name deleted"; break;
219 case 0x18: s = "NRC_SABORT session ended abnormally"; break;
220 case 0x19: s = "NRC_NAMCONF name conflict detected"; break;
221 case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying"; break;
222 case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
223 case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid"; break;
224 case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
225 case 0x26: s = "NRC_CANCEL command not valid to cancel"; break;
226 case 0x30: s = "NRC_DUPENV name defined by anther local process"; break;
227 case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required"; break;
228 case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted"; break;
229 case 0x36: s = "NRC_MAXAPPS max number of applications exceeded"; break;
230 case 0x37: s = "NRC_NOSAPS no saps available for netbios"; break;
231 case 0x38: s = "NRC_NORESOURCES requested resources are not available"; break;
232 case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment"; break;
233 case 0x3B: s = "NRC_INVDDID invalid NCB DDID"; break;
234 case 0x3C: s = "NRC_LOCKFAILlock of user area failed"; break;
235 case 0x3f: s = "NRC_OPENERR NETBIOS not loaded"; break;
236 case 0x40: s = "NRC_SYSTEM system error"; break;
237 default: s = "unknown error";
243 char * myCrt_Dispatch(int i)
248 return "(00)ReceiveCoreMakeDir";
250 return "(01)ReceiveCoreRemoveDir";
252 return "(02)ReceiveCoreOpen";
254 return "(03)ReceiveCoreCreate";
256 return "(04)ReceiveCoreClose";
258 return "(05)ReceiveCoreFlush";
260 return "(06)ReceiveCoreUnlink";
262 return "(07)ReceiveCoreRename";
264 return "(08)ReceiveCoreGetFileAttributes";
266 return "(09)ReceiveCoreSetFileAttributes";
268 return "(0a)ReceiveCoreRead";
270 return "(0b)ReceiveCoreWrite";
272 return "(0c)ReceiveCoreLockRecord";
274 return "(0d)ReceiveCoreUnlockRecord";
276 return "(0e)SendCoreBadOp";
278 return "(0f)ReceiveCoreCreate";
280 return "(10)ReceiveCoreCheckPath";
282 return "(11)SendCoreBadOp";
284 return "(12)ReceiveCoreSeek";
286 return "(1a)ReceiveCoreReadRaw";
288 return "(1d)ReceiveCoreWriteRawDummy";
290 return "(22)ReceiveV3SetAttributes";
292 return "(23)ReceiveV3GetAttributes";
294 return "(24)ReceiveV3LockingX";
296 return "(25)ReceiveV3Trans";
298 return "(26)ReceiveV3Trans[aux]";
300 return "(29)SendCoreBadOp";
302 return "(2b)ReceiveCoreEcho";
304 return "(2d)ReceiveV3OpenX";
306 return "(2e)ReceiveV3ReadX";
308 return "(2f)ReceiveV3WriteX";
310 return "(32)ReceiveV3Tran2A";
312 return "(33)ReceiveV3Tran2A[aux]";
314 return "(34)ReceiveV3FindClose";
316 return "(35)ReceiveV3FindNotifyClose";
318 return "(70)ReceiveCoreTreeConnect";
320 return "(71)ReceiveCoreTreeDisconnect";
322 return "(72)ReceiveNegotiate";
324 return "(73)ReceiveV3SessionSetupX";
326 return "(74)ReceiveV3UserLogoffX";
328 return "(75)ReceiveV3TreeConnectX";
330 return "(80)ReceiveCoreGetDiskAttributes";
332 return "(81)ReceiveCoreSearchDir";
336 return "(83)FindUnique";
338 return "(84)FindClose";
340 return "(A0)ReceiveNTTransact";
342 return "(A2)ReceiveNTCreateX";
344 return "(A4)ReceiveNTCancel";
346 return "(A5)ReceiveNTRename";
348 return "(C0)OpenPrintFile";
350 return "(C1)WritePrintFile";
352 return "(C2)ClosePrintFile";
354 return "(C3)GetPrintQueue";
356 return "(D8)ReadBulk";
358 return "(D9)WriteBulk";
360 return "(DA)WriteBulkData";
362 return "unknown SMB op";
366 char * myCrt_2Dispatch(int i)
371 return "unknown SMB op-2";
373 return "S(00)CreateFile_ReceiveTran2Open";
375 return "S(01)FindFirst_ReceiveTran2SearchDir";
377 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
379 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
381 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
383 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
385 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
387 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
389 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
391 return "S(09)_ReceiveTran2FSCTL";
393 return "S(0a)_ReceiveTran2IOCTL";
395 return "S(0b)_ReceiveTran2FindNotifyFirst";
397 return "S(0c)_ReceiveTran2FindNotifyNext";
399 return "S(0d)_ReceiveTran2CreateDirectory";
401 return "S(0e)_ReceiveTran2SessionSetup";
403 return "S(0f)_QueryFileSystemInformationFid";
405 return "S(10)_ReceiveTran2GetDfsReferral";
407 return "S(11)_ReceiveTran2ReportDfsInconsistency";
411 char * myCrt_RapDispatch(int i)
416 return "unknown RAP OP";
418 return "RAP(0)NetShareEnum";
420 return "RAP(1)NetShareGetInfo";
422 return "RAP(13)NetServerGetInfo";
424 return "RAP(63)NetWkStaGetInfo";
428 char * myCrt_NmpipeDispatch(int i)
431 case SMB_TRANS_SET_NMPIPE_STATE:
432 return "SET NMPIPE STATE";
434 case SMB_TRANS_RAW_READ_NMPIPE:
435 return "RAW READ NMPIPE";
437 case SMB_TRANS_QUERY_NMPIPE_STATE:
438 return "QUERY NMPIPE STATE";
440 case SMB_TRANS_QUERY_NMPIPE_INFO:
441 return "QUERY NMPIPE INFO";
443 case SMB_TRANS_PEEK_NMPIPE:
444 return "PEEK NMPIPE";
446 case SMB_TRANS_TRANSACT_NMPIPE:
447 return "TRANSACT NMPIPE";
449 case SMB_TRANS_RAW_WRITE_NMPIPE:
450 return "WRITE NMPIPE";
452 case SMB_TRANS_READ_NMPIPE:
453 return "READ NMPIPE";
455 case SMB_TRANS_WRITE_NMPIPE:
456 return "WRITE NMPIPE";
458 case SMB_TRANS_WAIT_NMPIPE:
459 return "WAIT NMPIPE";
461 case SMB_TRANS_CALL_NMPIPE:
462 return "CALL NMPIPE";
467 /* scache must be locked */
468 unsigned int smb_Attributes(cm_scache_t *scp)
472 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
473 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
474 scp->fileType == CM_SCACHETYPE_INVALID)
476 attrs = SMB_ATTR_DIRECTORY;
477 #ifdef SPECIAL_FOLDERS
478 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
479 #endif /* SPECIAL_FOLDERS */
480 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
481 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
486 * We used to mark a file RO if it was in an RO volume, but that
487 * turns out to be impolitic in NT. See defect 10007.
490 if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
491 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
493 if ((scp->unixModeBits & 0200) == 0)
494 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
500 void smb_SetInitialModeBitsForFile(int smb_attr, cm_attr_t * attr)
502 if (smb_unixModeDefaultFile != 0) {
503 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
504 attr->unixModeBits = smb_unixModeDefaultFile;
505 if (smb_attr & SMB_ATTR_READONLY)
506 attr->unixModeBits &= ~0222;
510 void smb_SetInitialModeBitsForDir(int smb_attr, cm_attr_t * attr)
512 if (smb_unixModeDefaultDir != 0) {
513 attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
514 attr->unixModeBits = smb_unixModeDefaultDir;
518 /* Check if the named file/dir is a dotfile/dotdir */
519 /* String pointed to by lastComp can have leading slashes, but otherwise should have
520 no other patch components */
521 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
525 /* skip over slashes */
526 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
531 /* nulls, curdir and parent dir doesn't count */
537 if(*(s+1) == _C('.') && !*(s + 2))
544 static int ExtractBits(WORD bits, short start, short len)
551 num = bits << (16 - end);
552 num = num >> ((16 - end) + start);
557 void ShowUnixTime(char *FuncName, time_t unixTime)
562 cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
564 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
565 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
567 int day, month, year, sec, min, hour;
570 day = ExtractBits(wDate, 0, 5);
571 month = ExtractBits(wDate, 5, 4);
572 year = ExtractBits(wDate, 9, 7) + 1980;
574 sec = ExtractBits(wTime, 0, 5);
575 min = ExtractBits(wTime, 5, 6);
576 hour = ExtractBits(wTime, 11, 5);
578 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
579 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
583 /* Determine if we are observing daylight savings time */
584 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
586 TIME_ZONE_INFORMATION timeZoneInformation;
587 SYSTEMTIME utc, local, localDST;
589 /* Get the time zone info. NT uses this to calc if we are in DST. */
590 GetTimeZoneInformation(&timeZoneInformation);
592 /* Return the daylight bias */
593 *pDstBias = timeZoneInformation.DaylightBias;
595 /* Return the bias */
596 *pBias = timeZoneInformation.Bias;
598 /* Now determine if DST is being observed */
600 /* Get the UTC (GMT) time */
603 /* Convert UTC time to local time using the time zone info. If we are
604 observing DST, the calculated local time will include this.
606 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
608 /* Set the daylight bias to 0. The daylight bias is the amount of change
609 * in time that we use for daylight savings time. By setting this to 0
610 * we cause there to be no change in time during daylight savings time.
612 timeZoneInformation.DaylightBias = 0;
614 /* Convert the utc time to local time again, but this time without any
615 adjustment for daylight savings time.
617 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
619 /* If the two times are different, then it means that the localDST that
620 we calculated includes the daylight bias, and therefore we are
621 observing daylight savings time.
623 *pDST = localDST.wHour != local.wHour;
627 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
629 BOOL dst; /* Will be TRUE if observing DST */
630 LONG dstBias; /* Offset from local time if observing DST */
631 LONG bias; /* Offset from GMT for local time */
634 * This function will adjust the last write time to compensate
635 * for two bugs in the smb client:
637 * 1) During Daylight Savings Time, the LastWriteTime is ahead
638 * in time by the DaylightBias (ignoring the sign - the
639 * DaylightBias is always stored as a negative number). If
640 * the DaylightBias is -60, then the LastWriteTime will be
641 * ahead by 60 minutes.
643 * 2) If the local time zone is a positive offset from GMT, then
644 * the LastWriteTime will be the correct local time plus the
645 * Bias (ignoring the sign - a positive offset from GMT is
646 * always stored as a negative Bias). If the Bias is -120,
647 * then the LastWriteTime will be ahead by 120 minutes.
649 * These bugs can occur at the same time.
652 GetTimeZoneInfo(&dst, &dstBias, &bias);
654 /* First adjust for DST */
656 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
658 /* Now adjust for a positive offset from GMT (a negative bias). */
660 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
663 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
665 time_t diff_t = unixTime - smb_localZero;
666 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
667 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
669 *dosUTimep = (afs_uint32)diff_t;
672 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
674 *unixTimep = dosTime + smb_localZero;
677 void smb_MarkAllVCsDead(smb_vc_t * exclude)
680 smb_vc_t **vcp_to_cleanup = NULL;
681 int n_to_cleanup = 0;
684 osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
686 lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
687 lock_ObtainWrite(&smb_rctLock);
688 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
690 if (vcp->magic != SMB_VC_MAGIC)
691 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
697 lock_ObtainMutex(&vcp->mx);
698 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
699 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
700 lock_ReleaseMutex(&vcp->mx);
701 dead_sessions[vcp->session] = TRUE;
703 lock_ReleaseMutex(&vcp->mx);
708 vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
710 for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
714 vcp_to_cleanup[i++] = vcp;
715 smb_HoldVCNoLock(vcp);
718 osi_assert(i == n_to_cleanup);
720 lock_ReleaseWrite(&smb_rctLock);
721 lock_ReleaseWrite(&smb_globalLock);
723 for (i=0; i < n_to_cleanup; i++) {
724 smb_CleanupDeadVC(vcp_to_cleanup[i]);
725 smb_ReleaseVC(vcp_to_cleanup[i]);
726 vcp_to_cleanup[i] = 0;
729 free(vcp_to_cleanup);
732 #ifdef DEBUG_SMB_REFCOUNT
733 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
735 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
740 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
741 lock_ObtainWrite(&smb_rctLock);
742 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
743 if (vcp->magic != SMB_VC_MAGIC)
744 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
747 lock_ObtainMutex(&vcp->mx);
748 if (lsn == vcp->lsn && lana == vcp->lana &&
749 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
750 lock_ReleaseMutex(&vcp->mx);
751 smb_HoldVCNoLock(vcp);
754 lock_ReleaseMutex(&vcp->mx);
756 if (!vcp && (flags & SMB_FLAG_CREATE)) {
757 vcp = malloc(sizeof(*vcp));
758 memset(vcp, 0, sizeof(*vcp));
759 vcp->vcID = ++numVCs;
760 vcp->magic = SMB_VC_MAGIC;
761 vcp->refCount = 2; /* smb_allVCsp and caller */
764 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
765 vcp->nextp = smb_allVCsp;
767 lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
772 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
773 /* We must obtain a challenge for extended auth
774 * in case the client negotiates smb v3
776 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
777 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
778 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
779 ULONG lsaRespSize = 0;
781 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
783 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
790 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
791 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
792 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
793 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
794 nts, ntsEx, lsaRespSize);
796 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
798 if (ntsEx == STATUS_SUCCESS) {
799 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
802 * This will cause the subsequent authentication to fail but
803 * that is better than us dereferencing a NULL pointer and
806 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
809 LsaFreeReturnBuffer(lsaResp);
812 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
814 if (numVCs >= CM_SESSION_RESERVED) {
816 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
819 #ifdef DEBUG_SMB_REFCOUNT
821 afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
822 osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
825 lock_ReleaseWrite(&smb_rctLock);
826 lock_ReleaseWrite(&smb_globalLock);
830 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
835 for(i=0; i<11; i++) {
837 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
843 static int smb_IsStarMask(clientchar_t *maskp)
849 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
855 #ifdef DEBUG_SMB_REFCOUNT
856 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
857 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
859 void smb_ReleaseVCInternal(smb_vc_t *vcp)
865 lock_AssertWrite(&smb_rctLock);
868 if (vcp->refCount == 0) {
869 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
870 #ifdef DEBUG_SMB_REFCOUNT
871 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
872 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
874 /* remove VCP from smb_deadVCsp */
875 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
881 lock_FinalizeMutex(&vcp->mx);
882 memset(vcp,0,sizeof(smb_vc_t));
885 #ifdef DEBUG_SMB_REFCOUNT
886 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
888 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
892 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
893 avcp?"":"not ",vcp, vcp->refCount);
895 /* This is a wrong. However, I suspect that there is an undercount
896 * and I don't want to release 1.4.1 in a state that will allow
897 * smb_vc_t objects to be deallocated while still in the
898 * smb_allVCsp list. The list is supposed to keep a reference
899 * to the smb_vc_t. Put it back.
903 #ifdef DEBUG_SMB_REFCOUNT
904 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
905 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
909 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
910 /* The reference count is non-zero but the VC is dead.
911 * This implies that some FIDs, TIDs, etc on the VC have yet to
912 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
913 * add a reference that will be dropped by
914 * smb_CleanupDeadVC() and try to cleanup the VC again.
915 * Eventually the refCount will drop to zero when all of the
916 * active threads working with the VC end their task.
918 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
919 vcp->refCount++; /* put the refCount back */
920 lock_ReleaseWrite(&smb_rctLock);
921 smb_CleanupDeadVC(vcp);
922 #ifdef DEBUG_SMB_REFCOUNT
923 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
924 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
926 lock_ObtainWrite(&smb_rctLock);
929 #ifdef DEBUG_SMB_REFCOUNT
930 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
931 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
936 #ifdef DEBUG_SMB_REFCOUNT
937 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
939 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
942 lock_AssertWrite(&smb_rctLock);
943 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
944 smb_ReleaseVCInternal(vcp);
947 #ifdef DEBUG_SMB_REFCOUNT
948 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
950 void smb_ReleaseVC(smb_vc_t *vcp)
953 lock_ObtainWrite(&smb_rctLock);
954 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
955 smb_ReleaseVCInternal(vcp);
956 lock_ReleaseWrite(&smb_rctLock);
959 #ifdef DEBUG_SMB_REFCOUNT
960 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
962 void smb_HoldVCNoLock(smb_vc_t *vcp)
965 lock_AssertWrite(&smb_rctLock);
967 #ifdef DEBUG_SMB_REFCOUNT
968 afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
969 osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
971 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
975 #ifdef DEBUG_SMB_REFCOUNT
976 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
978 void smb_HoldVC(smb_vc_t *vcp)
981 lock_ObtainWrite(&smb_rctLock);
983 #ifdef DEBUG_SMB_REFCOUNT
984 afsi_log("%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
985 osi_Log4(smb_logp,"%s:%d smb_HoldVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
987 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
989 lock_ReleaseWrite(&smb_rctLock);
992 void smb_CleanupDeadVC(smb_vc_t *vcp)
1000 smb_user_t *uidpIter;
1001 smb_user_t *uidpNext;
1003 afs_uint32 refCount = 0;
1005 lock_ObtainMutex(&vcp->mx);
1006 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1007 lock_ReleaseMutex(&vcp->mx);
1008 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1011 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1012 lock_ReleaseMutex(&vcp->mx);
1013 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1015 lock_ObtainWrite(&smb_rctLock);
1016 /* remove VCP from smb_allVCsp */
1017 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1018 if ((*vcpp)->magic != SMB_VC_MAGIC)
1019 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1020 __FILE__, __LINE__);
1023 vcp->nextp = smb_deadVCsp;
1025 /* Hold onto the reference until we are done with this function */
1030 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1031 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1033 if (fidpIter->deleteOk)
1036 fid = fidpIter->fid;
1037 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1039 smb_HoldFIDNoLock(fidpIter);
1040 lock_ReleaseWrite(&smb_rctLock);
1042 smb_CloseFID(vcp, fidpIter, NULL, 0);
1043 smb_ReleaseFID(fidpIter);
1045 lock_ObtainWrite(&smb_rctLock);
1046 fidpNext = vcp->fidsp;
1049 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1050 tidpNext = tidpIter->nextp;
1051 if (tidpIter->deleteOk)
1053 tidpIter->deleteOk = 1;
1055 tid = tidpIter->tid;
1056 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1058 smb_HoldTIDNoLock(tidpIter);
1059 smb_ReleaseTID(tidpIter, TRUE);
1060 tidpNext = vcp->tidsp;
1063 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1064 uidpNext = uidpIter->nextp;
1065 if (uidpIter->deleteOk)
1067 uidpIter->deleteOk = 1;
1069 /* do not add an additional reference count for the smb_user_t
1070 * as the smb_vc_t already is holding a reference */
1071 lock_ReleaseWrite(&smb_rctLock);
1073 smb_ReleaseUID(uidpIter);
1075 lock_ObtainWrite(&smb_rctLock);
1076 uidpNext = vcp->usersp;
1079 /* The vcp is now on the deadVCsp list. We intentionally drop the
1080 * reference so that the refcount can reach 0 and we can delete it
1082 * If the refCount == 1 going into the ReleaseVCNoLock call
1083 * the object will be freed and it won't be safe to clear
1086 refCount = vcp->refCount;
1087 smb_ReleaseVCNoLock(vcp);
1089 lock_ObtainMutex(&vcp->mx);
1090 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1091 lock_ReleaseMutex(&vcp->mx);
1094 lock_ReleaseWrite(&smb_rctLock);
1095 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1098 #ifdef DEBUG_SMB_REFCOUNT
1099 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1101 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1106 lock_ObtainWrite(&smb_rctLock);
1108 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1109 if (tidp->refCount == 0 && tidp->deleteOk) {
1111 smb_ReleaseTID(tidp, TRUE);
1115 if (tid == tidp->tid) {
1120 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1121 tidp = malloc(sizeof(*tidp));
1122 memset(tidp, 0, sizeof(*tidp));
1123 tidp->nextp = vcp->tidsp;
1126 smb_HoldVCNoLock(vcp);
1128 lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1131 #ifdef DEBUG_SMB_REFCOUNT
1133 afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1134 osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1137 lock_ReleaseWrite(&smb_rctLock);
1141 #ifdef DEBUG_SMB_REFCOUNT
1142 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1144 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1147 lock_AssertWrite(&smb_rctLock);
1149 #ifdef DEBUG_SMB_REFCOUNT
1150 afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1151 osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1155 #ifdef DEBUG_SMB_REFCOUNT
1156 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1158 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1163 cm_user_t *userp = NULL;
1164 smb_vc_t *vcp = NULL;
1167 lock_ObtainWrite(&smb_rctLock);
1169 lock_AssertWrite(&smb_rctLock);
1171 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1172 #ifdef DEBUG_SMB_REFCOUNT
1173 afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1174 osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1176 if (tidp->refCount == 0) {
1177 if (tidp->deleteOk) {
1178 ltpp = &tidp->vcp->tidsp;
1179 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1183 osi_assertx(tp != NULL, "null smb_tid_t");
1185 lock_FinalizeMutex(&tidp->mx);
1186 userp = tidp->userp; /* remember to drop ref later */
1194 smb_ReleaseVCNoLock(vcp);
1196 lock_ReleaseWrite(&smb_rctLock);
1198 cm_ReleaseUser(userp);
1201 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1203 smb_user_t *uidp = NULL;
1205 lock_ObtainWrite(&smb_rctLock);
1206 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1207 if (uid == uidp->userID) {
1209 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1211 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1215 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1216 uidp = malloc(sizeof(*uidp));
1217 memset(uidp, 0, sizeof(*uidp));
1218 uidp->nextp = vcp->usersp;
1219 uidp->refCount = 2; /* one for the vcp and one for the caller */
1221 smb_HoldVCNoLock(vcp);
1223 lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1225 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1227 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1229 lock_ReleaseWrite(&smb_rctLock);
1233 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1236 smb_username_t *unp= NULL;
1238 lock_ObtainWrite(&smb_rctLock);
1239 for(unp = usernamesp; unp; unp = unp->nextp) {
1240 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1241 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1246 if (!unp && (flags & SMB_FLAG_CREATE)) {
1247 unp = malloc(sizeof(*unp));
1248 memset(unp, 0, sizeof(*unp));
1250 unp->nextp = usernamesp;
1251 unp->name = cm_ClientStrDup(usern);
1252 unp->machine = cm_ClientStrDup(machine);
1254 lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1255 if (flags & SMB_FLAG_AFSLOGON)
1256 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1259 lock_ReleaseWrite(&smb_rctLock);
1263 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1265 smb_user_t *uidp= NULL;
1267 lock_ObtainWrite(&smb_rctLock);
1268 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1271 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1273 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1274 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1279 lock_ReleaseWrite(&smb_rctLock);
1283 void smb_ReleaseUsername(smb_username_t *unp)
1286 smb_username_t **lupp;
1287 cm_user_t *userp = NULL;
1288 time_t now = osi_Time();
1290 lock_ObtainWrite(&smb_rctLock);
1291 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1292 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1293 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1295 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1299 osi_assertx(up != NULL, "null smb_username_t");
1301 up->nextp = NULL; /* do not remove this */
1302 lock_FinalizeMutex(&unp->mx);
1308 lock_ReleaseWrite(&smb_rctLock);
1310 cm_ReleaseUser(userp);
1313 void smb_HoldUIDNoLock(smb_user_t *uidp)
1315 lock_AssertWrite(&smb_rctLock);
1319 void smb_ReleaseUID(smb_user_t *uidp)
1323 smb_username_t *unp = NULL;
1325 lock_ObtainWrite(&smb_rctLock);
1326 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1327 if (uidp->refCount == 0) {
1328 lupp = &uidp->vcp->usersp;
1329 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1333 osi_assertx(up != NULL, "null smb_user_t");
1335 lock_FinalizeMutex(&uidp->mx);
1337 smb_ReleaseVCNoLock(uidp->vcp);
1341 lock_ReleaseWrite(&smb_rctLock);
1345 cm_ReleaseUserVCRef(unp->userp);
1346 smb_ReleaseUsername(unp);
1350 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1352 cm_user_t *up = NULL;
1357 lock_ObtainMutex(&uidp->mx);
1359 up = uidp->unp->userp;
1362 lock_ReleaseMutex(&uidp->mx);
1368 /* retrieve a held reference to a user structure corresponding to an incoming
1370 * corresponding release function is cm_ReleaseUser.
1372 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1375 cm_user_t *up = NULL;
1378 smbp = (smb_t *) inp;
1379 uidp = smb_FindUID(vcp, smbp->uid, 0);
1383 up = smb_GetUserFromUID(uidp);
1385 smb_ReleaseUID(uidp);
1390 * Return a pointer to a pathname extracted from a TID structure. The
1391 * TID structure is not held; assume it won't go away.
1393 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1398 tidp = smb_FindTID(vcp, tid, 0);
1402 if (tidp->flags & SMB_TIDFLAG_IPC) {
1403 code = CM_ERROR_TIDIPC;
1404 /* tidp->pathname would be NULL, but that's fine */
1406 *treepath = tidp->pathname;
1407 smb_ReleaseTID(tidp, FALSE);
1412 /* check to see if we have a chained fid, that is, a fid that comes from an
1413 * OpenAndX message that ran earlier in this packet. In this case, the fid
1414 * field in a read, for example, request, isn't set, since the value is
1415 * supposed to be inherited from the openAndX call.
1417 int smb_ChainFID(int fid, smb_packet_t *inp)
1419 if (inp->fid == 0 || inp->inCount == 0)
1425 /* are we a priv'd user? What does this mean on NT? */
1426 int smb_SUser(cm_user_t *userp)
1431 /* find a file ID. If we pass in 0 we select an unused File ID.
1432 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1433 * smb_fid_t data structure if desired File ID cannot be found.
1435 #ifdef DEBUG_SMB_REFCOUNT
1436 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1438 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1445 if (!(flags & SMB_FLAG_CREATE))
1450 lock_ObtainWrite(&smb_rctLock);
1452 fid = vcp->fidCounter;
1455 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1456 if (fidp->refCount == 0 && fidp->deleteOk) {
1458 lock_ReleaseWrite(&smb_rctLock);
1459 smb_ReleaseFID(fidp);
1460 lock_ObtainWrite(&smb_rctLock);
1462 * We dropped the smb_rctLock so the fid value we are using
1463 * may now be used by another thread. Start over with the
1464 * current vcp->fidCounter.
1467 fid = vcp->fidCounter;
1470 if (fid == fidp->fid) {
1472 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. fid %d found -- retrying ...", fid);
1474 if (fid == 0xFFFF) {
1476 "New FID number wraps on vcp 0x%x", vcp);
1486 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1487 char eventName[MAX_PATH];
1491 osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1493 osi_Log1(smb_logp, "smb_FindFID New Fid Requested. Creating fid %d", fid);
1495 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1496 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1497 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1498 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1499 thrd_CloseHandle(event);
1501 if (fid == 0xFFFF) {
1502 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1508 fidp = malloc(sizeof(*fidp));
1509 memset(fidp, 0, sizeof(*fidp));
1510 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1513 smb_HoldVCNoLock(vcp);
1514 lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1516 fidp->curr_chunk = fidp->prev_chunk = -2;
1517 fidp->raw_write_event = event;
1519 vcp->fidCounter = fid+1;
1520 if (vcp->fidCounter == 0xFFFF) {
1521 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1523 vcp->fidCounter = 1;
1528 #ifdef DEBUG_SMB_REFCOUNT
1530 afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1531 osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1534 lock_ReleaseWrite(&smb_rctLock);
1539 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1540 #ifdef DEBUG_SMB_REFCOUNT
1541 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1543 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1546 smb_fid_t *fidp = NULL, *nextp = NULL;
1552 * If the fidp->scp changes out from under us then
1553 * we must not grab a refCount. It means the *fidp
1554 * was processed by smb_CloseFID() and the *fidp is
1555 * no longer valid for use.
1557 lock_ObtainWrite(&smb_rctLock);
1558 for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1559 nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1563 if (scp == fidp->scp) {
1564 lock_ReleaseWrite(&smb_rctLock);
1565 lock_ObtainMutex(&fidp->mx);
1566 lock_ObtainWrite(&smb_rctLock);
1567 if (scp == fidp->scp) {
1568 lock_ReleaseMutex(&fidp->mx);
1571 lock_ReleaseMutex(&fidp->mx);
1574 if (fidp->refCount > 1) {
1577 lock_ReleaseWrite(&smb_rctLock);
1578 smb_ReleaseFID(fidp);
1579 lock_ObtainWrite(&smb_rctLock);
1584 if (nextp->refCount > 1) {
1587 lock_ReleaseWrite(&smb_rctLock);
1588 smb_ReleaseFID(nextp);
1589 lock_ObtainWrite(&smb_rctLock);
1593 #ifdef DEBUG_SMB_REFCOUNT
1595 afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1596 osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1599 lock_ReleaseWrite(&smb_rctLock);
1603 #ifdef DEBUG_SMB_REFCOUNT
1604 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1606 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1609 lock_AssertWrite(&smb_rctLock);
1611 #ifdef DEBUG_SMB_REFCOUNT
1612 afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1613 osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1618 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1619 /* the smb_fid_t->mx and smb_rctLock must not be held */
1620 #ifdef DEBUG_SMB_REFCOUNT
1621 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1623 void smb_ReleaseFID(smb_fid_t *fidp)
1626 cm_scache_t *scp = NULL;
1627 cm_user_t *userp = NULL;
1628 smb_vc_t *vcp = NULL;
1629 smb_ioctl_t *ioctlp;
1631 lock_ObtainMutex(&fidp->mx);
1632 lock_ObtainWrite(&smb_rctLock);
1633 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1634 #ifdef DEBUG_SMB_REFCOUNT
1635 afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1636 osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1638 if (fidp->refCount == 0) {
1639 if (fidp->deleteOk) {
1642 scp = fidp->scp; /* release after lock is released */
1644 lock_ObtainWrite(&scp->rw);
1645 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1646 lock_ReleaseWrite(&scp->rw);
1647 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1650 userp = fidp->userp;
1654 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1655 thrd_CloseHandle(fidp->raw_write_event);
1657 /* and see if there is ioctl stuff to free */
1658 ioctlp = fidp->ioctlp;
1661 cm_FreeSpace(ioctlp->prefix);
1662 if (ioctlp->ioctl.inAllocp)
1663 free(ioctlp->ioctl.inAllocp);
1664 if (ioctlp->ioctl.outAllocp)
1665 free(ioctlp->ioctl.outAllocp);
1669 smb_CleanupRPCFid(fidp);
1671 lock_ReleaseMutex(&fidp->mx);
1672 lock_FinalizeMutex(&fidp->mx);
1677 smb_ReleaseVCNoLock(vcp);
1681 lock_ReleaseMutex(&fidp->mx);
1683 lock_ReleaseWrite(&smb_rctLock);
1685 /* now release the scache structure */
1687 cm_ReleaseSCache(scp);
1690 cm_ReleaseUser(userp);
1694 * Case-insensitive search for one string in another;
1695 * used to find variable names in submount pathnames.
1697 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1699 clientchar_t *cursor;
1701 for (cursor = str1; *cursor; cursor++)
1702 if (cm_ClientStrCmpI(cursor, str2) == 0)
1709 * Substitute a variable value for its name in a submount pathname. Variable
1710 * name has been identified by smb_stristr() and is in substr. Variable name
1711 * length (plus one) is in substr_size. Variable value is in newstr.
1713 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1714 unsigned int substr_size, clientchar_t *newstr)
1716 clientchar_t temp[1024];
1718 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1719 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1720 cm_ClientStrCat(str1, cchstr1, temp);
1723 clientchar_t VNUserName[] = _C("%USERNAME%");
1724 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1725 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1726 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1728 typedef struct smb_findShare_rock {
1729 clientchar_t * shareName;
1730 clientchar_t * match;
1732 } smb_findShare_rock_t;
1734 #define SMB_FINDSHARE_EXACT_MATCH 1
1735 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1737 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1741 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1742 normchar_t normName[MAX_PATH];
1744 if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1745 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1746 osi_LogSaveString(smb_logp, dep->name));
1750 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1751 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1752 matchType = SMB_FINDSHARE_EXACT_MATCH;
1754 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1757 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1758 vrock->matchType = matchType;
1760 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1761 return CM_ERROR_STOPNOW;
1767 /* find a shareName in the table of submounts */
1768 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1769 clientchar_t *shareName,
1770 clientchar_t **pathNamep)
1774 clientchar_t pathName[1024];
1777 clientchar_t *p, *q;
1778 fschar_t *cellname = NULL;
1781 DWORD allSubmount = 1;
1783 /* if allSubmounts == 0, only return the //mountRoot/all share
1784 * if in fact it has been been created in the subMounts table.
1785 * This is to allow sites that want to restrict access to the
1788 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1789 0, KEY_QUERY_VALUE, &parmKey);
1790 if (code == ERROR_SUCCESS) {
1791 cblen = sizeof(allSubmount);
1792 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1793 (BYTE *) &allSubmount, &cblen);
1794 if (code != ERROR_SUCCESS) {
1797 RegCloseKey (parmKey);
1800 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1805 /* In case, the all share is disabled we need to still be able
1806 * to handle ioctl requests
1808 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1809 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1813 if (MSRPC_IsWellKnownService(shareName) ||
1814 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1815 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1821 /* Check for volume references
1823 * They look like <cell>{%,#}<volume>
1825 if (cm_ClientStrChr(shareName, '%') != NULL ||
1826 cm_ClientStrChr(shareName, '#') != NULL) {
1827 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1828 /* make room for '/@vol:' + mountchar + NULL terminator*/
1830 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1831 osi_LogSaveClientString(smb_logp, shareName));
1833 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1834 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1835 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1837 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1839 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1840 cm_ClientStrLwr(*pathNamep);
1841 osi_Log1(smb_logp, " returning pathname [%S]",
1842 osi_LogSaveClientString(smb_logp, *pathNamep));
1850 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1851 0, KEY_QUERY_VALUE, &parmKey);
1852 if (code == ERROR_SUCCESS) {
1853 cblen = sizeof(pathName);
1854 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1855 (BYTE *) pathName, &cblen);
1856 if (code != ERROR_SUCCESS)
1858 RegCloseKey (parmKey);
1862 cchlen = cblen / sizeof(clientchar_t);
1863 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1864 /* We can accept either unix or PC style AFS pathnames. Convert
1865 * Unix-style to PC style here for internal use.
1868 cchlen = lengthof(pathName);
1870 /* within this code block, we maintain, cchlen = writeable
1871 buffer length of p */
1873 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1874 p += cm_mountRootCLen; /* skip mount path */
1875 cchlen -= (DWORD)(p - pathName);
1880 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1886 clientchar_t temp[1024];
1888 if (var = smb_stristr(p, VNUserName)) {
1889 if (uidp && uidp->unp)
1890 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1892 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1894 else if (var = smb_stristr(p, VNLCUserName))
1896 if (uidp && uidp->unp)
1897 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1899 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1900 cm_ClientStrLwr(temp);
1901 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1903 else if (var = smb_stristr(p, VNComputerName))
1905 sizeTemp = lengthof(temp);
1906 GetComputerNameW(temp, &sizeTemp);
1907 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1909 else if (var = smb_stristr(p, VNLCComputerName))
1911 sizeTemp = lengthof(temp);
1912 GetComputerName((LPTSTR)temp, &sizeTemp);
1913 cm_ClientStrLwr(temp);
1914 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1919 *pathNamep = cm_ClientStrDup(p);
1924 /* First lookup shareName in root.afs */
1926 smb_findShare_rock_t vrock;
1928 fschar_t ftemp[1024];
1929 clientchar_t * p = shareName;
1932 /* attempt to locate a partial match in root.afs. This is because
1933 when using the ANSI RAP calls, the share name is limited to 13 chars
1934 and hence is truncated. Of course we prefer exact matches. */
1936 thyper.HighPart = 0;
1939 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1940 if (vrock.shareName == NULL)
1943 vrock.matchType = 0;
1945 cm_HoldSCache(cm_data.rootSCachep);
1946 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1947 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1948 cm_ReleaseSCache(cm_data.rootSCachep);
1950 free(vrock.shareName);
1951 vrock.shareName = NULL;
1953 if (vrock.matchType) {
1954 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1955 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1960 /* if we get here, there was no match for the share in root.afs */
1961 /* so try to create \\<netbiosName>\<cellname> */
1966 /* Get the full name for this cell */
1967 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1968 code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
1969 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
1970 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1971 if (code && cm_dnsEnabled) {
1973 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1978 /* construct the path */
1980 clientchar_t temp[1024];
1982 if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
1983 cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
1984 rw ? _C("/.%S/") : _C("/%S/"), temp);
1985 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1995 /* Client-side offline caching policy types */
1996 #define CSC_POLICY_MANUAL 0
1997 #define CSC_POLICY_DOCUMENTS 1
1998 #define CSC_POLICY_PROGRAMS 2
1999 #define CSC_POLICY_DISABLE 3
2001 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2004 clientchar_t policy[1024];
2007 int retval = CSC_POLICY_MANUAL;
2009 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2010 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2013 REG_OPTION_NON_VOLATILE,
2017 NULL ) != ERROR_SUCCESS)
2018 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2020 len = sizeof(policy);
2021 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2023 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2025 else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2027 retval = CSC_POLICY_MANUAL;
2029 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2031 retval = CSC_POLICY_DOCUMENTS;
2033 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2035 retval = CSC_POLICY_PROGRAMS;
2037 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2039 retval = CSC_POLICY_DISABLE;
2042 RegCloseKey(hkCSCPolicy);
2046 /* find a dir search structure by cookie value, and return it held.
2047 * Must be called with smb_globalLock held.
2049 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2051 smb_dirSearch_t *dsp;
2053 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2054 if (dsp->cookie == cookie) {
2055 if (dsp != smb_firstDirSearchp) {
2056 /* move to head of LRU queue, too, if we're not already there */
2057 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2058 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2059 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2060 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2061 if (!smb_lastDirSearchp)
2062 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2070 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2071 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2072 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2078 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2080 lock_ObtainMutex(&dsp->mx);
2081 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2082 dsp->cookie, dsp, dsp->scp);
2083 dsp->flags |= SMB_DIRSEARCH_DELETE;
2084 if (dsp->scp != NULL) {
2085 lock_ObtainWrite(&dsp->scp->rw);
2086 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2087 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2088 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2089 dsp->scp->bulkStatProgress = hzero;
2091 lock_ReleaseWrite(&dsp->scp->rw);
2093 lock_ReleaseMutex(&dsp->mx);
2096 /* Must be called with the smb_globalLock held */
2097 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2099 cm_scache_t *scp = NULL;
2101 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2102 if (dsp->refCount == 0) {
2103 lock_ObtainMutex(&dsp->mx);
2104 if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2105 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2106 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2107 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2108 lock_ReleaseMutex(&dsp->mx);
2109 lock_FinalizeMutex(&dsp->mx);
2111 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2112 dsp->cookie, dsp, scp);
2115 lock_ReleaseMutex(&dsp->mx);
2118 /* do this now to avoid spurious locking hierarchy creation */
2120 cm_ReleaseSCache(scp);
2123 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2125 lock_ObtainWrite(&smb_globalLock);
2126 smb_ReleaseDirSearchNoLock(dsp);
2127 lock_ReleaseWrite(&smb_globalLock);
2130 /* find a dir search structure by cookie value, and return it held */
2131 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2133 smb_dirSearch_t *dsp;
2135 lock_ObtainWrite(&smb_globalLock);
2136 dsp = smb_FindDirSearchNoLock(cookie);
2137 lock_ReleaseWrite(&smb_globalLock);
2141 /* GC some dir search entries, in the address space expected by the specific protocol.
2142 * Must be called with smb_globalLock held; release the lock temporarily.
2144 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2145 void smb_GCDirSearches(int isV3)
2147 smb_dirSearch_t *prevp;
2148 smb_dirSearch_t *dsp;
2149 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2153 victimCount = 0; /* how many have we got so far */
2154 for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2155 /* we'll move tp from queue, so
2158 prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2159 /* if no one is using this guy, and we're either in the new protocol,
2160 * or we're in the old one and this is a small enough ID to be useful
2161 * to the old protocol, GC this guy.
2163 if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2164 /* hold and delete */
2165 lock_ObtainMutex(&dsp->mx);
2166 dsp->flags |= SMB_DIRSEARCH_DELETE;
2167 lock_ReleaseMutex(&dsp->mx);
2168 victimsp[victimCount++] = dsp;
2172 /* don't do more than this */
2173 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2177 /* now release them */
2178 for (i = 0; i < victimCount; i++) {
2179 smb_ReleaseDirSearchNoLock(victimsp[i]);
2183 /* function for allocating a dir search entry. We need these to remember enough context
2184 * since we don't get passed the path from call to call during a directory search.
2186 * Returns a held dir search structure, and bumps the reference count on the vnode,
2187 * since it saves a pointer to the vnode.
2189 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2191 smb_dirSearch_t *dsp;
2197 lock_ObtainWrite(&smb_globalLock);
2200 /* what's the biggest ID allowed in this version of the protocol */
2201 /* TODO: do we really want a non v3 dir search request to wrap
2202 smb_dirSearchCounter? */
2203 maxAllowed = isV3 ? 65535 : 255;
2204 if (smb_dirSearchCounter > maxAllowed)
2205 smb_dirSearchCounter = 1;
2207 start = smb_dirSearchCounter;
2210 /* twice so we have enough tries to find guys we GC after one pass;
2211 * 10 extra is just in case I mis-counted.
2213 if (++counter > 2*maxAllowed+10)
2214 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2216 if (smb_dirSearchCounter > maxAllowed) {
2217 smb_dirSearchCounter = 1;
2219 if (smb_dirSearchCounter == start) {
2221 smb_GCDirSearches(isV3);
2224 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2226 /* don't need to watch for refcount zero and deleted, since
2227 * we haven't dropped the global lock.
2230 ++smb_dirSearchCounter;
2234 dsp = malloc(sizeof(*dsp));
2235 memset(dsp, 0, sizeof(*dsp));
2236 dsp->cookie = smb_dirSearchCounter;
2237 ++smb_dirSearchCounter;
2239 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2240 dsp->lastTime = osi_Time();
2241 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2242 if (!smb_lastDirSearchp)
2243 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2245 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2249 lock_ReleaseWrite(&smb_globalLock);
2253 static smb_packet_t *smb_GetPacket(void)
2257 lock_ObtainWrite(&smb_globalLock);
2258 tbp = smb_packetFreeListp;
2260 smb_packetFreeListp = tbp->nextp;
2261 lock_ReleaseWrite(&smb_globalLock);
2263 tbp = calloc(sizeof(*tbp),1);
2264 tbp->magic = SMB_PACKETMAGIC;
2267 tbp->resumeCode = 0;
2273 tbp->ncb_length = 0;
2276 tbp->stringsp = NULL;
2278 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2283 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2286 tbp = smb_GetPacket();
2287 memcpy(tbp, pkt, sizeof(smb_packet_t));
2288 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2289 tbp->stringsp = NULL;
2291 smb_HoldVC(tbp->vcp);
2295 static NCB *smb_GetNCB(void)
2300 lock_ObtainWrite(&smb_globalLock);
2301 tbp = smb_ncbFreeListp;
2303 smb_ncbFreeListp = tbp->nextp;
2304 lock_ReleaseWrite(&smb_globalLock);
2306 tbp = calloc(sizeof(*tbp),1);
2307 tbp->magic = SMB_NCBMAGIC;
2310 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2312 memset(&tbp->ncb, 0, sizeof(NCB));
2317 static void FreeSMBStrings(smb_packet_t * pkt)
2322 for (s = pkt->stringsp; s; s = ns) {
2326 pkt->stringsp = NULL;
2329 void smb_FreePacket(smb_packet_t *tbp)
2331 smb_vc_t * vcp = NULL;
2332 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2334 lock_ObtainWrite(&smb_globalLock);
2335 tbp->nextp = smb_packetFreeListp;
2336 smb_packetFreeListp = tbp;
2337 tbp->magic = SMB_PACKETMAGIC;
2341 tbp->resumeCode = 0;
2347 tbp->ncb_length = 0;
2349 FreeSMBStrings(tbp);
2350 lock_ReleaseWrite(&smb_globalLock);
2356 static void smb_FreeNCB(NCB *bufferp)
2360 tbp = (smb_ncb_t *) bufferp;
2361 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2363 lock_ObtainWrite(&smb_globalLock);
2364 tbp->nextp = smb_ncbFreeListp;
2365 smb_ncbFreeListp = tbp;
2366 lock_ReleaseWrite(&smb_globalLock);
2369 /* get a ptr to the data part of a packet, and its count */
2370 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2374 unsigned char *afterParmsp;
2376 parmBytes = *smbp->wctp << 1;
2377 afterParmsp = smbp->wctp + parmBytes + 1;
2379 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2380 if (nbytesp) *nbytesp = dataBytes;
2382 /* don't forget to skip the data byte count, since it follows
2383 * the parameters; that's where the "2" comes from below.
2385 return (unsigned char *) (afterParmsp + 2);
2388 /* must set all the returned parameters before playing around with the
2389 * data region, since the data region is located past the end of the
2390 * variable number of parameters.
2392 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2394 unsigned char *afterParmsp;
2396 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2398 *afterParmsp++ = dsize & 0xff;
2399 *afterParmsp = (dsize>>8) & 0xff;
2402 /* return the parm'th parameter in the smbp packet */
2403 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2406 unsigned char *parmDatap;
2408 parmCount = *smbp->wctp;
2410 if (parm >= parmCount) {
2413 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2414 parm, parmCount, smbp->ncb_length);
2415 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2416 parm, parmCount, smbp->ncb_length);
2417 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2418 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2419 osi_panic(s, __FILE__, __LINE__);
2421 parmDatap = smbp->wctp + (2*parm) + 1;
2423 return parmDatap[0] + (parmDatap[1] << 8);
2426 /* return the parm'th parameter in the smbp packet */
2427 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2430 unsigned char *parmDatap;
2432 parmCount = *smbp->wctp;
2434 if (parm >= parmCount) {
2437 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2438 parm, parmCount, smbp->ncb_length);
2439 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2440 parm, parmCount, smbp->ncb_length);
2441 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2442 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2443 osi_panic(s, __FILE__, __LINE__);
2445 parmDatap = smbp->wctp + (2*parm) + 1;
2447 return parmDatap[0];
2450 /* return the parm'th parameter in the smbp packet */
2451 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2454 unsigned char *parmDatap;
2456 parmCount = *smbp->wctp;
2458 if (parm + 1 >= parmCount) {
2461 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2462 parm, parmCount, smbp->ncb_length);
2463 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2464 parm, parmCount, smbp->ncb_length);
2465 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2466 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2467 osi_panic(s, __FILE__, __LINE__);
2469 parmDatap = smbp->wctp + (2*parm) + 1;
2471 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2474 /* return the parm'th parameter in the smbp packet */
2475 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2478 unsigned char *parmDatap;
2480 parmCount = *smbp->wctp;
2482 if (parm * 2 + offset >= parmCount * 2) {
2485 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2486 parm, offset, parmCount, smbp->ncb_length);
2487 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2488 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2489 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2490 parm, offset, parmCount, smbp->ncb_length);
2491 osi_panic(s, __FILE__, __LINE__);
2493 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2495 return parmDatap[0] + (parmDatap[1] << 8);
2498 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2500 unsigned char *parmDatap;
2502 /* make sure we have enough slots */
2503 if (*smbp->wctp <= slot)
2504 *smbp->wctp = slot+1;
2506 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2507 *parmDatap++ = parmValue & 0xff;
2508 *parmDatap = (parmValue>>8) & 0xff;
2511 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2513 unsigned char *parmDatap;
2515 /* make sure we have enough slots */
2516 if (*smbp->wctp <= slot)
2517 *smbp->wctp = slot+2;
2519 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2520 *parmDatap++ = parmValue & 0xff;
2521 *parmDatap++ = (parmValue>>8) & 0xff;
2522 *parmDatap++ = (parmValue>>16) & 0xff;
2523 *parmDatap = (parmValue>>24) & 0xff;
2526 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2528 unsigned char *parmDatap;
2531 /* make sure we have enough slots */
2532 if (*smbp->wctp <= slot)
2533 *smbp->wctp = slot+4;
2535 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2537 *parmDatap++ = *parmValuep++;
2540 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2542 unsigned char *parmDatap;
2544 /* make sure we have enough slots */
2545 if (*smbp->wctp <= slot) {
2546 if (smbp->oddByte) {
2548 *smbp->wctp = slot+1;
2553 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2554 *parmDatap++ = parmValue & 0xff;
2559 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2560 clientchar_t *inPathp)
2562 clientchar_t *lastSlashp;
2563 clientchar_t *streamp = NULL;
2564 clientchar_t *typep = NULL;
2566 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2567 if (lastComponentp) {
2568 *lastComponentp = lastSlashp;
2572 * If the name contains a stream name and a type
2573 * and the stream name is the nul-string and the
2574 * type is $DATA, then strip "::$DATA" from the
2575 * last component string that is returned.
2577 * Otherwise, return the full path name and allow
2578 * the file name to be rejected because it contains
2581 typep = cm_ClientStrRChr(lastSlashp, L':');
2582 if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2584 streamp = cm_ClientStrRChr(lastSlashp, L':');
2585 if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2589 osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2590 osi_LogSaveClientString(smb_logp,streamp),
2591 osi_LogSaveClientString(smb_logp,typep));
2595 if (inPathp == lastSlashp)
2597 *outPathp++ = *inPathp++;
2606 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2607 char **chainpp, int flags)
2610 afs_uint32 type = *inp++;
2613 * The first byte specifies the type of the input string.
2614 * CIFS TR 1.0 3.2.10. This function only parses null terminated
2618 /* Length Counted */
2619 case 0x1: /* Data Block */
2620 case 0x5: /* Variable Block */
2621 cb = *inp++ << 16 | *inp++;
2624 /* Null-terminated string */
2625 case 0x4: /* ASCII */
2626 case 0x3: /* Pathname */
2627 case 0x2: /* Dialect */
2628 cb = sizeof(pktp->data) - (inp - pktp->data);
2629 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2630 #ifdef DEBUG_UNICODE
2633 cb = sizeof(pktp->data);
2638 return NULL; /* invalid input */
2642 if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2643 flags |= SMB_STRF_FORCEASCII;
2646 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2649 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2650 char ** chainpp, int flags)
2655 if (!WANTS_UNICODE(pktp))
2656 flags |= SMB_STRF_FORCEASCII;
2659 cb = sizeof(pktp->data) - (inp - pktp->data);
2660 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2661 #ifdef DEBUG_UNICODE
2664 cb = sizeof(pktp->data);
2666 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2667 flags | SMB_STRF_SRCNULTERM);
2670 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2671 size_t cb, char ** chainpp, int flags)
2674 if (!WANTS_UNICODE(pktp))
2675 flags |= SMB_STRF_FORCEASCII;
2678 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2681 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2682 size_t cch, char ** chainpp, int flags)
2687 if (!WANTS_UNICODE(pktp))
2688 flags |= SMB_STRF_FORCEASCII;
2690 cb = cch * sizeof(wchar_t);
2693 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2697 smb_ParseStringBuf(const unsigned char * bufbase,
2698 cm_space_t ** stringspp,
2699 unsigned char *inp, size_t *pcb_max,
2700 char **chainpp, int flags)
2703 if (!(flags & SMB_STRF_FORCEASCII)) {
2705 cm_space_t * spacep;
2708 if (bufbase && ((inp - bufbase) % 2) != 0) {
2709 inp++; /* unicode strings are always word aligned */
2713 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2715 cch_src = *pcb_max / sizeof(wchar_t);
2719 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2726 spacep = cm_GetSpace();
2727 spacep->nextp = *stringspp;
2728 *stringspp = spacep;
2732 *chainpp = inp + sizeof(wchar_t);
2735 *(spacep->wdata) = 0;
2736 return spacep->wdata;
2739 StringCchCopyNW(spacep->wdata,
2740 lengthof(spacep->wdata),
2741 (const clientchar_t *) inp, cch_src);
2744 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2746 return spacep->wdata;
2750 cm_space_t * spacep;
2753 /* Not using Unicode */
2755 *chainpp = inp + strlen(inp) + 1;
2758 spacep = cm_GetSpace();
2759 spacep->nextp = *stringspp;
2760 *stringspp = spacep;
2762 cchdest = lengthof(spacep->wdata);
2763 cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2764 spacep->wdata, cchdest);
2766 return spacep->wdata;
2772 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2774 size_t * plen, int flags)
2780 /* we are only calculating the required size */
2787 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2789 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2790 if (!(flags & SMB_STRF_IGNORENUL))
2791 *plen += sizeof(wchar_t);
2793 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2803 cch_str = cm_ClientStrLen(str);
2804 cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2807 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2815 /* if outp != NULL ... */
2817 /* Number of bytes left in the buffer.
2819 If outp lies inside the packet data buffer, we assume that the
2820 buffer is the packet data buffer. Otherwise we assume that the
2821 buffer is sizeof(packet->data).
2824 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2825 align = (int)((outp - pktp->data) % 2);
2826 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2828 align = (int)(((size_t) outp) % 2);
2829 buffersize = (int)sizeof(pktp->data);
2834 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2840 if (*str == _C('\0')) {
2842 if (buffersize < sizeof(wchar_t))
2845 *((wchar_t *) outp) = L'\0';
2846 if (plen && !(flags & SMB_STRF_IGNORENUL))
2847 *plen += sizeof(wchar_t);
2848 return outp + sizeof(wchar_t);
2851 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2853 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2854 osi_LogSaveClientString(smb_logp, str),
2860 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2862 return outp + sizeof(wchar_t) * nchars;
2870 cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2873 *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2875 return outp + cch_dest;
2879 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2885 tlen = inp[0] + (inp[1]<<8);
2886 inp += 2; /* skip length field */
2889 *chainpp = inp + tlen;
2898 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2902 if (*inp++ != 0x1) return NULL;
2903 tlen = inp[0] + (inp[1]<<8);
2904 inp += 2; /* skip length field */
2907 *chainpp = inp + tlen;
2910 if (lengthp) *lengthp = tlen;
2915 /* format a packet as a response */
2916 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2921 outp = (smb_t *) op;
2923 /* zero the basic structure through the smb_wct field, and zero the data
2924 * size field, assuming that wct stays zero; otherwise, you have to
2925 * explicitly set the data size field, too.
2927 inSmbp = (smb_t *) inp;
2928 memset(outp, 0, sizeof(smb_t)+2);
2934 outp->com = inSmbp->com;
2935 outp->tid = inSmbp->tid;
2936 outp->pid = inSmbp->pid;
2937 outp->uid = inSmbp->uid;
2938 outp->mid = inSmbp->mid;
2939 outp->res[0] = inSmbp->res[0];
2940 outp->res[1] = inSmbp->res[1];
2941 op->inCom = inSmbp->com;
2943 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2944 #ifdef SEND_CANONICAL_PATHNAMES
2945 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2947 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2949 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2950 outp->flg2 |= SMB_FLAGS2_UNICODE;
2953 /* copy fields in generic packet area */
2954 op->wctp = &outp->wct;
2957 /* send a (probably response) packet; vcp tells us to whom to send it.
2958 * we compute the length by looking at wct and bcc fields.
2960 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2970 ncbp = smb_GetNCB();
2974 memset(ncbp, 0, sizeof(NCB));
2976 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2977 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2978 extra += tp[0] + (tp[1]<<8);
2979 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2980 extra += 3; /* wct and length fields */
2982 ncbp->ncb_length = extra; /* bytes to send */
2983 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2984 ncbp->ncb_lana_num = vcp->lana;
2985 ncbp->ncb_command = NCBSEND; /* op means send data */
2986 ncbp->ncb_buffer = (char *) inp;/* packet */
2987 code = Netbios(ncbp);
2990 const char * s = ncb_error_string(code);
2991 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2992 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2994 lock_ObtainMutex(&vcp->mx);
2995 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2996 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2998 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2999 lock_ReleaseMutex(&vcp->mx);
3000 lock_ObtainWrite(&smb_globalLock);
3001 dead_sessions[vcp->session] = TRUE;
3002 lock_ReleaseWrite(&smb_globalLock);
3003 smb_CleanupDeadVC(vcp);
3005 lock_ReleaseMutex(&vcp->mx);
3013 void smb_MapNTError(long code, unsigned long *NTStatusp)
3015 unsigned long NTStatus;
3017 /* map CM_ERROR_* errors to NT 32-bit status codes */
3018 /* NT Status codes are listed in ntstatus.h not winerror.h */
3022 else if (code == CM_ERROR_NOSUCHCELL) {
3023 NTStatus = 0xC0000034L; /* Name not found */
3025 else if (code == CM_ERROR_NOSUCHVOLUME) {
3026 NTStatus = 0xC0000034L; /* Name not found */
3028 else if (code == CM_ERROR_TIMEDOUT) {
3030 NTStatus = 0xC00000CFL; /* Sharing Paused */
3032 /* Do not send Timeout to the SMB redirector.
3033 * It causes the redirector to drop the connection */
3034 NTStatus = 0x00000102L; /* Timeout */
3035 /* do not send Retry to the SMB redirector.
3036 * It believes the error comes from the transport
3037 * layer not from the SMB server. */
3038 NTStatus = 0xC000022DL; /* Retry */
3040 NTStatus = 0xC00000B5L; /* I/O Timeout */
3043 else if (code == CM_ERROR_RETRY) {
3045 NTStatus = 0xC000022DL; /* Retry */
3047 NTStatus = 0xC00000B5L; /* I/O Timeout */
3050 else if (code == CM_ERROR_NOACCESS) {
3051 NTStatus = 0xC0000022L; /* Access denied */
3053 else if (code == CM_ERROR_READONLY) {
3054 NTStatus = 0xC00000A2L; /* Write protected */
3056 else if (code == CM_ERROR_NOSUCHFILE ||
3057 code == CM_ERROR_BPLUS_NOMATCH) {
3058 NTStatus = 0xC0000034L; /* Name not found */
3060 else if (code == CM_ERROR_NOSUCHPATH) {
3061 NTStatus = 0xC000003AL; /* Object path not found */
3063 else if (code == CM_ERROR_TOOBIG) {
3064 NTStatus = 0xC000007BL; /* Invalid image format */
3066 else if (code == CM_ERROR_INVAL) {
3067 NTStatus = 0xC000000DL; /* Invalid parameter */
3069 else if (code == CM_ERROR_BADFD) {
3070 NTStatus = 0xC0000008L; /* Invalid handle */
3072 else if (code == CM_ERROR_BADFDOP) {
3073 NTStatus = 0xC0000022L; /* Access denied */
3075 else if (code == CM_ERROR_UNKNOWN) {
3076 NTStatus = 0xC0000022L; /* Access denied */
3078 else if (code == CM_ERROR_EXISTS) {
3079 NTStatus = 0xC0000035L; /* Object name collision */
3081 else if (code == CM_ERROR_NOTEMPTY) {
3082 NTStatus = 0xC0000101L; /* Directory not empty */
3084 else if (code == CM_ERROR_CROSSDEVLINK) {
3085 NTStatus = 0xC00000D4L; /* Not same device */
3087 else if (code == CM_ERROR_NOTDIR) {
3088 NTStatus = 0xC0000103L; /* Not a directory */
3090 else if (code == CM_ERROR_ISDIR) {
3091 NTStatus = 0xC00000BAL; /* File is a directory */
3093 else if (code == CM_ERROR_BADOP) {
3095 /* I have no idea where this comes from */
3096 NTStatus = 0xC09820FFL; /* SMB no support */
3098 NTStatus = 0xC00000BBL; /* Not supported */
3099 #endif /* COMMENT */
3101 else if (code == CM_ERROR_BADSHARENAME) {
3102 NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3104 else if (code == CM_ERROR_NOIPC) {
3106 NTStatus = 0xC0000022L; /* Access Denied */
3108 NTStatus = 0xC000013DL; /* Remote Resources */
3111 else if (code == CM_ERROR_CLOCKSKEW ||
3112 code == RXKADNOAUTH) {
3113 NTStatus = 0xC0000133L; /* Time difference at DC */
3115 else if (code == CM_ERROR_BADTID) {
3116 NTStatus = 0xC0982005L; /* SMB bad TID */
3118 else if (code == CM_ERROR_USESTD) {
3119 NTStatus = 0xC09820FBL; /* SMB use standard */
3121 else if (code == CM_ERROR_QUOTA) {
3122 NTStatus = 0xC0000044L; /* Quota exceeded */
3124 else if (code == CM_ERROR_SPACE) {
3125 NTStatus = 0xC000007FL; /* Disk full */
3127 else if (code == CM_ERROR_ATSYS) {
3128 NTStatus = 0xC0000033L; /* Object name invalid */
3130 else if (code == CM_ERROR_BADNTFILENAME) {
3131 NTStatus = 0xC0000033L; /* Object name invalid */
3133 else if (code == CM_ERROR_WOULDBLOCK) {
3134 NTStatus = 0xC00000D8L; /* Can't wait */
3136 else if (code == CM_ERROR_SHARING_VIOLATION) {
3137 NTStatus = 0xC0000043L; /* Sharing violation */
3139 else if (code == CM_ERROR_LOCK_CONFLICT) {
3140 NTStatus = 0xC0000054L; /* Lock conflict */
3142 else if (code == CM_ERROR_PARTIALWRITE) {
3143 NTStatus = 0xC000007FL; /* Disk full */
3145 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3146 NTStatus = 0xC0000023L; /* Buffer too small */
3148 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3149 NTStatus = 0xC0000035L; /* Object name collision */
3151 else if (code == CM_ERROR_BADPASSWORD) {
3152 NTStatus = 0xC000006DL; /* unknown username or bad password */
3154 else if (code == CM_ERROR_BADLOGONTYPE) {
3155 NTStatus = 0xC000015BL; /* logon type not granted */
3157 else if (code == CM_ERROR_GSSCONTINUE) {
3158 NTStatus = 0xC0000016L; /* more processing required */
3160 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3162 NTStatus = 0xC0000280L; /* reparse point not resolved */
3164 NTStatus = 0xC0000022L; /* Access Denied */
3167 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3168 NTStatus = 0xC0000257L; /* Path Not Covered */
3170 else if (code == CM_ERROR_ALLBUSY) {
3172 NTStatus = 0xC000022DL; /* Retry */
3174 NTStatus = 0xC00000B5L; /* I/O Timeout */
3177 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3178 NTStatus = 0xC000003AL; /* Path not found */
3180 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3181 NTStatus = 0xC0000322L; /* No Kerberos key */
3183 else if (code == CM_ERROR_BAD_LEVEL) {
3184 NTStatus = 0xC0000148L; /* Invalid Level */
3186 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3187 NTStatus = 0xC000007EL; /* Range Not Locked */
3189 else if (code == CM_ERROR_NOSUCHDEVICE) {
3190 NTStatus = 0xC000000EL; /* No Such Device */
3192 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3193 NTStatus = 0xC0000055L; /* Lock Not Granted */
3195 else if (code == ENOMEM) {
3196 NTStatus = 0xC0000017L; /* Out of Memory */
3198 else if (code == CM_ERROR_RPC_MOREDATA) {
3199 NTStatus = 0x80000005L; /* Buffer overflow */
3202 NTStatus = 0xC0982001L; /* SMB non-specific error */
3205 *NTStatusp = NTStatus;
3206 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3210 * NTSTATUS <-> Win32 Error Translation
3211 * http://support.microsoft.com/kb/113996
3213 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3215 unsigned long Win32E;
3217 /* map CM_ERROR_* errors to Win32 32-bit error codes */
3221 else if (code == CM_ERROR_NOSUCHCELL) {
3222 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3224 else if (code == CM_ERROR_NOSUCHVOLUME) {
3225 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3227 else if (code == CM_ERROR_TIMEDOUT) {
3229 Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
3231 Win32E = ERROR_UNEXP_NET_ERR; /* Timeout */
3234 else if (code == CM_ERROR_RETRY) {
3235 Win32E = ERROR_RETRY; /* Retry */
3237 else if (code == CM_ERROR_NOACCESS) {
3238 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3240 else if (code == CM_ERROR_READONLY) {
3241 Win32E = ERROR_WRITE_PROTECT; /* Write protected */
3243 else if (code == CM_ERROR_NOSUCHFILE ||
3244 code == CM_ERROR_BPLUS_NOMATCH) {
3245 Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
3247 else if (code == CM_ERROR_NOSUCHPATH) {
3248 Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
3250 else if (code == CM_ERROR_TOOBIG) {
3251 Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
3253 else if (code == CM_ERROR_INVAL) {
3254 Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3256 else if (code == CM_ERROR_BADFD) {
3257 Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
3259 else if (code == CM_ERROR_BADFDOP) {
3260 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3262 else if (code == CM_ERROR_UNKNOWN) {
3263 Win32E = ERROR_ACCESS_DENIED; /* Access denied */
3265 else if (code == CM_ERROR_EXISTS) {
3266 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3268 else if (code == CM_ERROR_NOTEMPTY) {
3269 Win32E = ERROR_DIR_NOT_EMPTY; /* Directory not empty */
3271 else if (code == CM_ERROR_CROSSDEVLINK) {
3272 Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3274 else if (code == CM_ERROR_NOTDIR) {
3275 Win32E = ERROR_DIRECTORY; /* Not a directory */
3277 else if (code == CM_ERROR_ISDIR) {
3278 Win32E = ERROR_ACCESS_DENIED; /* File is a directory */
3280 else if (code == CM_ERROR_BADOP) {
3281 Win32E = ERROR_NOT_SUPPORTED; /* Not supported */
3283 else if (code == CM_ERROR_BADSHARENAME) {
3284 Win32E = ERROR_BAD_NETPATH; /* Bad network path (server valid, share bad) */
3286 else if (code == CM_ERROR_NOIPC) {
3288 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3290 Win32E = ERROR_REM_NOT_LIST; /* Remote Resources */
3293 else if (code == CM_ERROR_CLOCKSKEW ||
3294 code == RXKADNOAUTH) {
3295 Win32E = ERROR_TIME_SKEW; /* Time difference at DC */
3297 else if (code == CM_ERROR_BADTID) {
3298 Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
3300 else if (code == CM_ERROR_USESTD) {
3301 Win32E = ERROR_ACCESS_DENIED; /* SMB use standard */
3303 else if (code == CM_ERROR_QUOTA) {
3304 Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3306 else if (code == CM_ERROR_SPACE) {
3307 Win32E = ERROR_DISK_FULL; /* Disk full */
3309 else if (code == CM_ERROR_ATSYS) {
3310 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3312 else if (code == CM_ERROR_BADNTFILENAME) {
3313 Win32E = ERROR_INVALID_NAME; /* Object name invalid */
3315 else if (code == CM_ERROR_WOULDBLOCK) {
3316 Win32E = WAIT_TIMEOUT; /* Can't wait */
3318 else if (code == CM_ERROR_SHARING_VIOLATION) {
3319 Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3321 else if (code == CM_ERROR_LOCK_CONFLICT) {
3322 Win32E = ERROR_LOCK_VIOLATION; /* Lock conflict */
3324 else if (code == CM_ERROR_PARTIALWRITE) {
3325 Win32E = ERROR_DISK_FULL; /* Disk full */
3327 else if (code == CM_ERROR_BUFFERTOOSMALL) {
3328 Win32E = ERROR_INSUFFICIENT_BUFFER; /* Buffer too small */
3330 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3331 Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
3333 else if (code == CM_ERROR_BADPASSWORD) {
3334 Win32E = ERROR_LOGON_FAILURE; /* unknown username or bad password */
3336 else if (code == CM_ERROR_BADLOGONTYPE) {
3337 Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3339 else if (code == CM_ERROR_GSSCONTINUE) {
3340 Win32E = ERROR_MORE_DATA; /* more processing required */
3342 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3344 Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3346 Win32E = ERROR_ACCESS_DENIED; /* Access Denied */
3349 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3350 Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3352 else if (code == CM_ERROR_ALLBUSY) {
3353 Win32E = ERROR_RETRY; /* Retry */
3355 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3356 Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3358 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3359 Win32E = SEC_E_NO_KERB_KEY; /* No Kerberos key */
3361 else if (code == CM_ERROR_BAD_LEVEL) {
3362 Win32E = ERROR_INVALID_LEVEL; /* Invalid Level */
3364 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3365 Win32E = ERROR_NOT_LOCKED; /* Range Not Locked */
3367 else if (code == CM_ERROR_NOSUCHDEVICE) {
3368 Win32E = ERROR_FILE_NOT_FOUND; /* No Such Device */
3370 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3371 Win32E = ERROR_LOCK_VIOLATION; /* Lock Not Granted */
3373 else if (code == ENOMEM) {
3374 Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3376 else if (code == CM_ERROR_RPC_MOREDATA) {
3377 Win32E = ERROR_MORE_DATA; /* Buffer overflow */
3380 Win32E = ERROR_GEN_FAILURE; /* SMB non-specific error */
3384 osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3387 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3388 unsigned char *classp)
3390 unsigned char class;
3391 unsigned short error;
3393 /* map CM_ERROR_* errors to SMB errors */
3394 if (code == CM_ERROR_NOSUCHCELL) {
3396 error = 3; /* bad path */
3398 else if (code == CM_ERROR_NOSUCHVOLUME) {
3400 error = 3; /* bad path */
3402 else if (code == CM_ERROR_TIMEDOUT) {
3404 error = 81; /* server is paused */
3406 else if (code == CM_ERROR_RETRY) {
3407 class = 2; /* shouldn't happen */
3410 else if (code == CM_ERROR_NOACCESS) {
3412 error = 4; /* bad access */
3414 else if (code == CM_ERROR_READONLY) {
3416 error = 19; /* read only */
3418 else if (code == CM_ERROR_NOSUCHFILE ||
3419 code == CM_ERROR_BPLUS_NOMATCH) {
3421 error = 2; /* ENOENT! */
3423 else if (code == CM_ERROR_NOSUCHPATH) {
3425 error = 3; /* Bad path */
3427 else if (code == CM_ERROR_TOOBIG) {
3429 error = 11; /* bad format */
3431 else if (code == CM_ERROR_INVAL) {
3432 class = 2; /* server non-specific error code */
3435 else if (code == CM_ERROR_BADFD) {
3437 error = 6; /* invalid file handle */
3439 else if (code == CM_ERROR_BADFDOP) {
3440 class = 1; /* invalid op on FD */
3443 else if (code == CM_ERROR_EXISTS) {
3445 error = 80; /* file already exists */
3447 else if (code == CM_ERROR_NOTEMPTY) {
3449 error = 5; /* delete directory not empty */
3451 else if (code == CM_ERROR_CROSSDEVLINK) {
3453 error = 17; /* EXDEV */
3455 else if (code == CM_ERROR_NOTDIR) {
3456 class = 1; /* bad path */
3459 else if (code == CM_ERROR_ISDIR) {
3460 class = 1; /* access denied; DOS doesn't have a good match */
3463 else if (code == CM_ERROR_BADOP) {
3467 else if (code == CM_ERROR_BADSHARENAME) {
3471 else if (code == CM_ERROR_NOIPC) {
3473 error = 4; /* bad access */
3475 else if (code == CM_ERROR_CLOCKSKEW) {
3476 class = 1; /* invalid function */
3479 else if (code == CM_ERROR_BADTID) {
3483 else if (code == CM_ERROR_USESTD) {
3487 else if (code == CM_ERROR_REMOTECONN) {
3491 else if (code == CM_ERROR_QUOTA) {
3492 if (vcp->flags & SMB_VCFLAG_USEV3) {
3494 error = 39; /* disk full */
3498 error = 5; /* access denied */
3501 else if (code == CM_ERROR_SPACE) {
3502 if (vcp->flags & SMB_VCFLAG_USEV3) {
3504 error = 39; /* disk full */
3508 error = 5; /* access denied */
3511 else if (code == CM_ERROR_PARTIALWRITE) {
3513 error = 39; /* disk full */
3515 else if (code == CM_ERROR_ATSYS) {
3517 error = 2; /* ENOENT */
3519 else if (code == CM_ERROR_WOULDBLOCK) {
3521 error = 33; /* lock conflict */
3523 else if (code == CM_ERROR_LOCK_CONFLICT) {
3525 error = 33; /* lock conflict */
3527 else if (code == CM_ERROR_SHARING_VIOLATION) {
3529 error = 33; /* lock conflict */
3531 else if (code == CM_ERROR_NOFILES) {
3533 error = 18; /* no files in search */
3535 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3537 error = 183; /* Samba uses this */
3539 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3540 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3542 error = 2; /* bad password */
3544 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3546 error = 3; /* bad path */
3555 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3558 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3560 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3561 return CM_ERROR_BADOP;
3565 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3567 unsigned short EchoCount, i;
3568 char *data, *outdata;
3571 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3573 for (i=1; i<=EchoCount; i++) {
3574 data = smb_GetSMBData(inp, &dataSize);
3575 smb_SetSMBParm(outp, 0, i);
3576 smb_SetSMBDataLength(outp, dataSize);
3577 outdata = smb_GetSMBData(outp, NULL);
3578 memcpy(outdata, data, dataSize);
3579 smb_SendPacket(vcp, outp);
3585 /* SMB_COM_READ_RAW */
3586 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3589 long count, minCount, finalCount;
3593 smb_t *smbp = (smb_t*) inp;
3595 cm_user_t *userp = NULL;
3598 char *rawBuf = NULL;
3603 fd = smb_GetSMBParm(inp, 0);
3604 count = smb_GetSMBParm(inp, 3);
3605 minCount = smb_GetSMBParm(inp, 4);
3606 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3608 if (*inp->wctp == 10) {
3609 /* we were sent a request with 64-bit file offsets */
3610 #ifdef AFS_LARGEFILES
3611 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3613 if (LargeIntegerLessThanZero(offset)) {
3614 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3618 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3619 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3622 offset.HighPart = 0;
3626 /* we were sent a request with 32-bit file offsets */
3627 offset.HighPart = 0;
3630 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3631 fd, offset.HighPart, offset.LowPart, count);
3633 fidp = smb_FindFID(vcp, fd, 0);
3635 osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3639 lock_ObtainMutex(&fidp->mx);
3641 lock_ReleaseMutex(&fidp->mx);
3642 smb_ReleaseFID(fidp);
3643 return CM_ERROR_BADFD;
3646 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3647 lock_ReleaseMutex(&fidp->mx);
3648 smb_CloseFID(vcp, fidp, NULL, 0);
3649 code = CM_ERROR_NOSUCHFILE;
3655 LARGE_INTEGER LOffset, LLength;
3658 key = cm_GenerateKey(vcp->vcID, pid, fd);
3660 LOffset.HighPart = offset.HighPart;
3661 LOffset.LowPart = offset.LowPart;
3662 LLength.HighPart = 0;
3663 LLength.LowPart = count;
3665 lock_ObtainWrite(&fidp->scp->rw);
3666 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3667 lock_ReleaseWrite(&fidp->scp->rw);
3670 lock_ReleaseMutex(&fidp->mx);
3674 lock_ObtainMutex(&smb_RawBufLock);
3676 /* Get a raw buf, from head of list */
3677 rawBuf = smb_RawBufs;
3678 smb_RawBufs = *(char **)smb_RawBufs;
3680 lock_ReleaseMutex(&smb_RawBufLock);
3682 lock_ReleaseMutex(&fidp->mx);
3686 if (fidp->flags & SMB_FID_IOCTL)
3688 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3690 /* Give back raw buffer */
3691 lock_ObtainMutex(&smb_RawBufLock);
3692 *((char **) rawBuf) = smb_RawBufs;
3694 smb_RawBufs = rawBuf;
3695 lock_ReleaseMutex(&smb_RawBufLock);
3698 lock_ReleaseMutex(&fidp->mx);
3699 smb_ReleaseFID(fidp);
3702 lock_ReleaseMutex(&fidp->mx);
3704 userp = smb_GetUserFromVCP(vcp, inp);
3706 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3712 cm_ReleaseUser(userp);
3715 smb_ReleaseFID(fidp);
3719 memset(ncbp, 0, sizeof(NCB));
3721 ncbp->ncb_length = (unsigned short) finalCount;
3722 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3723 ncbp->ncb_lana_num = vcp->lana;
3724 ncbp->ncb_command = NCBSEND;
3725 ncbp->ncb_buffer = rawBuf;
3727 code = Netbios(ncbp);
3729 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3732 /* Give back raw buffer */
3733 lock_ObtainMutex(&smb_RawBufLock);
3734 *((char **) rawBuf) = smb_RawBufs;
3736 smb_RawBufs = rawBuf;
3737 lock_ReleaseMutex(&smb_RawBufLock);
3743 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3745 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3750 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3752 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3757 /* SMB_COM_NEGOTIATE */
3758 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3765 int VistaProtoIndex;
3766 int protoIndex; /* index we're using */
3771 char protocol_array[10][1024]; /* protocol signature of the client */
3772 int caps; /* capabilities */
3775 TIME_ZONE_INFORMATION tzi;
3777 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3780 namep = smb_GetSMBData(inp, &dbytes);
3783 coreProtoIndex = -1; /* not found */
3786 VistaProtoIndex = -1;
3787 while(namex < dbytes) {
3788 osi_Log1(smb_logp, "Protocol %s",
3789 osi_LogSaveString(smb_logp, namep+1));
3790 strcpy(protocol_array[tcounter], namep+1);
3792 /* namep points at the first protocol, or really, a 0x02
3793 * byte preceding the null-terminated ASCII name.
3795 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3796 coreProtoIndex = tcounter;
3798 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3799 v3ProtoIndex = tcounter;
3801 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3802 NTProtoIndex = tcounter;
3804 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3805 VistaProtoIndex = tcounter;
3808 /* compute size of protocol entry */
3809 entryLength = (int)strlen(namep+1);
3810 entryLength += 2; /* 0x02 bytes and null termination */
3812 /* advance over this protocol entry */
3813 namex += entryLength;
3814 namep += entryLength;
3815 tcounter++; /* which proto entry we're looking at */
3818 lock_ObtainMutex(&vcp->mx);
3820 if (VistaProtoIndex != -1) {
3821 protoIndex = VistaProtoIndex;
3822 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3825 if (NTProtoIndex != -1) {
3826 protoIndex = NTProtoIndex;
3827 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3829 else if (v3ProtoIndex != -1) {
3830 protoIndex = v3ProtoIndex;
3831 vcp->flags |= SMB_VCFLAG_USEV3;
3833 else if (coreProtoIndex != -1) {
3834 protoIndex = coreProtoIndex;
3835 vcp->flags |= SMB_VCFLAG_USECORE;
3837 else protoIndex = -1;
3838 lock_ReleaseMutex(&vcp->mx);
3840 if (protoIndex == -1)
3841 return CM_ERROR_INVAL;
3842 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3843 smb_SetSMBParm(outp, 0, protoIndex);
3844 if (smb_authType != SMB_AUTH_NONE) {
3845 smb_SetSMBParmByte(outp, 1,
3846 NEGOTIATE_SECURITY_USER_LEVEL |
3847 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3849 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3851 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3852 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3853 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3854 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3855 /* The session key is not a well documented field however most clients
3856 * will echo back the session key to the server. Currently we are using
3857 * the same value for all sessions. We should generate a random value
3858 * and store it into the vcp
3860 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3861 smb_SetSMBParm(outp, 8, 1);
3863 * Tried changing the capabilities to support for W2K - defect 117695
3864 * Maybe something else needs to be changed here?
3868 smb_SetSMBParmLong(outp, 9, 0x43fd);
3870 smb_SetSMBParmLong(outp, 9, 0x251);
3873 * 32-bit error codes *
3879 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3881 NTNEGOTIATE_CAPABILITY_DFS |
3883 #ifdef AFS_LARGEFILES
3884 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3886 NTNEGOTIATE_CAPABILITY_NTFIND |
3887 NTNEGOTIATE_CAPABILITY_RAWMODE |
3888 NTNEGOTIATE_CAPABILITY_NTSMB;
3890 if ( smb_authType == SMB_AUTH_EXTENDED )
3891 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3894 if ( smb_UseUnicode ) {
3895 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3899 smb_SetSMBParmLong(outp, 9, caps);
3901 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3902 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3903 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3905 GetTimeZoneInformation(&tzi);
3906 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3908 if (smb_authType == SMB_AUTH_NTLM) {
3909 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3910 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3911 /* paste in encryption key */
3912 datap = smb_GetSMBData(outp, NULL);
3913 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3914 /* and the faux domain name */
3915 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3916 datap + MSV1_0_CHALLENGE_LENGTH,
3917 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3918 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3922 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3924 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3926 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3928 datap = smb_GetSMBData(outp, NULL);
3929 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3932 datap += sizeof(smb_ServerGUID);
3933 memcpy(datap, secBlob, secBlobLength);
3937 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3938 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3941 else if (v3ProtoIndex != -1) {
3942 smb_SetSMBParm(outp, 0, protoIndex);
3944 /* NOTE: Extended authentication cannot be negotiated with v3
3945 * therefore we fail over to NTLM
3947 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3948 smb_SetSMBParm(outp, 1,
3949 NEGOTIATE_SECURITY_USER_LEVEL |
3950 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3952 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3954 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3955 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3956 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3957 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3958 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3959 smb_SetSMBParm(outp, 7, 1);
3961 cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3962 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3963 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3965 GetTimeZoneInformation(&tzi);
3966 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3968 /* NOTE: Extended authentication cannot be negotiated with v3
3969 * therefore we fail over to NTLM
3971 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3972 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3973 smb_SetSMBParm(outp, 12, 0); /* resvd */
3974 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3975 datap = smb_GetSMBData(outp, NULL);
3976 /* paste in a new encryption key */
3977 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3978 /* and the faux domain name */
3979 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3980 datap + MSV1_0_CHALLENGE_LENGTH,
3981 (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3983 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3984 smb_SetSMBParm(outp, 12, 0); /* resvd */
3985 smb_SetSMBDataLength(outp, 0);
3988 else if (coreProtoIndex != -1) { /* not really supported anymore */
3989 smb_SetSMBParm(outp, 0, protoIndex);
3990 smb_SetSMBDataLength(outp, 0);
3995 void smb_CheckVCs(void)
3997 smb_vc_t * vcp, *nextp;
3998 smb_packet_t * outp = smb_GetPacket();
4001 lock_ObtainWrite(&smb_rctLock);
4002 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4004 if (vcp->magic != SMB_VC_MAGIC)
4005 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4006 __FILE__, __LINE__);
4008 /* on the first pass hold 'vcp' which was not held as 'nextp' */
4010 smb_HoldVCNoLock(vcp);
4013 * obtain a reference to 'nextp' now because we drop the
4014 * smb_rctLock later and the list contents could change
4015 * or 'vcp' could be destroyed when released.
4019 smb_HoldVCNoLock(nextp);
4021 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4022 smb_ReleaseVCNoLock(vcp);
4026 smb_FormatResponsePacket(vcp, NULL, outp);
4027 smbp = (smb_t *)outp;
4028 outp->inCom = smbp->com = 0x2b /* Echo */;
4036 smb_SetSMBParm(outp, 0, 0);
4037 smb_SetSMBDataLength(outp, 0);
4038 lock_ReleaseWrite(&smb_rctLock);
4040 smb_SendPacket(vcp, outp);
4042 lock_ObtainWrite(&smb_rctLock);
4043 smb_ReleaseVCNoLock(vcp);
4045 lock_ReleaseWrite(&smb_rctLock);
4046 smb_FreePacket(outp);
4049 void smb_Daemon(void *parmp)
4051 afs_uint32 count = 0;
4052 smb_username_t **unpp;
4055 while(smbShutdownFlag == 0) {
4059 if (smbShutdownFlag == 1)
4062 if ((count % 72) == 0) { /* every five minutes */
4064 time_t old_localZero = smb_localZero;
4066 /* Initialize smb_localZero */
4067 myTime.tm_isdst = -1; /* compute whether on DST or not */
4068 myTime.tm_year = 70;
4074 smb_localZero = mktime(&myTime);
4076 #ifdef AFS_FREELANCE
4077 if ( smb_localZero != old_localZero )
4078 cm_noteLocalMountPointChange();
4084 /* GC smb_username_t objects that will no longer be used */
4086 lock_ObtainWrite(&smb_rctLock);
4087 for ( unpp=&usernamesp; *unpp; ) {
4089 smb_username_t *unp;
4091 lock_ObtainMutex(&(*unpp)->mx);
4092 if ( (*unpp)->refCount > 0 ||
4093 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4094 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4096 else if (!smb_LogoffTokenTransfer ||
4097 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4099 lock_ReleaseMutex(&(*unpp)->mx);
4107 lock_FinalizeMutex(&unp->mx);
4113 cm_ReleaseUser(userp);
4115 unpp = &(*unpp)->nextp;
4118 lock_ReleaseWrite(&smb_rctLock);
4120 /* XXX GC dir search entries */
4124 void smb_WaitingLocksDaemon()
4126 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4127 smb_waitingLock_t *wl, *wlNext;
4130 smb_packet_t *inp, *outp;
4134 while (smbShutdownFlag == 0) {
4135 lock_ObtainWrite(&smb_globalLock);
4136 nwlRequest = smb_allWaitingLocks;
4137 if (nwlRequest == NULL) {
4138 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4143 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4150 lock_ObtainWrite(&smb_globalLock);
4152 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
4154 wlRequest = nwlRequest;
4155 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4156 lock_ReleaseWrite(&smb_globalLock);
4160 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4161 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4164 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4165 code = CM_ERROR_LOCK_NOT_GRANTED;
4169 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4171 /* wl->state is either _DONE or _WAITING. _ERROR
4172 would no longer be on the queue. */
4173 code = cm_RetryLock( wl->lockp,
4174 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4177 wl->state = SMB_WAITINGLOCKSTATE_DONE;
4178 } else if (code != CM_ERROR_WOULDBLOCK) {
4179 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4184 if (code == CM_ERROR_WOULDBLOCK) {
4187 if (wlRequest->msTimeout != 0xffffffff
4188 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4200 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4203 scp = wlRequest->scp;
4204 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4208 lock_ObtainWrite(&scp->rw);
4210 for (wl = wlRequest->locks; wl; wl = wlNext) {
4211 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4213 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4214 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4215 wl->LLength, wl->key, 0, NULL, &req);
4217 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4222 lock_ReleaseWrite(&scp->rw);
4226 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4229 for (wl = wlRequest->locks; wl; wl = wlNext) {
4230 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4231 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4236 vcp = wlRequest->vcp;
4237 inp = wlRequest->inp;
4238 outp = wlRequest->outp;
4239 ncbp = smb_GetNCB();
4240 ncbp->ncb_length = inp->ncb_length;
4241 inp->spacep = cm_GetSpace();
4243 /* Remove waitingLock from list */
4244 lock_ObtainWrite(&smb_globalLock);
4245 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4247 lock_ReleaseWrite(&smb_globalLock);
4249 /* Resume packet processing */
4251 smb_SetSMBDataLength(outp, 0);
4252 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4253 outp->resumeCode = code;
4255 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4258 cm_FreeSpace(inp->spacep);
4259 smb_FreePacket(inp);
4260 smb_FreePacket(outp);
4262 cm_ReleaseSCache(wlRequest->scp);
4265 } while (nwlRequest && smbShutdownFlag == 0);
4270 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4272 osi_Log0(smb_logp, "SMB receive get disk attributes");
4274 smb_SetSMBParm(outp, 0, 32000);
4275 smb_SetSMBParm(outp, 1, 64);
4276 smb_SetSMBParm(outp, 2, 1024);
4277 smb_SetSMBParm(outp, 3, 30000);
4278 smb_SetSMBParm(outp, 4, 0);
4279 smb_SetSMBDataLength(outp, 0);
4283 /* SMB_COM_TREE_CONNECT */
4284 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4288 unsigned short newTid;
4289 clientchar_t shareName[AFSPATHMAX];
4290 clientchar_t *sharePath;
4293 clientchar_t *pathp;
4296 osi_Log0(smb_logp, "SMB receive tree connect");
4298 /* parse input parameters */
4301 tbp = smb_GetSMBData(inp, NULL);
4302 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4304 return CM_ERROR_BADSMB;
4306 tp = cm_ClientStrRChr(pathp, '\\');
4308 return CM_ERROR_BADSMB;
4309 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4311 lock_ObtainMutex(&vcp->mx);
4312 newTid = vcp->tidCounter++;
4313 lock_ReleaseMutex(&vcp->mx);
4315 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4316 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4318 return CM_ERROR_BADSMB;
4319 userp = smb_GetUserFromUID(uidp);
4320 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4321 smb_ReleaseUID(uidp);
4323 smb_ReleaseTID(tidp, FALSE);
4324 return CM_ERROR_BADSHARENAME;
4326 lock_ObtainMutex(&tidp->mx);
4327 tidp->userp = userp;
4328 tidp->pathname = sharePath;
4329 lock_ReleaseMutex(&tidp->mx);
4330 smb_ReleaseTID(tidp, FALSE);
4332 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4333 smb_SetSMBParm(rsp, 1, newTid);
4334 smb_SetSMBDataLength(rsp, 0);
4336 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4340 /* set maskp to the mask part of the incoming path.
4341 * Mask is 11 bytes long (8.3 with the dot elided).
4342 * Returns true if succeeds with a valid name, otherwise it does
4343 * its best, but returns false.
4345 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4353 /* starts off valid */
4356 /* mask starts out all blanks */
4357 memset(maskp, ' ', 11);
4360 /* find last backslash, or use whole thing if there is none */
4361 tp = cm_ClientStrRChr(pathp, '\\');
4365 tp++; /* skip slash */
4369 /* names starting with a dot are illegal */
4377 if (tc == '.' || tc == '"')
4385 /* if we get here, tp point after the dot */
4386 up = maskp+8; /* ext goes here */
4393 if (tc == '.' || tc == '"')
4396 /* copy extension if not too long */
4406 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4408 clientchar_t umask[11];
4416 /* XXX redo this, calling cm_MatchMask with a converted mask */
4418 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4422 /* otherwise, we have a valid 8.3 name; see if we have a match,
4423 * treating '?' as a wildcard in maskp (but not in the file name).
4425 tp1 = umask; /* real name, in mask format */
4426 tp2 = maskp; /* mask, in mask format */
4427 for(i=0; i<11; i++) {
4428 tc1 = *tp1++; /* clientchar_t from real name */
4429 tc2 = *tp2++; /* clientchar_t from mask */
4430 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4431 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4434 if (tc2 == '?' && tc1 != ' ')
4441 /* we got a match */
4445 clientchar_t *smb_FindMask(clientchar_t *pathp)
4449 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4452 return tp+1; /* skip the slash */
4454 return pathp; /* no slash, return the entire path */
4457 /* SMB_COM_SEARCH for a volume label
4459 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4460 dispatch function.) */
4461 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4463 clientchar_t *pathp;
4465 clientchar_t mask[12];
4466 unsigned char *statBlockp;
4467 unsigned char initStatBlock[21];
4470 osi_Log0(smb_logp, "SMB receive search volume");
4472 /* pull pathname and stat block out of request */
4473 tp = smb_GetSMBData(inp, NULL);
4474 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4475 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4477 return CM_ERROR_BADSMB;
4478 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4479 osi_assertx(statBlockp != NULL, "null statBlock");
4481 statBlockp = initStatBlock;
4485 /* for returning to caller */
4486 smb_Get8Dot3MaskFromPath(mask, pathp);
4488 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4489 tp = smb_GetSMBData(outp, NULL);
4491 *tp++ = 43; /* bytes in a dir entry */
4492 *tp++ = 0; /* high byte in counter */
4494 /* now marshall the dir entry, starting with the search status */
4495 *tp++ = statBlockp[0]; /* Reserved */
4496 memcpy(tp, mask, 11); tp += 11; /* FileName */
4498 /* now pass back server use info, with 1st byte non-zero */
4500 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4502 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4504 *tp++ = 0x8; /* attribute: volume */
4514 /* 4 byte file size */
4520 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4523 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4524 memset(tp, ' ', 13);
4527 /* set the length of the data part of the packet to 43 + 3, for the dir
4528 * entry plus the 5 and the length fields.
4530 smb_SetSMBDataLength(outp, 46);
4535 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4536 clientchar_t * tidPathp, clientchar_t * relPathp,
4537 cm_user_t *userp, cm_req_t *reqp)
4545 smb_dirListPatch_t *patchp;
4546 smb_dirListPatch_t *npatchp;
4547 clientchar_t path[AFSPATHMAX];
4549 afs_int32 mustFake = 0;
4551 code = cm_FindACLCache(dscp, userp, &rights);
4553 lock_ObtainWrite(&dscp->rw);
4554 code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4555 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4556 lock_ReleaseWrite(&dscp->rw);
4557 if (code == CM_ERROR_NOACCESS) {
4565 if (!mustFake) { /* Bulk Stat */
4567 cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4569 memset(bsp, 0, sizeof(cm_bulkStat_t));
4571 for (patchp = *dirPatchespp, count=0;
4573 patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4574 cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4578 if (lock_TryWrite(&tscp->rw)) {
4579 /* we have an entry that we can look at */
4580 if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4581 /* we have a callback on it. Don't bother
4582 * fetching this stat entry, since we're happy
4583 * with the info we have.
4585 lock_ReleaseWrite(&tscp->rw);
4586 cm_ReleaseSCache(tscp);
4589 lock_ReleaseWrite(&tscp->rw);
4591 cm_ReleaseSCache(tscp);
4595 bsp->fids[i].Volume = patchp->fid.volume;
4596 bsp->fids[i].Vnode = patchp->fid.vnode;
4597 bsp->fids[i].Unique = patchp->fid.unique;
4599 if (bsp->counter == AFSCBMAX) {
4600 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4601 memset(bsp, 0, sizeof(cm_bulkStat_t));
4605 if (bsp->counter > 0)
4606 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4611 for (patchp = *dirPatchespp; patchp; patchp =
4612 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4614 dptr = patchp->dptr;
4616 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4617 relPathp ? relPathp : _C(""), patchp->dep->name);
4618 reqp->relPathp = path;
4619 reqp->tidPathp = tidPathp;
4621 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4622 reqp->relPathp = reqp->tidPathp = NULL;
4625 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4626 *dptr++ = SMB_ATTR_HIDDEN;
4629 lock_ObtainWrite(&scp->rw);
4630 if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4631 lock_ReleaseWrite(&scp->rw);
4633 /* set the attribute */
4634 switch (scp->fileType) {
4635 case CM_SCACHETYPE_DIRECTORY:
4636 case CM_SCACHETYPE_MOUNTPOINT:
4637 case CM_SCACHETYPE_INVALID:
4638 attr = SMB_ATTR_DIRECTORY;
4640 case CM_SCACHETYPE_SYMLINK:
4641 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4642 attr = SMB_ATTR_DIRECTORY;
4644 attr = SMB_ATTR_NORMAL;
4647 /* if we get here we either have a normal file
4648 * or we have a file for which we have never
4649 * received status info. In this case, we can
4650 * check the even/odd value of the entry's vnode.
4651 * odd means it is to be treated as a directory
4652 * and even means it is to be treated as a file.
4654 if (mustFake && (scp->fid.vnode & 0x1))
4655 attr = SMB_ATTR_DIRECTORY;
4657 attr = SMB_ATTR_NORMAL;
4661 /* 1969-12-31 23:59:58 +00*/
4662 dosTime = 0xEBBFBF7D;
4665 shortTemp = (unsigned short) (dosTime & 0xffff);
4666 *((u_short *)dptr) = shortTemp;
4669 /* and copy out date */
4670 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4671 *((u_short *)dptr) = shortTemp;
4674 /* copy out file length */
4675 *((u_long *)dptr) = 0;
4678 lock_ConvertWToR(&scp->rw);
4679 attr = smb_Attributes(scp);
4680 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4681 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4682 attr |= SMB_ATTR_HIDDEN;
4686 cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4689 shortTemp = (unsigned short) (dosTime & 0xffff);
4690 *((u_short *)dptr) = shortTemp;
4693 /* and copy out date */
4694 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4695 *((u_short *)dptr) = shortTemp;
4698 /* copy out file length */
4699 *((u_long *)dptr) = scp->length.LowPart;
4701 lock_ReleaseRead(&scp->rw);
4703 cm_ReleaseSCache(scp);
4706 /* now free the patches */
4707 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4708 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4712 /* and mark the list as empty */
4713 *dirPatchespp = NULL;
4719 /* SMB_COM_SEARCH */
4720 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4726 clientchar_t *pathp;
4727 cm_dirEntry_t *dep = 0;
4729 smb_dirListPatch_t *dirListPatchesp;
4730 smb_dirListPatch_t *curPatchp;
4734 osi_hyper_t dirLength;
4735 osi_hyper_t bufferOffset;
4736 osi_hyper_t curOffset;
4738 unsigned char *inCookiep;
4739 smb_dirSearch_t *dsp;
4743 unsigned long clientCookie;
4744 cm_pageHeader_t *pageHeaderp;
4745 cm_user_t *userp = NULL;
4747 clientchar_t mask[12];
4749 long nextEntryCookie;
4750 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4751 char resByte; /* reserved byte from the cookie */
4752 char *op; /* output data ptr */
4753 char *origOp; /* original value of op */
4754 cm_space_t *spacep; /* for pathname buffer */
4758 clientchar_t *tidPathp = 0;
4765 maxCount = smb_GetSMBParm(inp, 0);
4767 dirListPatchesp = NULL;
4769 caseFold = CM_FLAG_CASEFOLD;
4771 tp = smb_GetSMBData(inp, NULL);
4772 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4773 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4775 return CM_ERROR_BADSMB;
4777 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4779 return CM_ERROR_BADSMB;
4781 /* We can handle long names */
4782 if (vcp->flags & SMB_VCFLAG_USENT)
4783 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4785 /* make sure we got a whole search status */
4786 if (dataLength < 21) {
4787 nextCookie = 0; /* start at the beginning of the dir */
4790 attribute = smb_GetSMBParm(inp, 1);
4792 /* handle volume info in another function */
4793 if (attribute & 0x8)
4794 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4796 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4797 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4799 if (*pathp == 0) { /* null pathp, treat as root dir */
4800 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4801 return CM_ERROR_NOFILES;
4805 dsp = smb_NewDirSearch(0);
4806 dsp->attribute = attribute;
4807 smb_Get8Dot3MaskFromPath(mask, pathp);
4808 memcpy(dsp->mask, mask, 12);
4810 /* track if this is likely to match a lot of entries */
4811 if (smb_Is8Dot3StarMask(mask))
4816 /* pull the next cookie value out of the search status block */
4817 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4818 + (inCookiep[16]<<24);
4819 dsp = smb_FindDirSearch(inCookiep[12]);
4821 /* can't find dir search status; fatal error */
4822 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4823 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4824 return CM_ERROR_BADFD;
4826 attribute = dsp->attribute;
4827 resByte = inCookiep[0];
4829 /* copy out client cookie, in host byte order. Don't bother
4830 * interpreting it, since we're just passing it through, anyway.
4832 memcpy(&clientCookie, &inCookiep[17], 4);
4834 memcpy(mask, dsp->mask, 12);
4836 /* assume we're doing a star match if it has continued for more
4842 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4843 nextCookie, dsp->cookie, attribute);
4845 userp = smb_GetUserFromVCP(vcp, inp);
4847 /* try to get the vnode for the path name next */
4848 lock_ObtainMutex(&dsp->mx);
4851 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4855 spacep = inp->spacep;
4856 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4857 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4859 lock_ReleaseMutex(&dsp->mx);
4860 cm_ReleaseUser(userp);
4861 smb_DeleteDirSearch(dsp);
4862 smb_ReleaseDirSearch(dsp);
4863 return CM_ERROR_NOFILES;
4865 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4866 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4868 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4869 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4872 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4875 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4876 cm_ReleaseSCache(scp);
4877 lock_ReleaseMutex(&dsp->mx);
4878 cm_ReleaseUser(userp);
4879 smb_DeleteDirSearch(dsp);
4880 smb_ReleaseDirSearch(dsp);
4881 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4882 return CM_ERROR_PATH_NOT_COVERED;
4884 return CM_ERROR_NOSUCHPATH;
4886 #endif /* DFS_SUPPORT */
4889 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4890 /* we need one hold for the entry we just stored into,
4891 * and one for our own processing. When we're done with this
4892 * function, we'll drop the one for our own processing.
4893 * We held it once from the namei call, and so we do another hold
4897 lock_ObtainWrite(&scp->rw);
4898 dsp->flags |= SMB_DIRSEARCH_BULKST;
4899 lock_ReleaseWrite(&scp->rw);
4902 lock_ReleaseMutex(&dsp->mx);
4904 cm_ReleaseUser(userp);
4905 smb_DeleteDirSearch(dsp);
4906 smb_ReleaseDirSearch(dsp);
4910 /* reserves space for parameter; we'll adjust it again later to the
4911 * real count of the # of entries we returned once we've actually
4912 * assembled the directory listing.
4914 smb_SetSMBParm(outp, 0, 0);
4916 /* get the directory size */
4917 lock_ObtainWrite(&scp->rw);
4918 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4919 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4921 lock_ReleaseWrite(&scp->rw);
4922 cm_ReleaseSCache(scp);
4923 cm_ReleaseUser(userp);
4924 smb_DeleteDirSearch(dsp);
4925 smb_ReleaseDirSearch(dsp);
4929 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4931 dirLength = scp->length;
4933 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4934 curOffset.HighPart = 0;
4935 curOffset.LowPart = nextCookie;
4936 origOp = op = smb_GetSMBData(outp, NULL);
4937 /* and write out the basic header */
4938 *op++ = 5; /* variable block */
4939 op += 2; /* skip vbl block length; we'll fill it in later */
4943 clientchar_t *actualName = NULL;
4944 int free_actualName = 0;
4945 clientchar_t shortName[13];
4946 clientchar_t *shortNameEnd;
4948 /* make sure that curOffset.LowPart doesn't point to the first
4949 * 32 bytes in the 2nd through last dir page, and that it doesn't
4950 * point at the first 13 32-byte chunks in the first dir page,
4951 * since those are dir and page headers, and don't contain useful
4954 temp = curOffset.LowPart & (2048-1);
4955 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4956 /* we're in the first page */
4957 if (temp < 13*32) temp = 13*32;
4960 /* we're in a later dir page */
4961 if (temp < 32) temp = 32;
4964 /* make sure the low order 5 bits are zero */
4967 /* now put temp bits back ito curOffset.LowPart */
4968 curOffset.LowPart &= ~(2048-1);
4969 curOffset.LowPart |= temp;
4971 /* check if we've returned all the names that will fit in the
4974 if (returnedNames >= maxCount) {
4975 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4976 returnedNames, maxCount);
4980 /* check if we've passed the dir's EOF */
4981 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4983 /* see if we can use the bufferp we have now; compute in which page
4984 * the current offset would be, and check whether that's the offset
4985 * of the buffer we have. If not, get the buffer.
4987 thyper.HighPart = curOffset.HighPart;
4988 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4989 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4992 buf_Release(bufferp);
4995 lock_ReleaseWrite(&scp->rw);
4996 code = buf_Get(scp, &thyper, &req, &bufferp);
4997 lock_ObtainMutex(&dsp->mx);
4999 /* now, if we're doing a star match, do bulk fetching of all of
5000 * the status info for files in the dir.
5003 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5005 lock_ObtainWrite(&scp->rw);
5006 lock_ReleaseMutex(&dsp->mx);
5008 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5012 bufferOffset = thyper;
5014 /* now get the data in the cache */
5016 code = cm_SyncOp(scp, bufferp, userp, &req,
5018 CM_SCACHESYNC_NEEDCALLBACK |
5019 CM_SCACHESYNC_READ);
5021 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5025 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5027 if (cm_HaveBuffer(scp, bufferp, 0)) {
5028 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5032 /* otherwise, load the buffer and try again */
5033 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5035 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5036 scp, bufferp, code);
5041 buf_Release(bufferp);
5045 } /* if (wrong buffer) ... */
5047 /* now we have the buffer containing the entry we're interested in; copy
5048 * it out if it represents a non-deleted entry.
5050 entryInDir = curOffset.LowPart & (2048-1);
5051 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5053 /* page header will help tell us which entries are free. Page header
5054 * can change more often than once per buffer, since AFS 3 dir page size
5055 * may be less than (but not more than a buffer package buffer.
5057 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
5058 temp &= ~(2048 - 1); /* turn off intra-page bits */
5059 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5061 /* now determine which entry we're looking at in the page. If it is
5062 * free (there's a free bitmap at the start of the dir), we should
5063 * skip these 32 bytes.
5065 slotInPage = (entryInDir & 0x7e0) >> 5;
5066 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5067 /* this entry is free */
5068 numDirChunks = 1; /* only skip this guy */
5072 tp = bufferp->datap + entryInBuffer;
5073 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
5075 /* while we're here, compute the next entry's location, too,
5076 * since we'll need it when writing out the cookie into the dir
5079 * XXXX Probably should do more sanity checking.
5081 numDirChunks = cm_NameEntries(dep->name, NULL);
5083 /* compute the offset of the cookie representing the next entry */
5084 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5086 /* Compute 8.3 name if necessary */
5087 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5088 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5091 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5092 actualName = shortName;
5093 free_actualName = 0;
5095 free_actualName = 1;
5098 if (actualName == NULL) {
5099 /* Couldn't convert the name for some reason */
5100 osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5101 osi_LogSaveString(smb_logp, dep->name));
5105 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5106 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5107 osi_LogSaveClientString(smb_logp, actualName));
5109 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5110 /* this is one of the entries to use: it is not deleted
5111 * and it matches the star pattern we're looking for.
5114 /* Eliminate entries that don't match requested
5117 /* no hidden files */
5118 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5119 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5123 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
5125 /* We have already done the cm_TryBulkStat above */
5126 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5127 fileType = cm_FindFileType(&fid);
5128 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5129 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5131 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5132 fileType == CM_SCACHETYPE_MOUNTPOINT ||
5133 fileType == CM_SCACHETYPE_DFSLINK ||
5134 fileType == CM_SCACHETYPE_INVALID)
5135 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5140 memcpy(op, mask, 11); op += 11;
5141 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
5142 *op++ = (unsigned char)(nextEntryCookie & 0xff);
5143 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5144 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5145 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5146 memcpy(op, &clientCookie, 4); op += 4;
5148 /* now we emit the attribute. This is sort of tricky,
5149 * since we need to really stat the file to find out
5150 * what type of entry we've got. Right now, we're
5151 * copying out data from a buffer, while holding the
5152 * scp locked, so it isn't really convenient to stat
5153 * something now. We'll put in a place holder now,
5154 * and make a second pass before returning this to get
5155 * the real attributes. So, we just skip the data for
5156 * now, and adjust it later. We allocate a patch
5157 * record to make it easy to find this point later.
5158 * The replay will happen at a time when it is safe to
5159 * unlock the directory.
5161 curPatchp = malloc(sizeof(*curPatchp));
5162 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5163 curPatchp->dptr = op;
5164 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5166 /* do hidden attribute here since name won't be around when applying
5170 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5171 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5173 curPatchp->flags = 0;
5175 op += 9; /* skip attr, time, date and size */
5177 /* zero out name area. The spec says to pad with
5178 * spaces, but Samba doesn't, and neither do we.
5182 /* finally, we get to copy out the name; we know that
5183 * it fits in 8.3 or the pattern wouldn't match, but it
5184 * never hurts to be sure.
5186 cm_ClientStringToUtf8(actualName, -1, op, 13);
5187 if (smb_StoreAnsiFilenames)
5189 /* This is a UCHAR field, which is ASCII even if Unicode
5192 /* Uppercase if requested by client */
5193 if (!KNOWS_LONG_NAMES(inp))
5198 /* now, adjust the # of entries copied */
5200 } /* if we're including this name */
5203 if (free_actualName && actualName) {
5208 /* and adjust curOffset to be where the new cookie is */
5209 thyper.HighPart = 0;
5210 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5211 curOffset = LargeIntegerAdd(thyper, curOffset);
5212 } /* while copying data for dir listing */
5214 /* release the mutex */
5215 lock_ReleaseWrite(&scp->rw);
5217 buf_Release(bufferp);
5221 /* apply and free last set of patches; if not doing a star match, this
5222 * will be empty, but better safe (and freeing everything) than sorry.
5224 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5226 /* special return code for unsuccessful search */
5227 if (code == 0 && dataLength < 21 && returnedNames == 0)
5228 code = CM_ERROR_NOFILES;
5230 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5231 returnedNames, code);
5234 smb_DeleteDirSearch(dsp);
5235 smb_ReleaseDirSearch(dsp);
5236 cm_ReleaseSCache(scp);
5237 cm_ReleaseUser(userp);
5241 /* finalize the output buffer */
5242 smb_SetSMBParm(outp, 0, returnedNames);
5243 temp = (long) (op - origOp);
5244 smb_SetSMBDataLength(outp, temp);
5246 /* the data area is a variable block, which has a 5 (already there)
5247 * followed by the length of the # of data bytes. We now know this to
5248 * be "temp," although that includes the 3 bytes of vbl block header.
5249 * Deduct for them and fill in the length field.
5251 temp -= 3; /* deduct vbl block info */
5252 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5253 origOp[1] = (unsigned char)(temp & 0xff);
5254 origOp[2] = (unsigned char)((temp>>8) & 0xff);
5255 if (returnedNames == 0)
5256 smb_DeleteDirSearch(dsp);
5257 smb_ReleaseDirSearch(dsp);
5258 cm_ReleaseSCache(scp);
5259 cm_ReleaseUser(userp);
5264 /* verify that this is a valid path to a directory. I don't know why they
5265 * don't use the get file attributes call.
5267 * SMB_COM_CHECK_DIRECTORY
5269 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5271 clientchar_t *pathp;
5273 cm_scache_t *rootScp;
5274 cm_scache_t *newScp;
5278 clientchar_t *tidPathp;
5284 pdata = smb_GetSMBData(inp, NULL);
5285 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5287 return CM_ERROR_BADSMB;
5288 osi_Log1(smb_logp, "SMB receive check path %S",
5289 osi_LogSaveClientString(smb_logp, pathp));
5291 rootScp = cm_data.rootSCachep;
5293 userp = smb_GetUserFromVCP(vcp, inp);
5295 caseFold = CM_FLAG_CASEFOLD;
5297 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5299 cm_ReleaseUser(userp);
5300 return CM_ERROR_NOSUCHPATH;
5302 code = cm_NameI(rootScp, pathp,
5303 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5304 userp, tidPathp, &req, &newScp);
5307 cm_ReleaseUser(userp);
5312 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5313 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5314 cm_ReleaseSCache(newScp);
5315 cm_ReleaseUser(userp);
5316 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5317 return CM_ERROR_PATH_NOT_COVERED;
5319 return CM_ERROR_NOSUCHPATH;
5321 #endif /* DFS_SUPPORT */
5323 /* now lock the vnode with a callback; returns with newScp locked */
5324 lock_ObtainWrite(&newScp->rw);
5325 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5326 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5328 if (code != CM_ERROR_NOACCESS) {
5329 lock_ReleaseWrite(&newScp->rw);
5330 cm_ReleaseSCache(newScp);
5331 cm_ReleaseUser(userp);
5335 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5338 attrs = smb_Attributes(newScp);
5340 if (!(attrs & SMB_ATTR_DIRECTORY))
5341 code = CM_ERROR_NOTDIR;
5343 lock_ReleaseWrite(&newScp->rw);
5345 cm_ReleaseSCache(newScp);
5346 cm_ReleaseUser(userp);
5350 /* SMB_COM_SET_INFORMATION */
5351 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5353 clientchar_t *pathp;
5355 cm_scache_t *rootScp;
5356 unsigned short attribute;
5358 cm_scache_t *newScp;
5362 clientchar_t *tidPathp;
5368 /* decode basic attributes we're passed */
5369 attribute = smb_GetSMBParm(inp, 0);
5370 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5372 datap = smb_GetSMBData(inp, NULL);
5373 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5375 return CM_ERROR_BADSMB;
5377 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5378 dosTime, attribute);
5380 rootScp = cm_data.rootSCachep;
5382 userp = smb_GetUserFromVCP(vcp, inp);
5384 caseFold = CM_FLAG_CASEFOLD;
5386 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5388 cm_ReleaseUser(userp);
5389 return CM_ERROR_NOSUCHFILE;
5391 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5392 tidPathp, &req, &newScp);
5395 cm_ReleaseUser(userp);
5400 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5401 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5402 cm_ReleaseSCache(newScp);
5403 cm_ReleaseUser(userp);
5404 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5405 return CM_ERROR_PATH_NOT_COVERED;
5407 return CM_ERROR_NOSUCHPATH;
5409 #endif /* DFS_SUPPORT */
5411 /* now lock the vnode with a callback; returns with newScp locked; we
5412 * need the current status to determine what the new status is, in some
5415 lock_ObtainWrite(&newScp->rw);
5416 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5417 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5419 lock_ReleaseWrite(&newScp->rw);
5420 cm_ReleaseSCache(newScp);
5421 cm_ReleaseUser(userp);
5425 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5427 /* Check for RO volume */
5428 if (newScp->flags & CM_SCACHEFLAG_RO) {
5429 lock_ReleaseWrite(&newScp->rw);
5430 cm_ReleaseSCache(newScp);
5431 cm_ReleaseUser(userp);
5432 return CM_ERROR_READONLY;
5435 /* prepare for setattr call */
5438 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5439 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5441 if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5442 /* we're told to make a writable file read-only */
5443 attr.unixModeBits = newScp->unixModeBits & ~0222;
5444 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5446 else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5447 /* we're told to make a read-only file writable */
5448 attr.unixModeBits = newScp->unixModeBits | 0222;
5449 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5451 lock_ReleaseWrite(&newScp->rw);
5453 /* now call setattr */
5455 code = cm_SetAttr(newScp, &attr, userp, &req);
5459 cm_ReleaseSCache(newScp);
5460 cm_ReleaseUser(userp);
5466 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5468 clientchar_t *pathp;
5470 cm_scache_t *rootScp;
5471 cm_scache_t *newScp, *dscp;
5476 clientchar_t *tidPathp;
5478 clientchar_t *lastComp;
5484 datap = smb_GetSMBData(inp, NULL);
5485 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5487 return CM_ERROR_BADSMB;
5489 if (*pathp == 0) /* null path */
5492 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5493 osi_LogSaveClientString(smb_logp, pathp));
5495 rootScp = cm_data.rootSCachep;
5497 userp = smb_GetUserFromVCP(vcp, inp);
5499 /* we shouldn't need this for V3 requests, but we seem to */
5500 caseFold = CM_FLAG_CASEFOLD;
5502 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5504 cm_ReleaseUser(userp);
5505 return CM_ERROR_NOSUCHFILE;
5509 * XXX Strange hack XXX
5511 * As of Patch 5 (16 July 97), we are having the following problem:
5512 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5513 * requests to look up "desktop.ini" in all the subdirectories.
5514 * This can cause zillions of timeouts looking up non-existent cells
5515 * and volumes, especially in the top-level directory.
5517 * We have not found any way to avoid this or work around it except
5518 * to explicitly ignore the requests for mount points that haven't
5519 * yet been evaluated and for directories that haven't yet been
5522 * We should modify this hack to provide a fake desktop.ini file
5523 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5525 spacep = inp->spacep;
5526 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5527 #ifndef SPECIAL_FOLDERS
5528 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5529 code = cm_NameI(rootScp, spacep->wdata,
5530 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5531 userp, tidPathp, &req, &dscp);
5534 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5535 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5537 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5538 return CM_ERROR_PATH_NOT_COVERED;
5540 return CM_ERROR_NOSUCHPATH;
5542 #endif /* DFS_SUPPORT */
5543 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5544 code = CM_ERROR_NOSUCHFILE;
5545 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5546 cm_buf_t *bp = buf_Find(dscp, &hzero);
5551 code = CM_ERROR_NOSUCHFILE;
5553 cm_ReleaseSCache(dscp);
5555 cm_ReleaseUser(userp);
5560 #endif /* SPECIAL_FOLDERS */
5562 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5563 tidPathp, &req, &newScp);
5565 cm_ReleaseUser(userp);
5570 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5571 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5572 cm_ReleaseSCache(newScp);
5573 cm_ReleaseUser(userp);
5574 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5575 return CM_ERROR_PATH_NOT_COVERED;
5577 return CM_ERROR_NOSUCHPATH;
5579 #endif /* DFS_SUPPORT */
5581 /* now lock the vnode with a callback; returns with newScp locked */
5582 lock_ObtainWrite(&newScp->rw);
5583 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5584 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5586 lock_ReleaseWrite(&newScp->rw);
5587 cm_ReleaseSCache(newScp);
5588 cm_ReleaseUser(userp);
5592 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5594 attrs = smb_Attributes(newScp);
5596 smb_SetSMBParm(outp, 0, attrs);
5598 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5599 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5600 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5601 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5602 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5603 smb_SetSMBParm(outp, 5, 0);
5604 smb_SetSMBParm(outp, 6, 0);
5605 smb_SetSMBParm(outp, 7, 0);
5606 smb_SetSMBParm(outp, 8, 0);
5607 smb_SetSMBParm(outp, 9, 0);
5608 smb_SetSMBDataLength(outp, 0);
5609 lock_ReleaseWrite(&newScp->rw);
5611 cm_ReleaseSCache(newScp);
5612 cm_ReleaseUser(userp);
5617 /* SMB_COM_TREE_DISCONNECT */
5618 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5622 osi_Log0(smb_logp, "SMB receive tree disconnect");
5624 /* find the tree and free it */
5625 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5627 lock_ObtainWrite(&smb_rctLock);
5629 smb_ReleaseTID(tidp, TRUE);
5630 lock_ReleaseWrite(&smb_rctLock);
5637 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5640 clientchar_t *pathp;
5641 clientchar_t *lastNamep;
5650 clientchar_t *tidPathp;
5656 datap = smb_GetSMBData(inp, NULL);
5657 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5659 return CM_ERROR_BADSMB;
5661 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5663 #ifdef DEBUG_VERBOSE
5667 hexpath = osi_HexifyString( pathp );
5668 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5673 share = smb_GetSMBParm(inp, 0);
5674 attribute = smb_GetSMBParm(inp, 1);
5676 spacep = inp->spacep;
5677 /* smb_StripLastComponent will strip "::$DATA" if present */
5678 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5680 if (!cm_IsValidClientString(pathp)) {
5682 clientchar_t * hexp;
5684 hexp = cm_GetRawCharsAlloc(pathp, -1);
5685 osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5686 osi_LogSaveClientString(smb_logp, hexp));
5690 osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5692 return CM_ERROR_BADNTFILENAME;
5695 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5696 /* special case magic file name for receiving IOCTL requests
5697 * (since IOCTL calls themselves aren't getting through).
5699 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5700 smb_SetupIoctlFid(fidp, spacep);
5701 smb_SetSMBParm(outp, 0, fidp->fid);
5702 smb_SetSMBParm(outp, 1, 0); /* attrs */
5703 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5704 smb_SetSMBParm(outp, 3, 0);
5705 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5706 smb_SetSMBParm(outp, 5, 0x7fff);
5707 /* pass the open mode back */
5708 smb_SetSMBParm(outp, 6, (share & 0xf));
5709 smb_SetSMBDataLength(outp, 0);
5710 smb_ReleaseFID(fidp);
5714 userp = smb_GetUserFromVCP(vcp, inp);
5716 caseFold = CM_FLAG_CASEFOLD;
5718 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5720 cm_ReleaseUser(userp);
5721 return CM_ERROR_NOSUCHPATH;
5723 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5724 tidPathp, &req, &scp);
5727 cm_ReleaseUser(userp);
5732 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5733 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5734 cm_ReleaseSCache(scp);
5735 cm_ReleaseUser(userp);
5736 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5737 return CM_ERROR_PATH_NOT_COVERED;
5739 return CM_ERROR_NOSUCHPATH;
5741 #endif /* DFS_SUPPORT */
5743 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5745 cm_ReleaseSCache(scp);
5746 cm_ReleaseUser(userp);
5750 /* don't need callback to check file type, since file types never
5751 * change, and namei and cm_Lookup all stat the object at least once on
5752 * a successful return.
5754 if (scp->fileType != CM_SCACHETYPE_FILE) {
5755 cm_ReleaseSCache(scp);
5756 cm_ReleaseUser(userp);
5757 return CM_ERROR_ISDIR;
5760 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5761 osi_assertx(fidp, "null smb_fid_t");
5763 lock_ObtainMutex(&fidp->mx);
5764 if ((share & 0xf) == 0)
5765 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5766 else if ((share & 0xf) == 1)
5767 fidp->flags |= SMB_FID_OPENWRITE;
5769 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5773 fidp->userp = userp;
5775 /* and a pointer to the vnode */
5777 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5778 lock_ObtainWrite(&scp->rw);
5779 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5781 smb_SetSMBParm(outp, 0, fidp->fid);
5782 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5783 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5784 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5785 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5786 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5787 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5788 /* pass the open mode back; XXXX add access checks */
5789 smb_SetSMBParm(outp, 6, (share & 0xf));
5790 smb_SetSMBDataLength(outp, 0);
5791 lock_ReleaseMutex(&fidp->mx);
5792 lock_ReleaseRead(&scp->rw);
5795 cm_Open(scp, 0, userp);
5797 /* send and free packet */
5798 smb_ReleaseFID(fidp);
5799 cm_ReleaseUser(userp);
5800 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5804 typedef struct smb_unlinkRock {
5809 clientchar_t *maskp; /* pointer to the star pattern */
5812 cm_dirEntryList_t * matches;
5815 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5818 smb_unlinkRock_t *rockp;
5821 normchar_t matchName[MAX_PATH];
5825 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5826 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5827 caseFold |= CM_FLAG_8DOT3;
5829 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5830 /* Can't convert name */
5831 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5832 osi_LogSaveString(smb_logp, dep->name));
5836 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5838 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5839 !cm_Is8Dot3(matchName)) {
5840 cm_Gen8Dot3Name(dep, matchName, NULL);
5841 /* 8.3 matches are always case insensitive */
5842 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5845 osi_Log1(smb_logp, "Found match %S",
5846 osi_LogSaveClientString(smb_logp, matchName));
5848 cm_DirEntryListAdd(dep->name, &rockp->matches);
5852 /* If we made a case sensitive exact match, we might as well quit now. */
5853 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5854 code = CM_ERROR_STOPNOW;
5863 /* SMB_COM_DELETE */
5864 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5868 clientchar_t *pathp;
5872 clientchar_t *lastNamep;
5873 smb_unlinkRock_t rock;
5877 clientchar_t *tidPathp;
5881 memset(&rock, 0, sizeof(rock));
5883 attribute = smb_GetSMBParm(inp, 0);
5885 tp = smb_GetSMBData(inp, NULL);
5886 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5888 return CM_ERROR_BADSMB;
5890 osi_Log1(smb_logp, "SMB receive unlink %S",
5891 osi_LogSaveClientString(smb_logp, pathp));
5893 spacep = inp->spacep;
5894 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5896 userp = smb_GetUserFromVCP(vcp, inp);
5898 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5900 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5902 cm_ReleaseUser(userp);
5903 return CM_ERROR_NOSUCHPATH;
5905 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5908 cm_ReleaseUser(userp);
5913 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5914 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5915 cm_ReleaseSCache(dscp);
5916 cm_ReleaseUser(userp);
5917 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5918 return CM_ERROR_PATH_NOT_COVERED;
5920 return CM_ERROR_NOSUCHPATH;
5922 #endif /* DFS_SUPPORT */
5924 /* otherwise, scp points to the parent directory. */
5931 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5933 code = CM_ERROR_NOSUCHFILE;
5936 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5939 thyper.HighPart = 0;
5944 rock.matches = NULL;
5946 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5947 * match. If that fails, we do a case insensitve match.
5949 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5950 !smb_IsStarMask(rock.maskp)) {
5951 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5954 thyper.HighPart = 0;
5955 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5960 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5962 if (code == CM_ERROR_STOPNOW)
5965 if (code == 0 && rock.matches) {
5966 cm_dirEntryList_t * entry;
5968 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5969 normchar_t normalizedName[MAX_PATH];
5971 /* Note: entry->name is a non-normalized name */
5973 osi_Log1(smb_logp, "Unlinking %s",
5974 osi_LogSaveString(smb_logp, entry->name));
5976 /* We assume this works because entry->name was
5977 successfully converted in smb_UnlinkProc() once. */
5978 cm_FsStringToNormString(entry->name, -1,
5979 normalizedName, lengthof(normalizedName));
5981 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5983 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5984 smb_NotifyChange(FILE_ACTION_REMOVED,
5985 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5986 dscp, normalizedName, NULL, TRUE);
5990 cm_DirEntryListFree(&rock.matches);
5994 cm_ReleaseUser(userp);
5997 cm_ReleaseSCache(dscp);
6002 if (code == 0 && !rock.any)
6003 code = CM_ERROR_NOSUCHFILE;
6007 typedef struct smb_renameRock {
6008 cm_scache_t *odscp; /* old dir */
6009 cm_scache_t *ndscp; /* new dir */
6010 cm_user_t *userp; /* user */
6011 cm_req_t *reqp; /* request struct */
6012 smb_vc_t *vcp; /* virtual circuit */
6013 normchar_t *maskp; /* pointer to star pattern of old file name */
6014 int flags; /* tilde, casefold, etc */
6015 clientchar_t *newNamep; /* ptr to the new file's name */
6016 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6017 clientchar_t clOldName[MAX_PATH]; /* client name */
6021 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6024 smb_renameRock_t *rockp;
6027 normchar_t matchName[MAX_PATH];
6029 rockp = (smb_renameRock_t *) vrockp;
6031 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6032 /* Can't convert string */
6033 osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6034 osi_LogSaveString(smb_logp, dep->name));
6038 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6039 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6040 caseFold |= CM_FLAG_8DOT3;
6042 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6044 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6045 !cm_Is8Dot3(matchName)) {
6046 cm_Gen8Dot3Name(dep, matchName, NULL);
6047 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6052 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6053 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6055 code = CM_ERROR_STOPNOW;
6065 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6068 cm_space_t *spacep = NULL;
6069 smb_renameRock_t rock;
6070 cm_scache_t *oldDscp = NULL;
6071 cm_scache_t *newDscp = NULL;
6072 cm_scache_t *tmpscp= NULL;
6073 cm_scache_t *tmpscp2 = NULL;
6074 clientchar_t *oldLastNamep;
6075 clientchar_t *newLastNamep;
6079 clientchar_t *tidPathp;
6083 userp = smb_GetUserFromVCP(vcp, inp);
6084 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6086 cm_ReleaseUser(userp);
6087 return CM_ERROR_NOSUCHPATH;
6091 memset(&rock, 0, sizeof(rock));
6093 spacep = inp->spacep;
6094 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6096 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6097 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6098 userp, tidPathp, &req, &oldDscp);
6100 cm_ReleaseUser(userp);
6105 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6106 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6107 cm_ReleaseSCache(oldDscp);
6108 cm_ReleaseUser(userp);
6109 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6110 return CM_ERROR_PATH_NOT_COVERED;
6112 return CM_ERROR_NOSUCHPATH;
6114 #endif /* DFS_SUPPORT */
6116 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6117 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6118 userp, tidPathp, &req, &newDscp);
6121 cm_ReleaseSCache(oldDscp);
6122 cm_ReleaseUser(userp);
6127 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6128 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6129 cm_ReleaseSCache(oldDscp);
6130 cm_ReleaseSCache(newDscp);
6131 cm_ReleaseUser(userp);
6132 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6133 return CM_ERROR_PATH_NOT_COVERED;
6135 return CM_ERROR_NOSUCHPATH;
6137 #endif /* DFS_SUPPORT */
6140 /* otherwise, oldDscp and newDscp point to the corresponding directories.
6141 * next, get the component names, and lower case them.
6144 /* handle the old name first */
6146 oldLastNamep = oldPathp;
6150 /* and handle the new name, too */
6152 newLastNamep = newPathp;
6156 /* TODO: The old name could be a wildcard. The new name must not be */
6158 /* Check if the file already exists; if so return error */
6159 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6160 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6161 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6163 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6164 osi_LogSaveClientString(smb_logp, newLastNamep));
6166 /* Check if the old and the new names differ only in case. If so return
6167 * success, else return CM_ERROR_EXISTS
6169 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6171 /* This would be a success only if the old file is *as same as* the new file */
6172 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6174 if (tmpscp == tmpscp2)
6177 code = CM_ERROR_EXISTS;
6178 cm_ReleaseSCache(tmpscp2);
6181 code = CM_ERROR_NOSUCHFILE;
6184 /* file exist, do not rename, also fixes move */
6185 osi_Log0(smb_logp, "Can't rename. Target already exists");
6186 code = CM_ERROR_EXISTS;
6191 /* do the vnode call */
6192 rock.odscp = oldDscp;
6193 rock.ndscp = newDscp;
6197 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6199 code = CM_ERROR_NOSUCHFILE;
6202 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6203 rock.newNamep = newLastNamep;
6204 rock.fsOldName[0] = '\0';
6205 rock.clOldName[0] = '\0';
6208 /* Now search the directory for the pattern, and do the appropriate rename when found */
6209 thyper.LowPart = 0; /* search dir from here */
6210 thyper.HighPart = 0;
6212 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6213 if (code == 0 && !rock.any) {
6215 thyper.HighPart = 0;
6216 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6217 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6219 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6221 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6222 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6223 rock.ndscp, rock.newNamep, rock.userp,
6225 /* if the call worked, stop doing the search now, since we
6226 * really only want to rename one file.
6229 osi_Log0(smb_logp, "cm_Rename failure");
6230 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6231 } else if (code == 0) {
6232 code = CM_ERROR_NOSUCHFILE;
6235 /* Handle Change Notification */
6237 * Being lazy, not distinguishing between files and dirs in this
6238 * filter, since we'd have to do a lookup.
6241 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6242 if (oldDscp == newDscp) {
6243 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6244 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6245 filter, oldDscp, rock.clOldName,
6246 newLastNamep, TRUE);
6248 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6249 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6250 filter, oldDscp, rock.clOldName,
6252 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6253 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6254 filter, newDscp, newLastNamep,
6261 cm_ReleaseSCache(tmpscp);
6263 cm_ReleaseUser(userp);
6265 cm_ReleaseSCache(oldDscp);
6267 cm_ReleaseSCache(newDscp);
6275 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6278 cm_space_t *spacep = NULL;
6279 cm_scache_t *oldDscp = NULL;
6280 cm_scache_t *newDscp = NULL;
6281 cm_scache_t *tmpscp= NULL;
6282 cm_scache_t *tmpscp2 = NULL;
6283 cm_scache_t *sscp = NULL;
6284 clientchar_t *oldLastNamep;
6285 clientchar_t *newLastNamep;
6288 clientchar_t *tidPathp;
6292 userp = smb_GetUserFromVCP(vcp, inp);
6294 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6296 cm_ReleaseUser(userp);
6297 return CM_ERROR_NOSUCHPATH;
6302 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6304 spacep = inp->spacep;
6305 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6307 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6308 userp, tidPathp, &req, &oldDscp);
6310 cm_ReleaseUser(userp);
6315 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6316 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6317 cm_ReleaseSCache(oldDscp);
6318 cm_ReleaseUser(userp);
6319 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6320 return CM_ERROR_PATH_NOT_COVERED;
6322 return CM_ERROR_NOSUCHPATH;
6324 #endif /* DFS_SUPPORT */
6326 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6327 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
6328 userp, tidPathp, &req, &newDscp);
6330 cm_ReleaseSCache(oldDscp);
6331 cm_ReleaseUser(userp);
6336 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6337 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6338 cm_ReleaseSCache(newDscp);
6339 cm_ReleaseSCache(oldDscp);
6340 cm_ReleaseUser(userp);
6341 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6342 return CM_ERROR_PATH_NOT_COVERED;
6344 return CM_ERROR_NOSUCHPATH;
6346 #endif /* DFS_SUPPORT */
6348 /* Now, although we did two lookups for the two directories (because the same
6349 * directory can be referenced through different paths), we only allow hard links
6350 * within the same directory. */
6351 if (oldDscp != newDscp) {
6352 cm_ReleaseSCache(oldDscp);
6353 cm_ReleaseSCache(newDscp);
6354 cm_ReleaseUser(userp);
6355 return CM_ERROR_CROSSDEVLINK;
6358 /* handle the old name first */
6360 oldLastNamep = oldPathp;
6364 /* and handle the new name, too */
6366 newLastNamep = newPathp;
6370 /* now lookup the old name */
6371 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6372 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6374 cm_ReleaseSCache(oldDscp);
6375 cm_ReleaseSCache(newDscp);
6376 cm_ReleaseUser(userp);
6380 /* Check if the file already exists; if so return error */
6381 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6382 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6383 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6385 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
6386 osi_LogSaveClientString(smb_logp, newLastNamep));
6388 /* if the existing link is to the same file, then we return success */
6390 if(sscp == tmpscp) {
6393 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
6394 code = CM_ERROR_EXISTS;
6399 cm_ReleaseSCache(tmpscp);
6400 cm_ReleaseSCache(sscp);
6401 cm_ReleaseSCache(newDscp);
6402 cm_ReleaseSCache(oldDscp);
6403 cm_ReleaseUser(userp);
6407 /* now create the hardlink */
6408 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6409 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6410 osi_Log1(smb_logp," Link returns 0x%x", code);
6412 /* Handle Change Notification */
6414 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6415 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6416 smb_NotifyChange(FILE_ACTION_ADDED,
6417 filter, newDscp, newLastNamep,
6422 cm_ReleaseSCache(tmpscp);
6423 cm_ReleaseUser(userp);
6424 cm_ReleaseSCache(sscp);
6425 cm_ReleaseSCache(oldDscp);
6426 cm_ReleaseSCache(newDscp);
6430 /* SMB_COM_RENAME */
6432 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6434 clientchar_t *oldPathp;
6435 clientchar_t *newPathp;
6439 tp = smb_GetSMBData(inp, NULL);
6440 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6442 return CM_ERROR_BADSMB;
6443 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6445 return CM_ERROR_BADSMB;
6447 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6448 osi_LogSaveClientString(smb_logp, oldPathp),
6449 osi_LogSaveClientString(smb_logp, newPathp));
6451 if (!cm_IsValidClientString(newPathp)) {
6453 clientchar_t * hexp;
6455 hexp = cm_GetRawCharsAlloc(newPathp, -1);
6456 osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6457 osi_LogSaveClientString(smb_logp, hexp));
6461 osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6463 return CM_ERROR_BADNTFILENAME;
6466 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6468 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6474 typedef struct smb_rmdirRock {
6478 normchar_t *maskp; /* pointer to the star pattern */
6481 cm_dirEntryList_t * matches;
6484 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6487 smb_rmdirRock_t *rockp;
6489 normchar_t matchName[MAX_PATH];
6491 rockp = (smb_rmdirRock_t *) vrockp;
6493 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6494 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6495 osi_LogSaveString(smb_logp, dep->name));
6499 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6500 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6502 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6504 (rockp->flags & SMB_MASKFLAG_TILDE) &&
6505 !cm_Is8Dot3(matchName)) {
6506 cm_Gen8Dot3Name(dep, matchName, NULL);
6507 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6512 cm_DirEntryListAdd(dep->name, &rockp->matches);
6519 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6522 clientchar_t *pathp;
6526 clientchar_t *lastNamep;
6527 smb_rmdirRock_t rock;
6531 clientchar_t *tidPathp;
6535 memset(&rock, 0, sizeof(rock));
6537 tp = smb_GetSMBData(inp, NULL);
6538 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6540 return CM_ERROR_BADSMB;
6542 spacep = inp->spacep;
6543 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6545 userp = smb_GetUserFromVCP(vcp, inp);
6547 caseFold = CM_FLAG_CASEFOLD;
6549 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6551 cm_ReleaseUser(userp);
6552 return CM_ERROR_NOSUCHPATH;
6554 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6555 userp, tidPathp, &req, &dscp);
6558 cm_ReleaseUser(userp);
6563 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6564 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6565 cm_ReleaseSCache(dscp);
6566 cm_ReleaseUser(userp);
6567 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6568 return CM_ERROR_PATH_NOT_COVERED;
6570 return CM_ERROR_NOSUCHPATH;
6572 #endif /* DFS_SUPPORT */
6574 /* otherwise, scp points to the parent directory. */
6581 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6583 code = CM_ERROR_NOSUCHFILE;
6586 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6589 thyper.HighPart = 0;
6593 rock.matches = NULL;
6595 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6596 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6597 if (code == 0 && !rock.any) {
6599 thyper.HighPart = 0;
6600 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6601 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6604 if (code == 0 && rock.matches) {
6605 cm_dirEntryList_t * entry;
6607 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6608 clientchar_t clientName[MAX_PATH];
6610 /* We assume this will succeed because smb_RmdirProc()
6611 successfully converted entry->name once above. */
6612 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6614 osi_Log1(smb_logp, "Removing directory %s",
6615 osi_LogSaveString(smb_logp, entry->name));
6617 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6619 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6620 smb_NotifyChange(FILE_ACTION_REMOVED,
6621 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6622 dscp, clientName, NULL, TRUE);
6628 cm_DirEntryListFree(&rock.matches);
6631 cm_ReleaseUser(userp);
6634 cm_ReleaseSCache(dscp);
6636 if (code == 0 && !rock.any)
6637 code = CM_ERROR_NOSUCHFILE;
6646 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6656 fid = smb_GetSMBParm(inp, 0);
6658 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6660 fid = smb_ChainFID(fid, inp);
6661 fidp = smb_FindFID(vcp, fid, 0);
6663 osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6665 return CM_ERROR_BADFD;
6667 userp = smb_GetUserFromVCP(vcp, inp);
6669 lock_ObtainMutex(&fidp->mx);
6670 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6671 cm_ReleaseUser(userp);
6672 lock_ReleaseMutex(&fidp->mx);
6673 smb_ReleaseFID(fidp);
6674 return CM_ERROR_BADFD;
6677 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6678 lock_ReleaseMutex(&fidp->mx);
6679 cm_ReleaseUser(userp);
6680 smb_CloseFID(vcp, fidp, NULL, 0);
6681 smb_ReleaseFID(fidp);
6682 return CM_ERROR_NOSUCHFILE;
6685 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6686 cm_scache_t * scp = fidp->scp;
6688 lock_ReleaseMutex(&fidp->mx);
6689 code = cm_FSync(scp, userp, &req);
6690 cm_ReleaseSCache(scp);
6692 lock_ReleaseMutex(&fidp->mx);
6696 cm_ReleaseUser(userp);
6697 smb_ReleaseFID(fidp);
6701 struct smb_FullNameRock {
6704 clientchar_t *fullName;
6705 fschar_t *originalName;
6708 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6711 normchar_t matchName[MAX_PATH];
6712 struct smb_FullNameRock *vrockp;
6714 vrockp = (struct smb_FullNameRock *)rockp;
6716 if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6717 osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6718 osi_LogSaveString(smb_logp, dep->name));
6722 if (!cm_Is8Dot3(matchName)) {
6723 clientchar_t shortName[13];
6725 cm_Gen8Dot3Name(dep, shortName, NULL);
6727 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6728 vrockp->fullName = cm_ClientStrDup(matchName);
6729 vrockp->originalName = cm_FsStrDup(dep->name);
6730 return CM_ERROR_STOPNOW;
6733 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6734 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6735 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6736 vrockp->fullName = cm_ClientStrDup(matchName);
6737 vrockp->originalName = cm_FsStrDup(dep->name);
6738 return CM_ERROR_STOPNOW;
6743 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6744 clientchar_t **newPathp, fschar_t ** originalPathp,
6745 cm_user_t *userp, cm_req_t *reqp)
6747 struct smb_FullNameRock rock;
6750 memset(&rock, 0, sizeof(rock));
6754 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6755 if (code == CM_ERROR_STOPNOW) {
6756 *newPathp = rock.fullName;
6757 *originalPathp = rock.originalName;
6759 *newPathp = cm_ClientStrDup(pathp);
6760 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6764 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6765 afs_uint32 dosTime) {
6768 cm_scache_t *dscp = NULL;
6769 clientchar_t *pathp = NULL;
6770 cm_scache_t * scp = NULL;
6771 cm_scache_t *delscp = NULL;
6772 int nullcreator = 0;
6774 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6775 fidp, fidp->fid, scp, vcp);
6778 lock_ObtainMutex(&fidp->mx);
6779 if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6781 lock_ReleaseMutex(&fidp->mx);
6782 osi_Log0(smb_logp, " No user specified. Not closing fid");
6783 return CM_ERROR_BADFD;
6786 userp = fidp->userp; /* no hold required since fidp is held
6787 throughout the function */
6788 lock_ReleaseMutex(&fidp->mx);
6793 lock_ObtainWrite(&smb_rctLock);
6794 if (fidp->deleteOk) {
6795 osi_Log0(smb_logp, " Fid already closed.");
6796 lock_ReleaseWrite(&smb_rctLock);
6797 return CM_ERROR_BADFD;
6800 lock_ReleaseWrite(&smb_rctLock);
6802 lock_ObtainMutex(&fidp->mx);
6803 if (fidp->NTopen_dscp) {
6804 dscp = fidp->NTopen_dscp;
6805 cm_HoldSCache(dscp);
6808 if (fidp->NTopen_pathp)
6809 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6816 /* Don't jump the gun on an async raw write */
6817 while (fidp->raw_writers) {
6818 lock_ReleaseMutex(&fidp->mx);
6819 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6820 lock_ObtainMutex(&fidp->mx);
6823 /* watch for ioctl closes, and read-only opens */
6825 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6826 == SMB_FID_OPENWRITE) {
6827 if (dosTime != 0 && dosTime != -1) {
6828 lock_ObtainWrite(&fidp->scp->rw);
6829 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6830 /* This fixes defect 10958 */
6831 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6832 smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6833 lock_ReleaseWrite(&fidp->scp->rw);
6835 if (smb_AsyncStore != 2) {
6836 lock_ReleaseMutex(&fidp->mx);
6837 code = cm_FSync(scp, userp, &req);
6838 lock_ObtainMutex(&fidp->mx);
6844 /* unlock any pending locks */
6845 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6846 scp->fileType == CM_SCACHETYPE_FILE) {
6850 lock_ReleaseMutex(&fidp->mx);
6852 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6854 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6855 lock_ObtainWrite(&scp->rw);
6857 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6858 CM_SCACHESYNC_NEEDCALLBACK
6859 | CM_SCACHESYNC_GETSTATUS
6860 | CM_SCACHESYNC_LOCK);
6864 "smb CoreClose SyncOp failure code 0x%x", tcode);
6865 goto post_syncopdone;
6868 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6870 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6874 lock_ReleaseWrite(&scp->rw);
6875 lock_ObtainMutex(&fidp->mx);
6878 if (fidp->flags & SMB_FID_DELONCLOSE) {
6879 clientchar_t *fullPathp = NULL;
6880 fschar_t *originalNamep = NULL;
6882 lock_ReleaseMutex(&fidp->mx);
6884 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6889 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6890 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6891 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6893 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6894 smb_NotifyChange(FILE_ACTION_REMOVED,
6895 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6896 dscp, fullPathp, NULL, TRUE);
6899 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6901 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6902 smb_NotifyChange(FILE_ACTION_REMOVED,
6903 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6904 dscp, fullPathp, NULL, TRUE);
6911 free(originalNamep);
6913 lock_ObtainMutex(&fidp->mx);
6914 fidp->flags &= ~SMB_FID_DELONCLOSE;
6917 /* if this was a newly created file, then clear the creator
6918 * in the stat cache entry. */
6919 if (fidp->flags & SMB_FID_CREATED) {
6921 fidp->flags &= ~SMB_FID_CREATED;
6924 if (fidp->flags & SMB_FID_NTOPEN) {
6925 cm_ReleaseSCache(fidp->NTopen_dscp);
6926 fidp->NTopen_dscp = NULL;
6927 free(fidp->NTopen_pathp);
6928 fidp->NTopen_pathp = NULL;
6929 fidp->flags &= ~SMB_FID_NTOPEN;
6931 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6932 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6935 if (fidp->NTopen_wholepathp) {
6936 free(fidp->NTopen_wholepathp);
6937 fidp->NTopen_wholepathp = NULL;
6941 cm_ReleaseSCache(fidp->scp);
6944 lock_ReleaseMutex(&fidp->mx);
6947 cm_ReleaseSCache(dscp);
6950 cm_ReleaseSCache(delscp);
6954 lock_ObtainWrite(&scp->rw);
6955 if (nullcreator && scp->creator == userp)
6956 scp->creator = NULL;
6957 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6958 lock_ReleaseWrite(&scp->rw);
6959 cm_ReleaseSCache(scp);
6969 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6977 fid = smb_GetSMBParm(inp, 0);
6978 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6980 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6982 fid = smb_ChainFID(fid, inp);
6983 fidp = smb_FindFID(vcp, fid, 0);
6985 osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
6987 return CM_ERROR_BADFD;
6990 userp = smb_GetUserFromVCP(vcp, inp);
6992 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6994 smb_ReleaseFID(fidp);
6995 cm_ReleaseUser(userp);
7000 * smb_ReadData -- common code for Read, Read And X, and Raw Read
7002 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7003 cm_user_t *userp, long *readp)
7009 osi_hyper_t fileLength;
7011 osi_hyper_t lastByte;
7012 osi_hyper_t bufferOffset;
7016 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7019 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7020 fidp->fid, offsetp->LowPart, count);
7024 lock_ObtainMutex(&fidp->mx);
7025 /* make sure we have a readable FD */
7026 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7027 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7028 fidp->fid, fidp->flags);
7029 lock_ReleaseMutex(&fidp->mx);
7030 code = CM_ERROR_BADFDOP;
7035 lock_ReleaseMutex(&fidp->mx);
7036 code = CM_ERROR_BADFD;
7047 lock_ObtainWrite(&scp->rw);
7049 if (offset.HighPart == 0) {
7050 chunk = offset.LowPart >> cm_logChunkSize;
7051 if (chunk != fidp->curr_chunk) {
7052 fidp->prev_chunk = fidp->curr_chunk;
7053 fidp->curr_chunk = chunk;
7055 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7058 lock_ReleaseMutex(&fidp->mx);
7060 /* start by looking up the file's end */
7061 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7062 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7066 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7068 /* now we have the entry locked, look up the length */
7069 fileLength = scp->length;
7071 /* adjust count down so that it won't go past EOF */
7072 thyper.LowPart = count;
7073 thyper.HighPart = 0;
7074 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
7076 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7077 /* we'd read past EOF, so just stop at fileLength bytes.
7078 * Start by computing how many bytes remain in the file.
7080 thyper = LargeIntegerSubtract(fileLength, offset);
7082 /* if we are past EOF, read 0 bytes */
7083 if (LargeIntegerLessThanZero(thyper))
7086 count = thyper.LowPart;
7091 /* now, copy the data one buffer at a time,
7092 * until we've filled the request packet
7095 /* if we've copied all the data requested, we're done */
7096 if (count <= 0) break;
7098 /* otherwise, load up a buffer of data */
7099 thyper.HighPart = offset.HighPart;
7100 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7101 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7104 buf_Release(bufferp);
7107 lock_ReleaseWrite(&scp->rw);
7109 code = buf_Get(scp, &thyper, &req, &bufferp);
7111 lock_ObtainWrite(&scp->rw);
7112 if (code) goto done;
7113 bufferOffset = thyper;
7115 /* now get the data in the cache */
7117 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7118 CM_SCACHESYNC_NEEDCALLBACK |
7119 CM_SCACHESYNC_READ);
7123 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7125 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7127 /* otherwise, load the buffer and try again */
7128 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7132 buf_Release(bufferp);
7136 } /* if (wrong buffer) ... */
7138 /* now we have the right buffer loaded. Copy out the
7139 * data from here to the user's buffer.
7141 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7143 /* and figure out how many bytes we want from this buffer */
7144 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7145 if (nbytes > count) nbytes = count; /* don't go past EOF */
7147 /* now copy the data */
7148 memcpy(op, bufferp->datap + bufIndex, nbytes);
7150 /* adjust counters, pointers, etc. */
7153 thyper.LowPart = nbytes;
7154 thyper.HighPart = 0;
7155 offset = LargeIntegerAdd(thyper, offset);
7159 lock_ReleaseWrite(&scp->rw);
7161 buf_Release(bufferp);
7163 if (code == 0 && sequential)
7164 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7166 cm_ReleaseSCache(scp);
7169 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7170 fidp->fid, code, *readp);
7175 * smb_WriteData -- common code for Write and Raw Write
7177 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7178 cm_user_t *userp, long *writtenp)
7180 osi_hyper_t offset = *offsetp;
7183 cm_scache_t *scp = NULL;
7184 osi_hyper_t fileLength; /* file's length at start of write */
7185 osi_hyper_t minLength; /* don't read past this */
7186 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
7187 cm_buf_t *bufferp = NULL;
7188 osi_hyper_t thyper; /* hyper tmp variable */
7189 osi_hyper_t bufferOffset;
7190 afs_uint32 bufIndex; /* index in buffer where our data is */
7191 int doWriteBack = 0;
7192 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7195 int needSyncOpDone = 0;
7197 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7198 fidp->fid, offsetp->LowPart, count);
7202 lock_ObtainMutex(&fidp->mx);
7203 /* make sure we have a writable FD */
7204 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7205 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7206 fidp->fid, fidp->flags);
7207 lock_ReleaseMutex(&fidp->mx);
7208 code = CM_ERROR_BADFDOP;
7216 lock_ReleaseMutex(&fidp->mx);
7218 lock_ObtainWrite(&scp->rw);
7219 /* start by looking up the file's end */
7220 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7221 CM_SCACHESYNC_NEEDCALLBACK
7222 | CM_SCACHESYNC_SETSTATUS
7223 | CM_SCACHESYNC_GETSTATUS);
7227 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7229 /* now we have the entry locked, look up the length */
7230 fileLength = scp->length;
7231 minLength = fileLength;
7232 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7233 minLength = scp->serverLength;
7235 /* adjust file length if we extend past EOF */
7236 thyper.LowPart = count;
7237 thyper.HighPart = 0;
7238 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
7239 if (LargeIntegerGreaterThan(thyper, fileLength)) {
7240 /* we'd write past EOF, so extend the file */
7241 scp->mask |= CM_SCACHEMASK_LENGTH;
7242 scp->length = thyper;
7243 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7245 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7247 /* now, if the new position (thyper) and the old (offset) are in
7248 * different storeback windows, remember to store back the previous
7249 * storeback window when we're done with the write.
7251 * the purpose of this logic is to slow down the CIFS client
7252 * in order to avoid the client disconnecting during the CLOSE
7253 * operation if there are too many dirty buffers left to write
7254 * than can be accomplished during 45 seconds. This used to be
7255 * based upon cm_chunkSize but we desire cm_chunkSize to be large
7256 * so that we can read larger amounts of data at a time.
7258 if (smb_AsyncStore == 1 &&
7259 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7260 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7261 /* they're different */
7263 writeBackOffset.HighPart = offset.HighPart;
7264 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7269 /* now, copy the data one buffer at a time, until we've filled the
7271 while (count != 0) {
7273 /* handle over quota or out of space */
7274 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7275 *writtenp = written;
7276 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7280 /* otherwise, load up a buffer of data */
7281 thyper.HighPart = offset.HighPart;
7282 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7283 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7286 if (needSyncOpDone) {
7287 cm_SyncOpDone(scp, bufferp,
7288 CM_SCACHESYNC_NEEDCALLBACK
7289 | CM_SCACHESYNC_WRITE
7290 | CM_SCACHESYNC_BUFLOCKED);
7293 lock_ReleaseMutex(&bufferp->mx);
7294 buf_Release(bufferp);
7297 lock_ReleaseWrite(&scp->rw);
7299 code = buf_Get(scp, &thyper, &req, &bufferp);
7301 lock_ObtainMutex(&bufferp->mx);
7302 lock_ObtainWrite(&scp->rw);
7303 if (code) goto done;
7305 bufferOffset = thyper;
7307 /* now get the data in the cache */
7309 if (!needSyncOpDone) {
7310 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7311 CM_SCACHESYNC_NEEDCALLBACK
7312 | CM_SCACHESYNC_WRITE
7313 | CM_SCACHESYNC_BUFLOCKED);
7320 /* If we're overwriting the entire buffer, or
7321 * if we're writing at or past EOF, mark the
7322 * buffer as current so we don't call
7323 * cm_GetBuffer. This skips the fetch from the
7324 * server in those cases where we're going to
7325 * obliterate all the data in the buffer anyway,
7326 * or in those cases where there is no useful
7327 * data at the server to start with.
7329 * Use minLength instead of scp->length, since
7330 * the latter has already been updated by this
7333 * The scp lock has been dropped multiple times
7334 * so the minLength must be refreshed before it
7338 minLength = scp->length;
7339 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7340 minLength = scp->serverLength;
7342 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7343 || LargeIntegerEqualTo(offset, bufferp->offset)
7344 && (count >= cm_data.buf_blockSize
7345 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7346 ConvertLongToLargeInteger(count)),
7348 if (count < cm_data.buf_blockSize
7349 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7350 memset(bufferp->datap, 0,
7351 cm_data.buf_blockSize);
7352 bufferp->dataVersion = scp->dataVersion;
7355 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7357 /* otherwise, load the buffer and try again */
7358 cm_SyncOpDone(scp, bufferp,
7359 CM_SCACHESYNC_NEEDCALLBACK
7360 | CM_SCACHESYNC_WRITE
7361 | CM_SCACHESYNC_BUFLOCKED);
7364 lock_ReleaseMutex(&bufferp->mx);
7365 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7367 lock_ReleaseWrite(&scp->rw);
7368 lock_ObtainMutex(&bufferp->mx);
7369 lock_ObtainWrite(&scp->rw);
7373 } /* if (wrong buffer) ... */
7375 /* now we have the right buffer loaded. Copy out the
7376 * data from here to the user's buffer.
7378 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7380 /* and figure out how many bytes we want from this buffer */
7381 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
7383 nbytes = count; /* don't go past end of request */
7385 /* now copy the data */
7386 memcpy(bufferp->datap + bufIndex, op, nbytes);
7387 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7389 /* adjust counters, pointers, etc. */
7393 offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7394 } /* while count != 0 */
7397 if (bufferp && needSyncOpDone) {
7398 cm_SyncOpDone(scp, bufferp,
7399 CM_SCACHESYNC_NEEDCALLBACK
7400 | CM_SCACHESYNC_WRITE
7401 | CM_SCACHESYNC_BUFLOCKED);
7404 lock_ReleaseWrite(&scp->rw);
7407 lock_ReleaseMutex(&bufferp->mx);
7408 buf_Release(bufferp);
7411 lock_ObtainMutex(&fidp->mx);
7412 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7413 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7415 lock_ReleaseMutex(&fidp->mx);
7416 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7417 fidp->NTopen_dscp, fidp->NTopen_pathp,
7420 lock_ReleaseMutex(&fidp->mx);
7424 if (smb_AsyncStore > 0) {
7428 lock_ObtainWrite(&scp->rw);
7429 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7431 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7432 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7434 lock_ReleaseWrite(&scp->rw);
7435 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7436 writeBackOffset.HighPart,
7437 smb_AsyncStoreSize, 0, userp);
7438 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7441 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7445 cm_ReleaseSCache(scp);
7448 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7449 fidp->fid, code, *writtenp);
7454 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7457 unsigned short count;
7459 unsigned short hint;
7460 long written = 0, total_written = 0;
7463 smb_t* smbp = (smb_t*) inp;
7467 cm_attr_t truncAttr; /* attribute struct used for truncating file */
7469 int inDataBlockCount;
7471 fd = smb_GetSMBParm(inp, 0);
7472 count = smb_GetSMBParm(inp, 1);
7473 offset.HighPart = 0; /* too bad */
7474 offset.LowPart = smb_GetSMBParmLong(inp, 2);
7475 hint = smb_GetSMBParm(inp, 4);
7477 op = smb_GetSMBData(inp, NULL);
7478 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7480 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7481 fd, offset.LowPart, count);
7483 fd = smb_ChainFID(fd, inp);
7484 fidp = smb_FindFID(vcp, fd, 0);
7486 osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7488 return CM_ERROR_BADFD;
7491 lock_ObtainMutex(&fidp->mx);
7492 if (fidp->flags & SMB_FID_IOCTL) {
7493 lock_ReleaseMutex(&fidp->mx);
7494 code = smb_IoctlWrite(fidp, vcp, inp, outp);
7495 smb_ReleaseFID(fidp);
7496 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7500 if (fidp->flags & SMB_FID_RPC) {
7501 lock_ReleaseMutex(&fidp->mx);
7502 code = smb_RPCWrite(fidp, vcp, inp, outp);
7503 smb_ReleaseFID(fidp);
7504 osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7509 lock_ReleaseMutex(&fidp->mx);
7510 smb_ReleaseFID(fidp);
7511 return CM_ERROR_BADFD;
7514 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7515 lock_ReleaseMutex(&fidp->mx);
7516 smb_CloseFID(vcp, fidp, NULL, 0);
7517 smb_ReleaseFID(fidp);
7518 return CM_ERROR_NOSUCHFILE;
7523 lock_ReleaseMutex(&fidp->mx);
7524 userp = smb_GetUserFromVCP(vcp, inp);
7528 LARGE_INTEGER LOffset;
7529 LARGE_INTEGER LLength;
7532 key = cm_GenerateKey(vcp->vcID, pid, fd);
7534 LOffset.HighPart = offset.HighPart;
7535 LOffset.LowPart = offset.LowPart;
7536 LLength.HighPart = 0;
7537 LLength.LowPart = count;
7539 lock_ObtainWrite(&scp->rw);
7540 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7541 lock_ReleaseWrite(&scp->rw);
7544 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7549 /* special case: 0 bytes transferred means truncate to this position */
7553 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7557 truncAttr.mask = CM_ATTRMASK_LENGTH;
7558 truncAttr.length.LowPart = offset.LowPart;
7559 truncAttr.length.HighPart = 0;
7560 lock_ObtainMutex(&fidp->mx);
7561 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7562 fidp->flags |= SMB_FID_LENGTHSETDONE;
7563 lock_ReleaseMutex(&fidp->mx);
7564 smb_SetSMBParm(outp, 0, 0 /* count */);
7565 smb_SetSMBDataLength(outp, 0);
7570 * Work around bug in NT client
7572 * When copying a file, the NT client should first copy the data,
7573 * then copy the last write time. But sometimes the NT client does
7574 * these in the wrong order, so the data copies would inadvertently
7575 * cause the last write time to be overwritten. We try to detect this,
7576 * and don't set client mod time if we think that would go against the
7579 lock_ObtainMutex(&fidp->mx);
7580 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7581 lock_ObtainWrite(&fidp->scp->rw);
7582 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7583 fidp->scp->clientModTime = time(NULL);
7584 lock_ReleaseWrite(&fidp->scp->rw);
7586 lock_ReleaseMutex(&fidp->mx);
7589 while ( code == 0 && count > 0 ) {
7590 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7591 if (code == 0 && written == 0)
7592 code = CM_ERROR_PARTIALWRITE;
7594 offset = LargeIntegerAdd(offset,
7595 ConvertLongToLargeInteger(written));
7596 count -= (unsigned short)written;
7597 total_written += written;
7601 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7602 total_written, code);
7604 /* set the packet data length to 3 bytes for the data block header,
7605 * plus the size of the data.
7607 smb_SetSMBParm(outp, 0, total_written);
7608 smb_SetSMBParmLong(outp, 1, offset.LowPart);
7609 smb_SetSMBParm(outp, 3, hint);
7610 smb_SetSMBDataLength(outp, 0);
7613 smb_ReleaseFID(fidp);
7614 cm_ReleaseUser(userp);
7615 cm_ReleaseSCache(scp);
7620 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7621 NCB *ncbp, raw_write_cont_t *rwcp)
7630 fd = smb_GetSMBParm(inp, 0);
7631 fidp = smb_FindFID(vcp, fd, 0);
7633 lock_ObtainMutex(&fidp->mx);
7635 lock_ReleaseMutex(&fidp->mx);
7636 smb_ReleaseFID(fidp);
7640 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7641 lock_ReleaseMutex(&fidp->mx);
7642 smb_CloseFID(vcp, fidp, NULL, 0);
7643 smb_ReleaseFID(fidp);
7646 lock_ReleaseMutex(&fidp->mx);
7648 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7649 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7651 userp = smb_GetUserFromVCP(vcp, inp);
7654 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7656 if (rwcp->writeMode & 0x1) { /* synchronous */
7659 smb_FormatResponsePacket(vcp, inp, outp);
7660 op = (smb_t *) outp;
7661 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7662 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7663 smb_SetSMBDataLength(outp, 0);
7664 smb_SendPacket(vcp, outp);
7665 smb_FreePacket(outp);
7667 else { /* asynchronous */
7668 lock_ObtainMutex(&fidp->mx);
7669 fidp->raw_writers--;
7670 if (fidp->raw_writers == 0)
7671 thrd_SetEvent(fidp->raw_write_event);
7672 lock_ReleaseMutex(&fidp->mx);
7675 /* Give back raw buffer */
7676 lock_ObtainMutex(&smb_RawBufLock);
7677 *((char **)rawBuf) = smb_RawBufs;
7678 smb_RawBufs = rawBuf;
7679 lock_ReleaseMutex(&smb_RawBufLock);
7681 smb_ReleaseFID(fidp);
7682 cm_ReleaseUser(userp);
7685 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7690 /* SMB_COM_WRITE_RAW */
7691 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7694 long count, written = 0, total_written = 0;
7698 smb_t *smbp = (smb_t*) inp;
7703 unsigned short writeMode;
7705 fd = smb_GetSMBParm(inp, 0);
7706 totalCount = smb_GetSMBParm(inp, 1);
7707 count = smb_GetSMBParm(inp, 10);
7708 writeMode = smb_GetSMBParm(inp, 7);
7710 op = (char *) inp->data;
7711 op += smb_GetSMBParm(inp, 11);
7713 offset.HighPart = 0;
7714 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7716 if (*inp->wctp == 14) {
7717 /* we received a 64-bit file offset */
7718 #ifdef AFS_LARGEFILES
7719 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7721 if (LargeIntegerLessThanZero(offset)) {
7723 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7724 offset.HighPart, offset.LowPart);
7725 return CM_ERROR_BADSMB;
7728 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7730 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7731 return CM_ERROR_BADSMB;
7734 offset.HighPart = 0;
7737 offset.HighPart = 0; /* 32-bit file offset */
7741 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7742 fd, offset.HighPart, offset.LowPart, count);
7744 " WriteRaw WriteMode 0x%x",
7747 fd = smb_ChainFID(fd, inp);
7748 fidp = smb_FindFID(vcp, fd, 0);
7750 osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7752 return CM_ERROR_BADFD;
7754 lock_ObtainMutex(&fidp->mx);
7756 lock_ReleaseMutex(&fidp->mx);
7757 smb_ReleaseFID(fidp);
7758 return CM_ERROR_BADFD;
7761 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7762 lock_ReleaseMutex(&fidp->mx);
7763 smb_CloseFID(vcp, fidp, NULL, 0);
7764 smb_ReleaseFID(fidp);
7765 return CM_ERROR_NOSUCHFILE;
7770 lock_ReleaseMutex(&fidp->mx);
7775 LARGE_INTEGER LOffset;
7776 LARGE_INTEGER LLength;
7779 key = cm_GenerateKey(vcp->vcID, pid, fd);
7781 LOffset.HighPart = offset.HighPart;
7782 LOffset.LowPart = offset.LowPart;
7783 LLength.HighPart = 0;
7784 LLength.LowPart = count;
7786 lock_ObtainWrite(&scp->rw);
7787 code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7788 lock_ReleaseWrite(&scp->rw);
7791 cm_ReleaseSCache(scp);
7792 smb_ReleaseFID(fidp);
7797 userp = smb_GetUserFromVCP(vcp, inp);
7800 * Work around bug in NT client
7802 * When copying a file, the NT client should first copy the data,
7803 * then copy the last write time. But sometimes the NT client does
7804 * these in the wrong order, so the data copies would inadvertently
7805 * cause the last write time to be overwritten. We try to detect this,
7806 * and don't set client mod time if we think that would go against the
7809 lock_ObtainMutex(&fidp->mx);
7810 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7811 lock_ObtainWrite(&fidp->scp->rw);
7812 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7813 fidp->scp->clientModTime = time(NULL);
7814 lock_ReleaseWrite(&fidp->scp->rw);
7816 lock_ReleaseMutex(&fidp->mx);
7819 while ( code == 0 && count > 0 ) {
7820 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7821 if (code == 0 && written == 0)
7822 code = CM_ERROR_PARTIALWRITE;
7824 offset = LargeIntegerAdd(offset,
7825 ConvertLongToLargeInteger(written));
7828 total_written += written;
7832 /* Get a raw buffer */
7835 lock_ObtainMutex(&smb_RawBufLock);
7837 /* Get a raw buf, from head of list */
7838 rawBuf = smb_RawBufs;
7839 smb_RawBufs = *(char **)smb_RawBufs;
7842 code = CM_ERROR_USESTD;
7844 lock_ReleaseMutex(&smb_RawBufLock);
7847 /* Don't allow a premature Close */
7848 if (code == 0 && (writeMode & 1) == 0) {
7849 lock_ObtainMutex(&fidp->mx);
7850 fidp->raw_writers++;
7851 thrd_ResetEvent(fidp->raw_write_event);
7852 lock_ReleaseMutex(&fidp->mx);
7855 smb_ReleaseFID(fidp);
7856 cm_ReleaseUser(userp);
7857 cm_ReleaseSCache(scp);
7860 smb_SetSMBParm(outp, 0, total_written);
7861 smb_SetSMBDataLength(outp, 0);
7862 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7867 offset = LargeIntegerAdd(offset,
7868 ConvertLongToLargeInteger(count));
7872 rwcp->offset.HighPart = offset.HighPart;
7873 rwcp->offset.LowPart = offset.LowPart;
7874 rwcp->count = totalCount - count;
7875 rwcp->writeMode = writeMode;
7876 rwcp->alreadyWritten = total_written;
7878 /* set the packet data length to 3 bytes for the data block header,
7879 * plus the size of the data.
7881 smb_SetSMBParm(outp, 0, 0xffff);
7882 smb_SetSMBDataLength(outp, 0);
7888 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7891 long count, finalCount;
7895 smb_t *smbp = (smb_t*) inp;
7901 fd = smb_GetSMBParm(inp, 0);
7902 count = smb_GetSMBParm(inp, 1);
7903 offset.HighPart = 0; /* too bad */
7904 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7906 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7907 fd, offset.LowPart, count);
7909 fd = smb_ChainFID(fd, inp);
7910 fidp = smb_FindFID(vcp, fd, 0);
7912 osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7914 return CM_ERROR_BADFD;
7916 lock_ObtainMutex(&fidp->mx);
7917 if (fidp->flags & SMB_FID_IOCTL) {
7918 lock_ReleaseMutex(&fidp->mx);
7919 code = smb_IoctlRead(fidp, vcp, inp, outp);
7920 smb_ReleaseFID(fidp);
7924 if (fidp->flags & SMB_FID_RPC) {
7925 lock_ReleaseMutex(&fidp->mx);
7926 code = smb_RPCRead(fidp, vcp, inp, outp);
7927 smb_ReleaseFID(fidp);
7932 lock_ReleaseMutex(&fidp->mx);
7933 smb_ReleaseFID(fidp);
7934 return CM_ERROR_BADFD;
7937 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7938 lock_ReleaseMutex(&fidp->mx);
7939 smb_CloseFID(vcp, fidp, NULL, 0);
7940 smb_ReleaseFID(fidp);
7941 return CM_ERROR_NOSUCHFILE;
7946 lock_ReleaseMutex(&fidp->mx);
7949 LARGE_INTEGER LOffset, LLength;
7953 key = cm_GenerateKey(vcp->vcID, pid, fd);
7955 LOffset.HighPart = 0;
7956 LOffset.LowPart = offset.LowPart;
7957 LLength.HighPart = 0;
7958 LLength.LowPart = count;
7960 lock_ObtainWrite(&scp->rw);
7961 code = cm_LockCheckRead(scp, LOffset, LLength, key);
7962 lock_ReleaseWrite(&scp->rw);
7965 cm_ReleaseSCache(scp);
7966 smb_ReleaseFID(fidp);
7970 userp = smb_GetUserFromVCP(vcp, inp);
7972 /* remember this for final results */
7973 smb_SetSMBParm(outp, 0, count);
7974 smb_SetSMBParm(outp, 1, 0);
7975 smb_SetSMBParm(outp, 2, 0);
7976 smb_SetSMBParm(outp, 3, 0);
7977 smb_SetSMBParm(outp, 4, 0);
7979 /* set the packet data length to 3 bytes for the data block header,
7980 * plus the size of the data.
7982 smb_SetSMBDataLength(outp, count+3);
7984 /* get op ptr after putting in the parms, since otherwise we don't
7985 * know where the data really is.
7987 op = smb_GetSMBData(outp, NULL);
7989 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7990 *op++ = 1; /* data block marker */
7991 *op++ = (unsigned char) (count & 0xff);
7992 *op++ = (unsigned char) ((count >> 8) & 0xff);
7994 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7996 /* fix some things up */
7997 smb_SetSMBParm(outp, 0, finalCount);
7998 smb_SetSMBDataLength(outp, finalCount+3);
8000 smb_ReleaseFID(fidp);
8002 cm_ReleaseUser(userp);
8003 cm_ReleaseSCache(scp);
8007 /* SMB_COM_CREATE_DIRECTORY */
8008 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8010 clientchar_t *pathp;
8015 cm_scache_t *dscp; /* dir we're dealing with */
8016 cm_scache_t *scp; /* file we're creating */
8018 int initialModeBits;
8019 clientchar_t *lastNamep;
8021 clientchar_t *tidPathp;
8028 /* compute initial mode bits based on read-only flag in attributes */
8029 initialModeBits = 0777;
8031 tp = smb_GetSMBData(inp, NULL);
8032 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8034 return CM_ERROR_BADSMB;
8036 spacep = inp->spacep;
8037 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8039 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8040 return CM_ERROR_EXISTS;
8042 userp = smb_GetUserFromVCP(vcp, inp);
8044 caseFold = CM_FLAG_CASEFOLD;
8046 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8048 cm_ReleaseUser(userp);
8049 return CM_ERROR_NOSUCHPATH;
8052 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
8053 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8054 userp, tidPathp, &req, &dscp);
8057 cm_ReleaseUser(userp);
8062 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8063 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8064 cm_ReleaseSCache(dscp);
8065 cm_ReleaseUser(userp);
8066 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8067 return CM_ERROR_PATH_NOT_COVERED;
8069 return CM_ERROR_NOSUCHPATH;
8071 #endif /* DFS_SUPPORT */
8073 /* otherwise, scp points to the parent directory. Do a lookup, and
8074 * fail if we find it. Otherwise, we do the create.
8080 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8081 if (scp) cm_ReleaseSCache(scp);
8082 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8083 if (code == 0) code = CM_ERROR_EXISTS;
8084 cm_ReleaseSCache(dscp);
8085 cm_ReleaseUser(userp);
8089 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8090 setAttr.clientModTime = time(NULL);
8091 smb_SetInitialModeBitsForDir(0, &setAttr);
8093 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8094 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8095 smb_NotifyChange(FILE_ACTION_ADDED,
8096 FILE_NOTIFY_CHANGE_DIR_NAME,
8097 dscp, lastNamep, NULL, TRUE);
8099 /* we don't need this any longer */
8100 cm_ReleaseSCache(dscp);
8103 /* something went wrong creating or truncating the file */
8104 cm_ReleaseUser(userp);
8108 /* otherwise we succeeded */
8109 smb_SetSMBDataLength(outp, 0);
8110 cm_ReleaseUser(userp);
8115 BOOL smb_IsLegalFilename(clientchar_t *filename)
8118 * Find the longest substring of filename that does not contain
8119 * any of the chars in illegalChars. If that substring is less
8120 * than the length of the whole string, then one or more of the
8121 * illegal chars is in filename.
8123 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8129 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8130 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8132 clientchar_t *pathp;
8138 cm_scache_t *dscp; /* dir we're dealing with */
8139 cm_scache_t *scp; /* file we're creating */
8143 clientchar_t *lastNamep;
8146 clientchar_t *tidPathp;
8148 int created = 0; /* the file was new */
8153 excl = (inp->inCom == 0x03)? 0 : 1;
8155 attributes = smb_GetSMBParm(inp, 0);
8156 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8158 tp = smb_GetSMBData(inp, NULL);
8159 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8161 return CM_ERROR_BADSMB;
8163 spacep = inp->spacep;
8164 /* smb_StripLastComponent will strip "::$DATA" if present */
8165 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8167 if (!cm_IsValidClientString(pathp)) {
8169 clientchar_t * hexp;
8171 hexp = cm_GetRawCharsAlloc(pathp, -1);
8172 osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8173 osi_LogSaveClientString(smb_logp, hexp));
8177 osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8179 return CM_ERROR_BADNTFILENAME;
8182 userp = smb_GetUserFromVCP(vcp, inp);
8184 caseFold = CM_FLAG_CASEFOLD;
8186 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8188 cm_ReleaseUser(userp);
8189 return CM_ERROR_NOSUCHPATH;
8191 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8192 userp, tidPathp, &req, &dscp);
8195 cm_ReleaseUser(userp);
8200 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8201 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8202 cm_ReleaseSCache(dscp);
8203 cm_ReleaseUser(userp);
8204 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8205 return CM_ERROR_PATH_NOT_COVERED;
8207 return CM_ERROR_NOSUCHPATH;
8209 #endif /* DFS_SUPPORT */
8211 /* otherwise, scp points to the parent directory. Do a lookup, and
8212 * truncate the file if we find it, otherwise we create the file.
8219 if (!smb_IsLegalFilename(lastNamep))
8220 return CM_ERROR_BADNTFILENAME;
8222 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8223 #ifdef DEBUG_VERBOSE
8226 hexp = osi_HexifyString( lastNamep );
8227 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8232 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8233 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8234 cm_ReleaseSCache(dscp);
8235 cm_ReleaseUser(userp);
8239 /* if we get here, if code is 0, the file exists and is represented by
8240 * scp. Otherwise, we have to create it.
8244 /* oops, file shouldn't be there */
8245 cm_ReleaseSCache(dscp);
8246 cm_ReleaseSCache(scp);
8247 cm_ReleaseUser(userp);
8248 return CM_ERROR_EXISTS;
8251 setAttr.mask = CM_ATTRMASK_LENGTH;
8252 setAttr.length.LowPart = 0;
8253 setAttr.length.HighPart = 0;
8254 code = cm_SetAttr(scp, &setAttr, userp, &req);
8257 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8258 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8259 smb_SetInitialModeBitsForFile(attributes, &setAttr);
8261 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8265 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8266 smb_NotifyChange(FILE_ACTION_ADDED,
8267 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8268 dscp, lastNamep, NULL, TRUE);
8269 } else if (!excl && code == CM_ERROR_EXISTS) {
8270 /* not an exclusive create, and someone else tried
8271 * creating it already, then we open it anyway. We
8272 * don't bother retrying after this, since if this next
8273 * fails, that means that the file was deleted after
8274 * we started this call.
8276 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8279 setAttr.mask = CM_ATTRMASK_LENGTH;
8280 setAttr.length.LowPart = 0;
8281 setAttr.length.HighPart = 0;
8282 code = cm_SetAttr(scp, &setAttr, userp, &req);
8287 /* we don't need this any longer */
8288 cm_ReleaseSCache(dscp);
8291 /* something went wrong creating or truncating the file */
8292 if (scp) cm_ReleaseSCache(scp);
8293 cm_ReleaseUser(userp);
8297 /* make sure we only open files */
8298 if (scp->fileType != CM_SCACHETYPE_FILE) {
8299 cm_ReleaseSCache(scp);
8300 cm_ReleaseUser(userp);
8301 return CM_ERROR_ISDIR;
8304 /* now all we have to do is open the file itself */
8305 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8306 osi_assertx(fidp, "null smb_fid_t");
8310 lock_ObtainMutex(&fidp->mx);
8311 /* always create it open for read/write */
8312 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8314 /* remember that the file was newly created */
8316 fidp->flags |= SMB_FID_CREATED;
8318 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8320 /* save a pointer to the vnode */
8322 lock_ObtainWrite(&scp->rw);
8323 scp->flags |= CM_SCACHEFLAG_SMB_FID;
8324 lock_ReleaseWrite(&scp->rw);
8327 fidp->userp = userp;
8328 lock_ReleaseMutex(&fidp->mx);
8330 smb_SetSMBParm(outp, 0, fidp->fid);
8331 smb_SetSMBDataLength(outp, 0);
8333 cm_Open(scp, 0, userp);
8335 smb_ReleaseFID(fidp);
8336 cm_ReleaseUser(userp);
8337 /* leave scp held since we put it in fidp->scp */
8342 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8345 osi_hyper_t new_offset;
8356 fd = smb_GetSMBParm(inp, 0);
8357 whence = smb_GetSMBParm(inp, 1);
8358 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8360 /* try to find the file descriptor */
8361 fd = smb_ChainFID(fd, inp);
8362 fidp = smb_FindFID(vcp, fd, 0);
8364 osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8366 return CM_ERROR_BADFD;
8368 lock_ObtainMutex(&fidp->mx);
8369 if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8370 lock_ReleaseMutex(&fidp->mx);
8371 smb_ReleaseFID(fidp);
8372 return CM_ERROR_BADFD;
8375 if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8376 lock_ReleaseMutex(&fidp->mx);
8377 smb_CloseFID(vcp, fidp, NULL, 0);
8378 smb_ReleaseFID(fidp);
8379 return CM_ERROR_NOSUCHFILE;
8382 lock_ReleaseMutex(&fidp->mx);
8384 userp = smb_GetUserFromVCP(vcp, inp);
8386 lock_ObtainMutex(&fidp->mx);
8389 lock_ReleaseMutex(&fidp->mx);
8390 lock_ObtainWrite(&scp->rw);
8391 code = cm_SyncOp(scp, NULL, userp, &req, 0,
8392 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8394 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8396 /* offset from current offset */
8397 new_offset = LargeIntegerAdd(fidp->offset,
8398 ConvertLongToLargeInteger(offset));
8400 else if (whence == 2) {
8401 /* offset from current EOF */
8402 new_offset = LargeIntegerAdd(scp->length,
8403 ConvertLongToLargeInteger(offset));
8405 new_offset = ConvertLongToLargeInteger(offset);
8408 fidp->offset = new_offset;
8409 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8410 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8411 smb_SetSMBDataLength(outp, 0);
8413 lock_ReleaseWrite(&scp->rw);
8414 smb_ReleaseFID(fidp);
8415 cm_ReleaseSCache(scp);
8416 cm_ReleaseUser(userp);
8420 /* dispatch all of the requests received in a packet. Due to chaining, this may
8421 * be more than one request.
8423 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8424 NCB *ncbp, raw_write_cont_t *rwcp)
8428 unsigned long code = 0;
8429 unsigned char *outWctp;
8430 int nparms; /* # of bytes of parameters */
8432 int nbytes; /* bytes of data, excluding count */
8435 unsigned short errCode;
8436 unsigned long NTStatus;
8438 unsigned char errClass;
8439 unsigned int oldGen;
8440 DWORD oldTime, newTime;
8442 /* get easy pointer to the data */
8443 smbp = (smb_t *) inp->data;
8445 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8446 /* setup the basic parms for the initial request in the packet */
8447 inp->inCom = smbp->com;
8448 inp->wctp = &smbp->wct;
8450 inp->ncb_length = ncbp->ncb_length;
8455 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8456 /* log it and discard it */
8457 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8458 __FILE__, __LINE__, ncbp->ncb_length);
8459 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8463 /* We are an ongoing op */
8464 thrd_Increment(&ongoingOps);
8466 /* set up response packet for receiving output */
8467 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8468 smb_FormatResponsePacket(vcp, inp, outp);
8469 outWctp = outp->wctp;
8471 /* Remember session generation number and time */
8472 oldGen = sessionGen;
8473 oldTime = GetTickCount();
8475 while (inp->inCom != 0xff) {
8476 dp = &smb_dispatchTable[inp->inCom];
8478 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8479 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8480 code = outp->resumeCode;
8484 /* process each request in the packet; inCom, wctp and inCount
8485 * are already set up.
8487 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8490 /* now do the dispatch */
8491 /* start by formatting the response record a little, as a default */
8492 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8494 outWctp[1] = 0xff; /* no operation */
8495 outWctp[2] = 0; /* padding */
8500 /* not a chained request, this is a more reasonable default */
8501 outWctp[0] = 0; /* wct of zero */
8502 outWctp[1] = 0; /* and bcc (word) of zero */
8506 /* once set, stays set. Doesn't matter, since we never chain
8507 * "no response" calls.
8509 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8513 /* we have a recognized operation */
8514 char * opName = myCrt_Dispatch(inp->inCom);
8517 smbp = (smb_t *) inp;
8519 osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8520 opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8521 if (inp->inCom == 0x1d) {
8523 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8525 code = (*(dp->procp)) (vcp, inp, outp);
8527 osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8528 code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8530 newTime = GetTickCount();
8531 osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8532 opName, smbp->mid, newTime - oldTime);
8535 if ( code == CM_ERROR_BADSMB ||
8536 code == CM_ERROR_BADOP )
8538 #endif /* LOG_PACKET */
8540 /* ReceiveV3Tran2A handles its own logging */
8541 if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8544 clientchar_t *treepath = NULL; /* do not free */
8545 clientchar_t *pathname = NULL;
8546 cm_fid_t afid = {0,0,0,0,0};
8548 uidp = smb_FindUID(vcp, smbp->uid, 0);
8549 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8550 fidp = smb_FindFID(vcp, inp->fid, 0);
8553 lock_ObtainMutex(&fidp->mx);
8554 if (fidp->NTopen_pathp)
8555 pathname = fidp->NTopen_pathp;
8557 afid = fidp->scp->fid;
8559 if (inp->stringsp->wdata)
8560 pathname = inp->stringsp->wdata;
8563 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)",
8564 opName, newTime - oldTime,
8565 smbp->uid, uidp ? uidp->unp->name : NULL,
8566 smbp->pid, smbp->mid, smbp->tid,
8569 afid.cell, afid.volume, afid.vnode, afid.unique);
8572 lock_ReleaseMutex(&fidp->mx);
8575 smb_ReleaseUID(uidp);
8577 smb_ReleaseFID(fidp);
8580 if (oldGen != sessionGen) {
8581 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8582 newTime - oldTime, ncbp->ncb_length);
8583 osi_Log3(smb_logp, "Request %s straddled session startup, "
8584 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8587 FreeSMBStrings(inp);
8589 /* bad opcode, fail the request, after displaying it */
8590 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8593 #endif /* LOG_PACKET */
8596 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8597 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8598 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8599 if (code == IDCANCEL)
8602 code = CM_ERROR_BADOP;
8605 /* catastrophic failure: log as much as possible */
8606 if (code == CM_ERROR_BADSMB) {
8607 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8611 #endif /* LOG_PACKET */
8612 osi_Log1(smb_logp, "Invalid SMB message, length %d",
8615 code = CM_ERROR_INVAL;
8618 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8619 thrd_Decrement(&ongoingOps);
8624 /* now, if we failed, turn the current response into an empty
8625 * one, and fill in the response packet's error code.
8628 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8629 smb_MapNTError(code, &NTStatus);
8630 outWctp = outp->wctp;
8631 smbp = (smb_t *) &outp->data;
8632 if (code != CM_ERROR_PARTIALWRITE
8633 && code != CM_ERROR_BUFFERTOOSMALL
8634 && code != CM_ERROR_GSSCONTINUE) {
8635 /* nuke wct and bcc. For a partial
8636 * write or an in-process authentication handshake,
8637 * assume they're OK.
8643 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8644 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8645 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8646 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8647 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8651 smb_MapCoreError(code, vcp, &errCode, &errClass);
8652 outWctp = outp->wctp;
8653 smbp = (smb_t *) &outp->data;
8654 if (code != CM_ERROR_PARTIALWRITE) {
8655 /* nuke wct and bcc. For a partial
8656 * write, assume they're OK.
8662 smbp->errLow = (unsigned char) (errCode & 0xff);
8663 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8664 smbp->rcls = errClass;
8667 } /* error occurred */
8669 /* if we're here, we've finished one request. Look to see if
8670 * this is a chained opcode. If it is, setup things to process
8671 * the chained request, and setup the output buffer to hold the
8672 * chained response. Start by finding the next input record.
8674 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8675 break; /* not a chained req */
8676 tp = inp->wctp; /* points to start of last request */
8677 /* in a chained request, the first two
8678 * parm fields are required, and are
8679 * AndXCommand/AndXReserved and
8681 if (tp[0] < 2) break;
8682 if (tp[1] == 0xff) break; /* no more chained opcodes */
8684 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8687 /* and now append the next output request to the end of this
8688 * last request. Begin by finding out where the last response
8689 * ends, since that's where we'll put our new response.
8691 outWctp = outp->wctp; /* ptr to out parameters */
8692 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
8693 nparms = outWctp[0] << 1;
8694 tp = outWctp + nparms + 1; /* now points to bcc field */
8695 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
8696 tp += 2 /* for the count itself */ + nbytes;
8697 /* tp now points to the new output record; go back and patch the
8698 * second parameter (off2) to point to the new record.
8700 temp = (unsigned int)(tp - outp->data);
8701 outWctp[3] = (unsigned char) (temp & 0xff);
8702 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8703 outWctp[2] = 0; /* padding */
8704 outWctp[1] = inp->inCom; /* next opcode */
8706 /* finally, setup for the next iteration */
8709 } /* while loop over all requests in the packet */
8711 /* now send the output packet, and return */
8713 smb_SendPacket(vcp, outp);
8714 thrd_Decrement(&ongoingOps);
8719 /* Wait for Netbios() calls to return, and make the results available to server
8720 * threads. Note that server threads can't wait on the NCBevents array
8721 * themselves, because NCB events are manual-reset, and the servers would race
8722 * each other to reset them.
8724 void smb_ClientWaiter(void *parmp)
8729 while (smbShutdownFlag == 0) {
8730 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8732 if (code == WAIT_OBJECT_0)
8735 /* error checking */
8736 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8738 int abandonIdx = code - WAIT_ABANDONED_0;
8739 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8742 if (code == WAIT_IO_COMPLETION)
8744 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8748 if (code == WAIT_TIMEOUT)
8750 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8753 if (code == WAIT_FAILED)
8755 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8758 idx = code - WAIT_OBJECT_0;
8760 /* check idx range! */
8761 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8763 /* this is fatal - log as much as possible */
8764 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8765 osi_assertx(0, "invalid index");
8768 thrd_ResetEvent(NCBevents[idx]);
8769 thrd_SetEvent(NCBreturns[0][idx]);
8774 * Try to have one NCBRECV request waiting for every live session. Not more
8775 * than one, because if there is more than one, it's hard to handle Write Raw.
8777 void smb_ServerWaiter(void *parmp)
8780 int idx_session, idx_NCB;
8783 while (smbShutdownFlag == 0) {
8785 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8787 if (code == WAIT_OBJECT_0)
8790 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8792 int abandonIdx = code - WAIT_ABANDONED_0;
8793 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8796 if (code == WAIT_IO_COMPLETION)
8798 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8802 if (code == WAIT_TIMEOUT)
8804 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8807 if (code == WAIT_FAILED)
8809 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8812 idx_session = code - WAIT_OBJECT_0;
8814 /* check idx range! */
8815 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8817 /* this is fatal - log as much as possible */
8818 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8819 osi_assertx(0, "invalid index");
8824 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8826 if (code == WAIT_OBJECT_0) {
8827 if (smbShutdownFlag == 1)
8833 /* error checking */
8834 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8836 int abandonIdx = code - WAIT_ABANDONED_0;
8837 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8840 if (code == WAIT_IO_COMPLETION)
8842 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8846 if (code == WAIT_TIMEOUT)
8848 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8851 if (code == WAIT_FAILED)
8853 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8856 idx_NCB = code - WAIT_OBJECT_0;
8858 /* check idx range! */
8859 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8861 /* this is fatal - log as much as possible */
8862 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8863 osi_assertx(0, "invalid index");
8866 /* Link them together */
8867 NCBsessions[idx_NCB] = idx_session;
8870 ncbp = NCBs[idx_NCB];
8871 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8872 ncbp->ncb_command = NCBRECV | ASYNCH;
8873 ncbp->ncb_lana_num = lanas[idx_session];
8874 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8875 ncbp->ncb_event = NCBevents[idx_NCB];
8876 ncbp->ncb_length = SMB_PACKETSIZE;
8882 * The top level loop for handling SMB request messages. Each server thread
8883 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8884 * NCB and buffer for the incoming request are loaned to us.
8886 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8887 * to immediately send a request for the rest of the data. This must come
8888 * before any other traffic for that session, so we delay setting the session
8889 * event until that data has come in.
8891 void smb_Server(VOID *parmp)
8893 INT_PTR myIdx = (INT_PTR) parmp;
8897 smb_packet_t *outbufp;
8899 int idx_NCB, idx_session;
8901 smb_vc_t *vcp = NULL;
8903 extern void rx_StartClientThread(void);
8905 rx_StartClientThread();
8907 outncbp = smb_GetNCB();
8908 outbufp = smb_GetPacket();
8909 outbufp->ncbp = outncbp;
8917 cm_ResetServerPriority();
8919 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8922 /* terminate silently if shutdown flag is set */
8923 if (code == WAIT_OBJECT_0) {
8924 if (smbShutdownFlag == 1) {
8925 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8931 /* error checking */
8932 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8934 int abandonIdx = code - WAIT_ABANDONED_0;
8935 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8938 if (code == WAIT_IO_COMPLETION)
8940 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8944 if (code == WAIT_TIMEOUT)
8946 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8949 if (code == WAIT_FAILED)
8951 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8954 idx_NCB = code - WAIT_OBJECT_0;
8956 /* check idx range! */
8957 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8959 /* this is fatal - log as much as possible */
8960 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8961 osi_assertx(0, "invalid index");
8964 ncbp = NCBs[idx_NCB];
8965 idx_session = NCBsessions[idx_NCB];
8966 rc = ncbp->ncb_retcode;
8968 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8969 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8973 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8977 /* Can this happen? Or is it just my UNIX paranoia? */
8978 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8983 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8986 /* Client closed session */
8987 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8989 lock_ObtainMutex(&vcp->mx);
8990 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8991 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8993 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8994 lock_ReleaseMutex(&vcp->mx);
8995 lock_ObtainWrite(&smb_globalLock);
8996 dead_sessions[vcp->session] = TRUE;
8997 lock_ReleaseWrite(&smb_globalLock);
8999 lock_ReleaseMutex(&vcp->mx);
9001 smb_CleanupDeadVC(vcp);
9008 /* Treat as transient error */
9009 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9012 "dispatch smb recv failed, message incomplete, ncb_length %d",
9015 "SMB message incomplete, "
9016 "length %d", ncbp->ncb_length);
9019 * We used to discard the packet.
9020 * Instead, try handling it normally.
9024 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9028 /* A weird error code. Log it, sleep, and continue. */
9029 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9031 lock_ObtainMutex(&vcp->mx);
9032 if (vcp->errorCount++ > 3) {
9033 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9034 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9035 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9037 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9038 lock_ReleaseMutex(&vcp->mx);
9039 lock_ObtainWrite(&smb_globalLock);
9040 dead_sessions[vcp->session] = TRUE;
9041 lock_ReleaseWrite(&smb_globalLock);
9043 lock_ReleaseMutex(&vcp->mx);
9045 smb_CleanupDeadVC(vcp);
9051 lock_ReleaseMutex(&vcp->mx);
9055 thrd_SetEvent(SessionEvents[idx_session]);
9061 /* Success, so now dispatch on all the data in the packet */
9063 smb_concurrentCalls++;
9064 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9065 smb_maxObsConcurrentCalls = smb_concurrentCalls;
9068 * If at this point vcp is NULL (implies that packet was invalid)
9069 * then we are in big trouble. This means either :
9070 * a) we have the wrong NCB.
9071 * b) Netbios screwed up the call.
9072 * c) The VC was already marked dead before we were able to
9074 * Obviously this implies that
9075 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
9076 * lanas[idx_session] != ncbp->ncb_lana_num )
9077 * Either way, we can't do anything with this packet.
9078 * Log, sleep and resume.
9081 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9085 ncbp->ncb_lana_num);
9087 /* Also log in the trace log. */
9088 osi_Log4(smb_logp, "Server: VCP does not exist!"
9089 "LSNs[idx_session]=[%d],"
9090 "lanas[idx_session]=[%d],"
9091 "ncbp->ncb_lsn=[%d],"
9092 "ncbp->ncb_lana_num=[%d]",
9096 ncbp->ncb_lana_num);
9098 /* thrd_Sleep(1000); Don't bother sleeping */
9099 thrd_SetEvent(SessionEvents[idx_session]);
9100 smb_concurrentCalls--;
9104 cm_SetRequestStartTime();
9106 vcp->errorCount = 0;
9107 bufp = (struct smb_packet *) ncbp->ncb_buffer;
9108 smbp = (smb_t *)bufp->data;
9115 if (smbp->com == 0x1d) {
9116 /* Special handling for Write Raw */
9117 raw_write_cont_t rwc;
9119 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9120 if (rwc.code == 0) {
9121 EVENT_HANDLE rwevent;
9122 char eventName[MAX_PATH];
9124 snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9125 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9126 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9127 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9129 ncbp->ncb_command = NCBRECV | ASYNCH;
9130 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9131 ncbp->ncb_lana_num = vcp->lana;
9132 ncbp->ncb_buffer = rwc.buf;
9133 ncbp->ncb_length = 65535;
9134 ncbp->ncb_event = rwevent;
9136 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9137 thrd_CloseHandle(rwevent);
9139 thrd_SetEvent(SessionEvents[idx_session]);
9141 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9143 else if (smbp->com == 0xa0) {
9145 * Serialize the handling for NT Transact
9148 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9149 thrd_SetEvent(SessionEvents[idx_session]);
9151 thrd_SetEvent(SessionEvents[idx_session]);
9152 /* TODO: what else needs to be serialized? */
9153 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9157 __except( smb_ServerExceptionFilter() ) {
9161 smb_concurrentCalls--;
9164 thrd_SetEvent(NCBavails[idx_NCB]);
9169 smb_FreePacket(outbufp);
9171 smb_FreeNCB(outncbp);
9175 * Exception filter for the server threads. If an exception occurs in the
9176 * dispatch routines, which is where exceptions are most common, then do a
9177 * force trace and give control to upstream exception handlers. Useful for
9180 DWORD smb_ServerExceptionFilter(void) {
9181 /* While this is not the best time to do a trace, if it succeeds, then
9182 * we have a trace (assuming tracing was enabled). Otherwise, this should
9183 * throw a second exception.
9185 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9186 afsd_ForceTrace(TRUE);
9187 buf_ForceTrace(TRUE);
9188 return EXCEPTION_CONTINUE_SEARCH;
9192 * Create a new NCB and associated events, packet buffer, and "space" buffer.
9193 * If the number of server threads is M, and the number of live sessions is
9194 * N, then the number of NCB's in use at any time either waiting for, or
9195 * holding, received messages is M + N, so that is how many NCB's get created.
9197 void InitNCBslot(int idx)
9199 struct smb_packet *bufp;
9200 EVENT_HANDLE retHandle;
9202 char eventName[MAX_PATH];
9204 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9206 NCBs[idx] = smb_GetNCB();
9207 sprintf(eventName,"NCBavails[%d]", idx);
9208 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9209 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9210 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9211 sprintf(eventName,"NCBevents[%d]", idx);
9212 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9213 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9214 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9215 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9216 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9217 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9218 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9219 for (i=0; i<smb_NumServerThreads; i++)
9220 NCBreturns[i][idx] = retHandle;
9221 bufp = smb_GetPacket();
9222 bufp->spacep = cm_GetSpace();
9226 /* listen for new connections */
9227 void smb_Listener(void *parmp)
9233 afs_uint32 session, thread;
9234 smb_vc_t *vcp = NULL;
9236 char rname[NCBNAMSZ+1];
9237 char cname[MAX_COMPUTERNAME_LENGTH+1];
9238 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9239 INT_PTR lana = (INT_PTR) parmp;
9240 char eventName[MAX_PATH];
9241 int bridgeCount = 0;
9242 int nowildCount = 0;
9244 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9245 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9246 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9247 thrd_ResetEvent(ListenerShutdown[lana]);
9249 ncbp = smb_GetNCB();
9251 /* retrieve computer name */
9252 GetComputerName(cname, &cnamelen);
9255 while (smb_ListenerState == SMB_LISTENER_STARTED) {
9256 memset(ncbp, 0, sizeof(NCB));
9259 ncbp->ncb_command = NCBLISTEN;
9260 ncbp->ncb_rto = 0; /* No receive timeout */
9261 ncbp->ncb_sto = 0; /* No send timeout */
9263 /* pad out with spaces instead of null termination */
9264 len = (long)strlen(smb_localNamep);
9265 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9266 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9268 strcpy(ncbp->ncb_callname, "*");
9269 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9271 ncbp->ncb_lana_num = (UCHAR)lana;
9273 code = Netbios(ncbp);
9275 if (code == NRC_NAMERR) {
9276 /* An smb shutdown or Vista resume must have taken place */
9278 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9279 ncbp->ncb_lana_num);
9280 afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9282 if (lock_TryMutex(&smb_StartedLock)) {
9283 lana_list.lana[i] = LANA_INVALID;
9284 lock_ReleaseMutex(&smb_StartedLock);
9287 } else if (code == NRC_BRIDGE || code != 0) {
9288 int lanaRemaining = 0;
9290 if (code == NRC_BRIDGE) {
9291 if (++bridgeCount <= 5) {
9292 afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9295 } else if (code == NRC_NOWILD) {
9296 if (++nowildCount <= 5) {
9297 afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9299 if (bridgeCount > 0) {
9300 memset(ncbp, 0, sizeof(*ncbp));
9301 ncbp->ncb_command = NCBADDNAME;
9302 ncbp->ncb_lana_num = (UCHAR)lana;
9303 /* pad out with spaces instead of null termination */
9304 len = (long)strlen(smb_localNamep);
9305 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9306 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9307 code = Netbios(ncbp);
9313 while (!lock_TryMutex(&smb_StartedLock)) {
9314 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9320 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9321 ncbp->ncb_lana_num, ncb_error_string(code));
9322 afsi_log("NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
9323 ncbp->ncb_lana_num, ncb_error_string(code));
9325 for (i = 0; i < lana_list.length; i++) {
9326 if (lana_list.lana[i] == lana) {
9327 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9328 lana_list.lana[i] = LANA_INVALID;
9330 if (lana_list.lana[i] != LANA_INVALID)
9334 if (lanaRemaining == 0) {
9335 cm_VolStatus_Network_Stopped(cm_NetbiosName
9340 smb_ListenerState = SMB_LISTENER_STOPPED;
9341 smb_LANadapter = LANA_INVALID;
9342 lana_list.length = 0;
9344 lock_ReleaseMutex(&smb_StartedLock);
9348 else if (code != 0) {
9349 char tbuffer[AFSPATHMAX];
9351 /* terminate silently if shutdown flag is set */
9352 while (!lock_TryMutex(&smb_StartedLock)) {
9353 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9359 "NCBLISTEN lana=%d failed with code %d [%s]",
9360 ncbp->ncb_lana_num, code, ncb_error_string(code));
9362 "Client exiting due to network failure. Please restart client.\n");
9365 "Client exiting due to network failure. Please restart client.\n"
9366 "NCBLISTEN lana=%d failed with code %d [%s]",
9367 ncbp->ncb_lana_num, code, ncb_error_string(code));
9369 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9370 MB_OK|MB_SERVICE_NOTIFICATION);
9371 osi_panic(tbuffer, __FILE__, __LINE__);
9373 lock_ReleaseMutex(&smb_StartedLock);
9378 /* a successful packet received. clear bridge error count */
9382 /* check for remote conns */
9383 /* first get remote name and insert null terminator */
9384 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9385 for (i=NCBNAMSZ; i>0; i--) {
9386 if (rname[i-1] != ' ' && rname[i-1] != 0) {
9392 /* compare with local name */
9394 if (strncmp(rname, cname, NCBNAMSZ) != 0)
9395 flags |= SMB_VCFLAG_REMOTECONN;
9398 lock_ObtainMutex(&smb_ListenerLock);
9400 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9401 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9403 /* now ncbp->ncb_lsn is the connection ID */
9404 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9405 if (vcp->session == 0) {
9406 /* New generation */
9407 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9410 /* Log session startup */
9412 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9413 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9414 #endif /* NOTSERVICE */
9415 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9416 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9418 if (reportSessionStartups) {
9419 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9422 lock_ObtainMutex(&vcp->mx);
9423 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9424 vcp->flags |= flags;
9425 lock_ReleaseMutex(&vcp->mx);
9427 /* Allocate slot in session arrays */
9428 /* Re-use dead session if possible, otherwise add one more */
9429 /* But don't look at session[0], it is reserved */
9430 lock_ObtainWrite(&smb_globalLock);
9431 for (session = 1; session < numSessions; session++) {
9432 if (dead_sessions[session]) {
9433 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9434 dead_sessions[session] = FALSE;
9438 lock_ReleaseWrite(&smb_globalLock);
9440 /* We are re-using an existing VC because the lsn and lana
9442 session = vcp->session;
9444 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9446 /* Log session startup */
9448 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9449 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9450 #endif /* NOTSERVICE */
9451 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9452 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9454 if (reportSessionStartups) {
9455 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9459 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
9460 unsigned long code = CM_ERROR_ALLBUSY;
9461 smb_packet_t * outp = smb_GetPacket();
9462 unsigned char *outWctp;
9465 smb_FormatResponsePacket(vcp, NULL, outp);
9468 if (vcp->flags & SMB_VCFLAG_STATUS32) {
9469 unsigned long NTStatus;
9470 smb_MapNTError(code, &NTStatus);
9471 outWctp = outp->wctp;
9472 smbp = (smb_t *) &outp->data;
9476 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9477 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9478 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9479 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9480 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9482 unsigned short errCode;
9483 unsigned char errClass;
9484 smb_MapCoreError(code, vcp, &errCode, &errClass);
9485 outWctp = outp->wctp;
9486 smbp = (smb_t *) &outp->data;
9490 smbp->errLow = (unsigned char) (errCode & 0xff);
9491 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9492 smbp->rcls = errClass;
9495 smb_SendPacket(vcp, outp);
9496 smb_FreePacket(outp);
9498 lock_ObtainMutex(&vcp->mx);
9499 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9500 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9502 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9503 lock_ReleaseMutex(&vcp->mx);
9504 lock_ObtainWrite(&smb_globalLock);
9505 dead_sessions[vcp->session] = TRUE;
9506 lock_ReleaseWrite(&smb_globalLock);
9507 smb_CleanupDeadVC(vcp);
9509 lock_ReleaseMutex(&vcp->mx);
9512 /* assert that we do not exceed the maximum number of sessions or NCBs.
9513 * we should probably want to wait for a session to be freed in case
9516 osi_assertx(session < SESSION_MAX - 1, "invalid session");
9517 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
9519 lock_ObtainMutex(&vcp->mx);
9520 vcp->session = session;
9521 lock_ReleaseMutex(&vcp->mx);
9522 lock_ObtainWrite(&smb_globalLock);
9523 LSNs[session] = ncbp->ncb_lsn;
9524 lanas[session] = ncbp->ncb_lana_num;
9525 lock_ReleaseWrite(&smb_globalLock);
9527 if (session == numSessions) {
9528 /* Add new NCB for new session */
9529 char eventName[MAX_PATH];
9531 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9533 InitNCBslot(numNCBs);
9534 lock_ObtainWrite(&smb_globalLock);
9536 lock_ReleaseWrite(&smb_globalLock);
9537 thrd_SetEvent(NCBavails[0]);
9538 thrd_SetEvent(NCBevents[0]);
9539 for (thread = 0; thread < smb_NumServerThreads; thread++)
9540 thrd_SetEvent(NCBreturns[thread][0]);
9541 /* Also add new session event */
9542 sprintf(eventName, "SessionEvents[%d]", session);
9543 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9544 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9545 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9546 lock_ObtainWrite(&smb_globalLock);
9548 lock_ReleaseWrite(&smb_globalLock);
9549 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9550 thrd_SetEvent(SessionEvents[0]);
9552 thrd_SetEvent(SessionEvents[session]);
9558 lock_ReleaseMutex(&smb_ListenerLock);
9559 } /* dispatch while loop */
9563 thrd_SetEvent(ListenerShutdown[lana]);
9568 configureBackConnectionHostNames(void)
9570 /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9571 * there is a restriction on the use of SMB authentication on loopback connections.
9572 * There are two work arounds available:
9574 * (1) We can disable the check for matching host names. This does not
9576 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
9577 * "DisableLoopbackCheck"=dword:00000001
9579 * (2) We can add the AFS SMB/CIFS service name to an approved list. This
9580 * does require a reboot:
9581 * [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
9582 * "BackConnectionHostNames"=multi-sz
9584 * The algorithm will be:
9585 * (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
9586 * (2a) If not, add it to the list. (This will not take effect until the next reboot.)
9587 * (2b1) and check to see if DisableLoopbackCheck is set.
9588 * (2b2) If not set, set the DisableLoopbackCheck value to 0x1
9589 * (2b3) and create HKLM\SOFTWARE\OpenAFS\Client UnsetDisableLoopbackCheck
9590 * (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
9591 * check for the UnsetDisableLoopbackCheck value.
9592 * If set, set the DisableLoopbackCheck flag to 0x0
9593 * and delete the UnsetDisableLoopbackCheck value
9595 * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
9596 * force Windows to use the loopback authentication mechanism for the specified
9599 * Do not permit the "DisableLoopbackCheck" value to be removed within the same
9600 * service session that set it.
9606 DWORD dwSize, dwAllocSize;
9608 PBYTE pHostNames = NULL, pName = NULL;
9609 BOOL bNameFound = FALSE;
9610 static BOOL bLoopbackCheckDisabled = FALSE;
9612 /* BackConnectionHostNames and DisableLoopbackCheck */
9613 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9614 "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
9617 &hkMSV10) == ERROR_SUCCESS )
9619 if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
9620 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9621 (dwType == REG_MULTI_SZ))
9623 dwAllocSize += 1 /* in case the source string is not nul terminated */
9624 + (DWORD)strlen(cm_NetbiosName) + 2;
9625 pHostNames = malloc(dwAllocSize);
9626 dwSize = dwAllocSize;
9627 if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
9628 pHostNames, &dwSize) == ERROR_SUCCESS)
9630 for (pName = pHostNames;
9631 (pName - pHostNames < (int) dwSize) && *pName ;
9632 pName += strlen(pName) + 1)
9634 if ( !stricmp(pName, cm_NetbiosName) ) {
9642 if ( !bNameFound ) {
9643 size_t size = strlen(cm_NetbiosName) + 2;
9644 if ( !pHostNames ) {
9645 pHostNames = malloc(size);
9648 StringCbCopyA(pName, size, cm_NetbiosName);
9650 *pName = '\0'; /* add a second nul terminator */
9652 dwType = REG_MULTI_SZ;
9653 dwSize = (DWORD)(pName - pHostNames + 1);
9654 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
9656 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9657 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9660 &hkLsa) == ERROR_SUCCESS )
9662 dwSize = sizeof(DWORD);
9663 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
9666 dwSize = sizeof(DWORD);
9668 RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9670 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9671 AFSREG_CLT_OPENAFS_SUBKEY,
9674 REG_OPTION_NON_VOLATILE,
9678 NULL) == ERROR_SUCCESS) {
9681 dwSize = sizeof(DWORD);
9683 RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
9684 bLoopbackCheckDisabled = TRUE;
9685 RegCloseKey(hkClient);
9690 } else if (!bLoopbackCheckDisabled) {
9691 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
9692 AFSREG_CLT_OPENAFS_SUBKEY,
9695 REG_OPTION_NON_VOLATILE,
9699 NULL) == ERROR_SUCCESS) {
9701 dwSize = sizeof(DWORD);
9702 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
9704 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9705 "SYSTEM\\CurrentControlSet\\Control\\Lsa",
9708 &hkLsa) == ERROR_SUCCESS )
9710 RegDeleteValue(hkLsa, "DisableLoopbackCheck");
9714 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
9715 RegCloseKey(hkClient);
9724 RegCloseKey(hkMSV10);
9730 configureExtendedSMBSessionTimeouts(void)
9733 * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
9734 * new functionality:
9736 * [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
9737 * "ReconnectableServers" REG_MULTI_SZ
9738 * "ExtendedSessTimeout" REG_DWORD (seconds)
9739 * "ServersWithExtendedSessTimeout" REG_MULTI_SZ
9741 * These values can be used to prevent the smb redirector from timing out
9742 * smb connection to the afs smb server prematurely.
9746 DWORD dwSize, dwAllocSize;
9748 PBYTE pHostNames = NULL, pName = NULL;
9749 BOOL bNameFound = FALSE;
9751 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
9752 "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
9755 &hkLanMan) == ERROR_SUCCESS )
9757 if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
9758 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9759 (dwType == REG_MULTI_SZ))
9761 dwAllocSize += 1 /* in case the source string is not nul terminated */
9762 + (DWORD)strlen(cm_NetbiosName) + 2;
9763 pHostNames = malloc(dwAllocSize);
9764 dwSize = dwAllocSize;
9765 if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
9766 pHostNames, &dwSize) == ERROR_SUCCESS)
9768 for (pName = pHostNames;
9769 (pName - pHostNames < (int) dwSize) && *pName ;
9770 pName += strlen(pName) + 1)
9772 if ( !stricmp(pName, cm_NetbiosName) ) {
9780 if ( !bNameFound ) {
9781 size_t size = strlen(cm_NetbiosName) + 2;
9782 if ( !pHostNames ) {
9783 pHostNames = malloc(size);
9786 StringCbCopyA(pName, size, cm_NetbiosName);
9788 *pName = '\0'; /* add a second nul terminator */
9790 dwType = REG_MULTI_SZ;
9791 dwSize = (DWORD)(pName - pHostNames + 1);
9792 RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
9800 if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
9801 &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
9802 (dwType == REG_MULTI_SZ))
9804 dwAllocSize += 1 /* in case the source string is not nul terminated */
9805 + (DWORD)strlen(cm_NetbiosName) + 2;
9806 pHostNames = malloc(dwAllocSize);
9807 dwSize = dwAllocSize;
9808 if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
9809 pHostNames, &dwSize) == ERROR_SUCCESS)
9811 for (pName = pHostNames;
9812 (pName - pHostNames < (int) dwSize) && *pName ;
9813 pName += strlen(pName) + 1)
9815 if ( !stricmp(pName, cm_NetbiosName) ) {
9823 if ( !bNameFound ) {
9824 size_t size = strlen(cm_NetbiosName) + 2;
9825 if ( !pHostNames ) {
9826 pHostNames = malloc(size);
9829 StringCbCopyA(pName, size, cm_NetbiosName);
9831 *pName = '\0'; /* add a second nul terminator */
9833 dwType = REG_MULTI_SZ;
9834 dwSize = (DWORD)(pName - pHostNames + 1);
9835 RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
9843 if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
9844 &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
9845 (dwType != REG_DWORD))
9848 dwSize = sizeof(dwValue);
9849 dwValue = 300; /* 5 minutes */
9850 RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
9852 RegCloseKey(hkLanMan);
9857 smb_LanAdapterChangeThread(void *param)
9860 * Give the IPAddrDaemon thread a chance
9861 * to block before we trigger.
9864 smb_LanAdapterChange(0);
9867 void smb_SetLanAdapterChangeDetected(void)
9872 lock_ObtainMutex(&smb_StartedLock);
9874 if (!powerStateSuspended) {
9875 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
9876 NULL, 0, &lpid, "smb_LanAdapterChange");
9877 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
9878 thrd_CloseHandle(phandle);
9881 smb_LanAdapterChangeDetected = 1;
9882 lock_ReleaseMutex(&smb_StartedLock);
9885 void smb_LanAdapterChange(int locked) {
9886 lana_number_t lanaNum;
9888 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
9890 LANA_ENUM temp_list;
9895 afsi_log("smb_LanAdapterChange");
9898 lock_ObtainMutex(&smb_StartedLock);
9900 smb_LanAdapterChangeDetected = 0;
9902 if (!powerStateSuspended &&
9903 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
9904 LANA_NETBIOS_NAME_FULL)) &&
9905 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
9906 if ( isGateway != bGateway ) {
9907 afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
9908 smb_LANadapter, lanaNum, isGateway, bGateway);
9910 } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
9911 afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
9912 smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
9915 NCB *ncbp = smb_GetNCB();
9916 ncbp->ncb_command = NCBENUM;
9917 ncbp->ncb_buffer = (PUCHAR)&temp_list;
9918 ncbp->ncb_length = sizeof(temp_list);
9919 code = Netbios(ncbp);
9921 if (temp_list.length != lana_list.length) {
9922 afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
9923 smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
9926 for (i=0; i<lana_list.length; i++) {
9927 if ( temp_list.lana[i] != lana_list.lana[i] ) {
9928 afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
9929 smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
9941 smb_StopListeners(1);
9942 smb_RestartListeners(1);
9945 lock_ReleaseMutex(&smb_StartedLock);
9948 /* initialize Netbios */
9949 int smb_NetbiosInit(int locked)
9952 int i, lana, code, l;
9954 int delname_tried=0;
9957 lana_number_t lanaNum;
9960 lock_ObtainMutex(&smb_StartedLock);
9962 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
9963 smb_ListenerState != SMB_LISTENER_STOPPED) {
9966 lock_ReleaseMutex(&smb_StartedLock);
9969 /* setup the NCB system */
9970 ncbp = smb_GetNCB();
9972 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
9973 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
9974 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
9976 if (smb_LANadapter != LANA_INVALID)
9977 afsi_log("LAN adapter number %d", smb_LANadapter);
9979 afsi_log("LAN adapter number not determined");
9982 afsi_log("Set for gateway service");
9984 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
9986 /* something went horribly wrong. We can't proceed without a netbios name */
9988 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
9989 osi_panic(buf, __FILE__, __LINE__);
9992 /* remember the name */
9993 len = (int)strlen(cm_NetbiosName);
9995 free(smb_localNamep);
9996 smb_localNamep = malloc(len+1);
9997 strcpy(smb_localNamep, cm_NetbiosName);
9998 afsi_log("smb_localNamep is >%s<", smb_localNamep);
10000 /* Also copy the value to the client character encoded string */
10001 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10003 if (smb_LANadapter == LANA_INVALID) {
10004 ncbp->ncb_command = NCBENUM;
10005 ncbp->ncb_buffer = (PUCHAR)&lana_list;
10006 ncbp->ncb_length = sizeof(lana_list);
10007 code = Netbios(ncbp);
10009 afsi_log("Netbios NCBENUM error code %d", code);
10010 osi_panic(s, __FILE__, __LINE__);
10014 lana_list.length = 1;
10015 lana_list.lana[0] = smb_LANadapter;
10018 for (i = 0; i < lana_list.length; i++) {
10019 /* reset the adaptor: in Win32, this is required for every process, and
10020 * acts as an init call, not as a real hardware reset.
10022 ncbp->ncb_command = NCBRESET;
10023 ncbp->ncb_callname[0] = 100;
10024 ncbp->ncb_callname[2] = 100;
10025 ncbp->ncb_lana_num = lana_list.lana[i];
10026 code = Netbios(ncbp);
10028 code = ncbp->ncb_retcode;
10030 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10031 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
10033 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10037 /* and declare our name so we can receive connections */
10038 memset(ncbp, 0, sizeof(*ncbp));
10039 len=lstrlen(smb_localNamep);
10040 memset(smb_sharename,' ',NCBNAMSZ);
10041 memcpy(smb_sharename,smb_localNamep,len);
10042 afsi_log("lana_list.length %d", lana_list.length);
10044 /* Keep the name so we can unregister it later */
10045 for (l = 0; l < lana_list.length; l++) {
10046 lana = lana_list.lana[l];
10048 ncbp->ncb_command = NCBADDNAME;
10049 ncbp->ncb_lana_num = lana;
10050 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10051 code = Netbios(ncbp);
10053 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10054 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10056 char name[NCBNAMSZ+1];
10058 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10059 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10063 code = ncbp->ncb_retcode;
10066 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10069 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10070 if (code == NRC_BRIDGE) { /* invalid LANA num */
10071 lana_list.lana[l] = LANA_INVALID;
10074 else if (code == NRC_DUPNAME) {
10075 afsi_log("Name already exists; try to delete it");
10076 memset(ncbp, 0, sizeof(*ncbp));
10077 ncbp->ncb_command = NCBDELNAME;
10078 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10079 ncbp->ncb_lana_num = lana;
10080 code = Netbios(ncbp);
10082 code = ncbp->ncb_retcode;
10084 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10086 if (code != 0 || delname_tried) {
10087 lana_list.lana[l] = LANA_INVALID;
10089 else if (code == 0) {
10090 if (!delname_tried) {
10098 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10099 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10103 smb_LANadapter = lana;
10104 lana_found = 1; /* at least one worked */
10108 osi_assertx(lana_list.length >= 0, "empty lana list");
10110 afsi_log("No valid LANA numbers found!");
10111 lana_list.length = 0;
10112 smb_LANadapter = LANA_INVALID;
10113 smb_ListenerState = SMB_LISTENER_STOPPED;
10114 cm_VolStatus_Network_Stopped(cm_NetbiosName
10121 /* we're done with the NCB now */
10124 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10125 if (lana_list.length > 0)
10126 osi_assert(smb_LANadapter != LANA_INVALID);
10129 lock_ReleaseMutex(&smb_StartedLock);
10131 return (lana_list.length > 0 ? 1 : 0);
10134 void smb_StartListeners(int locked)
10141 lock_ObtainMutex(&smb_StartedLock);
10143 if (smb_ListenerState == SMB_LISTENER_STARTED) {
10145 lock_ReleaseMutex(&smb_StartedLock);
10149 afsi_log("smb_StartListeners");
10150 /* Ensure the AFS Netbios Name is registered to allow loopback access */
10151 configureBackConnectionHostNames();
10153 /* Configure Extended SMB Session Timeouts */
10154 if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10155 afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10156 configureExtendedSMBSessionTimeouts();
10159 smb_ListenerState = SMB_LISTENER_STARTED;
10160 cm_VolStatus_Network_Started(cm_NetbiosName
10166 for (i = 0; i < lana_list.length; i++) {
10167 if (lana_list.lana[i] == LANA_INVALID)
10169 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10170 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10171 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10172 thrd_CloseHandle(phandle);
10175 lock_ReleaseMutex(&smb_StartedLock);
10178 void smb_RestartListeners(int locked)
10181 lock_ObtainMutex(&smb_StartedLock);
10183 if (powerStateSuspended)
10184 afsi_log("smb_RestartListeners called while suspended");
10186 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10187 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10188 if (smb_NetbiosInit(1))
10189 smb_StartListeners(1);
10190 } else if (smb_LanAdapterChangeDetected) {
10191 smb_LanAdapterChange(1);
10195 lock_ReleaseMutex(&smb_StartedLock);
10198 void smb_StopListener(NCB *ncbp, int lana, int wait)
10202 memset(ncbp, 0, sizeof(*ncbp));
10203 ncbp->ncb_command = NCBDELNAME;
10204 ncbp->ncb_lana_num = lana;
10205 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10206 code = Netbios(ncbp);
10208 afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10209 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10211 /* and then reset the LANA; this will cause the listener threads to exit */
10212 ncbp->ncb_command = NCBRESET;
10213 ncbp->ncb_callname[0] = 100;
10214 ncbp->ncb_callname[2] = 100;
10215 ncbp->ncb_lana_num = lana;
10216 code = Netbios(ncbp);
10218 code = ncbp->ncb_retcode;
10220 afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10222 afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10226 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10229 void smb_StopListeners(int locked)
10235 lock_ObtainMutex(&smb_StartedLock);
10237 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10239 lock_ReleaseMutex(&smb_StartedLock);
10243 afsi_log("smb_StopListeners");
10244 smb_ListenerState = SMB_LISTENER_STOPPED;
10245 cm_VolStatus_Network_Stopped(cm_NetbiosName
10251 ncbp = smb_GetNCB();
10253 /* Unregister the SMB name */
10254 for (l = 0; l < lana_list.length; l++) {
10255 lana = lana_list.lana[l];
10257 if (lana != LANA_INVALID) {
10258 smb_StopListener(ncbp, lana, TRUE);
10260 /* mark the adapter invalid */
10261 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
10265 /* force a re-evaluation of the network adapters */
10266 lana_list.length = 0;
10267 smb_LANadapter = LANA_INVALID;
10270 lock_ReleaseMutex(&smb_StartedLock);
10273 void smb_Init(osi_log_t *logp, int useV3,
10283 EVENT_HANDLE retHandle;
10284 char eventName[MAX_PATH];
10285 int startListeners = 0;
10287 smb_MBfunc = aMBfunc;
10291 /* Initialize smb_localZero */
10292 myTime.tm_isdst = -1; /* compute whether on DST or not */
10293 myTime.tm_year = 70;
10295 myTime.tm_mday = 1;
10296 myTime.tm_hour = 0;
10299 smb_localZero = mktime(&myTime);
10301 #ifdef AFS_FREELANCE_CLIENT
10302 /* Make sure the root.afs volume has the correct time */
10303 cm_noteLocalMountPointChange();
10306 /* initialize the remote debugging log */
10309 /* and the global lock */
10310 lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10311 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10313 /* Raw I/O data structures */
10314 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10316 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10317 lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10319 /* 4 Raw I/O buffers */
10320 smb_RawBufs = calloc(65536,1);
10321 *((char **)smb_RawBufs) = NULL;
10322 for (i=0; i<3; i++) {
10323 char *rawBuf = calloc(65536,1);
10324 *((char **)rawBuf) = smb_RawBufs;
10325 smb_RawBufs = rawBuf;
10328 /* global free lists */
10329 smb_ncbFreeListp = NULL;
10330 smb_packetFreeListp = NULL;
10332 lock_ObtainMutex(&smb_StartedLock);
10333 startListeners = smb_NetbiosInit(1);
10335 /* Initialize listener and server structures */
10337 memset(dead_sessions, 0, sizeof(dead_sessions));
10338 sprintf(eventName, "SessionEvents[0]");
10339 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10340 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10341 afsi_log("Event Object Already Exists: %s", eventName);
10343 smb_NumServerThreads = nThreads;
10344 sprintf(eventName, "NCBavails[0]");
10345 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10346 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10347 afsi_log("Event Object Already Exists: %s", eventName);
10348 sprintf(eventName, "NCBevents[0]");
10349 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10350 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10351 afsi_log("Event Object Already Exists: %s", eventName);
10352 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10353 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10354 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10355 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10356 afsi_log("Event Object Already Exists: %s", eventName);
10357 for (i = 0; i < smb_NumServerThreads; i++) {
10358 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10359 NCBreturns[i][0] = retHandle;
10362 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10363 for (i = 0; i < smb_NumServerThreads; i++) {
10364 sprintf(eventName, "smb_ServerShutdown[%d]", i);
10365 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10366 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10367 afsi_log("Event Object Already Exists: %s", eventName);
10368 InitNCBslot((int)(i+1));
10370 numNCBs = smb_NumServerThreads + 1;
10372 /* Initialize dispatch table */
10373 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10374 /* Prepare the table for unknown operations */
10375 for(i=0; i<= SMB_NOPCODES; i++) {
10376 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10378 /* Fill in the ones we do know */
10379 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10380 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10381 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10382 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10383 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10384 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10385 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10386 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10387 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10388 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10389 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10390 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10391 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10392 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10393 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10394 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10395 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10396 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
10397 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10398 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10399 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10400 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10401 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10402 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10403 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10404 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10405 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10406 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10407 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10408 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10409 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10410 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
10411 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10412 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10413 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10414 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10415 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10416 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10417 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10418 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10419 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10420 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
10421 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10422 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10423 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10424 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10425 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10426 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10427 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10428 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10429 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10430 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10431 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10432 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10433 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10434 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10435 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10436 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10437 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10438 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10439 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10440 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10441 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10442 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10443 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10444 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10445 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10446 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
10447 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
10448 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
10449 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
10450 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
10451 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
10452 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
10454 /* setup tran 2 dispatch table */
10455 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10456 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
10457 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
10458 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10459 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10460 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10461 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10462 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10463 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10464 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10465 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10466 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10467 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10468 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10469 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10470 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10471 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10472 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10474 /* setup the rap dispatch table */
10475 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10476 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10477 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10478 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10479 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10483 /* if we are doing SMB authentication we have register outselves as a logon process */
10484 if (smb_authType != SMB_AUTH_NONE) {
10485 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10486 LSA_STRING afsProcessName;
10487 LSA_OPERATIONAL_MODE dummy; /*junk*/
10489 afsProcessName.Buffer = "OpenAFSClientDaemon";
10490 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10491 afsProcessName.MaximumLength = afsProcessName.Length + 1;
10493 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10495 if (nts == STATUS_SUCCESS) {
10496 LSA_STRING packageName;
10497 /* we are registered. Find out the security package id */
10498 packageName.Buffer = MSV1_0_PACKAGE_NAME;
10499 packageName.Length = (USHORT)strlen(packageName.Buffer);
10500 packageName.MaximumLength = packageName.Length + 1;
10501 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10502 if (nts == STATUS_SUCCESS) {
10504 * This code forces Windows to authenticate against the Logon Cache
10505 * first instead of attempting to authenticate against the Domain
10506 * Controller. When the Windows logon cache is enabled this improves
10507 * performance by removing the network access and works around a bug
10508 * seen at sites which are using a MIT Kerberos principal to login
10509 * to machines joined to a non-root domain in a multi-domain forest.
10510 * MsV1_0SetProcessOption was added in Windows XP.
10512 PVOID pResponse = NULL;
10513 ULONG cbResponse = 0;
10514 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10516 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10517 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10518 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10519 OptionsRequest.DisableOptions = FALSE;
10521 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10524 sizeof(OptionsRequest),
10530 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10531 osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10534 afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10536 osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10537 afsi_log("MsV1_0SetProcessOption success");
10539 /* END - code from Larry */
10541 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10542 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10543 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10545 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10547 /* something went wrong. We report the error and revert back to no authentication
10548 because we can't perform any auth requests without a successful lsa handle
10549 or sec package id. */
10550 afsi_log("Reverting to NO SMB AUTH");
10551 smb_authType = SMB_AUTH_NONE;
10554 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
10556 /* something went wrong. We report the error and revert back to no authentication
10557 because we can't perform any auth requests without a successful lsa handle
10558 or sec package id. */
10559 afsi_log("Reverting to NO SMB AUTH");
10560 smb_authType = SMB_AUTH_NONE;
10564 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
10565 * time prevents the failure of authentication when logged into Windows with an
10566 * external Kerberos principal mapped to a local account.
10568 else if ( smb_authType == SMB_AUTH_EXTENDED) {
10569 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
10570 * then the only option is NTLMSSP anyway; so just fallback.
10575 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
10576 if (secBlobLength == 0) {
10577 smb_authType = SMB_AUTH_NTLM;
10578 afsi_log("Reverting to SMB AUTH NTLM");
10587 /* Now get ourselves a domain name. */
10588 /* For now we are using the local computer name as the domain name.
10589 * It is actually the domain for local logins, and we are acting as
10590 * a local SMB server.
10592 bufsize = lengthof(smb_ServerDomainName) - 1;
10593 GetComputerNameW(smb_ServerDomainName, &bufsize);
10594 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
10595 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
10598 /* Start listeners, waiters, servers, and daemons */
10599 if (startListeners)
10600 smb_StartListeners(1);
10602 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
10603 NULL, 0, &lpid, "smb_ClientWaiter");
10604 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
10605 thrd_CloseHandle(phandle);
10607 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
10608 NULL, 0, &lpid, "smb_ServerWaiter");
10609 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
10610 thrd_CloseHandle(phandle);
10612 for (i=0; i<smb_NumServerThreads; i++) {
10613 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
10614 (void *) i, 0, &lpid, "smb_Server");
10615 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
10616 thrd_CloseHandle(phandle);
10619 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
10620 NULL, 0, &lpid, "smb_Daemon");
10621 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
10622 thrd_CloseHandle(phandle);
10624 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
10625 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
10626 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
10627 thrd_CloseHandle(phandle);
10629 lock_ReleaseMutex(&smb_StartedLock);
10633 void smb_Shutdown(void)
10640 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
10642 /* setup the NCB system */
10643 ncbp = smb_GetNCB();
10645 /* Block new sessions by setting shutdown flag */
10646 smbShutdownFlag = 1;
10648 /* Hang up all sessions */
10649 memset(ncbp, 0, sizeof(NCB));
10650 for (i = 1; i < numSessions; i++)
10652 if (dead_sessions[i])
10655 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10656 ncbp->ncb_command = NCBHANGUP;
10657 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
10658 ncbp->ncb_lsn = (UCHAR)LSNs[i];
10659 code = Netbios(ncbp);
10660 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
10661 if (code == 0) code = ncbp->ncb_retcode;
10663 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
10664 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
10668 /* Trigger the shutdown of all SMB threads */
10669 for (i = 0; i < smb_NumServerThreads; i++)
10670 thrd_SetEvent(NCBreturns[i][0]);
10672 thrd_SetEvent(NCBevents[0]);
10673 thrd_SetEvent(SessionEvents[0]);
10674 thrd_SetEvent(NCBavails[0]);
10676 for (i = 0;i < smb_NumServerThreads; i++) {
10677 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
10678 if (code == WAIT_OBJECT_0) {
10681 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
10682 thrd_SetEvent(NCBreturns[i--][0]);
10686 /* Delete Netbios name */
10687 memset(ncbp, 0, sizeof(NCB));
10688 for (i = 0; i < lana_list.length; i++) {
10689 if (lana_list.lana[i] == LANA_INVALID) continue;
10690 ncbp->ncb_command = NCBDELNAME;
10691 ncbp->ncb_lana_num = lana_list.lana[i];
10692 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10693 code = Netbios(ncbp);
10695 code = ncbp->ncb_retcode;
10697 fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
10698 ncbp->ncb_lana_num, code);
10703 /* Release the reference counts held by the VCs */
10704 lock_ObtainWrite(&smb_rctLock);
10705 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10710 if (vcp->magic != SMB_VC_MAGIC)
10711 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
10712 __FILE__, __LINE__);
10714 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10716 if (fidp->scp != NULL) {
10719 lock_ReleaseWrite(&smb_rctLock);
10720 lock_ObtainMutex(&fidp->mx);
10721 if (fidp->scp != NULL) {
10724 lock_ObtainWrite(&scp->rw);
10725 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
10726 lock_ReleaseWrite(&scp->rw);
10727 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
10728 cm_ReleaseSCache(scp);
10730 lock_ReleaseMutex(&fidp->mx);
10731 lock_ObtainWrite(&smb_rctLock);
10735 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10737 smb_ReleaseVCNoLock(tidp->vcp);
10739 cm_user_t *userp = tidp->userp;
10740 tidp->userp = NULL;
10741 cm_ReleaseUser(userp);
10745 lock_ReleaseWrite(&smb_rctLock);
10749 /* Get the UNC \\<servername>\<sharename> prefix. */
10750 char *smb_GetSharename()
10755 /* Make sure we have been properly initialized. */
10756 if (smb_localNamep == NULL)
10759 /* Allocate space for \\<servername>\<sharename>, plus the
10762 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
10763 name = malloc(len);
10764 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
10770 void smb_LogPacket(smb_packet_t *packet)
10774 unsigned length, paramlen, datalen, i, j;
10776 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
10778 if (!packet) return;
10780 osi_Log0(smb_logp, "*** SMB packet dump ***");
10782 smbp = (smb_t *) packet->data;
10783 vp = (BYTE *) packet->data;
10785 paramlen = smbp->wct * 2;
10786 datalen = *((WORD *) (smbp->vdata + paramlen));
10787 length = sizeof(*smbp) + paramlen + 1 + datalen;
10789 for (i=0;i < length; i+=16)
10791 memset( buf, ' ', 80 );
10794 itoa( i, buf, 16 );
10796 buf[strlen(buf)] = ' ';
10798 cp = (BYTE*) buf + 7;
10800 for (j=0;j < 16 && (i+j)<length; j++)
10802 *(cp++) = hex[vp[i+j] >> 4];
10803 *(cp++) = hex[vp[i+j] & 0xf];
10813 for (j=0;j < 16 && (i+j)<length;j++)
10815 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
10826 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
10829 osi_Log0(smb_logp, "*** End SMB packet dump ***");
10831 #endif /* LOG_PACKET */
10834 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
10840 smb_username_t *unp;
10841 smb_waitingLockRequest_t *wlrp;
10844 lock_ObtainRead(&smb_rctLock);
10846 sprintf(output, "begin dumping smb_username_t\r\n");
10847 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10848 for (unp = usernamesp; unp; unp=unp->nextp)
10850 cm_ucell_t *ucellp;
10852 sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
10853 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
10854 unp->name ? unp->name : _C("NULL"),
10855 unp->machine ? unp->machine : _C("NULL"));
10856 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10858 sprintf(output, " begin dumping cm_ucell_t\r\n");
10859 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10861 for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
10862 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",
10863 cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
10864 ucellp->expirationTime, ucellp->gen,
10866 ucellp->cellp->name);
10867 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10870 sprintf(output, " done dumping cm_ucell_t\r\n");
10871 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10874 sprintf(output, "done dumping smb_username_t\r\n");
10875 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10878 sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
10879 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10882 for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
10883 smb_waitingLock_t *lockp;
10885 sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
10886 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
10887 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10889 sprintf(output, " begin dumping smb_waitingLock_t\r\n");
10890 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10891 for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
10892 sprintf(output, " %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
10893 cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
10894 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10896 sprintf(output, " done dumping smb_waitingLock_t\r\n");
10897 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10900 sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
10901 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10903 sprintf(output, "begin dumping smb_vc_t\r\n");
10904 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10906 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
10912 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10913 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10914 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10916 sprintf(output, " begin dumping smb_user_t\r\n");
10917 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10918 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10919 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10920 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10921 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10923 sprintf(output, " done dumping smb_user_t\r\n");
10924 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10926 sprintf(output, " begin dumping smb_tid_t\r\n");
10927 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10928 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10929 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",
10930 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10931 tidp->pathname ? tidp->pathname : _C("NULL"));
10932 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10934 sprintf(output, " done dumping smb_tid_t\r\n");
10935 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10937 sprintf(output, " begin dumping smb_fid_t\r\n");
10938 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10940 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10942 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",
10943 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10944 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10945 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10946 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10949 sprintf(output, " done dumping smb_fid_t\r\n");
10950 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10953 sprintf(output, "done dumping smb_vc_t\r\n");
10954 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10956 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
10957 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10959 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
10965 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
10966 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
10967 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10969 sprintf(output, " begin dumping smb_user_t\r\n");
10970 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10971 for (userp = vcp->usersp; userp; userp = userp->nextp) {
10972 sprintf(output, " %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
10973 cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
10974 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10976 sprintf(output, " done dumping smb_user_t\r\n");
10977 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10979 sprintf(output, " begin dumping smb_tid_t\r\n");
10980 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10981 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
10982 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",
10983 cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
10984 tidp->pathname ? tidp->pathname : _C("NULL"));
10985 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10987 sprintf(output, " done dumping smb_tid_t\r\n");
10988 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10990 sprintf(output, " begin dumping smb_fid_t\r\n");
10991 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
10993 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
10995 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",
10996 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
10997 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
10998 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
10999 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11002 sprintf(output, " done dumping smb_fid_t\r\n");
11003 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11006 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11007 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11010 lock_ReleaseRead(&smb_rctLock);
11014 long smb_IsNetworkStarted(void)
11017 lock_ObtainWrite(&smb_globalLock);
11018 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11019 lock_ReleaseWrite(&smb_globalLock);