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>
32 #include "lanahelper.h"
34 /* These characters are illegal in Windows filenames */
35 static char *illegalChars = "\\/:*?\"<>|";
37 static int smbShutdownFlag = 0;
38 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
40 int smb_LogoffTokenTransfer;
41 time_t smb_LogoffTransferTimeout;
43 int smb_StoreAnsiFilenames = 0;
45 DWORD last_msg_time = 0;
49 unsigned int sessionGen = 0;
51 extern void afsi_log(char *pattern, ...);
52 extern HANDLE afsi_file;
53 extern int powerStateSuspended;
55 osi_hyper_t hzero = {0, 0};
56 osi_hyper_t hones = {0xFFFFFFFF, -1};
59 osi_rwlock_t smb_globalLock;
60 osi_rwlock_t smb_rctLock;
61 osi_mutex_t smb_ListenerLock;
62 osi_mutex_t smb_StartedLock;
64 unsigned char smb_LANadapter = LANA_INVALID;
65 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
66 int smb_LanAdapterChangeDetected = 0;
67 afs_uint32 smb_AsyncStore = 1;
68 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
70 BOOL isGateway = FALSE;
73 long smb_maxObsConcurrentCalls=0;
74 long smb_concurrentCalls=0;
76 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
78 smb_packet_t *smb_packetFreeListp;
79 smb_ncb_t *smb_ncbFreeListp;
81 afs_uint32 smb_NumServerThreads;
83 afs_uint32 numNCBs, numSessions, numVCs;
85 int smb_maxVCPerServer;
86 int smb_maxMpxRequests;
88 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
90 ULONG smb_lsaSecPackage;
91 LSA_STRING smb_lsaLogonOrigin;
93 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
94 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
95 EVENT_HANDLE **NCBreturns;
96 EVENT_HANDLE **NCBShutdown;
97 EVENT_HANDLE *smb_ServerShutdown;
98 EVENT_HANDLE ListenerShutdown[256];
99 DWORD NCBsessions[NCB_MAX];
101 struct smb_packet *bufs[NCB_MAX];
103 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
104 EVENT_HANDLE SessionEvents[SESSION_MAX];
105 unsigned short LSNs[SESSION_MAX];
106 int lanas[SESSION_MAX];
107 BOOL dead_sessions[SESSION_MAX];
110 osi_mutex_t smb_RawBufLock;
113 #define SMB_MASKFLAG_TILDE 1
114 #define SMB_MASKFLAG_CASEFOLD 2
116 #define RAWTIMEOUT INFINITE
119 typedef struct raw_write_cont {
128 /* dir search stuff */
129 long smb_dirSearchCounter = 1;
130 smb_dirSearch_t *smb_firstDirSearchp;
131 smb_dirSearch_t *smb_lastDirSearchp;
133 /* hide dot files? */
134 int smb_hideDotFiles;
136 /* global state about V3 protocols */
137 int smb_useV3; /* try to negotiate V3 */
139 static showErrors = 0;
140 /* MessageBox or something like it */
141 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
144 * Time in Unix format of midnight, 1/1/1970 local time.
145 * When added to dosUTime, gives Unix (AFS) time.
147 time_t smb_localZero = 0;
149 #define USE_NUMERIC_TIME_CONV 1
151 #ifndef USE_NUMERIC_TIME_CONV
152 /* Time difference for converting to kludge-GMT */
153 afs_uint32 smb_NowTZ;
154 #endif /* USE_NUMERIC_TIME_CONV */
156 char *smb_localNamep = NULL;
158 smb_vc_t *smb_allVCsp;
159 smb_vc_t *smb_deadVCsp;
161 smb_username_t *usernamesp = NULL;
163 smb_waitingLockRequest_t *smb_allWaitingLocks;
165 DWORD smb_TlsRequestSlot = -1;
168 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
169 NCB *ncbp, raw_write_cont_t *rwcp);
170 int smb_NetbiosInit(int);
173 void smb_LogPacket(smb_packet_t *packet);
174 #endif /* LOG_PACKET */
176 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
177 int smb_ServerDomainNameLength = 0;
178 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
179 int smb_ServerOSLength = sizeof(smb_ServerOS);
180 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
181 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
183 /* Faux server GUID. This is never checked. */
184 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
186 void smb_ResetServerPriority()
188 void * p = TlsGetValue(smb_TlsRequestSlot);
191 TlsSetValue(smb_TlsRequestSlot, NULL);
192 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
196 void smb_SetRequestStartTime()
198 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
200 tp = malloc(sizeof(time_t));
204 if (!TlsSetValue(smb_TlsRequestSlot, tp))
209 void smb_UpdateServerPriority()
211 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
214 time_t now = osi_Time();
216 /* Give one priority boost for each 15 seconds */
217 SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
222 const char * ncb_error_string(int code)
226 case 0x01: s = "llegal buffer length"; break;
227 case 0x03: s = "illegal command"; break;
228 case 0x05: s = "command timed out"; break;
229 case 0x06: s = "message incomplete, issue another command"; break;
230 case 0x07: s = "illegal buffer address"; break;
231 case 0x08: s = "session number out of range"; break;
232 case 0x09: s = "no resource available"; break;
233 case 0x0a: s = "session closed"; break;
234 case 0x0b: s = "command cancelled"; break;
235 case 0x0d: s = "duplicate name"; break;
236 case 0x0e: s = "name table full"; break;
237 case 0x0f: s = "no deletions, name has active sessions"; break;
238 case 0x11: s = "local session table full"; break;
239 case 0x12: s = "remote session table full"; break;
240 case 0x13: s = "illegal name number"; break;
241 case 0x14: s = "no callname"; break;
242 case 0x15: s = "cannot put * in NCB_NAME"; break;
243 case 0x16: s = "name in use on remote adapter"; break;
244 case 0x17: s = "name deleted"; break;
245 case 0x18: s = "session ended abnormally"; break;
246 case 0x19: s = "name conflict detected"; break;
247 case 0x21: s = "interface busy, IRET before retrying"; break;
248 case 0x22: s = "too many commands outstanding, retry later";break;
249 case 0x23: s = "ncb_lana_num field invalid"; break;
250 case 0x24: s = "command completed while cancel occurring "; break;
251 case 0x26: s = "command not valid to cancel"; break;
252 case 0x30: s = "name defined by anther local process"; break;
253 case 0x34: s = "environment undefined. RESET required"; break;
254 case 0x35: s = "required OS resources exhausted"; break;
255 case 0x36: s = "max number of applications exceeded"; break;
256 case 0x37: s = "no saps available for netbios"; break;
257 case 0x38: s = "requested resources are not available"; break;
258 case 0x39: s = "invalid ncb address or length > segment"; break;
259 case 0x3B: s = "invalid NCB DDID"; break;
260 case 0x3C: s = "lock of user area failed"; break;
261 case 0x3f: s = "NETBIOS not loaded"; break;
262 case 0x40: s = "system error"; break;
263 default: s = "unknown error";
269 char * myCrt_Dispatch(int i)
274 return "(00)ReceiveCoreMakeDir";
276 return "(01)ReceiveCoreRemoveDir";
278 return "(02)ReceiveCoreOpen";
280 return "(03)ReceiveCoreCreate";
282 return "(04)ReceiveCoreClose";
284 return "(05)ReceiveCoreFlush";
286 return "(06)ReceiveCoreUnlink";
288 return "(07)ReceiveCoreRename";
290 return "(08)ReceiveCoreGetFileAttributes";
292 return "(09)ReceiveCoreSetFileAttributes";
294 return "(0a)ReceiveCoreRead";
296 return "(0b)ReceiveCoreWrite";
298 return "(0c)ReceiveCoreLockRecord";
300 return "(0d)ReceiveCoreUnlockRecord";
302 return "(0e)SendCoreBadOp";
304 return "(0f)ReceiveCoreCreate";
306 return "(10)ReceiveCoreCheckPath";
308 return "(11)SendCoreBadOp";
310 return "(12)ReceiveCoreSeek";
312 return "(1a)ReceiveCoreReadRaw";
314 return "(1d)ReceiveCoreWriteRawDummy";
316 return "(22)ReceiveV3SetAttributes";
318 return "(23)ReceiveV3GetAttributes";
320 return "(24)ReceiveV3LockingX";
322 return "(25)ReceiveV3Trans";
324 return "(26)ReceiveV3Trans[aux]";
326 return "(29)SendCoreBadOp";
328 return "(2b)ReceiveCoreEcho";
330 return "(2d)ReceiveV3OpenX";
332 return "(2e)ReceiveV3ReadX";
334 return "(2f)ReceiveV3WriteX";
336 return "(32)ReceiveV3Tran2A";
338 return "(33)ReceiveV3Tran2A[aux]";
340 return "(34)ReceiveV3FindClose";
342 return "(35)ReceiveV3FindNotifyClose";
344 return "(70)ReceiveCoreTreeConnect";
346 return "(71)ReceiveCoreTreeDisconnect";
348 return "(72)ReceiveNegotiate";
350 return "(73)ReceiveV3SessionSetupX";
352 return "(74)ReceiveV3UserLogoffX";
354 return "(75)ReceiveV3TreeConnectX";
356 return "(80)ReceiveCoreGetDiskAttributes";
358 return "(81)ReceiveCoreSearchDir";
362 return "(83)FindUnique";
364 return "(84)FindClose";
366 return "(A0)ReceiveNTTransact";
368 return "(A2)ReceiveNTCreateX";
370 return "(A4)ReceiveNTCancel";
372 return "(A5)ReceiveNTRename";
374 return "(C0)OpenPrintFile";
376 return "(C1)WritePrintFile";
378 return "(C2)ClosePrintFile";
380 return "(C3)GetPrintQueue";
382 return "(D8)ReadBulk";
384 return "(D9)WriteBulk";
386 return "(DA)WriteBulkData";
388 return "unknown SMB op";
392 char * myCrt_2Dispatch(int i)
397 return "unknown SMB op-2";
399 return "S(00)CreateFile_ReceiveTran2Open";
401 return "S(01)FindFirst_ReceiveTran2SearchDir";
403 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
405 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
407 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
409 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
411 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
413 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
415 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
417 return "S(09)_ReceiveTran2FSCTL";
419 return "S(0a)_ReceiveTran2IOCTL";
421 return "S(0b)_ReceiveTran2FindNotifyFirst";
423 return "S(0c)_ReceiveTran2FindNotifyNext";
425 return "S(0d)_ReceiveTran2CreateDirectory";
427 return "S(0e)_ReceiveTran2SessionSetup";
429 return "S(0f)_QueryFileSystemInformationFid";
431 return "S(10)_ReceiveTran2GetDfsReferral";
433 return "S(11)_ReceiveTran2ReportDfsInconsistency";
437 char * myCrt_RapDispatch(int i)
442 return "unknown RAP OP";
444 return "RAP(0)NetShareEnum";
446 return "RAP(1)NetShareGetInfo";
448 return "RAP(13)NetServerGetInfo";
450 return "RAP(63)NetWkStaGetInfo";
454 /* scache must be locked */
455 unsigned int smb_Attributes(cm_scache_t *scp)
459 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
460 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
461 scp->fileType == CM_SCACHETYPE_INVALID)
463 attrs = SMB_ATTR_DIRECTORY;
464 #ifdef SPECIAL_FOLDERS
465 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
466 #endif /* SPECIAL_FOLDERS */
467 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
468 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
473 * We used to mark a file RO if it was in an RO volume, but that
474 * turns out to be impolitic in NT. See defect 10007.
477 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
478 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
480 if ((scp->unixModeBits & 0222) == 0)
481 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
487 /* Check if the named file/dir is a dotfile/dotdir */
488 /* String pointed to by lastComp can have leading slashes, but otherwise should have
489 no other patch components */
490 unsigned int smb_IsDotFile(char *lastComp) {
493 /* skip over slashes */
494 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
499 /* nulls, curdir and parent dir doesn't count */
505 if(*(s+1) == '.' && !*(s + 2))
512 static int ExtractBits(WORD bits, short start, short len)
519 num = bits << (16 - end);
520 num = num >> ((16 - end) + start);
525 void ShowUnixTime(char *FuncName, time_t unixTime)
530 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
532 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
533 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
535 int day, month, year, sec, min, hour;
538 day = ExtractBits(wDate, 0, 5);
539 month = ExtractBits(wDate, 5, 4);
540 year = ExtractBits(wDate, 9, 7) + 1980;
542 sec = ExtractBits(wTime, 0, 5);
543 min = ExtractBits(wTime, 5, 6);
544 hour = ExtractBits(wTime, 11, 5);
546 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
547 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
551 /* Determine if we are observing daylight savings time */
552 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
554 TIME_ZONE_INFORMATION timeZoneInformation;
555 SYSTEMTIME utc, local, localDST;
557 /* Get the time zone info. NT uses this to calc if we are in DST. */
558 GetTimeZoneInformation(&timeZoneInformation);
560 /* Return the daylight bias */
561 *pDstBias = timeZoneInformation.DaylightBias;
563 /* Return the bias */
564 *pBias = timeZoneInformation.Bias;
566 /* Now determine if DST is being observed */
568 /* Get the UTC (GMT) time */
571 /* Convert UTC time to local time using the time zone info. If we are
572 observing DST, the calculated local time will include this.
574 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
576 /* Set the daylight bias to 0. The daylight bias is the amount of change
577 * in time that we use for daylight savings time. By setting this to 0
578 * we cause there to be no change in time during daylight savings time.
580 timeZoneInformation.DaylightBias = 0;
582 /* Convert the utc time to local time again, but this time without any
583 adjustment for daylight savings time.
585 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
587 /* If the two times are different, then it means that the localDST that
588 we calculated includes the daylight bias, and therefore we are
589 observing daylight savings time.
591 *pDST = localDST.wHour != local.wHour;
595 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
597 BOOL dst; /* Will be TRUE if observing DST */
598 LONG dstBias; /* Offset from local time if observing DST */
599 LONG bias; /* Offset from GMT for local time */
602 * This function will adjust the last write time to compensate
603 * for two bugs in the smb client:
605 * 1) During Daylight Savings Time, the LastWriteTime is ahead
606 * in time by the DaylightBias (ignoring the sign - the
607 * DaylightBias is always stored as a negative number). If
608 * the DaylightBias is -60, then the LastWriteTime will be
609 * ahead by 60 minutes.
611 * 2) If the local time zone is a positive offset from GMT, then
612 * the LastWriteTime will be the correct local time plus the
613 * Bias (ignoring the sign - a positive offset from GMT is
614 * always stored as a negative Bias). If the Bias is -120,
615 * then the LastWriteTime will be ahead by 120 minutes.
617 * These bugs can occur at the same time.
620 GetTimeZoneInfo(&dst, &dstBias, &bias);
622 /* First adjust for DST */
624 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
626 /* Now adjust for a positive offset from GMT (a negative bias). */
628 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
631 #ifndef USE_NUMERIC_TIME_CONV
633 * Calculate the difference (in seconds) between local time and GMT.
634 * This enables us to convert file times to kludge-GMT.
640 struct tm gmt_tm, local_tm;
641 int days, hours, minutes, seconds;
644 gmt_tm = *(gmtime(&t));
645 local_tm = *(localtime(&t));
647 days = local_tm.tm_yday - gmt_tm.tm_yday;
648 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
649 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
650 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
654 #endif /* USE_NUMERIC_TIME_CONV */
656 #ifdef USE_NUMERIC_TIME_CONV
657 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
659 // Note that LONGLONG is a 64-bit value
662 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
663 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
664 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
667 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
672 time_t ersatz_unixTime;
675 * Must use kludge-GMT instead of real GMT.
676 * kludge-GMT is computed by adding time zone difference to localtime.
679 * ltp = gmtime(&unixTime);
681 ersatz_unixTime = unixTime - smb_NowTZ;
682 ltp = localtime(&ersatz_unixTime);
684 /* if we fail, make up something */
687 localJunk.tm_year = 89 - 20;
688 localJunk.tm_mon = 4;
689 localJunk.tm_mday = 12;
690 localJunk.tm_hour = 0;
691 localJunk.tm_min = 0;
692 localJunk.tm_sec = 0;
695 stm.wYear = ltp->tm_year + 1900;
696 stm.wMonth = ltp->tm_mon + 1;
697 stm.wDayOfWeek = ltp->tm_wday;
698 stm.wDay = ltp->tm_mday;
699 stm.wHour = ltp->tm_hour;
700 stm.wMinute = ltp->tm_min;
701 stm.wSecond = ltp->tm_sec;
702 stm.wMilliseconds = 0;
704 SystemTimeToFileTime(&stm, largeTimep);
706 #endif /* USE_NUMERIC_TIME_CONV */
708 #ifdef USE_NUMERIC_TIME_CONV
709 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
711 // Note that LONGLONG is a 64-bit value
714 ll = largeTimep->dwHighDateTime;
716 ll += largeTimep->dwLowDateTime;
718 ll -= 116444736000000000;
721 *unixTimep = (DWORD)ll;
723 #else /* USE_NUMERIC_TIME_CONV */
724 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
730 FileTimeToSystemTime(largeTimep, &stm);
732 lt.tm_year = stm.wYear - 1900;
733 lt.tm_mon = stm.wMonth - 1;
734 lt.tm_wday = stm.wDayOfWeek;
735 lt.tm_mday = stm.wDay;
736 lt.tm_hour = stm.wHour;
737 lt.tm_min = stm.wMinute;
738 lt.tm_sec = stm.wSecond;
741 save_timezone = _timezone;
742 _timezone += smb_NowTZ;
743 *unixTimep = mktime(<);
744 _timezone = save_timezone;
746 #endif /* USE_NUMERIC_TIME_CONV */
748 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
758 /* if we fail, make up something */
761 localJunk.tm_year = 89 - 20;
762 localJunk.tm_mon = 4;
763 localJunk.tm_mday = 12;
764 localJunk.tm_hour = 0;
765 localJunk.tm_min = 0;
766 localJunk.tm_sec = 0;
769 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
770 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
771 *searchTimep = (dosDate<<16) | dosTime;
774 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
776 unsigned short dosDate;
777 unsigned short dosTime;
780 dosDate = (unsigned short) (searchTime & 0xffff);
781 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
783 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
784 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
785 localTm.tm_mday = (dosDate) & 0x1f;
786 localTm.tm_hour = (dosTime>>11) & 0x1f;
787 localTm.tm_min = (dosTime >> 5) & 0x3f;
788 localTm.tm_sec = (dosTime & 0x1f) * 2;
789 localTm.tm_isdst = -1; /* compute whether DST in effect */
791 *unixTimep = mktime(&localTm);
794 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
796 time_t diff_t = unixTime - smb_localZero;
797 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
798 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
800 *dosUTimep = (afs_uint32)diff_t;
803 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
805 *unixTimep = dosTime + smb_localZero;
808 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
812 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
813 lock_ObtainWrite(&smb_rctLock);
814 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
815 if (vcp->magic != SMB_VC_MAGIC)
816 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
819 if (lsn == vcp->lsn && lana == vcp->lana &&
820 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
821 smb_HoldVCNoLock(vcp);
825 if (!vcp && (flags & SMB_FLAG_CREATE)) {
826 vcp = malloc(sizeof(*vcp));
827 memset(vcp, 0, sizeof(*vcp));
828 vcp->vcID = ++numVCs;
829 vcp->magic = SMB_VC_MAGIC;
830 vcp->refCount = 2; /* smb_allVCsp and caller */
833 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
834 vcp->nextp = smb_allVCsp;
836 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
841 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
842 /* We must obtain a challenge for extended auth
843 * in case the client negotiates smb v3
845 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
846 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
847 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
848 ULONG lsaRespSize = 0;
850 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
852 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
859 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
860 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
861 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
862 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
863 nts, ntsEx, lsaRespSize);
865 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
867 if (ntsEx == STATUS_SUCCESS) {
868 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
869 LsaFreeReturnBuffer(lsaResp);
872 * This will cause the subsequent authentication to fail but
873 * that is better than us dereferencing a NULL pointer and
876 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
880 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
882 if (numVCs >= CM_SESSION_RESERVED) {
884 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
887 lock_ReleaseWrite(&smb_rctLock);
888 lock_ReleaseWrite(&smb_globalLock);
892 int smb_IsStarMask(char *maskp)
897 for(i=0; i<11; i++) {
899 if (tc == '?' || tc == '*' || tc == '>')
905 void smb_ReleaseVCInternal(smb_vc_t *vcp)
912 if (vcp->refCount == 0) {
913 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
914 /* remove VCP from smb_deadVCsp */
915 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
921 lock_FinalizeMutex(&vcp->mx);
922 memset(vcp,0,sizeof(smb_vc_t));
925 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
929 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
930 avcp?"not ":"",vcp, vcp->refCount);
932 GenerateMiniDump(NULL);
934 /* This is a wrong. However, I suspect that there is an undercount
935 * and I don't want to release 1.4.1 in a state that will allow
936 * smb_vc_t objects to be deallocated while still in the
937 * smb_allVCsp list. The list is supposed to keep a reference
938 * to the smb_vc_t. Put it back.
945 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
947 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
948 smb_ReleaseVCInternal(vcp);
951 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 void smb_HoldVCNoLock(smb_vc_t *vcp)
962 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
965 void smb_HoldVC(smb_vc_t *vcp)
967 lock_ObtainWrite(&smb_rctLock);
969 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
970 lock_ReleaseWrite(&smb_rctLock);
973 void smb_CleanupDeadVC(smb_vc_t *vcp)
981 smb_user_t *uidpIter;
982 smb_user_t *uidpNext;
986 lock_ObtainMutex(&vcp->mx);
987 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
988 lock_ReleaseMutex(&vcp->mx);
989 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
992 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
993 lock_ReleaseMutex(&vcp->mx);
994 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
996 lock_ObtainWrite(&smb_rctLock);
997 /* remove VCP from smb_allVCsp */
998 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
999 if ((*vcpp)->magic != SMB_VC_MAGIC)
1000 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1001 __FILE__, __LINE__);
1004 vcp->nextp = smb_deadVCsp;
1006 /* Hold onto the reference until we are done with this function */
1011 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1012 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1014 if (fidpIter->delete)
1017 fid = fidpIter->fid;
1018 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1020 smb_HoldFIDNoLock(fidpIter);
1021 lock_ReleaseWrite(&smb_rctLock);
1023 smb_CloseFID(vcp, fidpIter, NULL, 0);
1024 smb_ReleaseFID(fidpIter);
1026 lock_ObtainWrite(&smb_rctLock);
1027 fidpNext = vcp->fidsp;
1030 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1031 tidpNext = tidpIter->nextp;
1032 if (tidpIter->delete)
1034 tidpIter->delete = 1;
1036 tid = tidpIter->tid;
1037 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1039 smb_HoldTIDNoLock(tidpIter);
1040 smb_ReleaseTID(tidpIter, TRUE);
1041 tidpNext = vcp->tidsp;
1044 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1045 uidpNext = uidpIter->nextp;
1046 if (uidpIter->delete)
1048 uidpIter->delete = 1;
1050 /* do not add an additional reference count for the smb_user_t
1051 * as the smb_vc_t already is holding a reference */
1052 lock_ReleaseWrite(&smb_rctLock);
1054 smb_ReleaseUID(uidpIter);
1056 lock_ObtainWrite(&smb_rctLock);
1057 uidpNext = vcp->usersp;
1060 /* The vcp is now on the deadVCsp list. We intentionally drop the
1061 * reference so that the refcount can reach 0 and we can delete it */
1062 smb_ReleaseVCNoLock(vcp);
1064 lock_ReleaseWrite(&smb_rctLock);
1065 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1068 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1072 lock_ObtainWrite(&smb_rctLock);
1074 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1075 if (tidp->refCount == 0 && tidp->delete) {
1077 smb_ReleaseTID(tidp, TRUE);
1081 if (tid == tidp->tid) {
1086 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1087 tidp = malloc(sizeof(*tidp));
1088 memset(tidp, 0, sizeof(*tidp));
1089 tidp->nextp = vcp->tidsp;
1092 smb_HoldVCNoLock(vcp);
1094 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1097 lock_ReleaseWrite(&smb_rctLock);
1101 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1106 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1114 lock_ObtainWrite(&smb_rctLock);
1115 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1116 if (tidp->refCount == 0 && (tidp->delete)) {
1117 ltpp = &tidp->vcp->tidsp;
1118 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1122 osi_assertx(tp != NULL, "null smb_tid_t");
1124 lock_FinalizeMutex(&tidp->mx);
1125 userp = tidp->userp; /* remember to drop ref later */
1127 smb_ReleaseVCNoLock(tidp->vcp);
1131 lock_ReleaseWrite(&smb_rctLock);
1133 cm_ReleaseUser(userp);
1136 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1138 smb_user_t *uidp = NULL;
1140 lock_ObtainWrite(&smb_rctLock);
1141 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1142 if (uid == uidp->userID) {
1144 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1146 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1150 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1151 uidp = malloc(sizeof(*uidp));
1152 memset(uidp, 0, sizeof(*uidp));
1153 uidp->nextp = vcp->usersp;
1154 uidp->refCount = 2; /* one for the vcp and one for the caller */
1156 smb_HoldVCNoLock(vcp);
1158 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1160 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1162 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1164 lock_ReleaseWrite(&smb_rctLock);
1168 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1170 smb_username_t *unp= NULL;
1172 lock_ObtainWrite(&smb_rctLock);
1173 for(unp = usernamesp; unp; unp = unp->nextp) {
1174 if (stricmp(unp->name, usern) == 0 &&
1175 stricmp(unp->machine, machine) == 0) {
1180 if (!unp && (flags & SMB_FLAG_CREATE)) {
1181 unp = malloc(sizeof(*unp));
1182 memset(unp, 0, sizeof(*unp));
1184 unp->nextp = usernamesp;
1185 unp->name = strdup(usern);
1186 unp->machine = strdup(machine);
1188 lock_InitializeMutex(&unp->mx, "username_t mutex");
1189 if (flags & SMB_FLAG_AFSLOGON)
1190 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1193 lock_ReleaseWrite(&smb_rctLock);
1197 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1199 smb_user_t *uidp= NULL;
1201 lock_ObtainWrite(&smb_rctLock);
1202 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1205 if (stricmp(uidp->unp->name, usern) == 0) {
1207 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1208 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1213 lock_ReleaseWrite(&smb_rctLock);
1217 void smb_ReleaseUsername(smb_username_t *unp)
1220 smb_username_t **lupp;
1221 cm_user_t *userp = NULL;
1222 time_t now = osi_Time();
1224 lock_ObtainWrite(&smb_rctLock);
1225 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1226 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1227 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1229 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1233 osi_assertx(up != NULL, "null smb_username_t");
1235 up->nextp = NULL; /* do not remove this */
1236 lock_FinalizeMutex(&unp->mx);
1242 lock_ReleaseWrite(&smb_rctLock);
1244 cm_ReleaseUser(userp);
1247 void smb_HoldUIDNoLock(smb_user_t *uidp)
1252 void smb_ReleaseUID(smb_user_t *uidp)
1256 smb_username_t *unp = NULL;
1258 lock_ObtainWrite(&smb_rctLock);
1259 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1260 if (uidp->refCount == 0) {
1261 lupp = &uidp->vcp->usersp;
1262 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1266 osi_assertx(up != NULL, "null smb_user_t");
1268 lock_FinalizeMutex(&uidp->mx);
1270 smb_ReleaseVCNoLock(uidp->vcp);
1274 lock_ReleaseWrite(&smb_rctLock);
1278 cm_ReleaseUserVCRef(unp->userp);
1279 smb_ReleaseUsername(unp);
1283 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1285 cm_user_t *up = NULL;
1290 lock_ObtainMutex(&uidp->mx);
1292 up = uidp->unp->userp;
1295 lock_ReleaseMutex(&uidp->mx);
1301 /* retrieve a held reference to a user structure corresponding to an incoming
1303 * corresponding release function is cm_ReleaseUser.
1305 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1308 cm_user_t *up = NULL;
1311 smbp = (smb_t *) inp;
1312 uidp = smb_FindUID(vcp, smbp->uid, 0);
1316 up = smb_GetUserFromUID(uidp);
1318 smb_ReleaseUID(uidp);
1323 * Return a pointer to a pathname extracted from a TID structure. The
1324 * TID structure is not held; assume it won't go away.
1326 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1331 tidp = smb_FindTID(vcp, tid, 0);
1335 if (tidp->flags & SMB_TIDFLAG_IPC) {
1336 code = CM_ERROR_TIDIPC;
1337 /* tidp->pathname would be NULL, but that's fine */
1339 *treepath = tidp->pathname;
1340 smb_ReleaseTID(tidp, FALSE);
1345 /* check to see if we have a chained fid, that is, a fid that comes from an
1346 * OpenAndX message that ran earlier in this packet. In this case, the fid
1347 * field in a read, for example, request, isn't set, since the value is
1348 * supposed to be inherited from the openAndX call.
1350 int smb_ChainFID(int fid, smb_packet_t *inp)
1352 if (inp->fid == 0 || inp->inCount == 0)
1358 /* are we a priv'd user? What does this mean on NT? */
1359 int smb_SUser(cm_user_t *userp)
1364 /* find a file ID. If we pass in 0 we select an unused File ID.
1365 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1366 * smb_fid_t data structure if desired File ID cannot be found.
1368 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1373 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1376 lock_ObtainWrite(&smb_rctLock);
1377 /* figure out if we need to allocate a new file ID */
1380 fid = vcp->fidCounter;
1384 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1385 if (fidp->refCount == 0 && fidp->delete) {
1387 lock_ReleaseWrite(&smb_rctLock);
1388 smb_ReleaseFID(fidp);
1389 lock_ObtainWrite(&smb_rctLock);
1392 if (fid == fidp->fid) {
1395 if (fid == 0xFFFF) {
1397 "New FID number wraps on vcp 0x%x", vcp);
1407 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1408 char eventName[MAX_PATH];
1410 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1411 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1412 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1413 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1414 thrd_CloseHandle(event);
1416 if (fid == 0xFFFF) {
1417 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1423 fidp = malloc(sizeof(*fidp));
1424 memset(fidp, 0, sizeof(*fidp));
1425 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1428 smb_HoldVCNoLock(vcp);
1429 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1431 fidp->curr_chunk = fidp->prev_chunk = -2;
1432 fidp->raw_write_event = event;
1434 vcp->fidCounter = fid+1;
1435 if (vcp->fidCounter == 0xFFFF) {
1436 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1438 vcp->fidCounter = 1;
1443 lock_ReleaseWrite(&smb_rctLock);
1447 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1449 smb_fid_t *fidp = NULL;
1455 lock_ObtainWrite(&smb_rctLock);
1456 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1457 if (scp == fidp->scp) {
1462 lock_ReleaseWrite(&smb_rctLock);
1466 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1472 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1473 /* the sm_fid_t->mx and smb_rctLock must not be held */
1474 void smb_ReleaseFID(smb_fid_t *fidp)
1476 cm_scache_t *scp = NULL;
1477 cm_user_t *userp = NULL;
1478 smb_vc_t *vcp = NULL;
1479 smb_ioctl_t *ioctlp;
1481 lock_ObtainMutex(&fidp->mx);
1482 lock_ObtainWrite(&smb_rctLock);
1483 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1484 if (fidp->refCount == 0 && (fidp->delete)) {
1487 scp = fidp->scp; /* release after lock is released */
1489 lock_ObtainMutex(&scp->mx);
1490 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1491 lock_ReleaseMutex(&scp->mx);
1492 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1495 userp = fidp->userp;
1499 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1500 thrd_CloseHandle(fidp->raw_write_event);
1502 /* and see if there is ioctl stuff to free */
1503 ioctlp = fidp->ioctlp;
1506 cm_FreeSpace(ioctlp->prefix);
1507 if (ioctlp->inAllocp)
1508 free(ioctlp->inAllocp);
1509 if (ioctlp->outAllocp)
1510 free(ioctlp->outAllocp);
1513 lock_ReleaseMutex(&fidp->mx);
1514 lock_FinalizeMutex(&fidp->mx);
1518 smb_ReleaseVCNoLock(vcp);
1520 lock_ReleaseMutex(&fidp->mx);
1522 lock_ReleaseWrite(&smb_rctLock);
1524 /* now release the scache structure */
1526 cm_ReleaseSCache(scp);
1529 cm_ReleaseUser(userp);
1533 * Case-insensitive search for one string in another;
1534 * used to find variable names in submount pathnames.
1536 static char *smb_stristr(char *str1, char *str2)
1540 for (cursor = str1; *cursor; cursor++)
1541 if (stricmp(cursor, str2) == 0)
1548 * Substitute a variable value for its name in a submount pathname. Variable
1549 * name has been identified by smb_stristr() and is in substr. Variable name
1550 * length (plus one) is in substr_size. Variable value is in newstr.
1552 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1557 strcpy(temp, substr + substr_size - 1);
1558 strcpy(substr, newstr);
1562 char VNUserName[] = "%USERNAME%";
1563 char VNLCUserName[] = "%LCUSERNAME%";
1564 char VNComputerName[] = "%COMPUTERNAME%";
1565 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1568 typedef struct smb_findShare_rock {
1572 } smb_findShare_rock_t;
1574 #define SMB_FINDSHARE_EXACT_MATCH 1
1575 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1577 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1581 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1582 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1583 if(!stricmp(dep->name, vrock->shareName))
1584 matchType = SMB_FINDSHARE_EXACT_MATCH;
1586 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1587 if(vrock->match) free(vrock->match);
1588 vrock->match = strdup(dep->name);
1589 vrock->matchType = matchType;
1591 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1592 return CM_ERROR_STOPNOW;
1598 /* find a shareName in the table of submounts */
1599 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1603 char pathName[1024];
1610 DWORD allSubmount = 1;
1612 /* if allSubmounts == 0, only return the //mountRoot/all share
1613 * if in fact it has been been created in the subMounts table.
1614 * This is to allow sites that want to restrict access to the
1617 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1618 0, KEY_QUERY_VALUE, &parmKey);
1619 if (code == ERROR_SUCCESS) {
1620 len = sizeof(allSubmount);
1621 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1622 (BYTE *) &allSubmount, &len);
1623 if (code != ERROR_SUCCESS) {
1626 RegCloseKey (parmKey);
1629 if (allSubmount && _stricmp(shareName, "all") == 0) {
1634 /* In case, the all share is disabled we need to still be able
1635 * to handle ioctl requests
1637 if (_stricmp(shareName, "ioctl$") == 0) {
1638 *pathNamep = strdup("/.__ioctl__");
1642 if (_stricmp(shareName, "IPC$") == 0 ||
1643 _stricmp(shareName, "srvsvc") == 0 ||
1644 _stricmp(shareName, "wkssvc") == 0 ||
1645 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1646 _stricmp(shareName, "DESKTOP.INI") == 0
1652 /* Check for volume references
1654 * They look like <cell>{%,#}<volume>
1656 if (strchr(shareName, '%') != NULL ||
1657 strchr(shareName, '#') != NULL) {
1658 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1659 /* make room for '/@vol:' + mountchar + NULL terminator*/
1661 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1662 osi_LogSaveString(smb_logp, shareName));
1664 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1665 "/" CM_PREFIX_VOL "%s", shareName);
1666 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1667 len = (DWORD)(strlen(pathstr) + 1);
1669 *pathNamep = malloc(len);
1671 strcpy(*pathNamep, pathstr);
1673 osi_Log1(smb_logp, " returning pathname [%s]",
1674 osi_LogSaveString(smb_logp, *pathNamep));
1682 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1683 0, KEY_QUERY_VALUE, &parmKey);
1684 if (code == ERROR_SUCCESS) {
1685 len = sizeof(pathName);
1686 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1687 (BYTE *) pathName, &len);
1688 if (code != ERROR_SUCCESS)
1690 RegCloseKey (parmKey);
1694 if (len != 0 && len != sizeof(pathName) - 1) {
1695 /* We can accept either unix or PC style AFS pathnames. Convert
1696 * Unix-style to PC style here for internal use.
1699 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1700 p += strlen(cm_mountRoot); /* skip mount path */
1703 if (*q == '/') *q = '\\'; /* change to \ */
1709 if (var = smb_stristr(p, VNUserName)) {
1710 if (uidp && uidp->unp)
1711 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1713 smb_subst(p, var, sizeof(VNUserName)," ");
1715 else if (var = smb_stristr(p, VNLCUserName))
1717 if (uidp && uidp->unp)
1718 strcpy(temp, uidp->unp->name);
1722 smb_subst(p, var, sizeof(VNLCUserName), temp);
1724 else if (var = smb_stristr(p, VNComputerName))
1726 sizeTemp = sizeof(temp);
1727 GetComputerName((LPTSTR)temp, &sizeTemp);
1728 smb_subst(p, var, sizeof(VNComputerName), temp);
1730 else if (var = smb_stristr(p, VNLCComputerName))
1732 sizeTemp = sizeof(temp);
1733 GetComputerName((LPTSTR)temp, &sizeTemp);
1735 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1740 *pathNamep = strdup(p);
1745 /* First lookup shareName in root.afs */
1747 smb_findShare_rock_t vrock;
1749 char * p = shareName;
1752 /* attempt to locate a partial match in root.afs. This is because
1753 when using the ANSI RAP calls, the share name is limited to 13 chars
1754 and hence is truncated. Of course we prefer exact matches. */
1756 thyper.HighPart = 0;
1759 vrock.shareName = shareName;
1761 vrock.matchType = 0;
1763 cm_HoldSCache(cm_data.rootSCachep);
1764 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1765 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1766 cm_ReleaseSCache(cm_data.rootSCachep);
1768 if (vrock.matchType) {
1769 sprintf(pathName,"/%s/",vrock.match);
1770 *pathNamep = strdup(strlwr(pathName));
1775 /* if we get here, there was no match for the share in root.afs */
1776 /* so try to create \\<netbiosName>\<cellname> */
1781 /* Get the full name for this cell */
1782 code = cm_SearchCellFile(p, temp, 0, 0);
1783 #ifdef AFS_AFSDB_ENV
1784 if (code && cm_dnsEnabled) {
1786 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1789 /* construct the path */
1791 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1792 *pathNamep = strdup(strlwr(pathName));
1801 /* Client-side offline caching policy types */
1802 #define CSC_POLICY_MANUAL 0
1803 #define CSC_POLICY_DOCUMENTS 1
1804 #define CSC_POLICY_PROGRAMS 2
1805 #define CSC_POLICY_DISABLE 3
1807 int smb_FindShareCSCPolicy(char *shareName)
1813 int retval = CSC_POLICY_MANUAL;
1815 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1816 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1819 REG_OPTION_NON_VOLATILE,
1825 len = sizeof(policy);
1826 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1828 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1830 else if (stricmp(policy, "documents") == 0)
1832 retval = CSC_POLICY_DOCUMENTS;
1834 else if (stricmp(policy, "programs") == 0)
1836 retval = CSC_POLICY_PROGRAMS;
1838 else if (stricmp(policy, "disable") == 0)
1840 retval = CSC_POLICY_DISABLE;
1843 RegCloseKey(hkCSCPolicy);
1847 /* find a dir search structure by cookie value, and return it held.
1848 * Must be called with smb_globalLock held.
1850 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1852 smb_dirSearch_t *dsp;
1854 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1855 if (dsp->cookie == cookie) {
1856 if (dsp != smb_firstDirSearchp) {
1857 /* move to head of LRU queue, too, if we're not already there */
1858 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1859 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1860 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1861 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1862 if (!smb_lastDirSearchp)
1863 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1865 lock_ObtainMutex(&dsp->mx);
1867 lock_ReleaseMutex(&dsp->mx);
1873 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1874 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1875 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1881 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1883 lock_ObtainWrite(&smb_globalLock);
1884 lock_ObtainMutex(&dsp->mx);
1885 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1886 dsp->cookie, dsp, dsp->scp);
1887 dsp->flags |= SMB_DIRSEARCH_DELETE;
1888 if (dsp->scp != NULL) {
1889 lock_ObtainMutex(&dsp->scp->mx);
1890 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1891 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1892 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1893 dsp->scp->bulkStatProgress = hzero;
1895 lock_ReleaseMutex(&dsp->scp->mx);
1897 lock_ReleaseMutex(&dsp->mx);
1898 lock_ReleaseWrite(&smb_globalLock);
1901 /* Must be called with the smb_globalLock held */
1902 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1904 cm_scache_t *scp = NULL;
1906 lock_ObtainMutex(&dsp->mx);
1907 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1908 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1909 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1910 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1911 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1912 lock_ReleaseMutex(&dsp->mx);
1913 lock_FinalizeMutex(&dsp->mx);
1915 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1916 dsp->cookie, dsp, scp);
1919 lock_ReleaseMutex(&dsp->mx);
1921 /* do this now to avoid spurious locking hierarchy creation */
1923 cm_ReleaseSCache(scp);
1926 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1928 lock_ObtainWrite(&smb_globalLock);
1929 smb_ReleaseDirSearchNoLock(dsp);
1930 lock_ReleaseWrite(&smb_globalLock);
1933 /* find a dir search structure by cookie value, and return it held */
1934 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1936 smb_dirSearch_t *dsp;
1938 lock_ObtainWrite(&smb_globalLock);
1939 dsp = smb_FindDirSearchNoLock(cookie);
1940 lock_ReleaseWrite(&smb_globalLock);
1944 /* GC some dir search entries, in the address space expected by the specific protocol.
1945 * Must be called with smb_globalLock held; release the lock temporarily.
1947 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1948 void smb_GCDirSearches(int isV3)
1950 smb_dirSearch_t *prevp;
1951 smb_dirSearch_t *tp;
1952 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1956 victimCount = 0; /* how many have we got so far */
1957 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1958 /* we'll move tp from queue, so
1961 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1962 /* if no one is using this guy, and we're either in the new protocol,
1963 * or we're in the old one and this is a small enough ID to be useful
1964 * to the old protocol, GC this guy.
1966 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1967 /* hold and delete */
1968 lock_ObtainMutex(&tp->mx);
1969 tp->flags |= SMB_DIRSEARCH_DELETE;
1970 lock_ReleaseMutex(&tp->mx);
1971 victimsp[victimCount++] = tp;
1975 /* don't do more than this */
1976 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1980 /* now release them */
1981 for (i = 0; i < victimCount; i++) {
1982 smb_ReleaseDirSearchNoLock(victimsp[i]);
1986 /* function for allocating a dir search entry. We need these to remember enough context
1987 * since we don't get passed the path from call to call during a directory search.
1989 * Returns a held dir search structure, and bumps the reference count on the vnode,
1990 * since it saves a pointer to the vnode.
1992 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1994 smb_dirSearch_t *dsp;
2000 lock_ObtainWrite(&smb_globalLock);
2003 /* what's the biggest ID allowed in this version of the protocol */
2004 /* TODO: do we really want a non v3 dir search request to wrap
2005 smb_dirSearchCounter? */
2006 maxAllowed = isV3 ? 65535 : 255;
2007 if (smb_dirSearchCounter > maxAllowed)
2008 smb_dirSearchCounter = 1;
2010 start = smb_dirSearchCounter;
2013 /* twice so we have enough tries to find guys we GC after one pass;
2014 * 10 extra is just in case I mis-counted.
2016 if (++counter > 2*maxAllowed+10)
2017 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2019 if (smb_dirSearchCounter > maxAllowed) {
2020 smb_dirSearchCounter = 1;
2022 if (smb_dirSearchCounter == start) {
2024 smb_GCDirSearches(isV3);
2027 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2029 /* don't need to watch for refcount zero and deleted, since
2030 * we haven't dropped the global lock.
2032 lock_ObtainMutex(&dsp->mx);
2034 lock_ReleaseMutex(&dsp->mx);
2035 ++smb_dirSearchCounter;
2039 dsp = malloc(sizeof(*dsp));
2040 memset(dsp, 0, sizeof(*dsp));
2041 dsp->cookie = smb_dirSearchCounter;
2042 ++smb_dirSearchCounter;
2044 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2045 dsp->lastTime = osi_Time();
2046 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2047 if (!smb_lastDirSearchp)
2048 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2050 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2054 lock_ReleaseWrite(&smb_globalLock);
2058 static smb_packet_t *GetPacket(void)
2062 lock_ObtainWrite(&smb_globalLock);
2063 tbp = smb_packetFreeListp;
2065 smb_packetFreeListp = tbp->nextp;
2066 lock_ReleaseWrite(&smb_globalLock);
2068 tbp = calloc(65540,1);
2069 tbp->magic = SMB_PACKETMAGIC;
2072 tbp->resumeCode = 0;
2078 tbp->ncb_length = 0;
2083 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2088 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2092 memcpy(tbp, pkt, sizeof(smb_packet_t));
2093 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2095 smb_HoldVC(tbp->vcp);
2099 static NCB *GetNCB(void)
2104 lock_ObtainWrite(&smb_globalLock);
2105 tbp = smb_ncbFreeListp;
2107 smb_ncbFreeListp = tbp->nextp;
2108 lock_ReleaseWrite(&smb_globalLock);
2110 tbp = calloc(sizeof(*tbp),1);
2111 tbp->magic = SMB_NCBMAGIC;
2114 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2116 memset(&tbp->ncb, 0, sizeof(NCB));
2121 void smb_FreePacket(smb_packet_t *tbp)
2123 smb_vc_t * vcp = NULL;
2124 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2126 lock_ObtainWrite(&smb_globalLock);
2127 tbp->nextp = smb_packetFreeListp;
2128 smb_packetFreeListp = tbp;
2129 tbp->magic = SMB_PACKETMAGIC;
2133 tbp->resumeCode = 0;
2139 tbp->ncb_length = 0;
2141 lock_ReleaseWrite(&smb_globalLock);
2147 static void FreeNCB(NCB *bufferp)
2151 tbp = (smb_ncb_t *) bufferp;
2152 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2154 lock_ObtainWrite(&smb_globalLock);
2155 tbp->nextp = smb_ncbFreeListp;
2156 smb_ncbFreeListp = tbp;
2157 lock_ReleaseWrite(&smb_globalLock);
2160 /* get a ptr to the data part of a packet, and its count */
2161 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2165 unsigned char *afterParmsp;
2167 parmBytes = *smbp->wctp << 1;
2168 afterParmsp = smbp->wctp + parmBytes + 1;
2170 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2171 if (nbytesp) *nbytesp = dataBytes;
2173 /* don't forget to skip the data byte count, since it follows
2174 * the parameters; that's where the "2" comes from below.
2176 return (unsigned char *) (afterParmsp + 2);
2179 /* must set all the returned parameters before playing around with the
2180 * data region, since the data region is located past the end of the
2181 * variable number of parameters.
2183 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2185 unsigned char *afterParmsp;
2187 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2189 *afterParmsp++ = dsize & 0xff;
2190 *afterParmsp = (dsize>>8) & 0xff;
2193 /* return the parm'th parameter in the smbp packet */
2194 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2197 unsigned char *parmDatap;
2199 parmCount = *smbp->wctp;
2201 if (parm >= parmCount) {
2204 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2205 parm, parmCount, smbp->ncb_length);
2206 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2207 parm, parmCount, smbp->ncb_length);
2208 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2209 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2210 osi_panic(s, __FILE__, __LINE__);
2212 parmDatap = smbp->wctp + (2*parm) + 1;
2214 return parmDatap[0] + (parmDatap[1] << 8);
2217 /* return the parm'th parameter in the smbp packet */
2218 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2221 unsigned char *parmDatap;
2223 parmCount = *smbp->wctp;
2225 if (parm >= parmCount) {
2228 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2229 parm, parmCount, smbp->ncb_length);
2230 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2231 parm, parmCount, smbp->ncb_length);
2232 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2233 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2234 osi_panic(s, __FILE__, __LINE__);
2236 parmDatap = smbp->wctp + (2*parm) + 1;
2238 return parmDatap[0];
2241 /* return the parm'th parameter in the smbp packet */
2242 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2245 unsigned char *parmDatap;
2247 parmCount = *smbp->wctp;
2249 if (parm + 1 >= parmCount) {
2252 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2253 parm, parmCount, smbp->ncb_length);
2254 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2255 parm, parmCount, smbp->ncb_length);
2256 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2257 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2258 osi_panic(s, __FILE__, __LINE__);
2260 parmDatap = smbp->wctp + (2*parm) + 1;
2262 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2265 /* return the parm'th parameter in the smbp packet */
2266 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2269 unsigned char *parmDatap;
2271 parmCount = *smbp->wctp;
2273 if (parm * 2 + offset >= parmCount * 2) {
2276 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2277 parm, offset, parmCount, smbp->ncb_length);
2278 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2279 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2280 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2281 parm, offset, parmCount, smbp->ncb_length);
2282 osi_panic(s, __FILE__, __LINE__);
2284 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2286 return parmDatap[0] + (parmDatap[1] << 8);
2289 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2293 /* make sure we have enough slots */
2294 if (*smbp->wctp <= slot)
2295 *smbp->wctp = slot+1;
2297 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2298 *parmDatap++ = parmValue & 0xff;
2299 *parmDatap = (parmValue>>8) & 0xff;
2302 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2306 /* make sure we have enough slots */
2307 if (*smbp->wctp <= slot)
2308 *smbp->wctp = slot+2;
2310 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2311 *parmDatap++ = parmValue & 0xff;
2312 *parmDatap++ = (parmValue>>8) & 0xff;
2313 *parmDatap++ = (parmValue>>16) & 0xff;
2314 *parmDatap = (parmValue>>24) & 0xff;
2317 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2322 /* make sure we have enough slots */
2323 if (*smbp->wctp <= slot)
2324 *smbp->wctp = slot+4;
2326 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2328 *parmDatap++ = *parmValuep++;
2331 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2335 /* make sure we have enough slots */
2336 if (*smbp->wctp <= slot) {
2337 if (smbp->oddByte) {
2339 *smbp->wctp = slot+1;
2344 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2345 *parmDatap++ = parmValue & 0xff;
2348 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2352 lastSlashp = strrchr(inPathp, '\\');
2354 *lastComponentp = lastSlashp;
2357 if (inPathp == lastSlashp)
2359 *outPathp++ = *inPathp++;
2368 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2373 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2378 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2384 tlen = inp[0] + (inp[1]<<8);
2385 inp += 2; /* skip length field */
2388 *chainpp = inp + tlen;
2397 /* format a packet as a response */
2398 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2403 outp = (smb_t *) op;
2405 /* zero the basic structure through the smb_wct field, and zero the data
2406 * size field, assuming that wct stays zero; otherwise, you have to
2407 * explicitly set the data size field, too.
2409 inSmbp = (smb_t *) inp;
2410 memset(outp, 0, sizeof(smb_t)+2);
2416 outp->com = inSmbp->com;
2417 outp->tid = inSmbp->tid;
2418 outp->pid = inSmbp->pid;
2419 outp->uid = inSmbp->uid;
2420 outp->mid = inSmbp->mid;
2421 outp->res[0] = inSmbp->res[0];
2422 outp->res[1] = inSmbp->res[1];
2423 op->inCom = inSmbp->com;
2425 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2426 #ifdef SEND_CANONICAL_PATHNAMES
2427 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2429 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2431 /* copy fields in generic packet area */
2432 op->wctp = &outp->wct;
2435 /* send a (probably response) packet; vcp tells us to whom to send it.
2436 * we compute the length by looking at wct and bcc fields.
2438 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2452 memset((char *)ncbp, 0, sizeof(NCB));
2454 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2455 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2456 extra += tp[0] + (tp[1]<<8);
2457 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2458 extra += 3; /* wct and length fields */
2460 ncbp->ncb_length = extra; /* bytes to send */
2461 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2462 ncbp->ncb_lana_num = vcp->lana;
2463 ncbp->ncb_command = NCBSEND; /* op means send data */
2464 ncbp->ncb_buffer = (char *) inp;/* packet */
2465 code = Netbios(ncbp);
2468 const char * s = ncb_error_string(code);
2469 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2470 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2472 lock_ObtainMutex(&vcp->mx);
2473 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2474 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2476 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2477 lock_ReleaseMutex(&vcp->mx);
2478 lock_ObtainWrite(&smb_globalLock);
2479 dead_sessions[vcp->session] = TRUE;
2480 lock_ReleaseWrite(&smb_globalLock);
2481 smb_CleanupDeadVC(vcp);
2483 lock_ReleaseMutex(&vcp->mx);
2491 void smb_MapNTError(long code, unsigned long *NTStatusp)
2493 unsigned long NTStatus;
2495 /* map CM_ERROR_* errors to NT 32-bit status codes */
2496 /* NT Status codes are listed in ntstatus.h not winerror.h */
2497 if (code == CM_ERROR_NOSUCHCELL) {
2498 NTStatus = 0xC000000FL; /* No such file */
2500 else if (code == CM_ERROR_NOSUCHVOLUME) {
2501 NTStatus = 0xC000000FL; /* No such file */
2503 else if (code == CM_ERROR_TIMEDOUT) {
2505 NTStatus = 0xC00000CFL; /* Sharing Paused */
2507 NTStatus = 0x00000102L; /* Timeout */
2510 else if (code == CM_ERROR_RETRY) {
2511 NTStatus = 0xC000022DL; /* Retry */
2513 else if (code == CM_ERROR_NOACCESS) {
2514 NTStatus = 0xC0000022L; /* Access denied */
2516 else if (code == CM_ERROR_READONLY) {
2517 NTStatus = 0xC00000A2L; /* Write protected */
2519 else if (code == CM_ERROR_NOSUCHFILE ||
2520 code == CM_ERROR_BPLUS_NOMATCH) {
2521 NTStatus = 0xC000000FL; /* No such file */
2523 else if (code == CM_ERROR_NOSUCHPATH) {
2524 NTStatus = 0xC000003AL; /* Object path not found */
2526 else if (code == CM_ERROR_TOOBIG) {
2527 NTStatus = 0xC000007BL; /* Invalid image format */
2529 else if (code == CM_ERROR_INVAL) {
2530 NTStatus = 0xC000000DL; /* Invalid parameter */
2532 else if (code == CM_ERROR_BADFD) {
2533 NTStatus = 0xC0000008L; /* Invalid handle */
2535 else if (code == CM_ERROR_BADFDOP) {
2536 NTStatus = 0xC0000022L; /* Access denied */
2538 else if (code == CM_ERROR_EXISTS) {
2539 NTStatus = 0xC0000035L; /* Object name collision */
2541 else if (code == CM_ERROR_NOTEMPTY) {
2542 NTStatus = 0xC0000101L; /* Directory not empty */
2544 else if (code == CM_ERROR_CROSSDEVLINK) {
2545 NTStatus = 0xC00000D4L; /* Not same device */
2547 else if (code == CM_ERROR_NOTDIR) {
2548 NTStatus = 0xC0000103L; /* Not a directory */
2550 else if (code == CM_ERROR_ISDIR) {
2551 NTStatus = 0xC00000BAL; /* File is a directory */
2553 else if (code == CM_ERROR_BADOP) {
2555 /* I have no idea where this comes from */
2556 NTStatus = 0xC09820FFL; /* SMB no support */
2558 NTStatus = 0xC00000BBL; /* Not supported */
2559 #endif /* COMMENT */
2561 else if (code == CM_ERROR_BADSHARENAME) {
2562 NTStatus = 0xC00000CCL; /* Bad network name */
2564 else if (code == CM_ERROR_NOIPC) {
2566 NTStatus = 0xC0000022L; /* Access Denied */
2568 NTStatus = 0xC000013DL; /* Remote Resources */
2571 else if (code == CM_ERROR_CLOCKSKEW) {
2572 NTStatus = 0xC0000133L; /* Time difference at DC */
2574 else if (code == CM_ERROR_BADTID) {
2575 NTStatus = 0xC0982005L; /* SMB bad TID */
2577 else if (code == CM_ERROR_USESTD) {
2578 NTStatus = 0xC09820FBL; /* SMB use standard */
2580 else if (code == CM_ERROR_QUOTA) {
2581 NTStatus = 0xC0000044L; /* Quota exceeded */
2583 else if (code == CM_ERROR_SPACE) {
2584 NTStatus = 0xC000007FL; /* Disk full */
2586 else if (code == CM_ERROR_ATSYS) {
2587 NTStatus = 0xC0000033L; /* Object name invalid */
2589 else if (code == CM_ERROR_BADNTFILENAME) {
2590 NTStatus = 0xC0000033L; /* Object name invalid */
2592 else if (code == CM_ERROR_WOULDBLOCK) {
2593 NTStatus = 0xC0000055L; /* Lock not granted */
2595 else if (code == CM_ERROR_SHARING_VIOLATION) {
2596 NTStatus = 0xC0000043L; /* Sharing violation */
2598 else if (code == CM_ERROR_LOCK_CONFLICT) {
2599 NTStatus = 0xC0000054L; /* Lock conflict */
2601 else if (code == CM_ERROR_PARTIALWRITE) {
2602 NTStatus = 0xC000007FL; /* Disk full */
2604 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2605 NTStatus = 0xC0000023L; /* Buffer too small */
2607 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2608 NTStatus = 0xC0000035L; /* Object name collision */
2610 else if (code == CM_ERROR_BADPASSWORD) {
2611 NTStatus = 0xC000006DL; /* unknown username or bad password */
2613 else if (code == CM_ERROR_BADLOGONTYPE) {
2614 NTStatus = 0xC000015BL; /* logon type not granted */
2616 else if (code == CM_ERROR_GSSCONTINUE) {
2617 NTStatus = 0xC0000016L; /* more processing required */
2619 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2621 NTStatus = 0xC0000280L; /* reparse point not resolved */
2623 NTStatus = 0xC0000022L; /* Access Denied */
2626 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2627 NTStatus = 0xC0000257L; /* Path Not Covered */
2629 else if (code == CM_ERROR_ALLBUSY) {
2630 NTStatus = 0xC000022DL; /* Retry */
2632 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2633 NTStatus = 0xC00000BEL; /* Bad Network Path */
2635 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
2636 NTStatus = 0xC0000322L; /* No Kerberos key */
2638 else if (code == CM_ERROR_BAD_LEVEL) {
2639 NTStatus = 0xC0000148L; /* Invalid Level */
2641 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
2642 NTStatus = 0xC000007EL; /* Range Not Locked */
2644 else if (code == CM_ERROR_NOSUCHDEVICE) {
2645 NTStatus = 0xC000000EL; /* No Such Device */
2647 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
2648 NTStatus = 0xC0000055L; /* Lock Not Granted */
2650 NTStatus = 0xC0982001L; /* SMB non-specific error */
2653 *NTStatusp = NTStatus;
2654 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2657 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2658 unsigned char *classp)
2660 unsigned char class;
2661 unsigned short error;
2663 /* map CM_ERROR_* errors to SMB errors */
2664 if (code == CM_ERROR_NOSUCHCELL) {
2666 error = 3; /* bad path */
2668 else if (code == CM_ERROR_NOSUCHVOLUME) {
2670 error = 3; /* bad path */
2672 else if (code == CM_ERROR_TIMEDOUT) {
2674 error = 81; /* server is paused */
2676 else if (code == CM_ERROR_RETRY) {
2677 class = 2; /* shouldn't happen */
2680 else if (code == CM_ERROR_NOACCESS) {
2682 error = 4; /* bad access */
2684 else if (code == CM_ERROR_READONLY) {
2686 error = 19; /* read only */
2688 else if (code == CM_ERROR_NOSUCHFILE ||
2689 code == CM_ERROR_BPLUS_NOMATCH) {
2691 error = 2; /* ENOENT! */
2693 else if (code == CM_ERROR_NOSUCHPATH) {
2695 error = 3; /* Bad path */
2697 else if (code == CM_ERROR_TOOBIG) {
2699 error = 11; /* bad format */
2701 else if (code == CM_ERROR_INVAL) {
2702 class = 2; /* server non-specific error code */
2705 else if (code == CM_ERROR_BADFD) {
2707 error = 6; /* invalid file handle */
2709 else if (code == CM_ERROR_BADFDOP) {
2710 class = 1; /* invalid op on FD */
2713 else if (code == CM_ERROR_EXISTS) {
2715 error = 80; /* file already exists */
2717 else if (code == CM_ERROR_NOTEMPTY) {
2719 error = 5; /* delete directory not empty */
2721 else if (code == CM_ERROR_CROSSDEVLINK) {
2723 error = 17; /* EXDEV */
2725 else if (code == CM_ERROR_NOTDIR) {
2726 class = 1; /* bad path */
2729 else if (code == CM_ERROR_ISDIR) {
2730 class = 1; /* access denied; DOS doesn't have a good match */
2733 else if (code == CM_ERROR_BADOP) {
2737 else if (code == CM_ERROR_BADSHARENAME) {
2741 else if (code == CM_ERROR_NOIPC) {
2743 error = 4; /* bad access */
2745 else if (code == CM_ERROR_CLOCKSKEW) {
2746 class = 1; /* invalid function */
2749 else if (code == CM_ERROR_BADTID) {
2753 else if (code == CM_ERROR_USESTD) {
2757 else if (code == CM_ERROR_REMOTECONN) {
2761 else if (code == CM_ERROR_QUOTA) {
2762 if (vcp->flags & SMB_VCFLAG_USEV3) {
2764 error = 39; /* disk full */
2768 error = 5; /* access denied */
2771 else if (code == CM_ERROR_SPACE) {
2772 if (vcp->flags & SMB_VCFLAG_USEV3) {
2774 error = 39; /* disk full */
2778 error = 5; /* access denied */
2781 else if (code == CM_ERROR_PARTIALWRITE) {
2783 error = 39; /* disk full */
2785 else if (code == CM_ERROR_ATSYS) {
2787 error = 2; /* ENOENT */
2789 else if (code == CM_ERROR_WOULDBLOCK) {
2791 error = 33; /* lock conflict */
2793 else if (code == CM_ERROR_LOCK_CONFLICT) {
2795 error = 33; /* lock conflict */
2797 else if (code == CM_ERROR_SHARING_VIOLATION) {
2799 error = 33; /* lock conflict */
2801 else if (code == CM_ERROR_NOFILES) {
2803 error = 18; /* no files in search */
2805 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2807 error = 183; /* Samba uses this */
2809 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2810 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2812 error = 2; /* bad password */
2814 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2816 error = 3; /* bad path */
2825 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2828 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2830 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2831 return CM_ERROR_BADOP;
2834 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2836 unsigned short EchoCount, i;
2837 char *data, *outdata;
2840 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2842 for (i=1; i<=EchoCount; i++) {
2843 data = smb_GetSMBData(inp, &dataSize);
2844 smb_SetSMBParm(outp, 0, i);
2845 smb_SetSMBDataLength(outp, dataSize);
2846 outdata = smb_GetSMBData(outp, NULL);
2847 memcpy(outdata, data, dataSize);
2848 smb_SendPacket(vcp, outp);
2854 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2857 long count, minCount, finalCount;
2862 cm_user_t *userp = NULL;
2865 char *rawBuf = NULL;
2870 fd = smb_GetSMBParm(inp, 0);
2871 count = smb_GetSMBParm(inp, 3);
2872 minCount = smb_GetSMBParm(inp, 4);
2873 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2875 if (*inp->wctp == 10) {
2876 /* we were sent a request with 64-bit file offsets */
2877 #ifdef AFS_LARGEFILES
2878 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2880 if (LargeIntegerLessThanZero(offset)) {
2881 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2885 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2886 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2889 offset.HighPart = 0;
2893 /* we were sent a request with 32-bit file offsets */
2894 offset.HighPart = 0;
2897 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2898 fd, offset.HighPart, offset.LowPart, count);
2900 fidp = smb_FindFID(vcp, fd, 0);
2904 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
2905 smb_CloseFID(vcp, fidp, NULL, 0);
2906 code = CM_ERROR_NOSUCHFILE;
2911 pid = ((smb_t *) inp)->pid;
2913 LARGE_INTEGER LOffset, LLength;
2916 key = cm_GenerateKey(vcp->vcID, pid, fd);
2918 LOffset.HighPart = offset.HighPart;
2919 LOffset.LowPart = offset.LowPart;
2920 LLength.HighPart = 0;
2921 LLength.LowPart = count;
2923 lock_ObtainMutex(&fidp->scp->mx);
2924 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2925 lock_ReleaseMutex(&fidp->scp->mx);
2931 lock_ObtainMutex(&smb_RawBufLock);
2933 /* Get a raw buf, from head of list */
2934 rawBuf = smb_RawBufs;
2935 smb_RawBufs = *(char **)smb_RawBufs;
2937 lock_ReleaseMutex(&smb_RawBufLock);
2941 lock_ObtainMutex(&fidp->mx);
2942 if (fidp->flags & SMB_FID_IOCTL)
2944 lock_ReleaseMutex(&fidp->mx);
2945 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2947 /* Give back raw buffer */
2948 lock_ObtainMutex(&smb_RawBufLock);
2949 *((char **) rawBuf) = smb_RawBufs;
2951 smb_RawBufs = rawBuf;
2952 lock_ReleaseMutex(&smb_RawBufLock);
2955 lock_ReleaseMutex(&fidp->mx);
2956 smb_ReleaseFID(fidp);
2959 lock_ReleaseMutex(&fidp->mx);
2961 userp = smb_GetUserFromVCP(vcp, inp);
2963 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2969 cm_ReleaseUser(userp);
2972 smb_ReleaseFID(fidp);
2976 memset((char *)ncbp, 0, sizeof(NCB));
2978 ncbp->ncb_length = (unsigned short) finalCount;
2979 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2980 ncbp->ncb_lana_num = vcp->lana;
2981 ncbp->ncb_command = NCBSEND;
2982 ncbp->ncb_buffer = rawBuf;
2984 code = Netbios(ncbp);
2986 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2989 /* Give back raw buffer */
2990 lock_ObtainMutex(&smb_RawBufLock);
2991 *((char **) rawBuf) = smb_RawBufs;
2993 smb_RawBufs = rawBuf;
2994 lock_ReleaseMutex(&smb_RawBufLock);
3000 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3002 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3007 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3009 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3014 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3021 int VistaProtoIndex;
3022 int protoIndex; /* index we're using */
3027 char protocol_array[10][1024]; /* protocol signature of the client */
3028 int caps; /* capabilities */
3031 TIME_ZONE_INFORMATION tzi;
3033 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3036 namep = smb_GetSMBData(inp, &dbytes);
3039 coreProtoIndex = -1; /* not found */
3042 VistaProtoIndex = -1;
3043 while(namex < dbytes) {
3044 osi_Log1(smb_logp, "Protocol %s",
3045 osi_LogSaveString(smb_logp, namep+1));
3046 strcpy(protocol_array[tcounter], namep+1);
3048 /* namep points at the first protocol, or really, a 0x02
3049 * byte preceding the null-terminated ASCII name.
3051 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3052 coreProtoIndex = tcounter;
3054 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3055 v3ProtoIndex = tcounter;
3057 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3058 NTProtoIndex = tcounter;
3060 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3061 VistaProtoIndex = tcounter;
3064 /* compute size of protocol entry */
3065 entryLength = (int)strlen(namep+1);
3066 entryLength += 2; /* 0x02 bytes and null termination */
3068 /* advance over this protocol entry */
3069 namex += entryLength;
3070 namep += entryLength;
3071 tcounter++; /* which proto entry we're looking at */
3074 lock_ObtainMutex(&vcp->mx);
3076 if (VistaProtoIndex != -1) {
3077 protoIndex = VistaProtoIndex;
3078 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3081 if (NTProtoIndex != -1) {
3082 protoIndex = NTProtoIndex;
3083 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3085 else if (v3ProtoIndex != -1) {
3086 protoIndex = v3ProtoIndex;
3087 vcp->flags |= SMB_VCFLAG_USEV3;
3089 else if (coreProtoIndex != -1) {
3090 protoIndex = coreProtoIndex;
3091 vcp->flags |= SMB_VCFLAG_USECORE;
3093 else protoIndex = -1;
3094 lock_ReleaseMutex(&vcp->mx);
3096 if (protoIndex == -1)
3097 return CM_ERROR_INVAL;
3098 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3099 smb_SetSMBParm(outp, 0, protoIndex);
3100 if (smb_authType != SMB_AUTH_NONE) {
3101 smb_SetSMBParmByte(outp, 1,
3102 NEGOTIATE_SECURITY_USER_LEVEL |
3103 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3105 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3107 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3108 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3109 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3110 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3111 /* The session key is not a well documented field however most clients
3112 * will echo back the session key to the server. Currently we are using
3113 * the same value for all sessions. We should generate a random value
3114 * and store it into the vcp
3116 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3117 smb_SetSMBParm(outp, 8, 1);
3119 * Tried changing the capabilities to support for W2K - defect 117695
3120 * Maybe something else needs to be changed here?
3124 smb_SetSMBParmLong(outp, 9, 0x43fd);
3126 smb_SetSMBParmLong(outp, 9, 0x251);
3129 * 32-bit error codes *
3134 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3136 NTNEGOTIATE_CAPABILITY_DFS |
3138 #ifdef AFS_LARGEFILES
3139 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3141 NTNEGOTIATE_CAPABILITY_NTFIND |
3142 NTNEGOTIATE_CAPABILITY_RAWMODE |
3143 NTNEGOTIATE_CAPABILITY_NTSMB;
3145 if ( smb_authType == SMB_AUTH_EXTENDED )
3146 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3148 smb_SetSMBParmLong(outp, 9, caps);
3150 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3151 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3152 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3154 GetTimeZoneInformation(&tzi);
3155 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3157 if (smb_authType == SMB_AUTH_NTLM) {
3158 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3159 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3160 /* paste in encryption key */
3161 datap = smb_GetSMBData(outp, NULL);
3162 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3163 /* and the faux domain name */
3164 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3165 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3169 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3171 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3173 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3175 datap = smb_GetSMBData(outp, NULL);
3176 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3179 datap += sizeof(smb_ServerGUID);
3180 memcpy(datap, secBlob, secBlobLength);
3184 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3185 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3188 else if (v3ProtoIndex != -1) {
3189 smb_SetSMBParm(outp, 0, protoIndex);
3191 /* NOTE: Extended authentication cannot be negotiated with v3
3192 * therefore we fail over to NTLM
3194 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3195 smb_SetSMBParm(outp, 1,
3196 NEGOTIATE_SECURITY_USER_LEVEL |
3197 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3199 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3201 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3202 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3203 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3204 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3205 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3206 smb_SetSMBParm(outp, 7, 1);
3208 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3209 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3210 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3212 GetTimeZoneInformation(&tzi);
3213 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3215 /* NOTE: Extended authentication cannot be negotiated with v3
3216 * therefore we fail over to NTLM
3218 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3219 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3220 smb_SetSMBParm(outp, 12, 0); /* resvd */
3221 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3222 datap = smb_GetSMBData(outp, NULL);
3223 /* paste in a new encryption key */
3224 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3225 /* and the faux domain name */
3226 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3228 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3229 smb_SetSMBParm(outp, 12, 0); /* resvd */
3230 smb_SetSMBDataLength(outp, 0);
3233 else if (coreProtoIndex != -1) { /* not really supported anymore */
3234 smb_SetSMBParm(outp, 0, protoIndex);
3235 smb_SetSMBDataLength(outp, 0);
3240 void smb_CheckVCs(void)
3242 smb_vc_t * vcp, *nextp;
3243 smb_packet_t * outp = GetPacket();
3246 lock_ObtainWrite(&smb_rctLock);
3247 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3249 if (vcp->magic != SMB_VC_MAGIC)
3250 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3251 __FILE__, __LINE__);
3255 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3258 smb_HoldVCNoLock(vcp);
3260 smb_HoldVCNoLock(nextp);
3261 smb_FormatResponsePacket(vcp, NULL, outp);
3262 smbp = (smb_t *)outp;
3263 outp->inCom = smbp->com = 0x2b /* Echo */;
3271 smb_SetSMBParm(outp, 0, 0);
3272 smb_SetSMBDataLength(outp, 0);
3273 lock_ReleaseWrite(&smb_rctLock);
3275 smb_SendPacket(vcp, outp);
3277 lock_ObtainWrite(&smb_rctLock);
3278 smb_ReleaseVCNoLock(vcp);
3280 smb_ReleaseVCNoLock(nextp);
3282 lock_ReleaseWrite(&smb_rctLock);
3283 smb_FreePacket(outp);
3286 void smb_Daemon(void *parmp)
3288 afs_uint32 count = 0;
3289 smb_username_t **unpp;
3292 while(smbShutdownFlag == 0) {
3296 if (smbShutdownFlag == 1)
3299 if ((count % 72) == 0) { /* every five minutes */
3301 time_t old_localZero = smb_localZero;
3303 /* Initialize smb_localZero */
3304 myTime.tm_isdst = -1; /* compute whether on DST or not */
3305 myTime.tm_year = 70;
3311 smb_localZero = mktime(&myTime);
3313 #ifndef USE_NUMERIC_TIME_CONV
3314 smb_CalculateNowTZ();
3315 #endif /* USE_NUMERIC_TIME_CONV */
3316 #ifdef AFS_FREELANCE
3317 if ( smb_localZero != old_localZero )
3318 cm_noteLocalMountPointChange();
3324 /* GC smb_username_t objects that will no longer be used */
3326 lock_ObtainWrite(&smb_rctLock);
3327 for ( unpp=&usernamesp; *unpp; ) {
3329 smb_username_t *unp;
3331 lock_ObtainMutex(&(*unpp)->mx);
3332 if ( (*unpp)->refCount > 0 ||
3333 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3334 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3336 else if (!smb_LogoffTokenTransfer ||
3337 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3339 lock_ReleaseMutex(&(*unpp)->mx);
3347 lock_FinalizeMutex(&unp->mx);
3353 cm_ReleaseUser(userp);
3355 unpp = &(*unpp)->nextp;
3358 lock_ReleaseWrite(&smb_rctLock);
3360 /* XXX GC dir search entries */
3364 void smb_WaitingLocksDaemon()
3366 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3367 smb_waitingLock_t *wl, *wlNext;
3370 smb_packet_t *inp, *outp;
3374 while (smbShutdownFlag == 0) {
3375 lock_ObtainWrite(&smb_globalLock);
3376 nwlRequest = smb_allWaitingLocks;
3377 if (nwlRequest == NULL) {
3378 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3383 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3390 lock_ObtainWrite(&smb_globalLock);
3392 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3394 wlRequest = nwlRequest;
3395 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3396 lock_ReleaseWrite(&smb_globalLock);
3400 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3401 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3404 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3405 code = CM_ERROR_LOCK_NOT_GRANTED;
3409 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3411 /* wl->state is either _DONE or _WAITING. _ERROR
3412 would no longer be on the queue. */
3413 code = cm_RetryLock( wl->lockp,
3414 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3417 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3418 } else if (code != CM_ERROR_WOULDBLOCK) {
3419 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3424 if (code == CM_ERROR_WOULDBLOCK) {
3427 if (wlRequest->msTimeout != 0xffffffff
3428 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3440 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3443 scp = wlRequest->scp;
3444 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3448 lock_ObtainMutex(&scp->mx);
3450 for (wl = wlRequest->locks; wl; wl = wlNext) {
3451 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3453 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3454 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3455 wl->LLength, wl->key, NULL, &req);
3457 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3462 lock_ReleaseMutex(&scp->mx);
3466 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3469 for (wl = wlRequest->locks; wl; wl = wlNext) {
3470 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3471 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3476 vcp = wlRequest->vcp;
3477 inp = wlRequest->inp;
3478 outp = wlRequest->outp;
3480 ncbp->ncb_length = inp->ncb_length;
3481 inp->spacep = cm_GetSpace();
3483 /* Remove waitingLock from list */
3484 lock_ObtainWrite(&smb_globalLock);
3485 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3487 lock_ReleaseWrite(&smb_globalLock);
3489 /* Resume packet processing */
3491 smb_SetSMBDataLength(outp, 0);
3492 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3493 outp->resumeCode = code;
3495 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3498 cm_FreeSpace(inp->spacep);
3499 smb_FreePacket(inp);
3500 smb_FreePacket(outp);
3502 cm_ReleaseSCache(wlRequest->scp);
3505 } while (nwlRequest && smbShutdownFlag == 0);
3510 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3512 osi_Log0(smb_logp, "SMB receive get disk attributes");
3514 smb_SetSMBParm(outp, 0, 32000);
3515 smb_SetSMBParm(outp, 1, 64);
3516 smb_SetSMBParm(outp, 2, 1024);
3517 smb_SetSMBParm(outp, 3, 30000);
3518 smb_SetSMBParm(outp, 4, 0);
3519 smb_SetSMBDataLength(outp, 0);
3523 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3527 unsigned short newTid;
3528 char shareName[AFSPATHMAX];
3536 osi_Log0(smb_logp, "SMB receive tree connect");
3538 /* parse input parameters */
3539 tp = smb_GetSMBData(inp, NULL);
3540 pathp = smb_ParseASCIIBlock(tp, &tp);
3541 if (smb_StoreAnsiFilenames)
3542 OemToChar(pathp,pathp);
3543 passwordp = smb_ParseASCIIBlock(tp, &tp);
3544 tp = strrchr(pathp, '\\');
3546 return CM_ERROR_BADSMB;
3547 strcpy(shareName, tp+1);
3549 lock_ObtainMutex(&vcp->mx);
3550 newTid = vcp->tidCounter++;
3551 lock_ReleaseMutex(&vcp->mx);
3553 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3554 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3555 userp = smb_GetUserFromUID(uidp);
3556 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3558 smb_ReleaseUID(uidp);
3560 smb_ReleaseTID(tidp, FALSE);
3561 return CM_ERROR_BADSHARENAME;
3563 lock_ObtainMutex(&tidp->mx);
3564 tidp->userp = userp;
3565 tidp->pathname = sharePath;
3566 lock_ReleaseMutex(&tidp->mx);
3567 smb_ReleaseTID(tidp, FALSE);
3569 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3570 smb_SetSMBParm(rsp, 1, newTid);
3571 smb_SetSMBDataLength(rsp, 0);
3573 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3577 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3581 if (*inp++ != 0x1) return NULL;
3582 tlen = inp[0] + (inp[1]<<8);
3583 inp += 2; /* skip length field */
3586 *chainpp = inp + tlen;
3589 if (lengthp) *lengthp = tlen;
3594 /* set maskp to the mask part of the incoming path.
3595 * Mask is 11 bytes long (8.3 with the dot elided).
3596 * Returns true if succeeds with a valid name, otherwise it does
3597 * its best, but returns false.
3599 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3607 /* starts off valid */
3610 /* mask starts out all blanks */
3611 memset(maskp, ' ', 11);
3614 /* find last backslash, or use whole thing if there is none */
3615 tp = strrchr(pathp, '\\');
3619 tp++; /* skip slash */
3623 /* names starting with a dot are illegal */
3631 if (tc == '.' || tc == '"')
3639 /* if we get here, tp point after the dot */
3640 up = maskp+8; /* ext goes here */
3647 if (tc == '.' || tc == '"')
3650 /* copy extension if not too long */
3660 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3670 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3672 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3676 /* otherwise, we have a valid 8.3 name; see if we have a match,
3677 * treating '?' as a wildcard in maskp (but not in the file name).
3679 tp1 = umask; /* real name, in mask format */
3680 tp2 = maskp; /* mask, in mask format */
3681 for(i=0; i<11; i++) {
3682 tc1 = *tp1++; /* char from real name */
3683 tc2 = *tp2++; /* char from mask */
3684 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3685 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3688 if (tc2 == '?' && tc1 != ' ')
3695 /* we got a match */
3699 char *smb_FindMask(char *pathp)
3703 tp = strrchr(pathp, '\\'); /* find last slash */
3706 return tp+1; /* skip the slash */
3708 return pathp; /* no slash, return the entire path */
3711 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3713 unsigned char *pathp;
3715 unsigned char mask[12];
3716 unsigned char *statBlockp;
3717 unsigned char initStatBlock[21];
3720 osi_Log0(smb_logp, "SMB receive search volume");
3722 /* pull pathname and stat block out of request */
3723 tp = smb_GetSMBData(inp, NULL);
3724 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3725 osi_assertx(pathp != NULL, "null path");
3726 if (smb_StoreAnsiFilenames)
3727 OemToChar(pathp,pathp);
3728 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3729 osi_assertx(statBlockp != NULL, "null statBlock");
3731 statBlockp = initStatBlock;
3735 /* for returning to caller */
3736 smb_Get8Dot3MaskFromPath(mask, pathp);
3738 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3739 tp = smb_GetSMBData(outp, NULL);
3741 *tp++ = 43; /* bytes in a dir entry */
3742 *tp++ = 0; /* high byte in counter */
3744 /* now marshall the dir entry, starting with the search status */
3745 *tp++ = statBlockp[0]; /* Reserved */
3746 memcpy(tp, mask, 11); tp += 11; /* FileName */
3748 /* now pass back server use info, with 1st byte non-zero */
3750 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3752 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3754 *tp++ = 0x8; /* attribute: volume */
3764 /* 4 byte file size */
3770 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3771 memset(tp, ' ', 13);
3774 /* set the length of the data part of the packet to 43 + 3, for the dir
3775 * entry plus the 5 and the length fields.
3777 smb_SetSMBDataLength(outp, 46);
3782 smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3783 char * tidPathp, char * relPathp,
3784 cm_user_t *userp, cm_req_t *reqp)
3792 smb_dirListPatch_t *patchp;
3793 smb_dirListPatch_t *npatchp;
3794 char path[AFSPATHMAX];
3796 for (patchp = *dirPatchespp; patchp; patchp =
3797 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3799 dptr = patchp->dptr;
3801 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
3802 reqp->relPathp = path;
3803 reqp->tidPathp = tidPathp;
3805 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3806 reqp->relPathp = reqp->tidPathp = NULL;
3809 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3810 *dptr++ = SMB_ATTR_HIDDEN;
3813 lock_ObtainMutex(&scp->mx);
3814 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3815 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3817 lock_ReleaseMutex(&scp->mx);
3818 cm_ReleaseSCache(scp);
3819 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3820 *dptr++ = SMB_ATTR_HIDDEN;
3824 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3826 attr = smb_Attributes(scp);
3827 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3828 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3829 attr |= SMB_ATTR_HIDDEN;
3833 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3836 shortTemp = (unsigned short) (dosTime & 0xffff);
3837 *((u_short *)dptr) = shortTemp;
3840 /* and copy out date */
3841 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3842 *((u_short *)dptr) = shortTemp;
3845 /* copy out file length */
3846 *((u_long *)dptr) = scp->length.LowPart;
3848 lock_ReleaseMutex(&scp->mx);
3849 cm_ReleaseSCache(scp);
3852 /* now free the patches */
3853 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3854 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3858 /* and mark the list as empty */
3859 *dirPatchespp = NULL;
3864 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3871 cm_dirEntry_t *dep = 0;
3873 smb_dirListPatch_t *dirListPatchesp;
3874 smb_dirListPatch_t *curPatchp;
3878 osi_hyper_t dirLength;
3879 osi_hyper_t bufferOffset;
3880 osi_hyper_t curOffset;
3882 unsigned char *inCookiep;
3883 smb_dirSearch_t *dsp;
3887 unsigned long clientCookie;
3888 cm_pageHeader_t *pageHeaderp;
3889 cm_user_t *userp = NULL;
3896 long nextEntryCookie;
3897 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3898 char resByte; /* reserved byte from the cookie */
3899 char *op; /* output data ptr */
3900 char *origOp; /* original value of op */
3901 cm_space_t *spacep; /* for pathname buffer */
3912 maxCount = smb_GetSMBParm(inp, 0);
3914 dirListPatchesp = NULL;
3916 caseFold = CM_FLAG_CASEFOLD;
3918 tp = smb_GetSMBData(inp, NULL);
3919 pathp = smb_ParseASCIIBlock(tp, &tp);
3920 if (smb_StoreAnsiFilenames)
3921 OemToChar(pathp,pathp);
3922 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3924 /* bail out if request looks bad */
3925 if (!tp || !pathp) {
3926 return CM_ERROR_BADSMB;
3929 /* We can handle long names */
3930 if (vcp->flags & SMB_VCFLAG_USENT)
3931 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3933 /* make sure we got a whole search status */
3934 if (dataLength < 21) {
3935 nextCookie = 0; /* start at the beginning of the dir */
3938 attribute = smb_GetSMBParm(inp, 1);
3940 /* handle volume info in another function */
3941 if (attribute & 0x8)
3942 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3944 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3945 maxCount, osi_LogSaveString(smb_logp, pathp));
3947 if (*pathp == 0) { /* null pathp, treat as root dir */
3948 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3949 return CM_ERROR_NOFILES;
3953 dsp = smb_NewDirSearch(0);
3954 dsp->attribute = attribute;
3955 smb_Get8Dot3MaskFromPath(mask, pathp);
3956 memcpy(dsp->mask, mask, 12);
3958 /* track if this is likely to match a lot of entries */
3959 if (smb_IsStarMask(mask))
3964 /* pull the next cookie value out of the search status block */
3965 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3966 + (inCookiep[16]<<24);
3967 dsp = smb_FindDirSearch(inCookiep[12]);
3969 /* can't find dir search status; fatal error */
3970 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3971 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3972 return CM_ERROR_BADFD;
3974 attribute = dsp->attribute;
3975 resByte = inCookiep[0];
3977 /* copy out client cookie, in host byte order. Don't bother
3978 * interpreting it, since we're just passing it through, anyway.
3980 memcpy(&clientCookie, &inCookiep[17], 4);
3982 memcpy(mask, dsp->mask, 12);
3984 /* assume we're doing a star match if it has continued for more
3990 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3991 nextCookie, dsp->cookie, attribute);
3993 userp = smb_GetUserFromVCP(vcp, inp);
3995 /* try to get the vnode for the path name next */
3996 lock_ObtainMutex(&dsp->mx);
3999 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4003 spacep = inp->spacep;
4004 smb_StripLastComponent(spacep->data, NULL, pathp);
4005 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4007 lock_ReleaseMutex(&dsp->mx);
4008 cm_ReleaseUser(userp);
4009 smb_DeleteDirSearch(dsp);
4010 smb_ReleaseDirSearch(dsp);
4011 return CM_ERROR_NOFILES;
4013 strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
4014 strcpy(dsp->relPath, spacep->data);
4016 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4017 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4020 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4021 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4022 cm_ReleaseSCache(scp);
4023 lock_ReleaseMutex(&dsp->mx);
4024 cm_ReleaseUser(userp);
4025 smb_DeleteDirSearch(dsp);
4026 smb_ReleaseDirSearch(dsp);
4027 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4028 return CM_ERROR_PATH_NOT_COVERED;
4030 return CM_ERROR_BADSHARENAME;
4032 #endif /* DFS_SUPPORT */
4035 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4036 /* we need one hold for the entry we just stored into,
4037 * and one for our own processing. When we're done with this
4038 * function, we'll drop the one for our own processing.
4039 * We held it once from the namei call, and so we do another hold
4043 lock_ObtainMutex(&scp->mx);
4044 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4045 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4046 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4047 dsp->flags |= SMB_DIRSEARCH_BULKST;
4048 dsp->scp->bulkStatProgress = hzero;
4050 lock_ReleaseMutex(&scp->mx);
4053 lock_ReleaseMutex(&dsp->mx);
4055 cm_ReleaseUser(userp);
4056 smb_DeleteDirSearch(dsp);
4057 smb_ReleaseDirSearch(dsp);
4061 /* reserves space for parameter; we'll adjust it again later to the
4062 * real count of the # of entries we returned once we've actually
4063 * assembled the directory listing.
4065 smb_SetSMBParm(outp, 0, 0);
4067 /* get the directory size */
4068 lock_ObtainMutex(&scp->mx);
4069 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4070 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4072 lock_ReleaseMutex(&scp->mx);
4073 cm_ReleaseSCache(scp);
4074 cm_ReleaseUser(userp);
4075 smb_DeleteDirSearch(dsp);
4076 smb_ReleaseDirSearch(dsp);
4080 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4082 dirLength = scp->length;
4084 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4085 curOffset.HighPart = 0;
4086 curOffset.LowPart = nextCookie;
4087 origOp = op = smb_GetSMBData(outp, NULL);
4088 /* and write out the basic header */
4089 *op++ = 5; /* variable block */
4090 op += 2; /* skip vbl block length; we'll fill it in later */
4094 /* make sure that curOffset.LowPart doesn't point to the first
4095 * 32 bytes in the 2nd through last dir page, and that it doesn't
4096 * point at the first 13 32-byte chunks in the first dir page,
4097 * since those are dir and page headers, and don't contain useful
4100 temp = curOffset.LowPart & (2048-1);
4101 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4102 /* we're in the first page */
4103 if (temp < 13*32) temp = 13*32;
4106 /* we're in a later dir page */
4107 if (temp < 32) temp = 32;
4110 /* make sure the low order 5 bits are zero */
4113 /* now put temp bits back ito curOffset.LowPart */
4114 curOffset.LowPart &= ~(2048-1);
4115 curOffset.LowPart |= temp;
4117 /* check if we've returned all the names that will fit in the
4120 if (returnedNames >= maxCount) {
4121 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4122 returnedNames, maxCount);
4126 /* check if we've passed the dir's EOF */
4127 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4129 /* see if we can use the bufferp we have now; compute in which page
4130 * the current offset would be, and check whether that's the offset
4131 * of the buffer we have. If not, get the buffer.
4133 thyper.HighPart = curOffset.HighPart;
4134 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4135 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4138 buf_Release(bufferp);
4141 lock_ReleaseMutex(&scp->mx);
4142 code = buf_Get(scp, &thyper, &bufferp);
4143 lock_ObtainMutex(&dsp->mx);
4145 /* now, if we're doing a star match, do bulk fetching of all of
4146 * the status info for files in the dir.
4149 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4150 lock_ObtainMutex(&scp->mx);
4151 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4152 LargeIntegerGreaterThanOrEqualTo(thyper,
4153 scp->bulkStatProgress)) {
4154 /* Don't bulk stat if risking timeout */
4155 int now = GetTickCount();
4156 if (now - req.startTime > RDRtimeout * 1000) {
4157 scp->bulkStatProgress = thyper;
4158 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4159 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4160 dsp->scp->bulkStatProgress = hzero;
4162 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4165 lock_ObtainMutex(&scp->mx);
4167 lock_ReleaseMutex(&dsp->mx);
4169 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4173 bufferOffset = thyper;
4175 /* now get the data in the cache */
4177 code = cm_SyncOp(scp, bufferp, userp, &req,
4179 CM_SCACHESYNC_NEEDCALLBACK |
4180 CM_SCACHESYNC_READ);
4182 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4186 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4188 if (cm_HaveBuffer(scp, bufferp, 0)) {
4189 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4193 /* otherwise, load the buffer and try again */
4194 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4196 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4197 scp, bufferp, code);
4202 buf_Release(bufferp);
4206 } /* if (wrong buffer) ... */
4208 /* now we have the buffer containing the entry we're interested in; copy
4209 * it out if it represents a non-deleted entry.
4211 entryInDir = curOffset.LowPart & (2048-1);
4212 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4214 /* page header will help tell us which entries are free. Page header
4215 * can change more often than once per buffer, since AFS 3 dir page size
4216 * may be less than (but not more than a buffer package buffer.
4218 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4219 temp &= ~(2048 - 1); /* turn off intra-page bits */
4220 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4222 /* now determine which entry we're looking at in the page. If it is
4223 * free (there's a free bitmap at the start of the dir), we should
4224 * skip these 32 bytes.
4226 slotInPage = (entryInDir & 0x7e0) >> 5;
4227 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4228 /* this entry is free */
4229 numDirChunks = 1; /* only skip this guy */
4233 tp = bufferp->datap + entryInBuffer;
4234 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4236 /* while we're here, compute the next entry's location, too,
4237 * since we'll need it when writing out the cookie into the dir
4240 * XXXX Probably should do more sanity checking.
4242 numDirChunks = cm_NameEntries(dep->name, NULL);
4244 /* compute the offset of the cookie representing the next entry */
4245 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4247 /* Compute 8.3 name if necessary */
4248 actualName = dep->name;
4249 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4250 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4251 actualName = shortName;
4254 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4255 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4256 osi_LogSaveString(smb_logp, actualName));
4258 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4259 /* this is one of the entries to use: it is not deleted
4260 * and it matches the star pattern we're looking for.
4263 /* Eliminate entries that don't match requested
4266 /* no hidden files */
4267 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4268 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4272 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4274 /* We have already done the cm_TryBulkStat above */
4275 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4276 fileType = cm_FindFileType(&fid);
4277 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4278 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4280 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4281 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4282 fileType == CM_SCACHETYPE_DFSLINK ||
4283 fileType == CM_SCACHETYPE_INVALID)
4284 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4289 memcpy(op, mask, 11); op += 11;
4290 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4291 *op++ = (char)(nextEntryCookie & 0xff);
4292 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4293 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4294 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4295 memcpy(op, &clientCookie, 4); op += 4;
4297 /* now we emit the attribute. This is sort of tricky,
4298 * since we need to really stat the file to find out
4299 * what type of entry we've got. Right now, we're
4300 * copying out data from a buffer, while holding the
4301 * scp locked, so it isn't really convenient to stat
4302 * something now. We'll put in a place holder now,
4303 * and make a second pass before returning this to get
4304 * the real attributes. So, we just skip the data for
4305 * now, and adjust it later. We allocate a patch
4306 * record to make it easy to find this point later.
4307 * The replay will happen at a time when it is safe to
4308 * unlock the directory.
4310 curPatchp = malloc(sizeof(*curPatchp));
4311 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4312 curPatchp->dptr = op;
4313 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4315 /* do hidden attribute here since name won't be around when applying
4319 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4320 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4322 curPatchp->flags = 0;
4324 op += 9; /* skip attr, time, date and size */
4326 /* zero out name area. The spec says to pad with
4327 * spaces, but Samba doesn't, and neither do we.
4331 /* finally, we get to copy out the name; we know that
4332 * it fits in 8.3 or the pattern wouldn't match, but it
4333 * never hurts to be sure.
4335 strncpy(op, actualName, 13);
4336 if (smb_StoreAnsiFilenames)
4339 /* Uppercase if requested by client */
4340 if (!KNOWS_LONG_NAMES(inp))
4345 /* now, adjust the # of entries copied */
4347 } /* if we're including this name */
4350 /* and adjust curOffset to be where the new cookie is */
4351 thyper.HighPart = 0;
4352 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4353 curOffset = LargeIntegerAdd(thyper, curOffset);
4354 } /* while copying data for dir listing */
4356 /* release the mutex */
4357 lock_ReleaseMutex(&scp->mx);
4359 buf_Release(bufferp);
4363 /* apply and free last set of patches; if not doing a star match, this
4364 * will be empty, but better safe (and freeing everything) than sorry.
4366 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4368 /* special return code for unsuccessful search */
4369 if (code == 0 && dataLength < 21 && returnedNames == 0)
4370 code = CM_ERROR_NOFILES;
4372 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4373 returnedNames, code);
4376 smb_DeleteDirSearch(dsp);
4377 smb_ReleaseDirSearch(dsp);
4378 cm_ReleaseSCache(scp);
4379 cm_ReleaseUser(userp);
4383 /* finalize the output buffer */
4384 smb_SetSMBParm(outp, 0, returnedNames);
4385 temp = (long) (op - origOp);
4386 smb_SetSMBDataLength(outp, temp);
4388 /* the data area is a variable block, which has a 5 (already there)
4389 * followed by the length of the # of data bytes. We now know this to
4390 * be "temp," although that includes the 3 bytes of vbl block header.
4391 * Deduct for them and fill in the length field.
4393 temp -= 3; /* deduct vbl block info */
4394 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4395 origOp[1] = (char)(temp & 0xff);
4396 origOp[2] = (char)((temp>>8) & 0xff);
4397 if (returnedNames == 0)
4398 smb_DeleteDirSearch(dsp);
4399 smb_ReleaseDirSearch(dsp);
4400 cm_ReleaseSCache(scp);
4401 cm_ReleaseUser(userp);
4405 /* verify that this is a valid path to a directory. I don't know why they
4406 * don't use the get file attributes call.
4408 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4412 cm_scache_t *rootScp;
4413 cm_scache_t *newScp;
4422 pathp = smb_GetSMBData(inp, NULL);
4423 pathp = smb_ParseASCIIBlock(pathp, NULL);
4425 return CM_ERROR_BADFD;
4426 if (smb_StoreAnsiFilenames)
4427 OemToChar(pathp,pathp);
4428 osi_Log1(smb_logp, "SMB receive check path %s",
4429 osi_LogSaveString(smb_logp, pathp));
4431 rootScp = cm_data.rootSCachep;
4433 userp = smb_GetUserFromVCP(vcp, inp);
4435 caseFold = CM_FLAG_CASEFOLD;
4437 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4439 cm_ReleaseUser(userp);
4440 return CM_ERROR_NOSUCHPATH;
4442 code = cm_NameI(rootScp, pathp,
4443 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4444 userp, tidPathp, &req, &newScp);
4447 cm_ReleaseUser(userp);
4452 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4453 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4454 cm_ReleaseSCache(newScp);
4455 cm_ReleaseUser(userp);
4456 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4457 return CM_ERROR_PATH_NOT_COVERED;
4459 return CM_ERROR_BADSHARENAME;
4461 #endif /* DFS_SUPPORT */
4463 /* now lock the vnode with a callback; returns with newScp locked */
4464 lock_ObtainMutex(&newScp->mx);
4465 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4466 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4468 if (code != CM_ERROR_NOACCESS) {
4469 lock_ReleaseMutex(&newScp->mx);
4470 cm_ReleaseSCache(newScp);
4471 cm_ReleaseUser(userp);
4475 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4478 attrs = smb_Attributes(newScp);
4480 if (!(attrs & SMB_ATTR_DIRECTORY))
4481 code = CM_ERROR_NOTDIR;
4483 lock_ReleaseMutex(&newScp->mx);
4485 cm_ReleaseSCache(newScp);
4486 cm_ReleaseUser(userp);
4490 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4494 cm_scache_t *rootScp;
4495 unsigned short attribute;
4497 cm_scache_t *newScp;
4506 /* decode basic attributes we're passed */
4507 attribute = smb_GetSMBParm(inp, 0);
4508 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4510 pathp = smb_GetSMBData(inp, NULL);
4511 pathp = smb_ParseASCIIBlock(pathp, NULL);
4513 return CM_ERROR_BADSMB;
4514 if (smb_StoreAnsiFilenames)
4515 OemToChar(pathp,pathp);
4517 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4518 dosTime, attribute);
4520 rootScp = cm_data.rootSCachep;
4522 userp = smb_GetUserFromVCP(vcp, inp);
4524 caseFold = CM_FLAG_CASEFOLD;
4526 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4528 cm_ReleaseUser(userp);
4529 return CM_ERROR_NOSUCHFILE;
4531 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4532 tidPathp, &req, &newScp);
4535 cm_ReleaseUser(userp);
4540 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4541 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4542 cm_ReleaseSCache(newScp);
4543 cm_ReleaseUser(userp);
4544 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4545 return CM_ERROR_PATH_NOT_COVERED;
4547 return CM_ERROR_BADSHARENAME;
4549 #endif /* DFS_SUPPORT */
4551 /* now lock the vnode with a callback; returns with newScp locked; we
4552 * need the current status to determine what the new status is, in some
4555 lock_ObtainMutex(&newScp->mx);
4556 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4557 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4559 lock_ReleaseMutex(&newScp->mx);
4560 cm_ReleaseSCache(newScp);
4561 cm_ReleaseUser(userp);
4565 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4567 /* Check for RO volume */
4568 if (newScp->flags & CM_SCACHEFLAG_RO) {
4569 lock_ReleaseMutex(&newScp->mx);
4570 cm_ReleaseSCache(newScp);
4571 cm_ReleaseUser(userp);
4572 return CM_ERROR_READONLY;
4575 /* prepare for setattr call */
4578 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4579 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4581 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4582 /* we're told to make a writable file read-only */
4583 attr.unixModeBits = newScp->unixModeBits & ~0222;
4584 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4586 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4587 /* we're told to make a read-only file writable */
4588 attr.unixModeBits = newScp->unixModeBits | 0222;
4589 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4591 lock_ReleaseMutex(&newScp->mx);
4593 /* now call setattr */
4595 code = cm_SetAttr(newScp, &attr, userp, &req);
4599 cm_ReleaseSCache(newScp);
4600 cm_ReleaseUser(userp);
4605 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4609 cm_scache_t *rootScp;
4610 cm_scache_t *newScp, *dscp;
4622 pathp = smb_GetSMBData(inp, NULL);
4623 pathp = smb_ParseASCIIBlock(pathp, NULL);
4625 return CM_ERROR_BADSMB;
4627 if (*pathp == 0) /* null path */
4630 if (smb_StoreAnsiFilenames)
4631 OemToChar(pathp,pathp);
4633 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4634 osi_LogSaveString(smb_logp, pathp));
4636 rootScp = cm_data.rootSCachep;
4638 userp = smb_GetUserFromVCP(vcp, inp);
4640 /* we shouldn't need this for V3 requests, but we seem to */
4641 caseFold = CM_FLAG_CASEFOLD;
4643 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4645 cm_ReleaseUser(userp);
4646 return CM_ERROR_NOSUCHFILE;
4650 * XXX Strange hack XXX
4652 * As of Patch 5 (16 July 97), we are having the following problem:
4653 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4654 * requests to look up "desktop.ini" in all the subdirectories.
4655 * This can cause zillions of timeouts looking up non-existent cells
4656 * and volumes, especially in the top-level directory.
4658 * We have not found any way to avoid this or work around it except
4659 * to explicitly ignore the requests for mount points that haven't
4660 * yet been evaluated and for directories that haven't yet been
4663 * We should modify this hack to provide a fake desktop.ini file
4664 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4666 spacep = inp->spacep;
4667 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4668 #ifndef SPECIAL_FOLDERS
4669 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4670 code = cm_NameI(rootScp, spacep->data,
4671 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4672 userp, tidPathp, &req, &dscp);
4675 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4676 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
4677 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4678 return CM_ERROR_PATH_NOT_COVERED;
4680 return CM_ERROR_BADSHARENAME;
4682 #endif /* DFS_SUPPORT */
4683 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4684 code = CM_ERROR_NOSUCHFILE;
4685 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4686 cm_buf_t *bp = buf_Find(dscp, &hzero);
4691 code = CM_ERROR_NOSUCHFILE;
4693 cm_ReleaseSCache(dscp);
4695 cm_ReleaseUser(userp);
4700 #endif /* SPECIAL_FOLDERS */
4702 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4703 tidPathp, &req, &newScp);
4705 cm_ReleaseUser(userp);
4710 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4711 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4712 cm_ReleaseSCache(newScp);
4713 cm_ReleaseUser(userp);
4714 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4715 return CM_ERROR_PATH_NOT_COVERED;
4717 return CM_ERROR_BADSHARENAME;
4719 #endif /* DFS_SUPPORT */
4721 /* now lock the vnode with a callback; returns with newScp locked */
4722 lock_ObtainMutex(&newScp->mx);
4723 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4724 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4726 lock_ReleaseMutex(&newScp->mx);
4727 cm_ReleaseSCache(newScp);
4728 cm_ReleaseUser(userp);
4732 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4735 /* use smb_Attributes instead. Also the fact that a file is
4736 * in a readonly volume doesn't mean it shojuld be marked as RO
4738 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4739 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4740 newScp->fileType == CM_SCACHETYPE_INVALID)
4741 attrs = SMB_ATTR_DIRECTORY;
4744 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4745 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4747 attrs = smb_Attributes(newScp);
4750 smb_SetSMBParm(outp, 0, attrs);
4752 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4753 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4754 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4755 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4756 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4757 smb_SetSMBParm(outp, 5, 0);
4758 smb_SetSMBParm(outp, 6, 0);
4759 smb_SetSMBParm(outp, 7, 0);
4760 smb_SetSMBParm(outp, 8, 0);
4761 smb_SetSMBParm(outp, 9, 0);
4762 smb_SetSMBDataLength(outp, 0);
4763 lock_ReleaseMutex(&newScp->mx);
4765 cm_ReleaseSCache(newScp);
4766 cm_ReleaseUser(userp);
4771 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4775 osi_Log0(smb_logp, "SMB receive tree disconnect");
4777 /* find the tree and free it */
4778 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4780 lock_ObtainWrite(&smb_rctLock);
4782 smb_ReleaseTID(tidp, TRUE);
4783 lock_ReleaseWrite(&smb_rctLock);
4789 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4807 pathp = smb_GetSMBData(inp, NULL);
4808 pathp = smb_ParseASCIIBlock(pathp, NULL);
4809 if (smb_StoreAnsiFilenames)
4810 OemToChar(pathp,pathp);
4812 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4814 #ifdef DEBUG_VERBOSE
4818 hexpath = osi_HexifyString( pathp );
4819 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4824 share = smb_GetSMBParm(inp, 0);
4825 attribute = smb_GetSMBParm(inp, 1);
4827 spacep = inp->spacep;
4828 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4829 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4830 /* special case magic file name for receiving IOCTL requests
4831 * (since IOCTL calls themselves aren't getting through).
4833 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4834 smb_SetupIoctlFid(fidp, spacep);
4835 smb_SetSMBParm(outp, 0, fidp->fid);
4836 smb_SetSMBParm(outp, 1, 0); /* attrs */
4837 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4838 smb_SetSMBParm(outp, 3, 0);
4839 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4840 smb_SetSMBParm(outp, 5, 0x7fff);
4841 /* pass the open mode back */
4842 smb_SetSMBParm(outp, 6, (share & 0xf));
4843 smb_SetSMBDataLength(outp, 0);
4844 smb_ReleaseFID(fidp);
4848 userp = smb_GetUserFromVCP(vcp, inp);
4850 caseFold = CM_FLAG_CASEFOLD;
4852 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4854 cm_ReleaseUser(userp);
4855 return CM_ERROR_NOSUCHPATH;
4857 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4858 tidPathp, &req, &scp);
4861 cm_ReleaseUser(userp);
4866 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4867 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
4868 cm_ReleaseSCache(scp);
4869 cm_ReleaseUser(userp);
4870 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4871 return CM_ERROR_PATH_NOT_COVERED;
4873 return CM_ERROR_BADSHARENAME;
4875 #endif /* DFS_SUPPORT */
4877 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4879 cm_ReleaseSCache(scp);
4880 cm_ReleaseUser(userp);
4884 /* don't need callback to check file type, since file types never
4885 * change, and namei and cm_Lookup all stat the object at least once on
4886 * a successful return.
4888 if (scp->fileType != CM_SCACHETYPE_FILE) {
4889 cm_ReleaseSCache(scp);
4890 cm_ReleaseUser(userp);
4891 return CM_ERROR_ISDIR;
4894 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4895 osi_assertx(fidp, "null smb_fid_t");
4897 /* save a pointer to the vnode */
4899 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4900 lock_ObtainMutex(&scp->mx);
4901 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4902 lock_ReleaseMutex(&scp->mx);
4906 fidp->userp = userp;
4908 lock_ObtainMutex(&fidp->mx);
4909 if ((share & 0xf) == 0)
4910 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
4911 else if ((share & 0xf) == 1)
4912 fidp->flags |= SMB_FID_OPENWRITE;
4914 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
4915 lock_ReleaseMutex(&fidp->mx);
4917 lock_ObtainMutex(&scp->mx);
4918 smb_SetSMBParm(outp, 0, fidp->fid);
4919 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4920 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4921 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4922 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4923 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4924 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4925 /* pass the open mode back; XXXX add access checks */
4926 smb_SetSMBParm(outp, 6, (share & 0xf));
4927 smb_SetSMBDataLength(outp, 0);
4928 lock_ReleaseMutex(&scp->mx);
4931 cm_Open(scp, 0, userp);
4933 /* send and free packet */
4934 smb_ReleaseFID(fidp);
4935 cm_ReleaseUser(userp);
4936 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4940 typedef struct smb_unlinkRock {
4945 char *maskp; /* pointer to the star pattern */
4948 cm_dirEntryList_t * matches;
4951 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4954 smb_unlinkRock_t *rockp;
4962 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4963 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4964 caseFold |= CM_FLAG_8DOT3;
4966 matchName = dep->name;
4967 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4969 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4970 !cm_Is8Dot3(dep->name)) {
4971 cm_Gen8Dot3Name(dep, shortName, NULL);
4972 matchName = shortName;
4973 /* 8.3 matches are always case insensitive */
4974 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4977 osi_Log1(smb_logp, "Found match %s",
4978 osi_LogSaveString(smb_logp, matchName));
4980 cm_DirEntryListAdd(dep->name, &rockp->matches);
4984 /* If we made a case sensitive exact match, we might as well quit now. */
4985 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4986 code = CM_ERROR_STOPNOW;
4995 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5004 smb_unlinkRock_t rock;
5013 attribute = smb_GetSMBParm(inp, 0);
5015 tp = smb_GetSMBData(inp, NULL);
5016 pathp = smb_ParseASCIIBlock(tp, &tp);
5017 if (smb_StoreAnsiFilenames)
5018 OemToChar(pathp,pathp);
5020 osi_Log1(smb_logp, "SMB receive unlink %s",
5021 osi_LogSaveString(smb_logp, pathp));
5023 spacep = inp->spacep;
5024 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5026 userp = smb_GetUserFromVCP(vcp, inp);
5028 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5030 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5032 cm_ReleaseUser(userp);
5033 return CM_ERROR_NOSUCHPATH;
5035 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5038 cm_ReleaseUser(userp);
5043 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5044 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,spacep->data);
5045 cm_ReleaseSCache(dscp);
5046 cm_ReleaseUser(userp);
5047 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5048 return CM_ERROR_PATH_NOT_COVERED;
5050 return CM_ERROR_BADSHARENAME;
5052 #endif /* DFS_SUPPORT */
5054 /* otherwise, scp points to the parent directory. */
5061 rock.maskp = smb_FindMask(pathp);
5062 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5065 thyper.HighPart = 0;
5070 rock.matches = NULL;
5072 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5073 * match. If that fails, we do a case insensitve match.
5075 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5076 !smb_IsStarMask(rock.maskp)) {
5077 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5080 thyper.HighPart = 0;
5081 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5086 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5088 if (code == CM_ERROR_STOPNOW)
5091 if (code == 0 && rock.matches) {
5092 cm_dirEntryList_t * entry;
5094 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5096 osi_Log1(smb_logp, "Unlinking %s",
5097 osi_LogSaveString(smb_logp, entry->name));
5098 code = cm_Unlink(dscp, entry->name, userp, &req);
5100 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5101 smb_NotifyChange(FILE_ACTION_REMOVED,
5102 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5103 dscp, entry->name, NULL, TRUE);
5107 cm_DirEntryListFree(&rock.matches);
5109 cm_ReleaseUser(userp);
5111 cm_ReleaseSCache(dscp);
5113 if (code == 0 && !rock.any)
5114 code = CM_ERROR_NOSUCHFILE;
5118 typedef struct smb_renameRock {
5119 cm_scache_t *odscp; /* old dir */
5120 cm_scache_t *ndscp; /* new dir */
5121 cm_user_t *userp; /* user */
5122 cm_req_t *reqp; /* request struct */
5123 smb_vc_t *vcp; /* virtual circuit */
5124 char *maskp; /* pointer to star pattern of old file name */
5125 int flags; /* tilde, casefold, etc */
5126 char *newNamep; /* ptr to the new file's name */
5127 char oldName[MAX_PATH];
5131 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5134 smb_renameRock_t *rockp;
5137 char shortName[13]="";
5139 rockp = (smb_renameRock_t *) vrockp;
5141 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5142 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5143 caseFold |= CM_FLAG_8DOT3;
5145 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5147 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5148 !cm_Is8Dot3(dep->name)) {
5149 cm_Gen8Dot3Name(dep, shortName, NULL);
5150 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5155 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5156 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5157 code = CM_ERROR_STOPNOW;
5167 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5170 cm_space_t *spacep = NULL;
5171 smb_renameRock_t rock;
5172 cm_scache_t *oldDscp = NULL;
5173 cm_scache_t *newDscp = NULL;
5174 cm_scache_t *tmpscp= NULL;
5175 cm_scache_t *tmpscp2 = NULL;
5185 userp = smb_GetUserFromVCP(vcp, inp);
5186 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5188 cm_ReleaseUser(userp);
5189 return CM_ERROR_NOSUCHPATH;
5193 spacep = inp->spacep;
5194 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5196 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5197 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5198 userp, tidPathp, &req, &oldDscp);
5200 cm_ReleaseUser(userp);
5205 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5206 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5207 cm_ReleaseSCache(oldDscp);
5208 cm_ReleaseUser(userp);
5209 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5210 return CM_ERROR_PATH_NOT_COVERED;
5212 return CM_ERROR_BADSHARENAME;
5214 #endif /* DFS_SUPPORT */
5216 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5217 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5218 userp, tidPathp, &req, &newDscp);
5221 cm_ReleaseSCache(oldDscp);
5222 cm_ReleaseUser(userp);
5227 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5228 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5229 cm_ReleaseSCache(oldDscp);
5230 cm_ReleaseSCache(newDscp);
5231 cm_ReleaseUser(userp);
5232 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5233 return CM_ERROR_PATH_NOT_COVERED;
5235 return CM_ERROR_BADSHARENAME;
5237 #endif /* DFS_SUPPORT */
5240 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5241 * next, get the component names, and lower case them.
5244 /* handle the old name first */
5246 oldLastNamep = oldPathp;
5250 /* and handle the new name, too */
5252 newLastNamep = newPathp;
5256 /* TODO: The old name could be a wildcard. The new name must not be */
5258 /* do the vnode call */
5259 rock.odscp = oldDscp;
5260 rock.ndscp = newDscp;
5264 rock.maskp = oldLastNamep;
5265 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5266 rock.newNamep = newLastNamep;
5267 rock.oldName[0] = '\0';
5270 /* Check if the file already exists; if so return error */
5271 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5272 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5273 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5275 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5276 osi_LogSaveString(smb_logp, newLastNamep));
5278 /* Check if the old and the new names differ only in case. If so return
5279 * success, else return CM_ERROR_EXISTS
5281 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5283 /* This would be a success only if the old file is *as same as* the new file */
5284 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5286 if (tmpscp == tmpscp2)
5289 code = CM_ERROR_EXISTS;
5290 cm_ReleaseSCache(tmpscp2);
5293 code = CM_ERROR_NOSUCHFILE;
5296 /* file exist, do not rename, also fixes move */
5297 osi_Log0(smb_logp, "Can't rename. Target already exists");
5298 code = CM_ERROR_EXISTS;
5302 cm_ReleaseSCache(tmpscp);
5303 cm_ReleaseSCache(newDscp);
5304 cm_ReleaseSCache(oldDscp);
5305 cm_ReleaseUser(userp);
5309 /* Now search the directory for the pattern, and do the appropriate rename when found */
5310 thyper.LowPart = 0; /* search dir from here */
5311 thyper.HighPart = 0;
5313 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5314 if (code == 0 && !rock.any) {
5316 thyper.HighPart = 0;
5317 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5318 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5320 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5322 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5323 code = cm_Rename(rock.odscp, rock.oldName,
5324 rock.ndscp, rock.newNamep, rock.userp,
5326 /* if the call worked, stop doing the search now, since we
5327 * really only want to rename one file.
5329 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5330 } else if (code == 0) {
5331 code = CM_ERROR_NOSUCHFILE;
5334 /* Handle Change Notification */
5336 * Being lazy, not distinguishing between files and dirs in this
5337 * filter, since we'd have to do a lookup.
5340 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5341 if (oldDscp == newDscp) {
5342 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5343 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5344 filter, oldDscp, oldLastNamep,
5345 newLastNamep, TRUE);
5347 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5348 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5349 filter, oldDscp, oldLastNamep,
5351 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5352 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5353 filter, newDscp, newLastNamep,
5359 cm_ReleaseSCache(tmpscp);
5360 cm_ReleaseUser(userp);
5361 cm_ReleaseSCache(oldDscp);
5362 cm_ReleaseSCache(newDscp);
5367 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5370 cm_space_t *spacep = NULL;
5371 cm_scache_t *oldDscp = NULL;
5372 cm_scache_t *newDscp = NULL;
5373 cm_scache_t *tmpscp= NULL;
5374 cm_scache_t *tmpscp2 = NULL;
5375 cm_scache_t *sscp = NULL;
5384 userp = smb_GetUserFromVCP(vcp, inp);
5386 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5388 cm_ReleaseUser(userp);
5389 return CM_ERROR_NOSUCHPATH;
5394 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5396 spacep = inp->spacep;
5397 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5399 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5400 userp, tidPathp, &req, &oldDscp);
5402 cm_ReleaseUser(userp);
5407 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5408 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5409 cm_ReleaseSCache(oldDscp);
5410 cm_ReleaseUser(userp);
5411 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5412 return CM_ERROR_PATH_NOT_COVERED;
5414 return CM_ERROR_BADSHARENAME;
5416 #endif /* DFS_SUPPORT */
5418 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5419 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5420 userp, tidPathp, &req, &newDscp);
5422 cm_ReleaseSCache(oldDscp);
5423 cm_ReleaseUser(userp);
5428 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5429 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5430 cm_ReleaseSCache(newDscp);
5431 cm_ReleaseSCache(oldDscp);
5432 cm_ReleaseUser(userp);
5433 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5434 return CM_ERROR_PATH_NOT_COVERED;
5436 return CM_ERROR_BADSHARENAME;
5438 #endif /* DFS_SUPPORT */
5440 /* Now, although we did two lookups for the two directories (because the same
5441 * directory can be referenced through different paths), we only allow hard links
5442 * within the same directory. */
5443 if (oldDscp != newDscp) {
5444 cm_ReleaseSCache(oldDscp);
5445 cm_ReleaseSCache(newDscp);
5446 cm_ReleaseUser(userp);
5447 return CM_ERROR_CROSSDEVLINK;
5450 /* handle the old name first */
5452 oldLastNamep = oldPathp;
5456 /* and handle the new name, too */
5458 newLastNamep = newPathp;
5462 /* now lookup the old name */
5463 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5464 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5466 cm_ReleaseSCache(oldDscp);
5467 cm_ReleaseSCache(newDscp);
5468 cm_ReleaseUser(userp);
5472 /* Check if the file already exists; if so return error */
5473 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5474 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5475 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5477 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5478 osi_LogSaveString(smb_logp, newLastNamep));
5480 /* if the existing link is to the same file, then we return success */
5482 if(sscp == tmpscp) {
5485 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5486 code = CM_ERROR_EXISTS;
5491 cm_ReleaseSCache(tmpscp);
5492 cm_ReleaseSCache(sscp);
5493 cm_ReleaseSCache(newDscp);
5494 cm_ReleaseSCache(oldDscp);
5495 cm_ReleaseUser(userp);
5499 /* now create the hardlink */
5500 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5501 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5502 osi_Log1(smb_logp," Link returns 0x%x", code);
5504 /* Handle Change Notification */
5506 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5507 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5508 smb_NotifyChange(FILE_ACTION_ADDED,
5509 filter, newDscp, newLastNamep,
5514 cm_ReleaseSCache(tmpscp);
5515 cm_ReleaseUser(userp);
5516 cm_ReleaseSCache(sscp);
5517 cm_ReleaseSCache(oldDscp);
5518 cm_ReleaseSCache(newDscp);
5523 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5530 tp = smb_GetSMBData(inp, NULL);
5531 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5532 if (smb_StoreAnsiFilenames)
5533 OemToChar(oldPathp,oldPathp);
5534 newPathp = smb_ParseASCIIBlock(tp, &tp);
5535 if (smb_StoreAnsiFilenames)
5536 OemToChar(newPathp,newPathp);
5538 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5539 osi_LogSaveString(smb_logp, oldPathp),
5540 osi_LogSaveString(smb_logp, newPathp));
5542 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5544 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5550 typedef struct smb_rmdirRock {
5554 char *maskp; /* pointer to the star pattern */
5557 cm_dirEntryList_t * matches;
5560 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5563 smb_rmdirRock_t *rockp;
5568 rockp = (smb_rmdirRock_t *) vrockp;
5570 matchName = dep->name;
5571 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5572 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5574 match = (strcmp(matchName, rockp->maskp) == 0);
5576 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5577 !cm_Is8Dot3(dep->name)) {
5578 cm_Gen8Dot3Name(dep, shortName, NULL);
5579 matchName = shortName;
5580 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5585 cm_DirEntryListAdd(dep->name, &rockp->matches);
5591 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5599 smb_rmdirRock_t rock;
5608 tp = smb_GetSMBData(inp, NULL);
5609 pathp = smb_ParseASCIIBlock(tp, &tp);
5610 if (smb_StoreAnsiFilenames)
5611 OemToChar(pathp,pathp);
5613 spacep = inp->spacep;
5614 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5616 userp = smb_GetUserFromVCP(vcp, inp);
5618 caseFold = CM_FLAG_CASEFOLD;
5620 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5622 cm_ReleaseUser(userp);
5623 return CM_ERROR_NOSUCHPATH;
5625 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5626 userp, tidPathp, &req, &dscp);
5629 cm_ReleaseUser(userp);
5634 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5635 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
5636 cm_ReleaseSCache(dscp);
5637 cm_ReleaseUser(userp);
5638 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5639 return CM_ERROR_PATH_NOT_COVERED;
5641 return CM_ERROR_BADSHARENAME;
5643 #endif /* DFS_SUPPORT */
5645 /* otherwise, scp points to the parent directory. */
5652 rock.maskp = lastNamep;
5653 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5656 thyper.HighPart = 0;
5660 rock.matches = NULL;
5662 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5663 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5664 if (code == 0 && !rock.any) {
5666 thyper.HighPart = 0;
5667 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5668 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5671 if (code == 0 && rock.matches) {
5672 cm_dirEntryList_t * entry;
5674 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5675 osi_Log1(smb_logp, "Removing directory %s",
5676 osi_LogSaveString(smb_logp, entry->name));
5678 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5680 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5681 smb_NotifyChange(FILE_ACTION_REMOVED,
5682 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5683 dscp, entry->name, NULL, TRUE);
5687 cm_DirEntryListFree(&rock.matches);
5689 cm_ReleaseUser(userp);
5691 cm_ReleaseSCache(dscp);
5693 if (code == 0 && !rock.any)
5694 code = CM_ERROR_NOSUCHFILE;
5698 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5708 fid = smb_GetSMBParm(inp, 0);
5710 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5712 fid = smb_ChainFID(fid, inp);
5713 fidp = smb_FindFID(vcp, fid, 0);
5715 return CM_ERROR_BADFD;
5717 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5718 smb_CloseFID(vcp, fidp, NULL, 0);
5719 smb_ReleaseFID(fidp);
5720 return CM_ERROR_NOSUCHFILE;
5723 lock_ObtainMutex(&fidp->mx);
5724 if (fidp->flags & SMB_FID_IOCTL) {
5725 lock_ReleaseMutex(&fidp->mx);
5726 smb_ReleaseFID(fidp);
5727 return CM_ERROR_BADFD;
5729 lock_ReleaseMutex(&fidp->mx);
5731 userp = smb_GetUserFromVCP(vcp, inp);
5733 lock_ObtainMutex(&fidp->mx);
5734 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
5735 cm_scache_t * scp = fidp->scp;
5737 lock_ReleaseMutex(&fidp->mx);
5738 code = cm_FSync(scp, userp, &req);
5739 cm_ReleaseSCache(scp);
5742 lock_ReleaseMutex(&fidp->mx);
5745 smb_ReleaseFID(fidp);
5747 cm_ReleaseUser(userp);
5752 struct smb_FullNameRock {
5758 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5762 struct smb_FullNameRock *vrockp;
5764 vrockp = (struct smb_FullNameRock *)rockp;
5766 if (!cm_Is8Dot3(dep->name)) {
5767 cm_Gen8Dot3Name(dep, shortName, NULL);
5769 if (cm_stricmp(shortName, vrockp->name) == 0) {
5770 vrockp->fullName = strdup(dep->name);
5771 return CM_ERROR_STOPNOW;
5774 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5775 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5776 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5777 vrockp->fullName = strdup(dep->name);
5778 return CM_ERROR_STOPNOW;
5783 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5784 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5786 struct smb_FullNameRock rock;
5792 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5793 if (code == CM_ERROR_STOPNOW)
5794 *newPathp = rock.fullName;
5796 *newPathp = strdup(pathp);
5799 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5800 afs_uint32 dosTime) {
5803 cm_scache_t *dscp = NULL;
5805 cm_scache_t * scp = NULL;
5806 cm_scache_t *delscp = NULL;
5808 int nullcreator = 0;
5810 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5811 fidp, fidp->fid, scp, vcp);
5814 lock_ObtainMutex(&fidp->mx);
5815 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5816 lock_ReleaseMutex(&fidp->mx);
5817 osi_Log0(smb_logp, " No user specified. Not closing fid");
5818 return CM_ERROR_BADFD;
5821 userp = fidp->userp; /* no hold required since fidp is held
5822 throughout the function */
5823 lock_ReleaseMutex(&fidp->mx);
5828 lock_ObtainWrite(&smb_rctLock);
5830 osi_Log0(smb_logp, " Fid already closed.");
5831 lock_ReleaseWrite(&smb_rctLock);
5832 return CM_ERROR_BADFD;
5835 lock_ReleaseWrite(&smb_rctLock);
5837 lock_ObtainMutex(&fidp->mx);
5838 if (fidp->NTopen_dscp) {
5839 dscp = fidp->NTopen_dscp;
5840 cm_HoldSCache(dscp);
5843 if (fidp->NTopen_pathp) {
5844 pathp = strdup(fidp->NTopen_pathp);
5852 /* Don't jump the gun on an async raw write */
5853 while (fidp->raw_writers) {
5854 lock_ReleaseMutex(&fidp->mx);
5855 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5856 lock_ObtainMutex(&fidp->mx);
5859 /* watch for ioctl closes, and read-only opens */
5861 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5862 == SMB_FID_OPENWRITE) {
5863 if (dosTime != 0 && dosTime != -1) {
5864 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5865 /* This fixes defect 10958 */
5866 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5867 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5869 if (smb_AsyncStore != 2) {
5870 lock_ReleaseMutex(&fidp->mx);
5871 code = cm_FSync(scp, userp, &req);
5872 lock_ObtainMutex(&fidp->mx);
5878 /* unlock any pending locks */
5879 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5880 scp->fileType == CM_SCACHETYPE_FILE) {
5884 lock_ReleaseMutex(&fidp->mx);
5886 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5888 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5889 lock_ObtainMutex(&scp->mx);
5891 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5892 CM_SCACHESYNC_NEEDCALLBACK
5893 | CM_SCACHESYNC_GETSTATUS
5894 | CM_SCACHESYNC_LOCK);
5898 "smb CoreClose SyncOp failure code 0x%x", tcode);
5899 goto post_syncopdone;
5902 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5904 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5908 lock_ReleaseMutex(&scp->mx);
5909 lock_ObtainMutex(&fidp->mx);
5912 if (fidp->flags & SMB_FID_DELONCLOSE) {
5915 lock_ReleaseMutex(&fidp->mx);
5917 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
5922 smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
5923 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5924 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5927 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5928 smb_NotifyChange(FILE_ACTION_REMOVED,
5929 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5930 dscp, fullPathp, NULL, TRUE);
5933 code = cm_Unlink(dscp, fullPathp, userp, &req);
5936 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5937 smb_NotifyChange(FILE_ACTION_REMOVED,
5938 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5939 dscp, fullPathp, NULL, TRUE);
5943 lock_ObtainMutex(&fidp->mx);
5944 fidp->flags &= ~SMB_FID_DELONCLOSE;
5947 /* if this was a newly created file, then clear the creator
5948 * in the stat cache entry. */
5949 if (fidp->flags & SMB_FID_CREATED) {
5951 fidp->flags &= ~SMB_FID_CREATED;
5954 if (fidp->flags & SMB_FID_NTOPEN) {
5955 cm_ReleaseSCache(fidp->NTopen_dscp);
5956 fidp->NTopen_dscp = NULL;
5957 free(fidp->NTopen_pathp);
5958 fidp->NTopen_pathp = NULL;
5959 fidp->flags &= ~SMB_FID_NTOPEN;
5961 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
5962 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
5965 if (fidp->NTopen_wholepathp) {
5966 free(fidp->NTopen_wholepathp);
5967 fidp->NTopen_wholepathp = NULL;
5971 cm_ReleaseSCache(fidp->scp);
5974 lock_ReleaseMutex(&fidp->mx);
5977 cm_ReleaseSCache(dscp);
5981 lock_ObtainMutex(&delscp->mx);
5983 delscp->flags |= CM_SCACHEFLAG_DELETED;
5984 lock_ReleaseMutex(&delscp->mx);
5986 cm_ReleaseSCache(delscp);
5990 lock_ObtainMutex(&scp->mx);
5991 if (nullcreator && scp->creator == userp)
5992 scp->creator = NULL;
5993 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5994 lock_ReleaseMutex(&scp->mx);
5995 cm_ReleaseSCache(scp);
6004 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6012 fid = smb_GetSMBParm(inp, 0);
6013 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6015 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6017 fid = smb_ChainFID(fid, inp);
6018 fidp = smb_FindFID(vcp, fid, 0);
6020 return CM_ERROR_BADFD;
6023 userp = smb_GetUserFromVCP(vcp, inp);
6025 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6027 smb_ReleaseFID(fidp);
6028 cm_ReleaseUser(userp);
6033 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6035 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6036 cm_user_t *userp, long *readp)
6042 osi_hyper_t fileLength;
6044 osi_hyper_t lastByte;
6045 osi_hyper_t bufferOffset;
6049 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6057 lock_ObtainMutex(&fidp->mx);
6060 lock_ObtainMutex(&scp->mx);
6062 if (offset.HighPart == 0) {
6063 chunk = offset.LowPart >> cm_logChunkSize;
6064 if (chunk != fidp->curr_chunk) {
6065 fidp->prev_chunk = fidp->curr_chunk;
6066 fidp->curr_chunk = chunk;
6068 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6071 lock_ReleaseMutex(&fidp->mx);
6073 /* start by looking up the file's end */
6074 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6075 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6079 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6081 /* now we have the entry locked, look up the length */
6082 fileLength = scp->length;
6084 /* adjust count down so that it won't go past EOF */
6085 thyper.LowPart = count;
6086 thyper.HighPart = 0;
6087 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6089 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6090 /* we'd read past EOF, so just stop at fileLength bytes.
6091 * Start by computing how many bytes remain in the file.
6093 thyper = LargeIntegerSubtract(fileLength, offset);
6095 /* if we are past EOF, read 0 bytes */
6096 if (LargeIntegerLessThanZero(thyper))
6099 count = thyper.LowPart;
6104 /* now, copy the data one buffer at a time,
6105 * until we've filled the request packet
6108 /* if we've copied all the data requested, we're done */
6109 if (count <= 0) break;
6111 /* otherwise, load up a buffer of data */
6112 thyper.HighPart = offset.HighPart;
6113 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6114 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6117 buf_Release(bufferp);
6120 lock_ReleaseMutex(&scp->mx);
6122 code = buf_Get(scp, &thyper, &bufferp);
6124 lock_ObtainMutex(&scp->mx);
6125 if (code) goto done;
6126 bufferOffset = thyper;
6128 /* now get the data in the cache */
6130 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6131 CM_SCACHESYNC_NEEDCALLBACK |
6132 CM_SCACHESYNC_READ);
6136 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6138 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6140 /* otherwise, load the buffer and try again */
6141 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6145 buf_Release(bufferp);
6149 } /* if (wrong buffer) ... */
6151 /* now we have the right buffer loaded. Copy out the
6152 * data from here to the user's buffer.
6154 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6156 /* and figure out how many bytes we want from this buffer */
6157 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6158 if (nbytes > count) nbytes = count; /* don't go past EOF */
6160 /* now copy the data */
6161 memcpy(op, bufferp->datap + bufIndex, nbytes);
6163 /* adjust counters, pointers, etc. */
6166 thyper.LowPart = nbytes;
6167 thyper.HighPart = 0;
6168 offset = LargeIntegerAdd(thyper, offset);
6172 lock_ReleaseMutex(&scp->mx);
6174 buf_Release(bufferp);
6176 if (code == 0 && sequential)
6177 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6179 cm_ReleaseSCache(scp);
6185 * smb_WriteData -- common code for Write and Raw Write
6187 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6188 cm_user_t *userp, long *writtenp)
6190 osi_hyper_t offset = *offsetp;
6194 osi_hyper_t fileLength; /* file's length at start of write */
6195 osi_hyper_t minLength; /* don't read past this */
6196 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6197 cm_buf_t *bufferp = NULL;
6198 osi_hyper_t thyper; /* hyper tmp variable */
6199 osi_hyper_t bufferOffset;
6200 afs_uint32 bufIndex; /* index in buffer where our data is */
6201 int doWriteBack = 0;
6202 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6206 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6207 fidp->fid, offsetp->LowPart, count);
6213 lock_ObtainMutex(&fidp->mx);
6214 /* make sure we have a writable FD */
6215 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6216 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6217 fidp->fid, fidp->flags);
6218 lock_ReleaseMutex(&fidp->mx);
6219 code = CM_ERROR_BADFDOP;
6225 lock_ReleaseMutex(&fidp->mx);
6227 lock_ObtainMutex(&scp->mx);
6228 /* start by looking up the file's end */
6229 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6230 CM_SCACHESYNC_NEEDCALLBACK
6231 | CM_SCACHESYNC_SETSTATUS
6232 | CM_SCACHESYNC_GETSTATUS);
6236 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6238 /* now we have the entry locked, look up the length */
6239 fileLength = scp->length;
6240 minLength = fileLength;
6241 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6242 minLength = scp->serverLength;
6244 /* adjust file length if we extend past EOF */
6245 thyper.LowPart = count;
6246 thyper.HighPart = 0;
6247 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6248 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6249 /* we'd write past EOF, so extend the file */
6250 scp->mask |= CM_SCACHEMASK_LENGTH;
6251 scp->length = thyper;
6252 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6254 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6256 /* now, if the new position (thyper) and the old (offset) are in
6257 * different storeback windows, remember to store back the previous
6258 * storeback window when we're done with the write.
6260 * the purpose of this logic is to slow down the CIFS client
6261 * in order to avoid the client disconnecting during the CLOSE
6262 * operation if there are too many dirty buffers left to write
6263 * than can be accomplished during 45 seconds. This used to be
6264 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6265 * so that we can read larger amounts of data at a time.
6267 if (smb_AsyncStore == 1 &&
6268 (thyper.LowPart & ~(cm_data.buf_blockSize-1)) !=
6269 (offset.LowPart & ~(cm_data.buf_blockSize-1))) {
6270 /* they're different */
6272 writeBackOffset.HighPart = offset.HighPart;
6273 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
6278 /* now, copy the data one buffer at a time, until we've filled the
6281 /* if we've copied all the data requested, we're done */
6285 /* handle over quota or out of space */
6286 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6287 *writtenp = written;
6288 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6292 /* otherwise, load up a buffer of data */
6293 thyper.HighPart = offset.HighPart;
6294 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6295 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6298 lock_ReleaseMutex(&bufferp->mx);
6299 buf_Release(bufferp);
6302 lock_ReleaseMutex(&scp->mx);
6304 code = buf_Get(scp, &thyper, &bufferp);
6306 lock_ObtainMutex(&bufferp->mx);
6307 lock_ObtainMutex(&scp->mx);
6308 if (code) goto done;
6310 bufferOffset = thyper;
6312 /* now get the data in the cache */
6314 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6315 CM_SCACHESYNC_NEEDCALLBACK
6316 | CM_SCACHESYNC_WRITE
6317 | CM_SCACHESYNC_BUFLOCKED);
6321 cm_SyncOpDone(scp, bufferp,
6322 CM_SCACHESYNC_NEEDCALLBACK
6323 | CM_SCACHESYNC_WRITE
6324 | CM_SCACHESYNC_BUFLOCKED);
6326 /* If we're overwriting the entire buffer, or
6327 * if we're writing at or past EOF, mark the
6328 * buffer as current so we don't call
6329 * cm_GetBuffer. This skips the fetch from the
6330 * server in those cases where we're going to
6331 * obliterate all the data in the buffer anyway,
6332 * or in those cases where there is no useful
6333 * data at the server to start with.
6335 * Use minLength instead of scp->length, since
6336 * the latter has already been updated by this
6339 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6340 || LargeIntegerEqualTo(offset, bufferp->offset)
6341 && (count >= cm_data.buf_blockSize
6342 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6343 ConvertLongToLargeInteger(count)),
6345 if (count < cm_data.buf_blockSize
6346 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
6347 memset(bufferp->datap, 0,
6348 cm_data.buf_blockSize);
6349 bufferp->dataVersion = scp->dataVersion;
6352 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6354 /* otherwise, load the buffer and try again */
6355 lock_ReleaseMutex(&bufferp->mx);
6356 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6358 lock_ReleaseMutex(&scp->mx);
6359 lock_ObtainMutex(&bufferp->mx);
6360 lock_ObtainMutex(&scp->mx);
6364 lock_ReleaseMutex(&bufferp->mx);
6365 buf_Release(bufferp);
6369 } /* if (wrong buffer) ... */
6371 /* now we have the right buffer loaded. Copy out the
6372 * data from here to the user's buffer.
6374 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6376 /* and figure out how many bytes we want from this buffer */
6377 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6379 nbytes = count; /* don't go past end of request */
6381 /* now copy the data */
6382 memcpy(bufferp->datap + bufIndex, op, nbytes);
6383 buf_SetDirty(bufferp, bufIndex, nbytes);
6385 /* and record the last writer */
6386 if (bufferp->userp != userp) {
6389 cm_ReleaseUser(bufferp->userp);
6390 bufferp->userp = userp;
6393 /* adjust counters, pointers, etc. */
6397 thyper.LowPart = nbytes;
6398 thyper.HighPart = 0;
6399 offset = LargeIntegerAdd(thyper, offset);
6403 lock_ReleaseMutex(&scp->mx);
6406 lock_ReleaseMutex(&bufferp->mx);
6407 buf_Release(bufferp);
6410 lock_ObtainMutex(&fidp->mx);
6411 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6412 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6413 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6414 fidp->NTopen_dscp, fidp->NTopen_pathp,
6417 lock_ReleaseMutex(&fidp->mx);
6420 if (smb_AsyncStore > 0) {
6424 lock_ObtainMutex(&scp->mx);
6425 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6427 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6428 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6430 lock_ReleaseMutex(&scp->mx);
6431 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6432 writeBackOffset.HighPart,
6433 *writtenp & ~(cm_data.blockSize-1), 0, userp);
6434 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6437 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
6441 cm_ReleaseSCache(scp);
6443 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6444 fidp->fid, code, *writtenp);
6448 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6451 unsigned short count;
6453 unsigned short hint;
6454 long written = 0, total_written = 0;
6459 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6461 int inDataBlockCount;
6463 fd = smb_GetSMBParm(inp, 0);
6464 count = smb_GetSMBParm(inp, 1);
6465 offset.HighPart = 0; /* too bad */
6466 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6467 hint = smb_GetSMBParm(inp, 4);
6469 op = smb_GetSMBData(inp, NULL);
6470 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6472 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6473 fd, offset.LowPart, count);
6475 fd = smb_ChainFID(fd, inp);
6476 fidp = smb_FindFID(vcp, fd, 0);
6478 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6479 return CM_ERROR_BADFD;
6482 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6483 smb_CloseFID(vcp, fidp, NULL, 0);
6484 smb_ReleaseFID(fidp);
6485 return CM_ERROR_NOSUCHFILE;
6488 lock_ObtainMutex(&fidp->mx);
6489 if (fidp->flags & SMB_FID_IOCTL) {
6490 lock_ReleaseMutex(&fidp->mx);
6491 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6492 smb_ReleaseFID(fidp);
6493 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6496 lock_ReleaseMutex(&fidp->mx);
6497 userp = smb_GetUserFromVCP(vcp, inp);
6501 LARGE_INTEGER LOffset;
6502 LARGE_INTEGER LLength;
6504 pid = ((smb_t *) inp)->pid;
6505 key = cm_GenerateKey(vcp->vcID, pid, fd);
6507 LOffset.HighPart = offset.HighPart;
6508 LOffset.LowPart = offset.LowPart;
6509 LLength.HighPart = 0;
6510 LLength.LowPart = count;
6512 lock_ObtainMutex(&fidp->scp->mx);
6513 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6514 lock_ReleaseMutex(&fidp->scp->mx);
6517 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6522 /* special case: 0 bytes transferred means truncate to this position */
6526 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6530 truncAttr.mask = CM_ATTRMASK_LENGTH;
6531 truncAttr.length.LowPart = offset.LowPart;
6532 truncAttr.length.HighPart = 0;
6533 lock_ObtainMutex(&fidp->mx);
6534 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6535 fidp->flags |= SMB_FID_LENGTHSETDONE;
6536 lock_ReleaseMutex(&fidp->mx);
6537 smb_SetSMBParm(outp, 0, 0 /* count */);
6538 smb_SetSMBDataLength(outp, 0);
6543 * Work around bug in NT client
6545 * When copying a file, the NT client should first copy the data,
6546 * then copy the last write time. But sometimes the NT client does
6547 * these in the wrong order, so the data copies would inadvertently
6548 * cause the last write time to be overwritten. We try to detect this,
6549 * and don't set client mod time if we think that would go against the
6552 lock_ObtainMutex(&fidp->mx);
6553 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6554 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6555 fidp->scp->clientModTime = time(NULL);
6557 lock_ReleaseMutex(&fidp->mx);
6560 while ( code == 0 && count > 0 ) {
6561 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6562 if (code == 0 && written == 0)
6563 code = CM_ERROR_PARTIALWRITE;
6565 offset = LargeIntegerAdd(offset,
6566 ConvertLongToLargeInteger(written));
6567 count -= (unsigned short)written;
6568 total_written += written;
6572 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6573 total_written, code);
6575 /* set the packet data length to 3 bytes for the data block header,
6576 * plus the size of the data.
6578 smb_SetSMBParm(outp, 0, total_written);
6579 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6580 smb_SetSMBParm(outp, 3, hint);
6581 smb_SetSMBDataLength(outp, 0);
6584 smb_ReleaseFID(fidp);
6585 cm_ReleaseUser(userp);
6590 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6591 NCB *ncbp, raw_write_cont_t *rwcp)
6600 fd = smb_GetSMBParm(inp, 0);
6601 fidp = smb_FindFID(vcp, fd, 0);
6603 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6604 smb_CloseFID(vcp, fidp, NULL, 0);
6605 smb_ReleaseFID(fidp);
6609 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6610 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6612 userp = smb_GetUserFromVCP(vcp, inp);
6615 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6617 if (rwcp->writeMode & 0x1) { /* synchronous */
6620 smb_FormatResponsePacket(vcp, inp, outp);
6621 op = (smb_t *) outp;
6622 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6623 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6624 smb_SetSMBDataLength(outp, 0);
6625 smb_SendPacket(vcp, outp);
6626 smb_FreePacket(outp);
6628 else { /* asynchronous */
6629 lock_ObtainMutex(&fidp->mx);
6630 fidp->raw_writers--;
6631 if (fidp->raw_writers == 0)
6632 thrd_SetEvent(fidp->raw_write_event);
6633 lock_ReleaseMutex(&fidp->mx);
6636 /* Give back raw buffer */
6637 lock_ObtainMutex(&smb_RawBufLock);
6638 *((char **)rawBuf) = smb_RawBufs;
6639 smb_RawBufs = rawBuf;
6640 lock_ReleaseMutex(&smb_RawBufLock);
6642 smb_ReleaseFID(fidp);
6643 cm_ReleaseUser(userp);
6646 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6651 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6654 long count, written = 0, total_written = 0;
6661 unsigned short writeMode;
6663 fd = smb_GetSMBParm(inp, 0);
6664 totalCount = smb_GetSMBParm(inp, 1);
6665 count = smb_GetSMBParm(inp, 10);
6666 writeMode = smb_GetSMBParm(inp, 7);
6668 op = (char *) inp->data;
6669 op += smb_GetSMBParm(inp, 11);
6671 offset.HighPart = 0;
6672 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6674 if (*inp->wctp == 14) {
6675 /* we received a 64-bit file offset */
6676 #ifdef AFS_LARGEFILES
6677 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6679 if (LargeIntegerLessThanZero(offset)) {
6681 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6682 offset.HighPart, offset.LowPart);
6683 return CM_ERROR_BADSMB;
6686 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6688 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6689 return CM_ERROR_BADSMB;
6692 offset.HighPart = 0;
6695 offset.HighPart = 0; /* 32-bit file offset */
6699 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6700 fd, offset.HighPart, offset.LowPart, count);
6702 " WriteRaw WriteMode 0x%x",
6705 fd = smb_ChainFID(fd, inp);
6706 fidp = smb_FindFID(vcp, fd, 0);
6708 return CM_ERROR_BADFD;
6711 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6712 smb_CloseFID(vcp, fidp, NULL, 0);
6713 smb_ReleaseFID(fidp);
6714 return CM_ERROR_NOSUCHFILE;
6720 LARGE_INTEGER LOffset;
6721 LARGE_INTEGER LLength;
6723 pid = ((smb_t *) inp)->pid;
6724 key = cm_GenerateKey(vcp->vcID, pid, fd);
6726 LOffset.HighPart = offset.HighPart;
6727 LOffset.LowPart = offset.LowPart;
6728 LLength.HighPart = 0;
6729 LLength.LowPart = count;
6731 lock_ObtainMutex(&fidp->scp->mx);
6732 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6733 lock_ReleaseMutex(&fidp->scp->mx);
6736 smb_ReleaseFID(fidp);
6741 userp = smb_GetUserFromVCP(vcp, inp);
6744 * Work around bug in NT client
6746 * When copying a file, the NT client should first copy the data,
6747 * then copy the last write time. But sometimes the NT client does
6748 * these in the wrong order, so the data copies would inadvertently
6749 * cause the last write time to be overwritten. We try to detect this,
6750 * and don't set client mod time if we think that would go against the
6753 lock_ObtainMutex(&fidp->mx);
6754 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6755 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6756 fidp->scp->clientModTime = time(NULL);
6758 lock_ReleaseMutex(&fidp->mx);
6761 while ( code == 0 && count > 0 ) {
6762 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6763 if (code == 0 && written == 0)
6764 code = CM_ERROR_PARTIALWRITE;
6766 offset = LargeIntegerAdd(offset,
6767 ConvertLongToLargeInteger(written));
6770 total_written += written;
6774 /* Get a raw buffer */
6777 lock_ObtainMutex(&smb_RawBufLock);
6779 /* Get a raw buf, from head of list */
6780 rawBuf = smb_RawBufs;
6781 smb_RawBufs = *(char **)smb_RawBufs;
6784 code = CM_ERROR_USESTD;
6786 lock_ReleaseMutex(&smb_RawBufLock);
6789 /* Don't allow a premature Close */
6790 if (code == 0 && (writeMode & 1) == 0) {
6791 lock_ObtainMutex(&fidp->mx);
6792 fidp->raw_writers++;
6793 thrd_ResetEvent(fidp->raw_write_event);
6794 lock_ReleaseMutex(&fidp->mx);
6797 smb_ReleaseFID(fidp);
6798 cm_ReleaseUser(userp);
6801 smb_SetSMBParm(outp, 0, total_written);
6802 smb_SetSMBDataLength(outp, 0);
6803 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6808 offset = LargeIntegerAdd(offset,
6809 ConvertLongToLargeInteger(count));
6813 rwcp->offset.HighPart = offset.HighPart;
6814 rwcp->offset.LowPart = offset.LowPart;
6815 rwcp->count = totalCount - count;
6816 rwcp->writeMode = writeMode;
6817 rwcp->alreadyWritten = total_written;
6819 /* set the packet data length to 3 bytes for the data block header,
6820 * plus the size of the data.
6822 smb_SetSMBParm(outp, 0, 0xffff);
6823 smb_SetSMBDataLength(outp, 0);
6828 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6831 long count, finalCount;
6839 fd = smb_GetSMBParm(inp, 0);
6840 count = smb_GetSMBParm(inp, 1);
6841 offset.HighPart = 0; /* too bad */
6842 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6844 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6845 fd, offset.LowPart, count);
6847 fd = smb_ChainFID(fd, inp);
6848 fidp = smb_FindFID(vcp, fd, 0);
6850 return CM_ERROR_BADFD;
6852 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6853 smb_CloseFID(vcp, fidp, NULL, 0);
6854 smb_ReleaseFID(fidp);
6855 return CM_ERROR_NOSUCHFILE;
6858 lock_ObtainMutex(&fidp->mx);
6859 if (fidp->flags & SMB_FID_IOCTL) {
6860 lock_ReleaseMutex(&fidp->mx);
6861 code = smb_IoctlRead(fidp, vcp, inp, outp);
6862 smb_ReleaseFID(fidp);
6865 lock_ReleaseMutex(&fidp->mx);
6868 LARGE_INTEGER LOffset, LLength;
6871 pid = ((smb_t *) inp)->pid;
6872 key = cm_GenerateKey(vcp->vcID, pid, fd);
6874 LOffset.HighPart = 0;
6875 LOffset.LowPart = offset.LowPart;
6876 LLength.HighPart = 0;
6877 LLength.LowPart = count;
6879 lock_ObtainMutex(&fidp->scp->mx);
6880 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6881 lock_ReleaseMutex(&fidp->scp->mx);
6884 smb_ReleaseFID(fidp);
6888 userp = smb_GetUserFromVCP(vcp, inp);
6890 /* remember this for final results */
6891 smb_SetSMBParm(outp, 0, count);
6892 smb_SetSMBParm(outp, 1, 0);
6893 smb_SetSMBParm(outp, 2, 0);
6894 smb_SetSMBParm(outp, 3, 0);
6895 smb_SetSMBParm(outp, 4, 0);
6897 /* set the packet data length to 3 bytes for the data block header,
6898 * plus the size of the data.
6900 smb_SetSMBDataLength(outp, count+3);
6902 /* get op ptr after putting in the parms, since otherwise we don't
6903 * know where the data really is.
6905 op = smb_GetSMBData(outp, NULL);
6907 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6908 *op++ = 1; /* data block marker */
6909 *op++ = (unsigned char) (count & 0xff);
6910 *op++ = (unsigned char) ((count >> 8) & 0xff);
6912 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6914 /* fix some things up */
6915 smb_SetSMBParm(outp, 0, finalCount);
6916 smb_SetSMBDataLength(outp, finalCount+3);
6918 smb_ReleaseFID(fidp);
6920 cm_ReleaseUser(userp);
6924 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6931 cm_scache_t *dscp; /* dir we're dealing with */
6932 cm_scache_t *scp; /* file we're creating */
6934 int initialModeBits;
6944 /* compute initial mode bits based on read-only flag in attributes */
6945 initialModeBits = 0777;
6947 tp = smb_GetSMBData(inp, NULL);
6948 pathp = smb_ParseASCIIBlock(tp, &tp);
6949 if (smb_StoreAnsiFilenames)
6950 OemToChar(pathp,pathp);
6952 if (strcmp(pathp, "\\") == 0)
6953 return CM_ERROR_EXISTS;
6955 spacep = inp->spacep;
6956 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6958 userp = smb_GetUserFromVCP(vcp, inp);
6960 caseFold = CM_FLAG_CASEFOLD;
6962 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6964 cm_ReleaseUser(userp);
6965 return CM_ERROR_NOSUCHPATH;
6968 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6969 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6970 userp, tidPathp, &req, &dscp);
6973 cm_ReleaseUser(userp);
6978 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6979 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
6980 cm_ReleaseSCache(dscp);
6981 cm_ReleaseUser(userp);
6982 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6983 return CM_ERROR_PATH_NOT_COVERED;
6985 return CM_ERROR_BADSHARENAME;
6987 #endif /* DFS_SUPPORT */
6989 /* otherwise, scp points to the parent directory. Do a lookup, and
6990 * fail if we find it. Otherwise, we do the create.
6996 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6997 if (scp) cm_ReleaseSCache(scp);
6998 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6999 if (code == 0) code = CM_ERROR_EXISTS;
7000 cm_ReleaseSCache(dscp);
7001 cm_ReleaseUser(userp);
7005 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7006 setAttr.clientModTime = time(NULL);
7007 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7008 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7009 smb_NotifyChange(FILE_ACTION_ADDED,
7010 FILE_NOTIFY_CHANGE_DIR_NAME,
7011 dscp, lastNamep, NULL, TRUE);
7013 /* we don't need this any longer */
7014 cm_ReleaseSCache(dscp);
7017 /* something went wrong creating or truncating the file */
7018 cm_ReleaseUser(userp);
7022 /* otherwise we succeeded */
7023 smb_SetSMBDataLength(outp, 0);
7024 cm_ReleaseUser(userp);
7029 BOOL smb_IsLegalFilename(char *filename)
7032 * Find the longest substring of filename that does not contain
7033 * any of the chars in illegalChars. If that substring is less
7034 * than the length of the whole string, then one or more of the
7035 * illegal chars is in filename.
7037 if (strcspn(filename, illegalChars) < strlen(filename))
7043 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7051 cm_scache_t *dscp; /* dir we're dealing with */
7052 cm_scache_t *scp; /* file we're creating */
7054 int initialModeBits;
7062 int created = 0; /* the file was new */
7067 excl = (inp->inCom == 0x03)? 0 : 1;
7069 attributes = smb_GetSMBParm(inp, 0);
7070 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7072 /* compute initial mode bits based on read-only flag in attributes */
7073 initialModeBits = 0666;
7074 if (attributes & SMB_ATTR_READONLY)
7075 initialModeBits &= ~0222;
7077 tp = smb_GetSMBData(inp, NULL);
7078 pathp = smb_ParseASCIIBlock(tp, &tp);
7079 if (smb_StoreAnsiFilenames)
7080 OemToChar(pathp,pathp);
7082 spacep = inp->spacep;
7083 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7085 userp = smb_GetUserFromVCP(vcp, inp);
7087 caseFold = CM_FLAG_CASEFOLD;
7089 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7091 cm_ReleaseUser(userp);
7092 return CM_ERROR_NOSUCHPATH;
7094 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7095 userp, tidPathp, &req, &dscp);
7098 cm_ReleaseUser(userp);
7103 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7104 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7105 cm_ReleaseSCache(dscp);
7106 cm_ReleaseUser(userp);
7107 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7108 return CM_ERROR_PATH_NOT_COVERED;
7110 return CM_ERROR_BADSHARENAME;
7112 #endif /* DFS_SUPPORT */
7114 /* otherwise, scp points to the parent directory. Do a lookup, and
7115 * truncate the file if we find it, otherwise we create the file.
7122 if (!smb_IsLegalFilename(lastNamep))
7123 return CM_ERROR_BADNTFILENAME;
7125 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7126 #ifdef DEBUG_VERBOSE
7129 hexp = osi_HexifyString( lastNamep );
7130 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7135 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7136 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7137 cm_ReleaseSCache(dscp);
7138 cm_ReleaseUser(userp);
7142 /* if we get here, if code is 0, the file exists and is represented by
7143 * scp. Otherwise, we have to create it.
7147 /* oops, file shouldn't be there */
7148 cm_ReleaseSCache(dscp);
7149 cm_ReleaseSCache(scp);
7150 cm_ReleaseUser(userp);
7151 return CM_ERROR_EXISTS;
7154 setAttr.mask = CM_ATTRMASK_LENGTH;
7155 setAttr.length.LowPart = 0;
7156 setAttr.length.HighPart = 0;
7157 code = cm_SetAttr(scp, &setAttr, userp, &req);
7160 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7161 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7162 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7166 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7167 smb_NotifyChange(FILE_ACTION_ADDED,
7168 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7169 dscp, lastNamep, NULL, TRUE);
7170 } else if (!excl && code == CM_ERROR_EXISTS) {
7171 /* not an exclusive create, and someone else tried
7172 * creating it already, then we open it anyway. We
7173 * don't bother retrying after this, since if this next
7174 * fails, that means that the file was deleted after
7175 * we started this call.
7177 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7180 setAttr.mask = CM_ATTRMASK_LENGTH;
7181 setAttr.length.LowPart = 0;
7182 setAttr.length.HighPart = 0;
7183 code = cm_SetAttr(scp, &setAttr, userp, &req);
7188 /* we don't need this any longer */
7189 cm_ReleaseSCache(dscp);
7192 /* something went wrong creating or truncating the file */
7193 if (scp) cm_ReleaseSCache(scp);
7194 cm_ReleaseUser(userp);
7198 /* make sure we only open files */
7199 if (scp->fileType != CM_SCACHETYPE_FILE) {
7200 cm_ReleaseSCache(scp);
7201 cm_ReleaseUser(userp);
7202 return CM_ERROR_ISDIR;
7205 /* now all we have to do is open the file itself */
7206 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7207 osi_assertx(fidp, "null smb_fid_t");
7211 lock_ObtainMutex(&fidp->mx);
7212 /* always create it open for read/write */
7213 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7215 /* remember that the file was newly created */
7217 fidp->flags |= SMB_FID_CREATED;
7219 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7221 /* save a pointer to the vnode */
7223 lock_ObtainMutex(&scp->mx);
7224 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7225 lock_ReleaseMutex(&scp->mx);
7228 fidp->userp = userp;
7229 lock_ReleaseMutex(&fidp->mx);
7231 smb_SetSMBParm(outp, 0, fidp->fid);
7232 smb_SetSMBDataLength(outp, 0);
7234 cm_Open(scp, 0, userp);
7236 smb_ReleaseFID(fidp);
7237 cm_ReleaseUser(userp);
7238 /* leave scp held since we put it in fidp->scp */
7242 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7245 osi_hyper_t new_offset;
7256 fd = smb_GetSMBParm(inp, 0);
7257 whence = smb_GetSMBParm(inp, 1);
7258 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7260 /* try to find the file descriptor */
7261 fd = smb_ChainFID(fd, inp);
7262 fidp = smb_FindFID(vcp, fd, 0);
7264 return CM_ERROR_BADFD;
7266 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7267 smb_CloseFID(vcp, fidp, NULL, 0);
7268 smb_ReleaseFID(fidp);
7269 return CM_ERROR_NOSUCHFILE;
7272 lock_ObtainMutex(&fidp->mx);
7273 if (fidp->flags & SMB_FID_IOCTL) {
7274 lock_ReleaseMutex(&fidp->mx);
7275 smb_ReleaseFID(fidp);
7276 return CM_ERROR_BADFD;
7278 lock_ReleaseMutex(&fidp->mx);
7280 userp = smb_GetUserFromVCP(vcp, inp);
7282 lock_ObtainMutex(&fidp->mx);
7285 lock_ReleaseMutex(&fidp->mx);
7286 lock_ObtainMutex(&scp->mx);
7287 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7288 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7290 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7292 /* offset from current offset */
7293 new_offset = LargeIntegerAdd(fidp->offset,
7294 ConvertLongToLargeInteger(offset));
7296 else if (whence == 2) {
7297 /* offset from current EOF */
7298 new_offset = LargeIntegerAdd(scp->length,
7299 ConvertLongToLargeInteger(offset));
7301 new_offset = ConvertLongToLargeInteger(offset);
7304 fidp->offset = new_offset;
7305 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7306 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7307 smb_SetSMBDataLength(outp, 0);
7309 lock_ReleaseMutex(&scp->mx);
7310 smb_ReleaseFID(fidp);
7311 cm_ReleaseSCache(scp);
7312 cm_ReleaseUser(userp);
7316 /* dispatch all of the requests received in a packet. Due to chaining, this may
7317 * be more than one request.
7319 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7320 NCB *ncbp, raw_write_cont_t *rwcp)
7324 unsigned long code = 0;
7325 unsigned char *outWctp;
7326 int nparms; /* # of bytes of parameters */
7328 int nbytes; /* bytes of data, excluding count */
7331 unsigned short errCode;
7332 unsigned long NTStatus;
7334 unsigned char errClass;
7335 unsigned int oldGen;
7336 DWORD oldTime, newTime;
7338 /* get easy pointer to the data */
7339 smbp = (smb_t *) inp->data;
7341 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7342 /* setup the basic parms for the initial request in the packet */
7343 inp->inCom = smbp->com;
7344 inp->wctp = &smbp->wct;
7346 inp->ncb_length = ncbp->ncb_length;
7351 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7352 /* log it and discard it */
7353 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7354 __FILE__, __LINE__, ncbp->ncb_length);
7355 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7359 /* We are an ongoing op */
7360 thrd_Increment(&ongoingOps);
7362 /* set up response packet for receiving output */
7363 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7364 smb_FormatResponsePacket(vcp, inp, outp);
7365 outWctp = outp->wctp;
7367 /* Remember session generation number and time */
7368 oldGen = sessionGen;
7369 oldTime = GetTickCount();
7371 while (inp->inCom != 0xff) {
7372 dp = &smb_dispatchTable[inp->inCom];
7374 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7375 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7376 code = outp->resumeCode;
7380 /* process each request in the packet; inCom, wctp and inCount
7381 * are already set up.
7383 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7386 /* now do the dispatch */
7387 /* start by formatting the response record a little, as a default */
7388 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7390 outWctp[1] = 0xff; /* no operation */
7391 outWctp[2] = 0; /* padding */
7396 /* not a chained request, this is a more reasonable default */
7397 outWctp[0] = 0; /* wct of zero */
7398 outWctp[1] = 0; /* and bcc (word) of zero */
7402 /* once set, stays set. Doesn't matter, since we never chain
7403 * "no response" calls.
7405 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7409 /* we have a recognized operation */
7410 char * opName = myCrt_Dispatch(inp->inCom);
7412 if (inp->inCom == 0x1d)
7414 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7416 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",opName,vcp,vcp->lana,vcp->lsn);
7417 code = (*(dp->procp)) (vcp, inp, outp);
7418 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7420 if ( code == CM_ERROR_BADSMB ||
7421 code == CM_ERROR_BADOP )
7423 #endif /* LOG_PACKET */
7426 newTime = GetTickCount();
7427 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
7429 if (oldGen != sessionGen) {
7430 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7431 newTime - oldTime, ncbp->ncb_length);
7432 osi_Log3(smb_logp, "Request %s straddled session startup, "
7433 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
7437 /* bad opcode, fail the request, after displaying it */
7438 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7441 #endif /* LOG_PACKET */
7444 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7445 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7446 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7447 if (code == IDCANCEL)
7450 code = CM_ERROR_BADOP;
7453 /* catastrophic failure: log as much as possible */
7454 if (code == CM_ERROR_BADSMB) {
7455 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7459 #endif /* LOG_PACKET */
7460 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7463 code = CM_ERROR_INVAL;
7466 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7467 thrd_Decrement(&ongoingOps);
7472 /* now, if we failed, turn the current response into an empty
7473 * one, and fill in the response packet's error code.
7476 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7477 smb_MapNTError(code, &NTStatus);
7478 outWctp = outp->wctp;
7479 smbp = (smb_t *) &outp->data;
7480 if (code != CM_ERROR_PARTIALWRITE
7481 && code != CM_ERROR_BUFFERTOOSMALL
7482 && code != CM_ERROR_GSSCONTINUE) {
7483 /* nuke wct and bcc. For a partial
7484 * write or an in-process authentication handshake,
7485 * assume they're OK.
7491 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7492 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7493 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7494 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7495 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7499 smb_MapCoreError(code, vcp, &errCode, &errClass);
7500 outWctp = outp->wctp;
7501 smbp = (smb_t *) &outp->data;
7502 if (code != CM_ERROR_PARTIALWRITE) {
7503 /* nuke wct and bcc. For a partial
7504 * write, assume they're OK.
7510 smbp->errLow = (unsigned char) (errCode & 0xff);
7511 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7512 smbp->rcls = errClass;
7515 } /* error occurred */
7517 /* if we're here, we've finished one request. Look to see if
7518 * this is a chained opcode. If it is, setup things to process
7519 * the chained request, and setup the output buffer to hold the
7520 * chained response. Start by finding the next input record.
7522 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7523 break; /* not a chained req */
7524 tp = inp->wctp; /* points to start of last request */
7525 /* in a chained request, the first two
7526 * parm fields are required, and are
7527 * AndXCommand/AndXReserved and
7529 if (tp[0] < 2) break;
7530 if (tp[1] == 0xff) break; /* no more chained opcodes */
7532 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7535 /* and now append the next output request to the end of this
7536 * last request. Begin by finding out where the last response
7537 * ends, since that's where we'll put our new response.
7539 outWctp = outp->wctp; /* ptr to out parameters */
7540 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7541 nparms = outWctp[0] << 1;
7542 tp = outWctp + nparms + 1; /* now points to bcc field */
7543 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7544 tp += 2 /* for the count itself */ + nbytes;
7545 /* tp now points to the new output record; go back and patch the
7546 * second parameter (off2) to point to the new record.
7548 temp = (unsigned int)(tp - outp->data);
7549 outWctp[3] = (unsigned char) (temp & 0xff);
7550 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7551 outWctp[2] = 0; /* padding */
7552 outWctp[1] = inp->inCom; /* next opcode */
7554 /* finally, setup for the next iteration */
7557 } /* while loop over all requests in the packet */
7559 /* now send the output packet, and return */
7561 smb_SendPacket(vcp, outp);
7562 thrd_Decrement(&ongoingOps);
7567 /* Wait for Netbios() calls to return, and make the results available to server
7568 * threads. Note that server threads can't wait on the NCBevents array
7569 * themselves, because NCB events are manual-reset, and the servers would race
7570 * each other to reset them.
7572 void smb_ClientWaiter(void *parmp)
7577 while (smbShutdownFlag == 0) {
7578 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7580 if (code == WAIT_OBJECT_0)
7583 /* error checking */
7584 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7586 int abandonIdx = code - WAIT_ABANDONED_0;
7587 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7590 if (code == WAIT_IO_COMPLETION)
7592 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7596 if (code == WAIT_TIMEOUT)
7598 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7601 if (code == WAIT_FAILED)
7603 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7606 idx = code - WAIT_OBJECT_0;
7608 /* check idx range! */
7609 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7611 /* this is fatal - log as much as possible */
7612 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7613 osi_assertx(0, "invalid index");
7616 thrd_ResetEvent(NCBevents[idx]);
7617 thrd_SetEvent(NCBreturns[0][idx]);
7622 * Try to have one NCBRECV request waiting for every live session. Not more
7623 * than one, because if there is more than one, it's hard to handle Write Raw.
7625 void smb_ServerWaiter(void *parmp)
7628 int idx_session, idx_NCB;
7631 while (smbShutdownFlag == 0) {
7633 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7635 if (code == WAIT_OBJECT_0)
7638 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7640 int abandonIdx = code - WAIT_ABANDONED_0;
7641 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7644 if (code == WAIT_IO_COMPLETION)
7646 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7650 if (code == WAIT_TIMEOUT)
7652 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7655 if (code == WAIT_FAILED)
7657 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7660 idx_session = code - WAIT_OBJECT_0;
7662 /* check idx range! */
7663 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7665 /* this is fatal - log as much as possible */
7666 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7667 osi_assertx(0, "invalid index");
7672 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7674 if (code == WAIT_OBJECT_0) {
7675 if (smbShutdownFlag == 1)
7681 /* error checking */
7682 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7684 int abandonIdx = code - WAIT_ABANDONED_0;
7685 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7688 if (code == WAIT_IO_COMPLETION)
7690 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7694 if (code == WAIT_TIMEOUT)
7696 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7699 if (code == WAIT_FAILED)
7701 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7704 idx_NCB = code - WAIT_OBJECT_0;
7706 /* check idx range! */
7707 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7709 /* this is fatal - log as much as possible */
7710 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7711 osi_assertx(0, "invalid index");
7714 /* Link them together */
7715 NCBsessions[idx_NCB] = idx_session;
7718 ncbp = NCBs[idx_NCB];
7719 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7720 ncbp->ncb_command = NCBRECV | ASYNCH;
7721 ncbp->ncb_lana_num = lanas[idx_session];
7722 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7723 ncbp->ncb_event = NCBevents[idx_NCB];
7724 ncbp->ncb_length = SMB_PACKETSIZE;
7730 * The top level loop for handling SMB request messages. Each server thread
7731 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7732 * NCB and buffer for the incoming request are loaned to us.
7734 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7735 * to immediately send a request for the rest of the data. This must come
7736 * before any other traffic for that session, so we delay setting the session
7737 * event until that data has come in.
7739 void smb_Server(VOID *parmp)
7741 INT_PTR myIdx = (INT_PTR) parmp;
7745 smb_packet_t *outbufp;
7747 int idx_NCB, idx_session;
7749 smb_vc_t *vcp = NULL;
7752 rx_StartClientThread();
7755 outbufp = GetPacket();
7756 outbufp->ncbp = outncbp;
7764 smb_ResetServerPriority();
7766 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7769 /* terminate silently if shutdown flag is set */
7770 if (code == WAIT_OBJECT_0) {
7771 if (smbShutdownFlag == 1) {
7772 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7778 /* error checking */
7779 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7781 int abandonIdx = code - WAIT_ABANDONED_0;
7782 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7785 if (code == WAIT_IO_COMPLETION)
7787 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7791 if (code == WAIT_TIMEOUT)
7793 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7796 if (code == WAIT_FAILED)
7798 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7801 idx_NCB = code - WAIT_OBJECT_0;
7803 /* check idx range! */
7804 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7806 /* this is fatal - log as much as possible */
7807 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7808 osi_assertx(0, "invalid index");
7811 ncbp = NCBs[idx_NCB];
7812 idx_session = NCBsessions[idx_NCB];
7813 rc = ncbp->ncb_retcode;
7815 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7816 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7820 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7824 /* Can this happen? Or is it just my UNIX paranoia? */
7825 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7830 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7833 /* Client closed session */
7834 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7836 lock_ObtainMutex(&vcp->mx);
7837 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7838 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7840 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7841 lock_ReleaseMutex(&vcp->mx);
7842 lock_ObtainWrite(&smb_globalLock);
7843 dead_sessions[vcp->session] = TRUE;
7844 lock_ReleaseWrite(&smb_globalLock);
7845 smb_CleanupDeadVC(vcp);
7849 lock_ReleaseMutex(&vcp->mx);
7855 /* Treat as transient error */
7856 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7859 "dispatch smb recv failed, message incomplete, ncb_length %d",
7862 "SMB message incomplete, "
7863 "length %d", ncbp->ncb_length);
7866 * We used to discard the packet.
7867 * Instead, try handling it normally.
7871 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7875 /* A weird error code. Log it, sleep, and continue. */
7876 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7878 lock_ObtainMutex(&vcp->mx);
7879 if (vcp && vcp->errorCount++ > 3) {
7880 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7881 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7882 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7884 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7885 lock_ReleaseMutex(&vcp->mx);
7886 lock_ObtainWrite(&smb_globalLock);
7887 dead_sessions[vcp->session] = TRUE;
7888 lock_ReleaseWrite(&smb_globalLock);
7889 smb_CleanupDeadVC(vcp);
7893 lock_ReleaseMutex(&vcp->mx);
7899 lock_ReleaseMutex(&vcp->mx);
7901 thrd_SetEvent(SessionEvents[idx_session]);
7906 /* Success, so now dispatch on all the data in the packet */
7908 smb_concurrentCalls++;
7909 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7910 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7913 * If at this point vcp is NULL (implies that packet was invalid)
7914 * then we are in big trouble. This means either :
7915 * a) we have the wrong NCB.
7916 * b) Netbios screwed up the call.
7917 * c) The VC was already marked dead before we were able to
7919 * Obviously this implies that
7920 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7921 * lanas[idx_session] != ncbp->ncb_lana_num )
7922 * Either way, we can't do anything with this packet.
7923 * Log, sleep and resume.
7926 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7930 ncbp->ncb_lana_num);
7932 /* Also log in the trace log. */
7933 osi_Log4(smb_logp, "Server: VCP does not exist!"
7934 "LSNs[idx_session]=[%d],"
7935 "lanas[idx_session]=[%d],"
7936 "ncbp->ncb_lsn=[%d],"
7937 "ncbp->ncb_lana_num=[%d]",
7941 ncbp->ncb_lana_num);
7943 /* thrd_Sleep(1000); Don't bother sleeping */
7944 thrd_SetEvent(SessionEvents[idx_session]);
7945 smb_concurrentCalls--;
7949 smb_SetRequestStartTime();
7951 vcp->errorCount = 0;
7952 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7953 smbp = (smb_t *)bufp->data;
7958 if (smbp->com == 0x1d) {
7959 /* Special handling for Write Raw */
7960 raw_write_cont_t rwc;
7961 EVENT_HANDLE rwevent;
7962 char eventName[MAX_PATH];
7964 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7965 if (rwc.code == 0) {
7966 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7967 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7968 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7969 ncbp->ncb_command = NCBRECV | ASYNCH;
7970 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7971 ncbp->ncb_lana_num = vcp->lana;
7972 ncbp->ncb_buffer = rwc.buf;
7973 ncbp->ncb_length = 65535;
7974 ncbp->ncb_event = rwevent;
7976 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7977 thrd_CloseHandle(rwevent);
7979 thrd_SetEvent(SessionEvents[idx_session]);
7981 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7983 else if (smbp->com == 0xa0) {
7985 * Serialize the handling for NT Transact
7988 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7989 thrd_SetEvent(SessionEvents[idx_session]);
7991 thrd_SetEvent(SessionEvents[idx_session]);
7992 /* TODO: what else needs to be serialized? */
7993 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7996 __except( smb_ServerExceptionFilter() ) {
7999 smb_concurrentCalls--;
8002 thrd_SetEvent(NCBavails[idx_NCB]);
8009 * Exception filter for the server threads. If an exception occurs in the
8010 * dispatch routines, which is where exceptions are most common, then do a
8011 * force trace and give control to upstream exception handlers. Useful for
8014 DWORD smb_ServerExceptionFilter(void) {
8015 /* While this is not the best time to do a trace, if it succeeds, then
8016 * we have a trace (assuming tracing was enabled). Otherwise, this should
8017 * throw a second exception.
8019 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8020 afsd_ForceTrace(TRUE);
8021 buf_ForceTrace(TRUE);
8022 return EXCEPTION_CONTINUE_SEARCH;
8026 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8027 * If the number of server threads is M, and the number of live sessions is
8028 * N, then the number of NCB's in use at any time either waiting for, or
8029 * holding, received messages is M + N, so that is how many NCB's get created.
8031 void InitNCBslot(int idx)
8033 struct smb_packet *bufp;
8034 EVENT_HANDLE retHandle;
8036 char eventName[MAX_PATH];
8038 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8040 NCBs[idx] = GetNCB();
8041 sprintf(eventName,"NCBavails[%d]", idx);
8042 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8043 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8044 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8045 sprintf(eventName,"NCBevents[%d]", idx);
8046 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8047 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8048 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8049 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8050 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8051 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8052 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8053 for (i=0; i<smb_NumServerThreads; i++)
8054 NCBreturns[i][idx] = retHandle;
8056 bufp->spacep = cm_GetSpace();
8060 /* listen for new connections */
8061 void smb_Listener(void *parmp)
8067 afs_uint32 session, thread;
8068 smb_vc_t *vcp = NULL;
8070 char rname[NCBNAMSZ+1];
8071 char cname[MAX_COMPUTERNAME_LENGTH+1];
8072 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8073 INT_PTR lana = (INT_PTR) parmp;
8074 char eventName[MAX_PATH];
8076 sprintf(eventName,"smb_Listener_lana_%d", (char)lana);
8077 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8078 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8079 thrd_ResetEvent(ListenerShutdown[lana]);
8083 /* retrieve computer name */
8084 GetComputerName(cname, &cnamelen);
8087 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8088 memset(ncbp, 0, sizeof(NCB));
8091 ncbp->ncb_command = NCBLISTEN;
8092 ncbp->ncb_rto = 0; /* No receive timeout */
8093 ncbp->ncb_sto = 0; /* No send timeout */
8095 /* pad out with spaces instead of null termination */
8096 len = (long)strlen(smb_localNamep);
8097 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8098 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8100 strcpy(ncbp->ncb_callname, "*");
8101 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8103 ncbp->ncb_lana_num = (UCHAR)lana;
8105 code = Netbios(ncbp);
8107 if (code == NRC_NAMERR) {
8108 /* An smb shutdown or Vista resume must have taken place */
8110 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8111 ncbp->ncb_lana_num, code);
8113 if (lock_TryMutex(&smb_StartedLock)) {
8114 lana_list.lana[i] = LANA_INVALID;
8115 lock_ReleaseMutex(&smb_StartedLock);
8118 } else if (code == NRC_BRIDGE || code != 0) {
8119 int lanaRemaining = 0;
8121 while (!lock_TryMutex(&smb_StartedLock)) {
8122 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8128 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8129 ncbp->ncb_lana_num, ncb_error_string(code));
8131 for (i = 0; i < lana_list.length; i++) {
8132 if (lana_list.lana[i] == lana) {
8133 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8134 lana_list.lana[i] = LANA_INVALID;
8136 if (lana_list.lana[i] != LANA_INVALID)
8140 if (lanaRemaining == 0) {
8141 cm_VolStatus_Network_Stopped(cm_NetbiosName
8146 smb_ListenerState = SMB_LISTENER_STOPPED;
8147 smb_LANadapter = LANA_INVALID;
8148 lana_list.length = 0;
8150 lock_ReleaseMutex(&smb_StartedLock);
8154 else if (code != 0) {
8155 char tbuffer[AFSPATHMAX];
8157 /* terminate silently if shutdown flag is set */
8158 while (!lock_TryMutex(&smb_StartedLock)) {
8159 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8165 "NCBLISTEN lana=%d failed with code %d [%s]",
8166 ncbp->ncb_lana_num, code, ncb_error_string(code));
8168 "Client exiting due to network failure. Please restart client.\n");
8171 "Client exiting due to network failure. Please restart client.\n"
8172 "NCBLISTEN lana=%d failed with code %d [%s]",
8173 ncbp->ncb_lana_num, code, ncb_error_string(code));
8175 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8176 MB_OK|MB_SERVICE_NOTIFICATION);
8177 osi_panic(tbuffer, __FILE__, __LINE__);
8179 lock_ReleaseMutex(&smb_StartedLock);
8184 /* check for remote conns */
8185 /* first get remote name and insert null terminator */
8186 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8187 for (i=NCBNAMSZ; i>0; i--) {
8188 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8194 /* compare with local name */
8196 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8197 flags |= SMB_VCFLAG_REMOTECONN;
8200 lock_ObtainMutex(&smb_ListenerLock);
8202 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8203 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8205 /* now ncbp->ncb_lsn is the connection ID */
8206 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8207 if (vcp->session == 0) {
8208 /* New generation */
8209 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8212 /* Log session startup */
8214 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8215 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8216 #endif /* NOTSERVICE */
8217 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8218 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8220 if (reportSessionStartups) {
8221 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8224 lock_ObtainMutex(&vcp->mx);
8225 strcpy(vcp->rname, rname);
8226 vcp->flags |= flags;
8227 lock_ReleaseMutex(&vcp->mx);
8229 /* Allocate slot in session arrays */
8230 /* Re-use dead session if possible, otherwise add one more */
8231 /* But don't look at session[0], it is reserved */
8232 lock_ObtainWrite(&smb_globalLock);
8233 for (session = 1; session < numSessions; session++) {
8234 if (dead_sessions[session]) {
8235 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8236 dead_sessions[session] = FALSE;
8240 lock_ReleaseWrite(&smb_globalLock);
8242 /* We are re-using an existing VC because the lsn and lana
8244 session = vcp->session;
8246 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8248 /* Log session startup */
8250 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8251 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8252 #endif /* NOTSERVICE */
8253 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8254 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8256 if (reportSessionStartups) {
8257 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8261 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8262 unsigned long code = CM_ERROR_ALLBUSY;
8263 smb_packet_t * outp = GetPacket();
8264 unsigned char *outWctp;
8267 smb_FormatResponsePacket(vcp, NULL, outp);
8270 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8271 unsigned long NTStatus;
8272 smb_MapNTError(code, &NTStatus);
8273 outWctp = outp->wctp;
8274 smbp = (smb_t *) &outp->data;
8278 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8279 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8280 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8281 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8282 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8284 unsigned short errCode;
8285 unsigned char errClass;
8286 smb_MapCoreError(code, vcp, &errCode, &errClass);
8287 outWctp = outp->wctp;
8288 smbp = (smb_t *) &outp->data;
8292 smbp->errLow = (unsigned char) (errCode & 0xff);
8293 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8294 smbp->rcls = errClass;
8296 smb_SendPacket(vcp, outp);
8297 smb_FreePacket(outp);
8299 lock_ObtainMutex(&vcp->mx);
8300 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8301 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8303 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8304 lock_ReleaseMutex(&vcp->mx);
8305 lock_ObtainWrite(&smb_globalLock);
8306 dead_sessions[vcp->session] = TRUE;
8307 lock_ReleaseWrite(&smb_globalLock);
8308 smb_CleanupDeadVC(vcp);
8310 lock_ReleaseMutex(&vcp->mx);
8313 /* assert that we do not exceed the maximum number of sessions or NCBs.
8314 * we should probably want to wait for a session to be freed in case
8317 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8318 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8320 lock_ObtainMutex(&vcp->mx);
8321 vcp->session = session;
8322 lock_ReleaseMutex(&vcp->mx);
8323 lock_ObtainWrite(&smb_globalLock);
8324 LSNs[session] = ncbp->ncb_lsn;
8325 lanas[session] = ncbp->ncb_lana_num;
8326 lock_ReleaseWrite(&smb_globalLock);
8328 if (session == numSessions) {
8329 /* Add new NCB for new session */
8330 char eventName[MAX_PATH];
8332 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8334 InitNCBslot(numNCBs);
8335 lock_ObtainWrite(&smb_globalLock);
8337 lock_ReleaseWrite(&smb_globalLock);
8338 thrd_SetEvent(NCBavails[0]);
8339 thrd_SetEvent(NCBevents[0]);
8340 for (thread = 0; thread < smb_NumServerThreads; thread++)
8341 thrd_SetEvent(NCBreturns[thread][0]);
8342 /* Also add new session event */
8343 sprintf(eventName, "SessionEvents[%d]", session);
8344 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8345 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8346 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8347 lock_ObtainWrite(&smb_globalLock);
8349 lock_ReleaseWrite(&smb_globalLock);
8350 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8351 thrd_SetEvent(SessionEvents[0]);
8353 thrd_SetEvent(SessionEvents[session]);
8359 lock_ReleaseMutex(&smb_ListenerLock);
8360 } /* dispatch while loop */
8364 thrd_SetEvent(ListenerShutdown[lana]);
8369 smb_LanAdapterChangeThread(void *param)
8372 * Give the IPAddrDaemon thread a chance
8373 * to block before we trigger.
8376 smb_LanAdapterChange(0);
8379 void smb_SetLanAdapterChangeDetected(void)
8384 lock_ObtainMutex(&smb_StartedLock);
8386 if (!powerStateSuspended) {
8387 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
8388 NULL, 0, &lpid, "smb_LanAdapterChange");
8389 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
8390 thrd_CloseHandle(phandle);
8393 smb_LanAdapterChangeDetected = 1;
8394 lock_ReleaseMutex(&smb_StartedLock);
8397 void smb_LanAdapterChange(int locked) {
8398 lana_number_t lanaNum;
8400 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
8402 LANA_ENUM temp_list;
8407 afsi_log("smb_LanAdapterChange");
8410 lock_ObtainMutex(&smb_StartedLock);
8412 smb_LanAdapterChangeDetected = 0;
8414 if (!powerStateSuspended &&
8415 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
8416 LANA_NETBIOS_NAME_FULL)) &&
8417 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
8418 if ( isGateway != bGateway ||
8419 strcmp(cm_NetbiosName, NetbiosName) ) {
8422 NCB *ncbp = GetNCB();
8423 ncbp->ncb_command = NCBENUM;
8424 ncbp->ncb_buffer = (PUCHAR)&temp_list;
8425 ncbp->ncb_length = sizeof(temp_list);
8426 code = Netbios(ncbp);
8428 if (temp_list.length != lana_list.length)
8431 for (i=0; i<lana_list.length; i++) {
8432 if ( temp_list.lana[i] != lana_list.lana[i] ) {
8444 afsi_log("Lan Adapter Change detected");
8445 smb_StopListeners(1);
8446 smb_RestartListeners(1);
8449 lock_ReleaseMutex(&smb_StartedLock);
8452 /* initialize Netbios */
8453 int smb_NetbiosInit(int locked)
8456 int i, lana, code, l;
8458 int delname_tried=0;
8461 lana_number_t lanaNum;
8464 lock_ObtainMutex(&smb_StartedLock);
8466 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
8467 smb_ListenerState != SMB_LISTENER_STOPPED) {
8470 lock_ReleaseMutex(&smb_StartedLock);
8473 /* setup the NCB system */
8476 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8477 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8478 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8480 if (smb_LANadapter != LANA_INVALID)
8481 afsi_log("LAN adapter number %d", smb_LANadapter);
8483 afsi_log("LAN adapter number not determined");
8486 afsi_log("Set for gateway service");
8488 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8490 /* something went horribly wrong. We can't proceed without a netbios name */
8492 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8493 osi_panic(buf, __FILE__, __LINE__);
8496 /* remember the name */
8497 len = (int)strlen(cm_NetbiosName);
8499 free(smb_localNamep);
8500 smb_localNamep = malloc(len+1);
8501 strcpy(smb_localNamep, cm_NetbiosName);
8502 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8505 if (smb_LANadapter == LANA_INVALID) {
8506 ncbp->ncb_command = NCBENUM;
8507 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8508 ncbp->ncb_length = sizeof(lana_list);
8509 code = Netbios(ncbp);
8511 afsi_log("Netbios NCBENUM error code %d", code);
8512 osi_panic(s, __FILE__, __LINE__);
8516 lana_list.length = 1;
8517 lana_list.lana[0] = smb_LANadapter;
8520 for (i = 0; i < lana_list.length; i++) {
8521 /* reset the adaptor: in Win32, this is required for every process, and
8522 * acts as an init call, not as a real hardware reset.
8524 ncbp->ncb_command = NCBRESET;
8525 ncbp->ncb_callname[0] = 100;
8526 ncbp->ncb_callname[2] = 100;
8527 ncbp->ncb_lana_num = lana_list.lana[i];
8528 code = Netbios(ncbp);
8530 code = ncbp->ncb_retcode;
8532 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8533 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
8535 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8539 /* and declare our name so we can receive connections */
8540 memset(ncbp, 0, sizeof(*ncbp));
8541 len=lstrlen(smb_localNamep);
8542 memset(smb_sharename,' ',NCBNAMSZ);
8543 memcpy(smb_sharename,smb_localNamep,len);
8544 afsi_log("lana_list.length %d", lana_list.length);
8546 /* Keep the name so we can unregister it later */
8547 for (l = 0; l < lana_list.length; l++) {
8548 lana = lana_list.lana[l];
8550 ncbp->ncb_command = NCBADDNAME;
8551 ncbp->ncb_lana_num = lana;
8552 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8553 code = Netbios(ncbp);
8555 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8556 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8558 char name[NCBNAMSZ+1];
8560 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8561 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8565 code = ncbp->ncb_retcode;
8568 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8571 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8572 if (code == NRC_BRIDGE) { /* invalid LANA num */
8573 lana_list.lana[l] = LANA_INVALID;
8576 else if (code == NRC_DUPNAME) {
8577 afsi_log("Name already exists; try to delete it");
8578 memset(ncbp, 0, sizeof(*ncbp));
8579 ncbp->ncb_command = NCBDELNAME;
8580 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8581 ncbp->ncb_lana_num = lana;
8582 code = Netbios(ncbp);
8584 code = ncbp->ncb_retcode;
8586 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8588 if (code != 0 || delname_tried) {
8589 lana_list.lana[l] = LANA_INVALID;
8591 else if (code == 0) {
8592 if (!delname_tried) {
8600 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8601 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8605 smb_LANadapter = lana;
8606 lana_found = 1; /* at least one worked */
8610 osi_assertx(lana_list.length >= 0, "empty lana list");
8612 afsi_log("No valid LANA numbers found!");
8613 lana_list.length = 0;
8614 smb_LANadapter = LANA_INVALID;
8615 smb_ListenerState = SMB_LISTENER_STOPPED;
8616 cm_VolStatus_Network_Stopped(cm_NetbiosName
8623 /* we're done with the NCB now */
8626 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
8627 if (lana_list.length > 0)
8628 osi_assert(smb_LANadapter != LANA_INVALID);
8631 lock_ReleaseMutex(&smb_StartedLock);
8633 return (lana_list.length > 0 ? 1 : 0);
8636 void smb_StartListeners(int locked)
8643 lock_ObtainMutex(&smb_StartedLock);
8645 if (smb_ListenerState == SMB_LISTENER_STARTED) {
8647 lock_ReleaseMutex(&smb_StartedLock);
8651 afsi_log("smb_StartListeners");
8652 smb_ListenerState = SMB_LISTENER_STARTED;
8653 cm_VolStatus_Network_Started(cm_NetbiosName
8659 for (i = 0; i < lana_list.length; i++) {
8660 if (lana_list.lana[i] == LANA_INVALID)
8662 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8663 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8664 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
8665 thrd_CloseHandle(phandle);
8668 lock_ReleaseMutex(&smb_StartedLock);
8671 void smb_RestartListeners(int locked)
8674 lock_ObtainMutex(&smb_StartedLock);
8676 if (powerStateSuspended)
8677 afsi_log("smb_RestartListeners called while suspended");
8679 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
8680 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
8681 if (smb_NetbiosInit(1))
8682 smb_StartListeners(1);
8683 } else if (smb_LanAdapterChangeDetected) {
8684 smb_LanAdapterChange(1);
8688 lock_ReleaseMutex(&smb_StartedLock);
8691 void smb_StopListener(NCB *ncbp, int lana, int wait)
8695 memset(ncbp, 0, sizeof(*ncbp));
8696 ncbp->ncb_command = NCBDELNAME;
8697 ncbp->ncb_lana_num = lana;
8698 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8699 code = Netbios(ncbp);
8701 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8702 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8704 /* and then reset the LANA; this will cause the listener threads to exit */
8705 ncbp->ncb_command = NCBRESET;
8706 ncbp->ncb_callname[0] = 100;
8707 ncbp->ncb_callname[2] = 100;
8708 ncbp->ncb_lana_num = lana;
8709 code = Netbios(ncbp);
8711 code = ncbp->ncb_retcode;
8713 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8715 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8719 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
8722 void smb_StopListeners(int locked)
8728 lock_ObtainMutex(&smb_StartedLock);
8730 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
8732 lock_ReleaseMutex(&smb_StartedLock);
8736 afsi_log("smb_StopListeners");
8737 smb_ListenerState = SMB_LISTENER_STOPPED;
8738 cm_VolStatus_Network_Stopped(cm_NetbiosName
8746 /* Unregister the SMB name */
8747 for (l = 0; l < lana_list.length; l++) {
8748 lana = lana_list.lana[l];
8750 if (lana != LANA_INVALID) {
8751 smb_StopListener(ncbp, lana, TRUE);
8753 /* mark the adapter invalid */
8754 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8758 /* force a re-evaluation of the network adapters */
8759 lana_list.length = 0;
8760 smb_LANadapter = LANA_INVALID;
8763 lock_ReleaseMutex(&smb_StartedLock);
8766 void smb_Init(osi_log_t *logp, int useV3,
8776 EVENT_HANDLE retHandle;
8777 char eventName[MAX_PATH];
8778 int startListeners = 0;
8780 smb_TlsRequestSlot = TlsAlloc();
8782 smb_MBfunc = aMBfunc;
8786 /* Initialize smb_localZero */
8787 myTime.tm_isdst = -1; /* compute whether on DST or not */
8788 myTime.tm_year = 70;
8794 smb_localZero = mktime(&myTime);
8796 #ifndef USE_NUMERIC_TIME_CONV
8797 /* Initialize kludge-GMT */
8798 smb_CalculateNowTZ();
8799 #endif /* USE_NUMERIC_TIME_CONV */
8800 #ifdef AFS_FREELANCE_CLIENT
8801 /* Make sure the root.afs volume has the correct time */
8802 cm_noteLocalMountPointChange();
8805 /* initialize the remote debugging log */
8808 /* and the global lock */
8809 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8810 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8812 /* Raw I/O data structures */
8813 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8815 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8816 lock_InitializeMutex(&smb_StartedLock, "smb started lock");
8818 /* 4 Raw I/O buffers */
8819 smb_RawBufs = calloc(65536,1);
8820 *((char **)smb_RawBufs) = NULL;
8821 for (i=0; i<3; i++) {
8822 char *rawBuf = calloc(65536,1);
8823 *((char **)rawBuf) = smb_RawBufs;
8824 smb_RawBufs = rawBuf;
8827 /* global free lists */
8828 smb_ncbFreeListp = NULL;
8829 smb_packetFreeListp = NULL;
8831 lock_ObtainMutex(&smb_StartedLock);
8832 startListeners = smb_NetbiosInit(1);
8834 /* Initialize listener and server structures */
8836 memset(dead_sessions, 0, sizeof(dead_sessions));
8837 sprintf(eventName, "SessionEvents[0]");
8838 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8839 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8840 afsi_log("Event Object Already Exists: %s", eventName);
8842 smb_NumServerThreads = nThreads;
8843 sprintf(eventName, "NCBavails[0]");
8844 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8845 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8846 afsi_log("Event Object Already Exists: %s", eventName);
8847 sprintf(eventName, "NCBevents[0]");
8848 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8849 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8850 afsi_log("Event Object Already Exists: %s", eventName);
8851 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8852 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8853 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8854 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8855 afsi_log("Event Object Already Exists: %s", eventName);
8856 for (i = 0; i < smb_NumServerThreads; i++) {
8857 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8858 NCBreturns[i][0] = retHandle;
8861 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8862 for (i = 0; i < smb_NumServerThreads; i++) {
8863 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8864 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8865 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8866 afsi_log("Event Object Already Exists: %s", eventName);
8867 InitNCBslot((int)(i+1));
8869 numNCBs = smb_NumServerThreads + 1;
8871 /* Initialize dispatch table */
8872 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8873 /* Prepare the table for unknown operations */
8874 for(i=0; i<= SMB_NOPCODES; i++) {
8875 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8877 /* Fill in the ones we do know */
8878 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8879 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8880 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8881 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8882 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8883 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8884 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8885 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8886 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8887 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8888 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8889 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8890 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8891 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8892 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8893 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8894 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8895 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8896 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8897 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8898 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8899 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8900 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8901 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8902 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8903 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8904 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8905 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8906 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8907 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8908 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8909 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8910 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8911 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8912 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8913 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8914 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8915 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8916 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8917 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8918 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8919 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8920 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8921 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8922 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8923 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8924 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8925 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8926 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8927 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8928 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8929 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8930 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8931 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8932 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8933 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8934 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8935 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8936 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8937 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8938 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8939 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8940 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8941 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8942 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8943 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8944 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8945 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8946 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8947 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8948 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8949 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8950 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8951 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8953 /* setup tran 2 dispatch table */
8954 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8955 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8956 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8957 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8958 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8959 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8960 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8961 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8962 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8963 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8964 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8965 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8966 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8967 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8968 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8969 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8970 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8971 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8973 /* setup the rap dispatch table */
8974 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8975 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8976 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8977 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8978 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8982 /* if we are doing SMB authentication we have register outselves as a logon process */
8983 if (smb_authType != SMB_AUTH_NONE) {
8984 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8985 LSA_STRING afsProcessName;
8986 LSA_OPERATIONAL_MODE dummy; /*junk*/
8988 afsProcessName.Buffer = "OpenAFSClientDaemon";
8989 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8990 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8992 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8994 if (nts == STATUS_SUCCESS) {
8995 LSA_STRING packageName;
8996 /* we are registered. Find out the security package id */
8997 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8998 packageName.Length = (USHORT)strlen(packageName.Buffer);
8999 packageName.MaximumLength = packageName.Length + 1;
9000 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9001 if (nts == STATUS_SUCCESS) {
9003 * This code forces Windows to authenticate against the Logon Cache
9004 * first instead of attempting to authenticate against the Domain
9005 * Controller. When the Windows logon cache is enabled this improves
9006 * performance by removing the network access and works around a bug
9007 * seen at sites which are using a MIT Kerberos principal to login
9008 * to machines joined to a non-root domain in a multi-domain forest.
9009 * MsV1_0SetProcessOption was added in Windows XP.
9011 PVOID pResponse = NULL;
9012 ULONG cbResponse = 0;
9013 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9015 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9016 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9017 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9018 OptionsRequest.DisableOptions = FALSE;
9020 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9023 sizeof(OptionsRequest),
9029 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9030 char message[AFSPATHMAX];
9031 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9033 OutputDebugString(message);
9036 OutputDebugString("MsV1_0SetProcessOption success");
9037 afsi_log("MsV1_0SetProcessOption success");
9039 /* END - code from Larry */
9041 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9042 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9043 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9045 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9047 /* something went wrong. We report the error and revert back to no authentication
9048 because we can't perform any auth requests without a successful lsa handle
9049 or sec package id. */
9050 afsi_log("Reverting to NO SMB AUTH");
9051 smb_authType = SMB_AUTH_NONE;
9054 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9056 /* something went wrong. We report the error and revert back to no authentication
9057 because we can't perform any auth requests without a successful lsa handle
9058 or sec package id. */
9059 afsi_log("Reverting to NO SMB AUTH");
9060 smb_authType = SMB_AUTH_NONE;
9064 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9065 * time prevents the failure of authentication when logged into Windows with an
9066 * external Kerberos principal mapped to a local account.
9068 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9069 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9070 * then the only option is NTLMSSP anyway; so just fallback.
9075 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9076 if (secBlobLength == 0) {
9077 smb_authType = SMB_AUTH_NTLM;
9078 afsi_log("Reverting to SMB AUTH NTLM");
9087 /* Now get ourselves a domain name. */
9088 /* For now we are using the local computer name as the domain name.
9089 * It is actually the domain for local logins, and we are acting as
9090 * a local SMB server.
9092 bufsize = sizeof(smb_ServerDomainName) - 1;
9093 GetComputerName(smb_ServerDomainName, &bufsize);
9094 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9095 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
9098 /* Start listeners, waiters, servers, and daemons */
9100 smb_StartListeners(1);
9102 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9103 NULL, 0, &lpid, "smb_ClientWaiter");
9104 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9105 thrd_CloseHandle(phandle);
9107 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9108 NULL, 0, &lpid, "smb_ServerWaiter");
9109 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9110 thrd_CloseHandle(phandle);
9112 for (i=0; i<smb_NumServerThreads; i++) {
9113 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9114 (void *) i, 0, &lpid, "smb_Server");
9115 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9116 thrd_CloseHandle(phandle);
9119 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9120 NULL, 0, &lpid, "smb_Daemon");
9121 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9122 thrd_CloseHandle(phandle);
9124 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9125 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9126 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9127 thrd_CloseHandle(phandle);
9129 lock_ReleaseMutex(&smb_StartedLock);
9133 void smb_Shutdown(void)
9140 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9142 /* setup the NCB system */
9145 /* Block new sessions by setting shutdown flag */
9146 smbShutdownFlag = 1;
9148 /* Hang up all sessions */
9149 memset((char *)ncbp, 0, sizeof(NCB));
9150 for (i = 1; i < numSessions; i++)
9152 if (dead_sessions[i])
9155 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9156 ncbp->ncb_command = NCBHANGUP;
9157 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9158 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9159 code = Netbios(ncbp);
9160 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9161 if (code == 0) code = ncbp->ncb_retcode;
9163 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9164 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9168 /* Trigger the shutdown of all SMB threads */
9169 for (i = 0; i < smb_NumServerThreads; i++)
9170 thrd_SetEvent(NCBreturns[i][0]);
9172 thrd_SetEvent(NCBevents[0]);
9173 thrd_SetEvent(SessionEvents[0]);
9174 thrd_SetEvent(NCBavails[0]);
9176 for (i = 0;i < smb_NumServerThreads; i++) {
9177 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9178 if (code == WAIT_OBJECT_0) {
9181 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9182 thrd_SetEvent(NCBreturns[i--][0]);
9186 /* Delete Netbios name */
9187 memset((char *)ncbp, 0, sizeof(NCB));
9188 for (i = 0; i < lana_list.length; i++) {
9189 if (lana_list.lana[i] == LANA_INVALID) continue;
9190 ncbp->ncb_command = NCBDELNAME;
9191 ncbp->ncb_lana_num = lana_list.lana[i];
9192 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9193 code = Netbios(ncbp);
9195 code = ncbp->ncb_retcode;
9197 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9198 ncbp->ncb_lana_num, code);
9203 /* Release the reference counts held by the VCs */
9204 lock_ObtainWrite(&smb_rctLock);
9205 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9210 if (vcp->magic != SMB_VC_MAGIC)
9211 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9212 __FILE__, __LINE__);
9214 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9216 if (fidp->scp != NULL) {
9219 lock_ObtainMutex(&fidp->mx);
9220 if (fidp->scp != NULL) {
9223 lock_ObtainMutex(&scp->mx);
9224 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9225 lock_ReleaseMutex(&scp->mx);
9226 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9227 cm_ReleaseSCache(scp);
9229 lock_ReleaseMutex(&fidp->mx);
9233 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9235 smb_ReleaseVCNoLock(tidp->vcp);
9237 cm_user_t *userp = tidp->userp;
9239 cm_ReleaseUser(userp);
9243 lock_ReleaseWrite(&smb_rctLock);
9245 TlsFree(smb_TlsRequestSlot);
9248 /* Get the UNC \\<servername>\<sharename> prefix. */
9249 char *smb_GetSharename()
9253 /* Make sure we have been properly initialized. */
9254 if (smb_localNamep == NULL)
9257 /* Allocate space for \\<servername>\<sharename>, plus the
9260 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9261 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9267 void smb_LogPacket(smb_packet_t *packet)
9270 unsigned length, paramlen, datalen, i, j;
9272 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9274 if (!packet) return;
9276 osi_Log0(smb_logp, "*** SMB packet dump ***");
9278 vp = (BYTE *) packet->data;
9280 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9281 length = paramlen + 2 + datalen;
9284 for (i=0;i < length; i+=16)
9286 memset( buf, ' ', 80 );
9291 buf[strlen(buf)] = ' ';
9293 cp = (BYTE*) buf + 7;
9295 for (j=0;j < 16 && (i+j)<length; j++)
9297 *(cp++) = hex[vp[i+j] >> 4];
9298 *(cp++) = hex[vp[i+j] & 0xf];
9308 for (j=0;j < 16 && (i+j)<length;j++)
9310 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9321 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9324 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9326 #endif /* LOG_PACKET */
9329 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9337 lock_ObtainRead(&smb_rctLock);
9339 sprintf(output, "begin dumping smb_vc_t\r\n");
9340 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9342 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9346 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9347 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9348 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9350 sprintf(output, "begin dumping smb_fid_t\r\n");
9351 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9353 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9355 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n",
9356 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9357 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9358 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9359 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9362 sprintf(output, "done dumping smb_fid_t\r\n");
9363 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9366 sprintf(output, "done dumping smb_vc_t\r\n");
9367 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9369 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9370 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9372 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9376 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9377 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9378 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9380 sprintf(output, "begin dumping smb_fid_t\r\n");
9381 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9383 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9385 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n",
9386 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9387 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9388 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9389 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9392 sprintf(output, "done dumping smb_fid_t\r\n");
9393 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9396 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9397 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9400 lock_ReleaseRead(&smb_rctLock);
9404 long smb_IsNetworkStarted(void)
9407 lock_ObtainWrite(&smb_globalLock);
9408 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
9409 lock_ReleaseWrite(&smb_globalLock);