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_assertx(diff_t < _UI32_MAX, "time_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 = NULL;
940 ULONG lsaRespSize = 0;
942 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
944 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
951 if (nts != STATUS_SUCCESS || ntsEx != 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 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
955 nts, ntsEx, lsaRespSize);
957 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
959 if (ntsEx == STATUS_SUCCESS) {
960 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
961 LsaFreeReturnBuffer(lsaResp);
964 * This will cause the subsequent authentication to fail but
965 * that is better than us dereferencing a NULL pointer and
968 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
972 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
974 if (numVCs >= CM_SESSION_RESERVED) {
976 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
979 lock_ReleaseWrite(&smb_rctLock);
980 lock_ReleaseWrite(&smb_globalLock);
984 int smb_IsStarMask(char *maskp)
989 for(i=0; i<11; i++) {
991 if (tc == '?' || tc == '*' || tc == '>')
997 void smb_ReleaseVCInternal(smb_vc_t *vcp)
1004 if (vcp->refCount == 0) {
1005 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
1006 /* remove VCP from smb_deadVCsp */
1007 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1013 lock_FinalizeMutex(&vcp->mx);
1014 memset(vcp,0,sizeof(smb_vc_t));
1017 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
1021 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
1022 avcp?"not ":"",vcp, vcp->refCount);
1024 GenerateMiniDump(NULL);
1026 /* This is a wrong. However, I suspect that there is an undercount
1027 * and I don't want to release 1.4.1 in a state that will allow
1028 * smb_vc_t objects to be deallocated while still in the
1029 * smb_allVCsp list. The list is supposed to keep a reference
1030 * to the smb_vc_t. Put it back.
1037 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1039 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1040 smb_ReleaseVCInternal(vcp);
1043 void smb_ReleaseVC(smb_vc_t *vcp)
1045 lock_ObtainWrite(&smb_rctLock);
1046 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
1047 smb_ReleaseVCInternal(vcp);
1048 lock_ReleaseWrite(&smb_rctLock);
1051 void smb_HoldVCNoLock(smb_vc_t *vcp)
1054 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1057 void smb_HoldVC(smb_vc_t *vcp)
1059 lock_ObtainWrite(&smb_rctLock);
1061 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
1062 lock_ReleaseWrite(&smb_rctLock);
1065 void smb_CleanupDeadVC(smb_vc_t *vcp)
1067 smb_fid_t *fidpIter;
1068 smb_fid_t *fidpNext;
1070 smb_tid_t *tidpIter;
1071 smb_tid_t *tidpNext;
1073 smb_user_t *uidpIter;
1074 smb_user_t *uidpNext;
1078 lock_ObtainMutex(&vcp->mx);
1079 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1080 lock_ReleaseMutex(&vcp->mx);
1081 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1084 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1085 lock_ReleaseMutex(&vcp->mx);
1086 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1088 lock_ObtainWrite(&smb_rctLock);
1089 /* remove VCP from smb_allVCsp */
1090 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1091 if ((*vcpp)->magic != SMB_VC_MAGIC)
1092 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1093 __FILE__, __LINE__);
1096 vcp->nextp = smb_deadVCsp;
1098 /* Hold onto the reference until we are done with this function */
1103 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1104 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1106 if (fidpIter->delete)
1109 fid = fidpIter->fid;
1110 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1112 smb_HoldFIDNoLock(fidpIter);
1113 lock_ReleaseWrite(&smb_rctLock);
1115 smb_CloseFID(vcp, fidpIter, NULL, 0);
1116 smb_ReleaseFID(fidpIter);
1118 lock_ObtainWrite(&smb_rctLock);
1119 fidpNext = vcp->fidsp;
1122 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1123 tidpNext = tidpIter->nextp;
1124 if (tidpIter->delete)
1126 tidpIter->delete = 1;
1128 tid = tidpIter->tid;
1129 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1131 smb_HoldTIDNoLock(tidpIter);
1132 lock_ReleaseWrite(&smb_rctLock);
1134 smb_ReleaseTID(tidpIter);
1136 lock_ObtainWrite(&smb_rctLock);
1137 tidpNext = vcp->tidsp;
1140 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1141 uidpNext = uidpIter->nextp;
1142 if (uidpIter->delete)
1144 uidpIter->delete = 1;
1146 /* do not add an additional reference count for the smb_user_t
1147 * as the smb_vc_t already is holding a reference */
1148 lock_ReleaseWrite(&smb_rctLock);
1150 smb_ReleaseUID(uidpIter);
1152 lock_ObtainWrite(&smb_rctLock);
1153 uidpNext = vcp->usersp;
1156 /* The vcp is now on the deadVCsp list. We intentionally drop the
1157 * reference so that the refcount can reach 0 and we can delete it */
1158 smb_ReleaseVCNoLock(vcp);
1160 lock_ReleaseWrite(&smb_rctLock);
1161 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1164 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1168 lock_ObtainWrite(&smb_rctLock);
1170 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1171 if (tidp->refCount == 0 && tidp->delete) {
1173 lock_ReleaseWrite(&smb_rctLock);
1174 smb_ReleaseTID(tidp);
1175 lock_ObtainWrite(&smb_rctLock);
1179 if (tid == tidp->tid) {
1184 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1185 tidp = malloc(sizeof(*tidp));
1186 memset(tidp, 0, sizeof(*tidp));
1187 tidp->nextp = vcp->tidsp;
1190 smb_HoldVCNoLock(vcp);
1192 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1195 lock_ReleaseWrite(&smb_rctLock);
1199 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1204 void smb_ReleaseTID(smb_tid_t *tidp)
1211 lock_ObtainWrite(&smb_rctLock);
1212 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1213 if (tidp->refCount == 0 && (tidp->delete)) {
1214 ltpp = &tidp->vcp->tidsp;
1215 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1219 osi_assertx(tp != NULL, "null smb_tid_t");
1221 lock_FinalizeMutex(&tidp->mx);
1222 userp = tidp->userp; /* remember to drop ref later */
1224 smb_ReleaseVCNoLock(tidp->vcp);
1227 lock_ReleaseWrite(&smb_rctLock);
1229 cm_ReleaseUser(userp);
1232 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1234 smb_user_t *uidp = NULL;
1236 lock_ObtainWrite(&smb_rctLock);
1237 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1238 if (uid == uidp->userID) {
1240 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1242 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1246 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1247 uidp = malloc(sizeof(*uidp));
1248 memset(uidp, 0, sizeof(*uidp));
1249 uidp->nextp = vcp->usersp;
1250 uidp->refCount = 2; /* one for the vcp and one for the caller */
1252 smb_HoldVCNoLock(vcp);
1254 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1256 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1258 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1260 lock_ReleaseWrite(&smb_rctLock);
1264 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1266 smb_username_t *unp= NULL;
1268 lock_ObtainWrite(&smb_rctLock);
1269 for(unp = usernamesp; unp; unp = unp->nextp) {
1270 if (stricmp(unp->name, usern) == 0 &&
1271 stricmp(unp->machine, machine) == 0) {
1276 if (!unp && (flags & SMB_FLAG_CREATE)) {
1277 unp = malloc(sizeof(*unp));
1278 memset(unp, 0, sizeof(*unp));
1280 unp->nextp = usernamesp;
1281 unp->name = strdup(usern);
1282 unp->machine = strdup(machine);
1284 lock_InitializeMutex(&unp->mx, "username_t mutex");
1285 if (flags & SMB_FLAG_AFSLOGON)
1286 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1289 lock_ReleaseWrite(&smb_rctLock);
1293 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1295 smb_user_t *uidp= NULL;
1297 lock_ObtainWrite(&smb_rctLock);
1298 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1301 if (stricmp(uidp->unp->name, usern) == 0) {
1303 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1304 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1309 lock_ReleaseWrite(&smb_rctLock);
1313 void smb_ReleaseUsername(smb_username_t *unp)
1316 smb_username_t **lupp;
1317 cm_user_t *userp = NULL;
1318 time_t now = osi_Time();
1320 lock_ObtainWrite(&smb_rctLock);
1321 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1322 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1323 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1325 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1329 osi_assertx(up != NULL, "null smb_username_t");
1331 up->nextp = NULL; /* do not remove this */
1332 lock_FinalizeMutex(&unp->mx);
1338 lock_ReleaseWrite(&smb_rctLock);
1341 cm_ReleaseUser(userp);
1345 void smb_HoldUIDNoLock(smb_user_t *uidp)
1350 void smb_ReleaseUID(smb_user_t *uidp)
1354 smb_username_t *unp = NULL;
1356 lock_ObtainWrite(&smb_rctLock);
1357 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1358 if (uidp->refCount == 0) {
1359 lupp = &uidp->vcp->usersp;
1360 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1364 osi_assertx(up != NULL, "null smb_user_t");
1366 lock_FinalizeMutex(&uidp->mx);
1368 smb_ReleaseVCNoLock(uidp->vcp);
1372 lock_ReleaseWrite(&smb_rctLock);
1376 cm_ReleaseUserVCRef(unp->userp);
1377 smb_ReleaseUsername(unp);
1381 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1383 cm_user_t *up = NULL;
1388 lock_ObtainMutex(&uidp->mx);
1390 up = uidp->unp->userp;
1393 lock_ReleaseMutex(&uidp->mx);
1399 /* retrieve a held reference to a user structure corresponding to an incoming
1401 * corresponding release function is cm_ReleaseUser.
1403 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1406 cm_user_t *up = NULL;
1409 smbp = (smb_t *) inp;
1410 uidp = smb_FindUID(vcp, smbp->uid, 0);
1414 up = smb_GetUserFromUID(uidp);
1416 smb_ReleaseUID(uidp);
1421 * Return a pointer to a pathname extracted from a TID structure. The
1422 * TID structure is not held; assume it won't go away.
1424 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1429 tidp = smb_FindTID(vcp, tid, 0);
1433 if (tidp->flags & SMB_TIDFLAG_IPC) {
1434 code = CM_ERROR_TIDIPC;
1435 /* tidp->pathname would be NULL, but that's fine */
1437 *treepath = tidp->pathname;
1438 smb_ReleaseTID(tidp);
1443 /* check to see if we have a chained fid, that is, a fid that comes from an
1444 * OpenAndX message that ran earlier in this packet. In this case, the fid
1445 * field in a read, for example, request, isn't set, since the value is
1446 * supposed to be inherited from the openAndX call.
1448 int smb_ChainFID(int fid, smb_packet_t *inp)
1450 if (inp->fid == 0 || inp->inCount == 0)
1456 /* are we a priv'd user? What does this mean on NT? */
1457 int smb_SUser(cm_user_t *userp)
1462 /* find a file ID. If we pass in 0 we select an unused File ID.
1463 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1464 * smb_fid_t data structure if desired File ID cannot be found.
1466 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1471 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1474 lock_ObtainWrite(&smb_rctLock);
1475 /* figure out if we need to allocate a new file ID */
1478 fid = vcp->fidCounter;
1482 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1483 if (fidp->refCount == 0 && fidp->delete) {
1485 lock_ReleaseWrite(&smb_rctLock);
1486 smb_ReleaseFID(fidp);
1487 lock_ObtainWrite(&smb_rctLock);
1490 if (fid == fidp->fid) {
1493 if (fid == 0xFFFF) {
1495 "New FID number wraps on vcp 0x%x", vcp);
1505 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1506 char eventName[MAX_PATH];
1508 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1509 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1510 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1511 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1512 thrd_CloseHandle(event);
1514 if (fid == 0xFFFF) {
1515 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1521 fidp = malloc(sizeof(*fidp));
1522 memset(fidp, 0, sizeof(*fidp));
1523 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1526 smb_HoldVCNoLock(vcp);
1527 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1529 fidp->curr_chunk = fidp->prev_chunk = -2;
1530 fidp->raw_write_event = event;
1532 vcp->fidCounter = fid+1;
1533 if (vcp->fidCounter == 0xFFFF) {
1534 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1536 vcp->fidCounter = 1;
1541 lock_ReleaseWrite(&smb_rctLock);
1545 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1547 smb_fid_t *fidp = NULL;
1553 lock_ObtainWrite(&smb_rctLock);
1554 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1555 if (scp == fidp->scp) {
1560 lock_ReleaseWrite(&smb_rctLock);
1564 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1570 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1571 /* the sm_fid_t->mx and smb_rctLock must not be held */
1572 void smb_ReleaseFID(smb_fid_t *fidp)
1574 cm_scache_t *scp = NULL;
1575 cm_user_t *userp = NULL;
1576 smb_vc_t *vcp = NULL;
1577 smb_ioctl_t *ioctlp;
1579 lock_ObtainMutex(&fidp->mx);
1580 lock_ObtainWrite(&smb_rctLock);
1581 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1582 if (fidp->refCount == 0 && (fidp->delete)) {
1585 scp = fidp->scp; /* release after lock is released */
1587 lock_ObtainMutex(&scp->mx);
1588 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1589 lock_ReleaseMutex(&scp->mx);
1590 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1593 userp = fidp->userp;
1597 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1598 thrd_CloseHandle(fidp->raw_write_event);
1600 /* and see if there is ioctl stuff to free */
1601 ioctlp = fidp->ioctlp;
1604 cm_FreeSpace(ioctlp->prefix);
1605 if (ioctlp->inAllocp)
1606 free(ioctlp->inAllocp);
1607 if (ioctlp->outAllocp)
1608 free(ioctlp->outAllocp);
1611 lock_ReleaseMutex(&fidp->mx);
1612 lock_FinalizeMutex(&fidp->mx);
1616 smb_ReleaseVCNoLock(vcp);
1618 lock_ReleaseMutex(&fidp->mx);
1620 lock_ReleaseWrite(&smb_rctLock);
1622 /* now release the scache structure */
1624 cm_ReleaseSCache(scp);
1627 cm_ReleaseUser(userp);
1631 * Case-insensitive search for one string in another;
1632 * used to find variable names in submount pathnames.
1634 static char *smb_stristr(char *str1, char *str2)
1638 for (cursor = str1; *cursor; cursor++)
1639 if (stricmp(cursor, str2) == 0)
1646 * Substitute a variable value for its name in a submount pathname. Variable
1647 * name has been identified by smb_stristr() and is in substr. Variable name
1648 * length (plus one) is in substr_size. Variable value is in newstr.
1650 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1655 strcpy(temp, substr + substr_size - 1);
1656 strcpy(substr, newstr);
1660 char VNUserName[] = "%USERNAME%";
1661 char VNLCUserName[] = "%LCUSERNAME%";
1662 char VNComputerName[] = "%COMPUTERNAME%";
1663 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1666 /* List available shares */
1667 int smb_ListShares()
1669 char sbmtpath[AFSPATHMAX];
1670 char pathName[AFSPATHMAX];
1671 char shareBuf[4096];
1679 /*strcpy(shareNameList[num_shares], "all");
1680 strcpy(pathNameList[num_shares++], "/afs");*/
1681 fprintf(stderr, "The following shares are available:\n");
1682 fprintf(stderr, "Share Name (AFS Path)\n");
1683 fprintf(stderr, "---------------------\n");
1684 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1687 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1688 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1690 strcpy(sbmtpath, cm_confDir);
1692 strcat(sbmtpath, "/afsdsbmt.ini");
1693 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1694 shareBuf, sizeof(shareBuf),
1700 this_share = shareBuf;
1704 /*strcpy(shareNameList[num_shares], this_share);*/
1705 len = GetPrivateProfileString("AFS Submounts", this_share,
1707 pathName, AFSPATHMAX,
1712 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1715 if (*p == '\\') *p = '/'; /* change to / */
1719 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1720 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1723 while (*this_share != 0) this_share++; /* find next NUL */
1724 this_share++; /* skip past the NUL */
1725 } while (*this_share != 0); /* stop at final NUL */
1731 typedef struct smb_findShare_rock {
1735 } smb_findShare_rock_t;
1737 #define SMB_FINDSHARE_EXACT_MATCH 1
1738 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1740 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1744 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1745 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1746 if(!stricmp(dep->name, vrock->shareName))
1747 matchType = SMB_FINDSHARE_EXACT_MATCH;
1749 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1750 if(vrock->match) free(vrock->match);
1751 vrock->match = strdup(dep->name);
1752 vrock->matchType = matchType;
1754 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1755 return CM_ERROR_STOPNOW;
1761 /* find a shareName in the table of submounts */
1762 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1766 char pathName[1024];
1771 char sbmtpath[MAX_PATH];
1776 DWORD allSubmount = 1;
1778 /* if allSubmounts == 0, only return the //mountRoot/all share
1779 * if in fact it has been been created in the subMounts table.
1780 * This is to allow sites that want to restrict access to the
1783 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1784 0, KEY_QUERY_VALUE, &parmKey);
1785 if (code == ERROR_SUCCESS) {
1786 len = sizeof(allSubmount);
1787 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1788 (BYTE *) &allSubmount, &len);
1789 if (code != ERROR_SUCCESS) {
1792 RegCloseKey (parmKey);
1795 if (allSubmount && _stricmp(shareName, "all") == 0) {
1800 /* In case, the all share is disabled we need to still be able
1801 * to handle ioctl requests
1803 if (_stricmp(shareName, "ioctl$") == 0) {
1804 *pathNamep = strdup("/.__ioctl__");
1808 if (_stricmp(shareName, "IPC$") == 0 ||
1809 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1810 _stricmp(shareName, "DESKTOP.INI") == 0
1816 /* Check for volume references
1818 They look like <cell>{%,#}<volume>
1820 if (strchr(shareName, '%') != NULL ||
1821 strchr(shareName, '#') != NULL) {
1822 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1823 /* make room for '/@vol:' + mountchar + NULL terminator*/
1825 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1826 osi_LogSaveString(smb_logp, shareName));
1828 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1829 "/" CM_PREFIX_VOL "%s", shareName);
1830 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1831 len = strlen(pathstr) + 1;
1833 *pathNamep = malloc(len);
1835 strcpy(*pathNamep, pathstr);
1837 osi_Log1(smb_logp, " returning pathname [%s]",
1838 osi_LogSaveString(smb_logp, *pathNamep));
1847 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1848 0, KEY_QUERY_VALUE, &parmKey);
1849 if (code == ERROR_SUCCESS) {
1850 len = sizeof(pathName);
1851 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1852 (BYTE *) pathName, &len);
1853 if (code != ERROR_SUCCESS)
1855 RegCloseKey (parmKey);
1860 strcpy(sbmtpath, cm_confDir);
1861 strcat(sbmtpath, "/afsdsbmt.ini");
1862 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1863 pathName, sizeof(pathName), sbmtpath);
1865 if (len != 0 && len != sizeof(pathName) - 1) {
1866 /* We can accept either unix or PC style AFS pathnames. Convert
1867 * Unix-style to PC style here for internal use.
1870 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1871 p += strlen(cm_mountRoot); /* skip mount path */
1874 if (*q == '/') *q = '\\'; /* change to \ */
1880 if (var = smb_stristr(p, VNUserName)) {
1881 if (uidp && uidp->unp)
1882 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1884 smb_subst(p, var, sizeof(VNUserName)," ");
1886 else if (var = smb_stristr(p, VNLCUserName))
1888 if (uidp && uidp->unp)
1889 strcpy(temp, uidp->unp->name);
1893 smb_subst(p, var, sizeof(VNLCUserName), temp);
1895 else if (var = smb_stristr(p, VNComputerName))
1897 sizeTemp = sizeof(temp);
1898 GetComputerName((LPTSTR)temp, &sizeTemp);
1899 smb_subst(p, var, sizeof(VNComputerName), temp);
1901 else if (var = smb_stristr(p, VNLCComputerName))
1903 sizeTemp = sizeof(temp);
1904 GetComputerName((LPTSTR)temp, &sizeTemp);
1906 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1911 *pathNamep = strdup(p);
1916 /* First lookup shareName in root.afs */
1918 smb_findShare_rock_t vrock;
1920 char * p = shareName;
1923 /* attempt to locate a partial match in root.afs. This is because
1924 when using the ANSI RAP calls, the share name is limited to 13 chars
1925 and hence is truncated. Of course we prefer exact matches. */
1927 thyper.HighPart = 0;
1930 vrock.shareName = shareName;
1932 vrock.matchType = 0;
1934 cm_HoldSCache(cm_data.rootSCachep);
1935 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1936 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1937 cm_ReleaseSCache(cm_data.rootSCachep);
1939 if (vrock.matchType) {
1940 sprintf(pathName,"/%s/",vrock.match);
1941 *pathNamep = strdup(strlwr(pathName));
1946 /* if we get here, there was no match for the share in root.afs */
1947 /* so try to create \\<netbiosName>\<cellname> */
1952 /* Get the full name for this cell */
1953 code = cm_SearchCellFile(p, temp, 0, 0);
1954 #ifdef AFS_AFSDB_ENV
1955 if (code && cm_dnsEnabled) {
1957 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1960 /* construct the path */
1962 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1963 *pathNamep = strdup(strlwr(pathName));
1972 /* Client-side offline caching policy types */
1973 #define CSC_POLICY_MANUAL 0
1974 #define CSC_POLICY_DOCUMENTS 1
1975 #define CSC_POLICY_PROGRAMS 2
1976 #define CSC_POLICY_DISABLE 3
1978 int smb_FindShareCSCPolicy(char *shareName)
1984 int retval = CSC_POLICY_MANUAL;
1986 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1987 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1990 REG_OPTION_NON_VOLATILE,
1996 len = sizeof(policy);
1997 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1999 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2001 else if (stricmp(policy, "documents") == 0)
2003 retval = CSC_POLICY_DOCUMENTS;
2005 else if (stricmp(policy, "programs") == 0)
2007 retval = CSC_POLICY_PROGRAMS;
2009 else if (stricmp(policy, "disable") == 0)
2011 retval = CSC_POLICY_DISABLE;
2014 RegCloseKey(hkCSCPolicy);
2018 /* find a dir search structure by cookie value, and return it held.
2019 * Must be called with smb_globalLock held.
2021 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2023 smb_dirSearch_t *dsp;
2025 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2026 if (dsp->cookie == cookie) {
2027 if (dsp != smb_firstDirSearchp) {
2028 /* move to head of LRU queue, too, if we're not already there */
2029 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2030 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2031 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2032 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2033 if (!smb_lastDirSearchp)
2034 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2036 lock_ObtainMutex(&dsp->mx);
2038 lock_ReleaseMutex(&dsp->mx);
2044 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2045 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2046 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2052 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2054 lock_ObtainWrite(&smb_globalLock);
2055 lock_ObtainMutex(&dsp->mx);
2056 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2057 dsp->cookie, dsp, dsp->scp);
2058 dsp->flags |= SMB_DIRSEARCH_DELETE;
2059 if (dsp->scp != NULL) {
2060 lock_ObtainMutex(&dsp->scp->mx);
2061 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2062 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2063 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2064 dsp->scp->bulkStatProgress = hzero;
2066 lock_ReleaseMutex(&dsp->scp->mx);
2068 lock_ReleaseMutex(&dsp->mx);
2069 lock_ReleaseWrite(&smb_globalLock);
2072 /* Must be called with the smb_globalLock held */
2073 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2075 cm_scache_t *scp = NULL;
2077 lock_ObtainMutex(&dsp->mx);
2078 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2079 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
2080 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2081 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2082 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2083 lock_ReleaseMutex(&dsp->mx);
2084 lock_FinalizeMutex(&dsp->mx);
2086 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2087 dsp->cookie, dsp, scp);
2090 lock_ReleaseMutex(&dsp->mx);
2092 /* do this now to avoid spurious locking hierarchy creation */
2094 cm_ReleaseSCache(scp);
2097 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2099 lock_ObtainWrite(&smb_globalLock);
2100 smb_ReleaseDirSearchNoLock(dsp);
2101 lock_ReleaseWrite(&smb_globalLock);
2104 /* find a dir search structure by cookie value, and return it held */
2105 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2107 smb_dirSearch_t *dsp;
2109 lock_ObtainWrite(&smb_globalLock);
2110 dsp = smb_FindDirSearchNoLock(cookie);
2111 lock_ReleaseWrite(&smb_globalLock);
2115 /* GC some dir search entries, in the address space expected by the specific protocol.
2116 * Must be called with smb_globalLock held; release the lock temporarily.
2118 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2119 void smb_GCDirSearches(int isV3)
2121 smb_dirSearch_t *prevp;
2122 smb_dirSearch_t *tp;
2123 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2127 victimCount = 0; /* how many have we got so far */
2128 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
2129 /* we'll move tp from queue, so
2132 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
2133 /* if no one is using this guy, and we're either in the new protocol,
2134 * or we're in the old one and this is a small enough ID to be useful
2135 * to the old protocol, GC this guy.
2137 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
2138 /* hold and delete */
2139 lock_ObtainMutex(&tp->mx);
2140 tp->flags |= SMB_DIRSEARCH_DELETE;
2141 lock_ReleaseMutex(&tp->mx);
2142 victimsp[victimCount++] = tp;
2146 /* don't do more than this */
2147 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2151 /* now release them */
2152 for (i = 0; i < victimCount; i++) {
2153 smb_ReleaseDirSearchNoLock(victimsp[i]);
2157 /* function for allocating a dir search entry. We need these to remember enough context
2158 * since we don't get passed the path from call to call during a directory search.
2160 * Returns a held dir search structure, and bumps the reference count on the vnode,
2161 * since it saves a pointer to the vnode.
2163 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2165 smb_dirSearch_t *dsp;
2171 lock_ObtainWrite(&smb_globalLock);
2174 /* what's the biggest ID allowed in this version of the protocol */
2175 /* TODO: do we really want a non v3 dir search request to wrap
2176 smb_dirSearchCounter? */
2177 maxAllowed = isV3 ? 65535 : 255;
2178 if (smb_dirSearchCounter > maxAllowed)
2179 smb_dirSearchCounter = 1;
2181 start = smb_dirSearchCounter;
2184 /* twice so we have enough tries to find guys we GC after one pass;
2185 * 10 extra is just in case I mis-counted.
2187 if (++counter > 2*maxAllowed+10)
2188 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2190 if (smb_dirSearchCounter > maxAllowed) {
2191 smb_dirSearchCounter = 1;
2193 if (smb_dirSearchCounter == start) {
2195 smb_GCDirSearches(isV3);
2198 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2200 /* don't need to watch for refcount zero and deleted, since
2201 * we haven't dropped the global lock.
2203 lock_ObtainMutex(&dsp->mx);
2205 lock_ReleaseMutex(&dsp->mx);
2206 ++smb_dirSearchCounter;
2210 dsp = malloc(sizeof(*dsp));
2211 memset(dsp, 0, sizeof(*dsp));
2212 dsp->cookie = smb_dirSearchCounter;
2213 ++smb_dirSearchCounter;
2215 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2216 dsp->lastTime = osi_Time();
2217 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2218 if (!smb_lastDirSearchp)
2219 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2221 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2225 lock_ReleaseWrite(&smb_globalLock);
2229 static smb_packet_t *GetPacket(void)
2233 unsigned int npar, seg, tb_sel;
2236 lock_ObtainWrite(&smb_globalLock);
2237 tbp = smb_packetFreeListp;
2239 smb_packetFreeListp = tbp->nextp;
2240 lock_ReleaseWrite(&smb_globalLock);
2243 tbp = calloc(65540,1);
2245 tbp = malloc(sizeof(smb_packet_t));
2247 tbp->magic = SMB_PACKETMAGIC;
2250 tbp->resumeCode = 0;
2256 tbp->ncb_length = 0;
2261 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
2264 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2266 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
2268 osi_panic("",__FILE__,__LINE__);
2271 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
2276 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
2277 tbp->dos_pkt_sel = tb_sel;
2280 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2285 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2289 memcpy(tbp, pkt, sizeof(smb_packet_t));
2290 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2292 smb_HoldVC(tbp->vcp);
2296 static NCB *GetNCB(void)
2301 unsigned int npar, seg, tb_sel;
2304 lock_ObtainWrite(&smb_globalLock);
2305 tbp = smb_ncbFreeListp;
2307 smb_ncbFreeListp = tbp->nextp;
2308 lock_ReleaseWrite(&smb_globalLock);
2311 tbp = calloc(sizeof(*tbp),1);
2313 tbp = malloc(sizeof(*tbp));
2314 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
2317 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2319 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2321 osi_panic("",__FILE__,__LINE__);
2323 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2328 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
2329 tbp->dos_ncb_sel = tb_sel;
2331 tbp->magic = SMB_NCBMAGIC;
2334 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2336 memset(&tbp->ncb, 0, sizeof(NCB));
2339 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2344 void smb_FreePacket(smb_packet_t *tbp)
2346 smb_vc_t * vcp = NULL;
2347 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2349 lock_ObtainWrite(&smb_globalLock);
2350 tbp->nextp = smb_packetFreeListp;
2351 smb_packetFreeListp = tbp;
2352 tbp->magic = SMB_PACKETMAGIC;
2356 tbp->resumeCode = 0;
2362 tbp->ncb_length = 0;
2364 lock_ReleaseWrite(&smb_globalLock);
2370 static void FreeNCB(NCB *bufferp)
2374 tbp = (smb_ncb_t *) bufferp;
2375 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2377 lock_ObtainWrite(&smb_globalLock);
2378 tbp->nextp = smb_ncbFreeListp;
2379 smb_ncbFreeListp = tbp;
2380 lock_ReleaseWrite(&smb_globalLock);
2383 /* get a ptr to the data part of a packet, and its count */
2384 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2388 unsigned char *afterParmsp;
2390 parmBytes = *smbp->wctp << 1;
2391 afterParmsp = smbp->wctp + parmBytes + 1;
2393 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2394 if (nbytesp) *nbytesp = dataBytes;
2396 /* don't forget to skip the data byte count, since it follows
2397 * the parameters; that's where the "2" comes from below.
2399 return (unsigned char *) (afterParmsp + 2);
2402 /* must set all the returned parameters before playing around with the
2403 * data region, since the data region is located past the end of the
2404 * variable number of parameters.
2406 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2408 unsigned char *afterParmsp;
2410 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2412 *afterParmsp++ = dsize & 0xff;
2413 *afterParmsp = (dsize>>8) & 0xff;
2416 /* return the parm'th parameter in the smbp packet */
2417 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2420 unsigned char *parmDatap;
2422 parmCount = *smbp->wctp;
2424 if (parm >= parmCount) {
2427 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2428 parm, parmCount, smbp->ncb_length);
2429 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2430 parm, parmCount, smbp->ncb_length);
2432 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2433 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2435 osi_panic(s, __FILE__, __LINE__);
2437 parmDatap = smbp->wctp + (2*parm) + 1;
2439 return parmDatap[0] + (parmDatap[1] << 8);
2442 /* return the parm'th parameter in the smbp packet */
2443 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2446 unsigned char *parmDatap;
2448 parmCount = *smbp->wctp;
2450 if (parm >= parmCount) {
2453 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2454 parm, parmCount, smbp->ncb_length);
2455 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2456 parm, parmCount, smbp->ncb_length);
2457 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2458 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2459 osi_panic(s, __FILE__, __LINE__);
2461 parmDatap = smbp->wctp + (2*parm) + 1;
2463 return parmDatap[0];
2466 /* return the parm'th parameter in the smbp packet */
2467 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2470 unsigned char *parmDatap;
2472 parmCount = *smbp->wctp;
2474 if (parm + 1 >= parmCount) {
2477 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2478 parm, parmCount, smbp->ncb_length);
2479 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2480 parm, parmCount, smbp->ncb_length);
2482 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2483 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2485 osi_panic(s, __FILE__, __LINE__);
2487 parmDatap = smbp->wctp + (2*parm) + 1;
2489 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2492 /* return the parm'th parameter in the smbp packet */
2493 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2496 unsigned char *parmDatap;
2498 parmCount = *smbp->wctp;
2500 if (parm * 2 + offset >= parmCount * 2) {
2503 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2504 parm, offset, parmCount, smbp->ncb_length);
2506 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2507 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2509 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2510 parm, offset, parmCount, smbp->ncb_length);
2511 osi_panic(s, __FILE__, __LINE__);
2513 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2515 return parmDatap[0] + (parmDatap[1] << 8);
2518 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2522 /* make sure we have enough slots */
2523 if (*smbp->wctp <= slot)
2524 *smbp->wctp = slot+1;
2526 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2527 *parmDatap++ = parmValue & 0xff;
2528 *parmDatap = (parmValue>>8) & 0xff;
2531 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2535 /* make sure we have enough slots */
2536 if (*smbp->wctp <= slot)
2537 *smbp->wctp = slot+2;
2539 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2540 *parmDatap++ = parmValue & 0xff;
2541 *parmDatap++ = (parmValue>>8) & 0xff;
2542 *parmDatap++ = (parmValue>>16) & 0xff;
2543 *parmDatap = (parmValue>>24) & 0xff;
2546 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2551 /* make sure we have enough slots */
2552 if (*smbp->wctp <= slot)
2553 *smbp->wctp = slot+4;
2555 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2557 *parmDatap++ = *parmValuep++;
2560 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2564 /* make sure we have enough slots */
2565 if (*smbp->wctp <= slot) {
2566 if (smbp->oddByte) {
2568 *smbp->wctp = slot+1;
2573 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2574 *parmDatap++ = parmValue & 0xff;
2577 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2581 lastSlashp = strrchr(inPathp, '\\');
2583 *lastComponentp = lastSlashp;
2586 if (inPathp == lastSlashp)
2588 *outPathp++ = *inPathp++;
2597 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2602 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2607 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2613 tlen = inp[0] + (inp[1]<<8);
2614 inp += 2; /* skip length field */
2617 *chainpp = inp + tlen;
2626 /* format a packet as a response */
2627 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2632 outp = (smb_t *) op;
2634 /* zero the basic structure through the smb_wct field, and zero the data
2635 * size field, assuming that wct stays zero; otherwise, you have to
2636 * explicitly set the data size field, too.
2638 inSmbp = (smb_t *) inp;
2639 memset(outp, 0, sizeof(smb_t)+2);
2645 outp->com = inSmbp->com;
2646 outp->tid = inSmbp->tid;
2647 outp->pid = inSmbp->pid;
2648 outp->uid = inSmbp->uid;
2649 outp->mid = inSmbp->mid;
2650 outp->res[0] = inSmbp->res[0];
2651 outp->res[1] = inSmbp->res[1];
2652 op->inCom = inSmbp->com;
2654 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2655 #ifdef SEND_CANONICAL_PATHNAMES
2656 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2658 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2660 /* copy fields in generic packet area */
2661 op->wctp = &outp->wct;
2664 /* send a (probably response) packet; vcp tells us to whom to send it.
2665 * we compute the length by looking at wct and bcc fields.
2667 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2684 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2687 memset((char *)ncbp, 0, sizeof(NCB));
2689 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2690 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2691 extra += tp[0] + (tp[1]<<8);
2692 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2693 extra += 3; /* wct and length fields */
2695 ncbp->ncb_length = extra; /* bytes to send */
2696 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2697 ncbp->ncb_lana_num = vcp->lana;
2698 ncbp->ncb_command = NCBSEND; /* op means send data */
2700 ncbp->ncb_buffer = (char *) inp;/* packet */
2701 code = Netbios(ncbp);
2703 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2704 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2706 /* copy header information from virtual to DOS address space */
2707 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2708 code = Netbios(ncbp, dos_ncb);
2712 const char * s = ncb_error_string(code);
2713 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2715 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2718 lock_ObtainMutex(&vcp->mx);
2719 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2720 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2722 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2723 lock_ReleaseMutex(&vcp->mx);
2724 lock_ObtainWrite(&smb_globalLock);
2725 dead_sessions[vcp->session] = TRUE;
2726 lock_ReleaseWrite(&smb_globalLock);
2727 smb_CleanupDeadVC(vcp);
2729 lock_ReleaseMutex(&vcp->mx);
2737 void smb_MapNTError(long code, unsigned long *NTStatusp)
2739 unsigned long NTStatus;
2741 /* map CM_ERROR_* errors to NT 32-bit status codes */
2742 /* NT Status codes are listed in ntstatus.h not winerror.h */
2743 if (code == CM_ERROR_NOSUCHCELL) {
2744 NTStatus = 0xC000000FL; /* No such file */
2746 else if (code == CM_ERROR_NOSUCHVOLUME) {
2747 NTStatus = 0xC000000FL; /* No such file */
2749 else if (code == CM_ERROR_TIMEDOUT) {
2751 NTStatus = 0xC00000CFL; /* Sharing Paused */
2753 NTStatus = 0x00000102L; /* Timeout */
2756 else if (code == CM_ERROR_RETRY) {
2757 NTStatus = 0xC000022DL; /* Retry */
2759 else if (code == CM_ERROR_NOACCESS) {
2760 NTStatus = 0xC0000022L; /* Access denied */
2762 else if (code == CM_ERROR_READONLY) {
2763 NTStatus = 0xC00000A2L; /* Write protected */
2765 else if (code == CM_ERROR_NOSUCHFILE ||
2766 code == CM_ERROR_BPLUS_NOMATCH) {
2767 NTStatus = 0xC000000FL; /* No such file */
2769 else if (code == CM_ERROR_NOSUCHPATH) {
2770 NTStatus = 0xC000003AL; /* Object path not found */
2772 else if (code == CM_ERROR_TOOBIG) {
2773 NTStatus = 0xC000007BL; /* Invalid image format */
2775 else if (code == CM_ERROR_INVAL) {
2776 NTStatus = 0xC000000DL; /* Invalid parameter */
2778 else if (code == CM_ERROR_BADFD) {
2779 NTStatus = 0xC0000008L; /* Invalid handle */
2781 else if (code == CM_ERROR_BADFDOP) {
2782 NTStatus = 0xC0000022L; /* Access denied */
2784 else if (code == CM_ERROR_EXISTS) {
2785 NTStatus = 0xC0000035L; /* Object name collision */
2787 else if (code == CM_ERROR_NOTEMPTY) {
2788 NTStatus = 0xC0000101L; /* Directory not empty */
2790 else if (code == CM_ERROR_CROSSDEVLINK) {
2791 NTStatus = 0xC00000D4L; /* Not same device */
2793 else if (code == CM_ERROR_NOTDIR) {
2794 NTStatus = 0xC0000103L; /* Not a directory */
2796 else if (code == CM_ERROR_ISDIR) {
2797 NTStatus = 0xC00000BAL; /* File is a directory */
2799 else if (code == CM_ERROR_BADOP) {
2801 /* I have no idea where this comes from */
2802 NTStatus = 0xC09820FFL; /* SMB no support */
2804 NTStatus = 0xC00000BBL; /* Not supported */
2805 #endif /* COMMENT */
2807 else if (code == CM_ERROR_BADSHARENAME) {
2808 NTStatus = 0xC00000CCL; /* Bad network name */
2810 else if (code == CM_ERROR_NOIPC) {
2812 NTStatus = 0xC0000022L; /* Access Denied */
2814 NTStatus = 0xC000013DL; /* Remote Resources */
2817 else if (code == CM_ERROR_CLOCKSKEW) {
2818 NTStatus = 0xC0000133L; /* Time difference at DC */
2820 else if (code == CM_ERROR_BADTID) {
2821 NTStatus = 0xC0982005L; /* SMB bad TID */
2823 else if (code == CM_ERROR_USESTD) {
2824 NTStatus = 0xC09820FBL; /* SMB use standard */
2826 else if (code == CM_ERROR_QUOTA) {
2828 NTStatus = 0xC0000044L; /* Quota exceeded */
2830 NTStatus = 0xC000007FL; /* Disk full */
2833 else if (code == CM_ERROR_SPACE) {
2834 NTStatus = 0xC000007FL; /* Disk full */
2836 else if (code == CM_ERROR_ATSYS) {
2837 NTStatus = 0xC0000033L; /* Object name invalid */
2839 else if (code == CM_ERROR_BADNTFILENAME) {
2840 NTStatus = 0xC0000033L; /* Object name invalid */
2842 else if (code == CM_ERROR_WOULDBLOCK) {
2843 NTStatus = 0xC0000055L; /* Lock not granted */
2845 else if (code == CM_ERROR_SHARING_VIOLATION) {
2846 NTStatus = 0xC0000043L; /* Sharing violation */
2848 else if (code == CM_ERROR_LOCK_CONFLICT) {
2849 NTStatus = 0xC0000054L; /* Lock conflict */
2851 else if (code == CM_ERROR_PARTIALWRITE) {
2852 NTStatus = 0xC000007FL; /* Disk full */
2854 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2855 NTStatus = 0xC0000023L; /* Buffer too small */
2857 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2858 NTStatus = 0xC0000035L; /* Object name collision */
2860 else if (code == CM_ERROR_BADPASSWORD) {
2861 NTStatus = 0xC000006DL; /* unknown username or bad password */
2863 else if (code == CM_ERROR_BADLOGONTYPE) {
2864 NTStatus = 0xC000015BL; /* logon type not granted */
2866 else if (code == CM_ERROR_GSSCONTINUE) {
2867 NTStatus = 0xC0000016L; /* more processing required */
2869 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2871 NTStatus = 0xC0000280L; /* reparse point not resolved */
2873 NTStatus = 0xC0000022L; /* Access Denied */
2876 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2877 NTStatus = 0xC0000257L; /* Path Not Covered */
2880 else if (code == CM_ERROR_ALLBUSY) {
2881 NTStatus = 0xC00000BFL; /* Network Busy */
2883 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2884 NTStatus = 0xC0000350L; /* Remote Host Down */
2887 /* we do not want to be telling the SMB/CIFS client that
2888 * the AFS Client Service is busy or down.
2890 else if (code == CM_ERROR_ALLBUSY ||
2891 code == CM_ERROR_ALLOFFLINE ||
2892 code == CM_ERROR_ALLDOWN) {
2893 NTStatus = 0xC00000BEL; /* Bad Network Path */
2896 else if (code == RXKADUNKNOWNKEY) {
2897 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2899 else if (code == CM_ERROR_BAD_LEVEL) {
2900 NTStatus = 0xC0000148L; /* Invalid Level */
2902 NTStatus = 0xC0982001L; /* SMB non-specific error */
2905 *NTStatusp = NTStatus;
2906 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2909 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2910 unsigned char *classp)
2912 unsigned char class;
2913 unsigned short error;
2915 /* map CM_ERROR_* errors to SMB errors */
2916 if (code == CM_ERROR_NOSUCHCELL) {
2918 error = 3; /* bad path */
2920 else if (code == CM_ERROR_NOSUCHVOLUME) {
2922 error = 3; /* bad path */
2924 else if (code == CM_ERROR_TIMEDOUT) {
2926 error = 81; /* server is paused */
2928 else if (code == CM_ERROR_RETRY) {
2929 class = 2; /* shouldn't happen */
2932 else if (code == CM_ERROR_NOACCESS) {
2934 error = 4; /* bad access */
2936 else if (code == CM_ERROR_READONLY) {
2938 error = 19; /* read only */
2940 else if (code == CM_ERROR_NOSUCHFILE ||
2941 code == CM_ERROR_BPLUS_NOMATCH) {
2943 error = 2; /* ENOENT! */
2945 else if (code == CM_ERROR_NOSUCHPATH) {
2947 error = 3; /* Bad path */
2949 else if (code == CM_ERROR_TOOBIG) {
2951 error = 11; /* bad format */
2953 else if (code == CM_ERROR_INVAL) {
2954 class = 2; /* server non-specific error code */
2957 else if (code == CM_ERROR_BADFD) {
2959 error = 6; /* invalid file handle */
2961 else if (code == CM_ERROR_BADFDOP) {
2962 class = 1; /* invalid op on FD */
2965 else if (code == CM_ERROR_EXISTS) {
2967 error = 80; /* file already exists */
2969 else if (code == CM_ERROR_NOTEMPTY) {
2971 error = 5; /* delete directory not empty */
2973 else if (code == CM_ERROR_CROSSDEVLINK) {
2975 error = 17; /* EXDEV */
2977 else if (code == CM_ERROR_NOTDIR) {
2978 class = 1; /* bad path */
2981 else if (code == CM_ERROR_ISDIR) {
2982 class = 1; /* access denied; DOS doesn't have a good match */
2985 else if (code == CM_ERROR_BADOP) {
2989 else if (code == CM_ERROR_BADSHARENAME) {
2993 else if (code == CM_ERROR_NOIPC) {
2995 error = 4; /* bad access */
2997 else if (code == CM_ERROR_CLOCKSKEW) {
2998 class = 1; /* invalid function */
3001 else if (code == CM_ERROR_BADTID) {
3005 else if (code == CM_ERROR_USESTD) {
3009 else if (code == CM_ERROR_REMOTECONN) {
3013 else if (code == CM_ERROR_QUOTA) {
3014 if (vcp->flags & SMB_VCFLAG_USEV3) {
3016 error = 39; /* disk full */
3020 error = 5; /* access denied */
3023 else if (code == CM_ERROR_SPACE) {
3024 if (vcp->flags & SMB_VCFLAG_USEV3) {
3026 error = 39; /* disk full */
3030 error = 5; /* access denied */
3033 else if (code == CM_ERROR_PARTIALWRITE) {
3035 error = 39; /* disk full */
3037 else if (code == CM_ERROR_ATSYS) {
3039 error = 2; /* ENOENT */
3041 else if (code == CM_ERROR_WOULDBLOCK) {
3043 error = 33; /* lock conflict */
3045 else if (code == CM_ERROR_LOCK_CONFLICT) {
3047 error = 33; /* lock conflict */
3049 else if (code == CM_ERROR_SHARING_VIOLATION) {
3051 error = 33; /* lock conflict */
3053 else if (code == CM_ERROR_NOFILES) {
3055 error = 18; /* no files in search */
3057 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3059 error = 183; /* Samba uses this */
3061 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3062 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3064 error = 2; /* bad password */
3066 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3068 error = 3; /* bad path */
3077 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3080 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3082 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3083 return CM_ERROR_BADOP;
3086 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3088 unsigned short EchoCount, i;
3089 char *data, *outdata;
3092 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3094 for (i=1; i<=EchoCount; i++) {
3095 data = smb_GetSMBData(inp, &dataSize);
3096 smb_SetSMBParm(outp, 0, i);
3097 smb_SetSMBDataLength(outp, dataSize);
3098 outdata = smb_GetSMBData(outp, NULL);
3099 memcpy(outdata, data, dataSize);
3100 smb_SendPacket(vcp, outp);
3106 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3109 long count, minCount, finalCount;
3114 cm_user_t *userp = NULL;
3118 char *rawBuf = NULL;
3120 dos_ptr rawBuf = NULL;
3127 fd = smb_GetSMBParm(inp, 0);
3128 count = smb_GetSMBParm(inp, 3);
3129 minCount = smb_GetSMBParm(inp, 4);
3130 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3132 if (*inp->wctp == 10) {
3133 /* we were sent a request with 64-bit file offsets */
3134 #ifdef AFS_LARGEFILES
3135 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3137 if (LargeIntegerLessThanZero(offset)) {
3138 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3142 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3143 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3146 offset.HighPart = 0;
3150 /* we were sent a request with 32-bit file offsets */
3151 offset.HighPart = 0;
3154 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3155 fd, offset.HighPart, offset.LowPart, count);
3157 fidp = smb_FindFID(vcp, fd, 0);
3161 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3162 smb_CloseFID(vcp, fidp, NULL, 0);
3163 code = CM_ERROR_NOSUCHFILE;
3168 pid = ((smb_t *) inp)->pid;
3170 LARGE_INTEGER LOffset, LLength;
3173 key = cm_GenerateKey(vcp->vcID, pid, fd);
3175 LOffset.HighPart = offset.HighPart;
3176 LOffset.LowPart = offset.LowPart;
3177 LLength.HighPart = 0;
3178 LLength.LowPart = count;
3180 lock_ObtainMutex(&fidp->scp->mx);
3181 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3182 lock_ReleaseMutex(&fidp->scp->mx);
3188 lock_ObtainMutex(&smb_RawBufLock);
3190 /* Get a raw buf, from head of list */
3191 rawBuf = smb_RawBufs;
3193 smb_RawBufs = *(char **)smb_RawBufs;
3195 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
3198 lock_ReleaseMutex(&smb_RawBufLock);
3202 lock_ObtainMutex(&fidp->mx);
3203 if (fidp->flags & SMB_FID_IOCTL)
3205 lock_ReleaseMutex(&fidp->mx);
3207 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3209 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
3212 /* Give back raw buffer */
3213 lock_ObtainMutex(&smb_RawBufLock);
3215 *((char **) rawBuf) = smb_RawBufs;
3217 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3220 smb_RawBufs = rawBuf;
3221 lock_ReleaseMutex(&smb_RawBufLock);
3224 smb_ReleaseFID(fidp);
3227 lock_ReleaseMutex(&fidp->mx);
3229 userp = smb_GetUserFromVCP(vcp, inp);
3232 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3234 /* have to give ReadData flag so it will treat buffer as DOS mem. */
3235 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
3236 userp, &finalCount, TRUE /* rawFlag */);
3243 cm_ReleaseUser(userp);
3246 smb_ReleaseFID(fidp);
3251 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
3253 memset((char *)ncbp, 0, sizeof(NCB));
3255 ncbp->ncb_length = (unsigned short) finalCount;
3256 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3257 ncbp->ncb_lana_num = vcp->lana;
3258 ncbp->ncb_command = NCBSEND;
3259 ncbp->ncb_buffer = rawBuf;
3262 code = Netbios(ncbp);
3264 code = Netbios(ncbp, dos_ncb);
3267 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3270 /* Give back raw buffer */
3271 lock_ObtainMutex(&smb_RawBufLock);
3273 *((char **) rawBuf) = smb_RawBufs;
3275 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
3278 smb_RawBufs = rawBuf;
3279 lock_ReleaseMutex(&smb_RawBufLock);
3285 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3287 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3292 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3294 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3299 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3306 int VistaProtoIndex;
3307 int protoIndex; /* index we're using */
3312 char protocol_array[10][1024]; /* protocol signature of the client */
3313 int caps; /* capabilities */
3316 TIME_ZONE_INFORMATION tzi;
3318 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3321 namep = smb_GetSMBData(inp, &dbytes);
3324 coreProtoIndex = -1; /* not found */
3327 VistaProtoIndex = -1;
3328 while(namex < dbytes) {
3329 osi_Log1(smb_logp, "Protocol %s",
3330 osi_LogSaveString(smb_logp, namep+1));
3331 strcpy(protocol_array[tcounter], namep+1);
3333 /* namep points at the first protocol, or really, a 0x02
3334 * byte preceding the null-terminated ASCII name.
3336 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3337 coreProtoIndex = tcounter;
3339 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3340 v3ProtoIndex = tcounter;
3342 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3343 NTProtoIndex = tcounter;
3345 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3346 VistaProtoIndex = tcounter;
3349 /* compute size of protocol entry */
3350 entryLength = (int)strlen(namep+1);
3351 entryLength += 2; /* 0x02 bytes and null termination */
3353 /* advance over this protocol entry */
3354 namex += entryLength;
3355 namep += entryLength;
3356 tcounter++; /* which proto entry we're looking at */
3359 lock_ObtainMutex(&vcp->mx);
3361 if (VistaProtoIndex != -1) {
3362 protoIndex = VistaProtoIndex;
3363 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3366 if (NTProtoIndex != -1) {
3367 protoIndex = NTProtoIndex;
3368 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3370 else if (v3ProtoIndex != -1) {
3371 protoIndex = v3ProtoIndex;
3372 vcp->flags |= SMB_VCFLAG_USEV3;
3374 else if (coreProtoIndex != -1) {
3375 protoIndex = coreProtoIndex;
3376 vcp->flags |= SMB_VCFLAG_USECORE;
3378 else protoIndex = -1;
3379 lock_ReleaseMutex(&vcp->mx);
3381 if (protoIndex == -1)
3382 return CM_ERROR_INVAL;
3383 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3384 smb_SetSMBParm(outp, 0, protoIndex);
3385 if (smb_authType != SMB_AUTH_NONE) {
3386 smb_SetSMBParmByte(outp, 1,
3387 NEGOTIATE_SECURITY_USER_LEVEL |
3388 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3390 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3392 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3393 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3394 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3395 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3396 /* The session key is not a well documented field however most clients
3397 * will echo back the session key to the server. Currently we are using
3398 * the same value for all sessions. We should generate a random value
3399 * and store it into the vcp
3401 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3402 smb_SetSMBParm(outp, 8, 1);
3404 * Tried changing the capabilities to support for W2K - defect 117695
3405 * Maybe something else needs to be changed here?
3409 smb_SetSMBParmLong(outp, 9, 0x43fd);
3411 smb_SetSMBParmLong(outp, 9, 0x251);
3414 * 32-bit error codes *
3419 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3421 NTNEGOTIATE_CAPABILITY_DFS |
3423 #ifdef AFS_LARGEFILES
3424 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3426 NTNEGOTIATE_CAPABILITY_NTFIND |
3427 NTNEGOTIATE_CAPABILITY_RAWMODE |
3428 NTNEGOTIATE_CAPABILITY_NTSMB;
3430 if ( smb_authType == SMB_AUTH_EXTENDED )
3431 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3433 smb_SetSMBParmLong(outp, 9, caps);
3435 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3436 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3437 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3439 GetTimeZoneInformation(&tzi);
3440 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3442 if (smb_authType == SMB_AUTH_NTLM) {
3443 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3444 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3445 /* paste in encryption key */
3446 datap = smb_GetSMBData(outp, NULL);
3447 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3448 /* and the faux domain name */
3449 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3450 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3454 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3456 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3458 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3460 datap = smb_GetSMBData(outp, NULL);
3461 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3464 datap += sizeof(smb_ServerGUID);
3465 memcpy(datap, secBlob, secBlobLength);
3469 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3470 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3473 else if (v3ProtoIndex != -1) {
3474 smb_SetSMBParm(outp, 0, protoIndex);
3476 /* NOTE: Extended authentication cannot be negotiated with v3
3477 * therefore we fail over to NTLM
3479 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3480 smb_SetSMBParm(outp, 1,
3481 NEGOTIATE_SECURITY_USER_LEVEL |
3482 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3484 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3486 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3487 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3488 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3489 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3490 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3491 smb_SetSMBParm(outp, 7, 1);
3493 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3494 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3495 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3497 GetTimeZoneInformation(&tzi);
3498 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3500 /* NOTE: Extended authentication cannot be negotiated with v3
3501 * therefore we fail over to NTLM
3503 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3504 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3505 smb_SetSMBParm(outp, 12, 0); /* resvd */
3506 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3507 datap = smb_GetSMBData(outp, NULL);
3508 /* paste in a new encryption key */
3509 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3510 /* and the faux domain name */
3511 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3513 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3514 smb_SetSMBParm(outp, 12, 0); /* resvd */
3515 smb_SetSMBDataLength(outp, 0);
3518 else if (coreProtoIndex != -1) { /* not really supported anymore */
3519 smb_SetSMBParm(outp, 0, protoIndex);
3520 smb_SetSMBDataLength(outp, 0);
3525 void smb_CheckVCs(void)
3527 smb_vc_t * vcp, *nextp;
3528 smb_packet_t * outp = GetPacket();
3531 lock_ObtainWrite(&smb_rctLock);
3532 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3534 if (vcp->magic != SMB_VC_MAGIC)
3535 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3536 __FILE__, __LINE__);
3540 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3543 smb_HoldVCNoLock(vcp);
3545 smb_HoldVCNoLock(nextp);
3546 smb_FormatResponsePacket(vcp, NULL, outp);
3547 smbp = (smb_t *)outp;
3548 outp->inCom = smbp->com = 0x2b /* Echo */;
3556 smb_SetSMBParm(outp, 0, 0);
3557 smb_SetSMBDataLength(outp, 0);
3558 lock_ReleaseWrite(&smb_rctLock);
3560 smb_SendPacket(vcp, outp);
3562 lock_ObtainWrite(&smb_rctLock);
3563 smb_ReleaseVCNoLock(vcp);
3565 smb_ReleaseVCNoLock(nextp);
3567 lock_ReleaseWrite(&smb_rctLock);
3568 smb_FreePacket(outp);
3571 void smb_Daemon(void *parmp)
3573 afs_uint32 count = 0;
3574 smb_username_t **unpp;
3577 while(smbShutdownFlag == 0) {
3581 if (smbShutdownFlag == 1)
3584 if ((count % 72) == 0) { /* every five minutes */
3586 time_t old_localZero = smb_localZero;
3588 /* Initialize smb_localZero */
3589 myTime.tm_isdst = -1; /* compute whether on DST or not */
3590 myTime.tm_year = 70;
3596 smb_localZero = mktime(&myTime);
3598 #ifndef USE_NUMERIC_TIME_CONV
3599 smb_CalculateNowTZ();
3600 #endif /* USE_NUMERIC_TIME_CONV */
3601 #ifdef AFS_FREELANCE
3602 if ( smb_localZero != old_localZero )
3603 cm_noteLocalMountPointChange();
3609 /* GC smb_username_t objects that will no longer be used */
3611 lock_ObtainWrite(&smb_rctLock);
3612 for ( unpp=&usernamesp; *unpp; ) {
3614 smb_username_t *unp;
3616 lock_ObtainMutex(&(*unpp)->mx);
3617 if ( (*unpp)->refCount > 0 ||
3618 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3619 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3621 else if (!smb_LogoffTokenTransfer ||
3622 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3624 lock_ReleaseMutex(&(*unpp)->mx);
3632 lock_FinalizeMutex(&unp->mx);
3638 lock_ReleaseWrite(&smb_rctLock);
3639 cm_ReleaseUser(userp);
3640 lock_ObtainWrite(&smb_rctLock);
3643 unpp = &(*unpp)->nextp;
3646 lock_ReleaseWrite(&smb_rctLock);
3648 /* XXX GC dir search entries */
3652 void smb_WaitingLocksDaemon()
3654 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3655 smb_waitingLock_t *wl, *wlNext;
3658 smb_packet_t *inp, *outp;
3662 while (smbShutdownFlag == 0) {
3663 lock_ObtainWrite(&smb_globalLock);
3664 nwlRequest = smb_allWaitingLocks;
3665 if (nwlRequest == NULL) {
3666 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3671 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3678 lock_ObtainWrite(&smb_globalLock);
3680 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3682 wlRequest = nwlRequest;
3683 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3684 lock_ReleaseWrite(&smb_globalLock);
3688 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3689 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3692 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3694 /* wl->state is either _DONE or _WAITING. _ERROR
3695 would no longer be on the queue. */
3696 code = cm_RetryLock( wl->lockp,
3697 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3700 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3701 } else if (code != CM_ERROR_WOULDBLOCK) {
3702 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3707 if (code == CM_ERROR_WOULDBLOCK) {
3710 if (wlRequest->timeRemaining != 0xffffffff
3711 && (wlRequest->timeRemaining -= 1000) < 0)
3723 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3726 scp = wlRequest->scp;
3727 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3731 lock_ObtainMutex(&scp->mx);
3733 for (wl = wlRequest->locks; wl; wl = wlNext) {
3734 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3736 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3737 wl->LLength, wl->key, NULL, &req);
3739 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3744 lock_ReleaseMutex(&scp->mx);
3748 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3751 for (wl = wlRequest->locks; wl; wl = wlNext) {
3752 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3753 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3758 vcp = wlRequest->vcp;
3759 inp = wlRequest->inp;
3760 outp = wlRequest->outp;
3762 ncbp->ncb_length = inp->ncb_length;
3763 inp->spacep = cm_GetSpace();
3765 /* Remove waitingLock from list */
3766 lock_ObtainWrite(&smb_globalLock);
3767 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3769 lock_ReleaseWrite(&smb_globalLock);
3771 /* Resume packet processing */
3773 smb_SetSMBDataLength(outp, 0);
3774 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3775 outp->resumeCode = code;
3777 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3780 cm_FreeSpace(inp->spacep);
3781 smb_FreePacket(inp);
3782 smb_FreePacket(outp);
3784 cm_ReleaseSCache(wlRequest->scp);
3787 } while (nwlRequest && smbShutdownFlag == 0);
3792 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3794 osi_Log0(smb_logp, "SMB receive get disk attributes");
3796 smb_SetSMBParm(outp, 0, 32000);
3797 smb_SetSMBParm(outp, 1, 64);
3798 smb_SetSMBParm(outp, 2, 1024);
3799 smb_SetSMBParm(outp, 3, 30000);
3800 smb_SetSMBParm(outp, 4, 0);
3801 smb_SetSMBDataLength(outp, 0);
3805 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3809 unsigned short newTid;
3810 char shareName[AFSPATHMAX];
3818 osi_Log0(smb_logp, "SMB receive tree connect");
3820 /* parse input parameters */
3821 tp = smb_GetSMBData(inp, NULL);
3822 pathp = smb_ParseASCIIBlock(tp, &tp);
3823 if (smb_StoreAnsiFilenames)
3824 OemToChar(pathp,pathp);
3825 passwordp = smb_ParseASCIIBlock(tp, &tp);
3826 tp = strrchr(pathp, '\\');
3828 return CM_ERROR_BADSMB;
3829 strcpy(shareName, tp+1);
3831 lock_ObtainMutex(&vcp->mx);
3832 newTid = vcp->tidCounter++;
3833 lock_ReleaseMutex(&vcp->mx);
3835 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3836 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3837 userp = smb_GetUserFromUID(uidp);
3838 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3840 smb_ReleaseUID(uidp);
3842 smb_ReleaseTID(tidp);
3843 return CM_ERROR_BADSHARENAME;
3845 lock_ObtainMutex(&tidp->mx);
3846 tidp->userp = userp;
3847 tidp->pathname = sharePath;
3848 lock_ReleaseMutex(&tidp->mx);
3849 smb_ReleaseTID(tidp);
3851 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3852 smb_SetSMBParm(rsp, 1, newTid);
3853 smb_SetSMBDataLength(rsp, 0);
3855 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3859 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3863 if (*inp++ != 0x1) return NULL;
3864 tlen = inp[0] + (inp[1]<<8);
3865 inp += 2; /* skip length field */
3868 *chainpp = inp + tlen;
3871 if (lengthp) *lengthp = tlen;
3876 /* set maskp to the mask part of the incoming path.
3877 * Mask is 11 bytes long (8.3 with the dot elided).
3878 * Returns true if succeeds with a valid name, otherwise it does
3879 * its best, but returns false.
3881 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3889 /* starts off valid */
3892 /* mask starts out all blanks */
3893 memset(maskp, ' ', 11);
3895 /* find last backslash, or use whole thing if there is none */
3896 tp = strrchr(pathp, '\\');
3897 if (!tp) tp = pathp;
3898 else tp++; /* skip slash */
3902 /* names starting with a dot are illegal */
3903 if (*tp == '.') valid8Dot3 = 0;
3907 if (tc == 0) return valid8Dot3;
3908 if (tc == '.' || tc == '"') break;
3909 if (i < 8) *up++ = tc;
3910 else valid8Dot3 = 0;
3913 /* if we get here, tp point after the dot */
3914 up = maskp+8; /* ext goes here */
3921 if (tc == '.' || tc == '"')
3924 /* copy extension if not too long */
3934 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3944 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3946 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3950 /* otherwise, we have a valid 8.3 name; see if we have a match,
3951 * treating '?' as a wildcard in maskp (but not in the file name).
3953 tp1 = umask; /* real name, in mask format */
3954 tp2 = maskp; /* mask, in mask format */
3955 for(i=0; i<11; i++) {
3956 tc1 = *tp1++; /* char from real name */
3957 tc2 = *tp2++; /* char from mask */
3958 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3959 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3962 if (tc2 == '?' && tc1 != ' ')
3969 /* we got a match */
3973 char *smb_FindMask(char *pathp)
3977 tp = strrchr(pathp, '\\'); /* find last slash */
3980 return tp+1; /* skip the slash */
3982 return pathp; /* no slash, return the entire path */
3985 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3987 unsigned char *pathp;
3989 unsigned char mask[11];
3990 unsigned char *statBlockp;
3991 unsigned char initStatBlock[21];
3994 osi_Log0(smb_logp, "SMB receive search volume");
3996 /* pull pathname and stat block out of request */
3997 tp = smb_GetSMBData(inp, NULL);
3998 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3999 osi_assertx(pathp != NULL, "null path");
4000 if (smb_StoreAnsiFilenames)
4001 OemToChar(pathp,pathp);
4002 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
4003 osi_assertx(statBlockp != NULL, "null statBlock");
4005 statBlockp = initStatBlock;
4009 /* for returning to caller */
4010 smb_Get8Dot3MaskFromPath(mask, pathp);
4012 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4013 tp = smb_GetSMBData(outp, NULL);
4015 *tp++ = 43; /* bytes in a dir entry */
4016 *tp++ = 0; /* high byte in counter */
4018 /* now marshall the dir entry, starting with the search status */
4019 *tp++ = statBlockp[0]; /* Reserved */
4020 memcpy(tp, mask, 11); tp += 11; /* FileName */
4022 /* now pass back server use info, with 1st byte non-zero */
4024 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4026 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4028 *tp++ = 0x8; /* attribute: volume */
4038 /* 4 byte file size */
4044 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4045 memset(tp, ' ', 13);
4048 /* set the length of the data part of the packet to 43 + 3, for the dir
4049 * entry plus the 5 and the length fields.
4051 smb_SetSMBDataLength(outp, 46);
4055 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
4056 cm_user_t *userp, cm_req_t *reqp)
4064 smb_dirListPatch_t *patchp;
4065 smb_dirListPatch_t *npatchp;
4067 for (patchp = *dirPatchespp; patchp; patchp =
4068 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4070 dptr = patchp->dptr;
4072 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4074 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4075 *dptr++ = SMB_ATTR_HIDDEN;
4078 lock_ObtainMutex(&scp->mx);
4079 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
4080 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4082 lock_ReleaseMutex(&scp->mx);
4083 cm_ReleaseSCache(scp);
4084 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4085 *dptr++ = SMB_ATTR_HIDDEN;
4089 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4091 attr = smb_Attributes(scp);
4092 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4093 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4094 attr |= SMB_ATTR_HIDDEN;
4098 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4101 shortTemp = (unsigned short) (dosTime & 0xffff);
4102 *((u_short *)dptr) = shortTemp;
4105 /* and copy out date */
4106 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4107 *((u_short *)dptr) = shortTemp;
4110 /* copy out file length */
4111 *((u_long *)dptr) = scp->length.LowPart;
4113 lock_ReleaseMutex(&scp->mx);
4114 cm_ReleaseSCache(scp);
4117 /* now free the patches */
4118 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4119 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4123 /* and mark the list as empty */
4124 *dirPatchespp = NULL;
4129 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4138 smb_dirListPatch_t *dirListPatchesp;
4139 smb_dirListPatch_t *curPatchp;
4143 osi_hyper_t dirLength;
4144 osi_hyper_t bufferOffset;
4145 osi_hyper_t curOffset;
4147 unsigned char *inCookiep;
4148 smb_dirSearch_t *dsp;
4152 unsigned long clientCookie;
4153 cm_pageHeader_t *pageHeaderp;
4154 cm_user_t *userp = NULL;
4161 long nextEntryCookie;
4162 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4163 char resByte; /* reserved byte from the cookie */
4164 char *op; /* output data ptr */
4165 char *origOp; /* original value of op */
4166 cm_space_t *spacep; /* for pathname buffer */
4177 maxCount = smb_GetSMBParm(inp, 0);
4179 dirListPatchesp = NULL;
4181 caseFold = CM_FLAG_CASEFOLD;
4183 tp = smb_GetSMBData(inp, NULL);
4184 pathp = smb_ParseASCIIBlock(tp, &tp);
4185 if (smb_StoreAnsiFilenames)
4186 OemToChar(pathp,pathp);
4187 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4189 /* bail out if request looks bad */
4190 if (!tp || !pathp) {
4191 return CM_ERROR_BADSMB;
4194 /* We can handle long names */
4195 if (vcp->flags & SMB_VCFLAG_USENT)
4196 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4198 /* make sure we got a whole search status */
4199 if (dataLength < 21) {
4200 nextCookie = 0; /* start at the beginning of the dir */
4203 attribute = smb_GetSMBParm(inp, 1);
4205 /* handle volume info in another function */
4206 if (attribute & 0x8)
4207 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4209 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
4210 maxCount, osi_LogSaveString(smb_logp, pathp));
4212 if (*pathp == 0) { /* null pathp, treat as root dir */
4213 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4214 return CM_ERROR_NOFILES;
4218 dsp = smb_NewDirSearch(0);
4219 dsp->attribute = attribute;
4220 smb_Get8Dot3MaskFromPath(mask, pathp);
4221 memcpy(dsp->mask, mask, 11);
4223 /* track if this is likely to match a lot of entries */
4224 if (smb_IsStarMask(mask))
4229 /* pull the next cookie value out of the search status block */
4230 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4231 + (inCookiep[16]<<24);
4232 dsp = smb_FindDirSearch(inCookiep[12]);
4234 /* can't find dir search status; fatal error */
4235 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
4236 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
4237 return CM_ERROR_BADFD;
4239 attribute = dsp->attribute;
4240 resByte = inCookiep[0];
4242 /* copy out client cookie, in host byte order. Don't bother
4243 * interpreting it, since we're just passing it through, anyway.
4245 memcpy(&clientCookie, &inCookiep[17], 4);
4247 memcpy(mask, dsp->mask, 11);
4249 /* assume we're doing a star match if it has continued for more
4255 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4256 nextCookie, dsp->cookie, attribute);
4258 userp = smb_GetUserFromVCP(vcp, inp);
4260 /* try to get the vnode for the path name next */
4261 lock_ObtainMutex(&dsp->mx);
4264 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4268 spacep = inp->spacep;
4269 smb_StripLastComponent(spacep->data, NULL, pathp);
4270 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4272 lock_ReleaseMutex(&dsp->mx);
4273 cm_ReleaseUser(userp);
4274 smb_DeleteDirSearch(dsp);
4275 smb_ReleaseDirSearch(dsp);
4276 return CM_ERROR_NOFILES;
4278 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4279 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4282 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4283 cm_ReleaseSCache(scp);
4284 lock_ReleaseMutex(&dsp->mx);
4285 cm_ReleaseUser(userp);
4286 smb_DeleteDirSearch(dsp);
4287 smb_ReleaseDirSearch(dsp);
4288 if ( WANTS_DFS_PATHNAMES(inp) )
4289 return CM_ERROR_PATH_NOT_COVERED;
4291 return CM_ERROR_BADSHARENAME;
4293 #endif /* DFS_SUPPORT */
4296 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4297 /* we need one hold for the entry we just stored into,
4298 * and one for our own processing. When we're done with this
4299 * function, we'll drop the one for our own processing.
4300 * We held it once from the namei call, and so we do another hold
4304 lock_ObtainMutex(&scp->mx);
4305 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4306 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4307 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4308 dsp->flags |= SMB_DIRSEARCH_BULKST;
4309 dsp->scp->bulkStatProgress = hzero;
4311 lock_ReleaseMutex(&scp->mx);
4314 lock_ReleaseMutex(&dsp->mx);
4316 cm_ReleaseUser(userp);
4317 smb_DeleteDirSearch(dsp);
4318 smb_ReleaseDirSearch(dsp);
4322 /* reserves space for parameter; we'll adjust it again later to the
4323 * real count of the # of entries we returned once we've actually
4324 * assembled the directory listing.
4326 smb_SetSMBParm(outp, 0, 0);
4328 /* get the directory size */
4329 lock_ObtainMutex(&scp->mx);
4330 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4331 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4333 lock_ReleaseMutex(&scp->mx);
4334 cm_ReleaseSCache(scp);
4335 cm_ReleaseUser(userp);
4336 smb_DeleteDirSearch(dsp);
4337 smb_ReleaseDirSearch(dsp);
4341 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4343 dirLength = scp->length;
4345 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4346 curOffset.HighPart = 0;
4347 curOffset.LowPart = nextCookie;
4348 origOp = op = smb_GetSMBData(outp, NULL);
4349 /* and write out the basic header */
4350 *op++ = 5; /* variable block */
4351 op += 2; /* skip vbl block length; we'll fill it in later */
4355 /* make sure that curOffset.LowPart doesn't point to the first
4356 * 32 bytes in the 2nd through last dir page, and that it doesn't
4357 * point at the first 13 32-byte chunks in the first dir page,
4358 * since those are dir and page headers, and don't contain useful
4361 temp = curOffset.LowPart & (2048-1);
4362 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4363 /* we're in the first page */
4364 if (temp < 13*32) temp = 13*32;
4367 /* we're in a later dir page */
4368 if (temp < 32) temp = 32;
4371 /* make sure the low order 5 bits are zero */
4374 /* now put temp bits back ito curOffset.LowPart */
4375 curOffset.LowPart &= ~(2048-1);
4376 curOffset.LowPart |= temp;
4378 /* check if we've returned all the names that will fit in the
4381 if (returnedNames >= maxCount) {
4382 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4383 returnedNames, maxCount);
4387 /* check if we've passed the dir's EOF */
4388 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4390 /* see if we can use the bufferp we have now; compute in which page
4391 * the current offset would be, and check whether that's the offset
4392 * of the buffer we have. If not, get the buffer.
4394 thyper.HighPart = curOffset.HighPart;
4395 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4396 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4399 buf_Release(bufferp);
4402 lock_ReleaseMutex(&scp->mx);
4403 lock_ObtainRead(&scp->bufCreateLock);
4404 code = buf_Get(scp, &thyper, &bufferp);
4405 lock_ReleaseRead(&scp->bufCreateLock);
4406 lock_ObtainMutex(&dsp->mx);
4408 /* now, if we're doing a star match, do bulk fetching of all of
4409 * the status info for files in the dir.
4412 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4413 lock_ObtainMutex(&scp->mx);
4414 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4415 LargeIntegerGreaterThanOrEqualTo(thyper,
4416 scp->bulkStatProgress)) {
4417 /* Don't bulk stat if risking timeout */
4418 int now = GetTickCount();
4419 if (now - req.startTime > RDRtimeout * 1000) {
4420 scp->bulkStatProgress = thyper;
4421 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4422 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4423 dsp->scp->bulkStatProgress = hzero;
4425 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4428 lock_ObtainMutex(&scp->mx);
4430 lock_ReleaseMutex(&dsp->mx);
4432 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4436 bufferOffset = thyper;
4438 /* now get the data in the cache */
4440 code = cm_SyncOp(scp, bufferp, userp, &req,
4442 CM_SCACHESYNC_NEEDCALLBACK |
4443 CM_SCACHESYNC_READ);
4445 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4449 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4451 if (cm_HaveBuffer(scp, bufferp, 0)) {
4452 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4456 /* otherwise, load the buffer and try again */
4457 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4459 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4460 scp, bufferp, code);
4465 buf_Release(bufferp);
4469 } /* if (wrong buffer) ... */
4471 /* now we have the buffer containing the entry we're interested in; copy
4472 * it out if it represents a non-deleted entry.
4474 entryInDir = curOffset.LowPart & (2048-1);
4475 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4477 /* page header will help tell us which entries are free. Page header
4478 * can change more often than once per buffer, since AFS 3 dir page size
4479 * may be less than (but not more than a buffer package buffer.
4481 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4482 temp &= ~(2048 - 1); /* turn off intra-page bits */
4483 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4485 /* now determine which entry we're looking at in the page. If it is
4486 * free (there's a free bitmap at the start of the dir), we should
4487 * skip these 32 bytes.
4489 slotInPage = (entryInDir & 0x7e0) >> 5;
4490 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4491 /* this entry is free */
4492 numDirChunks = 1; /* only skip this guy */
4496 tp = bufferp->datap + entryInBuffer;
4497 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4499 /* while we're here, compute the next entry's location, too,
4500 * since we'll need it when writing out the cookie into the dir
4503 * XXXX Probably should do more sanity checking.
4505 numDirChunks = cm_NameEntries(dep->name, NULL);
4507 /* compute the offset of the cookie representing the next entry */
4508 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4510 /* Compute 8.3 name if necessary */
4511 actualName = dep->name;
4512 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4513 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4514 actualName = shortName;
4517 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4518 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4519 osi_LogSaveString(smb_logp, actualName));
4521 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4522 /* this is one of the entries to use: it is not deleted
4523 * and it matches the star pattern we're looking for.
4526 /* Eliminate entries that don't match requested
4529 /* no hidden files */
4530 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4531 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4535 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4537 /* We have already done the cm_TryBulkStat above */
4538 fid.cell = scp->fid.cell;
4539 fid.volume = scp->fid.volume;
4540 fid.vnode = ntohl(dep->fid.vnode);
4541 fid.unique = ntohl(dep->fid.unique);
4542 fileType = cm_FindFileType(&fid);
4543 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4544 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4546 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4547 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4548 fileType == CM_SCACHETYPE_DFSLINK ||
4549 fileType == CM_SCACHETYPE_INVALID)
4550 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4555 memcpy(op, mask, 11); op += 11;
4556 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4557 *op++ = (char)(nextEntryCookie & 0xff);
4558 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4559 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4560 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4561 memcpy(op, &clientCookie, 4); op += 4;
4563 /* now we emit the attribute. This is sort of tricky,
4564 * since we need to really stat the file to find out
4565 * what type of entry we've got. Right now, we're
4566 * copying out data from a buffer, while holding the
4567 * scp locked, so it isn't really convenient to stat
4568 * something now. We'll put in a place holder now,
4569 * and make a second pass before returning this to get
4570 * the real attributes. So, we just skip the data for
4571 * now, and adjust it later. We allocate a patch
4572 * record to make it easy to find this point later.
4573 * The replay will happen at a time when it is safe to
4574 * unlock the directory.
4576 curPatchp = malloc(sizeof(*curPatchp));
4577 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4578 curPatchp->dptr = op;
4579 curPatchp->fid.cell = scp->fid.cell;
4580 curPatchp->fid.volume = scp->fid.volume;
4581 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4582 curPatchp->fid.unique = ntohl(dep->fid.unique);
4584 /* do hidden attribute here since name won't be around when applying
4588 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4589 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4591 curPatchp->flags = 0;
4593 op += 9; /* skip attr, time, date and size */
4595 /* zero out name area. The spec says to pad with
4596 * spaces, but Samba doesn't, and neither do we.
4600 /* finally, we get to copy out the name; we know that
4601 * it fits in 8.3 or the pattern wouldn't match, but it
4602 * never hurts to be sure.
4604 strncpy(op, actualName, 13);
4605 if (smb_StoreAnsiFilenames)
4608 /* Uppercase if requested by client */
4609 if (!KNOWS_LONG_NAMES(inp))
4614 /* now, adjust the # of entries copied */
4616 } /* if we're including this name */
4619 /* and adjust curOffset to be where the new cookie is */
4620 thyper.HighPart = 0;
4621 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4622 curOffset = LargeIntegerAdd(thyper, curOffset);
4623 } /* while copying data for dir listing */
4625 /* release the mutex */
4626 lock_ReleaseMutex(&scp->mx);
4628 buf_Release(bufferp);
4632 /* apply and free last set of patches; if not doing a star match, this
4633 * will be empty, but better safe (and freeing everything) than sorry.
4635 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4637 /* special return code for unsuccessful search */
4638 if (code == 0 && dataLength < 21 && returnedNames == 0)
4639 code = CM_ERROR_NOFILES;
4641 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4642 returnedNames, code);
4645 smb_DeleteDirSearch(dsp);
4646 smb_ReleaseDirSearch(dsp);
4647 cm_ReleaseSCache(scp);
4648 cm_ReleaseUser(userp);
4652 /* finalize the output buffer */
4653 smb_SetSMBParm(outp, 0, returnedNames);
4654 temp = (long) (op - origOp);
4655 smb_SetSMBDataLength(outp, temp);
4657 /* the data area is a variable block, which has a 5 (already there)
4658 * followed by the length of the # of data bytes. We now know this to
4659 * be "temp," although that includes the 3 bytes of vbl block header.
4660 * Deduct for them and fill in the length field.
4662 temp -= 3; /* deduct vbl block info */
4663 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4664 origOp[1] = (char)(temp & 0xff);
4665 origOp[2] = (char)((temp>>8) & 0xff);
4666 if (returnedNames == 0)
4667 smb_DeleteDirSearch(dsp);
4668 smb_ReleaseDirSearch(dsp);
4669 cm_ReleaseSCache(scp);
4670 cm_ReleaseUser(userp);
4674 /* verify that this is a valid path to a directory. I don't know why they
4675 * don't use the get file attributes call.
4677 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4681 cm_scache_t *rootScp;
4682 cm_scache_t *newScp;
4691 pathp = smb_GetSMBData(inp, NULL);
4692 pathp = smb_ParseASCIIBlock(pathp, NULL);
4694 return CM_ERROR_BADFD;
4695 if (smb_StoreAnsiFilenames)
4696 OemToChar(pathp,pathp);
4697 osi_Log1(smb_logp, "SMB receive check path %s",
4698 osi_LogSaveString(smb_logp, pathp));
4700 rootScp = cm_data.rootSCachep;
4702 userp = smb_GetUserFromVCP(vcp, inp);
4704 caseFold = CM_FLAG_CASEFOLD;
4706 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4708 cm_ReleaseUser(userp);
4709 return CM_ERROR_NOSUCHPATH;
4711 code = cm_NameI(rootScp, pathp,
4712 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4713 userp, tidPathp, &req, &newScp);
4716 cm_ReleaseUser(userp);
4721 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4722 cm_ReleaseSCache(newScp);
4723 cm_ReleaseUser(userp);
4724 if ( WANTS_DFS_PATHNAMES(inp) )
4725 return CM_ERROR_PATH_NOT_COVERED;
4727 return CM_ERROR_BADSHARENAME;
4729 #endif /* DFS_SUPPORT */
4731 /* now lock the vnode with a callback; returns with newScp locked */
4732 lock_ObtainMutex(&newScp->mx);
4733 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4734 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4736 if (code != CM_ERROR_NOACCESS) {
4737 lock_ReleaseMutex(&newScp->mx);
4738 cm_ReleaseSCache(newScp);
4739 cm_ReleaseUser(userp);
4743 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4746 attrs = smb_Attributes(newScp);
4748 if (!(attrs & SMB_ATTR_DIRECTORY))
4749 code = CM_ERROR_NOTDIR;
4751 lock_ReleaseMutex(&newScp->mx);
4753 cm_ReleaseSCache(newScp);
4754 cm_ReleaseUser(userp);
4758 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4762 cm_scache_t *rootScp;
4763 unsigned short attribute;
4765 cm_scache_t *newScp;
4774 /* decode basic attributes we're passed */
4775 attribute = smb_GetSMBParm(inp, 0);
4776 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4778 pathp = smb_GetSMBData(inp, NULL);
4779 pathp = smb_ParseASCIIBlock(pathp, NULL);
4781 return CM_ERROR_BADSMB;
4782 if (smb_StoreAnsiFilenames)
4783 OemToChar(pathp,pathp);
4785 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4786 dosTime, attribute);
4788 rootScp = cm_data.rootSCachep;
4790 userp = smb_GetUserFromVCP(vcp, inp);
4792 caseFold = CM_FLAG_CASEFOLD;
4794 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4796 cm_ReleaseUser(userp);
4797 return CM_ERROR_NOSUCHFILE;
4799 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4800 tidPathp, &req, &newScp);
4803 cm_ReleaseUser(userp);
4808 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4809 cm_ReleaseSCache(newScp);
4810 cm_ReleaseUser(userp);
4811 if ( WANTS_DFS_PATHNAMES(inp) )
4812 return CM_ERROR_PATH_NOT_COVERED;
4814 return CM_ERROR_BADSHARENAME;
4816 #endif /* DFS_SUPPORT */
4818 /* now lock the vnode with a callback; returns with newScp locked; we
4819 * need the current status to determine what the new status is, in some
4822 lock_ObtainMutex(&newScp->mx);
4823 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4824 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4826 lock_ReleaseMutex(&newScp->mx);
4827 cm_ReleaseSCache(newScp);
4828 cm_ReleaseUser(userp);
4832 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4834 /* Check for RO volume */
4835 if (newScp->flags & CM_SCACHEFLAG_RO) {
4836 lock_ReleaseMutex(&newScp->mx);
4837 cm_ReleaseSCache(newScp);
4838 cm_ReleaseUser(userp);
4839 return CM_ERROR_READONLY;
4842 /* prepare for setattr call */
4845 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4846 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4848 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4849 /* we're told to make a writable file read-only */
4850 attr.unixModeBits = newScp->unixModeBits & ~0222;
4851 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4853 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4854 /* we're told to make a read-only file writable */
4855 attr.unixModeBits = newScp->unixModeBits | 0222;
4856 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4858 lock_ReleaseMutex(&newScp->mx);
4860 /* now call setattr */
4862 code = cm_SetAttr(newScp, &attr, userp, &req);
4866 cm_ReleaseSCache(newScp);
4867 cm_ReleaseUser(userp);
4872 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4876 cm_scache_t *rootScp;
4877 cm_scache_t *newScp, *dscp;
4889 pathp = smb_GetSMBData(inp, NULL);
4890 pathp = smb_ParseASCIIBlock(pathp, NULL);
4892 return CM_ERROR_BADSMB;
4894 if (*pathp == 0) /* null path */
4897 if (smb_StoreAnsiFilenames)
4898 OemToChar(pathp,pathp);
4900 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4901 osi_LogSaveString(smb_logp, pathp));
4903 rootScp = cm_data.rootSCachep;
4905 userp = smb_GetUserFromVCP(vcp, inp);
4907 /* we shouldn't need this for V3 requests, but we seem to */
4908 caseFold = CM_FLAG_CASEFOLD;
4910 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4912 cm_ReleaseUser(userp);
4913 return CM_ERROR_NOSUCHFILE;
4917 * XXX Strange hack XXX
4919 * As of Patch 5 (16 July 97), we are having the following problem:
4920 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4921 * requests to look up "desktop.ini" in all the subdirectories.
4922 * This can cause zillions of timeouts looking up non-existent cells
4923 * and volumes, especially in the top-level directory.
4925 * We have not found any way to avoid this or work around it except
4926 * to explicitly ignore the requests for mount points that haven't
4927 * yet been evaluated and for directories that haven't yet been
4930 * We should modify this hack to provide a fake desktop.ini file
4931 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4933 spacep = inp->spacep;
4934 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4935 #ifndef SPECIAL_FOLDERS
4936 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4937 code = cm_NameI(rootScp, spacep->data,
4938 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4939 userp, tidPathp, &req, &dscp);
4942 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4943 if ( WANTS_DFS_PATHNAMES(inp) )
4944 return CM_ERROR_PATH_NOT_COVERED;
4946 return CM_ERROR_BADSHARENAME;
4948 #endif /* DFS_SUPPORT */
4949 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4950 code = CM_ERROR_NOSUCHFILE;
4951 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4952 cm_buf_t *bp = buf_Find(dscp, &hzero);
4957 code = CM_ERROR_NOSUCHFILE;
4959 cm_ReleaseSCache(dscp);
4961 cm_ReleaseUser(userp);
4966 #endif /* SPECIAL_FOLDERS */
4968 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4969 tidPathp, &req, &newScp);
4971 cm_ReleaseUser(userp);
4976 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4977 cm_ReleaseSCache(newScp);
4978 cm_ReleaseUser(userp);
4979 if ( WANTS_DFS_PATHNAMES(inp) )
4980 return CM_ERROR_PATH_NOT_COVERED;
4982 return CM_ERROR_BADSHARENAME;
4984 #endif /* DFS_SUPPORT */
4986 /* now lock the vnode with a callback; returns with newScp locked */
4987 lock_ObtainMutex(&newScp->mx);
4988 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4989 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4991 lock_ReleaseMutex(&newScp->mx);
4992 cm_ReleaseSCache(newScp);
4993 cm_ReleaseUser(userp);
4997 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5000 /* use smb_Attributes instead. Also the fact that a file is
5001 * in a readonly volume doesn't mean it shojuld be marked as RO
5003 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5004 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5005 newScp->fileType == CM_SCACHETYPE_INVALID)
5006 attrs = SMB_ATTR_DIRECTORY;
5009 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
5010 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
5012 attrs = smb_Attributes(newScp);
5015 smb_SetSMBParm(outp, 0, attrs);
5017 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5018 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5019 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5020 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5021 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5022 smb_SetSMBParm(outp, 5, 0);
5023 smb_SetSMBParm(outp, 6, 0);
5024 smb_SetSMBParm(outp, 7, 0);
5025 smb_SetSMBParm(outp, 8, 0);
5026 smb_SetSMBParm(outp, 9, 0);
5027 smb_SetSMBDataLength(outp, 0);
5028 lock_ReleaseMutex(&newScp->mx);
5030 cm_ReleaseSCache(newScp);
5031 cm_ReleaseUser(userp);
5036 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5040 osi_Log0(smb_logp, "SMB receive tree disconnect");
5042 /* find the tree and free it */
5043 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5045 lock_ObtainWrite(&smb_rctLock);
5047 lock_ReleaseWrite(&smb_rctLock);
5048 smb_ReleaseTID(tidp);
5054 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5072 pathp = smb_GetSMBData(inp, NULL);
5073 pathp = smb_ParseASCIIBlock(pathp, NULL);
5074 if (smb_StoreAnsiFilenames)
5075 OemToChar(pathp,pathp);
5077 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
5079 #ifdef DEBUG_VERBOSE
5083 hexpath = osi_HexifyString( pathp );
5084 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5089 share = smb_GetSMBParm(inp, 0);
5090 attribute = smb_GetSMBParm(inp, 1);
5092 spacep = inp->spacep;
5093 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5094 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5095 /* special case magic file name for receiving IOCTL requests
5096 * (since IOCTL calls themselves aren't getting through).
5098 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5099 smb_SetupIoctlFid(fidp, spacep);
5100 smb_SetSMBParm(outp, 0, fidp->fid);
5101 smb_SetSMBParm(outp, 1, 0); /* attrs */
5102 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5103 smb_SetSMBParm(outp, 3, 0);
5104 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5105 smb_SetSMBParm(outp, 5, 0x7fff);
5106 /* pass the open mode back */
5107 smb_SetSMBParm(outp, 6, (share & 0xf));
5108 smb_SetSMBDataLength(outp, 0);
5109 smb_ReleaseFID(fidp);
5113 userp = smb_GetUserFromVCP(vcp, inp);
5115 caseFold = CM_FLAG_CASEFOLD;
5117 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5119 cm_ReleaseUser(userp);
5120 return CM_ERROR_NOSUCHPATH;
5122 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5123 tidPathp, &req, &scp);
5126 cm_ReleaseUser(userp);
5131 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5132 cm_ReleaseSCache(scp);
5133 cm_ReleaseUser(userp);
5134 if ( WANTS_DFS_PATHNAMES(inp) )
5135 return CM_ERROR_PATH_NOT_COVERED;
5137 return CM_ERROR_BADSHARENAME;
5139 #endif /* DFS_SUPPORT */
5141 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5143 cm_ReleaseSCache(scp);
5144 cm_ReleaseUser(userp);
5148 /* don't need callback to check file type, since file types never
5149 * change, and namei and cm_Lookup all stat the object at least once on
5150 * a successful return.
5152 if (scp->fileType != CM_SCACHETYPE_FILE) {
5153 cm_ReleaseSCache(scp);
5154 cm_ReleaseUser(userp);
5155 return CM_ERROR_ISDIR;
5158 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5159 osi_assertx(fidp, "null smb_fid_t");
5161 /* save a pointer to the vnode */
5163 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5164 lock_ObtainMutex(&scp->mx);
5165 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5166 lock_ReleaseMutex(&scp->mx);
5170 fidp->userp = userp;
5172 lock_ObtainMutex(&fidp->mx);
5173 if ((share & 0xf) == 0)
5174 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5175 else if ((share & 0xf) == 1)
5176 fidp->flags |= SMB_FID_OPENWRITE;
5178 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5179 lock_ReleaseMutex(&fidp->mx);
5181 lock_ObtainMutex(&scp->mx);
5182 smb_SetSMBParm(outp, 0, fidp->fid);
5183 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5184 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5185 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5186 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5187 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5188 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5189 /* pass the open mode back; XXXX add access checks */
5190 smb_SetSMBParm(outp, 6, (share & 0xf));
5191 smb_SetSMBDataLength(outp, 0);
5192 lock_ReleaseMutex(&scp->mx);
5195 cm_Open(scp, 0, userp);
5197 /* send and free packet */
5198 smb_ReleaseFID(fidp);
5199 cm_ReleaseUser(userp);
5200 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5204 typedef struct smb_unlinkRock {
5209 char *maskp; /* pointer to the star pattern */
5212 cm_dirEntryList_t * matches;
5215 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5218 smb_unlinkRock_t *rockp;
5226 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5227 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5228 caseFold |= CM_FLAG_8DOT3;
5230 matchName = dep->name;
5231 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
5233 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5234 !cm_Is8Dot3(dep->name)) {
5235 cm_Gen8Dot3Name(dep, shortName, NULL);
5236 matchName = shortName;
5237 /* 8.3 matches are always case insensitive */
5238 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5241 osi_Log1(smb_logp, "Found match %s",
5242 osi_LogSaveString(smb_logp, matchName));
5244 cm_DirEntryListAdd(dep->name, &rockp->matches);
5248 /* If we made a case sensitive exact match, we might as well quit now. */
5249 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
5250 code = CM_ERROR_STOPNOW;
5259 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5268 smb_unlinkRock_t rock;
5277 attribute = smb_GetSMBParm(inp, 0);
5279 tp = smb_GetSMBData(inp, NULL);
5280 pathp = smb_ParseASCIIBlock(tp, &tp);
5281 if (smb_StoreAnsiFilenames)
5282 OemToChar(pathp,pathp);
5284 osi_Log1(smb_logp, "SMB receive unlink %s",
5285 osi_LogSaveString(smb_logp, pathp));
5287 spacep = inp->spacep;
5288 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5290 userp = smb_GetUserFromVCP(vcp, inp);
5292 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5294 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5296 cm_ReleaseUser(userp);
5297 return CM_ERROR_NOSUCHPATH;
5299 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5302 cm_ReleaseUser(userp);
5307 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5308 cm_ReleaseSCache(dscp);
5309 cm_ReleaseUser(userp);
5310 if ( WANTS_DFS_PATHNAMES(inp) )
5311 return CM_ERROR_PATH_NOT_COVERED;
5313 return CM_ERROR_BADSHARENAME;
5315 #endif /* DFS_SUPPORT */
5317 /* otherwise, scp points to the parent directory. */
5324 rock.maskp = smb_FindMask(pathp);
5325 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5328 thyper.HighPart = 0;
5333 rock.matches = NULL;
5335 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5336 * match. If that fails, we do a case insensitve match.
5338 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5339 !smb_IsStarMask(rock.maskp)) {
5340 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5343 thyper.HighPart = 0;
5344 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5349 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5351 if (code == CM_ERROR_STOPNOW)
5354 if (code == 0 && rock.matches) {
5355 cm_dirEntryList_t * entry;
5357 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5359 osi_Log1(smb_logp, "Unlinking %s",
5360 osi_LogSaveString(smb_logp, entry->name));
5361 code = cm_Unlink(dscp, entry->name, userp, &req);
5363 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5364 smb_NotifyChange(FILE_ACTION_REMOVED,
5365 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5366 dscp, entry->name, NULL, TRUE);
5370 cm_DirEntryListFree(&rock.matches);
5372 cm_ReleaseUser(userp);
5374 cm_ReleaseSCache(dscp);
5376 if (code == 0 && !rock.any)
5377 code = CM_ERROR_NOSUCHFILE;
5381 typedef struct smb_renameRock {
5382 cm_scache_t *odscp; /* old dir */
5383 cm_scache_t *ndscp; /* new dir */
5384 cm_user_t *userp; /* user */
5385 cm_req_t *reqp; /* request struct */
5386 smb_vc_t *vcp; /* virtual circuit */
5387 char *maskp; /* pointer to star pattern of old file name */
5388 int flags; /* tilde, casefold, etc */
5389 char *newNamep; /* ptr to the new file's name */
5390 char oldName[MAX_PATH];
5394 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5397 smb_renameRock_t *rockp;
5400 char shortName[13]="";
5402 rockp = (smb_renameRock_t *) vrockp;
5404 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5405 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5406 caseFold |= CM_FLAG_8DOT3;
5408 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5410 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5411 !cm_Is8Dot3(dep->name)) {
5412 cm_Gen8Dot3Name(dep, shortName, NULL);
5413 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5418 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5419 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5420 code = CM_ERROR_STOPNOW;
5430 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5433 cm_space_t *spacep = NULL;
5434 smb_renameRock_t rock;
5435 cm_scache_t *oldDscp = NULL;
5436 cm_scache_t *newDscp = NULL;
5437 cm_scache_t *tmpscp= NULL;
5438 cm_scache_t *tmpscp2 = NULL;
5448 userp = smb_GetUserFromVCP(vcp, inp);
5449 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5451 cm_ReleaseUser(userp);
5452 return CM_ERROR_NOSUCHPATH;
5456 spacep = inp->spacep;
5457 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5459 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5460 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5461 userp, tidPathp, &req, &oldDscp);
5463 cm_ReleaseUser(userp);
5468 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5469 cm_ReleaseSCache(oldDscp);
5470 cm_ReleaseUser(userp);
5471 if ( WANTS_DFS_PATHNAMES(inp) )
5472 return CM_ERROR_PATH_NOT_COVERED;
5474 return CM_ERROR_BADSHARENAME;
5476 #endif /* DFS_SUPPORT */
5478 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5479 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5480 userp, tidPathp, &req, &newDscp);
5483 cm_ReleaseSCache(oldDscp);
5484 cm_ReleaseUser(userp);
5489 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5490 cm_ReleaseSCache(oldDscp);
5491 cm_ReleaseSCache(newDscp);
5492 cm_ReleaseUser(userp);
5493 if ( WANTS_DFS_PATHNAMES(inp) )
5494 return CM_ERROR_PATH_NOT_COVERED;
5496 return CM_ERROR_BADSHARENAME;
5498 #endif /* DFS_SUPPORT */
5501 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5502 * next, get the component names, and lower case them.
5505 /* handle the old name first */
5507 oldLastNamep = oldPathp;
5511 /* and handle the new name, too */
5513 newLastNamep = newPathp;
5517 /* TODO: The old name could be a wildcard. The new name must not be */
5519 /* do the vnode call */
5520 rock.odscp = oldDscp;
5521 rock.ndscp = newDscp;
5525 rock.maskp = oldLastNamep;
5526 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5527 rock.newNamep = newLastNamep;
5528 rock.oldName[0] = '\0';
5531 /* Check if the file already exists; if so return error */
5532 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5533 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5534 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5536 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5537 osi_LogSaveString(smb_logp, newLastNamep));
5539 /* Check if the old and the new names differ only in case. If so return
5540 * success, else return CM_ERROR_EXISTS
5542 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5544 /* This would be a success only if the old file is *as same as* the new file */
5545 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5547 if (tmpscp == tmpscp2)
5550 code = CM_ERROR_EXISTS;
5551 cm_ReleaseSCache(tmpscp2);
5554 code = CM_ERROR_NOSUCHFILE;
5557 /* file exist, do not rename, also fixes move */
5558 osi_Log0(smb_logp, "Can't rename. Target already exists");
5559 code = CM_ERROR_EXISTS;
5563 cm_ReleaseSCache(tmpscp);
5564 cm_ReleaseSCache(newDscp);
5565 cm_ReleaseSCache(oldDscp);
5566 cm_ReleaseUser(userp);
5570 /* Now search the directory for the pattern, and do the appropriate rename when found */
5571 thyper.LowPart = 0; /* search dir from here */
5572 thyper.HighPart = 0;
5574 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5575 if (code == 0 && !rock.any) {
5577 thyper.HighPart = 0;
5578 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5579 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5581 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5583 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5584 code = cm_Rename(rock.odscp, rock.oldName,
5585 rock.ndscp, rock.newNamep, rock.userp,
5587 /* if the call worked, stop doing the search now, since we
5588 * really only want to rename one file.
5590 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5591 } else if (code == 0) {
5592 code = CM_ERROR_NOSUCHFILE;
5595 /* Handle Change Notification */
5597 * Being lazy, not distinguishing between files and dirs in this
5598 * filter, since we'd have to do a lookup.
5601 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5602 if (oldDscp == newDscp) {
5603 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5604 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5605 filter, oldDscp, oldLastNamep,
5606 newLastNamep, TRUE);
5608 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5609 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5610 filter, oldDscp, oldLastNamep,
5612 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5613 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5614 filter, newDscp, newLastNamep,
5620 cm_ReleaseSCache(tmpscp);
5621 cm_ReleaseUser(userp);
5622 cm_ReleaseSCache(oldDscp);
5623 cm_ReleaseSCache(newDscp);
5628 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5631 cm_space_t *spacep = NULL;
5632 cm_scache_t *oldDscp = NULL;
5633 cm_scache_t *newDscp = NULL;
5634 cm_scache_t *tmpscp= NULL;
5635 cm_scache_t *tmpscp2 = NULL;
5636 cm_scache_t *sscp = NULL;
5645 userp = smb_GetUserFromVCP(vcp, inp);
5647 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5649 cm_ReleaseUser(userp);
5650 return CM_ERROR_NOSUCHPATH;
5655 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5657 spacep = inp->spacep;
5658 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5660 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5661 userp, tidPathp, &req, &oldDscp);
5663 cm_ReleaseUser(userp);
5668 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5669 cm_ReleaseSCache(oldDscp);
5670 cm_ReleaseUser(userp);
5671 if ( WANTS_DFS_PATHNAMES(inp) )
5672 return CM_ERROR_PATH_NOT_COVERED;
5674 return CM_ERROR_BADSHARENAME;
5676 #endif /* DFS_SUPPORT */
5678 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5679 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5680 userp, tidPathp, &req, &newDscp);
5682 cm_ReleaseSCache(oldDscp);
5683 cm_ReleaseUser(userp);
5688 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5689 cm_ReleaseSCache(newDscp);
5690 cm_ReleaseSCache(oldDscp);
5691 cm_ReleaseUser(userp);
5692 if ( WANTS_DFS_PATHNAMES(inp) )
5693 return CM_ERROR_PATH_NOT_COVERED;
5695 return CM_ERROR_BADSHARENAME;
5697 #endif /* DFS_SUPPORT */
5699 /* Now, although we did two lookups for the two directories (because the same
5700 * directory can be referenced through different paths), we only allow hard links
5701 * within the same directory. */
5702 if (oldDscp != newDscp) {
5703 cm_ReleaseSCache(oldDscp);
5704 cm_ReleaseSCache(newDscp);
5705 cm_ReleaseUser(userp);
5706 return CM_ERROR_CROSSDEVLINK;
5709 /* handle the old name first */
5711 oldLastNamep = oldPathp;
5715 /* and handle the new name, too */
5717 newLastNamep = newPathp;
5721 /* now lookup the old name */
5722 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5723 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5725 cm_ReleaseSCache(oldDscp);
5726 cm_ReleaseSCache(newDscp);
5727 cm_ReleaseUser(userp);
5731 /* Check if the file already exists; if so return error */
5732 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5733 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5734 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5736 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5737 osi_LogSaveString(smb_logp, newLastNamep));
5739 /* if the existing link is to the same file, then we return success */
5741 if(sscp == tmpscp) {
5744 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5745 code = CM_ERROR_EXISTS;
5750 cm_ReleaseSCache(tmpscp);
5751 cm_ReleaseSCache(sscp);
5752 cm_ReleaseSCache(newDscp);
5753 cm_ReleaseSCache(oldDscp);
5754 cm_ReleaseUser(userp);
5758 /* now create the hardlink */
5759 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5760 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5761 osi_Log1(smb_logp," Link returns 0x%x", code);
5763 /* Handle Change Notification */
5765 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5766 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5767 smb_NotifyChange(FILE_ACTION_ADDED,
5768 filter, newDscp, newLastNamep,
5773 cm_ReleaseSCache(tmpscp);
5774 cm_ReleaseUser(userp);
5775 cm_ReleaseSCache(sscp);
5776 cm_ReleaseSCache(oldDscp);
5777 cm_ReleaseSCache(newDscp);
5782 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5789 tp = smb_GetSMBData(inp, NULL);
5790 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5791 if (smb_StoreAnsiFilenames)
5792 OemToChar(oldPathp,oldPathp);
5793 newPathp = smb_ParseASCIIBlock(tp, &tp);
5794 if (smb_StoreAnsiFilenames)
5795 OemToChar(newPathp,newPathp);
5797 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5798 osi_LogSaveString(smb_logp, oldPathp),
5799 osi_LogSaveString(smb_logp, newPathp));
5801 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5803 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5809 typedef struct smb_rmdirRock {
5813 char *maskp; /* pointer to the star pattern */
5816 cm_dirEntryList_t * matches;
5819 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5822 smb_rmdirRock_t *rockp;
5827 rockp = (smb_rmdirRock_t *) vrockp;
5829 matchName = dep->name;
5830 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5831 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5833 match = (strcmp(matchName, rockp->maskp) == 0);
5835 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5836 !cm_Is8Dot3(dep->name)) {
5837 cm_Gen8Dot3Name(dep, shortName, NULL);
5838 matchName = shortName;
5839 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5844 cm_DirEntryListAdd(dep->name, &rockp->matches);
5850 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5858 smb_rmdirRock_t rock;
5867 tp = smb_GetSMBData(inp, NULL);
5868 pathp = smb_ParseASCIIBlock(tp, &tp);
5869 if (smb_StoreAnsiFilenames)
5870 OemToChar(pathp,pathp);
5872 spacep = inp->spacep;
5873 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5875 userp = smb_GetUserFromVCP(vcp, inp);
5877 caseFold = CM_FLAG_CASEFOLD;
5879 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5881 cm_ReleaseUser(userp);
5882 return CM_ERROR_NOSUCHPATH;
5884 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5885 userp, tidPathp, &req, &dscp);
5888 cm_ReleaseUser(userp);
5893 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5894 cm_ReleaseSCache(dscp);
5895 cm_ReleaseUser(userp);
5896 if ( WANTS_DFS_PATHNAMES(inp) )
5897 return CM_ERROR_PATH_NOT_COVERED;
5899 return CM_ERROR_BADSHARENAME;
5901 #endif /* DFS_SUPPORT */
5903 /* otherwise, scp points to the parent directory. */
5910 rock.maskp = lastNamep;
5911 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5914 thyper.HighPart = 0;
5918 rock.matches = NULL;
5920 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5921 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5922 if (code == 0 && !rock.any) {
5924 thyper.HighPart = 0;
5925 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5926 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5929 if (code == 0 && rock.matches) {
5930 cm_dirEntryList_t * entry;
5932 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5933 osi_Log1(smb_logp, "Removing directory %s",
5934 osi_LogSaveString(smb_logp, entry->name));
5936 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5938 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5939 smb_NotifyChange(FILE_ACTION_REMOVED,
5940 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5941 dscp, entry->name, NULL, TRUE);
5945 cm_DirEntryListFree(&rock.matches);
5947 cm_ReleaseUser(userp);
5949 cm_ReleaseSCache(dscp);
5951 if (code == 0 && !rock.any)
5952 code = CM_ERROR_NOSUCHFILE;
5956 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5966 fid = smb_GetSMBParm(inp, 0);
5968 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5970 fid = smb_ChainFID(fid, inp);
5971 fidp = smb_FindFID(vcp, fid, 0);
5973 return CM_ERROR_BADFD;
5975 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5976 smb_CloseFID(vcp, fidp, NULL, 0);
5977 smb_ReleaseFID(fidp);
5978 return CM_ERROR_NOSUCHFILE;
5981 lock_ObtainMutex(&fidp->mx);
5982 if (fidp->flags & SMB_FID_IOCTL) {
5983 lock_ReleaseMutex(&fidp->mx);
5984 smb_ReleaseFID(fidp);
5985 return CM_ERROR_BADFD;
5987 lock_ReleaseMutex(&fidp->mx);
5989 userp = smb_GetUserFromVCP(vcp, inp);
5991 lock_ObtainMutex(&fidp->mx);
5992 if (fidp->flags & SMB_FID_OPENWRITE) {
5993 cm_scache_t * scp = fidp->scp;
5995 lock_ReleaseMutex(&fidp->mx);
5996 code = cm_FSync(scp, userp, &req);
5997 cm_ReleaseSCache(scp);
6000 lock_ReleaseMutex(&fidp->mx);
6003 smb_ReleaseFID(fidp);
6005 cm_ReleaseUser(userp);
6010 struct smb_FullNameRock {
6016 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6020 struct smb_FullNameRock *vrockp;
6022 vrockp = (struct smb_FullNameRock *)rockp;
6024 if (!cm_Is8Dot3(dep->name)) {
6025 cm_Gen8Dot3Name(dep, shortName, NULL);
6027 if (cm_stricmp(shortName, vrockp->name) == 0) {
6028 vrockp->fullName = strdup(dep->name);
6029 return CM_ERROR_STOPNOW;
6032 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
6033 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6034 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6035 vrockp->fullName = strdup(dep->name);
6036 return CM_ERROR_STOPNOW;
6041 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
6042 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
6044 struct smb_FullNameRock rock;
6050 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6051 if (code == CM_ERROR_STOPNOW)
6052 *newPathp = rock.fullName;
6054 *newPathp = strdup(pathp);
6057 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6058 afs_uint32 dosTime) {
6061 cm_scache_t *dscp = NULL;
6063 cm_scache_t * scp = NULL;
6064 cm_scache_t *delscp = NULL;
6066 int nullcreator = 0;
6068 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6069 fidp, fidp->fid, scp, vcp);
6072 lock_ObtainMutex(&fidp->mx);
6073 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6074 lock_ReleaseMutex(&fidp->mx);
6075 osi_Log0(smb_logp, " No user specified. Not closing fid");
6076 return CM_ERROR_BADFD;
6079 userp = fidp->userp; /* no hold required since fidp is held
6080 throughout the function */
6081 lock_ReleaseMutex(&fidp->mx);
6086 lock_ObtainWrite(&smb_rctLock);
6088 osi_Log0(smb_logp, " Fid already closed.");
6089 lock_ReleaseWrite(&smb_rctLock);
6090 return CM_ERROR_BADFD;
6093 lock_ReleaseWrite(&smb_rctLock);
6095 lock_ObtainMutex(&fidp->mx);
6096 if (fidp->NTopen_dscp) {
6097 dscp = fidp->NTopen_dscp;
6098 cm_HoldSCache(dscp);
6101 if (fidp->NTopen_pathp) {
6102 pathp = strdup(fidp->NTopen_pathp);
6110 /* Don't jump the gun on an async raw write */
6111 while (fidp->raw_writers) {
6112 lock_ReleaseMutex(&fidp->mx);
6113 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6114 lock_ObtainMutex(&fidp->mx);
6117 /* watch for ioctl closes, and read-only opens */
6119 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6120 == SMB_FID_OPENWRITE) {
6121 if (dosTime != 0 && dosTime != -1) {
6122 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6123 /* This fixes defect 10958 */
6124 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6125 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6127 lock_ReleaseMutex(&fidp->mx);
6128 code = cm_FSync(scp, userp, &req);
6129 lock_ObtainMutex(&fidp->mx);
6134 /* unlock any pending locks */
6135 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6136 scp->fileType == CM_SCACHETYPE_FILE) {
6140 lock_ReleaseMutex(&fidp->mx);
6142 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6144 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6145 lock_ObtainMutex(&scp->mx);
6147 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6148 CM_SCACHESYNC_NEEDCALLBACK
6149 | CM_SCACHESYNC_GETSTATUS
6150 | CM_SCACHESYNC_LOCK);
6154 "smb CoreClose SyncOp failure code 0x%x", tcode);
6155 goto post_syncopdone;
6158 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6160 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6164 lock_ReleaseMutex(&scp->mx);
6165 lock_ObtainMutex(&fidp->mx);
6168 if (fidp->flags & SMB_FID_DELONCLOSE) {
6171 lock_ReleaseMutex(&fidp->mx);
6173 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6178 smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
6179 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6180 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
6183 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6184 smb_NotifyChange(FILE_ACTION_REMOVED,
6185 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6186 dscp, fullPathp, NULL, TRUE);
6189 code = cm_Unlink(dscp, fullPathp, userp, &req);
6192 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6193 smb_NotifyChange(FILE_ACTION_REMOVED,
6194 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6195 dscp, fullPathp, NULL, TRUE);
6199 lock_ObtainMutex(&fidp->mx);
6200 fidp->flags &= ~SMB_FID_DELONCLOSE;
6203 /* if this was a newly created file, then clear the creator
6204 * in the stat cache entry. */
6205 if (fidp->flags & SMB_FID_CREATED) {
6207 fidp->flags &= ~SMB_FID_CREATED;
6210 if (fidp->flags & SMB_FID_NTOPEN) {
6211 cm_ReleaseSCache(fidp->NTopen_dscp);
6212 fidp->NTopen_dscp = NULL;
6213 free(fidp->NTopen_pathp);
6214 fidp->NTopen_pathp = NULL;
6215 fidp->flags &= ~SMB_FID_NTOPEN;
6217 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6218 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6221 if (fidp->NTopen_wholepathp) {
6222 free(fidp->NTopen_wholepathp);
6223 fidp->NTopen_wholepathp = NULL;
6227 cm_ReleaseSCache(fidp->scp);
6230 lock_ReleaseMutex(&fidp->mx);
6233 cm_ReleaseSCache(dscp);
6237 lock_ObtainMutex(&delscp->mx);
6239 delscp->flags |= CM_SCACHEFLAG_DELETED;
6240 lock_ReleaseMutex(&delscp->mx);
6242 cm_ReleaseSCache(delscp);
6246 lock_ObtainMutex(&scp->mx);
6247 if (nullcreator && scp->creator == userp)
6248 scp->creator = NULL;
6249 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6250 lock_ReleaseMutex(&scp->mx);
6251 cm_ReleaseSCache(scp);
6260 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6268 fid = smb_GetSMBParm(inp, 0);
6269 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6271 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6273 fid = smb_ChainFID(fid, inp);
6274 fidp = smb_FindFID(vcp, fid, 0);
6276 return CM_ERROR_BADFD;
6279 userp = smb_GetUserFromVCP(vcp, inp);
6281 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6283 smb_ReleaseFID(fidp);
6284 cm_ReleaseUser(userp);
6289 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6292 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6293 cm_user_t *userp, long *readp)
6295 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6296 cm_user_t *userp, long *readp, int dosflag)
6303 osi_hyper_t fileLength;
6305 osi_hyper_t lastByte;
6306 osi_hyper_t bufferOffset;
6307 long bufIndex, nbytes;
6309 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6317 lock_ObtainMutex(&fidp->mx);
6320 lock_ObtainMutex(&scp->mx);
6322 if (offset.HighPart == 0) {
6323 chunk = offset.LowPart >> cm_logChunkSize;
6324 if (chunk != fidp->curr_chunk) {
6325 fidp->prev_chunk = fidp->curr_chunk;
6326 fidp->curr_chunk = chunk;
6328 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6331 lock_ReleaseMutex(&fidp->mx);
6333 /* start by looking up the file's end */
6334 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6335 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6339 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6341 /* now we have the entry locked, look up the length */
6342 fileLength = scp->length;
6344 /* adjust count down so that it won't go past EOF */
6345 thyper.LowPart = count;
6346 thyper.HighPart = 0;
6347 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6349 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6350 /* we'd read past EOF, so just stop at fileLength bytes.
6351 * Start by computing how many bytes remain in the file.
6353 thyper = LargeIntegerSubtract(fileLength, offset);
6355 /* if we are past EOF, read 0 bytes */
6356 if (LargeIntegerLessThanZero(thyper))
6359 count = thyper.LowPart;
6364 /* now, copy the data one buffer at a time,
6365 * until we've filled the request packet
6368 /* if we've copied all the data requested, we're done */
6369 if (count <= 0) break;
6371 /* otherwise, load up a buffer of data */
6372 thyper.HighPart = offset.HighPart;
6373 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6374 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6377 buf_Release(bufferp);
6380 lock_ReleaseMutex(&scp->mx);
6382 lock_ObtainRead(&scp->bufCreateLock);
6383 code = buf_Get(scp, &thyper, &bufferp);
6384 lock_ReleaseRead(&scp->bufCreateLock);
6386 lock_ObtainMutex(&scp->mx);
6387 if (code) goto done;
6388 bufferOffset = thyper;
6390 /* now get the data in the cache */
6392 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6393 CM_SCACHESYNC_NEEDCALLBACK |
6394 CM_SCACHESYNC_READ);
6398 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6400 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6402 /* otherwise, load the buffer and try again */
6403 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6407 buf_Release(bufferp);
6411 } /* if (wrong buffer) ... */
6413 /* now we have the right buffer loaded. Copy out the
6414 * data from here to the user's buffer.
6416 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6418 /* and figure out how many bytes we want from this buffer */
6419 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6420 if (nbytes > count) nbytes = count; /* don't go past EOF */
6422 /* now copy the data */
6425 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
6428 memcpy(op, bufferp->datap + bufIndex, nbytes);
6430 /* adjust counters, pointers, etc. */
6433 thyper.LowPart = nbytes;
6434 thyper.HighPart = 0;
6435 offset = LargeIntegerAdd(thyper, offset);
6439 lock_ReleaseMutex(&scp->mx);
6441 buf_Release(bufferp);
6443 if (code == 0 && sequential)
6444 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6446 cm_ReleaseSCache(scp);
6452 * smb_WriteData -- common code for Write and Raw Write
6455 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6456 cm_user_t *userp, long *writtenp)
6458 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6459 cm_user_t *userp, long *writtenp, int dosflag)
6466 osi_hyper_t fileLength; /* file's length at start of write */
6467 osi_hyper_t minLength; /* don't read past this */
6468 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6470 osi_hyper_t thyper; /* hyper tmp variable */
6471 osi_hyper_t bufferOffset;
6472 afs_uint32 bufIndex; /* index in buffer where our data is */
6474 osi_hyper_t writeBackOffset;/* offset of region to write back when
6479 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6480 fidp->fid, offsetp->LowPart, count);
6490 lock_ObtainMutex(&fidp->mx);
6491 /* make sure we have a writable FD */
6492 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6493 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6494 fidp->fid, fidp->flags);
6495 lock_ReleaseMutex(&fidp->mx);
6496 code = CM_ERROR_BADFDOP;
6502 lock_ReleaseMutex(&fidp->mx);
6504 lock_ObtainMutex(&scp->mx);
6505 /* start by looking up the file's end */
6506 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6507 CM_SCACHESYNC_NEEDCALLBACK
6508 | CM_SCACHESYNC_SETSTATUS
6509 | CM_SCACHESYNC_GETSTATUS);
6513 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6515 /* now we have the entry locked, look up the length */
6516 fileLength = scp->length;
6517 minLength = fileLength;
6518 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6519 minLength = scp->serverLength;
6521 /* adjust file length if we extend past EOF */
6522 thyper.LowPart = count;
6523 thyper.HighPart = 0;
6524 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6525 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6526 /* we'd write past EOF, so extend the file */
6527 scp->mask |= CM_SCACHEMASK_LENGTH;
6528 scp->length = thyper;
6529 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6531 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6533 /* now, if the new position (thyper) and the old (offset) are in
6534 * different storeback windows, remember to store back the previous
6535 * storeback window when we're done with the write.
6537 if ((thyper.LowPart & (-cm_chunkSize)) !=
6538 (offset.LowPart & (-cm_chunkSize))) {
6539 /* they're different */
6541 writeBackOffset.HighPart = offset.HighPart;
6542 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6547 /* now, copy the data one buffer at a time, until we've filled the
6550 /* if we've copied all the data requested, we're done */
6554 /* handle over quota or out of space */
6555 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6556 *writtenp = written;
6557 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6561 /* otherwise, load up a buffer of data */
6562 thyper.HighPart = offset.HighPart;
6563 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6564 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6567 lock_ReleaseMutex(&bufferp->mx);
6568 buf_Release(bufferp);
6571 lock_ReleaseMutex(&scp->mx);
6573 lock_ObtainRead(&scp->bufCreateLock);
6574 code = buf_Get(scp, &thyper, &bufferp);
6575 lock_ReleaseRead(&scp->bufCreateLock);
6577 lock_ObtainMutex(&bufferp->mx);
6578 lock_ObtainMutex(&scp->mx);
6579 if (code) goto done;
6581 bufferOffset = thyper;
6583 /* now get the data in the cache */
6585 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6586 CM_SCACHESYNC_NEEDCALLBACK
6587 | CM_SCACHESYNC_WRITE
6588 | CM_SCACHESYNC_BUFLOCKED);
6592 cm_SyncOpDone(scp, bufferp,
6593 CM_SCACHESYNC_NEEDCALLBACK
6594 | CM_SCACHESYNC_WRITE
6595 | CM_SCACHESYNC_BUFLOCKED);
6597 /* If we're overwriting the entire buffer, or
6598 * if we're writing at or past EOF, mark the
6599 * buffer as current so we don't call
6600 * cm_GetBuffer. This skips the fetch from the
6601 * server in those cases where we're going to
6602 * obliterate all the data in the buffer anyway,
6603 * or in those cases where there is no useful
6604 * data at the server to start with.
6606 * Use minLength instead of scp->length, since
6607 * the latter has already been updated by this
6610 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6611 || LargeIntegerEqualTo(offset, bufferp->offset)
6612 && (count >= cm_data.buf_blockSize
6613 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6614 ConvertLongToLargeInteger(count)),
6616 if (count < cm_data.buf_blockSize
6617 && bufferp->dataVersion == -1)
6618 memset(bufferp->datap, 0,
6619 cm_data.buf_blockSize);
6620 bufferp->dataVersion = scp->dataVersion;
6623 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6625 /* otherwise, load the buffer and try again */
6626 lock_ReleaseMutex(&bufferp->mx);
6627 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6629 lock_ReleaseMutex(&scp->mx);
6630 lock_ObtainMutex(&bufferp->mx);
6631 lock_ObtainMutex(&scp->mx);
6635 lock_ReleaseMutex(&bufferp->mx);
6636 buf_Release(bufferp);
6640 } /* if (wrong buffer) ... */
6642 /* now we have the right buffer loaded. Copy out the
6643 * data from here to the user's buffer.
6645 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6647 /* and figure out how many bytes we want from this buffer */
6648 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6650 nbytes = count; /* don't go past end of request */
6652 /* now copy the data */
6655 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
6658 memcpy(bufferp->datap + bufIndex, op, nbytes);
6659 buf_SetDirty(bufferp, bufIndex, nbytes);
6661 /* and record the last writer */
6662 if (bufferp->userp != userp) {
6665 cm_ReleaseUser(bufferp->userp);
6666 bufferp->userp = userp;
6669 /* adjust counters, pointers, etc. */
6673 thyper.LowPart = nbytes;
6674 thyper.HighPart = 0;
6675 offset = LargeIntegerAdd(thyper, offset);
6679 lock_ReleaseMutex(&scp->mx);
6682 lock_ReleaseMutex(&bufferp->mx);
6683 buf_Release(bufferp);
6686 lock_ObtainMutex(&fidp->mx);
6687 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6688 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6689 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6690 fidp->NTopen_dscp, fidp->NTopen_pathp,
6693 lock_ReleaseMutex(&fidp->mx);
6695 if (code == 0 && doWriteBack) {
6697 lock_ObtainMutex(&scp->mx);
6698 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6700 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6701 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6703 lock_ReleaseMutex(&scp->mx);
6704 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6705 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6706 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6709 cm_ReleaseSCache(scp);
6711 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6712 fidp->fid, code, *writtenp);
6716 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6719 unsigned short count;
6721 unsigned short hint;
6722 long written = 0, total_written = 0;
6727 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6729 int inDataBlockCount;
6731 fd = smb_GetSMBParm(inp, 0);
6732 count = smb_GetSMBParm(inp, 1);
6733 offset.HighPart = 0; /* too bad */
6734 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6735 hint = smb_GetSMBParm(inp, 4);
6737 op = smb_GetSMBData(inp, NULL);
6738 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6740 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6741 fd, offset.LowPart, count);
6743 fd = smb_ChainFID(fd, inp);
6744 fidp = smb_FindFID(vcp, fd, 0);
6746 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6747 return CM_ERROR_BADFD;
6750 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6751 smb_CloseFID(vcp, fidp, NULL, 0);
6752 smb_ReleaseFID(fidp);
6753 return CM_ERROR_NOSUCHFILE;
6756 lock_ObtainMutex(&fidp->mx);
6757 if (fidp->flags & SMB_FID_IOCTL) {
6758 lock_ReleaseMutex(&fidp->mx);
6759 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6760 smb_ReleaseFID(fidp);
6761 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6764 lock_ReleaseMutex(&fidp->mx);
6765 userp = smb_GetUserFromVCP(vcp, inp);
6769 LARGE_INTEGER LOffset;
6770 LARGE_INTEGER LLength;
6772 pid = ((smb_t *) inp)->pid;
6773 key = cm_GenerateKey(vcp->vcID, pid, fd);
6775 LOffset.HighPart = offset.HighPart;
6776 LOffset.LowPart = offset.LowPart;
6777 LLength.HighPart = 0;
6778 LLength.LowPart = count;
6780 lock_ObtainMutex(&fidp->scp->mx);
6781 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6782 lock_ReleaseMutex(&fidp->scp->mx);
6785 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6790 /* special case: 0 bytes transferred means truncate to this position */
6794 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6798 truncAttr.mask = CM_ATTRMASK_LENGTH;
6799 truncAttr.length.LowPart = offset.LowPart;
6800 truncAttr.length.HighPart = 0;
6801 lock_ObtainMutex(&fidp->mx);
6802 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6803 fidp->flags |= SMB_FID_LENGTHSETDONE;
6804 lock_ReleaseMutex(&fidp->mx);
6805 smb_SetSMBParm(outp, 0, 0 /* count */);
6806 smb_SetSMBDataLength(outp, 0);
6811 * Work around bug in NT client
6813 * When copying a file, the NT client should first copy the data,
6814 * then copy the last write time. But sometimes the NT client does
6815 * these in the wrong order, so the data copies would inadvertently
6816 * cause the last write time to be overwritten. We try to detect this,
6817 * and don't set client mod time if we think that would go against the
6820 lock_ObtainMutex(&fidp->mx);
6821 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6822 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6823 fidp->scp->clientModTime = time(NULL);
6825 lock_ReleaseMutex(&fidp->mx);
6828 while ( code == 0 && count > 0 ) {
6830 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6832 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6834 if (code == 0 && written == 0)
6835 code = CM_ERROR_PARTIALWRITE;
6837 offset = LargeIntegerAdd(offset,
6838 ConvertLongToLargeInteger(written));
6839 count -= (unsigned short)written;
6840 total_written += written;
6844 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6845 total_written, code);
6847 /* set the packet data length to 3 bytes for the data block header,
6848 * plus the size of the data.
6850 smb_SetSMBParm(outp, 0, total_written);
6851 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6852 smb_SetSMBParm(outp, 3, hint);
6853 smb_SetSMBDataLength(outp, 0);
6856 smb_ReleaseFID(fidp);
6857 cm_ReleaseUser(userp);
6862 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6863 NCB *ncbp, raw_write_cont_t *rwcp)
6876 fd = smb_GetSMBParm(inp, 0);
6877 fidp = smb_FindFID(vcp, fd, 0);
6879 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6880 smb_CloseFID(vcp, fidp, NULL, 0);
6881 smb_ReleaseFID(fidp);
6885 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6886 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6888 userp = smb_GetUserFromVCP(vcp, inp);
6892 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6895 rawBuf = (dos_ptr) rwcp->buf;
6896 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
6897 (unsigned char *) rawBuf, userp,
6901 if (rwcp->writeMode & 0x1) { /* synchronous */
6904 smb_FormatResponsePacket(vcp, inp, outp);
6905 op = (smb_t *) outp;
6906 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6907 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6908 smb_SetSMBDataLength(outp, 0);
6909 smb_SendPacket(vcp, outp);
6910 smb_FreePacket(outp);
6912 else { /* asynchronous */
6913 lock_ObtainMutex(&fidp->mx);
6914 fidp->raw_writers--;
6915 if (fidp->raw_writers == 0)
6916 thrd_SetEvent(fidp->raw_write_event);
6917 lock_ReleaseMutex(&fidp->mx);
6920 /* Give back raw buffer */
6921 lock_ObtainMutex(&smb_RawBufLock);
6923 *((char **)rawBuf) = smb_RawBufs;
6925 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6927 smb_RawBufs = rawBuf;
6928 lock_ReleaseMutex(&smb_RawBufLock);
6930 smb_ReleaseFID(fidp);
6931 cm_ReleaseUser(userp);
6934 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6939 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6942 long count, written = 0, total_written = 0;
6949 unsigned short writeMode;
6956 fd = smb_GetSMBParm(inp, 0);
6957 totalCount = smb_GetSMBParm(inp, 1);
6958 count = smb_GetSMBParm(inp, 10);
6959 writeMode = smb_GetSMBParm(inp, 7);
6961 op = (char *) inp->data;
6962 op += smb_GetSMBParm(inp, 11);
6964 offset.HighPart = 0;
6965 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6967 if (*inp->wctp == 14) {
6968 /* we received a 64-bit file offset */
6969 #ifdef AFS_LARGEFILES
6970 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6972 if (LargeIntegerLessThanZero(offset)) {
6974 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6975 offset.HighPart, offset.LowPart);
6976 return CM_ERROR_BADSMB;
6979 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6981 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6982 return CM_ERROR_BADSMB;
6985 offset.HighPart = 0;
6988 offset.HighPart = 0; /* 32-bit file offset */
6992 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6993 fd, offset.HighPart, offset.LowPart, count);
6995 " WriteRaw WriteMode 0x%x",
6998 fd = smb_ChainFID(fd, inp);
6999 fidp = smb_FindFID(vcp, fd, 0);
7001 return CM_ERROR_BADFD;
7004 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7005 smb_CloseFID(vcp, fidp, NULL, 0);
7006 smb_ReleaseFID(fidp);
7007 return CM_ERROR_NOSUCHFILE;
7013 LARGE_INTEGER LOffset;
7014 LARGE_INTEGER LLength;
7016 pid = ((smb_t *) inp)->pid;
7017 key = cm_GenerateKey(vcp->vcID, pid, fd);
7019 LOffset.HighPart = offset.HighPart;
7020 LOffset.LowPart = offset.LowPart;
7021 LLength.HighPart = 0;
7022 LLength.LowPart = count;
7024 lock_ObtainMutex(&fidp->scp->mx);
7025 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7026 lock_ReleaseMutex(&fidp->scp->mx);
7029 smb_ReleaseFID(fidp);
7034 userp = smb_GetUserFromVCP(vcp, inp);
7037 * Work around bug in NT client
7039 * When copying a file, the NT client should first copy the data,
7040 * then copy the last write time. But sometimes the NT client does
7041 * these in the wrong order, so the data copies would inadvertently
7042 * cause the last write time to be overwritten. We try to detect this,
7043 * and don't set client mod time if we think that would go against the
7046 lock_ObtainMutex(&fidp->mx);
7047 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7048 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7049 fidp->scp->clientModTime = time(NULL);
7051 lock_ReleaseMutex(&fidp->mx);
7054 while ( code == 0 && count > 0 ) {
7056 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7058 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
7060 if (code == 0 && written == 0)
7061 code = CM_ERROR_PARTIALWRITE;
7063 offset = LargeIntegerAdd(offset,
7064 ConvertLongToLargeInteger(written));
7067 total_written += written;
7071 /* Get a raw buffer */
7074 lock_ObtainMutex(&smb_RawBufLock);
7076 /* Get a raw buf, from head of list */
7077 rawBuf = smb_RawBufs;
7079 smb_RawBufs = *(char **)smb_RawBufs;
7081 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
7085 code = CM_ERROR_USESTD;
7087 lock_ReleaseMutex(&smb_RawBufLock);
7090 /* Don't allow a premature Close */
7091 if (code == 0 && (writeMode & 1) == 0) {
7092 lock_ObtainMutex(&fidp->mx);
7093 fidp->raw_writers++;
7094 thrd_ResetEvent(fidp->raw_write_event);
7095 lock_ReleaseMutex(&fidp->mx);
7098 smb_ReleaseFID(fidp);
7099 cm_ReleaseUser(userp);
7102 smb_SetSMBParm(outp, 0, total_written);
7103 smb_SetSMBDataLength(outp, 0);
7104 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7109 offset = LargeIntegerAdd(offset,
7110 ConvertLongToLargeInteger(count));
7114 rwcp->offset.HighPart = offset.HighPart;
7115 rwcp->offset.LowPart = offset.LowPart;
7116 rwcp->count = totalCount - count;
7117 rwcp->writeMode = writeMode;
7118 rwcp->alreadyWritten = total_written;
7120 /* set the packet data length to 3 bytes for the data block header,
7121 * plus the size of the data.
7123 smb_SetSMBParm(outp, 0, 0xffff);
7124 smb_SetSMBDataLength(outp, 0);
7129 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7132 long count, finalCount;
7140 fd = smb_GetSMBParm(inp, 0);
7141 count = smb_GetSMBParm(inp, 1);
7142 offset.HighPart = 0; /* too bad */
7143 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7145 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7146 fd, offset.LowPart, count);
7148 fd = smb_ChainFID(fd, inp);
7149 fidp = smb_FindFID(vcp, fd, 0);
7151 return CM_ERROR_BADFD;
7153 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7154 smb_CloseFID(vcp, fidp, NULL, 0);
7155 smb_ReleaseFID(fidp);
7156 return CM_ERROR_NOSUCHFILE;
7159 lock_ObtainMutex(&fidp->mx);
7160 if (fidp->flags & SMB_FID_IOCTL) {
7161 lock_ReleaseMutex(&fidp->mx);
7162 code = smb_IoctlRead(fidp, vcp, inp, outp);
7163 smb_ReleaseFID(fidp);
7166 lock_ReleaseMutex(&fidp->mx);
7169 LARGE_INTEGER LOffset, LLength;
7172 pid = ((smb_t *) inp)->pid;
7173 key = cm_GenerateKey(vcp->vcID, pid, fd);
7175 LOffset.HighPart = 0;
7176 LOffset.LowPart = offset.LowPart;
7177 LLength.HighPart = 0;
7178 LLength.LowPart = count;
7180 lock_ObtainMutex(&fidp->scp->mx);
7181 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7182 lock_ReleaseMutex(&fidp->scp->mx);
7185 smb_ReleaseFID(fidp);
7189 userp = smb_GetUserFromVCP(vcp, inp);
7191 /* remember this for final results */
7192 smb_SetSMBParm(outp, 0, count);
7193 smb_SetSMBParm(outp, 1, 0);
7194 smb_SetSMBParm(outp, 2, 0);
7195 smb_SetSMBParm(outp, 3, 0);
7196 smb_SetSMBParm(outp, 4, 0);
7198 /* set the packet data length to 3 bytes for the data block header,
7199 * plus the size of the data.
7201 smb_SetSMBDataLength(outp, count+3);
7203 /* get op ptr after putting in the parms, since otherwise we don't
7204 * know where the data really is.
7206 op = smb_GetSMBData(outp, NULL);
7208 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7209 *op++ = 1; /* data block marker */
7210 *op++ = (unsigned char) (count & 0xff);
7211 *op++ = (unsigned char) ((count >> 8) & 0xff);
7214 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7216 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
7219 /* fix some things up */
7220 smb_SetSMBParm(outp, 0, finalCount);
7221 smb_SetSMBDataLength(outp, finalCount+3);
7223 smb_ReleaseFID(fidp);
7225 cm_ReleaseUser(userp);
7229 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7236 cm_scache_t *dscp; /* dir we're dealing with */
7237 cm_scache_t *scp; /* file we're creating */
7239 int initialModeBits;
7249 /* compute initial mode bits based on read-only flag in attributes */
7250 initialModeBits = 0777;
7252 tp = smb_GetSMBData(inp, NULL);
7253 pathp = smb_ParseASCIIBlock(tp, &tp);
7254 if (smb_StoreAnsiFilenames)
7255 OemToChar(pathp,pathp);
7257 if (strcmp(pathp, "\\") == 0)
7258 return CM_ERROR_EXISTS;
7260 spacep = inp->spacep;
7261 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7263 userp = smb_GetUserFromVCP(vcp, inp);
7265 caseFold = CM_FLAG_CASEFOLD;
7267 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7269 cm_ReleaseUser(userp);
7270 return CM_ERROR_NOSUCHPATH;
7273 code = cm_NameI(cm_data.rootSCachep, spacep->data,
7274 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7275 userp, tidPathp, &req, &dscp);
7278 cm_ReleaseUser(userp);
7283 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7284 cm_ReleaseSCache(dscp);
7285 cm_ReleaseUser(userp);
7286 if ( WANTS_DFS_PATHNAMES(inp) )
7287 return CM_ERROR_PATH_NOT_COVERED;
7289 return CM_ERROR_BADSHARENAME;
7291 #endif /* DFS_SUPPORT */
7293 /* otherwise, scp points to the parent directory. Do a lookup, and
7294 * fail if we find it. Otherwise, we do the create.
7300 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7301 if (scp) cm_ReleaseSCache(scp);
7302 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7303 if (code == 0) code = CM_ERROR_EXISTS;
7304 cm_ReleaseSCache(dscp);
7305 cm_ReleaseUser(userp);
7309 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7310 setAttr.clientModTime = time(NULL);
7311 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7312 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7313 smb_NotifyChange(FILE_ACTION_ADDED,
7314 FILE_NOTIFY_CHANGE_DIR_NAME,
7315 dscp, lastNamep, NULL, TRUE);
7317 /* we don't need this any longer */
7318 cm_ReleaseSCache(dscp);
7321 /* something went wrong creating or truncating the file */
7322 cm_ReleaseUser(userp);
7326 /* otherwise we succeeded */
7327 smb_SetSMBDataLength(outp, 0);
7328 cm_ReleaseUser(userp);
7333 BOOL smb_IsLegalFilename(char *filename)
7336 * Find the longest substring of filename that does not contain
7337 * any of the chars in illegalChars. If that substring is less
7338 * than the length of the whole string, then one or more of the
7339 * illegal chars is in filename.
7341 if (strcspn(filename, illegalChars) < strlen(filename))
7347 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7355 cm_scache_t *dscp; /* dir we're dealing with */
7356 cm_scache_t *scp; /* file we're creating */
7358 int initialModeBits;
7366 int created = 0; /* the file was new */
7371 excl = (inp->inCom == 0x03)? 0 : 1;
7373 attributes = smb_GetSMBParm(inp, 0);
7374 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7376 /* compute initial mode bits based on read-only flag in attributes */
7377 initialModeBits = 0666;
7378 if (attributes & SMB_ATTR_READONLY)
7379 initialModeBits &= ~0222;
7381 tp = smb_GetSMBData(inp, NULL);
7382 pathp = smb_ParseASCIIBlock(tp, &tp);
7383 if (smb_StoreAnsiFilenames)
7384 OemToChar(pathp,pathp);
7386 spacep = inp->spacep;
7387 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7389 userp = smb_GetUserFromVCP(vcp, inp);
7391 caseFold = CM_FLAG_CASEFOLD;
7393 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7395 cm_ReleaseUser(userp);
7396 return CM_ERROR_NOSUCHPATH;
7398 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7399 userp, tidPathp, &req, &dscp);
7402 cm_ReleaseUser(userp);
7407 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7408 cm_ReleaseSCache(dscp);
7409 cm_ReleaseUser(userp);
7410 if ( WANTS_DFS_PATHNAMES(inp) )
7411 return CM_ERROR_PATH_NOT_COVERED;
7413 return CM_ERROR_BADSHARENAME;
7415 #endif /* DFS_SUPPORT */
7417 /* otherwise, scp points to the parent directory. Do a lookup, and
7418 * truncate the file if we find it, otherwise we create the file.
7425 if (!smb_IsLegalFilename(lastNamep))
7426 return CM_ERROR_BADNTFILENAME;
7428 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7429 #ifdef DEBUG_VERBOSE
7432 hexp = osi_HexifyString( lastNamep );
7433 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7438 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7439 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7440 cm_ReleaseSCache(dscp);
7441 cm_ReleaseUser(userp);
7445 /* if we get here, if code is 0, the file exists and is represented by
7446 * scp. Otherwise, we have to create it.
7450 /* oops, file shouldn't be there */
7451 cm_ReleaseSCache(dscp);
7452 cm_ReleaseSCache(scp);
7453 cm_ReleaseUser(userp);
7454 return CM_ERROR_EXISTS;
7457 setAttr.mask = CM_ATTRMASK_LENGTH;
7458 setAttr.length.LowPart = 0;
7459 setAttr.length.HighPart = 0;
7460 code = cm_SetAttr(scp, &setAttr, userp, &req);
7463 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7464 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7465 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7469 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7470 smb_NotifyChange(FILE_ACTION_ADDED,
7471 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7472 dscp, lastNamep, NULL, TRUE);
7473 } else if (!excl && code == CM_ERROR_EXISTS) {
7474 /* not an exclusive create, and someone else tried
7475 * creating it already, then we open it anyway. We
7476 * don't bother retrying after this, since if this next
7477 * fails, that means that the file was deleted after
7478 * we started this call.
7480 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7483 setAttr.mask = CM_ATTRMASK_LENGTH;
7484 setAttr.length.LowPart = 0;
7485 setAttr.length.HighPart = 0;
7486 code = cm_SetAttr(scp, &setAttr, userp, &req);
7491 /* we don't need this any longer */
7492 cm_ReleaseSCache(dscp);
7495 /* something went wrong creating or truncating the file */
7496 if (scp) cm_ReleaseSCache(scp);
7497 cm_ReleaseUser(userp);
7501 /* make sure we only open files */
7502 if (scp->fileType != CM_SCACHETYPE_FILE) {
7503 cm_ReleaseSCache(scp);
7504 cm_ReleaseUser(userp);
7505 return CM_ERROR_ISDIR;
7508 /* now all we have to do is open the file itself */
7509 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7510 osi_assertx(fidp, "null smb_fid_t");
7514 lock_ObtainMutex(&fidp->mx);
7515 /* always create it open for read/write */
7516 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7518 /* remember that the file was newly created */
7520 fidp->flags |= SMB_FID_CREATED;
7522 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7524 /* save a pointer to the vnode */
7526 lock_ObtainMutex(&scp->mx);
7527 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7528 lock_ReleaseMutex(&scp->mx);
7531 fidp->userp = userp;
7532 lock_ReleaseMutex(&fidp->mx);
7534 smb_SetSMBParm(outp, 0, fidp->fid);
7535 smb_SetSMBDataLength(outp, 0);
7537 cm_Open(scp, 0, userp);
7539 smb_ReleaseFID(fidp);
7540 cm_ReleaseUser(userp);
7541 /* leave scp held since we put it in fidp->scp */
7545 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7548 osi_hyper_t new_offset;
7559 fd = smb_GetSMBParm(inp, 0);
7560 whence = smb_GetSMBParm(inp, 1);
7561 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7563 /* try to find the file descriptor */
7564 fd = smb_ChainFID(fd, inp);
7565 fidp = smb_FindFID(vcp, fd, 0);
7567 return CM_ERROR_BADFD;
7569 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7570 smb_CloseFID(vcp, fidp, NULL, 0);
7571 smb_ReleaseFID(fidp);
7572 return CM_ERROR_NOSUCHFILE;
7575 lock_ObtainMutex(&fidp->mx);
7576 if (fidp->flags & SMB_FID_IOCTL) {
7577 lock_ReleaseMutex(&fidp->mx);
7578 smb_ReleaseFID(fidp);
7579 return CM_ERROR_BADFD;
7581 lock_ReleaseMutex(&fidp->mx);
7583 userp = smb_GetUserFromVCP(vcp, inp);
7585 lock_ObtainMutex(&fidp->mx);
7588 lock_ReleaseMutex(&fidp->mx);
7589 lock_ObtainMutex(&scp->mx);
7590 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7591 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7593 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7595 /* offset from current offset */
7596 new_offset = LargeIntegerAdd(fidp->offset,
7597 ConvertLongToLargeInteger(offset));
7599 else if (whence == 2) {
7600 /* offset from current EOF */
7601 new_offset = LargeIntegerAdd(scp->length,
7602 ConvertLongToLargeInteger(offset));
7604 new_offset = ConvertLongToLargeInteger(offset);
7607 fidp->offset = new_offset;
7608 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7609 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7610 smb_SetSMBDataLength(outp, 0);
7612 lock_ReleaseMutex(&scp->mx);
7613 smb_ReleaseFID(fidp);
7614 cm_ReleaseSCache(scp);
7615 cm_ReleaseUser(userp);
7619 /* dispatch all of the requests received in a packet. Due to chaining, this may
7620 * be more than one request.
7622 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7623 NCB *ncbp, raw_write_cont_t *rwcp)
7627 unsigned long code = 0;
7628 unsigned char *outWctp;
7629 int nparms; /* # of bytes of parameters */
7631 int nbytes; /* bytes of data, excluding count */
7634 unsigned short errCode;
7635 unsigned long NTStatus;
7637 unsigned char errClass;
7638 unsigned int oldGen;
7639 DWORD oldTime, newTime;
7641 /* get easy pointer to the data */
7642 smbp = (smb_t *) inp->data;
7644 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7645 /* setup the basic parms for the initial request in the packet */
7646 inp->inCom = smbp->com;
7647 inp->wctp = &smbp->wct;
7649 inp->ncb_length = ncbp->ncb_length;
7654 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7655 /* log it and discard it */
7657 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7658 __FILE__, __LINE__, ncbp->ncb_length);
7660 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7664 /* We are an ongoing op */
7665 thrd_Increment(&ongoingOps);
7667 /* set up response packet for receiving output */
7668 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7669 smb_FormatResponsePacket(vcp, inp, outp);
7670 outWctp = outp->wctp;
7672 /* Remember session generation number and time */
7673 oldGen = sessionGen;
7674 oldTime = GetTickCount();
7676 while (inp->inCom != 0xff) {
7677 dp = &smb_dispatchTable[inp->inCom];
7679 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7680 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7681 code = outp->resumeCode;
7685 /* process each request in the packet; inCom, wctp and inCount
7686 * are already set up.
7688 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7691 /* now do the dispatch */
7692 /* start by formatting the response record a little, as a default */
7693 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7695 outWctp[1] = 0xff; /* no operation */
7696 outWctp[2] = 0; /* padding */
7701 /* not a chained request, this is a more reasonable default */
7702 outWctp[0] = 0; /* wct of zero */
7703 outWctp[1] = 0; /* and bcc (word) of zero */
7707 /* once set, stays set. Doesn't matter, since we never chain
7708 * "no response" calls.
7710 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7714 /* we have a recognized operation */
7716 if (inp->inCom == 0x1d)
7718 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7720 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7721 code = (*(dp->procp)) (vcp, inp, outp);
7722 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7724 if ( code == CM_ERROR_BADSMB ||
7725 code == CM_ERROR_BADOP )
7727 #endif /* LOG_PACKET */
7730 if (oldGen != sessionGen) {
7731 newTime = GetTickCount();
7733 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7734 newTime - oldTime, ncbp->ncb_length);
7736 osi_Log2(smb_logp, "Pkt straddled session startup, "
7737 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7741 /* bad opcode, fail the request, after displaying it */
7742 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7745 #endif /* LOG_PACKET */
7749 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7750 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7751 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7752 if (code == IDCANCEL)
7756 code = CM_ERROR_BADOP;
7759 /* catastrophic failure: log as much as possible */
7760 if (code == CM_ERROR_BADSMB) {
7762 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7767 #endif /* LOG_PACKET */
7768 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7771 code = CM_ERROR_INVAL;
7774 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7775 thrd_Decrement(&ongoingOps);
7780 /* now, if we failed, turn the current response into an empty
7781 * one, and fill in the response packet's error code.
7784 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7785 smb_MapNTError(code, &NTStatus);
7786 outWctp = outp->wctp;
7787 smbp = (smb_t *) &outp->data;
7788 if (code != CM_ERROR_PARTIALWRITE
7789 && code != CM_ERROR_BUFFERTOOSMALL
7790 && code != CM_ERROR_GSSCONTINUE) {
7791 /* nuke wct and bcc. For a partial
7792 * write or an in-process authentication handshake,
7793 * assume they're OK.
7799 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7800 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7801 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7802 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7803 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7807 smb_MapCoreError(code, vcp, &errCode, &errClass);
7808 outWctp = outp->wctp;
7809 smbp = (smb_t *) &outp->data;
7810 if (code != CM_ERROR_PARTIALWRITE) {
7811 /* nuke wct and bcc. For a partial
7812 * write, assume they're OK.
7818 smbp->errLow = (unsigned char) (errCode & 0xff);
7819 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7820 smbp->rcls = errClass;
7823 } /* error occurred */
7825 /* if we're here, we've finished one request. Look to see if
7826 * this is a chained opcode. If it is, setup things to process
7827 * the chained request, and setup the output buffer to hold the
7828 * chained response. Start by finding the next input record.
7830 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7831 break; /* not a chained req */
7832 tp = inp->wctp; /* points to start of last request */
7833 /* in a chained request, the first two
7834 * parm fields are required, and are
7835 * AndXCommand/AndXReserved and
7837 if (tp[0] < 2) break;
7838 if (tp[1] == 0xff) break; /* no more chained opcodes */
7840 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7843 /* and now append the next output request to the end of this
7844 * last request. Begin by finding out where the last response
7845 * ends, since that's where we'll put our new response.
7847 outWctp = outp->wctp; /* ptr to out parameters */
7848 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7849 nparms = outWctp[0] << 1;
7850 tp = outWctp + nparms + 1; /* now points to bcc field */
7851 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7852 tp += 2 /* for the count itself */ + nbytes;
7853 /* tp now points to the new output record; go back and patch the
7854 * second parameter (off2) to point to the new record.
7856 temp = (unsigned int)(tp - outp->data);
7857 outWctp[3] = (unsigned char) (temp & 0xff);
7858 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7859 outWctp[2] = 0; /* padding */
7860 outWctp[1] = inp->inCom; /* next opcode */
7862 /* finally, setup for the next iteration */
7865 } /* while loop over all requests in the packet */
7867 /* now send the output packet, and return */
7869 smb_SendPacket(vcp, outp);
7870 thrd_Decrement(&ongoingOps);
7876 /* Wait for Netbios() calls to return, and make the results available to server
7877 * threads. Note that server threads can't wait on the NCBevents array
7878 * themselves, because NCB events are manual-reset, and the servers would race
7879 * each other to reset them.
7881 void smb_ClientWaiter(void *parmp)
7886 while (smbShutdownFlag == 0) {
7887 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7889 if (code == WAIT_OBJECT_0)
7892 /* error checking */
7893 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7895 int abandonIdx = code - WAIT_ABANDONED_0;
7896 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7899 if (code == WAIT_IO_COMPLETION)
7901 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7905 if (code == WAIT_TIMEOUT)
7907 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7910 if (code == WAIT_FAILED)
7912 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7915 idx = code - WAIT_OBJECT_0;
7917 /* check idx range! */
7918 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7920 /* this is fatal - log as much as possible */
7921 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7922 osi_assertx(0, "invalid index");
7925 thrd_ResetEvent(NCBevents[idx]);
7926 thrd_SetEvent(NCBreturns[0][idx]);
7932 * Try to have one NCBRECV request waiting for every live session. Not more
7933 * than one, because if there is more than one, it's hard to handle Write Raw.
7935 void smb_ServerWaiter(void *parmp)
7938 int idx_session, idx_NCB;
7944 while (smbShutdownFlag == 0) {
7946 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7948 if (code == WAIT_OBJECT_0)
7951 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7953 int abandonIdx = code - WAIT_ABANDONED_0;
7954 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7957 if (code == WAIT_IO_COMPLETION)
7959 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7963 if (code == WAIT_TIMEOUT)
7965 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7968 if (code == WAIT_FAILED)
7970 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7973 idx_session = code - WAIT_OBJECT_0;
7975 /* check idx range! */
7976 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7978 /* this is fatal - log as much as possible */
7979 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7980 osi_assertx(0, "invalid index");
7985 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7987 if (code == WAIT_OBJECT_0) {
7988 if (smbShutdownFlag == 1)
7994 /* error checking */
7995 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7997 int abandonIdx = code - WAIT_ABANDONED_0;
7998 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8001 if (code == WAIT_IO_COMPLETION)
8003 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8007 if (code == WAIT_TIMEOUT)
8009 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8012 if (code == WAIT_FAILED)
8014 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8017 idx_NCB = code - WAIT_OBJECT_0;
8019 /* check idx range! */
8020 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8022 /* this is fatal - log as much as possible */
8023 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8024 osi_assertx(0, "invalid index");
8027 /* Link them together */
8028 NCBsessions[idx_NCB] = idx_session;
8031 ncbp = NCBs[idx_NCB];
8032 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8033 ncbp->ncb_command = NCBRECV | ASYNCH;
8034 ncbp->ncb_lana_num = lanas[idx_session];
8036 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8037 ncbp->ncb_event = NCBevents[idx_NCB];
8038 ncbp->ncb_length = SMB_PACKETSIZE;
8041 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
8042 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
8043 ncbp->ncb_event = NCBreturns[0][idx_NCB];
8044 ncbp->ncb_length = SMB_PACKETSIZE;
8045 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8046 Netbios(ncbp, dos_ncb);
8052 * The top level loop for handling SMB request messages. Each server thread
8053 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8054 * NCB and buffer for the incoming request are loaned to us.
8056 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8057 * to immediately send a request for the rest of the data. This must come
8058 * before any other traffic for that session, so we delay setting the session
8059 * event until that data has come in.
8061 void smb_Server(VOID *parmp)
8063 INT_PTR myIdx = (INT_PTR) parmp;
8067 smb_packet_t *outbufp;
8069 int idx_NCB, idx_session;
8071 smb_vc_t *vcp = NULL;
8077 rx_StartClientThread();
8080 outbufp = GetPacket();
8081 outbufp->ncbp = outncbp;
8089 smb_ResetServerPriority();
8091 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8094 /* terminate silently if shutdown flag is set */
8095 if (code == WAIT_OBJECT_0) {
8096 if (smbShutdownFlag == 1) {
8097 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8103 /* error checking */
8104 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8106 int abandonIdx = code - WAIT_ABANDONED_0;
8107 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8110 if (code == WAIT_IO_COMPLETION)
8112 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8116 if (code == WAIT_TIMEOUT)
8118 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8121 if (code == WAIT_FAILED)
8123 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8126 idx_NCB = code - WAIT_OBJECT_0;
8128 /* check idx range! */
8129 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8131 /* this is fatal - log as much as possible */
8132 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8133 osi_assertx(0, "invalid index");
8136 ncbp = NCBs[idx_NCB];
8138 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8140 idx_session = NCBsessions[idx_NCB];
8141 rc = ncbp->ncb_retcode;
8143 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8144 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8148 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8152 /* Can this happen? Or is it just my UNIX paranoia? */
8153 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8159 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8163 /* Client closed session */
8164 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8166 lock_ObtainMutex(&vcp->mx);
8167 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8168 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8170 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8171 lock_ReleaseMutex(&vcp->mx);
8172 lock_ObtainWrite(&smb_globalLock);
8173 dead_sessions[vcp->session] = TRUE;
8174 lock_ReleaseWrite(&smb_globalLock);
8175 smb_CleanupDeadVC(vcp);
8179 lock_ReleaseMutex(&vcp->mx);
8185 /* Treat as transient error */
8187 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8191 "dispatch smb recv failed, message incomplete, ncb_length %d",
8194 "SMB message incomplete, "
8195 "length %d", ncbp->ncb_length);
8198 * We used to discard the packet.
8199 * Instead, try handling it normally.
8203 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8207 /* A weird error code. Log it, sleep, and continue. */
8208 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8210 lock_ObtainMutex(&vcp->mx);
8211 if (vcp && vcp->errorCount++ > 3) {
8212 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8213 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8214 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8216 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8217 lock_ReleaseMutex(&vcp->mx);
8218 lock_ObtainWrite(&smb_globalLock);
8219 dead_sessions[vcp->session] = TRUE;
8220 lock_ReleaseWrite(&smb_globalLock);
8221 smb_CleanupDeadVC(vcp);
8225 lock_ReleaseMutex(&vcp->mx);
8231 lock_ReleaseMutex(&vcp->mx);
8233 thrd_SetEvent(SessionEvents[idx_session]);
8238 /* Success, so now dispatch on all the data in the packet */
8240 smb_concurrentCalls++;
8241 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8242 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8245 * If at this point vcp is NULL (implies that packet was invalid)
8246 * then we are in big trouble. This means either :
8247 * a) we have the wrong NCB.
8248 * b) Netbios screwed up the call.
8249 * c) The VC was already marked dead before we were able to
8251 * Obviously this implies that
8252 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8253 * lanas[idx_session] != ncbp->ncb_lana_num )
8254 * Either way, we can't do anything with this packet.
8255 * Log, sleep and resume.
8258 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8262 ncbp->ncb_lana_num);
8264 /* Also log in the trace log. */
8265 osi_Log4(smb_logp, "Server: VCP does not exist!"
8266 "LSNs[idx_session]=[%d],"
8267 "lanas[idx_session]=[%d],"
8268 "ncbp->ncb_lsn=[%d],"
8269 "ncbp->ncb_lana_num=[%d]",
8273 ncbp->ncb_lana_num);
8275 /* thrd_Sleep(1000); Don't bother sleeping */
8276 thrd_SetEvent(SessionEvents[idx_session]);
8277 smb_concurrentCalls--;
8281 smb_SetRequestStartTime();
8283 vcp->errorCount = 0;
8284 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8286 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
8287 /* copy whole packet to virtual memory */
8288 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
8290 bufp->dos_pkt / 16, bufp);*/
8292 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
8294 smbp = (smb_t *)bufp->data;
8297 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
8301 if (smbp->com == 0x1d) {
8302 /* Special handling for Write Raw */
8303 raw_write_cont_t rwc;
8304 EVENT_HANDLE rwevent;
8305 char eventName[MAX_PATH];
8307 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8308 if (rwc.code == 0) {
8309 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8310 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8311 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8312 ncbp->ncb_command = NCBRECV | ASYNCH;
8313 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8314 ncbp->ncb_lana_num = vcp->lana;
8315 ncbp->ncb_buffer = rwc.buf;
8316 ncbp->ncb_length = 65535;
8317 ncbp->ncb_event = rwevent;
8321 Netbios(ncbp, dos_ncb);
8323 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8324 thrd_CloseHandle(rwevent);
8326 thrd_SetEvent(SessionEvents[idx_session]);
8328 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8330 else if (smbp->com == 0xa0) {
8332 * Serialize the handling for NT Transact
8335 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8336 thrd_SetEvent(SessionEvents[idx_session]);
8338 thrd_SetEvent(SessionEvents[idx_session]);
8339 /* TODO: what else needs to be serialized? */
8340 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8342 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
8344 __except( smb_ServerExceptionFilter() ) {
8348 smb_concurrentCalls--;
8351 thrd_SetEvent(NCBavails[idx_NCB]);
8358 * Exception filter for the server threads. If an exception occurs in the
8359 * dispatch routines, which is where exceptions are most common, then do a
8360 * force trace and give control to upstream exception handlers. Useful for
8363 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
8364 DWORD smb_ServerExceptionFilter(void) {
8365 /* While this is not the best time to do a trace, if it succeeds, then
8366 * we have a trace (assuming tracing was enabled). Otherwise, this should
8367 * throw a second exception.
8369 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8370 afsd_ForceTrace(TRUE);
8371 buf_ForceTrace(TRUE);
8372 return EXCEPTION_CONTINUE_SEARCH;
8377 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8378 * If the number of server threads is M, and the number of live sessions is
8379 * N, then the number of NCB's in use at any time either waiting for, or
8380 * holding, received messages is M + N, so that is how many NCB's get created.
8382 void InitNCBslot(int idx)
8384 struct smb_packet *bufp;
8385 EVENT_HANDLE retHandle;
8387 char eventName[MAX_PATH];
8389 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8391 NCBs[idx] = GetNCB();
8392 sprintf(eventName,"NCBavails[%d]", idx);
8393 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8394 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8395 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8397 sprintf(eventName,"NCBevents[%d]", idx);
8398 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8399 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8400 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8402 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8403 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8404 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8405 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8406 for (i=0; i<smb_NumServerThreads; i++)
8407 NCBreturns[i][idx] = retHandle;
8409 bufp->spacep = cm_GetSpace();
8413 /* listen for new connections */
8414 void smb_Listener(void *parmp)
8420 int session, thread;
8421 smb_vc_t *vcp = NULL;
8423 char rname[NCBNAMSZ+1];
8424 char cname[MAX_COMPUTERNAME_LENGTH+1];
8425 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8430 INT_PTR lana = (INT_PTR) parmp;
8434 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8437 /* retrieve computer name */
8438 GetComputerName(cname, &cnamelen);
8441 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8442 memset(ncbp, 0, sizeof(NCB));
8445 ncbp->ncb_command = NCBLISTEN;
8446 ncbp->ncb_rto = 0; /* No receive timeout */
8447 ncbp->ncb_sto = 0; /* No send timeout */
8449 /* pad out with spaces instead of null termination */
8450 len = (long)strlen(smb_localNamep);
8451 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8452 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8454 strcpy(ncbp->ncb_callname, "*");
8455 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8457 ncbp->ncb_lana_num = (UCHAR)lana;
8460 code = Netbios(ncbp);
8462 code = Netbios(ncbp, dos_ncb);
8464 if (code == NRC_BRIDGE) {
8465 int lanaRemaining = 0;
8467 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
8476 "NCBLISTEN lana=%d failed with NRC_BRIDGE. Listener thread exiting.",
8477 ncbp->ncb_lana_num, code);
8479 for (i = 0; i < lana_list.length; i++) {
8480 if (lana_list.lana[i] == ncbp->ncb_lana_num) {
8481 smb_StopListener(ncbp, lana_list.lana[i]);
8482 lana_list.lana[i] = 255;
8484 if (lana_list.lana[i] != 255)
8488 if (lanaRemaining == 0) {
8489 cm_VolStatus_Network_Stopped(cm_NetbiosName
8494 smb_ListenerState = SMB_LISTENER_STOPPED;
8495 smb_LANadapter = -1;
8496 lana_list.length = 0;
8500 } else if (code != 0) {
8502 char tbuffer[AFSPATHMAX];
8505 /* terminate silently if shutdown flag is set */
8506 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
8515 "NCBLISTEN lana=%d failed with code %d",
8516 ncbp->ncb_lana_num, code);
8518 "Client exiting due to network failure. Please restart client.\n");
8522 "Client exiting due to network failure. Please restart client.\n"
8523 "NCBLISTEN lana=%d failed with code %d",
8524 ncbp->ncb_lana_num, code);
8526 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8527 MB_OK|MB_SERVICE_NOTIFICATION);
8528 osi_panic(tbuffer, __FILE__, __LINE__);
8530 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
8531 ncbp->ncb_lana_num, code);
8532 fprintf(stderr, "\nClient exiting due to network failure "
8533 "(possibly due to power-saving mode)\n");
8534 fprintf(stderr, "Please restart client.\n");
8535 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
8539 /* check for remote conns */
8540 /* first get remote name and insert null terminator */
8541 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8542 for (i=NCBNAMSZ; i>0; i--) {
8543 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8549 /* compare with local name */
8551 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8552 flags |= SMB_VCFLAG_REMOTECONN;
8555 lock_ObtainMutex(&smb_ListenerLock);
8557 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8558 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8560 /* now ncbp->ncb_lsn is the connection ID */
8561 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8562 if (vcp->session == 0) {
8563 /* New generation */
8564 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8567 /* Log session startup */
8569 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8570 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8571 #endif /* NOTSERVICE */
8572 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8573 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8575 if (reportSessionStartups) {
8577 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8580 fprintf(stderr, "%s: New session %d starting from host %s\n",
8581 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8586 lock_ObtainMutex(&vcp->mx);
8587 strcpy(vcp->rname, rname);
8588 vcp->flags |= flags;
8589 lock_ReleaseMutex(&vcp->mx);
8591 /* Allocate slot in session arrays */
8592 /* Re-use dead session if possible, otherwise add one more */
8593 /* But don't look at session[0], it is reserved */
8594 lock_ObtainWrite(&smb_globalLock);
8595 for (session = 1; session < numSessions; session++) {
8596 if (dead_sessions[session]) {
8597 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8598 dead_sessions[session] = FALSE;
8602 lock_ReleaseWrite(&smb_globalLock);
8604 /* We are re-using an existing VC because the lsn and lana
8606 session = vcp->session;
8608 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8610 /* Log session startup */
8612 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8613 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8614 #endif /* NOTSERVICE */
8615 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8616 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8618 if (reportSessionStartups) {
8620 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8623 fprintf(stderr, "%s: Re-using session %d starting from host %s\n",
8624 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
8630 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8631 unsigned long code = CM_ERROR_ALLBUSY;
8632 smb_packet_t * outp = GetPacket();
8633 unsigned char *outWctp;
8636 smb_FormatResponsePacket(vcp, NULL, outp);
8639 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8640 unsigned long NTStatus;
8641 smb_MapNTError(code, &NTStatus);
8642 outWctp = outp->wctp;
8643 smbp = (smb_t *) &outp->data;
8647 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8648 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8649 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8650 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8651 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8653 unsigned short errCode;
8654 unsigned char errClass;
8655 smb_MapCoreError(code, vcp, &errCode, &errClass);
8656 outWctp = outp->wctp;
8657 smbp = (smb_t *) &outp->data;
8661 smbp->errLow = (unsigned char) (errCode & 0xff);
8662 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8663 smbp->rcls = errClass;
8665 smb_SendPacket(vcp, outp);
8666 smb_FreePacket(outp);
8668 lock_ObtainMutex(&vcp->mx);
8669 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8670 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8672 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8673 lock_ReleaseMutex(&vcp->mx);
8674 lock_ObtainWrite(&smb_globalLock);
8675 dead_sessions[vcp->session] = TRUE;
8676 lock_ReleaseWrite(&smb_globalLock);
8677 smb_CleanupDeadVC(vcp);
8679 lock_ReleaseMutex(&vcp->mx);
8682 /* assert that we do not exceed the maximum number of sessions or NCBs.
8683 * we should probably want to wait for a session to be freed in case
8686 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8687 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8689 lock_ObtainMutex(&vcp->mx);
8690 vcp->session = session;
8691 lock_ReleaseMutex(&vcp->mx);
8692 lock_ObtainWrite(&smb_globalLock);
8693 LSNs[session] = ncbp->ncb_lsn;
8694 lanas[session] = ncbp->ncb_lana_num;
8695 lock_ReleaseWrite(&smb_globalLock);
8697 if (session == numSessions) {
8698 /* Add new NCB for new session */
8699 char eventName[MAX_PATH];
8701 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8703 InitNCBslot(numNCBs);
8704 lock_ObtainWrite(&smb_globalLock);
8706 lock_ReleaseWrite(&smb_globalLock);
8707 thrd_SetEvent(NCBavails[0]);
8708 thrd_SetEvent(NCBevents[0]);
8709 for (thread = 0; thread < smb_NumServerThreads; thread++)
8710 thrd_SetEvent(NCBreturns[thread][0]);
8711 /* Also add new session event */
8712 sprintf(eventName, "SessionEvents[%d]", session);
8713 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8714 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8715 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8716 lock_ObtainWrite(&smb_globalLock);
8718 lock_ReleaseWrite(&smb_globalLock);
8719 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8720 thrd_SetEvent(SessionEvents[0]);
8722 thrd_SetEvent(SessionEvents[session]);
8728 lock_ReleaseMutex(&smb_ListenerLock);
8729 } /* dispatch while loop */
8734 /* initialize Netbios */
8735 int smb_NetbiosInit(void)
8741 int i, lana, code, l;
8743 int delname_tried=0;
8746 lana_number_t lanaNum;
8748 /* setup the NCB system */
8751 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8754 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8755 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8756 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8758 if (smb_LANadapter != -1)
8759 afsi_log("LAN adapter number %d", smb_LANadapter);
8761 afsi_log("LAN adapter number not determined");
8764 afsi_log("Set for gateway service");
8766 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8768 /* something went horribly wrong. We can't proceed without a netbios name */
8770 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8771 osi_panic(buf, __FILE__, __LINE__);
8774 /* remember the name */
8775 len = (int)strlen(cm_NetbiosName);
8777 free(smb_localNamep);
8778 smb_localNamep = malloc(len+1);
8779 strcpy(smb_localNamep, cm_NetbiosName);
8780 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8784 if (smb_LANadapter == -1) {
8785 ncbp->ncb_command = NCBENUM;
8786 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8787 ncbp->ncb_length = sizeof(lana_list);
8788 code = Netbios(ncbp);
8790 afsi_log("Netbios NCBENUM error code %d", code);
8791 osi_panic(s, __FILE__, __LINE__);
8795 lana_list.length = 1;
8796 lana_list.lana[0] = smb_LANadapter;
8799 for (i = 0; i < lana_list.length; i++) {
8800 /* reset the adaptor: in Win32, this is required for every process, and
8801 * acts as an init call, not as a real hardware reset.
8803 ncbp->ncb_command = NCBRESET;
8804 ncbp->ncb_callname[0] = 100;
8805 ncbp->ncb_callname[2] = 100;
8806 ncbp->ncb_lana_num = lana_list.lana[i];
8807 code = Netbios(ncbp);
8809 code = ncbp->ncb_retcode;
8811 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8812 lana_list.lana[i] = 255; /* invalid lana */
8814 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8818 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
8819 we will just fake the LANA list */
8820 if (smb_LANadapter == -1) {
8821 for (i = 0; i < 8; i++)
8822 lana_list.lana[i] = i;
8823 lana_list.length = 8;
8826 lana_list.length = 1;
8827 lana_list.lana[0] = smb_LANadapter;
8831 /* and declare our name so we can receive connections */
8832 memset(ncbp, 0, sizeof(*ncbp));
8833 len=lstrlen(smb_localNamep);
8834 memset(smb_sharename,' ',NCBNAMSZ);
8835 memcpy(smb_sharename,smb_localNamep,len);
8836 afsi_log("lana_list.length %d", lana_list.length);
8838 /* Keep the name so we can unregister it later */
8839 for (l = 0; l < lana_list.length; l++) {
8840 lana = lana_list.lana[l];
8842 ncbp->ncb_command = NCBADDNAME;
8843 ncbp->ncb_lana_num = lana;
8844 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8846 code = Netbios(ncbp);
8848 code = Netbios(ncbp, dos_ncb);
8851 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8852 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8854 char name[NCBNAMSZ+1];
8856 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8857 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8861 code = ncbp->ncb_retcode;
8864 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8866 /* we only use one LANA with djgpp */
8867 lana_list.lana[0] = lana;
8868 lana_list.length = 1;
8872 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8873 if (code == NRC_BRIDGE) { /* invalid LANA num */
8874 lana_list.lana[l] = 255;
8877 else if (code == NRC_DUPNAME) {
8878 afsi_log("Name already exists; try to delete it");
8879 memset(ncbp, 0, sizeof(*ncbp));
8880 ncbp->ncb_command = NCBDELNAME;
8881 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8882 ncbp->ncb_lana_num = lana;
8884 code = Netbios(ncbp);
8886 code = Netbios(ncbp, dos_ncb);
8889 code = ncbp->ncb_retcode;
8891 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8893 if (code != 0 || delname_tried) {
8894 lana_list.lana[l] = 255;
8896 else if (code == 0) {
8897 if (!delname_tried) {
8905 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8906 lana_list.lana[l] = 255; /* invalid lana */
8910 lana_found = 1; /* at least one worked */
8917 osi_assertx(lana_list.length >= 0, "empty lana list");
8919 afsi_log("No valid LANA numbers found!");
8920 lana_list.length = 0;
8921 smb_LANadapter = -1;
8922 smb_ListenerState = SMB_LISTENER_STOPPED;
8923 cm_VolStatus_Network_Stopped(cm_NetbiosName
8930 /* we're done with the NCB now */
8933 return (lana_list.length > 0 ? 1 : 0);
8936 void smb_StartListeners()
8942 if (smb_ListenerState == SMB_LISTENER_STARTED)
8945 smb_ListenerState = SMB_LISTENER_STARTED;
8946 cm_VolStatus_Network_Started(cm_NetbiosName
8952 for (i = 0; i < lana_list.length; i++) {
8953 if (lana_list.lana[i] == 255)
8955 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8956 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8957 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
8958 thrd_CloseHandle(phandle);
8962 void smb_RestartListeners()
8964 if (!powerStateSuspended && smb_ListenerState == SMB_LISTENER_STOPPED) {
8965 if (smb_NetbiosInit())
8966 smb_StartListeners();
8970 void smb_StopListener(NCB *ncbp, int lana)
8974 memset(ncbp, 0, sizeof(*ncbp));
8975 ncbp->ncb_command = NCBDELNAME;
8976 ncbp->ncb_lana_num = lana;
8977 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8978 code = Netbios(ncbp);
8980 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8981 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8983 /* and then reset the LANA; this will cause the listener threads to exit */
8984 ncbp->ncb_command = NCBRESET;
8985 ncbp->ncb_callname[0] = 100;
8986 ncbp->ncb_callname[2] = 100;
8987 ncbp->ncb_lana_num = lana;
8988 code = Netbios(ncbp);
8990 code = ncbp->ncb_retcode;
8992 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8994 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8998 void smb_StopListeners(void)
9003 if (smb_ListenerState == SMB_LISTENER_STOPPED)
9006 smb_ListenerState = SMB_LISTENER_STOPPED;
9007 cm_VolStatus_Network_Stopped(cm_NetbiosName
9015 /* Unregister the SMB name */
9016 for (l = 0; l < lana_list.length; l++) {
9017 lana = lana_list.lana[l];
9020 smb_StopListener(ncbp, lana);
9022 /* mark the adapter invalid */
9023 lana_list.lana[l] = 255; /* invalid lana */
9027 /* force a re-evaluation of the network adapters */
9028 lana_list.length = 0;
9029 smb_LANadapter = -1;
9031 Sleep(1000); /* give the listener threads a chance to exit */
9034 void smb_Init(osi_log_t *logp, int useV3,
9050 EVENT_HANDLE retHandle;
9051 char eventName[MAX_PATH];
9053 smb_TlsRequestSlot = TlsAlloc();
9056 smb_MBfunc = aMBfunc;
9061 /* Initialize smb_localZero */
9062 myTime.tm_isdst = -1; /* compute whether on DST or not */
9063 myTime.tm_year = 70;
9069 smb_localZero = mktime(&myTime);
9071 #ifndef USE_NUMERIC_TIME_CONV
9072 /* Initialize kludge-GMT */
9073 smb_CalculateNowTZ();
9074 #endif /* USE_NUMERIC_TIME_CONV */
9075 #ifdef AFS_FREELANCE_CLIENT
9076 /* Make sure the root.afs volume has the correct time */
9077 cm_noteLocalMountPointChange();
9080 /* initialize the remote debugging log */
9083 /* and the global lock */
9084 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
9085 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
9087 /* Raw I/O data structures */
9088 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
9090 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
9092 /* 4 Raw I/O buffers */
9094 smb_RawBufs = calloc(65536,1);
9095 *((char **)smb_RawBufs) = NULL;
9096 for (i=0; i<3; i++) {
9097 char *rawBuf = calloc(65536,1);
9098 *((char **)rawBuf) = smb_RawBufs;
9099 smb_RawBufs = rawBuf;
9102 npar = 65536 >> 4; /* number of paragraphs */
9103 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
9105 afsi_log("Cannot allocate %d paragraphs of DOS memory",
9107 osi_panic("",__FILE__,__LINE__);
9110 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
9113 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
9115 _farpokel(_dos_ds, smb_RawBufs, NULL);
9116 for (i=0; i<SMB_RAW_BUFS-1; i++) {
9117 npar = 65536 >> 4; /* number of paragraphs */
9118 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
9120 afsi_log("Cannot allocate %d paragraphs of DOS memory",
9122 osi_panic("",__FILE__,__LINE__);
9125 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
9128 rawBuf = (seg * 16) + 0; /* DOS physical address */
9129 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
9130 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
9131 smb_RawBufs = rawBuf;
9135 /* global free lists */
9136 smb_ncbFreeListp = NULL;
9137 smb_packetFreeListp = NULL;
9141 /* Initialize listener and server structures */
9143 memset(dead_sessions, 0, sizeof(dead_sessions));
9144 sprintf(eventName, "SessionEvents[0]");
9145 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9146 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9147 afsi_log("Event Object Already Exists: %s", eventName);
9149 smb_NumServerThreads = nThreads;
9150 sprintf(eventName, "NCBavails[0]");
9151 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9152 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9153 afsi_log("Event Object Already Exists: %s", eventName);
9154 sprintf(eventName, "NCBevents[0]");
9155 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9156 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9157 afsi_log("Event Object Already Exists: %s", eventName);
9158 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9159 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9160 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9161 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9162 afsi_log("Event Object Already Exists: %s", eventName);
9163 for (i = 0; i < smb_NumServerThreads; i++) {
9164 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9165 NCBreturns[i][0] = retHandle;
9168 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9169 for (i = 0; i < smb_NumServerThreads; i++) {
9170 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9171 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9172 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9173 afsi_log("Event Object Already Exists: %s", eventName);
9174 InitNCBslot((int)(i+1));
9176 numNCBs = smb_NumServerThreads + 1;
9178 /* Initialize dispatch table */
9179 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9180 /* Prepare the table for unknown operations */
9181 for(i=0; i<= SMB_NOPCODES; i++) {
9182 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9184 /* Fill in the ones we do know */
9185 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9186 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9187 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9188 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9189 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9190 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9191 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9192 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9193 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9194 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9195 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9196 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9197 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9198 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9199 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9200 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9201 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9202 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9203 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9204 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9205 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9206 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9207 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9208 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9209 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9210 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9211 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9212 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9213 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9214 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9215 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9216 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9217 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9218 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9219 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9220 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9221 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9222 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9223 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9224 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9225 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9226 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9227 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9228 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9229 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9230 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9231 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9232 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9233 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9234 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9235 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9236 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9237 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9238 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9239 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9240 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9241 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9242 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9243 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9244 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9245 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9246 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9247 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9248 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9249 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9250 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9251 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9252 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9253 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9254 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9255 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9256 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9257 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9258 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9260 /* setup tran 2 dispatch table */
9261 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9262 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9263 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9264 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9265 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9266 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9267 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9268 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9269 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9270 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9271 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9272 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9273 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9274 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9275 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9276 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9277 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9278 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9280 /* setup the rap dispatch table */
9281 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9282 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9283 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9284 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9285 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9289 /* if we are doing SMB authentication we have register outselves as a logon process */
9290 if (smb_authType != SMB_AUTH_NONE) {
9291 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9292 LSA_STRING afsProcessName;
9293 LSA_OPERATIONAL_MODE dummy; /*junk*/
9295 afsProcessName.Buffer = "OpenAFSClientDaemon";
9296 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9297 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9299 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9301 if (nts == STATUS_SUCCESS) {
9302 LSA_STRING packageName;
9303 /* we are registered. Find out the security package id */
9304 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9305 packageName.Length = (USHORT)strlen(packageName.Buffer);
9306 packageName.MaximumLength = packageName.Length + 1;
9307 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9308 if (nts == STATUS_SUCCESS) {
9310 * This code forces Windows to authenticate against the Logon Cache
9311 * first instead of attempting to authenticate against the Domain
9312 * Controller. When the Windows logon cache is enabled this improves
9313 * performance by removing the network access and works around a bug
9314 * seen at sites which are using a MIT Kerberos principal to login
9315 * to machines joined to a non-root domain in a multi-domain forest.
9316 * MsV1_0SetProcessOption was added in Windows XP.
9318 PVOID pResponse = NULL;
9319 ULONG cbResponse = 0;
9320 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9322 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9323 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9324 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9325 OptionsRequest.DisableOptions = FALSE;
9327 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9330 sizeof(OptionsRequest),
9336 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9337 char message[AFSPATHMAX];
9338 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9340 OutputDebugString(message);
9343 OutputDebugString("MsV1_0SetProcessOption success");
9344 afsi_log("MsV1_0SetProcessOption success");
9346 /* END - code from Larry */
9348 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9349 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9350 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9352 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9354 /* something went wrong. We report the error and revert back to no authentication
9355 because we can't perform any auth requests without a successful lsa handle
9356 or sec package id. */
9357 afsi_log("Reverting to NO SMB AUTH");
9358 smb_authType = SMB_AUTH_NONE;
9361 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9363 /* something went wrong. We report the error and revert back to no authentication
9364 because we can't perform any auth requests without a successful lsa handle
9365 or sec package id. */
9366 afsi_log("Reverting to NO SMB AUTH");
9367 smb_authType = SMB_AUTH_NONE;
9371 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9372 * time prevents the failure of authentication when logged into Windows with an
9373 * external Kerberos principal mapped to a local account.
9375 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9376 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9377 * then the only option is NTLMSSP anyway; so just fallback.
9382 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9383 if (secBlobLength == 0) {
9384 smb_authType = SMB_AUTH_NTLM;
9385 afsi_log("Reverting to SMB AUTH NTLM");
9394 /* Now get ourselves a domain name. */
9395 /* For now we are using the local computer name as the domain name.
9396 * It is actually the domain for local logins, and we are acting as
9397 * a local SMB server.
9399 bufsize = sizeof(smb_ServerDomainName) - 1;
9400 GetComputerName(smb_ServerDomainName, &bufsize);
9401 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9402 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
9405 /* Start listeners, waiters, servers, and daemons */
9407 smb_StartListeners();
9410 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9411 NULL, 0, &lpid, "smb_ClientWaiter");
9412 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9413 thrd_CloseHandle(phandle);
9416 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9417 NULL, 0, &lpid, "smb_ServerWaiter");
9418 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9419 thrd_CloseHandle(phandle);
9421 for (i=0; i<smb_NumServerThreads; i++) {
9422 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9423 (void *) i, 0, &lpid, "smb_Server");
9424 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9425 thrd_CloseHandle(phandle);
9428 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9429 NULL, 0, &lpid, "smb_Daemon");
9430 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9431 thrd_CloseHandle(phandle);
9433 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9434 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9435 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9436 thrd_CloseHandle(phandle);
9445 void smb_Shutdown(void)
9455 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9457 /* setup the NCB system */
9460 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
9463 /* Block new sessions by setting shutdown flag */
9464 smbShutdownFlag = 1;
9466 /* Hang up all sessions */
9467 memset((char *)ncbp, 0, sizeof(NCB));
9468 for (i = 1; i < numSessions; i++)
9470 if (dead_sessions[i])
9473 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9474 ncbp->ncb_command = NCBHANGUP;
9475 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9476 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9478 code = Netbios(ncbp);
9480 code = Netbios(ncbp, dos_ncb);
9482 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9483 if (code == 0) code = ncbp->ncb_retcode;
9485 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9486 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9490 /* Trigger the shutdown of all SMB threads */
9491 for (i = 0; i < smb_NumServerThreads; i++)
9492 thrd_SetEvent(NCBreturns[i][0]);
9494 thrd_SetEvent(NCBevents[0]);
9495 thrd_SetEvent(SessionEvents[0]);
9496 thrd_SetEvent(NCBavails[0]);
9498 for (i = 0;i < smb_NumServerThreads; i++) {
9499 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9500 if (code == WAIT_OBJECT_0) {
9503 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9504 thrd_SetEvent(NCBreturns[i--][0]);
9508 /* Delete Netbios name */
9509 memset((char *)ncbp, 0, sizeof(NCB));
9510 for (i = 0; i < lana_list.length; i++) {
9511 if (lana_list.lana[i] == 255) continue;
9512 ncbp->ncb_command = NCBDELNAME;
9513 ncbp->ncb_lana_num = lana_list.lana[i];
9514 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9516 code = Netbios(ncbp);
9518 code = Netbios(ncbp, dos_ncb);
9521 code = ncbp->ncb_retcode;
9523 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9524 ncbp->ncb_lana_num, code);
9529 /* Release the reference counts held by the VCs */
9530 lock_ObtainWrite(&smb_rctLock);
9531 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9536 if (vcp->magic != SMB_VC_MAGIC)
9537 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9538 __FILE__, __LINE__);
9540 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9542 if (fidp->scp != NULL) {
9545 lock_ObtainMutex(&fidp->mx);
9546 if (fidp->scp != NULL) {
9549 lock_ObtainMutex(&scp->mx);
9550 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9551 lock_ReleaseMutex(&scp->mx);
9552 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9553 cm_ReleaseSCache(scp);
9555 lock_ReleaseMutex(&fidp->mx);
9559 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9561 smb_ReleaseVCNoLock(tidp->vcp);
9563 cm_user_t *userp = tidp->userp;
9565 lock_ReleaseWrite(&smb_rctLock);
9566 cm_ReleaseUser(userp);
9567 lock_ObtainWrite(&smb_rctLock);
9571 lock_ReleaseWrite(&smb_rctLock);
9573 TlsFree(smb_TlsRequestSlot);
9576 /* Get the UNC \\<servername>\<sharename> prefix. */
9577 char *smb_GetSharename()
9581 /* Make sure we have been properly initialized. */
9582 if (smb_localNamep == NULL)
9585 /* Allocate space for \\<servername>\<sharename>, plus the
9588 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9589 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9595 void smb_LogPacket(smb_packet_t *packet)
9598 unsigned length, paramlen, datalen, i, j;
9600 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9602 if (!packet) return;
9604 osi_Log0(smb_logp, "*** SMB packet dump ***");
9606 vp = (BYTE *) packet->data;
9608 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9609 length = paramlen + 2 + datalen;
9612 for (i=0;i < length; i+=16)
9614 memset( buf, ' ', 80 );
9619 buf[strlen(buf)] = ' ';
9621 cp = (BYTE*) buf + 7;
9623 for (j=0;j < 16 && (i+j)<length; j++)
9625 *(cp++) = hex[vp[i+j] >> 4];
9626 *(cp++) = hex[vp[i+j] & 0xf];
9636 for (j=0;j < 16 && (i+j)<length;j++)
9638 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9649 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9652 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9654 #endif /* LOG_PACKET */
9657 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9665 lock_ObtainRead(&smb_rctLock);
9667 sprintf(output, "begin dumping smb_vc_t\r\n");
9668 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9670 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9674 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9675 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9676 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9678 sprintf(output, "begin dumping smb_fid_t\r\n");
9679 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9681 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9683 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",
9684 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9685 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9686 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9687 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9690 sprintf(output, "done dumping smb_fid_t\r\n");
9691 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9694 sprintf(output, "done dumping smb_vc_t\r\n");
9695 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9697 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9698 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9700 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9704 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9705 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9706 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9708 sprintf(output, "begin dumping smb_fid_t\r\n");
9709 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9711 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9713 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",
9714 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9715 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9716 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9717 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9720 sprintf(output, "done dumping smb_fid_t\r\n");
9721 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9724 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9725 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9728 lock_ReleaseRead(&smb_rctLock);
9732 long smb_IsNetworkStarted(void)
9734 return (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);