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>
16 #pragma warning(disable: 4005)
20 #include <sys/timeb.h>
33 #include <rx/rx_prototypes.h>
34 #include <WINNT\afsreg.h>
37 #include "lanahelper.h"
39 /* These characters are illegal in Windows filenames */
40 static char *illegalChars = "\\/:*?\"<>|";
42 static int smbShutdownFlag = 0;
43 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
45 int smb_LogoffTokenTransfer;
46 time_t smb_LogoffTransferTimeout;
48 int smb_StoreAnsiFilenames = 0;
50 DWORD last_msg_time = 0;
54 unsigned int sessionGen = 0;
56 extern void afsi_log(char *pattern, ...);
57 extern HANDLE afsi_file;
58 extern int powerStateSuspended;
60 osi_hyper_t hzero = {0, 0};
61 osi_hyper_t hones = {0xFFFFFFFF, -1};
64 osi_rwlock_t smb_globalLock;
65 osi_rwlock_t smb_rctLock;
66 osi_mutex_t smb_ListenerLock;
69 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
71 BOOL isGateway = FALSE;
74 long smb_maxObsConcurrentCalls=0;
75 long smb_concurrentCalls=0;
77 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
79 smb_packet_t *smb_packetFreeListp;
80 smb_ncb_t *smb_ncbFreeListp;
82 int smb_NumServerThreads;
84 int numNCBs, numSessions, numVCs;
86 int smb_maxVCPerServer;
87 int smb_maxMpxRequests;
89 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
91 ULONG smb_lsaSecPackage;
92 LSA_STRING smb_lsaLogonOrigin;
94 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
95 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
96 EVENT_HANDLE **NCBreturns;
97 EVENT_HANDLE **NCBShutdown;
98 EVENT_HANDLE *smb_ServerShutdown;
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];
111 osi_mutex_t smb_RawBufLock;
113 #define SMB_RAW_BUFS 4
115 int smb_RawBufSel[SMB_RAW_BUFS];
120 #define SMB_MASKFLAG_TILDE 1
121 #define SMB_MASKFLAG_CASEFOLD 2
123 #define RAWTIMEOUT INFINITE
126 typedef struct raw_write_cont {
139 /* dir search stuff */
140 long smb_dirSearchCounter = 1;
141 smb_dirSearch_t *smb_firstDirSearchp;
142 smb_dirSearch_t *smb_lastDirSearchp;
144 /* hide dot files? */
145 int smb_hideDotFiles;
147 /* global state about V3 protocols */
148 int smb_useV3; /* try to negotiate V3 */
151 static showErrors = 0;
152 /* MessageBox or something like it */
153 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
157 * Time in Unix format of midnight, 1/1/1970 local time.
158 * When added to dosUTime, gives Unix (AFS) time.
160 time_t smb_localZero = 0;
162 #define USE_NUMERIC_TIME_CONV 1
164 #ifndef USE_NUMERIC_TIME_CONV
165 /* Time difference for converting to kludge-GMT */
166 afs_uint32 smb_NowTZ;
167 #endif /* USE_NUMERIC_TIME_CONV */
169 char *smb_localNamep = NULL;
171 smb_vc_t *smb_allVCsp;
172 smb_vc_t *smb_deadVCsp;
174 smb_username_t *usernamesp = NULL;
176 smb_waitingLockRequest_t *smb_allWaitingLocks;
178 DWORD smb_TlsRequestSlot = -1;
181 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
182 NCB *ncbp, raw_write_cont_t *rwcp);
183 int smb_NetbiosInit(void);
185 #ifndef AFS_WIN95_ENV
186 DWORD smb_ServerExceptionFilter(void);
189 extern char cm_HostName[];
190 extern char cm_confDir[];
194 #define LPTSTR char *
195 #define GetComputerName(str, sizep) \
196 strcpy((str), cm_HostName); \
197 *(sizep) = strlen(cm_HostName)
201 void smb_LogPacket(smb_packet_t *packet);
202 #endif /* LOG_PACKET */
204 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
205 int smb_ServerDomainNameLength = 0;
206 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
207 int smb_ServerOSLength = sizeof(smb_ServerOS);
208 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
209 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
211 /* Faux server GUID. This is never checked. */
212 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
214 void smb_ResetServerPriority()
216 void * p = TlsGetValue(smb_TlsRequestSlot);
219 TlsSetValue(smb_TlsRequestSlot, NULL);
220 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
224 void smb_SetRequestStartTime()
226 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
228 tp = malloc(sizeof(time_t));
232 if (!TlsSetValue(smb_TlsRequestSlot, tp))
237 void smb_UpdateServerPriority()
239 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
242 time_t now = osi_Time();
244 /* Give one priority boost for each 15 seconds */
245 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
250 const char * ncb_error_string(int code)
254 case 0x01: s = "llegal buffer length"; break;
255 case 0x03: s = "illegal command"; break;
256 case 0x05: s = "command timed out"; break;
257 case 0x06: s = "message incomplete, issue another command"; break;
258 case 0x07: s = "illegal buffer address"; break;
259 case 0x08: s = "session number out of range"; break;
260 case 0x09: s = "no resource available"; break;
261 case 0x0a: s = "session closed"; break;
262 case 0x0b: s = "command cancelled"; break;
263 case 0x0d: s = "duplicate name"; break;
264 case 0x0e: s = "name table full"; break;
265 case 0x0f: s = "no deletions, name has active sessions"; break;
266 case 0x11: s = "local session table full"; break;
267 case 0x12: s = "remote session table full"; break;
268 case 0x13: s = "illegal name number"; break;
269 case 0x14: s = "no callname"; break;
270 case 0x15: s = "cannot put * in NCB_NAME"; break;
271 case 0x16: s = "name in use on remote adapter"; break;
272 case 0x17: s = "name deleted"; break;
273 case 0x18: s = "session ended abnormally"; break;
274 case 0x19: s = "name conflict detected"; break;
275 case 0x21: s = "interface busy, IRET before retrying"; break;
276 case 0x22: s = "too many commands outstanding, retry later";break;
277 case 0x23: s = "ncb_lana_num field invalid"; break;
278 case 0x24: s = "command completed while cancel occurring "; break;
279 case 0x26: s = "command not valid to cancel"; break;
280 case 0x30: s = "name defined by anther local process"; break;
281 case 0x34: s = "environment undefined. RESET required"; break;
282 case 0x35: s = "required OS resources exhausted"; break;
283 case 0x36: s = "max number of applications exceeded"; break;
284 case 0x37: s = "no saps available for netbios"; break;
285 case 0x38: s = "requested resources are not available"; break;
286 case 0x39: s = "invalid ncb address or length > segment"; break;
287 case 0x3B: s = "invalid NCB DDID"; break;
288 case 0x3C: s = "lock of user area failed"; break;
289 case 0x3f: s = "NETBIOS not loaded"; break;
290 case 0x40: s = "system error"; break;
291 default: s = "unknown error";
297 char * myCrt_Dispatch(int i)
302 return "(00)ReceiveCoreMakeDir";
304 return "(01)ReceiveCoreRemoveDir";
306 return "(02)ReceiveCoreOpen";
308 return "(03)ReceiveCoreCreate";
310 return "(04)ReceiveCoreClose";
312 return "(05)ReceiveCoreFlush";
314 return "(06)ReceiveCoreUnlink";
316 return "(07)ReceiveCoreRename";
318 return "(08)ReceiveCoreGetFileAttributes";
320 return "(09)ReceiveCoreSetFileAttributes";
322 return "(0a)ReceiveCoreRead";
324 return "(0b)ReceiveCoreWrite";
326 return "(0c)ReceiveCoreLockRecord";
328 return "(0d)ReceiveCoreUnlockRecord";
330 return "(0e)SendCoreBadOp";
332 return "(0f)ReceiveCoreCreate";
334 return "(10)ReceiveCoreCheckPath";
336 return "(11)SendCoreBadOp";
338 return "(12)ReceiveCoreSeek";
340 return "(1a)ReceiveCoreReadRaw";
342 return "(1d)ReceiveCoreWriteRawDummy";
344 return "(22)ReceiveV3SetAttributes";
346 return "(23)ReceiveV3GetAttributes";
348 return "(24)ReceiveV3LockingX";
350 return "(25)ReceiveV3Trans";
352 return "(26)ReceiveV3Trans[aux]";
354 return "(29)SendCoreBadOp";
356 return "(2b)ReceiveCoreEcho";
358 return "(2d)ReceiveV3OpenX";
360 return "(2e)ReceiveV3ReadX";
362 return "(2f)ReceiveV3WriteX";
364 return "(32)ReceiveV3Tran2A";
366 return "(33)ReceiveV3Tran2A[aux]";
368 return "(34)ReceiveV3FindClose";
370 return "(35)ReceiveV3FindNotifyClose";
372 return "(70)ReceiveCoreTreeConnect";
374 return "(71)ReceiveCoreTreeDisconnect";
376 return "(72)ReceiveNegotiate";
378 return "(73)ReceiveV3SessionSetupX";
380 return "(74)ReceiveV3UserLogoffX";
382 return "(75)ReceiveV3TreeConnectX";
384 return "(80)ReceiveCoreGetDiskAttributes";
386 return "(81)ReceiveCoreSearchDir";
390 return "(83)FindUnique";
392 return "(84)FindClose";
394 return "(A0)ReceiveNTTransact";
396 return "(A2)ReceiveNTCreateX";
398 return "(A4)ReceiveNTCancel";
400 return "(A5)ReceiveNTRename";
402 return "(C0)OpenPrintFile";
404 return "(C1)WritePrintFile";
406 return "(C2)ClosePrintFile";
408 return "(C3)GetPrintQueue";
410 return "(D8)ReadBulk";
412 return "(D9)WriteBulk";
414 return "(DA)WriteBulkData";
416 return "unknown SMB op";
420 char * myCrt_2Dispatch(int i)
425 return "unknown SMB op-2";
427 return "S(00)CreateFile_ReceiveTran2Open";
429 return "S(01)FindFirst_ReceiveTran2SearchDir";
431 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
433 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
435 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
437 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
439 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
441 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
443 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
445 return "S(09)_ReceiveTran2FSCTL";
447 return "S(0a)_ReceiveTran2IOCTL";
449 return "S(0b)_ReceiveTran2FindNotifyFirst";
451 return "S(0c)_ReceiveTran2FindNotifyNext";
453 return "S(0d)_ReceiveTran2CreateDirectory";
455 return "S(0e)_ReceiveTran2SessionSetup";
457 return "S(0f)_QueryFileSystemInformationFid";
459 return "S(10)_ReceiveTran2GetDfsReferral";
461 return "S(11)_ReceiveTran2ReportDfsInconsistency";
465 char * myCrt_RapDispatch(int i)
470 return "unknown RAP OP";
472 return "RAP(0)NetShareEnum";
474 return "RAP(1)NetShareGetInfo";
476 return "RAP(13)NetServerGetInfo";
478 return "RAP(63)NetWkStaGetInfo";
482 /* scache must be locked */
483 unsigned int smb_Attributes(cm_scache_t *scp)
487 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
488 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
489 scp->fileType == CM_SCACHETYPE_INVALID)
491 attrs = SMB_ATTR_DIRECTORY;
492 #ifdef SPECIAL_FOLDERS
493 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
494 #endif /* SPECIAL_FOLDERS */
495 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
496 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
501 * We used to mark a file RO if it was in an RO volume, but that
502 * turns out to be impolitic in NT. See defect 10007.
505 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
506 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
508 if ((scp->unixModeBits & 0222) == 0)
509 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
515 /* Check if the named file/dir is a dotfile/dotdir */
516 /* String pointed to by lastComp can have leading slashes, but otherwise should have
517 no other patch components */
518 unsigned int smb_IsDotFile(char *lastComp) {
521 /* skip over slashes */
522 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
527 /* nulls, curdir and parent dir doesn't count */
533 if(*(s+1) == '.' && !*(s + 2))
540 static int ExtractBits(WORD bits, short start, short len)
547 num = bits << (16 - end);
548 num = num >> ((16 - end) + start);
554 void ShowUnixTime(char *FuncName, time_t unixTime)
559 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
561 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
562 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
564 int day, month, year, sec, min, hour;
567 day = ExtractBits(wDate, 0, 5);
568 month = ExtractBits(wDate, 5, 4);
569 year = ExtractBits(wDate, 9, 7) + 1980;
571 sec = ExtractBits(wTime, 0, 5);
572 min = ExtractBits(wTime, 5, 6);
573 hour = ExtractBits(wTime, 11, 5);
575 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
576 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
582 /* Determine if we are observing daylight savings time */
583 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
585 TIME_ZONE_INFORMATION timeZoneInformation;
586 SYSTEMTIME utc, local, localDST;
588 /* Get the time zone info. NT uses this to calc if we are in DST. */
589 GetTimeZoneInformation(&timeZoneInformation);
591 /* Return the daylight bias */
592 *pDstBias = timeZoneInformation.DaylightBias;
594 /* Return the bias */
595 *pBias = timeZoneInformation.Bias;
597 /* Now determine if DST is being observed */
599 /* Get the UTC (GMT) time */
602 /* Convert UTC time to local time using the time zone info. If we are
603 observing DST, the calculated local time will include this.
605 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
607 /* Set the daylight bias to 0. The daylight bias is the amount of change
608 * in time that we use for daylight savings time. By setting this to 0
609 * we cause there to be no change in time during daylight savings time.
611 timeZoneInformation.DaylightBias = 0;
613 /* Convert the utc time to local time again, but this time without any
614 adjustment for daylight savings time.
616 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
618 /* If the two times are different, then it means that the localDST that
619 we calculated includes the daylight bias, and therefore we are
620 observing daylight savings time.
622 *pDST = localDST.wHour != local.wHour;
625 /* Determine if we are observing daylight savings time */
626 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
632 *pDstBias = -60; /* where can this be different? */
638 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
640 BOOL dst; /* Will be TRUE if observing DST */
641 LONG dstBias; /* Offset from local time if observing DST */
642 LONG bias; /* Offset from GMT for local time */
645 * This function will adjust the last write time to compensate
646 * for two bugs in the smb client:
648 * 1) During Daylight Savings Time, the LastWriteTime is ahead
649 * in time by the DaylightBias (ignoring the sign - the
650 * DaylightBias is always stored as a negative number). If
651 * the DaylightBias is -60, then the LastWriteTime will be
652 * ahead by 60 minutes.
654 * 2) If the local time zone is a positive offset from GMT, then
655 * the LastWriteTime will be the correct local time plus the
656 * Bias (ignoring the sign - a positive offset from GMT is
657 * always stored as a negative Bias). If the Bias is -120,
658 * then the LastWriteTime will be ahead by 120 minutes.
660 * These bugs can occur at the same time.
663 GetTimeZoneInfo(&dst, &dstBias, &bias);
665 /* First adjust for DST */
667 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
669 /* Now adjust for a positive offset from GMT (a negative bias). */
671 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
674 #ifndef USE_NUMERIC_TIME_CONV
676 * Calculate the difference (in seconds) between local time and GMT.
677 * This enables us to convert file times to kludge-GMT.
683 struct tm gmt_tm, local_tm;
684 int days, hours, minutes, seconds;
687 gmt_tm = *(gmtime(&t));
688 local_tm = *(localtime(&t));
690 days = local_tm.tm_yday - gmt_tm.tm_yday;
691 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
692 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
693 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
697 #endif /* USE_NUMERIC_TIME_CONV */
700 #ifdef USE_NUMERIC_TIME_CONV
701 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
703 // Note that LONGLONG is a 64-bit value
706 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
707 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
708 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
711 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
716 time_t ersatz_unixTime;
719 * Must use kludge-GMT instead of real GMT.
720 * kludge-GMT is computed by adding time zone difference to localtime.
723 * ltp = gmtime(&unixTime);
725 ersatz_unixTime = unixTime - smb_NowTZ;
726 ltp = localtime(&ersatz_unixTime);
728 /* if we fail, make up something */
731 localJunk.tm_year = 89 - 20;
732 localJunk.tm_mon = 4;
733 localJunk.tm_mday = 12;
734 localJunk.tm_hour = 0;
735 localJunk.tm_min = 0;
736 localJunk.tm_sec = 0;
739 stm.wYear = ltp->tm_year + 1900;
740 stm.wMonth = ltp->tm_mon + 1;
741 stm.wDayOfWeek = ltp->tm_wday;
742 stm.wDay = ltp->tm_mday;
743 stm.wHour = ltp->tm_hour;
744 stm.wMinute = ltp->tm_min;
745 stm.wSecond = ltp->tm_sec;
746 stm.wMilliseconds = 0;
748 SystemTimeToFileTime(&stm, largeTimep);
750 #endif /* USE_NUMERIC_TIME_CONV */
752 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
754 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
755 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
756 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
758 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
760 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
761 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
763 *ft = LargeIntegerMultiplyByLong(*ft, 60);
764 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
767 ut = ConvertLongToLargeInteger(unixTime);
768 ut = LargeIntegerMultiplyByLong(ut, 10000000);
769 *ft = LargeIntegerAdd(*ft, ut);
774 #ifdef USE_NUMERIC_TIME_CONV
775 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
777 // Note that LONGLONG is a 64-bit value
780 ll = largeTimep->dwHighDateTime;
782 ll += largeTimep->dwLowDateTime;
784 ll -= 116444736000000000;
787 *unixTimep = (DWORD)ll;
789 #else /* USE_NUMERIC_TIME_CONV */
790 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
796 FileTimeToSystemTime(largeTimep, &stm);
798 lt.tm_year = stm.wYear - 1900;
799 lt.tm_mon = stm.wMonth - 1;
800 lt.tm_wday = stm.wDayOfWeek;
801 lt.tm_mday = stm.wDay;
802 lt.tm_hour = stm.wHour;
803 lt.tm_min = stm.wMinute;
804 lt.tm_sec = stm.wSecond;
807 save_timezone = _timezone;
808 _timezone += smb_NowTZ;
809 *unixTimep = mktime(<);
810 _timezone = save_timezone;
812 #endif /* USE_NUMERIC_TIME_CONV */
814 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
816 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
817 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
818 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
822 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
823 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
824 a = LargeIntegerMultiplyByLong(a, 60);
825 a = LargeIntegerMultiplyByLong(a, 10000000);
827 /* subtract it from ft */
828 a = LargeIntegerSubtract(*ft, a);
830 /* divide down to seconds */
831 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
835 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
845 /* if we fail, make up something */
848 localJunk.tm_year = 89 - 20;
849 localJunk.tm_mon = 4;
850 localJunk.tm_mday = 12;
851 localJunk.tm_hour = 0;
852 localJunk.tm_min = 0;
853 localJunk.tm_sec = 0;
856 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
857 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
858 *searchTimep = (dosDate<<16) | dosTime;
861 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
863 unsigned short dosDate;
864 unsigned short dosTime;
867 dosDate = (unsigned short) (searchTime & 0xffff);
868 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
870 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
871 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
872 localTm.tm_mday = (dosDate) & 0x1f;
873 localTm.tm_hour = (dosTime>>11) & 0x1f;
874 localTm.tm_min = (dosTime >> 5) & 0x3f;
875 localTm.tm_sec = (dosTime & 0x1f) * 2;
876 localTm.tm_isdst = -1; /* compute whether DST in effect */
878 *unixTimep = mktime(&localTm);
881 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
883 time_t diff_t = unixTime - smb_localZero;
884 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
885 osi_assert(diff_t < _UI32_MAX);
887 *dosUTimep = (afs_uint32)diff_t;
890 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
893 *unixTimep = dosTime + smb_localZero;
895 /* dosTime seems to be already adjusted for GMT */
896 *unixTimep = dosTime;
900 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
904 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
905 lock_ObtainWrite(&smb_rctLock);
906 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
907 if (vcp->magic != SMB_VC_MAGIC)
908 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
911 if (lsn == vcp->lsn && lana == vcp->lana &&
912 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
913 smb_HoldVCNoLock(vcp);
917 if (!vcp && (flags & SMB_FLAG_CREATE)) {
918 vcp = malloc(sizeof(*vcp));
919 memset(vcp, 0, sizeof(*vcp));
920 vcp->vcID = ++numVCs;
921 vcp->magic = SMB_VC_MAGIC;
922 vcp->refCount = 2; /* smb_allVCsp and caller */
925 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
926 vcp->nextp = smb_allVCsp;
928 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
933 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
934 /* We must obtain a challenge for extended auth
935 * in case the client negotiates smb v3
937 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
938 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
939 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
940 ULONG lsaRespSize = 0;
942 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
944 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
951 if (nts != STATUS_SUCCESS)
952 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
953 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
954 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
956 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
957 LsaFreeReturnBuffer(lsaResp);
960 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
962 if (numVCs >= CM_SESSION_RESERVED) {
964 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
967 lock_ReleaseWrite(&smb_rctLock);
968 lock_ReleaseWrite(&smb_globalLock);
972 int smb_IsStarMask(char *maskp)
977 for(i=0; i<11; i++) {
979 if (tc == '?' || tc == '*' || tc == '>')
985 void smb_ReleaseVCInternal(smb_vc_t *vcp)
992 if (vcp->refCount == 0) {
993 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
994 /* remove VCP from smb_deadVCsp */
995 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1001 lock_FinalizeMutex(&vcp->mx);
1002 memset(vcp,0,sizeof(smb_vc_t));
1005 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
1009 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
1010 avcp?"not ":"",vcp, vcp->refCount);
1012 GenerateMiniDump(NULL);
1014 /* This is a wrong. However, I suspect that there is an undercount
1015 * and I don't want to release 1.4.1 in a state that will allow
1016 * smb_vc_t objects to be deallocated while still in the
1017 * smb_allVCsp list. The list is supposed to keep a reference
1018 * to the smb_vc_t. Put it back.
1025 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1027 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1028 smb_ReleaseVCInternal(vcp);
1031 void smb_ReleaseVC(smb_vc_t *vcp)
1033 lock_ObtainWrite(&smb_rctLock);
1034 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1035 smb_ReleaseVCInternal(vcp);
1036 lock_ReleaseWrite(&smb_rctLock);
1039 void smb_HoldVCNoLock(smb_vc_t *vcp)
1042 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1045 void smb_HoldVC(smb_vc_t *vcp)
1047 lock_ObtainWrite(&smb_rctLock);
1049 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1050 lock_ReleaseWrite(&smb_rctLock);
1053 void smb_CleanupDeadVC(smb_vc_t *vcp)
1055 smb_fid_t *fidpIter;
1056 smb_fid_t *fidpNext;
1058 smb_tid_t *tidpIter;
1059 smb_tid_t *tidpNext;
1061 smb_user_t *uidpIter;
1062 smb_user_t *uidpNext;
1066 lock_ObtainMutex(&vcp->mx);
1067 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1068 lock_ReleaseMutex(&vcp->mx);
1069 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1072 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1073 lock_ReleaseMutex(&vcp->mx);
1074 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1076 lock_ObtainWrite(&smb_rctLock);
1077 /* remove VCP from smb_allVCsp */
1078 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1079 if ((*vcpp)->magic != SMB_VC_MAGIC)
1080 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1081 __FILE__, __LINE__);
1084 vcp->nextp = smb_deadVCsp;
1086 /* Hold onto the reference until we are done with this function */
1091 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1092 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1094 if (fidpIter->delete)
1097 fid = fidpIter->fid;
1098 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1100 smb_HoldFIDNoLock(fidpIter);
1101 lock_ReleaseWrite(&smb_rctLock);
1103 smb_CloseFID(vcp, fidpIter, NULL, 0);
1104 smb_ReleaseFID(fidpIter);
1106 lock_ObtainWrite(&smb_rctLock);
1107 fidpNext = vcp->fidsp;
1110 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1111 tidpNext = tidpIter->nextp;
1112 if (tidpIter->delete)
1114 tidpIter->delete = 1;
1116 tid = tidpIter->tid;
1117 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1119 smb_HoldTIDNoLock(tidpIter);
1120 lock_ReleaseWrite(&smb_rctLock);
1122 smb_ReleaseTID(tidpIter);
1124 lock_ObtainWrite(&smb_rctLock);
1125 tidpNext = vcp->tidsp;
1128 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1129 uidpNext = uidpIter->nextp;
1130 if (uidpIter->delete)
1132 uidpIter->delete = 1;
1134 /* do not add an additional reference count for the smb_user_t
1135 * as the smb_vc_t already is holding a reference */
1136 lock_ReleaseWrite(&smb_rctLock);
1138 smb_ReleaseUID(uidpIter);
1140 lock_ObtainWrite(&smb_rctLock);
1141 uidpNext = vcp->usersp;
1144 /* The vcp is now on the deadVCsp list. We intentionally drop the
1145 * reference so that the refcount can reach 0 and we can delete it */
1146 smb_ReleaseVCNoLock(vcp);
1148 lock_ReleaseWrite(&smb_rctLock);
1149 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1152 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1156 lock_ObtainWrite(&smb_rctLock);
1158 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1159 if (tidp->refCount == 0 && tidp->delete) {
1161 lock_ReleaseWrite(&smb_rctLock);
1162 smb_ReleaseTID(tidp);
1163 lock_ObtainWrite(&smb_rctLock);
1167 if (tid == tidp->tid) {
1172 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1173 tidp = malloc(sizeof(*tidp));
1174 memset(tidp, 0, sizeof(*tidp));
1175 tidp->nextp = vcp->tidsp;
1178 smb_HoldVCNoLock(vcp);
1180 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1183 lock_ReleaseWrite(&smb_rctLock);
1187 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1192 void smb_ReleaseTID(smb_tid_t *tidp)
1199 lock_ObtainWrite(&smb_rctLock);
1200 osi_assert(tidp->refCount-- > 0);
1201 if (tidp->refCount == 0 && (tidp->delete)) {
1202 ltpp = &tidp->vcp->tidsp;
1203 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1207 osi_assert(tp != NULL);
1209 lock_FinalizeMutex(&tidp->mx);
1210 userp = tidp->userp; /* remember to drop ref later */
1212 smb_ReleaseVCNoLock(tidp->vcp);
1215 lock_ReleaseWrite(&smb_rctLock);
1217 cm_ReleaseUser(userp);
1220 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1222 smb_user_t *uidp = NULL;
1224 lock_ObtainWrite(&smb_rctLock);
1225 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1226 if (uid == uidp->userID) {
1228 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1230 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1234 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1235 uidp = malloc(sizeof(*uidp));
1236 memset(uidp, 0, sizeof(*uidp));
1237 uidp->nextp = vcp->usersp;
1238 uidp->refCount = 2; /* one for the vcp and one for the caller */
1240 smb_HoldVCNoLock(vcp);
1242 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1244 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1246 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1248 lock_ReleaseWrite(&smb_rctLock);
1252 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1254 smb_username_t *unp= NULL;
1256 lock_ObtainWrite(&smb_rctLock);
1257 for(unp = usernamesp; unp; unp = unp->nextp) {
1258 if (stricmp(unp->name, usern) == 0 &&
1259 stricmp(unp->machine, machine) == 0) {
1264 if (!unp && (flags & SMB_FLAG_CREATE)) {
1265 unp = malloc(sizeof(*unp));
1266 memset(unp, 0, sizeof(*unp));
1268 unp->nextp = usernamesp;
1269 unp->name = strdup(usern);
1270 unp->machine = strdup(machine);
1272 lock_InitializeMutex(&unp->mx, "username_t mutex");
1273 if (flags & SMB_FLAG_AFSLOGON)
1274 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1277 lock_ReleaseWrite(&smb_rctLock);
1281 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1283 smb_user_t *uidp= NULL;
1285 lock_ObtainWrite(&smb_rctLock);
1286 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1289 if (stricmp(uidp->unp->name, usern) == 0) {
1291 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1292 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1297 lock_ReleaseWrite(&smb_rctLock);
1301 void smb_ReleaseUsername(smb_username_t *unp)
1304 smb_username_t **lupp;
1305 cm_user_t *userp = NULL;
1306 time_t now = osi_Time();
1308 lock_ObtainWrite(&smb_rctLock);
1309 osi_assert(unp->refCount-- > 0);
1310 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1311 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1313 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1317 osi_assert(up != NULL);
1319 up->nextp = NULL; /* do not remove this */
1320 lock_FinalizeMutex(&unp->mx);
1326 lock_ReleaseWrite(&smb_rctLock);
1329 cm_ReleaseUser(userp);
1333 void smb_HoldUIDNoLock(smb_user_t *uidp)
1338 void smb_ReleaseUID(smb_user_t *uidp)
1342 smb_username_t *unp = NULL;
1344 lock_ObtainWrite(&smb_rctLock);
1345 osi_assert(uidp->refCount-- > 0);
1346 if (uidp->refCount == 0) {
1347 lupp = &uidp->vcp->usersp;
1348 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1352 osi_assert(up != NULL);
1354 lock_FinalizeMutex(&uidp->mx);
1356 smb_ReleaseVCNoLock(uidp->vcp);
1360 lock_ReleaseWrite(&smb_rctLock);
1364 cm_ReleaseUserVCRef(unp->userp);
1365 smb_ReleaseUsername(unp);
1369 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1371 cm_user_t *up = NULL;
1376 lock_ObtainMutex(&uidp->mx);
1378 up = uidp->unp->userp;
1381 lock_ReleaseMutex(&uidp->mx);
1387 /* retrieve a held reference to a user structure corresponding to an incoming
1389 * corresponding release function is cm_ReleaseUser.
1391 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1394 cm_user_t *up = NULL;
1397 smbp = (smb_t *) inp;
1398 uidp = smb_FindUID(vcp, smbp->uid, 0);
1402 up = smb_GetUserFromUID(uidp);
1404 smb_ReleaseUID(uidp);
1409 * Return a pointer to a pathname extracted from a TID structure. The
1410 * TID structure is not held; assume it won't go away.
1412 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1417 tidp = smb_FindTID(vcp, tid, 0);
1421 if (tidp->flags & SMB_TIDFLAG_IPC) {
1422 code = CM_ERROR_TIDIPC;
1423 /* tidp->pathname would be NULL, but that's fine */
1425 *treepath = tidp->pathname;
1426 smb_ReleaseTID(tidp);
1431 /* check to see if we have a chained fid, that is, a fid that comes from an
1432 * OpenAndX message that ran earlier in this packet. In this case, the fid
1433 * field in a read, for example, request, isn't set, since the value is
1434 * supposed to be inherited from the openAndX call.
1436 int smb_ChainFID(int fid, smb_packet_t *inp)
1438 if (inp->fid == 0 || inp->inCount == 0)
1444 /* are we a priv'd user? What does this mean on NT? */
1445 int smb_SUser(cm_user_t *userp)
1450 /* find a file ID. If we pass in 0 we select an unused File ID.
1451 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1452 * smb_fid_t data structure if desired File ID cannot be found.
1454 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1459 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1462 lock_ObtainWrite(&smb_rctLock);
1463 /* figure out if we need to allocate a new file ID */
1466 fid = vcp->fidCounter;
1470 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1471 if (fidp->refCount == 0 && fidp->delete) {
1473 lock_ReleaseWrite(&smb_rctLock);
1474 smb_ReleaseFID(fidp);
1475 lock_ObtainWrite(&smb_rctLock);
1478 if (fid == fidp->fid) {
1481 if (fid == 0xFFFF) {
1483 "New FID number wraps on vcp 0x%x", vcp);
1493 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1494 char eventName[MAX_PATH];
1496 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1497 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1498 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1499 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1500 thrd_CloseHandle(event);
1502 if (fid == 0xFFFF) {
1503 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1509 fidp = malloc(sizeof(*fidp));
1510 memset(fidp, 0, sizeof(*fidp));
1511 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1514 smb_HoldVCNoLock(vcp);
1515 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1517 fidp->curr_chunk = fidp->prev_chunk = -2;
1518 fidp->raw_write_event = event;
1520 vcp->fidCounter = fid+1;
1521 if (vcp->fidCounter == 0xFFFF) {
1522 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1524 vcp->fidCounter = 1;
1529 lock_ReleaseWrite(&smb_rctLock);
1533 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1535 smb_fid_t *fidp = NULL;
1541 lock_ObtainWrite(&smb_rctLock);
1542 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1543 if (scp == fidp->scp) {
1548 lock_ReleaseWrite(&smb_rctLock);
1552 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1558 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1559 /* the sm_fid_t->mx and smb_rctLock must not be held */
1560 void smb_ReleaseFID(smb_fid_t *fidp)
1562 cm_scache_t *scp = NULL;
1563 cm_user_t *userp = NULL;
1564 smb_vc_t *vcp = NULL;
1565 smb_ioctl_t *ioctlp;
1567 lock_ObtainMutex(&fidp->mx);
1568 lock_ObtainWrite(&smb_rctLock);
1569 osi_assert(fidp->refCount-- > 0);
1570 if (fidp->refCount == 0 && (fidp->delete)) {
1573 scp = fidp->scp; /* release after lock is released */
1575 lock_ObtainMutex(&scp->mx);
1576 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1577 lock_ReleaseMutex(&scp->mx);
1578 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1581 userp = fidp->userp;
1585 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1586 thrd_CloseHandle(fidp->raw_write_event);
1588 /* and see if there is ioctl stuff to free */
1589 ioctlp = fidp->ioctlp;
1592 cm_FreeSpace(ioctlp->prefix);
1593 if (ioctlp->inAllocp)
1594 free(ioctlp->inAllocp);
1595 if (ioctlp->outAllocp)
1596 free(ioctlp->outAllocp);
1599 lock_ReleaseMutex(&fidp->mx);
1600 lock_FinalizeMutex(&fidp->mx);
1604 smb_ReleaseVCNoLock(vcp);
1606 lock_ReleaseMutex(&fidp->mx);
1608 lock_ReleaseWrite(&smb_rctLock);
1610 /* now release the scache structure */
1612 cm_ReleaseSCache(scp);
1615 cm_ReleaseUser(userp);
1619 * Case-insensitive search for one string in another;
1620 * used to find variable names in submount pathnames.
1622 static char *smb_stristr(char *str1, char *str2)
1626 for (cursor = str1; *cursor; cursor++)
1627 if (stricmp(cursor, str2) == 0)
1634 * Substitute a variable value for its name in a submount pathname. Variable
1635 * name has been identified by smb_stristr() and is in substr. Variable name
1636 * length (plus one) is in substr_size. Variable value is in newstr.
1638 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1643 strcpy(temp, substr + substr_size - 1);
1644 strcpy(substr, newstr);
1648 char VNUserName[] = "%USERNAME%";
1649 char VNLCUserName[] = "%LCUSERNAME%";
1650 char VNComputerName[] = "%COMPUTERNAME%";
1651 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1654 /* List available shares */
1655 int smb_ListShares()
1657 char sbmtpath[AFSPATHMAX];
1658 char pathName[AFSPATHMAX];
1659 char shareBuf[4096];
1667 /*strcpy(shareNameList[num_shares], "all");
1668 strcpy(pathNameList[num_shares++], "/afs");*/
1669 fprintf(stderr, "The following shares are available:\n");
1670 fprintf(stderr, "Share Name (AFS Path)\n");
1671 fprintf(stderr, "---------------------\n");
1672 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1675 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1676 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1678 strcpy(sbmtpath, cm_confDir);
1680 strcat(sbmtpath, "/afsdsbmt.ini");
1681 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1682 shareBuf, sizeof(shareBuf),
1688 this_share = shareBuf;
1692 /*strcpy(shareNameList[num_shares], this_share);*/
1693 len = GetPrivateProfileString("AFS Submounts", this_share,
1695 pathName, AFSPATHMAX,
1700 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1703 if (*p == '\\') *p = '/'; /* change to / */
1707 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1708 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1711 while (*this_share != 0) this_share++; /* find next NUL */
1712 this_share++; /* skip past the NUL */
1713 } while (*this_share != 0); /* stop at final NUL */
1719 typedef struct smb_findShare_rock {
1723 } smb_findShare_rock_t;
1725 #define SMB_FINDSHARE_EXACT_MATCH 1
1726 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1728 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1732 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1733 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1734 if(!stricmp(dep->name, vrock->shareName))
1735 matchType = SMB_FINDSHARE_EXACT_MATCH;
1737 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1738 if(vrock->match) free(vrock->match);
1739 vrock->match = strdup(dep->name);
1740 vrock->matchType = matchType;
1742 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1743 return CM_ERROR_STOPNOW;
1749 /* find a shareName in the table of submounts */
1750 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1754 char pathName[1024];
1759 char sbmtpath[MAX_PATH];
1764 DWORD allSubmount = 1;
1766 /* if allSubmounts == 0, only return the //mountRoot/all share
1767 * if in fact it has been been created in the subMounts table.
1768 * This is to allow sites that want to restrict access to the
1771 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1772 0, KEY_QUERY_VALUE, &parmKey);
1773 if (code == ERROR_SUCCESS) {
1774 len = sizeof(allSubmount);
1775 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1776 (BYTE *) &allSubmount, &len);
1777 if (code != ERROR_SUCCESS) {
1780 RegCloseKey (parmKey);
1783 if (allSubmount && _stricmp(shareName, "all") == 0) {
1788 /* In case, the all share is disabled we need to still be able
1789 * to handle ioctl requests
1791 if (_stricmp(shareName, "ioctl$") == 0) {
1792 *pathNamep = strdup("/.__ioctl__");
1796 if (_stricmp(shareName, "IPC$") == 0 ||
1797 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1798 _stricmp(shareName, "DESKTOP.INI") == 0
1804 /* Check for volume references
1806 They look like <cell>{%,#}<volume>
1808 if (strchr(shareName, '%') != NULL ||
1809 strchr(shareName, '#') != NULL) {
1810 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1811 /* make room for '/@vol:' + mountchar + NULL terminator*/
1813 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1814 osi_LogSaveString(smb_logp, shareName));
1816 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1817 "/" CM_PREFIX_VOL "%s", shareName);
1818 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1819 len = strlen(pathstr) + 1;
1821 *pathNamep = malloc(len);
1823 strcpy(*pathNamep, pathstr);
1825 osi_Log1(smb_logp, " returning pathname [%s]",
1826 osi_LogSaveString(smb_logp, *pathNamep));
1835 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1836 0, KEY_QUERY_VALUE, &parmKey);
1837 if (code == ERROR_SUCCESS) {
1838 len = sizeof(pathName);
1839 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1840 (BYTE *) pathName, &len);
1841 if (code != ERROR_SUCCESS)
1843 RegCloseKey (parmKey);
1848 strcpy(sbmtpath, cm_confDir);
1849 strcat(sbmtpath, "/afsdsbmt.ini");
1850 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1851 pathName, sizeof(pathName), sbmtpath);
1853 if (len != 0 && len != sizeof(pathName) - 1) {
1854 /* We can accept either unix or PC style AFS pathnames. Convert
1855 * Unix-style to PC style here for internal use.
1858 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1859 p += strlen(cm_mountRoot); /* skip mount path */
1862 if (*q == '/') *q = '\\'; /* change to \ */
1868 if (var = smb_stristr(p, VNUserName)) {
1869 if (uidp && uidp->unp)
1870 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1872 smb_subst(p, var, sizeof(VNUserName)," ");
1874 else if (var = smb_stristr(p, VNLCUserName))
1876 if (uidp && uidp->unp)
1877 strcpy(temp, uidp->unp->name);
1881 smb_subst(p, var, sizeof(VNLCUserName), temp);
1883 else if (var = smb_stristr(p, VNComputerName))
1885 sizeTemp = sizeof(temp);
1886 GetComputerName((LPTSTR)temp, &sizeTemp);
1887 smb_subst(p, var, sizeof(VNComputerName), temp);
1889 else if (var = smb_stristr(p, VNLCComputerName))
1891 sizeTemp = sizeof(temp);
1892 GetComputerName((LPTSTR)temp, &sizeTemp);
1894 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1899 *pathNamep = strdup(p);
1904 /* First lookup shareName in root.afs */
1906 smb_findShare_rock_t vrock;
1908 char * p = shareName;
1911 /* attempt to locate a partial match in root.afs. This is because
1912 when using the ANSI RAP calls, the share name is limited to 13 chars
1913 and hence is truncated. Of course we prefer exact matches. */
1915 thyper.HighPart = 0;
1918 vrock.shareName = shareName;
1920 vrock.matchType = 0;
1922 cm_HoldSCache(cm_data.rootSCachep);
1923 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1924 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1925 cm_ReleaseSCache(cm_data.rootSCachep);
1927 if (vrock.matchType) {
1928 sprintf(pathName,"/%s/",vrock.match);
1929 *pathNamep = strdup(strlwr(pathName));
1934 /* if we get here, there was no match for the share in root.afs */
1935 /* so try to create \\<netbiosName>\<cellname> */
1940 /* Get the full name for this cell */
1941 code = cm_SearchCellFile(p, temp, 0, 0);
1942 #ifdef AFS_AFSDB_ENV
1943 if (code && cm_dnsEnabled) {
1945 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1948 /* construct the path */
1950 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1951 *pathNamep = strdup(strlwr(pathName));
1960 /* Client-side offline caching policy types */
1961 #define CSC_POLICY_MANUAL 0
1962 #define CSC_POLICY_DOCUMENTS 1
1963 #define CSC_POLICY_PROGRAMS 2
1964 #define CSC_POLICY_DISABLE 3
1966 int smb_FindShareCSCPolicy(char *shareName)
1972 int retval = CSC_POLICY_MANUAL;
1974 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1975 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1978 REG_OPTION_NON_VOLATILE,
1984 len = sizeof(policy);
1985 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1987 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1989 else if (stricmp(policy, "documents") == 0)
1991 retval = CSC_POLICY_DOCUMENTS;
1993 else if (stricmp(policy, "programs") == 0)
1995 retval = CSC_POLICY_PROGRAMS;
1997 else if (stricmp(policy, "disable") == 0)
1999 retval = CSC_POLICY_DISABLE;
2002 RegCloseKey(hkCSCPolicy);
2006 /* find a dir search structure by cookie value, and return it held.
2007 * Must be called with smb_globalLock held.
2009 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2011 smb_dirSearch_t *dsp;
2013 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2014 if (dsp->cookie == cookie) {
2015 if (dsp != smb_firstDirSearchp) {
2016 /* move to head of LRU queue, too, if we're not already there */
2017 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2018 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2019 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2020 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2021 if (!smb_lastDirSearchp)
2022 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2024 lock_ObtainMutex(&dsp->mx);
2026 lock_ReleaseMutex(&dsp->mx);
2032 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2033 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2034 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2040 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2042 lock_ObtainWrite(&smb_globalLock);
2043 lock_ObtainMutex(&dsp->mx);
2044 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2045 dsp->cookie, dsp, dsp->scp);
2046 dsp->flags |= SMB_DIRSEARCH_DELETE;
2047 if (dsp->scp != NULL) {
2048 lock_ObtainMutex(&dsp->scp->mx);
2049 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2050 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2051 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2052 dsp->scp->bulkStatProgress = hzero;
2054 lock_ReleaseMutex(&dsp->scp->mx);
2056 lock_ReleaseMutex(&dsp->mx);
2057 lock_ReleaseWrite(&smb_globalLock);
2060 /* Must be called with the smb_globalLock held */
2061 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2063 cm_scache_t *scp = NULL;
2065 lock_ObtainMutex(&dsp->mx);
2066 osi_assert(dsp->refCount-- > 0);
2067 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
2068 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2069 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2070 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2071 lock_ReleaseMutex(&dsp->mx);
2072 lock_FinalizeMutex(&dsp->mx);
2074 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2075 dsp->cookie, dsp, scp);
2078 lock_ReleaseMutex(&dsp->mx);
2080 /* do this now to avoid spurious locking hierarchy creation */
2082 cm_ReleaseSCache(scp);
2085 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2087 lock_ObtainWrite(&smb_globalLock);
2088 smb_ReleaseDirSearchNoLock(dsp);
2089 lock_ReleaseWrite(&smb_globalLock);
2092 /* find a dir search structure by cookie value, and return it held */
2093 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2095 smb_dirSearch_t *dsp;
2097 lock_ObtainWrite(&smb_globalLock);
2098 dsp = smb_FindDirSearchNoLock(cookie);
2099 lock_ReleaseWrite(&smb_globalLock);
2103 /* GC some dir search entries, in the address space expected by the specific protocol.
2104 * Must be called with smb_globalLock held; release the lock temporarily.
2106 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2107 void smb_GCDirSearches(int isV3)
2109 smb_dirSearch_t *prevp;
2110 smb_dirSearch_t *tp;
2111 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2115 victimCount = 0; /* how many have we got so far */
2116 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
2117 /* we'll move tp from queue, so
2120 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
2121 /* if no one is using this guy, and we're either in the new protocol,
2122 * or we're in the old one and this is a small enough ID to be useful
2123 * to the old protocol, GC this guy.
2125 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
2126 /* hold and delete */
2127 lock_ObtainMutex(&tp->mx);
2128 tp->flags |= SMB_DIRSEARCH_DELETE;
2129 lock_ReleaseMutex(&tp->mx);
2130 victimsp[victimCount++] = tp;
2134 /* don't do more than this */
2135 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2139 /* now release them */
2140 for (i = 0; i < victimCount; i++) {
2141 smb_ReleaseDirSearchNoLock(victimsp[i]);
2145 /* function for allocating a dir search entry. We need these to remember enough context
2146 * since we don't get passed the path from call to call during a directory search.
2148 * Returns a held dir search structure, and bumps the reference count on the vnode,
2149 * since it saves a pointer to the vnode.
2151 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2153 smb_dirSearch_t *dsp;
2159 lock_ObtainWrite(&smb_globalLock);
2162 /* what's the biggest ID allowed in this version of the protocol */
2163 /* TODO: do we really want a non v3 dir search request to wrap
2164 smb_dirSearchCounter? */
2165 maxAllowed = isV3 ? 65535 : 255;
2166 if (smb_dirSearchCounter > maxAllowed)
2167 smb_dirSearchCounter = 1;
2169 start = smb_dirSearchCounter;
2172 /* twice so we have enough tries to find guys we GC after one pass;
2173 * 10 extra is just in case I mis-counted.
2175 if (++counter > 2*maxAllowed+10)
2176 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2178 if (smb_dirSearchCounter > maxAllowed) {
2179 smb_dirSearchCounter = 1;
2181 if (smb_dirSearchCounter == start) {
2183 smb_GCDirSearches(isV3);
2186 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2188 /* don't need to watch for refcount zero and deleted, since
2189 * we haven't dropped the global lock.
2191 lock_ObtainMutex(&dsp->mx);
2193 lock_ReleaseMutex(&dsp->mx);
2194 ++smb_dirSearchCounter;
2198 dsp = malloc(sizeof(*dsp));
2199 memset(dsp, 0, sizeof(*dsp));
2200 dsp->cookie = smb_dirSearchCounter;
2201 ++smb_dirSearchCounter;
2203 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2204 dsp->lastTime = osi_Time();
2205 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2206 if (!smb_lastDirSearchp)
2207 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2209 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2213 lock_ReleaseWrite(&smb_globalLock);
2217 static smb_packet_t *GetPacket(void)
2221 unsigned int npar, seg, tb_sel;
2224 lock_ObtainWrite(&smb_globalLock);
2225 tbp = smb_packetFreeListp;
2227 smb_packetFreeListp = tbp->nextp;
2228 lock_ReleaseWrite(&smb_globalLock);
2231 tbp = calloc(65540,1);
2233 tbp = malloc(sizeof(smb_packet_t));
2235 tbp->magic = SMB_PACKETMAGIC;
2238 tbp->resumeCode = 0;
2244 tbp->ncb_length = 0;
2249 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
2252 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2254 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
2256 osi_panic("",__FILE__,__LINE__);
2259 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
2264 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
2265 tbp->dos_pkt_sel = tb_sel;
2268 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2273 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2277 memcpy(tbp, pkt, sizeof(smb_packet_t));
2278 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2280 smb_HoldVC(tbp->vcp);
2284 static NCB *GetNCB(void)
2289 unsigned int npar, seg, tb_sel;
2292 lock_ObtainWrite(&smb_globalLock);
2293 tbp = smb_ncbFreeListp;
2295 smb_ncbFreeListp = tbp->nextp;
2296 lock_ReleaseWrite(&smb_globalLock);
2299 tbp = calloc(sizeof(*tbp),1);
2301 tbp = malloc(sizeof(*tbp));
2302 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
2305 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2307 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2309 osi_panic("",__FILE__,__LINE__);
2311 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2316 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
2317 tbp->dos_ncb_sel = tb_sel;
2319 tbp->magic = SMB_NCBMAGIC;
2322 osi_assert(tbp->magic == SMB_NCBMAGIC);
2324 memset(&tbp->ncb, 0, sizeof(NCB));
2327 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2332 void smb_FreePacket(smb_packet_t *tbp)
2334 smb_vc_t * vcp = NULL;
2335 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2337 lock_ObtainWrite(&smb_globalLock);
2338 tbp->nextp = smb_packetFreeListp;
2339 smb_packetFreeListp = tbp;
2340 tbp->magic = SMB_PACKETMAGIC;
2344 tbp->resumeCode = 0;
2350 tbp->ncb_length = 0;
2352 lock_ReleaseWrite(&smb_globalLock);
2358 static void FreeNCB(NCB *bufferp)
2362 tbp = (smb_ncb_t *) bufferp;
2363 osi_assert(tbp->magic == SMB_NCBMAGIC);
2365 lock_ObtainWrite(&smb_globalLock);
2366 tbp->nextp = smb_ncbFreeListp;
2367 smb_ncbFreeListp = tbp;
2368 lock_ReleaseWrite(&smb_globalLock);
2371 /* get a ptr to the data part of a packet, and its count */
2372 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2376 unsigned char *afterParmsp;
2378 parmBytes = *smbp->wctp << 1;
2379 afterParmsp = smbp->wctp + parmBytes + 1;
2381 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2382 if (nbytesp) *nbytesp = dataBytes;
2384 /* don't forget to skip the data byte count, since it follows
2385 * the parameters; that's where the "2" comes from below.
2387 return (unsigned char *) (afterParmsp + 2);
2390 /* must set all the returned parameters before playing around with the
2391 * data region, since the data region is located past the end of the
2392 * variable number of parameters.
2394 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2396 unsigned char *afterParmsp;
2398 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2400 *afterParmsp++ = dsize & 0xff;
2401 *afterParmsp = (dsize>>8) & 0xff;
2404 /* return the parm'th parameter in the smbp packet */
2405 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2408 unsigned char *parmDatap;
2410 parmCount = *smbp->wctp;
2412 if (parm >= parmCount) {
2415 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2416 parm, parmCount, smbp->ncb_length);
2417 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2418 parm, parmCount, smbp->ncb_length);
2420 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2421 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2423 osi_panic(s, __FILE__, __LINE__);
2425 parmDatap = smbp->wctp + (2*parm) + 1;
2427 return parmDatap[0] + (parmDatap[1] << 8);
2430 /* return the parm'th parameter in the smbp packet */
2431 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2434 unsigned char *parmDatap;
2436 parmCount = *smbp->wctp;
2438 if (parm >= parmCount) {
2441 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2442 parm, parmCount, smbp->ncb_length);
2443 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2444 parm, parmCount, smbp->ncb_length);
2445 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2446 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2447 osi_panic(s, __FILE__, __LINE__);
2449 parmDatap = smbp->wctp + (2*parm) + 1;
2451 return parmDatap[0];
2454 /* return the parm'th parameter in the smbp packet */
2455 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2458 unsigned char *parmDatap;
2460 parmCount = *smbp->wctp;
2462 if (parm + 1 >= parmCount) {
2465 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2466 parm, parmCount, smbp->ncb_length);
2467 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2468 parm, parmCount, smbp->ncb_length);
2470 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2471 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2473 osi_panic(s, __FILE__, __LINE__);
2475 parmDatap = smbp->wctp + (2*parm) + 1;
2477 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2480 /* return the parm'th parameter in the smbp packet */
2481 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2484 unsigned char *parmDatap;
2486 parmCount = *smbp->wctp;
2488 if (parm * 2 + offset >= parmCount * 2) {
2491 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2492 parm, offset, parmCount, smbp->ncb_length);
2494 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2495 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2497 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2498 parm, offset, parmCount, smbp->ncb_length);
2499 osi_panic(s, __FILE__, __LINE__);
2501 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2503 return parmDatap[0] + (parmDatap[1] << 8);
2506 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2510 /* make sure we have enough slots */
2511 if (*smbp->wctp <= slot)
2512 *smbp->wctp = slot+1;
2514 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2515 *parmDatap++ = parmValue & 0xff;
2516 *parmDatap = (parmValue>>8) & 0xff;
2519 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2523 /* make sure we have enough slots */
2524 if (*smbp->wctp <= slot)
2525 *smbp->wctp = slot+2;
2527 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2528 *parmDatap++ = parmValue & 0xff;
2529 *parmDatap++ = (parmValue>>8) & 0xff;
2530 *parmDatap++ = (parmValue>>16) & 0xff;
2531 *parmDatap = (parmValue>>24) & 0xff;
2534 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2539 /* make sure we have enough slots */
2540 if (*smbp->wctp <= slot)
2541 *smbp->wctp = slot+4;
2543 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2545 *parmDatap++ = *parmValuep++;
2548 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2552 /* make sure we have enough slots */
2553 if (*smbp->wctp <= slot) {
2554 if (smbp->oddByte) {
2556 *smbp->wctp = slot+1;
2561 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2562 *parmDatap++ = parmValue & 0xff;
2565 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2569 lastSlashp = strrchr(inPathp, '\\');
2571 *lastComponentp = lastSlashp;
2574 if (inPathp == lastSlashp)
2576 *outPathp++ = *inPathp++;
2585 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2590 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2595 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2601 tlen = inp[0] + (inp[1]<<8);
2602 inp += 2; /* skip length field */
2605 *chainpp = inp + tlen;
2614 /* format a packet as a response */
2615 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2620 outp = (smb_t *) op;
2622 /* zero the basic structure through the smb_wct field, and zero the data
2623 * size field, assuming that wct stays zero; otherwise, you have to
2624 * explicitly set the data size field, too.
2626 inSmbp = (smb_t *) inp;
2627 memset(outp, 0, sizeof(smb_t)+2);
2633 outp->com = inSmbp->com;
2634 outp->tid = inSmbp->tid;
2635 outp->pid = inSmbp->pid;
2636 outp->uid = inSmbp->uid;
2637 outp->mid = inSmbp->mid;
2638 outp->res[0] = inSmbp->res[0];
2639 outp->res[1] = inSmbp->res[1];
2640 op->inCom = inSmbp->com;
2642 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2643 #ifdef SEND_CANONICAL_PATHNAMES
2644 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2646 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2648 /* copy fields in generic packet area */
2649 op->wctp = &outp->wct;
2652 /* send a (probably response) packet; vcp tells us to whom to send it.
2653 * we compute the length by looking at wct and bcc fields.
2655 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2672 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2675 memset((char *)ncbp, 0, sizeof(NCB));
2677 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2678 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2679 extra += tp[0] + (tp[1]<<8);
2680 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2681 extra += 3; /* wct and length fields */
2683 ncbp->ncb_length = extra; /* bytes to send */
2684 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2685 ncbp->ncb_lana_num = vcp->lana;
2686 ncbp->ncb_command = NCBSEND; /* op means send data */
2688 ncbp->ncb_buffer = (char *) inp;/* packet */
2689 code = Netbios(ncbp);
2691 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2692 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2694 /* copy header information from virtual to DOS address space */
2695 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2696 code = Netbios(ncbp, dos_ncb);
2700 const char * s = ncb_error_string(code);
2701 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2703 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2706 lock_ObtainMutex(&vcp->mx);
2707 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2708 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2710 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2711 lock_ReleaseMutex(&vcp->mx);
2712 lock_ObtainWrite(&smb_globalLock);
2713 dead_sessions[vcp->session] = TRUE;
2714 lock_ReleaseWrite(&smb_globalLock);
2715 smb_CleanupDeadVC(vcp);
2717 lock_ReleaseMutex(&vcp->mx);
2725 void smb_MapNTError(long code, unsigned long *NTStatusp)
2727 unsigned long NTStatus;
2729 /* map CM_ERROR_* errors to NT 32-bit status codes */
2730 /* NT Status codes are listed in ntstatus.h not winerror.h */
2731 if (code == CM_ERROR_NOSUCHCELL) {
2732 NTStatus = 0xC000000FL; /* No such file */
2734 else if (code == CM_ERROR_NOSUCHVOLUME) {
2735 NTStatus = 0xC000000FL; /* No such file */
2737 else if (code == CM_ERROR_TIMEDOUT) {
2739 NTStatus = 0xC00000CFL; /* Sharing Paused */
2741 NTStatus = 0x00000102L; /* Timeout */
2744 else if (code == CM_ERROR_RETRY) {
2745 NTStatus = 0xC000022DL; /* Retry */
2747 else if (code == CM_ERROR_NOACCESS) {
2748 NTStatus = 0xC0000022L; /* Access denied */
2750 else if (code == CM_ERROR_READONLY) {
2751 NTStatus = 0xC00000A2L; /* Write protected */
2753 else if (code == CM_ERROR_NOSUCHFILE ||
2754 code == CM_ERROR_BPLUS_NOMATCH) {
2755 NTStatus = 0xC000000FL; /* No such file */
2757 else if (code == CM_ERROR_NOSUCHPATH) {
2758 NTStatus = 0xC000003AL; /* Object path not found */
2760 else if (code == CM_ERROR_TOOBIG) {
2761 NTStatus = 0xC000007BL; /* Invalid image format */
2763 else if (code == CM_ERROR_INVAL) {
2764 NTStatus = 0xC000000DL; /* Invalid parameter */
2766 else if (code == CM_ERROR_BADFD) {
2767 NTStatus = 0xC0000008L; /* Invalid handle */
2769 else if (code == CM_ERROR_BADFDOP) {
2770 NTStatus = 0xC0000022L; /* Access denied */
2772 else if (code == CM_ERROR_EXISTS) {
2773 NTStatus = 0xC0000035L; /* Object name collision */
2775 else if (code == CM_ERROR_NOTEMPTY) {
2776 NTStatus = 0xC0000101L; /* Directory not empty */
2778 else if (code == CM_ERROR_CROSSDEVLINK) {
2779 NTStatus = 0xC00000D4L; /* Not same device */
2781 else if (code == CM_ERROR_NOTDIR) {
2782 NTStatus = 0xC0000103L; /* Not a directory */
2784 else if (code == CM_ERROR_ISDIR) {
2785 NTStatus = 0xC00000BAL; /* File is a directory */
2787 else if (code == CM_ERROR_BADOP) {
2789 /* I have no idea where this comes from */
2790 NTStatus = 0xC09820FFL; /* SMB no support */
2792 NTStatus = 0xC00000BBL; /* Not supported */
2793 #endif /* COMMENT */
2795 else if (code == CM_ERROR_BADSHARENAME) {
2796 NTStatus = 0xC00000CCL; /* Bad network name */
2798 else if (code == CM_ERROR_NOIPC) {
2800 NTStatus = 0xC0000022L; /* Access Denied */
2802 NTStatus = 0xC000013DL; /* Remote Resources */
2805 else if (code == CM_ERROR_CLOCKSKEW) {
2806 NTStatus = 0xC0000133L; /* Time difference at DC */
2808 else if (code == CM_ERROR_BADTID) {
2809 NTStatus = 0xC0982005L; /* SMB bad TID */
2811 else if (code == CM_ERROR_USESTD) {
2812 NTStatus = 0xC09820FBL; /* SMB use standard */
2814 else if (code == CM_ERROR_QUOTA) {
2816 NTStatus = 0xC0000044L; /* Quota exceeded */
2818 NTStatus = 0xC000007FL; /* Disk full */
2821 else if (code == CM_ERROR_SPACE) {
2822 NTStatus = 0xC000007FL; /* Disk full */
2824 else if (code == CM_ERROR_ATSYS) {
2825 NTStatus = 0xC0000033L; /* Object name invalid */
2827 else if (code == CM_ERROR_BADNTFILENAME) {
2828 NTStatus = 0xC0000033L; /* Object name invalid */
2830 else if (code == CM_ERROR_WOULDBLOCK) {
2831 NTStatus = 0xC0000055L; /* Lock not granted */
2833 else if (code == CM_ERROR_SHARING_VIOLATION) {
2834 NTStatus = 0xC0000043L; /* Sharing violation */
2836 else if (code == CM_ERROR_LOCK_CONFLICT) {
2837 NTStatus = 0xC0000054L; /* Lock conflict */
2839 else if (code == CM_ERROR_PARTIALWRITE) {
2840 NTStatus = 0xC000007FL; /* Disk full */
2842 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2843 NTStatus = 0xC0000023L; /* Buffer too small */
2845 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2846 NTStatus = 0xC0000035L; /* Object name collision */
2848 else if (code == CM_ERROR_BADPASSWORD) {
2849 NTStatus = 0xC000006DL; /* unknown username or bad password */
2851 else if (code == CM_ERROR_BADLOGONTYPE) {
2852 NTStatus = 0xC000015BL; /* logon type not granted */
2854 else if (code == CM_ERROR_GSSCONTINUE) {
2855 NTStatus = 0xC0000016L; /* more processing required */
2857 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2859 NTStatus = 0xC0000280L; /* reparse point not resolved */
2861 NTStatus = 0xC0000022L; /* Access Denied */
2864 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2865 NTStatus = 0xC0000257L; /* Path Not Covered */
2868 else if (code == CM_ERROR_ALLBUSY) {
2869 NTStatus = 0xC00000BFL; /* Network Busy */
2871 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2872 NTStatus = 0xC0000350L; /* Remote Host Down */
2875 /* we do not want to be telling the SMB/CIFS client that
2876 * the AFS Client Service is busy or down.
2878 else if (code == CM_ERROR_ALLBUSY ||
2879 code == CM_ERROR_ALLOFFLINE ||
2880 code == CM_ERROR_ALLDOWN) {
2881 NTStatus = 0xC00000BEL; /* Bad Network Path */
2884 else if (code == RXKADUNKNOWNKEY) {
2885 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2887 else if (code == CM_ERROR_BAD_LEVEL) {
2888 NTStatus = 0xC0000148L; /* Invalid Level */
2890 NTStatus = 0xC0982001L; /* SMB non-specific error */
2893 *NTStatusp = NTStatus;
2894 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2897 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2898 unsigned char *classp)
2900 unsigned char class;
2901 unsigned short error;
2903 /* map CM_ERROR_* errors to SMB errors */
2904 if (code == CM_ERROR_NOSUCHCELL) {
2906 error = 3; /* bad path */
2908 else if (code == CM_ERROR_NOSUCHVOLUME) {
2910 error = 3; /* bad path */
2912 else if (code == CM_ERROR_TIMEDOUT) {
2914 error = 81; /* server is paused */
2916 else if (code == CM_ERROR_RETRY) {
2917 class = 2; /* shouldn't happen */
2920 else if (code == CM_ERROR_NOACCESS) {
2922 error = 4; /* bad access */
2924 else if (code == CM_ERROR_READONLY) {
2926 error = 19; /* read only */
2928 else if (code == CM_ERROR_NOSUCHFILE ||
2929 code == CM_ERROR_BPLUS_NOMATCH) {
2931 error = 2; /* ENOENT! */
2933 else if (code == CM_ERROR_NOSUCHPATH) {
2935 error = 3; /* Bad path */
2937 else if (code == CM_ERROR_TOOBIG) {
2939 error = 11; /* bad format */
2941 else if (code == CM_ERROR_INVAL) {
2942 class = 2; /* server non-specific error code */
2945 else if (code == CM_ERROR_BADFD) {
2947 error = 6; /* invalid file handle */
2949 else if (code == CM_ERROR_BADFDOP) {
2950 class = 1; /* invalid op on FD */
2953 else if (code == CM_ERROR_EXISTS) {
2955 error = 80; /* file already exists */
2957 else if (code == CM_ERROR_NOTEMPTY) {
2959 error = 5; /* delete directory not empty */
2961 else if (code == CM_ERROR_CROSSDEVLINK) {
2963 error = 17; /* EXDEV */
2965 else if (code == CM_ERROR_NOTDIR) {
2966 class = 1; /* bad path */
2969 else if (code == CM_ERROR_ISDIR) {
2970 class = 1; /* access denied; DOS doesn't have a good match */
2973 else if (code == CM_ERROR_BADOP) {
2977 else if (code == CM_ERROR_BADSHARENAME) {
2981 else if (code == CM_ERROR_NOIPC) {
2983 error = 4; /* bad access */
2985 else if (code == CM_ERROR_CLOCKSKEW) {
2986 class = 1; /* invalid function */
2989 else if (code == CM_ERROR_BADTID) {
2993 else if (code == CM_ERROR_USESTD) {
2997 else if (code == CM_ERROR_REMOTECONN) {
3001 else if (code == CM_ERROR_QUOTA) {
3002 if (vcp->flags & SMB_VCFLAG_USEV3) {
3004 error = 39; /* disk full */
3008 error = 5; /* access denied */
3011 else if (code == CM_ERROR_SPACE) {
3012 if (vcp->flags & SMB_VCFLAG_USEV3) {
3014 error = 39; /* disk full */
3018 error = 5; /* access denied */
3021 else if (code == CM_ERROR_PARTIALWRITE) {
3023 error = 39; /* disk full */
3025 else if (code == CM_ERROR_ATSYS) {
3027 error = 2; /* ENOENT */
3029 else if (code == CM_ERROR_WOULDBLOCK) {
3031 error = 33; /* lock conflict */
3033 else if (code == CM_ERROR_LOCK_CONFLICT) {
3035 error = 33; /* lock conflict */
3037 else if (code == CM_ERROR_SHARING_VIOLATION) {
3039 error = 33; /* lock conflict */
3041 else if (code == CM_ERROR_NOFILES) {
3043 error = 18; /* no files in search */
3045 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3047 error = 183; /* Samba uses this */
3049 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3050 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3052 error = 2; /* bad password */
3054 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3056 error = 3; /* bad path */
3065 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3068 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3070 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3071 return CM_ERROR_BADOP;
3074 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3076 unsigned short EchoCount, i;
3077 char *data, *outdata;
3080 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3082 for (i=1; i<=EchoCount; i++) {
3083 data = smb_GetSMBData(inp, &dataSize);
3084 smb_SetSMBParm(outp, 0, i);
3085 smb_SetSMBDataLength(outp, dataSize);
3086 outdata = smb_GetSMBData(outp, NULL);
3087 memcpy(outdata, data, dataSize);
3088 smb_SendPacket(vcp, outp);
3094 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3097 long count, minCount, finalCount;
3102 cm_user_t *userp = NULL;
3106 char *rawBuf = NULL;
3108 dos_ptr rawBuf = NULL;
3115 fd = smb_GetSMBParm(inp, 0);
3116 count = smb_GetSMBParm(inp, 3);
3117 minCount = smb_GetSMBParm(inp, 4);
3118 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3120 if (*inp->wctp == 10) {
3121 /* we were sent a request with 64-bit file offsets */
3122 #ifdef AFS_LARGEFILES
3123 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3125 if (LargeIntegerLessThanZero(offset)) {
3126 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3130 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3131 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3134 offset.HighPart = 0;
3138 /* we were sent a request with 32-bit file offsets */
3139 offset.HighPart = 0;
3142 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3143 fd, offset.HighPart, offset.LowPart, count);
3145 fidp = smb_FindFID(vcp, fd, 0);
3149 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3150 smb_CloseFID(vcp, fidp, NULL, 0);
3151 code = CM_ERROR_NOSUCHFILE;
3156 pid = ((smb_t *) inp)->pid;
3158 LARGE_INTEGER LOffset, LLength;
3161 key = cm_GenerateKey(vcp->vcID, pid, fd);
3163 LOffset.HighPart = offset.HighPart;
3164 LOffset.LowPart = offset.LowPart;
3165 LLength.HighPart = 0;
3166 LLength.LowPart = count;
3168 lock_ObtainMutex(&fidp->scp->mx);
3169 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3170 lock_ReleaseMutex(&fidp->scp->mx);
3176 lock_ObtainMutex(&smb_RawBufLock);
3178 /* Get a raw buf, from head of list */
3179 rawBuf = smb_RawBufs;
3181 smb_RawBufs = *(char **)smb_RawBufs;
3183 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
3186 lock_ReleaseMutex(&smb_RawBufLock);
3190 lock_ObtainMutex(&fidp->mx);
3191 if (fidp->flags & SMB_FID_IOCTL)
3193 lock_ReleaseMutex(&fidp->mx);
3195 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3197 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
3200 /* Give back raw buffer */
3201 lock_ObtainMutex(&smb_RawBufLock);
3203 *((char **) rawBuf) = smb_RawBufs;
3205 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3208 smb_RawBufs = rawBuf;
3209 lock_ReleaseMutex(&smb_RawBufLock);
3212 smb_ReleaseFID(fidp);
3215 lock_ReleaseMutex(&fidp->mx);
3217 userp = smb_GetUserFromVCP(vcp, inp);
3220 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3222 /* have to give ReadData flag so it will treat buffer as DOS mem. */
3223 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
3224 userp, &finalCount, TRUE /* rawFlag */);
3231 cm_ReleaseUser(userp);
3234 smb_ReleaseFID(fidp);
3239 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
3241 memset((char *)ncbp, 0, sizeof(NCB));
3243 ncbp->ncb_length = (unsigned short) finalCount;
3244 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3245 ncbp->ncb_lana_num = vcp->lana;
3246 ncbp->ncb_command = NCBSEND;
3247 ncbp->ncb_buffer = rawBuf;
3250 code = Netbios(ncbp);
3252 code = Netbios(ncbp, dos_ncb);
3255 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3258 /* Give back raw buffer */
3259 lock_ObtainMutex(&smb_RawBufLock);
3261 *((char **) rawBuf) = smb_RawBufs;
3263 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3266 smb_RawBufs = rawBuf;
3267 lock_ReleaseMutex(&smb_RawBufLock);
3273 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3275 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3280 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3282 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3287 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3294 int VistaProtoIndex;
3295 int protoIndex; /* index we're using */
3300 char protocol_array[10][1024]; /* protocol signature of the client */
3301 int caps; /* capabilities */
3304 TIME_ZONE_INFORMATION tzi;
3306 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3309 namep = smb_GetSMBData(inp, &dbytes);
3312 coreProtoIndex = -1; /* not found */
3315 VistaProtoIndex = -1;
3316 while(namex < dbytes) {
3317 osi_Log1(smb_logp, "Protocol %s",
3318 osi_LogSaveString(smb_logp, namep+1));
3319 strcpy(protocol_array[tcounter], namep+1);
3321 /* namep points at the first protocol, or really, a 0x02
3322 * byte preceding the null-terminated ASCII name.
3324 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3325 coreProtoIndex = tcounter;
3327 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3328 v3ProtoIndex = tcounter;
3330 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3331 NTProtoIndex = tcounter;
3333 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3334 VistaProtoIndex = tcounter;
3337 /* compute size of protocol entry */
3338 entryLength = (int)strlen(namep+1);
3339 entryLength += 2; /* 0x02 bytes and null termination */
3341 /* advance over this protocol entry */
3342 namex += entryLength;
3343 namep += entryLength;
3344 tcounter++; /* which proto entry we're looking at */
3347 lock_ObtainMutex(&vcp->mx);
3349 if (VistaProtoIndex != -1) {
3350 protoIndex = VistaProtoIndex;
3351 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3354 if (NTProtoIndex != -1) {
3355 protoIndex = NTProtoIndex;
3356 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3358 else if (v3ProtoIndex != -1) {
3359 protoIndex = v3ProtoIndex;
3360 vcp->flags |= SMB_VCFLAG_USEV3;
3362 else if (coreProtoIndex != -1) {
3363 protoIndex = coreProtoIndex;
3364 vcp->flags |= SMB_VCFLAG_USECORE;
3366 else protoIndex = -1;
3367 lock_ReleaseMutex(&vcp->mx);
3369 if (protoIndex == -1)
3370 return CM_ERROR_INVAL;
3371 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3372 smb_SetSMBParm(outp, 0, protoIndex);
3373 if (smb_authType != SMB_AUTH_NONE) {
3374 smb_SetSMBParmByte(outp, 1,
3375 NEGOTIATE_SECURITY_USER_LEVEL |
3376 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3378 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3380 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3381 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3382 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3383 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3384 /* The session key is not a well documented field however most clients
3385 * will echo back the session key to the server. Currently we are using
3386 * the same value for all sessions. We should generate a random value
3387 * and store it into the vcp
3389 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3390 smb_SetSMBParm(outp, 8, 1);
3392 * Tried changing the capabilities to support for W2K - defect 117695
3393 * Maybe something else needs to be changed here?
3397 smb_SetSMBParmLong(outp, 9, 0x43fd);
3399 smb_SetSMBParmLong(outp, 9, 0x251);
3402 * 32-bit error codes *
3407 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3409 NTNEGOTIATE_CAPABILITY_DFS |
3411 #ifdef AFS_LARGEFILES
3412 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3414 NTNEGOTIATE_CAPABILITY_NTFIND |
3415 NTNEGOTIATE_CAPABILITY_RAWMODE |
3416 NTNEGOTIATE_CAPABILITY_NTSMB;
3418 if ( smb_authType == SMB_AUTH_EXTENDED )
3419 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3421 smb_SetSMBParmLong(outp, 9, caps);
3423 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3424 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3425 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3427 GetTimeZoneInformation(&tzi);
3428 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3430 if (smb_authType == SMB_AUTH_NTLM) {
3431 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3432 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3433 /* paste in encryption key */
3434 datap = smb_GetSMBData(outp, NULL);
3435 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3436 /* and the faux domain name */
3437 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3438 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3442 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3444 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3446 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3448 datap = smb_GetSMBData(outp, NULL);
3449 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3452 datap += sizeof(smb_ServerGUID);
3453 memcpy(datap, secBlob, secBlobLength);
3457 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3458 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3461 else if (v3ProtoIndex != -1) {
3462 smb_SetSMBParm(outp, 0, protoIndex);
3464 /* NOTE: Extended authentication cannot be negotiated with v3
3465 * therefore we fail over to NTLM
3467 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3468 smb_SetSMBParm(outp, 1,
3469 NEGOTIATE_SECURITY_USER_LEVEL |
3470 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3472 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3474 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3475 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3476 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3477 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3478 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3479 smb_SetSMBParm(outp, 7, 1);
3481 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3482 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3483 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3485 GetTimeZoneInformation(&tzi);
3486 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3488 /* NOTE: Extended authentication cannot be negotiated with v3
3489 * therefore we fail over to NTLM
3491 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3492 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3493 smb_SetSMBParm(outp, 12, 0); /* resvd */
3494 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3495 datap = smb_GetSMBData(outp, NULL);
3496 /* paste in a new encryption key */
3497 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3498 /* and the faux domain name */
3499 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3501 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3502 smb_SetSMBParm(outp, 12, 0); /* resvd */
3503 smb_SetSMBDataLength(outp, 0);
3506 else if (coreProtoIndex != -1) { /* not really supported anymore */
3507 smb_SetSMBParm(outp, 0, protoIndex);
3508 smb_SetSMBDataLength(outp, 0);
3513 void smb_CheckVCs(void)
3515 smb_vc_t * vcp, *nextp;
3516 smb_packet_t * outp = GetPacket();
3519 lock_ObtainWrite(&smb_rctLock);
3520 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3522 if (vcp->magic != SMB_VC_MAGIC)
3523 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3524 __FILE__, __LINE__);
3528 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3531 smb_HoldVCNoLock(vcp);
3533 smb_HoldVCNoLock(nextp);
3534 smb_FormatResponsePacket(vcp, NULL, outp);
3535 smbp = (smb_t *)outp;
3536 outp->inCom = smbp->com = 0x2b /* Echo */;
3544 smb_SetSMBParm(outp, 0, 0);
3545 smb_SetSMBDataLength(outp, 0);
3546 lock_ReleaseWrite(&smb_rctLock);
3548 smb_SendPacket(vcp, outp);
3550 lock_ObtainWrite(&smb_rctLock);
3551 smb_ReleaseVCNoLock(vcp);
3553 smb_ReleaseVCNoLock(nextp);
3555 lock_ReleaseWrite(&smb_rctLock);
3556 smb_FreePacket(outp);
3559 void smb_Daemon(void *parmp)
3561 afs_uint32 count = 0;
3562 smb_username_t **unpp;
3565 while(smbShutdownFlag == 0) {
3569 if (smbShutdownFlag == 1)
3572 if ((count % 72) == 0) { /* every five minutes */
3574 time_t old_localZero = smb_localZero;
3576 /* Initialize smb_localZero */
3577 myTime.tm_isdst = -1; /* compute whether on DST or not */
3578 myTime.tm_year = 70;
3584 smb_localZero = mktime(&myTime);
3586 #ifndef USE_NUMERIC_TIME_CONV
3587 smb_CalculateNowTZ();
3588 #endif /* USE_NUMERIC_TIME_CONV */
3589 #ifdef AFS_FREELANCE
3590 if ( smb_localZero != old_localZero )
3591 cm_noteLocalMountPointChange();
3597 /* GC smb_username_t objects that will no longer be used */
3599 lock_ObtainWrite(&smb_rctLock);
3600 for ( unpp=&usernamesp; *unpp; ) {
3602 smb_username_t *unp;
3604 lock_ObtainMutex(&(*unpp)->mx);
3605 if ( (*unpp)->refCount > 0 ||
3606 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3607 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3609 else if (!smb_LogoffTokenTransfer ||
3610 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3612 lock_ReleaseMutex(&(*unpp)->mx);
3620 lock_FinalizeMutex(&unp->mx);
3626 lock_ReleaseWrite(&smb_rctLock);
3627 cm_ReleaseUser(userp);
3628 lock_ObtainWrite(&smb_rctLock);
3631 unpp = &(*unpp)->nextp;
3634 lock_ReleaseWrite(&smb_rctLock);
3636 /* XXX GC dir search entries */
3640 void smb_WaitingLocksDaemon()
3642 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3643 smb_waitingLock_t *wl, *wlNext;
3646 smb_packet_t *inp, *outp;
3650 while (smbShutdownFlag == 0) {
3651 lock_ObtainWrite(&smb_globalLock);
3652 nwlRequest = smb_allWaitingLocks;
3653 if (nwlRequest == NULL) {
3654 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3659 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3666 lock_ObtainWrite(&smb_globalLock);
3668 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3670 wlRequest = nwlRequest;
3671 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3672 lock_ReleaseWrite(&smb_globalLock);
3676 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3677 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3680 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3682 /* wl->state is either _DONE or _WAITING. _ERROR
3683 would no longer be on the queue. */
3684 code = cm_RetryLock( wl->lockp,
3685 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3688 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3689 } else if (code != CM_ERROR_WOULDBLOCK) {
3690 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3695 if (code == CM_ERROR_WOULDBLOCK) {
3698 if (wlRequest->timeRemaining != 0xffffffff
3699 && (wlRequest->timeRemaining -= 1000) < 0)
3711 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3714 scp = wlRequest->scp;
3715 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3719 lock_ObtainMutex(&scp->mx);
3721 for (wl = wlRequest->locks; wl; wl = wlNext) {
3722 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3724 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3725 wl->LLength, wl->key, NULL, &req);
3727 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3732 lock_ReleaseMutex(&scp->mx);
3736 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3739 for (wl = wlRequest->locks; wl; wl = wlNext) {
3740 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3741 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3746 vcp = wlRequest->vcp;
3747 inp = wlRequest->inp;
3748 outp = wlRequest->outp;
3750 ncbp->ncb_length = inp->ncb_length;
3751 inp->spacep = cm_GetSpace();
3753 /* Remove waitingLock from list */
3754 lock_ObtainWrite(&smb_globalLock);
3755 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3757 lock_ReleaseWrite(&smb_globalLock);
3759 /* Resume packet processing */
3761 smb_SetSMBDataLength(outp, 0);
3762 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3763 outp->resumeCode = code;
3765 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3768 cm_FreeSpace(inp->spacep);
3769 smb_FreePacket(inp);
3770 smb_FreePacket(outp);
3772 cm_ReleaseSCache(wlRequest->scp);
3775 } while (nwlRequest && smbShutdownFlag == 0);
3780 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3782 osi_Log0(smb_logp, "SMB receive get disk attributes");
3784 smb_SetSMBParm(outp, 0, 32000);
3785 smb_SetSMBParm(outp, 1, 64);
3786 smb_SetSMBParm(outp, 2, 1024);
3787 smb_SetSMBParm(outp, 3, 30000);
3788 smb_SetSMBParm(outp, 4, 0);
3789 smb_SetSMBDataLength(outp, 0);
3793 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3797 unsigned short newTid;
3798 char shareName[AFSPATHMAX];
3806 osi_Log0(smb_logp, "SMB receive tree connect");
3808 /* parse input parameters */
3809 tp = smb_GetSMBData(inp, NULL);
3810 pathp = smb_ParseASCIIBlock(tp, &tp);
3811 if (smb_StoreAnsiFilenames)
3812 OemToChar(pathp,pathp);
3813 passwordp = smb_ParseASCIIBlock(tp, &tp);
3814 tp = strrchr(pathp, '\\');
3816 return CM_ERROR_BADSMB;
3817 strcpy(shareName, tp+1);
3819 lock_ObtainMutex(&vcp->mx);
3820 newTid = vcp->tidCounter++;
3821 lock_ReleaseMutex(&vcp->mx);
3823 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3824 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3825 userp = smb_GetUserFromUID(uidp);
3826 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3828 smb_ReleaseUID(uidp);
3830 smb_ReleaseTID(tidp);
3831 return CM_ERROR_BADSHARENAME;
3833 lock_ObtainMutex(&tidp->mx);
3834 tidp->userp = userp;
3835 tidp->pathname = sharePath;
3836 lock_ReleaseMutex(&tidp->mx);
3837 smb_ReleaseTID(tidp);
3839 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3840 smb_SetSMBParm(rsp, 1, newTid);
3841 smb_SetSMBDataLength(rsp, 0);
3843 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3847 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3851 if (*inp++ != 0x1) return NULL;
3852 tlen = inp[0] + (inp[1]<<8);
3853 inp += 2; /* skip length field */
3856 *chainpp = inp + tlen;
3859 if (lengthp) *lengthp = tlen;
3864 /* set maskp to the mask part of the incoming path.
3865 * Mask is 11 bytes long (8.3 with the dot elided).
3866 * Returns true if succeeds with a valid name, otherwise it does
3867 * its best, but returns false.
3869 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3877 /* starts off valid */
3880 /* mask starts out all blanks */
3881 memset(maskp, ' ', 11);
3883 /* find last backslash, or use whole thing if there is none */
3884 tp = strrchr(pathp, '\\');
3885 if (!tp) tp = pathp;
3886 else tp++; /* skip slash */
3890 /* names starting with a dot are illegal */
3891 if (*tp == '.') valid8Dot3 = 0;
3895 if (tc == 0) return valid8Dot3;
3896 if (tc == '.' || tc == '"') break;
3897 if (i < 8) *up++ = tc;
3898 else valid8Dot3 = 0;
3901 /* if we get here, tp point after the dot */
3902 up = maskp+8; /* ext goes here */
3909 if (tc == '.' || tc == '"')
3912 /* copy extension if not too long */
3922 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3932 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3934 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3938 /* otherwise, we have a valid 8.3 name; see if we have a match,
3939 * treating '?' as a wildcard in maskp (but not in the file name).
3941 tp1 = umask; /* real name, in mask format */
3942 tp2 = maskp; /* mask, in mask format */
3943 for(i=0; i<11; i++) {
3944 tc1 = *tp1++; /* char from real name */
3945 tc2 = *tp2++; /* char from mask */
3946 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3947 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3950 if (tc2 == '?' && tc1 != ' ')
3957 /* we got a match */
3961 char *smb_FindMask(char *pathp)
3965 tp = strrchr(pathp, '\\'); /* find last slash */
3968 return tp+1; /* skip the slash */
3970 return pathp; /* no slash, return the entire path */
3973 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3975 unsigned char *pathp;
3977 unsigned char mask[11];
3978 unsigned char *statBlockp;
3979 unsigned char initStatBlock[21];
3982 osi_Log0(smb_logp, "SMB receive search volume");
3984 /* pull pathname and stat block out of request */
3985 tp = smb_GetSMBData(inp, NULL);
3986 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3987 osi_assert(pathp != NULL);
3988 if (smb_StoreAnsiFilenames)
3989 OemToChar(pathp,pathp);
3990 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3991 osi_assert(statBlockp != NULL);
3993 statBlockp = initStatBlock;
3997 /* for returning to caller */
3998 smb_Get8Dot3MaskFromPath(mask, pathp);
4000 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4001 tp = smb_GetSMBData(outp, NULL);
4003 *tp++ = 43; /* bytes in a dir entry */
4004 *tp++ = 0; /* high byte in counter */
4006 /* now marshall the dir entry, starting with the search status */
4007 *tp++ = statBlockp[0]; /* Reserved */
4008 memcpy(tp, mask, 11); tp += 11; /* FileName */
4010 /* now pass back server use info, with 1st byte non-zero */
4012 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4014 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4016 *tp++ = 0x8; /* attribute: volume */
4026 /* 4 byte file size */
4032 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4033 memset(tp, ' ', 13);
4036 /* set the length of the data part of the packet to 43 + 3, for the dir
4037 * entry plus the 5 and the length fields.
4039 smb_SetSMBDataLength(outp, 46);
4043 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
4044 cm_user_t *userp, cm_req_t *reqp)
4052 smb_dirListPatch_t *patchp;
4053 smb_dirListPatch_t *npatchp;
4055 for (patchp = *dirPatchespp; patchp; patchp =
4056 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4058 dptr = patchp->dptr;
4060 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4062 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4063 *dptr++ = SMB_ATTR_HIDDEN;
4066 lock_ObtainMutex(&scp->mx);
4067 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
4068 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4070 lock_ReleaseMutex(&scp->mx);
4071 cm_ReleaseSCache(scp);
4072 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4073 *dptr++ = SMB_ATTR_HIDDEN;
4077 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4079 attr = smb_Attributes(scp);
4080 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4081 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4082 attr |= SMB_ATTR_HIDDEN;
4086 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4089 shortTemp = (unsigned short) (dosTime & 0xffff);
4090 *((u_short *)dptr) = shortTemp;
4093 /* and copy out date */
4094 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4095 *((u_short *)dptr) = shortTemp;
4098 /* copy out file length */
4099 *((u_long *)dptr) = scp->length.LowPart;
4101 lock_ReleaseMutex(&scp->mx);
4102 cm_ReleaseSCache(scp);
4105 /* now free the patches */
4106 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4107 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4111 /* and mark the list as empty */
4112 *dirPatchespp = NULL;
4117 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4126 smb_dirListPatch_t *dirListPatchesp;
4127 smb_dirListPatch_t *curPatchp;
4131 osi_hyper_t dirLength;
4132 osi_hyper_t bufferOffset;
4133 osi_hyper_t curOffset;
4135 unsigned char *inCookiep;
4136 smb_dirSearch_t *dsp;
4140 unsigned long clientCookie;
4141 cm_pageHeader_t *pageHeaderp;
4142 cm_user_t *userp = NULL;
4149 long nextEntryCookie;
4150 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4151 char resByte; /* reserved byte from the cookie */
4152 char *op; /* output data ptr */
4153 char *origOp; /* original value of op */
4154 cm_space_t *spacep; /* for pathname buffer */
4165 maxCount = smb_GetSMBParm(inp, 0);
4167 dirListPatchesp = NULL;
4169 caseFold = CM_FLAG_CASEFOLD;
4171 tp = smb_GetSMBData(inp, NULL);
4172 pathp = smb_ParseASCIIBlock(tp, &tp);
4173 if (smb_StoreAnsiFilenames)
4174 OemToChar(pathp,pathp);
4175 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4177 /* bail out if request looks bad */
4178 if (!tp || !pathp) {
4179 return CM_ERROR_BADSMB;
4182 /* We can handle long names */
4183 if (vcp->flags & SMB_VCFLAG_USENT)
4184 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4186 /* make sure we got a whole search status */
4187 if (dataLength < 21) {
4188 nextCookie = 0; /* start at the beginning of the dir */
4191 attribute = smb_GetSMBParm(inp, 1);
4193 /* handle volume info in another function */
4194 if (attribute & 0x8)
4195 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4197 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
4198 maxCount, osi_LogSaveString(smb_logp, pathp));
4200 if (*pathp == 0) { /* null pathp, treat as root dir */
4201 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4202 return CM_ERROR_NOFILES;
4206 dsp = smb_NewDirSearch(0);
4207 dsp->attribute = attribute;
4208 smb_Get8Dot3MaskFromPath(mask, pathp);
4209 memcpy(dsp->mask, mask, 11);
4211 /* track if this is likely to match a lot of entries */
4212 if (smb_IsStarMask(mask))
4217 /* pull the next cookie value out of the search status block */
4218 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4219 + (inCookiep[16]<<24);
4220 dsp = smb_FindDirSearch(inCookiep[12]);
4222 /* can't find dir search status; fatal error */
4223 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
4224 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
4225 return CM_ERROR_BADFD;
4227 attribute = dsp->attribute;
4228 resByte = inCookiep[0];
4230 /* copy out client cookie, in host byte order. Don't bother
4231 * interpreting it, since we're just passing it through, anyway.
4233 memcpy(&clientCookie, &inCookiep[17], 4);
4235 memcpy(mask, dsp->mask, 11);
4237 /* assume we're doing a star match if it has continued for more
4243 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4244 nextCookie, dsp->cookie, attribute);
4246 userp = smb_GetUserFromVCP(vcp, inp);
4248 /* try to get the vnode for the path name next */
4249 lock_ObtainMutex(&dsp->mx);
4252 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4256 spacep = inp->spacep;
4257 smb_StripLastComponent(spacep->data, NULL, pathp);
4258 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4260 lock_ReleaseMutex(&dsp->mx);
4261 cm_ReleaseUser(userp);
4262 smb_DeleteDirSearch(dsp);
4263 smb_ReleaseDirSearch(dsp);
4264 return CM_ERROR_NOFILES;
4266 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4267 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4270 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4271 cm_ReleaseSCache(scp);
4272 lock_ReleaseMutex(&dsp->mx);
4273 cm_ReleaseUser(userp);
4274 smb_DeleteDirSearch(dsp);
4275 smb_ReleaseDirSearch(dsp);
4276 if ( WANTS_DFS_PATHNAMES(inp) )
4277 return CM_ERROR_PATH_NOT_COVERED;
4279 return CM_ERROR_BADSHARENAME;
4281 #endif /* DFS_SUPPORT */
4284 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4285 /* we need one hold for the entry we just stored into,
4286 * and one for our own processing. When we're done with this
4287 * function, we'll drop the one for our own processing.
4288 * We held it once from the namei call, and so we do another hold
4292 lock_ObtainMutex(&scp->mx);
4293 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4294 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4295 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4296 dsp->flags |= SMB_DIRSEARCH_BULKST;
4297 dsp->scp->bulkStatProgress = hzero;
4299 lock_ReleaseMutex(&scp->mx);
4302 lock_ReleaseMutex(&dsp->mx);
4304 cm_ReleaseUser(userp);
4305 smb_DeleteDirSearch(dsp);
4306 smb_ReleaseDirSearch(dsp);
4310 /* reserves space for parameter; we'll adjust it again later to the
4311 * real count of the # of entries we returned once we've actually
4312 * assembled the directory listing.
4314 smb_SetSMBParm(outp, 0, 0);
4316 /* get the directory size */
4317 lock_ObtainMutex(&scp->mx);
4318 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4319 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4321 lock_ReleaseMutex(&scp->mx);
4322 cm_ReleaseSCache(scp);
4323 cm_ReleaseUser(userp);
4324 smb_DeleteDirSearch(dsp);
4325 smb_ReleaseDirSearch(dsp);
4329 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4331 dirLength = scp->length;
4333 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4334 curOffset.HighPart = 0;
4335 curOffset.LowPart = nextCookie;
4336 origOp = op = smb_GetSMBData(outp, NULL);
4337 /* and write out the basic header */
4338 *op++ = 5; /* variable block */
4339 op += 2; /* skip vbl block length; we'll fill it in later */
4343 /* make sure that curOffset.LowPart doesn't point to the first
4344 * 32 bytes in the 2nd through last dir page, and that it doesn't
4345 * point at the first 13 32-byte chunks in the first dir page,
4346 * since those are dir and page headers, and don't contain useful
4349 temp = curOffset.LowPart & (2048-1);
4350 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4351 /* we're in the first page */
4352 if (temp < 13*32) temp = 13*32;
4355 /* we're in a later dir page */
4356 if (temp < 32) temp = 32;
4359 /* make sure the low order 5 bits are zero */
4362 /* now put temp bits back ito curOffset.LowPart */
4363 curOffset.LowPart &= ~(2048-1);
4364 curOffset.LowPart |= temp;
4366 /* check if we've returned all the names that will fit in the
4369 if (returnedNames >= maxCount) {
4370 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4371 returnedNames, maxCount);
4375 /* check if we've passed the dir's EOF */
4376 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4378 /* see if we can use the bufferp we have now; compute in which page
4379 * the current offset would be, and check whether that's the offset
4380 * of the buffer we have. If not, get the buffer.
4382 thyper.HighPart = curOffset.HighPart;
4383 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4384 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4387 buf_Release(bufferp);
4390 lock_ReleaseMutex(&scp->mx);
4391 lock_ObtainRead(&scp->bufCreateLock);
4392 code = buf_Get(scp, &thyper, &bufferp);
4393 lock_ReleaseRead(&scp->bufCreateLock);
4394 lock_ObtainMutex(&dsp->mx);
4396 /* now, if we're doing a star match, do bulk fetching of all of
4397 * the status info for files in the dir.
4400 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4401 lock_ObtainMutex(&scp->mx);
4402 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4403 LargeIntegerGreaterThanOrEqualTo(thyper,
4404 scp->bulkStatProgress)) {
4405 /* Don't bulk stat if risking timeout */
4406 int now = GetTickCount();
4407 if (now - req.startTime > RDRtimeout * 1000) {
4408 scp->bulkStatProgress = thyper;
4409 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4410 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4411 dsp->scp->bulkStatProgress = hzero;
4413 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4416 lock_ObtainMutex(&scp->mx);
4418 lock_ReleaseMutex(&dsp->mx);
4420 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4424 bufferOffset = thyper;
4426 /* now get the data in the cache */
4428 code = cm_SyncOp(scp, bufferp, userp, &req,
4430 CM_SCACHESYNC_NEEDCALLBACK |
4431 CM_SCACHESYNC_READ);
4433 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4437 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4439 if (cm_HaveBuffer(scp, bufferp, 0)) {
4440 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4444 /* otherwise, load the buffer and try again */
4445 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4447 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4448 scp, bufferp, code);
4453 buf_Release(bufferp);
4457 } /* if (wrong buffer) ... */
4459 /* now we have the buffer containing the entry we're interested in; copy
4460 * it out if it represents a non-deleted entry.
4462 entryInDir = curOffset.LowPart & (2048-1);
4463 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4465 /* page header will help tell us which entries are free. Page header
4466 * can change more often than once per buffer, since AFS 3 dir page size
4467 * may be less than (but not more than a buffer package buffer.
4469 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4470 temp &= ~(2048 - 1); /* turn off intra-page bits */
4471 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4473 /* now determine which entry we're looking at in the page. If it is
4474 * free (there's a free bitmap at the start of the dir), we should
4475 * skip these 32 bytes.
4477 slotInPage = (entryInDir & 0x7e0) >> 5;
4478 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4479 /* this entry is free */
4480 numDirChunks = 1; /* only skip this guy */
4484 tp = bufferp->datap + entryInBuffer;
4485 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4487 /* while we're here, compute the next entry's location, too,
4488 * since we'll need it when writing out the cookie into the dir
4491 * XXXX Probably should do more sanity checking.
4493 numDirChunks = cm_NameEntries(dep->name, NULL);
4495 /* compute the offset of the cookie representing the next entry */
4496 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4498 /* Compute 8.3 name if necessary */
4499 actualName = dep->name;
4500 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4501 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4502 actualName = shortName;
4505 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4506 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4507 osi_LogSaveString(smb_logp, actualName));
4509 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4510 /* this is one of the entries to use: it is not deleted
4511 * and it matches the star pattern we're looking for.
4514 /* Eliminate entries that don't match requested
4517 /* no hidden files */
4518 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4519 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4523 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4525 /* We have already done the cm_TryBulkStat above */
4526 fid.cell = scp->fid.cell;
4527 fid.volume = scp->fid.volume;
4528 fid.vnode = ntohl(dep->fid.vnode);
4529 fid.unique = ntohl(dep->fid.unique);
4530 fileType = cm_FindFileType(&fid);
4531 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4532 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4534 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4535 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4536 fileType == CM_SCACHETYPE_DFSLINK ||
4537 fileType == CM_SCACHETYPE_INVALID)
4538 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4543 memcpy(op, mask, 11); op += 11;
4544 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4545 *op++ = (char)(nextEntryCookie & 0xff);
4546 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4547 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4548 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4549 memcpy(op, &clientCookie, 4); op += 4;
4551 /* now we emit the attribute. This is sort of tricky,
4552 * since we need to really stat the file to find out
4553 * what type of entry we've got. Right now, we're
4554 * copying out data from a buffer, while holding the
4555 * scp locked, so it isn't really convenient to stat
4556 * something now. We'll put in a place holder now,
4557 * and make a second pass before returning this to get
4558 * the real attributes. So, we just skip the data for
4559 * now, and adjust it later. We allocate a patch
4560 * record to make it easy to find this point later.
4561 * The replay will happen at a time when it is safe to
4562 * unlock the directory.
4564 curPatchp = malloc(sizeof(*curPatchp));
4565 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4566 curPatchp->dptr = op;
4567 curPatchp->fid.cell = scp->fid.cell;
4568 curPatchp->fid.volume = scp->fid.volume;
4569 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4570 curPatchp->fid.unique = ntohl(dep->fid.unique);
4572 /* do hidden attribute here since name won't be around when applying
4576 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4577 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4579 curPatchp->flags = 0;
4581 op += 9; /* skip attr, time, date and size */
4583 /* zero out name area. The spec says to pad with
4584 * spaces, but Samba doesn't, and neither do we.
4588 /* finally, we get to copy out the name; we know that
4589 * it fits in 8.3 or the pattern wouldn't match, but it
4590 * never hurts to be sure.
4592 strncpy(op, actualName, 13);
4593 if (smb_StoreAnsiFilenames)
4596 /* Uppercase if requested by client */
4597 if (!KNOWS_LONG_NAMES(inp))
4602 /* now, adjust the # of entries copied */
4604 } /* if we're including this name */
4607 /* and adjust curOffset to be where the new cookie is */
4608 thyper.HighPart = 0;
4609 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4610 curOffset = LargeIntegerAdd(thyper, curOffset);
4611 } /* while copying data for dir listing */
4613 /* release the mutex */
4614 lock_ReleaseMutex(&scp->mx);
4616 buf_Release(bufferp);
4620 /* apply and free last set of patches; if not doing a star match, this
4621 * will be empty, but better safe (and freeing everything) than sorry.
4623 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4625 /* special return code for unsuccessful search */
4626 if (code == 0 && dataLength < 21 && returnedNames == 0)
4627 code = CM_ERROR_NOFILES;
4629 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4630 returnedNames, code);
4633 smb_DeleteDirSearch(dsp);
4634 smb_ReleaseDirSearch(dsp);
4635 cm_ReleaseSCache(scp);
4636 cm_ReleaseUser(userp);
4640 /* finalize the output buffer */
4641 smb_SetSMBParm(outp, 0, returnedNames);
4642 temp = (long) (op - origOp);
4643 smb_SetSMBDataLength(outp, temp);
4645 /* the data area is a variable block, which has a 5 (already there)
4646 * followed by the length of the # of data bytes. We now know this to
4647 * be "temp," although that includes the 3 bytes of vbl block header.
4648 * Deduct for them and fill in the length field.
4650 temp -= 3; /* deduct vbl block info */
4651 osi_assert(temp == (43 * returnedNames));
4652 origOp[1] = (char)(temp & 0xff);
4653 origOp[2] = (char)((temp>>8) & 0xff);
4654 if (returnedNames == 0)
4655 smb_DeleteDirSearch(dsp);
4656 smb_ReleaseDirSearch(dsp);
4657 cm_ReleaseSCache(scp);
4658 cm_ReleaseUser(userp);
4662 /* verify that this is a valid path to a directory. I don't know why they
4663 * don't use the get file attributes call.
4665 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4669 cm_scache_t *rootScp;
4670 cm_scache_t *newScp;
4679 pathp = smb_GetSMBData(inp, NULL);
4680 pathp = smb_ParseASCIIBlock(pathp, NULL);
4682 return CM_ERROR_BADFD;
4683 if (smb_StoreAnsiFilenames)
4684 OemToChar(pathp,pathp);
4685 osi_Log1(smb_logp, "SMB receive check path %s",
4686 osi_LogSaveString(smb_logp, pathp));
4688 rootScp = cm_data.rootSCachep;
4690 userp = smb_GetUserFromVCP(vcp, inp);
4692 caseFold = CM_FLAG_CASEFOLD;
4694 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4696 cm_ReleaseUser(userp);
4697 return CM_ERROR_NOSUCHPATH;
4699 code = cm_NameI(rootScp, pathp,
4700 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4701 userp, tidPathp, &req, &newScp);
4704 cm_ReleaseUser(userp);
4709 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4710 cm_ReleaseSCache(newScp);
4711 cm_ReleaseUser(userp);
4712 if ( WANTS_DFS_PATHNAMES(inp) )
4713 return CM_ERROR_PATH_NOT_COVERED;
4715 return CM_ERROR_BADSHARENAME;
4717 #endif /* DFS_SUPPORT */
4719 /* now lock the vnode with a callback; returns with newScp locked */
4720 lock_ObtainMutex(&newScp->mx);
4721 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4722 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4724 if (code != CM_ERROR_NOACCESS) {
4725 lock_ReleaseMutex(&newScp->mx);
4726 cm_ReleaseSCache(newScp);
4727 cm_ReleaseUser(userp);
4731 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4734 attrs = smb_Attributes(newScp);
4736 if (!(attrs & SMB_ATTR_DIRECTORY))
4737 code = CM_ERROR_NOTDIR;
4739 lock_ReleaseMutex(&newScp->mx);
4741 cm_ReleaseSCache(newScp);
4742 cm_ReleaseUser(userp);
4746 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4750 cm_scache_t *rootScp;
4751 unsigned short attribute;
4753 cm_scache_t *newScp;
4762 /* decode basic attributes we're passed */
4763 attribute = smb_GetSMBParm(inp, 0);
4764 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4766 pathp = smb_GetSMBData(inp, NULL);
4767 pathp = smb_ParseASCIIBlock(pathp, NULL);
4769 return CM_ERROR_BADSMB;
4770 if (smb_StoreAnsiFilenames)
4771 OemToChar(pathp,pathp);
4773 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4774 dosTime, attribute);
4776 rootScp = cm_data.rootSCachep;
4778 userp = smb_GetUserFromVCP(vcp, inp);
4780 caseFold = CM_FLAG_CASEFOLD;
4782 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4784 cm_ReleaseUser(userp);
4785 return CM_ERROR_NOSUCHFILE;
4787 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4788 tidPathp, &req, &newScp);
4791 cm_ReleaseUser(userp);
4796 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4797 cm_ReleaseSCache(newScp);
4798 cm_ReleaseUser(userp);
4799 if ( WANTS_DFS_PATHNAMES(inp) )
4800 return CM_ERROR_PATH_NOT_COVERED;
4802 return CM_ERROR_BADSHARENAME;
4804 #endif /* DFS_SUPPORT */
4806 /* now lock the vnode with a callback; returns with newScp locked; we
4807 * need the current status to determine what the new status is, in some
4810 lock_ObtainMutex(&newScp->mx);
4811 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4812 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4814 lock_ReleaseMutex(&newScp->mx);
4815 cm_ReleaseSCache(newScp);
4816 cm_ReleaseUser(userp);
4820 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4822 /* Check for RO volume */
4823 if (newScp->flags & CM_SCACHEFLAG_RO) {
4824 lock_ReleaseMutex(&newScp->mx);
4825 cm_ReleaseSCache(newScp);
4826 cm_ReleaseUser(userp);
4827 return CM_ERROR_READONLY;
4830 /* prepare for setattr call */
4833 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4834 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4836 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4837 /* we're told to make a writable file read-only */
4838 attr.unixModeBits = newScp->unixModeBits & ~0222;
4839 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4841 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4842 /* we're told to make a read-only file writable */
4843 attr.unixModeBits = newScp->unixModeBits | 0222;
4844 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4846 lock_ReleaseMutex(&newScp->mx);
4848 /* now call setattr */
4850 code = cm_SetAttr(newScp, &attr, userp, &req);
4854 cm_ReleaseSCache(newScp);
4855 cm_ReleaseUser(userp);
4860 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4864 cm_scache_t *rootScp;
4865 cm_scache_t *newScp, *dscp;
4877 pathp = smb_GetSMBData(inp, NULL);
4878 pathp = smb_ParseASCIIBlock(pathp, NULL);
4880 return CM_ERROR_BADSMB;
4882 if (*pathp == 0) /* null path */
4885 if (smb_StoreAnsiFilenames)
4886 OemToChar(pathp,pathp);
4888 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4889 osi_LogSaveString(smb_logp, pathp));
4891 rootScp = cm_data.rootSCachep;
4893 userp = smb_GetUserFromVCP(vcp, inp);
4895 /* we shouldn't need this for V3 requests, but we seem to */
4896 caseFold = CM_FLAG_CASEFOLD;
4898 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4900 cm_ReleaseUser(userp);
4901 return CM_ERROR_NOSUCHFILE;
4905 * XXX Strange hack XXX
4907 * As of Patch 5 (16 July 97), we are having the following problem:
4908 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4909 * requests to look up "desktop.ini" in all the subdirectories.
4910 * This can cause zillions of timeouts looking up non-existent cells
4911 * and volumes, especially in the top-level directory.
4913 * We have not found any way to avoid this or work around it except
4914 * to explicitly ignore the requests for mount points that haven't
4915 * yet been evaluated and for directories that haven't yet been
4918 * We should modify this hack to provide a fake desktop.ini file
4919 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4921 spacep = inp->spacep;
4922 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4923 #ifndef SPECIAL_FOLDERS
4924 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4925 code = cm_NameI(rootScp, spacep->data,
4926 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4927 userp, tidPathp, &req, &dscp);
4930 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4931 if ( WANTS_DFS_PATHNAMES(inp) )
4932 return CM_ERROR_PATH_NOT_COVERED;
4934 return CM_ERROR_BADSHARENAME;
4936 #endif /* DFS_SUPPORT */
4937 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4938 code = CM_ERROR_NOSUCHFILE;
4939 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4940 cm_buf_t *bp = buf_Find(dscp, &hzero);
4945 code = CM_ERROR_NOSUCHFILE;
4947 cm_ReleaseSCache(dscp);
4949 cm_ReleaseUser(userp);
4954 #endif /* SPECIAL_FOLDERS */
4956 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4957 tidPathp, &req, &newScp);
4959 cm_ReleaseUser(userp);
4964 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4965 cm_ReleaseSCache(newScp);
4966 cm_ReleaseUser(userp);
4967 if ( WANTS_DFS_PATHNAMES(inp) )
4968 return CM_ERROR_PATH_NOT_COVERED;
4970 return CM_ERROR_BADSHARENAME;
4972 #endif /* DFS_SUPPORT */
4974 /* now lock the vnode with a callback; returns with newScp locked */
4975 lock_ObtainMutex(&newScp->mx);
4976 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4977 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4979 lock_ReleaseMutex(&newScp->mx);
4980 cm_ReleaseSCache(newScp);
4981 cm_ReleaseUser(userp);
4985 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4988 /* use smb_Attributes instead. Also the fact that a file is
4989 * in a readonly volume doesn't mean it shojuld be marked as RO
4991 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4992 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4993 newScp->fileType == CM_SCACHETYPE_INVALID)
4994 attrs = SMB_ATTR_DIRECTORY;
4997 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4998 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
5000 attrs = smb_Attributes(newScp);
5003 smb_SetSMBParm(outp, 0, attrs);
5005 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5006 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5007 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5008 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5009 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5010 smb_SetSMBParm(outp, 5, 0);
5011 smb_SetSMBParm(outp, 6, 0);
5012 smb_SetSMBParm(outp, 7, 0);
5013 smb_SetSMBParm(outp, 8, 0);
5014 smb_SetSMBParm(outp, 9, 0);
5015 smb_SetSMBDataLength(outp, 0);
5016 lock_ReleaseMutex(&newScp->mx);
5018 cm_ReleaseSCache(newScp);
5019 cm_ReleaseUser(userp);
5024 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5028 osi_Log0(smb_logp, "SMB receive tree disconnect");
5030 /* find the tree and free it */
5031 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5033 lock_ObtainWrite(&smb_rctLock);
5035 lock_ReleaseWrite(&smb_rctLock);
5036 smb_ReleaseTID(tidp);
5042 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5060 pathp = smb_GetSMBData(inp, NULL);
5061 pathp = smb_ParseASCIIBlock(pathp, NULL);
5062 if (smb_StoreAnsiFilenames)
5063 OemToChar(pathp,pathp);
5065 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
5067 #ifdef DEBUG_VERBOSE
5071 hexpath = osi_HexifyString( pathp );
5072 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5077 share = smb_GetSMBParm(inp, 0);
5078 attribute = smb_GetSMBParm(inp, 1);
5080 spacep = inp->spacep;
5081 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5082 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5083 /* special case magic file name for receiving IOCTL requests
5084 * (since IOCTL calls themselves aren't getting through).
5086 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5087 smb_SetupIoctlFid(fidp, spacep);
5088 smb_SetSMBParm(outp, 0, fidp->fid);
5089 smb_SetSMBParm(outp, 1, 0); /* attrs */
5090 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5091 smb_SetSMBParm(outp, 3, 0);
5092 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5093 smb_SetSMBParm(outp, 5, 0x7fff);
5094 /* pass the open mode back */
5095 smb_SetSMBParm(outp, 6, (share & 0xf));
5096 smb_SetSMBDataLength(outp, 0);
5097 smb_ReleaseFID(fidp);
5101 userp = smb_GetUserFromVCP(vcp, inp);
5103 caseFold = CM_FLAG_CASEFOLD;
5105 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5107 cm_ReleaseUser(userp);
5108 return CM_ERROR_NOSUCHPATH;
5110 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5111 tidPathp, &req, &scp);
5114 cm_ReleaseUser(userp);
5119 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5120 cm_ReleaseSCache(scp);
5121 cm_ReleaseUser(userp);
5122 if ( WANTS_DFS_PATHNAMES(inp) )
5123 return CM_ERROR_PATH_NOT_COVERED;
5125 return CM_ERROR_BADSHARENAME;
5127 #endif /* DFS_SUPPORT */
5129 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5131 cm_ReleaseSCache(scp);
5132 cm_ReleaseUser(userp);
5136 /* don't need callback to check file type, since file types never
5137 * change, and namei and cm_Lookup all stat the object at least once on
5138 * a successful return.
5140 if (scp->fileType != CM_SCACHETYPE_FILE) {
5141 cm_ReleaseSCache(scp);
5142 cm_ReleaseUser(userp);
5143 return CM_ERROR_ISDIR;
5146 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5149 /* save a pointer to the vnode */
5151 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5152 lock_ObtainMutex(&scp->mx);
5153 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5154 lock_ReleaseMutex(&scp->mx);
5158 fidp->userp = userp;
5160 lock_ObtainMutex(&fidp->mx);
5161 if ((share & 0xf) == 0)
5162 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5163 else if ((share & 0xf) == 1)
5164 fidp->flags |= SMB_FID_OPENWRITE;
5166 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5167 lock_ReleaseMutex(&fidp->mx);
5169 lock_ObtainMutex(&scp->mx);
5170 smb_SetSMBParm(outp, 0, fidp->fid);
5171 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5172 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5173 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5174 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5175 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5176 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5177 /* pass the open mode back; XXXX add access checks */
5178 smb_SetSMBParm(outp, 6, (share & 0xf));
5179 smb_SetSMBDataLength(outp, 0);
5180 lock_ReleaseMutex(&scp->mx);
5183 cm_Open(scp, 0, userp);
5185 /* send and free packet */
5186 smb_ReleaseFID(fidp);
5187 cm_ReleaseUser(userp);
5188 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5192 typedef struct smb_unlinkRock {
5197 char *maskp; /* pointer to the star pattern */
5200 cm_dirEntryList_t * matches;
5203 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5206 smb_unlinkRock_t *rockp;
5214 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5215 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5216 caseFold |= CM_FLAG_8DOT3;
5218 matchName = dep->name;
5219 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
5221 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5222 !cm_Is8Dot3(dep->name)) {
5223 cm_Gen8Dot3Name(dep, shortName, NULL);
5224 matchName = shortName;
5225 /* 8.3 matches are always case insensitive */
5226 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5229 osi_Log1(smb_logp, "Found match %s",
5230 osi_LogSaveString(smb_logp, matchName));
5232 cm_DirEntryListAdd(dep->name, &rockp->matches);
5236 /* If we made a case sensitive exact match, we might as well quit now. */
5237 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
5238 code = CM_ERROR_STOPNOW;
5247 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5256 smb_unlinkRock_t rock;
5265 attribute = smb_GetSMBParm(inp, 0);
5267 tp = smb_GetSMBData(inp, NULL);
5268 pathp = smb_ParseASCIIBlock(tp, &tp);
5269 if (smb_StoreAnsiFilenames)
5270 OemToChar(pathp,pathp);
5272 osi_Log1(smb_logp, "SMB receive unlink %s",
5273 osi_LogSaveString(smb_logp, pathp));
5275 spacep = inp->spacep;
5276 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5278 userp = smb_GetUserFromVCP(vcp, inp);
5280 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5282 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5284 cm_ReleaseUser(userp);
5285 return CM_ERROR_NOSUCHPATH;
5287 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5290 cm_ReleaseUser(userp);
5295 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5296 cm_ReleaseSCache(dscp);
5297 cm_ReleaseUser(userp);
5298 if ( WANTS_DFS_PATHNAMES(inp) )
5299 return CM_ERROR_PATH_NOT_COVERED;
5301 return CM_ERROR_BADSHARENAME;
5303 #endif /* DFS_SUPPORT */
5305 /* otherwise, scp points to the parent directory. */
5312 rock.maskp = smb_FindMask(pathp);
5313 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5316 thyper.HighPart = 0;
5321 rock.matches = NULL;
5323 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5324 * match. If that fails, we do a case insensitve match.
5326 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5327 !smb_IsStarMask(rock.maskp)) {
5328 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5331 thyper.HighPart = 0;
5332 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5337 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5339 if (code == CM_ERROR_STOPNOW)
5342 if (code == 0 && rock.matches) {
5343 cm_dirEntryList_t * entry;
5345 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5347 osi_Log1(smb_logp, "Unlinking %s",
5348 osi_LogSaveString(smb_logp, entry->name));
5349 code = cm_Unlink(dscp, entry->name, userp, &req);
5351 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5352 smb_NotifyChange(FILE_ACTION_REMOVED,
5353 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5354 dscp, entry->name, NULL, TRUE);
5358 cm_DirEntryListFree(&rock.matches);
5360 cm_ReleaseUser(userp);
5362 cm_ReleaseSCache(dscp);
5364 if (code == 0 && !rock.any)
5365 code = CM_ERROR_NOSUCHFILE;
5369 typedef struct smb_renameRock {
5370 cm_scache_t *odscp; /* old dir */
5371 cm_scache_t *ndscp; /* new dir */
5372 cm_user_t *userp; /* user */
5373 cm_req_t *reqp; /* request struct */
5374 smb_vc_t *vcp; /* virtual circuit */
5375 char *maskp; /* pointer to star pattern of old file name */
5376 int flags; /* tilde, casefold, etc */
5377 char *newNamep; /* ptr to the new file's name */
5378 char oldName[MAX_PATH];
5382 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5385 smb_renameRock_t *rockp;
5388 char shortName[13]="";
5390 rockp = (smb_renameRock_t *) vrockp;
5392 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5393 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5394 caseFold |= CM_FLAG_8DOT3;
5396 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5398 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5399 !cm_Is8Dot3(dep->name)) {
5400 cm_Gen8Dot3Name(dep, shortName, NULL);
5401 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5406 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5407 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5408 code = CM_ERROR_STOPNOW;
5418 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5421 cm_space_t *spacep = NULL;
5422 smb_renameRock_t rock;
5423 cm_scache_t *oldDscp = NULL;
5424 cm_scache_t *newDscp = NULL;
5425 cm_scache_t *tmpscp= NULL;
5426 cm_scache_t *tmpscp2 = NULL;
5436 userp = smb_GetUserFromVCP(vcp, inp);
5437 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5439 cm_ReleaseUser(userp);
5440 return CM_ERROR_NOSUCHPATH;
5444 spacep = inp->spacep;
5445 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5447 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5448 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5449 userp, tidPathp, &req, &oldDscp);
5451 cm_ReleaseUser(userp);
5456 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5457 cm_ReleaseSCache(oldDscp);
5458 cm_ReleaseUser(userp);
5459 if ( WANTS_DFS_PATHNAMES(inp) )
5460 return CM_ERROR_PATH_NOT_COVERED;
5462 return CM_ERROR_BADSHARENAME;
5464 #endif /* DFS_SUPPORT */
5466 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5467 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5468 userp, tidPathp, &req, &newDscp);
5471 cm_ReleaseSCache(oldDscp);
5472 cm_ReleaseUser(userp);
5477 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5478 cm_ReleaseSCache(oldDscp);
5479 cm_ReleaseSCache(newDscp);
5480 cm_ReleaseUser(userp);
5481 if ( WANTS_DFS_PATHNAMES(inp) )
5482 return CM_ERROR_PATH_NOT_COVERED;
5484 return CM_ERROR_BADSHARENAME;
5486 #endif /* DFS_SUPPORT */
5489 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5490 * next, get the component names, and lower case them.
5493 /* handle the old name first */
5495 oldLastNamep = oldPathp;
5499 /* and handle the new name, too */
5501 newLastNamep = newPathp;
5505 /* TODO: The old name could be a wildcard. The new name must not be */
5507 /* do the vnode call */
5508 rock.odscp = oldDscp;
5509 rock.ndscp = newDscp;
5513 rock.maskp = oldLastNamep;
5514 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5515 rock.newNamep = newLastNamep;
5516 rock.oldName[0] = '\0';
5519 /* Check if the file already exists; if so return error */
5520 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5521 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5522 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5524 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5525 osi_LogSaveString(smb_logp, newLastNamep));
5527 /* Check if the old and the new names differ only in case. If so return
5528 * success, else return CM_ERROR_EXISTS
5530 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5532 /* This would be a success only if the old file is *as same as* the new file */
5533 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5535 if (tmpscp == tmpscp2)
5538 code = CM_ERROR_EXISTS;
5539 cm_ReleaseSCache(tmpscp2);
5542 code = CM_ERROR_NOSUCHFILE;
5545 /* file exist, do not rename, also fixes move */
5546 osi_Log0(smb_logp, "Can't rename. Target already exists");
5547 code = CM_ERROR_EXISTS;
5551 cm_ReleaseSCache(tmpscp);
5552 cm_ReleaseSCache(newDscp);
5553 cm_ReleaseSCache(oldDscp);
5554 cm_ReleaseUser(userp);
5558 /* Now search the directory for the pattern, and do the appropriate rename when found */
5559 thyper.LowPart = 0; /* search dir from here */
5560 thyper.HighPart = 0;
5562 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5563 if (code == 0 && !rock.any) {
5565 thyper.HighPart = 0;
5566 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5567 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5569 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5571 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5572 code = cm_Rename(rock.odscp, rock.oldName,
5573 rock.ndscp, rock.newNamep, rock.userp,
5575 /* if the call worked, stop doing the search now, since we
5576 * really only want to rename one file.
5578 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5579 } else if (code == 0) {
5580 code = CM_ERROR_NOSUCHFILE;
5583 /* Handle Change Notification */
5585 * Being lazy, not distinguishing between files and dirs in this
5586 * filter, since we'd have to do a lookup.
5589 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5590 if (oldDscp == newDscp) {
5591 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5592 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5593 filter, oldDscp, oldLastNamep,
5594 newLastNamep, TRUE);
5596 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5597 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5598 filter, oldDscp, oldLastNamep,
5600 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5601 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5602 filter, newDscp, newLastNamep,
5608 cm_ReleaseSCache(tmpscp);
5609 cm_ReleaseUser(userp);
5610 cm_ReleaseSCache(oldDscp);
5611 cm_ReleaseSCache(newDscp);
5616 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5619 cm_space_t *spacep = NULL;
5620 cm_scache_t *oldDscp = NULL;
5621 cm_scache_t *newDscp = NULL;
5622 cm_scache_t *tmpscp= NULL;
5623 cm_scache_t *tmpscp2 = NULL;
5624 cm_scache_t *sscp = NULL;
5633 userp = smb_GetUserFromVCP(vcp, inp);
5635 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5637 cm_ReleaseUser(userp);
5638 return CM_ERROR_NOSUCHPATH;
5643 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5645 spacep = inp->spacep;
5646 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5648 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5649 userp, tidPathp, &req, &oldDscp);
5651 cm_ReleaseUser(userp);
5656 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5657 cm_ReleaseSCache(oldDscp);
5658 cm_ReleaseUser(userp);
5659 if ( WANTS_DFS_PATHNAMES(inp) )
5660 return CM_ERROR_PATH_NOT_COVERED;
5662 return CM_ERROR_BADSHARENAME;
5664 #endif /* DFS_SUPPORT */
5666 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5667 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5668 userp, tidPathp, &req, &newDscp);
5670 cm_ReleaseSCache(oldDscp);
5671 cm_ReleaseUser(userp);
5676 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5677 cm_ReleaseSCache(newDscp);
5678 cm_ReleaseSCache(oldDscp);
5679 cm_ReleaseUser(userp);
5680 if ( WANTS_DFS_PATHNAMES(inp) )
5681 return CM_ERROR_PATH_NOT_COVERED;
5683 return CM_ERROR_BADSHARENAME;
5685 #endif /* DFS_SUPPORT */
5687 /* Now, although we did two lookups for the two directories (because the same
5688 * directory can be referenced through different paths), we only allow hard links
5689 * within the same directory. */
5690 if (oldDscp != newDscp) {
5691 cm_ReleaseSCache(oldDscp);
5692 cm_ReleaseSCache(newDscp);
5693 cm_ReleaseUser(userp);
5694 return CM_ERROR_CROSSDEVLINK;
5697 /* handle the old name first */
5699 oldLastNamep = oldPathp;
5703 /* and handle the new name, too */
5705 newLastNamep = newPathp;
5709 /* now lookup the old name */
5710 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5711 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5713 cm_ReleaseSCache(oldDscp);
5714 cm_ReleaseSCache(newDscp);
5715 cm_ReleaseUser(userp);
5719 /* Check if the file already exists; if so return error */
5720 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5721 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5722 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5724 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5725 osi_LogSaveString(smb_logp, newLastNamep));
5727 /* if the existing link is to the same file, then we return success */
5729 if(sscp == tmpscp) {
5732 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5733 code = CM_ERROR_EXISTS;
5738 cm_ReleaseSCache(tmpscp);
5739 cm_ReleaseSCache(sscp);
5740 cm_ReleaseSCache(newDscp);
5741 cm_ReleaseSCache(oldDscp);
5742 cm_ReleaseUser(userp);
5746 /* now create the hardlink */
5747 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5748 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5749 osi_Log1(smb_logp," Link returns 0x%x", code);
5751 /* Handle Change Notification */
5753 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5754 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5755 smb_NotifyChange(FILE_ACTION_ADDED,
5756 filter, newDscp, newLastNamep,
5761 cm_ReleaseSCache(tmpscp);
5762 cm_ReleaseUser(userp);
5763 cm_ReleaseSCache(sscp);
5764 cm_ReleaseSCache(oldDscp);
5765 cm_ReleaseSCache(newDscp);
5770 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5777 tp = smb_GetSMBData(inp, NULL);
5778 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5779 if (smb_StoreAnsiFilenames)
5780 OemToChar(oldPathp,oldPathp);
5781 newPathp = smb_ParseASCIIBlock(tp, &tp);
5782 if (smb_StoreAnsiFilenames)
5783 OemToChar(newPathp,newPathp);
5785 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5786 osi_LogSaveString(smb_logp, oldPathp),
5787 osi_LogSaveString(smb_logp, newPathp));
5789 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5791 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5797 typedef struct smb_rmdirRock {
5801 char *maskp; /* pointer to the star pattern */
5804 cm_dirEntryList_t * matches;
5807 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5810 smb_rmdirRock_t *rockp;
5815 rockp = (smb_rmdirRock_t *) vrockp;
5817 matchName = dep->name;
5818 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5819 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5821 match = (strcmp(matchName, rockp->maskp) == 0);
5823 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5824 !cm_Is8Dot3(dep->name)) {
5825 cm_Gen8Dot3Name(dep, shortName, NULL);
5826 matchName = shortName;
5827 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5832 cm_DirEntryListAdd(dep->name, &rockp->matches);
5838 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5846 smb_rmdirRock_t rock;
5855 tp = smb_GetSMBData(inp, NULL);
5856 pathp = smb_ParseASCIIBlock(tp, &tp);
5857 if (smb_StoreAnsiFilenames)
5858 OemToChar(pathp,pathp);
5860 spacep = inp->spacep;
5861 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5863 userp = smb_GetUserFromVCP(vcp, inp);
5865 caseFold = CM_FLAG_CASEFOLD;
5867 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5869 cm_ReleaseUser(userp);
5870 return CM_ERROR_NOSUCHPATH;
5872 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5873 userp, tidPathp, &req, &dscp);
5876 cm_ReleaseUser(userp);
5881 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5882 cm_ReleaseSCache(dscp);
5883 cm_ReleaseUser(userp);
5884 if ( WANTS_DFS_PATHNAMES(inp) )
5885 return CM_ERROR_PATH_NOT_COVERED;
5887 return CM_ERROR_BADSHARENAME;
5889 #endif /* DFS_SUPPORT */
5891 /* otherwise, scp points to the parent directory. */
5898 rock.maskp = lastNamep;
5899 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5902 thyper.HighPart = 0;
5906 rock.matches = NULL;
5908 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5909 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5910 if (code == 0 && !rock.any) {
5912 thyper.HighPart = 0;
5913 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5914 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5917 if (code == 0 && rock.matches) {
5918 cm_dirEntryList_t * entry;
5920 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5921 osi_Log1(smb_logp, "Removing directory %s",
5922 osi_LogSaveString(smb_logp, entry->name));
5924 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5926 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5927 smb_NotifyChange(FILE_ACTION_REMOVED,
5928 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5929 dscp, entry->name, NULL, TRUE);
5933 cm_DirEntryListFree(&rock.matches);
5935 cm_ReleaseUser(userp);
5937 cm_ReleaseSCache(dscp);
5939 if (code == 0 && !rock.any)
5940 code = CM_ERROR_NOSUCHFILE;
5944 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5954 fid = smb_GetSMBParm(inp, 0);
5956 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5958 fid = smb_ChainFID(fid, inp);
5959 fidp = smb_FindFID(vcp, fid, 0);
5961 return CM_ERROR_BADFD;
5963 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5964 smb_CloseFID(vcp, fidp, NULL, 0);
5965 smb_ReleaseFID(fidp);
5966 return CM_ERROR_NOSUCHFILE;
5969 lock_ObtainMutex(&fidp->mx);
5970 if (fidp->flags & SMB_FID_IOCTL) {
5971 lock_ReleaseMutex(&fidp->mx);
5972 smb_ReleaseFID(fidp);
5973 return CM_ERROR_BADFD;
5975 lock_ReleaseMutex(&fidp->mx);
5977 userp = smb_GetUserFromVCP(vcp, inp);
5979 lock_ObtainMutex(&fidp->mx);
5980 if (fidp->flags & SMB_FID_OPENWRITE) {
5981 cm_scache_t * scp = fidp->scp;
5983 lock_ReleaseMutex(&fidp->mx);
5984 code = cm_FSync(scp, userp, &req);
5985 cm_ReleaseSCache(scp);
5988 lock_ReleaseMutex(&fidp->mx);
5991 smb_ReleaseFID(fidp);
5993 cm_ReleaseUser(userp);
5998 struct smb_FullNameRock {
6004 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6008 struct smb_FullNameRock *vrockp;
6010 vrockp = (struct smb_FullNameRock *)rockp;
6012 if (!cm_Is8Dot3(dep->name)) {
6013 cm_Gen8Dot3Name(dep, shortName, NULL);
6015 if (cm_stricmp(shortName, vrockp->name) == 0) {
6016 vrockp->fullName = strdup(dep->name);
6017 return CM_ERROR_STOPNOW;
6020 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
6021 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6022 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6023 vrockp->fullName = strdup(dep->name);
6024 return CM_ERROR_STOPNOW;
6029 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
6030 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
6032 struct smb_FullNameRock rock;
6038 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6039 if (code == CM_ERROR_STOPNOW)
6040 *newPathp = rock.fullName;
6042 *newPathp = strdup(pathp);
6045 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6046 afs_uint32 dosTime) {
6049 cm_scache_t *dscp = NULL;
6051 cm_scache_t * scp = NULL;
6052 cm_scache_t *delscp = NULL;
6054 int nullcreator = 0;
6056 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6057 fidp, fidp->fid, scp, vcp);
6060 lock_ObtainMutex(&fidp->mx);
6061 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6062 lock_ReleaseMutex(&fidp->mx);
6063 osi_Log0(smb_logp, " No user specified. Not closing fid");
6064 return CM_ERROR_BADFD;
6067 userp = fidp->userp; /* no hold required since fidp is held
6068 throughout the function */
6069 lock_ReleaseMutex(&fidp->mx);
6074 lock_ObtainWrite(&smb_rctLock);
6076 osi_Log0(smb_logp, " Fid already closed.");
6077 lock_ReleaseWrite(&smb_rctLock);
6078 return CM_ERROR_BADFD;
6081 lock_ReleaseWrite(&smb_rctLock);
6083 lock_ObtainMutex(&fidp->mx);
6084 if (fidp->NTopen_dscp) {
6085 dscp = fidp->NTopen_dscp;
6086 cm_HoldSCache(dscp);
6089 if (fidp->NTopen_pathp) {
6090 pathp = strdup(fidp->NTopen_pathp);
6098 /* Don't jump the gun on an async raw write */
6099 while (fidp->raw_writers) {
6100 lock_ReleaseMutex(&fidp->mx);
6101 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6102 lock_ObtainMutex(&fidp->mx);
6105 /* watch for ioctl closes, and read-only opens */
6107 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6108 == SMB_FID_OPENWRITE) {
6109 if (dosTime != 0 && dosTime != -1) {
6110 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6111 /* This fixes defect 10958 */
6112 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6113 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6115 lock_ReleaseMutex(&fidp->mx);
6116 code = cm_FSync(scp, userp, &req);
6117 lock_ObtainMutex(&fidp->mx);
6122 /* unlock any pending locks */
6123 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6124 scp->fileType == CM_SCACHETYPE_FILE) {
6128 lock_ReleaseMutex(&fidp->mx);
6130 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6132 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6133 lock_ObtainMutex(&scp->mx);
6135 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6136 CM_SCACHESYNC_NEEDCALLBACK
6137 | CM_SCACHESYNC_GETSTATUS
6138 | CM_SCACHESYNC_LOCK);
6142 "smb CoreClose SyncOp failure code 0x%x", tcode);
6143 goto post_syncopdone;
6146 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6148 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6152 lock_ReleaseMutex(&scp->mx);
6153 lock_ObtainMutex(&fidp->mx);
6156 if (fidp->flags & SMB_FID_DELONCLOSE) {
6159 lock_ReleaseMutex(&fidp->mx);
6161 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6166 smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
6167 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6168 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
6171 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6172 smb_NotifyChange(FILE_ACTION_REMOVED,
6173 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6174 dscp, fullPathp, NULL, TRUE);
6177 code = cm_Unlink(dscp, fullPathp, userp, &req);
6180 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6181 smb_NotifyChange(FILE_ACTION_REMOVED,
6182 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6183 dscp, fullPathp, NULL, TRUE);
6187 lock_ObtainMutex(&fidp->mx);
6188 fidp->flags &= ~SMB_FID_DELONCLOSE;
6191 /* if this was a newly created file, then clear the creator
6192 * in the stat cache entry. */
6193 if (fidp->flags & SMB_FID_CREATED) {
6195 fidp->flags &= ~SMB_FID_CREATED;
6198 if (fidp->flags & SMB_FID_NTOPEN) {
6199 cm_ReleaseSCache(fidp->NTopen_dscp);
6200 fidp->NTopen_dscp = NULL;
6201 free(fidp->NTopen_pathp);
6202 fidp->NTopen_pathp = NULL;
6203 fidp->flags &= ~SMB_FID_NTOPEN;
6205 osi_assert(fidp->NTopen_dscp == NULL);
6206 osi_assert(fidp->NTopen_pathp == NULL);
6209 if (fidp->NTopen_wholepathp) {
6210 free(fidp->NTopen_wholepathp);
6211 fidp->NTopen_wholepathp = NULL;
6215 cm_ReleaseSCache(fidp->scp);
6218 lock_ReleaseMutex(&fidp->mx);
6221 cm_ReleaseSCache(dscp);
6225 lock_ObtainMutex(&delscp->mx);
6227 delscp->flags |= CM_SCACHEFLAG_DELETED;
6228 lock_ReleaseMutex(&delscp->mx);
6230 cm_ReleaseSCache(delscp);
6234 lock_ObtainMutex(&scp->mx);
6235 if (nullcreator && scp->creator == userp)
6236 scp->creator = NULL;
6237 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6238 lock_ReleaseMutex(&scp->mx);
6239 cm_ReleaseSCache(scp);
6248 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6256 fid = smb_GetSMBParm(inp, 0);
6257 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6259 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6261 fid = smb_ChainFID(fid, inp);
6262 fidp = smb_FindFID(vcp, fid, 0);
6264 return CM_ERROR_BADFD;
6267 userp = smb_GetUserFromVCP(vcp, inp);
6269 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6271 smb_ReleaseFID(fidp);
6272 cm_ReleaseUser(userp);
6277 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6280 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6281 cm_user_t *userp, long *readp)
6283 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6284 cm_user_t *userp, long *readp, int dosflag)
6291 osi_hyper_t fileLength;
6293 osi_hyper_t lastByte;
6294 osi_hyper_t bufferOffset;
6295 long bufIndex, nbytes;
6297 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6305 lock_ObtainMutex(&fidp->mx);
6308 lock_ObtainMutex(&scp->mx);
6310 if (offset.HighPart == 0) {
6311 chunk = offset.LowPart >> cm_logChunkSize;
6312 if (chunk != fidp->curr_chunk) {
6313 fidp->prev_chunk = fidp->curr_chunk;
6314 fidp->curr_chunk = chunk;
6316 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6319 lock_ReleaseMutex(&fidp->mx);
6321 /* start by looking up the file's end */
6322 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6323 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6327 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6329 /* now we have the entry locked, look up the length */
6330 fileLength = scp->length;
6332 /* adjust count down so that it won't go past EOF */
6333 thyper.LowPart = count;
6334 thyper.HighPart = 0;
6335 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6337 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6338 /* we'd read past EOF, so just stop at fileLength bytes.
6339 * Start by computing how many bytes remain in the file.
6341 thyper = LargeIntegerSubtract(fileLength, offset);
6343 /* if we are past EOF, read 0 bytes */
6344 if (LargeIntegerLessThanZero(thyper))
6347 count = thyper.LowPart;
6352 /* now, copy the data one buffer at a time,
6353 * until we've filled the request packet
6356 /* if we've copied all the data requested, we're done */
6357 if (count <= 0) break;
6359 /* otherwise, load up a buffer of data */
6360 thyper.HighPart = offset.HighPart;
6361 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6362 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6365 buf_Release(bufferp);
6368 lock_ReleaseMutex(&scp->mx);
6370 lock_ObtainRead(&scp->bufCreateLock);
6371 code = buf_Get(scp, &thyper, &bufferp);
6372 lock_ReleaseRead(&scp->bufCreateLock);
6374 lock_ObtainMutex(&scp->mx);
6375 if (code) goto done;
6376 bufferOffset = thyper;
6378 /* now get the data in the cache */
6380 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6381 CM_SCACHESYNC_NEEDCALLBACK |
6382 CM_SCACHESYNC_READ);
6386 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6388 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6390 /* otherwise, load the buffer and try again */
6391 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6395 buf_Release(bufferp);
6399 } /* if (wrong buffer) ... */
6401 /* now we have the right buffer loaded. Copy out the
6402 * data from here to the user's buffer.
6404 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6406 /* and figure out how many bytes we want from this buffer */
6407 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6408 if (nbytes > count) nbytes = count; /* don't go past EOF */
6410 /* now copy the data */
6413 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
6416 memcpy(op, bufferp->datap + bufIndex, nbytes);
6418 /* adjust counters, pointers, etc. */
6421 thyper.LowPart = nbytes;
6422 thyper.HighPart = 0;
6423 offset = LargeIntegerAdd(thyper, offset);
6427 lock_ReleaseMutex(&scp->mx);
6429 buf_Release(bufferp);
6431 if (code == 0 && sequential)
6432 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6434 cm_ReleaseSCache(scp);
6440 * smb_WriteData -- common code for Write and Raw Write
6443 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6444 cm_user_t *userp, long *writtenp)
6446 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6447 cm_user_t *userp, long *writtenp, int dosflag)
6454 osi_hyper_t fileLength; /* file's length at start of write */
6455 osi_hyper_t minLength; /* don't read past this */
6456 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6458 osi_hyper_t thyper; /* hyper tmp variable */
6459 osi_hyper_t bufferOffset;
6460 afs_uint32 bufIndex; /* index in buffer where our data is */
6462 osi_hyper_t writeBackOffset;/* offset of region to write back when
6467 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6468 fidp->fid, offsetp->LowPart, count);
6478 lock_ObtainMutex(&fidp->mx);
6479 /* make sure we have a writable FD */
6480 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6481 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6482 fidp->fid, fidp->flags);
6483 lock_ReleaseMutex(&fidp->mx);
6484 code = CM_ERROR_BADFDOP;
6490 lock_ReleaseMutex(&fidp->mx);
6492 lock_ObtainMutex(&scp->mx);
6493 /* start by looking up the file's end */
6494 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6495 CM_SCACHESYNC_NEEDCALLBACK
6496 | CM_SCACHESYNC_SETSTATUS
6497 | CM_SCACHESYNC_GETSTATUS);
6501 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6503 /* now we have the entry locked, look up the length */
6504 fileLength = scp->length;
6505 minLength = fileLength;
6506 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6507 minLength = scp->serverLength;
6509 /* adjust file length if we extend past EOF */
6510 thyper.LowPart = count;
6511 thyper.HighPart = 0;
6512 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6513 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6514 /* we'd write past EOF, so extend the file */
6515 scp->mask |= CM_SCACHEMASK_LENGTH;
6516 scp->length = thyper;
6517 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6519 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6521 /* now, if the new position (thyper) and the old (offset) are in
6522 * different storeback windows, remember to store back the previous
6523 * storeback window when we're done with the write.
6525 if ((thyper.LowPart & (-cm_chunkSize)) !=
6526 (offset.LowPart & (-cm_chunkSize))) {
6527 /* they're different */
6529 writeBackOffset.HighPart = offset.HighPart;
6530 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6535 /* now, copy the data one buffer at a time, until we've filled the
6538 /* if we've copied all the data requested, we're done */
6542 /* handle over quota or out of space */
6543 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6544 *writtenp = written;
6545 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6549 /* otherwise, load up a buffer of data */
6550 thyper.HighPart = offset.HighPart;
6551 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6552 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6555 lock_ReleaseMutex(&bufferp->mx);
6556 buf_Release(bufferp);
6559 lock_ReleaseMutex(&scp->mx);
6561 lock_ObtainRead(&scp->bufCreateLock);
6562 code = buf_Get(scp, &thyper, &bufferp);
6563 lock_ReleaseRead(&scp->bufCreateLock);
6565 lock_ObtainMutex(&bufferp->mx);
6566 lock_ObtainMutex(&scp->mx);
6567 if (code) goto done;
6569 bufferOffset = thyper;
6571 /* now get the data in the cache */
6573 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6574 CM_SCACHESYNC_NEEDCALLBACK
6575 | CM_SCACHESYNC_WRITE
6576 | CM_SCACHESYNC_BUFLOCKED);
6580 cm_SyncOpDone(scp, bufferp,
6581 CM_SCACHESYNC_NEEDCALLBACK
6582 | CM_SCACHESYNC_WRITE
6583 | CM_SCACHESYNC_BUFLOCKED);
6585 /* If we're overwriting the entire buffer, or
6586 * if we're writing at or past EOF, mark the
6587 * buffer as current so we don't call
6588 * cm_GetBuffer. This skips the fetch from the
6589 * server in those cases where we're going to
6590 * obliterate all the data in the buffer anyway,
6591 * or in those cases where there is no useful
6592 * data at the server to start with.
6594 * Use minLength instead of scp->length, since
6595 * the latter has already been updated by this
6598 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6599 || LargeIntegerEqualTo(offset, bufferp->offset)
6600 && (count >= cm_data.buf_blockSize
6601 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6602 ConvertLongToLargeInteger(count)),
6604 if (count < cm_data.buf_blockSize
6605 && bufferp->dataVersion == -1)
6606 memset(bufferp->datap, 0,
6607 cm_data.buf_blockSize);
6608 bufferp->dataVersion = scp->dataVersion;
6611 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6613 /* otherwise, load the buffer and try again */
6614 lock_ReleaseMutex(&bufferp->mx);
6615 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6617 lock_ReleaseMutex(&scp->mx);
6618 lock_ObtainMutex(&bufferp->mx);
6619 lock_ObtainMutex(&scp->mx);
6623 lock_ReleaseMutex(&bufferp->mx);
6624 buf_Release(bufferp);
6628 } /* if (wrong buffer) ... */
6630 /* now we have the right buffer loaded. Copy out the
6631 * data from here to the user's buffer.
6633 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6635 /* and figure out how many bytes we want from this buffer */
6636 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6638 nbytes = count; /* don't go past end of request */
6640 /* now copy the data */
6643 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
6646 memcpy(bufferp->datap + bufIndex, op, nbytes);
6647 buf_SetDirty(bufferp, bufIndex, nbytes);
6649 /* and record the last writer */
6650 if (bufferp->userp != userp) {
6653 cm_ReleaseUser(bufferp->userp);
6654 bufferp->userp = userp;
6657 /* adjust counters, pointers, etc. */
6661 thyper.LowPart = nbytes;
6662 thyper.HighPart = 0;
6663 offset = LargeIntegerAdd(thyper, offset);
6667 lock_ReleaseMutex(&scp->mx);
6670 lock_ReleaseMutex(&bufferp->mx);
6671 buf_Release(bufferp);
6674 lock_ObtainMutex(&fidp->mx);
6675 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6676 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6677 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6678 fidp->NTopen_dscp, fidp->NTopen_pathp,
6681 lock_ReleaseMutex(&fidp->mx);
6683 if (code == 0 && doWriteBack) {
6685 lock_ObtainMutex(&scp->mx);
6686 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6688 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6689 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6691 lock_ReleaseMutex(&scp->mx);
6692 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6693 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6694 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6697 cm_ReleaseSCache(scp);
6699 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6700 fidp->fid, code, *writtenp);
6704 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6707 unsigned short count;
6709 unsigned short hint;
6710 long written = 0, total_written = 0;
6715 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6717 int inDataBlockCount;
6719 fd = smb_GetSMBParm(inp, 0);
6720 count = smb_GetSMBParm(inp, 1);
6721 offset.HighPart = 0; /* too bad */
6722 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6723 hint = smb_GetSMBParm(inp, 4);
6725 op = smb_GetSMBData(inp, NULL);
6726 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6728 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6729 fd, offset.LowPart, count);
6731 fd = smb_ChainFID(fd, inp);
6732 fidp = smb_FindFID(vcp, fd, 0);
6734 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6735 return CM_ERROR_BADFD;
6738 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6739 smb_CloseFID(vcp, fidp, NULL, 0);
6740 smb_ReleaseFID(fidp);
6741 return CM_ERROR_NOSUCHFILE;
6744 lock_ObtainMutex(&fidp->mx);
6745 if (fidp->flags & SMB_FID_IOCTL) {
6746 lock_ReleaseMutex(&fidp->mx);
6747 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6748 smb_ReleaseFID(fidp);
6749 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6752 lock_ReleaseMutex(&fidp->mx);
6753 userp = smb_GetUserFromVCP(vcp, inp);
6757 LARGE_INTEGER LOffset;
6758 LARGE_INTEGER LLength;
6760 pid = ((smb_t *) inp)->pid;
6761 key = cm_GenerateKey(vcp->vcID, pid, fd);
6763 LOffset.HighPart = offset.HighPart;
6764 LOffset.LowPart = offset.LowPart;
6765 LLength.HighPart = 0;
6766 LLength.LowPart = count;
6768 lock_ObtainMutex(&fidp->scp->mx);
6769 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6770 lock_ReleaseMutex(&fidp->scp->mx);
6773 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6778 /* special case: 0 bytes transferred means truncate to this position */
6782 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6786 truncAttr.mask = CM_ATTRMASK_LENGTH;
6787 truncAttr.length.LowPart = offset.LowPart;
6788 truncAttr.length.HighPart = 0;
6789 lock_ObtainMutex(&fidp->mx);
6790 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6791 fidp->flags |= SMB_FID_LENGTHSETDONE;
6792 lock_ReleaseMutex(&fidp->mx);
6793 smb_SetSMBParm(outp, 0, 0 /* count */);
6794 smb_SetSMBDataLength(outp, 0);
6799 * Work around bug in NT client
6801 * When copying a file, the NT client should first copy the data,
6802 * then copy the last write time. But sometimes the NT client does
6803 * these in the wrong order, so the data copies would inadvertently
6804 * cause the last write time to be overwritten. We try to detect this,
6805 * and don't set client mod time if we think that would go against the
6808 lock_ObtainMutex(&fidp->mx);
6809 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6810 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6811 fidp->scp->clientModTime = time(NULL);
6813 lock_ReleaseMutex(&fidp->mx);
6816 while ( code == 0 && count > 0 ) {
6818 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6820 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6822 if (code == 0 && written == 0)
6823 code = CM_ERROR_PARTIALWRITE;
6825 offset = LargeIntegerAdd(offset,
6826 ConvertLongToLargeInteger(written));
6827 count -= (unsigned short)written;
6828 total_written += written;
6832 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6833 total_written, code);
6835 /* set the packet data length to 3 bytes for the data block header,
6836 * plus the size of the data.
6838 smb_SetSMBParm(outp, 0, total_written);
6839 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6840 smb_SetSMBParm(outp, 3, hint);
6841 smb_SetSMBDataLength(outp, 0);
6844 smb_ReleaseFID(fidp);
6845 cm_ReleaseUser(userp);
6850 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6851 NCB *ncbp, raw_write_cont_t *rwcp)
6864 fd = smb_GetSMBParm(inp, 0);
6865 fidp = smb_FindFID(vcp, fd, 0);
6867 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6868 smb_CloseFID(vcp, fidp, NULL, 0);
6869 smb_ReleaseFID(fidp);
6873 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6874 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6876 userp = smb_GetUserFromVCP(vcp, inp);
6880 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6883 rawBuf = (dos_ptr) rwcp->buf;
6884 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6885 (unsigned char *) rawBuf, userp,
6889 if (rwcp->writeMode & 0x1) { /* synchronous */
6892 smb_FormatResponsePacket(vcp, inp, outp);
6893 op = (smb_t *) outp;
6894 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6895 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6896 smb_SetSMBDataLength(outp, 0);
6897 smb_SendPacket(vcp, outp);
6898 smb_FreePacket(outp);
6900 else { /* asynchronous */
6901 lock_ObtainMutex(&fidp->mx);
6902 fidp->raw_writers--;
6903 if (fidp->raw_writers == 0)
6904 thrd_SetEvent(fidp->raw_write_event);
6905 lock_ReleaseMutex(&fidp->mx);
6908 /* Give back raw buffer */
6909 lock_ObtainMutex(&smb_RawBufLock);
6911 *((char **)rawBuf) = smb_RawBufs;
6913 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6915 smb_RawBufs = rawBuf;
6916 lock_ReleaseMutex(&smb_RawBufLock);
6918 smb_ReleaseFID(fidp);
6919 cm_ReleaseUser(userp);
6922 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6927 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6930 long count, written = 0, total_written = 0;
6937 unsigned short writeMode;
6944 fd = smb_GetSMBParm(inp, 0);
6945 totalCount = smb_GetSMBParm(inp, 1);
6946 count = smb_GetSMBParm(inp, 10);
6947 writeMode = smb_GetSMBParm(inp, 7);
6949 op = (char *) inp->data;
6950 op += smb_GetSMBParm(inp, 11);
6952 offset.HighPart = 0;
6953 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6955 if (*inp->wctp == 14) {
6956 /* we received a 64-bit file offset */
6957 #ifdef AFS_LARGEFILES
6958 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6960 if (LargeIntegerLessThanZero(offset)) {
6962 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6963 offset.HighPart, offset.LowPart);
6964 return CM_ERROR_BADSMB;
6967 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6969 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6970 return CM_ERROR_BADSMB;
6973 offset.HighPart = 0;
6976 offset.HighPart = 0; /* 32-bit file offset */
6980 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6981 fd, offset.HighPart, offset.LowPart, count);
6983 " WriteRaw WriteMode 0x%x",
6986 fd = smb_ChainFID(fd, inp);
6987 fidp = smb_FindFID(vcp, fd, 0);
6989 return CM_ERROR_BADFD;
6992 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6993 smb_CloseFID(vcp, fidp, NULL, 0);
6994 smb_ReleaseFID(fidp);
6995 return CM_ERROR_NOSUCHFILE;
7001 LARGE_INTEGER LOffset;
7002 LARGE_INTEGER LLength;
7004 pid = ((smb_t *) inp)->pid;
7005 key = cm_GenerateKey(vcp->vcID, pid, fd);
7007 LOffset.HighPart = offset.HighPart;
7008 LOffset.LowPart = offset.LowPart;
7009 LLength.HighPart = 0;
7010 LLength.LowPart = count;
7012 lock_ObtainMutex(&fidp->scp->mx);
7013 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7014 lock_ReleaseMutex(&fidp->scp->mx);
7017 smb_ReleaseFID(fidp);
7022 userp = smb_GetUserFromVCP(vcp, inp);
7025 * Work around bug in NT client
7027 * When copying a file, the NT client should first copy the data,
7028 * then copy the last write time. But sometimes the NT client does
7029 * these in the wrong order, so the data copies would inadvertently
7030 * cause the last write time to be overwritten. We try to detect this,
7031 * and don't set client mod time if we think that would go against the
7034 lock_ObtainMutex(&fidp->mx);
7035 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7036 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7037 fidp->scp->clientModTime = time(NULL);
7039 lock_ReleaseMutex(&fidp->mx);
7042 while ( code == 0 && count > 0 ) {
7044 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7046 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
7048 if (code == 0 && written == 0)
7049 code = CM_ERROR_PARTIALWRITE;
7051 offset = LargeIntegerAdd(offset,
7052 ConvertLongToLargeInteger(written));
7055 total_written += written;
7059 /* Get a raw buffer */
7062 lock_ObtainMutex(&smb_RawBufLock);
7064 /* Get a raw buf, from head of list */
7065 rawBuf = smb_RawBufs;
7067 smb_RawBufs = *(char **)smb_RawBufs;
7069 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
7073 code = CM_ERROR_USESTD;
7075 lock_ReleaseMutex(&smb_RawBufLock);
7078 /* Don't allow a premature Close */
7079 if (code == 0 && (writeMode & 1) == 0) {
7080 lock_ObtainMutex(&fidp->mx);
7081 fidp->raw_writers++;
7082 thrd_ResetEvent(fidp->raw_write_event);
7083 lock_ReleaseMutex(&fidp->mx);
7086 smb_ReleaseFID(fidp);
7087 cm_ReleaseUser(userp);
7090 smb_SetSMBParm(outp, 0, total_written);
7091 smb_SetSMBDataLength(outp, 0);
7092 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7097 offset = LargeIntegerAdd(offset,
7098 ConvertLongToLargeInteger(count));
7102 rwcp->offset.HighPart = offset.HighPart;
7103 rwcp->offset.LowPart = offset.LowPart;
7104 rwcp->count = totalCount - count;
7105 rwcp->writeMode = writeMode;
7106 rwcp->alreadyWritten = total_written;
7108 /* set the packet data length to 3 bytes for the data block header,
7109 * plus the size of the data.
7111 smb_SetSMBParm(outp, 0, 0xffff);
7112 smb_SetSMBDataLength(outp, 0);
7117 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7120 long count, finalCount;
7128 fd = smb_GetSMBParm(inp, 0);
7129 count = smb_GetSMBParm(inp, 1);
7130 offset.HighPart = 0; /* too bad */
7131 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7133 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7134 fd, offset.LowPart, count);
7136 fd = smb_ChainFID(fd, inp);
7137 fidp = smb_FindFID(vcp, fd, 0);
7139 return CM_ERROR_BADFD;
7141 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7142 smb_CloseFID(vcp, fidp, NULL, 0);
7143 smb_ReleaseFID(fidp);
7144 return CM_ERROR_NOSUCHFILE;
7147 lock_ObtainMutex(&fidp->mx);
7148 if (fidp->flags & SMB_FID_IOCTL) {
7149 lock_ReleaseMutex(&fidp->mx);
7150 code = smb_IoctlRead(fidp, vcp, inp, outp);
7151 smb_ReleaseFID(fidp);
7154 lock_ReleaseMutex(&fidp->mx);
7157 LARGE_INTEGER LOffset, LLength;
7160 pid = ((smb_t *) inp)->pid;
7161 key = cm_GenerateKey(vcp->vcID, pid, fd);
7163 LOffset.HighPart = 0;
7164 LOffset.LowPart = offset.LowPart;
7165 LLength.HighPart = 0;
7166 LLength.LowPart = count;
7168 lock_ObtainMutex(&fidp->scp->mx);
7169 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7170 lock_ReleaseMutex(&fidp->scp->mx);
7173 smb_ReleaseFID(fidp);
7177 userp = smb_GetUserFromVCP(vcp, inp);
7179 /* remember this for final results */
7180 smb_SetSMBParm(outp, 0, count);
7181 smb_SetSMBParm(outp, 1, 0);
7182 smb_SetSMBParm(outp, 2, 0);
7183 smb_SetSMBParm(outp, 3, 0);
7184 smb_SetSMBParm(outp, 4, 0);
7186 /* set the packet data length to 3 bytes for the data block header,
7187 * plus the size of the data.
7189 smb_SetSMBDataLength(outp, count+3);
7191 /* get op ptr after putting in the parms, since otherwise we don't
7192 * know where the data really is.
7194 op = smb_GetSMBData(outp, NULL);
7196 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7197 *op++ = 1; /* data block marker */
7198 *op++ = (unsigned char) (count & 0xff);
7199 *op++ = (unsigned char) ((count >> 8) & 0xff);
7202 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7204 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
7207 /* fix some things up */
7208 smb_SetSMBParm(outp, 0, finalCount);
7209 smb_SetSMBDataLength(outp, finalCount+3);
7211 smb_ReleaseFID(fidp);
7213 cm_ReleaseUser(userp);
7217 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7224 cm_scache_t *dscp; /* dir we're dealing with */
7225 cm_scache_t *scp; /* file we're creating */
7227 int initialModeBits;
7237 /* compute initial mode bits based on read-only flag in attributes */
7238 initialModeBits = 0777;
7240 tp = smb_GetSMBData(inp, NULL);
7241 pathp = smb_ParseASCIIBlock(tp, &tp);
7242 if (smb_StoreAnsiFilenames)
7243 OemToChar(pathp,pathp);
7245 if (strcmp(pathp, "\\") == 0)
7246 return CM_ERROR_EXISTS;
7248 spacep = inp->spacep;
7249 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7251 userp = smb_GetUserFromVCP(vcp, inp);
7253 caseFold = CM_FLAG_CASEFOLD;
7255 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7257 cm_ReleaseUser(userp);
7258 return CM_ERROR_NOSUCHPATH;
7261 code = cm_NameI(cm_data.rootSCachep, spacep->data,
7262 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7263 userp, tidPathp, &req, &dscp);
7266 cm_ReleaseUser(userp);
7271 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7272 cm_ReleaseSCache(dscp);
7273 cm_ReleaseUser(userp);
7274 if ( WANTS_DFS_PATHNAMES(inp) )
7275 return CM_ERROR_PATH_NOT_COVERED;
7277 return CM_ERROR_BADSHARENAME;
7279 #endif /* DFS_SUPPORT */
7281 /* otherwise, scp points to the parent directory. Do a lookup, and
7282 * fail if we find it. Otherwise, we do the create.
7288 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7289 if (scp) cm_ReleaseSCache(scp);
7290 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7291 if (code == 0) code = CM_ERROR_EXISTS;
7292 cm_ReleaseSCache(dscp);
7293 cm_ReleaseUser(userp);
7297 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7298 setAttr.clientModTime = time(NULL);
7299 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7300 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7301 smb_NotifyChange(FILE_ACTION_ADDED,
7302 FILE_NOTIFY_CHANGE_DIR_NAME,
7303 dscp, lastNamep, NULL, TRUE);
7305 /* we don't need this any longer */
7306 cm_ReleaseSCache(dscp);
7309 /* something went wrong creating or truncating the file */
7310 cm_ReleaseUser(userp);
7314 /* otherwise we succeeded */
7315 smb_SetSMBDataLength(outp, 0);
7316 cm_ReleaseUser(userp);
7321 BOOL smb_IsLegalFilename(char *filename)
7324 * Find the longest substring of filename that does not contain
7325 * any of the chars in illegalChars. If that substring is less
7326 * than the length of the whole string, then one or more of the
7327 * illegal chars is in filename.
7329 if (strcspn(filename, illegalChars) < strlen(filename))
7335 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7343 cm_scache_t *dscp; /* dir we're dealing with */
7344 cm_scache_t *scp; /* file we're creating */
7346 int initialModeBits;
7354 int created = 0; /* the file was new */
7359 excl = (inp->inCom == 0x03)? 0 : 1;
7361 attributes = smb_GetSMBParm(inp, 0);
7362 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7364 /* compute initial mode bits based on read-only flag in attributes */
7365 initialModeBits = 0666;
7366 if (attributes & SMB_ATTR_READONLY)
7367 initialModeBits &= ~0222;
7369 tp = smb_GetSMBData(inp, NULL);
7370 pathp = smb_ParseASCIIBlock(tp, &tp);
7371 if (smb_StoreAnsiFilenames)
7372 OemToChar(pathp,pathp);
7374 spacep = inp->spacep;
7375 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7377 userp = smb_GetUserFromVCP(vcp, inp);
7379 caseFold = CM_FLAG_CASEFOLD;
7381 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7383 cm_ReleaseUser(userp);
7384 return CM_ERROR_NOSUCHPATH;
7386 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7387 userp, tidPathp, &req, &dscp);
7390 cm_ReleaseUser(userp);
7395 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7396 cm_ReleaseSCache(dscp);
7397 cm_ReleaseUser(userp);
7398 if ( WANTS_DFS_PATHNAMES(inp) )
7399 return CM_ERROR_PATH_NOT_COVERED;
7401 return CM_ERROR_BADSHARENAME;
7403 #endif /* DFS_SUPPORT */
7405 /* otherwise, scp points to the parent directory. Do a lookup, and
7406 * truncate the file if we find it, otherwise we create the file.
7413 if (!smb_IsLegalFilename(lastNamep))
7414 return CM_ERROR_BADNTFILENAME;
7416 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7417 #ifdef DEBUG_VERBOSE
7420 hexp = osi_HexifyString( lastNamep );
7421 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7426 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7427 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7428 cm_ReleaseSCache(dscp);
7429 cm_ReleaseUser(userp);
7433 /* if we get here, if code is 0, the file exists and is represented by
7434 * scp. Otherwise, we have to create it.
7438 /* oops, file shouldn't be there */
7439 cm_ReleaseSCache(dscp);
7440 cm_ReleaseSCache(scp);
7441 cm_ReleaseUser(userp);
7442 return CM_ERROR_EXISTS;
7445 setAttr.mask = CM_ATTRMASK_LENGTH;
7446 setAttr.length.LowPart = 0;
7447 setAttr.length.HighPart = 0;
7448 code = cm_SetAttr(scp, &setAttr, userp, &req);
7451 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7452 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7453 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7457 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7458 smb_NotifyChange(FILE_ACTION_ADDED,
7459 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7460 dscp, lastNamep, NULL, TRUE);
7461 } else if (!excl && code == CM_ERROR_EXISTS) {
7462 /* not an exclusive create, and someone else tried
7463 * creating it already, then we open it anyway. We
7464 * don't bother retrying after this, since if this next
7465 * fails, that means that the file was deleted after
7466 * we started this call.
7468 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7471 setAttr.mask = CM_ATTRMASK_LENGTH;
7472 setAttr.length.LowPart = 0;
7473 setAttr.length.HighPart = 0;
7474 code = cm_SetAttr(scp, &setAttr, userp, &req);
7479 /* we don't need this any longer */
7480 cm_ReleaseSCache(dscp);
7483 /* something went wrong creating or truncating the file */
7484 if (scp) cm_ReleaseSCache(scp);
7485 cm_ReleaseUser(userp);
7489 /* make sure we only open files */
7490 if (scp->fileType != CM_SCACHETYPE_FILE) {
7491 cm_ReleaseSCache(scp);
7492 cm_ReleaseUser(userp);
7493 return CM_ERROR_ISDIR;
7496 /* now all we have to do is open the file itself */
7497 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7502 lock_ObtainMutex(&fidp->mx);
7503 /* always create it open for read/write */
7504 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7506 /* remember that the file was newly created */
7508 fidp->flags |= SMB_FID_CREATED;
7510 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7512 /* save a pointer to the vnode */
7514 lock_ObtainMutex(&scp->mx);
7515 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7516 lock_ReleaseMutex(&scp->mx);
7519 fidp->userp = userp;
7520 lock_ReleaseMutex(&fidp->mx);
7522 smb_SetSMBParm(outp, 0, fidp->fid);
7523 smb_SetSMBDataLength(outp, 0);
7525 cm_Open(scp, 0, userp);
7527 smb_ReleaseFID(fidp);
7528 cm_ReleaseUser(userp);
7529 /* leave scp held since we put it in fidp->scp */
7533 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7536 osi_hyper_t new_offset;
7547 fd = smb_GetSMBParm(inp, 0);
7548 whence = smb_GetSMBParm(inp, 1);
7549 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7551 /* try to find the file descriptor */
7552 fd = smb_ChainFID(fd, inp);
7553 fidp = smb_FindFID(vcp, fd, 0);
7555 return CM_ERROR_BADFD;
7557 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7558 smb_CloseFID(vcp, fidp, NULL, 0);
7559 smb_ReleaseFID(fidp);
7560 return CM_ERROR_NOSUCHFILE;
7563 lock_ObtainMutex(&fidp->mx);
7564 if (fidp->flags & SMB_FID_IOCTL) {
7565 lock_ReleaseMutex(&fidp->mx);
7566 smb_ReleaseFID(fidp);
7567 return CM_ERROR_BADFD;
7569 lock_ReleaseMutex(&fidp->mx);
7571 userp = smb_GetUserFromVCP(vcp, inp);
7573 lock_ObtainMutex(&fidp->mx);
7576 lock_ReleaseMutex(&fidp->mx);
7577 lock_ObtainMutex(&scp->mx);
7578 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7579 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7581 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7583 /* offset from current offset */
7584 new_offset = LargeIntegerAdd(fidp->offset,
7585 ConvertLongToLargeInteger(offset));
7587 else if (whence == 2) {
7588 /* offset from current EOF */
7589 new_offset = LargeIntegerAdd(scp->length,
7590 ConvertLongToLargeInteger(offset));
7592 new_offset = ConvertLongToLargeInteger(offset);
7595 fidp->offset = new_offset;
7596 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7597 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7598 smb_SetSMBDataLength(outp, 0);
7600 lock_ReleaseMutex(&scp->mx);
7601 smb_ReleaseFID(fidp);
7602 cm_ReleaseSCache(scp);
7603 cm_ReleaseUser(userp);
7607 /* dispatch all of the requests received in a packet. Due to chaining, this may
7608 * be more than one request.
7610 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7611 NCB *ncbp, raw_write_cont_t *rwcp)
7615 unsigned long code = 0;
7616 unsigned char *outWctp;
7617 int nparms; /* # of bytes of parameters */
7619 int nbytes; /* bytes of data, excluding count */
7622 unsigned short errCode;
7623 unsigned long NTStatus;
7625 unsigned char errClass;
7626 unsigned int oldGen;
7627 DWORD oldTime, newTime;
7629 /* get easy pointer to the data */
7630 smbp = (smb_t *) inp->data;
7632 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7633 /* setup the basic parms for the initial request in the packet */
7634 inp->inCom = smbp->com;
7635 inp->wctp = &smbp->wct;
7637 inp->ncb_length = ncbp->ncb_length;
7642 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7643 /* log it and discard it */
7645 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7646 __FILE__, __LINE__, ncbp->ncb_length);
7648 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7652 /* We are an ongoing op */
7653 thrd_Increment(&ongoingOps);
7655 /* set up response packet for receiving output */
7656 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7657 smb_FormatResponsePacket(vcp, inp, outp);
7658 outWctp = outp->wctp;
7660 /* Remember session generation number and time */
7661 oldGen = sessionGen;
7662 oldTime = GetTickCount();
7664 while (inp->inCom != 0xff) {
7665 dp = &smb_dispatchTable[inp->inCom];
7667 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7668 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7669 code = outp->resumeCode;
7673 /* process each request in the packet; inCom, wctp and inCount
7674 * are already set up.
7676 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7679 /* now do the dispatch */
7680 /* start by formatting the response record a little, as a default */
7681 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7683 outWctp[1] = 0xff; /* no operation */
7684 outWctp[2] = 0; /* padding */
7689 /* not a chained request, this is a more reasonable default */
7690 outWctp[0] = 0; /* wct of zero */
7691 outWctp[1] = 0; /* and bcc (word) of zero */
7695 /* once set, stays set. Doesn't matter, since we never chain
7696 * "no response" calls.
7698 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7702 /* we have a recognized operation */
7704 if (inp->inCom == 0x1d)
7706 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7708 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7709 code = (*(dp->procp)) (vcp, inp, outp);
7710 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7712 if ( code == CM_ERROR_BADSMB ||
7713 code == CM_ERROR_BADOP )
7715 #endif /* LOG_PACKET */
7718 if (oldGen != sessionGen) {
7719 newTime = GetTickCount();
7721 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7722 newTime - oldTime, ncbp->ncb_length);
7724 osi_Log2(smb_logp, "Pkt straddled session startup, "
7725 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7729 /* bad opcode, fail the request, after displaying it */
7730 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7733 #endif /* LOG_PACKET */
7737 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7738 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7739 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7740 if (code == IDCANCEL)
7744 code = CM_ERROR_BADOP;
7747 /* catastrophic failure: log as much as possible */
7748 if (code == CM_ERROR_BADSMB) {
7750 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7755 #endif /* LOG_PACKET */
7756 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7759 code = CM_ERROR_INVAL;
7762 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7763 thrd_Decrement(&ongoingOps);
7768 /* now, if we failed, turn the current response into an empty
7769 * one, and fill in the response packet's error code.
7772 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7773 smb_MapNTError(code, &NTStatus);
7774 outWctp = outp->wctp;
7775 smbp = (smb_t *) &outp->data;
7776 if (code != CM_ERROR_PARTIALWRITE
7777 && code != CM_ERROR_BUFFERTOOSMALL
7778 && code != CM_ERROR_GSSCONTINUE) {
7779 /* nuke wct and bcc. For a partial
7780 * write or an in-process authentication handshake,
7781 * assume they're OK.
7787 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7788 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7789 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7790 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7791 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7795 smb_MapCoreError(code, vcp, &errCode, &errClass);
7796 outWctp = outp->wctp;
7797 smbp = (smb_t *) &outp->data;
7798 if (code != CM_ERROR_PARTIALWRITE) {
7799 /* nuke wct and bcc. For a partial
7800 * write, assume they're OK.
7806 smbp->errLow = (unsigned char) (errCode & 0xff);
7807 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7808 smbp->rcls = errClass;
7811 } /* error occurred */
7813 /* if we're here, we've finished one request. Look to see if
7814 * this is a chained opcode. If it is, setup things to process
7815 * the chained request, and setup the output buffer to hold the
7816 * chained response. Start by finding the next input record.
7818 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7819 break; /* not a chained req */
7820 tp = inp->wctp; /* points to start of last request */
7821 /* in a chained request, the first two
7822 * parm fields are required, and are
7823 * AndXCommand/AndXReserved and
7825 if (tp[0] < 2) break;
7826 if (tp[1] == 0xff) break; /* no more chained opcodes */
7828 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7831 /* and now append the next output request to the end of this
7832 * last request. Begin by finding out where the last response
7833 * ends, since that's where we'll put our new response.
7835 outWctp = outp->wctp; /* ptr to out parameters */
7836 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7837 nparms = outWctp[0] << 1;
7838 tp = outWctp + nparms + 1; /* now points to bcc field */
7839 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7840 tp += 2 /* for the count itself */ + nbytes;
7841 /* tp now points to the new output record; go back and patch the
7842 * second parameter (off2) to point to the new record.
7844 temp = (unsigned int)(tp - outp->data);
7845 outWctp[3] = (unsigned char) (temp & 0xff);
7846 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7847 outWctp[2] = 0; /* padding */
7848 outWctp[1] = inp->inCom; /* next opcode */
7850 /* finally, setup for the next iteration */
7853 } /* while loop over all requests in the packet */
7855 /* now send the output packet, and return */
7857 smb_SendPacket(vcp, outp);
7858 thrd_Decrement(&ongoingOps);
7864 /* Wait for Netbios() calls to return, and make the results available to server
7865 * threads. Note that server threads can't wait on the NCBevents array
7866 * themselves, because NCB events are manual-reset, and the servers would race
7867 * each other to reset them.
7869 void smb_ClientWaiter(void *parmp)
7874 while (smbShutdownFlag == 0) {
7875 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7877 if (code == WAIT_OBJECT_0)
7880 /* error checking */
7881 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7883 int abandonIdx = code - WAIT_ABANDONED_0;
7884 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7887 if (code == WAIT_IO_COMPLETION)
7889 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7893 if (code == WAIT_TIMEOUT)
7895 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7898 if (code == WAIT_FAILED)
7900 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7903 idx = code - WAIT_OBJECT_0;
7905 /* check idx range! */
7906 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7908 /* this is fatal - log as much as possible */
7909 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7913 thrd_ResetEvent(NCBevents[idx]);
7914 thrd_SetEvent(NCBreturns[0][idx]);
7920 * Try to have one NCBRECV request waiting for every live session. Not more
7921 * than one, because if there is more than one, it's hard to handle Write Raw.
7923 void smb_ServerWaiter(void *parmp)
7926 int idx_session, idx_NCB;
7932 while (smbShutdownFlag == 0) {
7934 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7936 if (code == WAIT_OBJECT_0)
7939 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7941 int abandonIdx = code - WAIT_ABANDONED_0;
7942 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7945 if (code == WAIT_IO_COMPLETION)
7947 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7951 if (code == WAIT_TIMEOUT)
7953 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7956 if (code == WAIT_FAILED)
7958 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7961 idx_session = code - WAIT_OBJECT_0;
7963 /* check idx range! */
7964 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7966 /* this is fatal - log as much as possible */
7967 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7973 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7975 if (code == WAIT_OBJECT_0) {
7976 if (smbShutdownFlag == 1)
7982 /* error checking */
7983 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7985 int abandonIdx = code - WAIT_ABANDONED_0;
7986 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7989 if (code == WAIT_IO_COMPLETION)
7991 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7995 if (code == WAIT_TIMEOUT)
7997 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8000 if (code == WAIT_FAILED)
8002 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8005 idx_NCB = code - WAIT_OBJECT_0;
8007 /* check idx range! */
8008 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8010 /* this is fatal - log as much as possible */
8011 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8015 /* Link them together */
8016 NCBsessions[idx_NCB] = idx_session;
8019 ncbp = NCBs[idx_NCB];
8020 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8021 ncbp->ncb_command = NCBRECV | ASYNCH;
8022 ncbp->ncb_lana_num = lanas[idx_session];
8024 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8025 ncbp->ncb_event = NCBevents[idx_NCB];
8026 ncbp->ncb_length = SMB_PACKETSIZE;
8029 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
8030 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
8031 ncbp->ncb_event = NCBreturns[0][idx_NCB];
8032 ncbp->ncb_length = SMB_PACKETSIZE;
8033 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8034 Netbios(ncbp, dos_ncb);
8040 * The top level loop for handling SMB request messages. Each server thread
8041 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8042 * NCB and buffer for the incoming request are loaned to us.
8044 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8045 * to immediately send a request for the rest of the data. This must come
8046 * before any other traffic for that session, so we delay setting the session
8047 * event until that data has come in.
8049 void smb_Server(VOID *parmp)
8051 INT_PTR myIdx = (INT_PTR) parmp;
8055 smb_packet_t *outbufp;
8057 int idx_NCB, idx_session;
8059 smb_vc_t *vcp = NULL;
8065 rx_StartClientThread();
8068 outbufp = GetPacket();
8069 outbufp->ncbp = outncbp;
8077 smb_ResetServerPriority();
8079 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8082 /* terminate silently if shutdown flag is set */
8083 if (code == WAIT_OBJECT_0) {
8084 if (smbShutdownFlag == 1) {
8085 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8091 /* error checking */
8092 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8094 int abandonIdx = code - WAIT_ABANDONED_0;
8095 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8098 if (code == WAIT_IO_COMPLETION)
8100 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8104 if (code == WAIT_TIMEOUT)
8106 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8109 if (code == WAIT_FAILED)
8111 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8114 idx_NCB = code - WAIT_OBJECT_0;
8116 /* check idx range! */
8117 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8119 /* this is fatal - log as much as possible */
8120 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8124 ncbp = NCBs[idx_NCB];
8126 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8128 idx_session = NCBsessions[idx_NCB];
8129 rc = ncbp->ncb_retcode;
8131 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8132 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8136 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8140 /* Can this happen? Or is it just my UNIX paranoia? */
8141 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8147 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8151 /* Client closed session */
8152 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8154 lock_ObtainMutex(&vcp->mx);
8155 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8156 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8158 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8159 lock_ReleaseMutex(&vcp->mx);
8160 lock_ObtainWrite(&smb_globalLock);
8161 dead_sessions[vcp->session] = TRUE;
8162 lock_ReleaseWrite(&smb_globalLock);
8163 smb_CleanupDeadVC(vcp);
8167 lock_ReleaseMutex(&vcp->mx);
8173 /* Treat as transient error */
8175 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8179 "dispatch smb recv failed, message incomplete, ncb_length %d",
8182 "SMB message incomplete, "
8183 "length %d", ncbp->ncb_length);
8186 * We used to discard the packet.
8187 * Instead, try handling it normally.
8191 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8195 /* A weird error code. Log it, sleep, and continue. */
8196 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8198 lock_ObtainMutex(&vcp->mx);
8199 if (vcp && vcp->errorCount++ > 3) {
8200 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8201 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8202 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8204 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8205 lock_ReleaseMutex(&vcp->mx);
8206 lock_ObtainWrite(&smb_globalLock);
8207 dead_sessions[vcp->session] = TRUE;
8208 lock_ReleaseWrite(&smb_globalLock);
8209 smb_CleanupDeadVC(vcp);
8213 lock_ReleaseMutex(&vcp->mx);
8219 lock_ReleaseMutex(&vcp->mx);
8221 thrd_SetEvent(SessionEvents[idx_session]);
8226 /* Success, so now dispatch on all the data in the packet */
8228 smb_concurrentCalls++;
8229 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8230 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8233 * If at this point vcp is NULL (implies that packet was invalid)
8234 * then we are in big trouble. This means either :
8235 * a) we have the wrong NCB.
8236 * b) Netbios screwed up the call.
8237 * c) The VC was already marked dead before we were able to
8239 * Obviously this implies that
8240 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8241 * lanas[idx_session] != ncbp->ncb_lana_num )
8242 * Either way, we can't do anything with this packet.
8243 * Log, sleep and resume.
8246 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8250 ncbp->ncb_lana_num);
8252 /* Also log in the trace log. */
8253 osi_Log4(smb_logp, "Server: VCP does not exist!"
8254 "LSNs[idx_session]=[%d],"
8255 "lanas[idx_session]=[%d],"
8256 "ncbp->ncb_lsn=[%d],"
8257 "ncbp->ncb_lana_num=[%d]",
8261 ncbp->ncb_lana_num);
8263 /* thrd_Sleep(1000); Don't bother sleeping */
8264 thrd_SetEvent(SessionEvents[idx_session]);
8265 smb_concurrentCalls--;
8269 smb_SetRequestStartTime();
8271 vcp->errorCount = 0;
8272 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8274 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
8275 /* copy whole packet to virtual memory */
8276 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
8278 bufp->dos_pkt / 16, bufp);*/
8280 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
8282 smbp = (smb_t *)bufp->data;
8285 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
8289 if (smbp->com == 0x1d) {
8290 /* Special handling for Write Raw */
8291 raw_write_cont_t rwc;
8292 EVENT_HANDLE rwevent;
8293 char eventName[MAX_PATH];
8295 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8296 if (rwc.code == 0) {
8297 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8298 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8299 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8300 ncbp->ncb_command = NCBRECV | ASYNCH;
8301 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8302 ncbp->ncb_lana_num = vcp->lana;
8303 ncbp->ncb_buffer = rwc.buf;
8304 ncbp->ncb_length = 65535;
8305 ncbp->ncb_event = rwevent;
8309 Netbios(ncbp, dos_ncb);
8311 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8312 thrd_CloseHandle(rwevent);
8314 thrd_SetEvent(SessionEvents[idx_session]);
8316 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8318 else if (smbp->com == 0xa0) {
8320 * Serialize the handling for NT Transact
8323 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8324 thrd_SetEvent(SessionEvents[idx_session]);
8326 thrd_SetEvent(SessionEvents[idx_session]);
8327 /* TODO: what else needs to be serialized? */
8328 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8330 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
8332 __except( smb_ServerExceptionFilter() ) {
8336 smb_concurrentCalls--;
8339 thrd_SetEvent(NCBavails[idx_NCB]);
8346 * Exception filter for the server threads. If an exception occurs in the
8347 * dispatch routines, which is where exceptions are most common, then do a
8348 * force trace and give control to upstream exception handlers. Useful for
8351 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
8352 DWORD smb_ServerExceptionFilter(void) {
8353 /* While this is not the best time to do a trace, if it succeeds, then
8354 * we have a trace (assuming tracing was enabled). Otherwise, this should
8355 * throw a second exception.
8357 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8358 afsd_ForceTrace(TRUE);
8359 buf_ForceTrace(TRUE);
8360 return EXCEPTION_CONTINUE_SEARCH;
8365 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8366 * If the number of server threads is M, and the number of live sessions is
8367 * N, then the number of NCB's in use at any time either waiting for, or
8368 * holding, received messages is M + N, so that is how many NCB's get created.
8370 void InitNCBslot(int idx)
8372 struct smb_packet *bufp;
8373 EVENT_HANDLE retHandle;
8375 char eventName[MAX_PATH];
8377 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
8379 NCBs[idx] = GetNCB();
8380 sprintf(eventName,"NCBavails[%d]", idx);
8381 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8382 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8383 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8385 sprintf(eventName,"NCBevents[%d]", idx);
8386 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8387 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8388 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8390 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8391 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8392 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8393 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8394 for (i=0; i<smb_NumServerThreads; i++)
8395 NCBreturns[i][idx] = retHandle;
8397 bufp->spacep = cm_GetSpace();
8401 /* listen for new connections */
8402 void smb_Listener(void *parmp)
8408 int session, thread;
8409 smb_vc_t *vcp = NULL;
8411 char rname[NCBNAMSZ+1];
8412 char cname[MAX_COMPUTERNAME_LENGTH+1];
8413 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8418 INT_PTR lana = (INT_PTR) parmp;
8422 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8425 /* retrieve computer name */
8426 GetComputerName(cname, &cnamelen);
8429 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8430 memset(ncbp, 0, sizeof(NCB));
8433 ncbp->ncb_command = NCBLISTEN;
8434 ncbp->ncb_rto = 0; /* No receive timeout */
8435 ncbp->ncb_sto = 0; /* No send timeout */
8437 /* pad out with spaces instead of null termination */
8438 len = (long)strlen(smb_localNamep);
8439 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8440 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8442 strcpy(ncbp->ncb_callname, "*");
8443 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8445 ncbp->ncb_lana_num = (UCHAR)lana;
8448 code = Netbios(ncbp);
8450 code = Netbios(ncbp, dos_ncb);
8452 if (code == NRC_BRIDGE) {
8453 int lanaRemaining = 0;
8455 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
8464 "NCBLISTEN lana=%d failed with NRC_BRIDGE. Listener thread exiting.",
8465 ncbp->ncb_lana_num, code);
8467 for (i = 0; i < lana_list.length; i++) {
8468 if (lana_list.lana[i] == ncbp->ncb_lana_num) {
8469 smb_StopListener(ncbp, lana_list.lana[i]);
8470 lana_list.lana[i] = 255;
8472 if (lana_list.lana[i] != 255)
8476 if (lanaRemaining == 0) {
8477 cm_VolStatus_Network_Stopped(cm_NetbiosName
8482 smb_ListenerState = SMB_LISTENER_STOPPED;
8483 smb_LANadapter = -1;
8484 lana_list.length = 0;
8488 } else if (code != 0) {
8490 char tbuffer[AFSPATHMAX];
8493 /* terminate silently if shutdown flag is set */
8494 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
8503 "NCBLISTEN lana=%d failed with code %d",
8504 ncbp->ncb_lana_num, code);
8506 "Client exiting due to network failure. Please restart client.\n");
8510 "Client exiting due to network failure. Please restart client.\n"
8511 "NCBLISTEN lana=%d failed with code %d",
8512 ncbp->ncb_lana_num, code);
8514 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8515 MB_OK|MB_SERVICE_NOTIFICATION);
8516 osi_panic(tbuffer, __FILE__, __LINE__);
8518 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
8519 ncbp->ncb_lana_num, code);
8520 fprintf(stderr, "\nClient exiting due to network failure "
8521 "(possibly due to power-saving mode)\n");
8522 fprintf(stderr, "Please restart client.\n");
8523 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
8527 /* check for remote conns */
8528 /* first get remote name and insert null terminator */
8529 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8530 for (i=NCBNAMSZ; i>0; i--) {
8531 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8537 /* compare with local name */
8539 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8540 flags |= SMB_VCFLAG_REMOTECONN;
8543 lock_ObtainMutex(&smb_ListenerLock);
8545 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8546 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8548 /* now ncbp->ncb_lsn is the connection ID */
8549 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8550 if (vcp->session == 0) {
8551 /* New generation */
8552 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8555 /* Log session startup */
8557 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8558 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8559 #endif /* NOTSERVICE */
8560 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8561 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8563 if (reportSessionStartups) {
8565 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8568 fprintf(stderr, "%s: New session %d starting from host %s\n",
8569 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8574 lock_ObtainMutex(&vcp->mx);
8575 strcpy(vcp->rname, rname);
8576 vcp->flags |= flags;
8577 lock_ReleaseMutex(&vcp->mx);
8579 /* Allocate slot in session arrays */
8580 /* Re-use dead session if possible, otherwise add one more */
8581 /* But don't look at session[0], it is reserved */
8582 lock_ObtainWrite(&smb_globalLock);
8583 for (session = 1; session < numSessions; session++) {
8584 if (dead_sessions[session]) {
8585 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8586 dead_sessions[session] = FALSE;
8590 lock_ReleaseWrite(&smb_globalLock);
8592 /* We are re-using an existing VC because the lsn and lana
8594 session = vcp->session;
8596 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8598 /* Log session startup */
8600 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8601 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8602 #endif /* NOTSERVICE */
8603 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8604 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8606 if (reportSessionStartups) {
8608 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8611 fprintf(stderr, "%s: Re-using session %d starting from host %s\n",
8612 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8618 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8619 unsigned long code = CM_ERROR_ALLBUSY;
8620 smb_packet_t * outp = GetPacket();
8621 unsigned char *outWctp;
8624 smb_FormatResponsePacket(vcp, NULL, outp);
8627 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8628 unsigned long NTStatus;
8629 smb_MapNTError(code, &NTStatus);
8630 outWctp = outp->wctp;
8631 smbp = (smb_t *) &outp->data;
8635 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8636 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8637 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8638 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8639 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8641 unsigned short errCode;
8642 unsigned char errClass;
8643 smb_MapCoreError(code, vcp, &errCode, &errClass);
8644 outWctp = outp->wctp;
8645 smbp = (smb_t *) &outp->data;
8649 smbp->errLow = (unsigned char) (errCode & 0xff);
8650 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8651 smbp->rcls = errClass;
8653 smb_SendPacket(vcp, outp);
8654 smb_FreePacket(outp);
8656 lock_ObtainMutex(&vcp->mx);
8657 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8658 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8660 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8661 lock_ReleaseMutex(&vcp->mx);
8662 lock_ObtainWrite(&smb_globalLock);
8663 dead_sessions[vcp->session] = TRUE;
8664 lock_ReleaseWrite(&smb_globalLock);
8665 smb_CleanupDeadVC(vcp);
8667 lock_ReleaseMutex(&vcp->mx);
8670 /* assert that we do not exceed the maximum number of sessions or NCBs.
8671 * we should probably want to wait for a session to be freed in case
8674 osi_assert(session < SESSION_MAX - 1);
8675 osi_assert(numNCBs < NCB_MAX - 1); /* if we pass this test we can allocate one more */
8677 lock_ObtainMutex(&vcp->mx);
8678 vcp->session = session;
8679 lock_ReleaseMutex(&vcp->mx);
8680 lock_ObtainWrite(&smb_globalLock);
8681 LSNs[session] = ncbp->ncb_lsn;
8682 lanas[session] = ncbp->ncb_lana_num;
8683 lock_ReleaseWrite(&smb_globalLock);
8685 if (session == numSessions) {
8686 /* Add new NCB for new session */
8687 char eventName[MAX_PATH];
8689 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8691 InitNCBslot(numNCBs);
8692 lock_ObtainWrite(&smb_globalLock);
8694 lock_ReleaseWrite(&smb_globalLock);
8695 thrd_SetEvent(NCBavails[0]);
8696 thrd_SetEvent(NCBevents[0]);
8697 for (thread = 0; thread < smb_NumServerThreads; thread++)
8698 thrd_SetEvent(NCBreturns[thread][0]);
8699 /* Also add new session event */
8700 sprintf(eventName, "SessionEvents[%d]", session);
8701 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8702 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8703 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8704 lock_ObtainWrite(&smb_globalLock);
8706 lock_ReleaseWrite(&smb_globalLock);
8707 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8708 thrd_SetEvent(SessionEvents[0]);
8710 thrd_SetEvent(SessionEvents[session]);
8716 lock_ReleaseMutex(&smb_ListenerLock);
8717 } /* dispatch while loop */
8722 /* initialize Netbios */
8723 int smb_NetbiosInit(void)
8729 int i, lana, code, l;
8731 int delname_tried=0;
8734 lana_number_t lanaNum;
8736 /* setup the NCB system */
8739 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8742 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8743 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8744 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8746 if (smb_LANadapter != -1)
8747 afsi_log("LAN adapter number %d", smb_LANadapter);
8749 afsi_log("LAN adapter number not determined");
8752 afsi_log("Set for gateway service");
8754 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8756 /* something went horribly wrong. We can't proceed without a netbios name */
8758 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8759 osi_panic(buf, __FILE__, __LINE__);
8762 /* remember the name */
8763 len = (int)strlen(cm_NetbiosName);
8765 free(smb_localNamep);
8766 smb_localNamep = malloc(len+1);
8767 strcpy(smb_localNamep, cm_NetbiosName);
8768 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8772 if (smb_LANadapter == -1) {
8773 ncbp->ncb_command = NCBENUM;
8774 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8775 ncbp->ncb_length = sizeof(lana_list);
8776 code = Netbios(ncbp);
8778 afsi_log("Netbios NCBENUM error code %d", code);
8779 osi_panic(s, __FILE__, __LINE__);
8783 lana_list.length = 1;
8784 lana_list.lana[0] = smb_LANadapter;
8787 for (i = 0; i < lana_list.length; i++) {
8788 /* reset the adaptor: in Win32, this is required for every process, and
8789 * acts as an init call, not as a real hardware reset.
8791 ncbp->ncb_command = NCBRESET;
8792 ncbp->ncb_callname[0] = 100;
8793 ncbp->ncb_callname[2] = 100;
8794 ncbp->ncb_lana_num = lana_list.lana[i];
8795 code = Netbios(ncbp);
8797 code = ncbp->ncb_retcode;
8799 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8800 lana_list.lana[i] = 255; /* invalid lana */
8802 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8806 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
8807 we will just fake the LANA list */
8808 if (smb_LANadapter == -1) {
8809 for (i = 0; i < 8; i++)
8810 lana_list.lana[i] = i;
8811 lana_list.length = 8;
8814 lana_list.length = 1;
8815 lana_list.lana[0] = smb_LANadapter;
8819 /* and declare our name so we can receive connections */
8820 memset(ncbp, 0, sizeof(*ncbp));
8821 len=lstrlen(smb_localNamep);
8822 memset(smb_sharename,' ',NCBNAMSZ);
8823 memcpy(smb_sharename,smb_localNamep,len);
8824 afsi_log("lana_list.length %d", lana_list.length);
8826 /* Keep the name so we can unregister it later */
8827 for (l = 0; l < lana_list.length; l++) {
8828 lana = lana_list.lana[l];
8830 ncbp->ncb_command = NCBADDNAME;
8831 ncbp->ncb_lana_num = lana;
8832 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8834 code = Netbios(ncbp);
8836 code = Netbios(ncbp, dos_ncb);
8839 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8840 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8842 char name[NCBNAMSZ+1];
8844 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8845 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8849 code = ncbp->ncb_retcode;
8852 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8854 /* we only use one LANA with djgpp */
8855 lana_list.lana[0] = lana;
8856 lana_list.length = 1;
8860 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8861 if (code == NRC_BRIDGE) { /* invalid LANA num */
8862 lana_list.lana[l] = 255;
8865 else if (code == NRC_DUPNAME) {
8866 afsi_log("Name already exists; try to delete it");
8867 memset(ncbp, 0, sizeof(*ncbp));
8868 ncbp->ncb_command = NCBDELNAME;
8869 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8870 ncbp->ncb_lana_num = lana;
8872 code = Netbios(ncbp);
8874 code = Netbios(ncbp, dos_ncb);
8877 code = ncbp->ncb_retcode;
8879 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8881 if (code != 0 || delname_tried) {
8882 lana_list.lana[l] = 255;
8884 else if (code == 0) {
8885 if (!delname_tried) {
8893 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8894 lana_list.lana[l] = 255; /* invalid lana */
8898 lana_found = 1; /* at least one worked */
8905 osi_assert(lana_list.length >= 0);
8907 afsi_log("No valid LANA numbers found!");
8908 lana_list.length = 0;
8909 smb_LANadapter = -1;
8910 smb_ListenerState = SMB_LISTENER_STOPPED;
8911 cm_VolStatus_Network_Stopped(cm_NetbiosName
8918 /* we're done with the NCB now */
8921 return (lana_list.length > 0 ? 1 : 0);
8924 void smb_StartListeners()
8930 if (smb_ListenerState == SMB_LISTENER_STARTED)
8933 smb_ListenerState = SMB_LISTENER_STARTED;
8934 cm_VolStatus_Network_Started(cm_NetbiosName
8940 for (i = 0; i < lana_list.length; i++) {
8941 if (lana_list.lana[i] == 255)
8943 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8944 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8945 osi_assert(phandle != NULL);
8946 thrd_CloseHandle(phandle);
8950 void smb_RestartListeners()
8952 if (!powerStateSuspended && smb_ListenerState == SMB_LISTENER_STOPPED) {
8953 if (smb_NetbiosInit())
8954 smb_StartListeners();
8958 void smb_StopListener(NCB *ncbp, int lana)
8962 memset(ncbp, 0, sizeof(*ncbp));
8963 ncbp->ncb_command = NCBDELNAME;
8964 ncbp->ncb_lana_num = lana;
8965 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8966 code = Netbios(ncbp);
8968 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8969 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8971 /* and then reset the LANA; this will cause the listener threads to exit */
8972 ncbp->ncb_command = NCBRESET;
8973 ncbp->ncb_callname[0] = 100;
8974 ncbp->ncb_callname[2] = 100;
8975 ncbp->ncb_lana_num = lana;
8976 code = Netbios(ncbp);
8978 code = ncbp->ncb_retcode;
8980 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8982 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8986 void smb_StopListeners(void)
8991 if (smb_ListenerState == SMB_LISTENER_STOPPED)
8994 smb_ListenerState = SMB_LISTENER_STOPPED;
8995 cm_VolStatus_Network_Stopped(cm_NetbiosName
9003 /* Unregister the SMB name */
9004 for (l = 0; l < lana_list.length; l++) {
9005 lana = lana_list.lana[l];
9008 smb_StopListener(ncbp, lana);
9010 /* mark the adapter invalid */
9011 lana_list.lana[l] = 255; /* invalid lana */
9015 /* force a re-evaluation of the network adapters */
9016 lana_list.length = 0;
9017 smb_LANadapter = -1;
9019 Sleep(1000); /* give the listener threads a chance to exit */
9022 void smb_Init(osi_log_t *logp, int useV3,
9038 EVENT_HANDLE retHandle;
9039 char eventName[MAX_PATH];
9041 smb_TlsRequestSlot = TlsAlloc();
9044 smb_MBfunc = aMBfunc;
9049 /* Initialize smb_localZero */
9050 myTime.tm_isdst = -1; /* compute whether on DST or not */
9051 myTime.tm_year = 70;
9057 smb_localZero = mktime(&myTime);
9059 #ifndef USE_NUMERIC_TIME_CONV
9060 /* Initialize kludge-GMT */
9061 smb_CalculateNowTZ();
9062 #endif /* USE_NUMERIC_TIME_CONV */
9063 #ifdef AFS_FREELANCE_CLIENT
9064 /* Make sure the root.afs volume has the correct time */
9065 cm_noteLocalMountPointChange();
9068 /* initialize the remote debugging log */
9071 /* and the global lock */
9072 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
9073 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
9075 /* Raw I/O data structures */
9076 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
9078 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
9080 /* 4 Raw I/O buffers */
9082 smb_RawBufs = calloc(65536,1);
9083 *((char **)smb_RawBufs) = NULL;
9084 for (i=0; i<3; i++) {
9085 char *rawBuf = calloc(65536,1);
9086 *((char **)rawBuf) = smb_RawBufs;
9087 smb_RawBufs = rawBuf;
9090 npar = 65536 >> 4; /* number of paragraphs */
9091 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
9093 afsi_log("Cannot allocate %d paragraphs of DOS memory",
9095 osi_panic("",__FILE__,__LINE__);
9098 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
9101 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
9103 _farpokel(_dos_ds, smb_RawBufs, NULL);
9104 for (i=0; i<SMB_RAW_BUFS-1; i++) {
9105 npar = 65536 >> 4; /* number of paragraphs */
9106 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
9108 afsi_log("Cannot allocate %d paragraphs of DOS memory",
9110 osi_panic("",__FILE__,__LINE__);
9113 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
9116 rawBuf = (seg * 16) + 0; /* DOS physical address */
9117 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
9118 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
9119 smb_RawBufs = rawBuf;
9123 /* global free lists */
9124 smb_ncbFreeListp = NULL;
9125 smb_packetFreeListp = NULL;
9129 /* Initialize listener and server structures */
9131 memset(dead_sessions, 0, sizeof(dead_sessions));
9132 sprintf(eventName, "SessionEvents[0]");
9133 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9134 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9135 afsi_log("Event Object Already Exists: %s", eventName);
9137 smb_NumServerThreads = nThreads;
9138 sprintf(eventName, "NCBavails[0]");
9139 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9140 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9141 afsi_log("Event Object Already Exists: %s", eventName);
9142 sprintf(eventName, "NCBevents[0]");
9143 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9144 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9145 afsi_log("Event Object Already Exists: %s", eventName);
9146 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9147 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9148 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9149 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9150 afsi_log("Event Object Already Exists: %s", eventName);
9151 for (i = 0; i < smb_NumServerThreads; i++) {
9152 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9153 NCBreturns[i][0] = retHandle;
9156 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9157 for (i = 0; i < smb_NumServerThreads; i++) {
9158 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9159 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9160 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9161 afsi_log("Event Object Already Exists: %s", eventName);
9162 InitNCBslot((int)(i+1));
9164 numNCBs = smb_NumServerThreads + 1;
9166 /* Initialize dispatch table */
9167 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9168 /* Prepare the table for unknown operations */
9169 for(i=0; i<= SMB_NOPCODES; i++) {
9170 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9172 /* Fill in the ones we do know */
9173 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9174 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9175 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9176 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9177 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9178 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9179 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9180 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9181 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9182 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9183 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9184 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9185 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9186 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9187 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9188 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9189 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9190 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9191 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9192 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9193 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9194 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9195 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9196 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9197 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9198 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9199 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9200 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9201 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9202 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9203 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9204 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9205 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9206 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9207 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9208 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9209 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9210 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9211 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9212 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9213 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9214 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9215 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9216 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9217 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9218 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9219 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9220 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9221 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9222 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9223 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9224 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9225 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9226 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9227 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9228 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9229 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9230 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9231 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9232 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9233 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9234 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9235 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9236 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9237 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9238 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9239 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9240 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9241 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9242 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9243 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9244 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9245 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9246 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9248 /* setup tran 2 dispatch table */
9249 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9250 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9251 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9252 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9253 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9254 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9255 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9256 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9257 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9258 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9259 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9260 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9261 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9262 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9263 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9264 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9265 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9266 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9268 /* setup the rap dispatch table */
9269 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9270 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9271 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9272 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9273 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9277 /* if we are doing SMB authentication we have register outselves as a logon process */
9278 if (smb_authType != SMB_AUTH_NONE) {
9279 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9280 LSA_STRING afsProcessName;
9281 LSA_OPERATIONAL_MODE dummy; /*junk*/
9283 afsProcessName.Buffer = "OpenAFSClientDaemon";
9284 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9285 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9287 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9289 if (nts == STATUS_SUCCESS) {
9290 LSA_STRING packageName;
9291 /* we are registered. Find out the security package id */
9292 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9293 packageName.Length = (USHORT)strlen(packageName.Buffer);
9294 packageName.MaximumLength = packageName.Length + 1;
9295 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9296 if (nts == STATUS_SUCCESS) {
9298 * This code forces Windows to authenticate against the Logon Cache
9299 * first instead of attempting to authenticate against the Domain
9300 * Controller. When the Windows logon cache is enabled this improves
9301 * performance by removing the network access and works around a bug
9302 * seen at sites which are using a MIT Kerberos principal to login
9303 * to machines joined to a non-root domain in a multi-domain forest.
9304 * MsV1_0SetProcessOption was added in Windows XP.
9306 PVOID pResponse = NULL;
9307 ULONG cbResponse = 0;
9308 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9310 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9311 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9312 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9313 OptionsRequest.DisableOptions = FALSE;
9315 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9318 sizeof(OptionsRequest),
9324 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9325 char message[AFSPATHMAX];
9326 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9328 OutputDebugString(message);
9331 OutputDebugString("MsV1_0SetProcessOption success");
9332 afsi_log("MsV1_0SetProcessOption success");
9334 /* END - code from Larry */
9336 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9337 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9338 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9340 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9342 /* something went wrong. We report the error and revert back to no authentication
9343 because we can't perform any auth requests without a successful lsa handle
9344 or sec package id. */
9345 afsi_log("Reverting to NO SMB AUTH");
9346 smb_authType = SMB_AUTH_NONE;
9349 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9351 /* something went wrong. We report the error and revert back to no authentication
9352 because we can't perform any auth requests without a successful lsa handle
9353 or sec package id. */
9354 afsi_log("Reverting to NO SMB AUTH");
9355 smb_authType = SMB_AUTH_NONE;
9359 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9360 * time prevents the failure of authentication when logged into Windows with an
9361 * external Kerberos principal mapped to a local account.
9363 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9364 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9365 * then the only option is NTLMSSP anyway; so just fallback.
9370 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9371 if (secBlobLength == 0) {
9372 smb_authType = SMB_AUTH_NTLM;
9373 afsi_log("Reverting to SMB AUTH NTLM");
9382 /* Now get ourselves a domain name. */
9383 /* For now we are using the local computer name as the domain name.
9384 * It is actually the domain for local logins, and we are acting as
9385 * a local SMB server.
9387 bufsize = sizeof(smb_ServerDomainName) - 1;
9388 GetComputerName(smb_ServerDomainName, &bufsize);
9389 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9390 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
9393 /* Start listeners, waiters, servers, and daemons */
9395 smb_StartListeners();
9398 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9399 NULL, 0, &lpid, "smb_ClientWaiter");
9400 osi_assert(phandle != NULL);
9401 thrd_CloseHandle(phandle);
9404 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9405 NULL, 0, &lpid, "smb_ServerWaiter");
9406 osi_assert(phandle != NULL);
9407 thrd_CloseHandle(phandle);
9409 for (i=0; i<smb_NumServerThreads; i++) {
9410 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9411 (void *) i, 0, &lpid, "smb_Server");
9412 osi_assert(phandle != NULL);
9413 thrd_CloseHandle(phandle);
9416 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9417 NULL, 0, &lpid, "smb_Daemon");
9418 osi_assert(phandle != NULL);
9419 thrd_CloseHandle(phandle);
9421 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9422 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9423 osi_assert(phandle != NULL);
9424 thrd_CloseHandle(phandle);
9433 void smb_Shutdown(void)
9443 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9445 /* setup the NCB system */
9448 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
9451 /* Block new sessions by setting shutdown flag */
9452 smbShutdownFlag = 1;
9454 /* Hang up all sessions */
9455 memset((char *)ncbp, 0, sizeof(NCB));
9456 for (i = 1; i < numSessions; i++)
9458 if (dead_sessions[i])
9461 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9462 ncbp->ncb_command = NCBHANGUP;
9463 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9464 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9466 code = Netbios(ncbp);
9468 code = Netbios(ncbp, dos_ncb);
9470 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9471 if (code == 0) code = ncbp->ncb_retcode;
9473 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9474 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9478 /* Trigger the shutdown of all SMB threads */
9479 for (i = 0; i < smb_NumServerThreads; i++)
9480 thrd_SetEvent(NCBreturns[i][0]);
9482 thrd_SetEvent(NCBevents[0]);
9483 thrd_SetEvent(SessionEvents[0]);
9484 thrd_SetEvent(NCBavails[0]);
9486 for (i = 0;i < smb_NumServerThreads; i++) {
9487 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9488 if (code == WAIT_OBJECT_0) {
9491 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9492 thrd_SetEvent(NCBreturns[i--][0]);
9496 /* Delete Netbios name */
9497 memset((char *)ncbp, 0, sizeof(NCB));
9498 for (i = 0; i < lana_list.length; i++) {
9499 if (lana_list.lana[i] == 255) continue;
9500 ncbp->ncb_command = NCBDELNAME;
9501 ncbp->ncb_lana_num = lana_list.lana[i];
9502 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9504 code = Netbios(ncbp);
9506 code = Netbios(ncbp, dos_ncb);
9509 code = ncbp->ncb_retcode;
9511 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9512 ncbp->ncb_lana_num, code);
9517 /* Release the reference counts held by the VCs */
9518 lock_ObtainWrite(&smb_rctLock);
9519 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9524 if (vcp->magic != SMB_VC_MAGIC)
9525 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9526 __FILE__, __LINE__);
9528 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9530 if (fidp->scp != NULL) {
9533 lock_ObtainMutex(&fidp->mx);
9534 if (fidp->scp != NULL) {
9537 lock_ObtainMutex(&scp->mx);
9538 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9539 lock_ReleaseMutex(&scp->mx);
9540 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9541 cm_ReleaseSCache(scp);
9543 lock_ReleaseMutex(&fidp->mx);
9547 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9549 smb_ReleaseVCNoLock(tidp->vcp);
9551 cm_user_t *userp = tidp->userp;
9553 lock_ReleaseWrite(&smb_rctLock);
9554 cm_ReleaseUser(userp);
9555 lock_ObtainWrite(&smb_rctLock);
9559 lock_ReleaseWrite(&smb_rctLock);
9561 TlsFree(smb_TlsRequestSlot);
9564 /* Get the UNC \\<servername>\<sharename> prefix. */
9565 char *smb_GetSharename()
9569 /* Make sure we have been properly initialized. */
9570 if (smb_localNamep == NULL)
9573 /* Allocate space for \\<servername>\<sharename>, plus the
9576 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9577 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9583 void smb_LogPacket(smb_packet_t *packet)
9586 unsigned length, paramlen, datalen, i, j;
9588 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9590 if (!packet) return;
9592 osi_Log0(smb_logp, "*** SMB packet dump ***");
9594 vp = (BYTE *) packet->data;
9596 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9597 length = paramlen + 2 + datalen;
9600 for (i=0;i < length; i+=16)
9602 memset( buf, ' ', 80 );
9607 buf[strlen(buf)] = ' ';
9609 cp = (BYTE*) buf + 7;
9611 for (j=0;j < 16 && (i+j)<length; j++)
9613 *(cp++) = hex[vp[i+j] >> 4];
9614 *(cp++) = hex[vp[i+j] & 0xf];
9624 for (j=0;j < 16 && (i+j)<length;j++)
9626 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9637 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9640 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9642 #endif /* LOG_PACKET */
9645 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9653 lock_ObtainRead(&smb_rctLock);
9655 sprintf(output, "begin dumping smb_vc_t\r\n");
9656 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9658 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9662 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9663 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9664 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9666 sprintf(output, "begin dumping smb_fid_t\r\n");
9667 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9669 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9671 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",
9672 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9673 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9674 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9675 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9678 sprintf(output, "done dumping smb_fid_t\r\n");
9679 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9682 sprintf(output, "done dumping smb_vc_t\r\n");
9683 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9685 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9686 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9688 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9692 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9693 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9694 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9696 sprintf(output, "begin dumping smb_fid_t\r\n");
9697 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9699 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9701 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",
9702 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9703 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9704 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9705 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9708 sprintf(output, "done dumping smb_fid_t\r\n");
9709 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9712 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9713 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9716 lock_ReleaseRead(&smb_rctLock);
9720 long smb_IsNetworkStarted(void)
9722 return (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);