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>
17 #include <sys/timeb.h>
29 #include <rx/rx_prototypes.h>
32 #include <WINNT\afsreg.h>
35 #include "lanahelper.h"
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
41 smb_vc_t *dead_vcp = NULL;
42 smb_vc_t *active_vcp = NULL;
44 /* TODO; logout mechanism needs to be thread-safe */
45 char *loggedOutName = NULL;
46 smb_user_t *loggedOutUserp = NULL;
49 int smbShutdownFlag = 0;
51 int smb_LogoffTokenTransfer;
52 time_t smb_LogoffTransferTimeout;
54 int smb_StoreAnsiFilenames = 0;
56 DWORD last_msg_time = 0;
60 unsigned int sessionGen = 0;
62 extern void afsi_log(char *pattern, ...);
63 extern HANDLE afsi_file;
65 osi_hyper_t hzero = {0, 0};
66 osi_hyper_t hones = {0xFFFFFFFF, -1};
69 osi_rwlock_t smb_globalLock;
70 osi_rwlock_t smb_rctLock;
71 osi_mutex_t smb_ListenerLock;
74 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
85 int smb_NumServerThreads;
87 int numNCBs, numSessions, numVCs;
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
92 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
94 ULONG smb_lsaSecPackage;
95 LSA_STRING smb_lsaLogonOrigin;
97 #define NCBmax MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
99 EVENT_HANDLE **NCBreturns;
100 EVENT_HANDLE **NCBShutdown;
101 EVENT_HANDLE *smb_ServerShutdown;
102 DWORD NCBsessions[NCBmax];
104 struct smb_packet *bufs[NCBmax];
106 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
107 EVENT_HANDLE SessionEvents[Sessionmax];
108 unsigned short LSNs[Sessionmax];
109 int lanas[Sessionmax];
110 BOOL dead_sessions[Sessionmax];
114 osi_mutex_t smb_RawBufLock;
116 #define SMB_RAW_BUFS 4
118 int smb_RawBufSel[SMB_RAW_BUFS];
123 #define SMB_MASKFLAG_TILDE 1
124 #define SMB_MASKFLAG_CASEFOLD 2
126 #define RAWTIMEOUT INFINITE
129 typedef struct raw_write_cont {
142 /* dir search stuff */
143 long smb_dirSearchCounter = 1;
144 smb_dirSearch_t *smb_firstDirSearchp;
145 smb_dirSearch_t *smb_lastDirSearchp;
147 /* hide dot files? */
148 int smb_hideDotFiles;
150 /* global state about V3 protocols */
151 int smb_useV3; /* try to negotiate V3 */
154 static showErrors = 1;
155 /* MessageBox or something like it */
156 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
160 * Time in Unix format of midnight, 1/1/1970 local time.
161 * When added to dosUTime, gives Unix (AFS) time.
163 time_t smb_localZero = 0;
165 #define USE_NUMERIC_TIME_CONV 1
167 #ifndef USE_NUMERIC_TIME_CONV
168 /* Time difference for converting to kludge-GMT */
169 afs_uint32 smb_NowTZ;
170 #endif /* USE_NUMERIC_TIME_CONV */
172 char *smb_localNamep = NULL;
174 smb_vc_t *smb_allVCsp;
176 smb_username_t *usernamesp = NULL;
178 smb_waitingLockRequest_t *smb_allWaitingLocks;
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 void smb_NetbiosInit();
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 const char * ncb_error_string(int code)
218 case 0x01: s = "llegal buffer length"; break;
219 case 0x03: s = "illegal command"; break;
220 case 0x05: s = "command timed out"; break;
221 case 0x06: s = "message incomplete, issue another command"; break;
222 case 0x07: s = "illegal buffer address"; break;
223 case 0x08: s = "session number out of range"; break;
224 case 0x09: s = "no resource available"; break;
225 case 0x0a: s = "session closed"; break;
226 case 0x0b: s = "command cancelled"; break;
227 case 0x0d: s = "duplicate name"; break;
228 case 0x0e: s = "name table full"; break;
229 case 0x0f: s = "no deletions, name has active sessions"; break;
230 case 0x11: s = "local session table full"; break;
231 case 0x12: s = "remote session table full"; break;
232 case 0x13: s = "illegal name number"; break;
233 case 0x14: s = "no callname"; break;
234 case 0x15: s = "cannot put * in NCB_NAME"; break;
235 case 0x16: s = "name in use on remote adapter"; break;
236 case 0x17: s = "name deleted"; break;
237 case 0x18: s = "session ended abnormally"; break;
238 case 0x19: s = "name conflict detected"; break;
239 case 0x21: s = "interface busy, IRET before retrying"; break;
240 case 0x22: s = "too many commands outstanding, retry later";break;
241 case 0x23: s = "ncb_lana_num field invalid"; break;
242 case 0x24: s = "command completed while cancel occurring "; break;
243 case 0x26: s = "command not valid to cancel"; break;
244 case 0x30: s = "name defined by anther local process"; break;
245 case 0x34: s = "environment undefined. RESET required"; break;
246 case 0x35: s = "required OS resources exhausted"; break;
247 case 0x36: s = "max number of applications exceeded"; break;
248 case 0x37: s = "no saps available for netbios"; break;
249 case 0x38: s = "requested resources are not available"; break;
250 case 0x39: s = "invalid ncb address or length > segment"; break;
251 case 0x3B: s = "invalid NCB DDID"; break;
252 case 0x3C: s = "lock of user area failed"; break;
253 case 0x3f: s = "NETBIOS not loaded"; break;
254 case 0x40: s = "system error"; break;
255 default: s = "unknown error";
261 char * myCrt_Dispatch(int i)
266 return "(00)ReceiveCoreMakeDir";
268 return "(01)ReceiveCoreRemoveDir";
270 return "(02)ReceiveCoreOpen";
272 return "(03)ReceiveCoreCreate";
274 return "(04)ReceiveCoreClose";
276 return "(05)ReceiveCoreFlush";
278 return "(06)ReceiveCoreUnlink";
280 return "(07)ReceiveCoreRename";
282 return "(08)ReceiveCoreGetFileAttributes";
284 return "(09)ReceiveCoreSetFileAttributes";
286 return "(0a)ReceiveCoreRead";
288 return "(0b)ReceiveCoreWrite";
290 return "(0c)ReceiveCoreLockRecord";
292 return "(0d)ReceiveCoreUnlockRecord";
294 return "(0e)SendCoreBadOp";
296 return "(0f)ReceiveCoreCreate";
298 return "(10)ReceiveCoreCheckPath";
300 return "(11)SendCoreBadOp";
302 return "(12)ReceiveCoreSeek";
304 return "(1a)ReceiveCoreReadRaw";
306 return "(1d)ReceiveCoreWriteRawDummy";
308 return "(22)ReceiveV3SetAttributes";
310 return "(23)ReceiveV3GetAttributes";
312 return "(24)ReceiveV3LockingX";
314 return "(25)ReceiveV3Trans";
316 return "(26)ReceiveV3Trans[aux]";
318 return "(29)SendCoreBadOp";
320 return "(2b)ReceiveCoreEcho";
322 return "(2d)ReceiveV3OpenX";
324 return "(2e)ReceiveV3ReadX";
326 return "(32)ReceiveV3Tran2A";
328 return "(33)ReceiveV3Tran2A[aux]";
330 return "(34)ReceiveV3FindClose";
332 return "(35)ReceiveV3FindNotifyClose";
334 return "(70)ReceiveCoreTreeConnect";
336 return "(71)ReceiveCoreTreeDisconnect";
338 return "(72)ReceiveNegotiate";
340 return "(73)ReceiveV3SessionSetupX";
342 return "(74)ReceiveV3UserLogoffX";
344 return "(75)ReceiveV3TreeConnectX";
346 return "(80)ReceiveCoreGetDiskAttributes";
348 return "(81)ReceiveCoreSearchDir";
352 return "(83)FindUnique";
354 return "(84)FindClose";
356 return "(A0)ReceiveNTTransact";
358 return "(A2)ReceiveNTCreateX";
360 return "(A4)ReceiveNTCancel";
362 return "(A5)ReceiveNTRename";
364 return "(C0)OpenPrintFile";
366 return "(C1)WritePrintFile";
368 return "(C2)ClosePrintFile";
370 return "(C3)GetPrintQueue";
372 return "(D8)ReadBulk";
374 return "(D9)WriteBulk";
376 return "(DA)WriteBulkData";
378 return "unknown SMB op";
382 char * myCrt_2Dispatch(int i)
387 return "unknown SMB op-2";
389 return "S(00)CreateFile";
391 return "S(01)FindFirst";
393 return "S(02)FindNext"; /* FindNext */
395 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
399 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
401 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
403 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
405 return "S(08)??_ReceiveTran2SetFileInfo";
407 return "S(09)??_ReceiveTran2FSCTL";
409 return "S(0a)_ReceiveTran2IOCTL";
411 return "S(0b)_ReceiveTran2FindNotifyFirst";
413 return "S(0c)_ReceiveTran2FindNotifyNext";
415 return "S(0d)_ReceiveTran2CreateDirectory";
417 return "S(0e)_ReceiveTran2SessionSetup";
419 return "S(10)_ReceiveTran2GetDfsReferral";
421 return "S(11)_ReceiveTran2ReportDfsInconsistency";
425 char * myCrt_RapDispatch(int i)
430 return "unknown RAP OP";
432 return "RAP(0)NetShareEnum";
434 return "RAP(1)NetShareGetInfo";
436 return "RAP(13)NetServerGetInfo";
438 return "RAP(63)NetWkStaGetInfo";
442 /* scache must be locked */
443 unsigned int smb_Attributes(cm_scache_t *scp)
447 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
448 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
449 scp->fileType == CM_SCACHETYPE_INVALID)
451 attrs = SMB_ATTR_DIRECTORY;
452 #ifdef SPECIAL_FOLDERS
453 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
454 #endif /* SPECIAL_FOLDERS */
455 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
456 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
461 * We used to mark a file RO if it was in an RO volume, but that
462 * turns out to be impolitic in NT. See defect 10007.
465 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
466 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
468 if ((scp->unixModeBits & 0222) == 0)
469 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
475 /* Check if the named file/dir is a dotfile/dotdir */
476 /* String pointed to by lastComp can have leading slashes, but otherwise should have
477 no other patch components */
478 unsigned int smb_IsDotFile(char *lastComp) {
481 /* skip over slashes */
482 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
487 /* nulls, curdir and parent dir doesn't count */
493 if(*(s+1) == '.' && !*(s + 2))
500 static int ExtractBits(WORD bits, short start, short len)
507 num = bits << (16 - end);
508 num = num >> ((16 - end) + start);
514 void ShowUnixTime(char *FuncName, time_t unixTime)
519 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
521 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
522 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
524 int day, month, year, sec, min, hour;
527 day = ExtractBits(wDate, 0, 5);
528 month = ExtractBits(wDate, 5, 4);
529 year = ExtractBits(wDate, 9, 7) + 1980;
531 sec = ExtractBits(wTime, 0, 5);
532 min = ExtractBits(wTime, 5, 6);
533 hour = ExtractBits(wTime, 11, 5);
535 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
536 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
542 /* Determine if we are observing daylight savings time */
543 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
545 TIME_ZONE_INFORMATION timeZoneInformation;
546 SYSTEMTIME utc, local, localDST;
548 /* Get the time zone info. NT uses this to calc if we are in DST. */
549 GetTimeZoneInformation(&timeZoneInformation);
551 /* Return the daylight bias */
552 *pDstBias = timeZoneInformation.DaylightBias;
554 /* Return the bias */
555 *pBias = timeZoneInformation.Bias;
557 /* Now determine if DST is being observed */
559 /* Get the UTC (GMT) time */
562 /* Convert UTC time to local time using the time zone info. If we are
563 observing DST, the calculated local time will include this.
565 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
567 /* Set the daylight bias to 0. The daylight bias is the amount of change
568 * in time that we use for daylight savings time. By setting this to 0
569 * we cause there to be no change in time during daylight savings time.
571 timeZoneInformation.DaylightBias = 0;
573 /* Convert the utc time to local time again, but this time without any
574 adjustment for daylight savings time.
576 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
578 /* If the two times are different, then it means that the localDST that
579 we calculated includes the daylight bias, and therefore we are
580 observing daylight savings time.
582 *pDST = localDST.wHour != local.wHour;
585 /* Determine if we are observing daylight savings time */
586 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
592 *pDstBias = -60; /* where can this be different? */
598 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
600 BOOL dst; /* Will be TRUE if observing DST */
601 LONG dstBias; /* Offset from local time if observing DST */
602 LONG bias; /* Offset from GMT for local time */
605 * This function will adjust the last write time to compensate
606 * for two bugs in the smb client:
608 * 1) During Daylight Savings Time, the LastWriteTime is ahead
609 * in time by the DaylightBias (ignoring the sign - the
610 * DaylightBias is always stored as a negative number). If
611 * the DaylightBias is -60, then the LastWriteTime will be
612 * ahead by 60 minutes.
614 * 2) If the local time zone is a positive offset from GMT, then
615 * the LastWriteTime will be the correct local time plus the
616 * Bias (ignoring the sign - a positive offset from GMT is
617 * always stored as a negative Bias). If the Bias is -120,
618 * then the LastWriteTime will be ahead by 120 minutes.
620 * These bugs can occur at the same time.
623 GetTimeZoneInfo(&dst, &dstBias, &bias);
625 /* First adjust for DST */
627 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
629 /* Now adjust for a positive offset from GMT (a negative bias). */
631 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
634 #ifndef USE_NUMERIC_TIME_CONV
636 * Calculate the difference (in seconds) between local time and GMT.
637 * This enables us to convert file times to kludge-GMT.
643 struct tm gmt_tm, local_tm;
644 int days, hours, minutes, seconds;
647 gmt_tm = *(gmtime(&t));
648 local_tm = *(localtime(&t));
650 days = local_tm.tm_yday - gmt_tm.tm_yday;
651 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
652 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
653 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
657 #endif /* USE_NUMERIC_TIME_CONV */
660 #ifdef USE_NUMERIC_TIME_CONV
661 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
663 // Note that LONGLONG is a 64-bit value
666 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
667 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
668 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
671 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
676 time_t ersatz_unixTime;
679 * Must use kludge-GMT instead of real GMT.
680 * kludge-GMT is computed by adding time zone difference to localtime.
683 * ltp = gmtime(&unixTime);
685 ersatz_unixTime = unixTime - smb_NowTZ;
686 ltp = localtime(&ersatz_unixTime);
688 /* if we fail, make up something */
691 localJunk.tm_year = 89 - 20;
692 localJunk.tm_mon = 4;
693 localJunk.tm_mday = 12;
694 localJunk.tm_hour = 0;
695 localJunk.tm_min = 0;
696 localJunk.tm_sec = 0;
699 stm.wYear = ltp->tm_year + 1900;
700 stm.wMonth = ltp->tm_mon + 1;
701 stm.wDayOfWeek = ltp->tm_wday;
702 stm.wDay = ltp->tm_mday;
703 stm.wHour = ltp->tm_hour;
704 stm.wMinute = ltp->tm_min;
705 stm.wSecond = ltp->tm_sec;
706 stm.wMilliseconds = 0;
708 SystemTimeToFileTime(&stm, largeTimep);
710 #endif /* USE_NUMERIC_TIME_CONV */
712 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
714 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
715 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
716 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
718 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
720 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
721 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
723 *ft = LargeIntegerMultiplyByLong(*ft, 60);
724 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
727 ut = ConvertLongToLargeInteger(unixTime);
728 ut = LargeIntegerMultiplyByLong(ut, 10000000);
729 *ft = LargeIntegerAdd(*ft, ut);
734 #ifdef USE_NUMERIC_TIME_CONV
735 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
737 // Note that LONGLONG is a 64-bit value
740 ll = largeTimep->dwHighDateTime;
742 ll += largeTimep->dwLowDateTime;
744 ll -= 116444736000000000;
747 *unixTimep = (DWORD)ll;
749 #else /* USE_NUMERIC_TIME_CONV */
750 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
756 FileTimeToSystemTime(largeTimep, &stm);
758 lt.tm_year = stm.wYear - 1900;
759 lt.tm_mon = stm.wMonth - 1;
760 lt.tm_wday = stm.wDayOfWeek;
761 lt.tm_mday = stm.wDay;
762 lt.tm_hour = stm.wHour;
763 lt.tm_min = stm.wMinute;
764 lt.tm_sec = stm.wSecond;
767 save_timezone = _timezone;
768 _timezone += smb_NowTZ;
769 *unixTimep = mktime(<);
770 _timezone = save_timezone;
772 #endif /* USE_NUMERIC_TIME_CONV */
774 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
776 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
777 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
778 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
782 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
783 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
784 a = LargeIntegerMultiplyByLong(a, 60);
785 a = LargeIntegerMultiplyByLong(a, 10000000);
787 /* subtract it from ft */
788 a = LargeIntegerSubtract(*ft, a);
790 /* divide down to seconds */
791 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
795 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
803 ltp = localtime((time_t*) &t);
805 /* if we fail, make up something */
808 localJunk.tm_year = 89 - 20;
809 localJunk.tm_mon = 4;
810 localJunk.tm_mday = 12;
811 localJunk.tm_hour = 0;
812 localJunk.tm_min = 0;
813 localJunk.tm_sec = 0;
816 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
817 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
818 *searchTimep = (dosDate<<16) | dosTime;
821 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
823 unsigned short dosDate;
824 unsigned short dosTime;
827 dosDate = (unsigned short) (searchTime & 0xffff);
828 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
830 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
831 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
832 localTm.tm_mday = (dosDate) & 0x1f;
833 localTm.tm_hour = (dosTime>>11) & 0x1f;
834 localTm.tm_min = (dosTime >> 5) & 0x3f;
835 localTm.tm_sec = (dosTime & 0x1f) * 2;
836 localTm.tm_isdst = -1; /* compute whether DST in effect */
838 *unixTimep = mktime(&localTm);
841 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
843 time_t diff_t = unixTime - smb_localZero;
844 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
845 osi_assert(diff_t < _UI32_MAX);
847 *dosUTimep = (afs_uint32)diff_t;
850 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
853 *unixTimep = dosTime + smb_localZero;
855 /* dosTime seems to be already adjusted for GMT */
856 *unixTimep = dosTime;
860 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
864 lock_ObtainWrite(&smb_rctLock);
865 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
866 if (lsn == vcp->lsn && lana == vcp->lana) {
867 smb_HoldVCNoLock(vcp);
871 if (!vcp && (flags & SMB_FLAG_CREATE)) {
872 vcp = malloc(sizeof(*vcp));
873 memset(vcp, 0, sizeof(*vcp));
874 vcp->vcID = numVCs++;
875 vcp->refCount = 2; /* smb_allVCsp and caller */
878 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
879 vcp->nextp = smb_allVCsp;
881 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
886 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
887 /* We must obtain a challenge for extended auth
888 * in case the client negotiates smb v3
890 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
891 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
892 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
893 ULONG lsaRespSize = 0;
895 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
897 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
904 if (nts != STATUS_SUCCESS)
905 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
906 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
907 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
909 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
910 LsaFreeReturnBuffer(lsaResp);
913 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
915 if (numVCs >= CM_SESSION_RESERVED) {
917 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
920 lock_ReleaseWrite(&smb_rctLock);
924 int smb_IsStarMask(char *maskp)
929 for(i=0; i<11; i++) {
931 if (tc == '?' || tc == '*' || tc == '>') return 1;
936 void smb_ReleaseVCInternal(smb_vc_t *vcp)
939 osi_assert(vcp->refCount-- != 0);
944 if (vcp->refCount == 0) {
945 memset(vcp,0,sizeof(smb_vc_t));
950 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
952 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
953 smb_ReleaseVCInternal(vcp);
956 void smb_ReleaseVC(smb_vc_t *vcp)
958 lock_ObtainWrite(&smb_rctLock);
959 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
960 smb_ReleaseVCInternal(vcp);
961 lock_ReleaseWrite(&smb_rctLock);
964 void smb_HoldVCNoLock(smb_vc_t *vcp)
967 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
970 void smb_HoldVC(smb_vc_t *vcp)
972 lock_ObtainWrite(&smb_rctLock);
974 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
975 lock_ReleaseWrite(&smb_rctLock);
978 void smb_CleanupDeadVC(smb_vc_t *vcp)
988 smb_user_t *userpIter;
989 smb_user_t *userpNext;
994 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
996 lock_ObtainRead(&smb_rctLock);
997 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
998 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1000 if (fidpIter->flags & SMB_FID_DELETE)
1003 fid = fidpIter->fid;
1004 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1005 lock_ReleaseRead(&smb_rctLock);
1007 fidp = smb_FindFID(vcp, fid, 0);
1009 smb_CloseFID(vcp, fidp, NULL, 0);
1010 smb_ReleaseFID(fidp);
1012 lock_ObtainRead(&smb_rctLock);
1015 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1016 tidpNext = tidpIter->nextp;
1018 if (tidpIter->flags & SMB_TIDFLAG_DELETE)
1021 tid = tidpIter->tid;
1022 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1023 lock_ReleaseRead(&smb_rctLock);
1025 tidp = smb_FindTID(vcp, tid, 0);
1028 lock_ObtainMutex(&tidp->mx);
1029 tidp->flags |= SMB_TIDFLAG_DELETE;
1030 lock_ReleaseMutex(&tidp->mx);
1032 smb_ReleaseTID(tidp);
1034 lock_ObtainRead(&smb_rctLock);
1037 for (userpIter = vcp->usersp; userpIter; userpIter = userpNext) {
1038 userpNext = userpIter->nextp;
1040 if (userpIter->flags & SMB_USERFLAG_DELETE)
1043 uid = userpIter->userID;
1044 osi_Log2(smb_logp, " Cleanup UID %d (userp=0x%x)", uid, userpIter);
1045 lock_ReleaseRead(&smb_rctLock);
1047 userp = smb_FindUID(vcp, uid, 0);
1050 lock_ObtainMutex(&userp->mx);
1051 userp->flags |= SMB_USERFLAG_DELETE;
1052 lock_ReleaseMutex(&userp->mx);
1054 smb_ReleaseUID(userp);
1056 lock_ObtainRead(&smb_rctLock);
1059 /* remove VCP from smb_allVCsp */
1060 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1063 smb_ReleaseVCNoLock(vcp);
1067 lock_ReleaseRead(&smb_rctLock);
1068 osi_Log0(smb_logp, "Done cleaning up dead vcp");
1071 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1075 lock_ObtainWrite(&smb_rctLock);
1076 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1077 if (tid == tidp->tid) {
1082 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1083 tidp = malloc(sizeof(*tidp));
1084 memset(tidp, 0, sizeof(*tidp));
1085 tidp->nextp = vcp->tidsp;
1088 smb_HoldVCNoLock(vcp);
1090 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1093 lock_ReleaseWrite(&smb_rctLock);
1097 void smb_ReleaseTID(smb_tid_t *tidp)
1104 lock_ObtainWrite(&smb_rctLock);
1105 osi_assert(tidp->refCount-- > 0);
1106 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
1107 ltpp = &tidp->vcp->tidsp;
1108 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1112 osi_assert(tp != NULL);
1114 lock_FinalizeMutex(&tidp->mx);
1115 userp = tidp->userp; /* remember to drop ref later */
1117 smb_ReleaseVCNoLock(tidp->vcp);
1120 lock_ReleaseWrite(&smb_rctLock);
1122 cm_ReleaseUser(userp);
1125 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1127 smb_user_t *uidp = NULL;
1129 lock_ObtainWrite(&smb_rctLock);
1130 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1131 if (uid == uidp->userID) {
1133 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1135 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1139 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1140 uidp = malloc(sizeof(*uidp));
1141 memset(uidp, 0, sizeof(*uidp));
1142 uidp->nextp = vcp->usersp;
1143 uidp->refCount = 2; /* one for the vcp and one for the caller */
1145 smb_HoldVCNoLock(vcp);
1147 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1149 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1151 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1153 lock_ReleaseWrite(&smb_rctLock);
1157 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1159 smb_username_t *unp= NULL;
1161 lock_ObtainWrite(&smb_rctLock);
1162 for(unp = usernamesp; unp; unp = unp->nextp) {
1163 if (stricmp(unp->name, usern) == 0 &&
1164 stricmp(unp->machine, machine) == 0) {
1169 if (!unp && (flags & SMB_FLAG_CREATE)) {
1170 unp = malloc(sizeof(*unp));
1171 memset(unp, 0, sizeof(*unp));
1173 unp->nextp = usernamesp;
1174 unp->name = strdup(usern);
1175 unp->machine = strdup(machine);
1177 lock_InitializeMutex(&unp->mx, "username_t mutex");
1179 lock_ReleaseWrite(&smb_rctLock);
1183 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1185 smb_user_t *uidp= NULL;
1187 lock_ObtainWrite(&smb_rctLock);
1188 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1191 if (stricmp(uidp->unp->name, usern) == 0) {
1193 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1194 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1199 lock_ReleaseWrite(&smb_rctLock);
1203 void smb_ReleaseUsername(smb_username_t *unp)
1206 smb_username_t **lupp;
1207 cm_user_t *userp = NULL;
1209 lock_ObtainWrite(&smb_rctLock);
1210 osi_assert(unp->refCount-- > 0);
1211 if (unp->refCount == 0) {
1213 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1217 osi_assert(up != NULL);
1219 lock_FinalizeMutex(&unp->mx);
1225 lock_ReleaseWrite(&smb_rctLock);
1228 cm_ReleaseUserVCRef(userp);
1229 cm_ReleaseUser(userp);
1233 void smb_ReleaseUID(smb_user_t *uidp)
1237 smb_username_t *unp = NULL;
1239 lock_ObtainWrite(&smb_rctLock);
1240 osi_assert(uidp->refCount-- > 0);
1241 if (uidp->refCount == 0) {
1242 lupp = &uidp->vcp->usersp;
1243 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1247 osi_assert(up != NULL);
1249 lock_FinalizeMutex(&uidp->mx);
1251 smb_ReleaseVCNoLock(uidp->vcp);
1254 lock_ReleaseWrite(&smb_rctLock);
1257 smb_ReleaseUsername(unp);
1260 /* retrieve a held reference to a user structure corresponding to an incoming
1262 * corresponding release function is cm_ReleaseUser.
1264 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1267 cm_user_t *up = NULL;
1270 smbp = (smb_t *) inp;
1271 uidp = smb_FindUID(vcp, smbp->uid, 0);
1275 lock_ObtainMutex(&uidp->mx);
1277 up = uidp->unp->userp;
1280 lock_ReleaseMutex(&uidp->mx);
1282 smb_ReleaseUID(uidp);
1287 * Return a pointer to a pathname extracted from a TID structure. The
1288 * TID structure is not held; assume it won't go away.
1290 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1295 tidp = smb_FindTID(vcp, tid, 0);
1299 if (tidp->flags & SMB_TIDFLAG_IPC) {
1300 code = CM_ERROR_TIDIPC;
1301 /* tidp->pathname would be NULL, but that's fine */
1303 *treepath = tidp->pathname;
1304 smb_ReleaseTID(tidp);
1309 /* check to see if we have a chained fid, that is, a fid that comes from an
1310 * OpenAndX message that ran earlier in this packet. In this case, the fid
1311 * field in a read, for example, request, isn't set, since the value is
1312 * supposed to be inherited from the openAndX call.
1314 int smb_ChainFID(int fid, smb_packet_t *inp)
1316 if (inp->fid == 0 || inp->inCount == 0)
1322 /* are we a priv'd user? What does this mean on NT? */
1323 int smb_SUser(cm_user_t *userp)
1328 /* find a file ID. If we pass in 0 we select an unused File ID.
1329 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1330 * smb_fid_t data structure if desired File ID cannot be found.
1332 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1337 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1340 lock_ObtainWrite(&smb_rctLock);
1341 /* figure out if we need to allocate a new file ID */
1344 fid = vcp->fidCounter;
1348 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1349 if (fid == fidp->fid) {
1354 "New FID number wraps on vcp 0x%x", vcp);
1364 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1365 char eventName[MAX_PATH];
1367 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1368 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1369 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1370 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1371 thrd_CloseHandle(event);
1374 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1380 fidp = malloc(sizeof(*fidp));
1381 memset(fidp, 0, sizeof(*fidp));
1382 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1385 smb_HoldVCNoLock(vcp);
1386 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1388 fidp->curr_chunk = fidp->prev_chunk = -2;
1389 fidp->raw_write_event = event;
1391 vcp->fidCounter = fid+1;
1392 if (vcp->fidCounter == 0) {
1393 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1395 vcp->fidCounter = 1;
1400 lock_ReleaseWrite(&smb_rctLock);
1404 void smb_ReleaseFID(smb_fid_t *fidp)
1408 smb_vc_t *vcp = NULL;
1409 smb_ioctl_t *ioctlp;
1416 lock_ObtainWrite(&smb_rctLock);
1417 osi_assert(fidp->refCount-- > 0);
1418 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1421 scp = fidp->scp; /* release after lock is released */
1423 userp = fidp->userp;
1426 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1427 thrd_CloseHandle(fidp->raw_write_event);
1429 /* and see if there is ioctl stuff to free */
1430 ioctlp = fidp->ioctlp;
1433 cm_FreeSpace(ioctlp->prefix);
1434 if (ioctlp->inAllocp)
1435 free(ioctlp->inAllocp);
1436 if (ioctlp->outAllocp)
1437 free(ioctlp->outAllocp);
1443 smb_ReleaseVCNoLock(vcp);
1445 lock_ReleaseWrite(&smb_rctLock);
1447 /* now release the scache structure */
1449 cm_ReleaseSCache(scp);
1452 cm_ReleaseUser(userp);
1456 * Case-insensitive search for one string in another;
1457 * used to find variable names in submount pathnames.
1459 static char *smb_stristr(char *str1, char *str2)
1463 for (cursor = str1; *cursor; cursor++)
1464 if (stricmp(cursor, str2) == 0)
1471 * Substitute a variable value for its name in a submount pathname. Variable
1472 * name has been identified by smb_stristr() and is in substr. Variable name
1473 * length (plus one) is in substr_size. Variable value is in newstr.
1475 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1480 strcpy(temp, substr + substr_size - 1);
1481 strcpy(substr, newstr);
1485 char VNUserName[] = "%USERNAME%";
1486 char VNLCUserName[] = "%LCUSERNAME%";
1487 char VNComputerName[] = "%COMPUTERNAME%";
1488 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1491 /* List available shares */
1492 int smb_ListShares()
1496 char shareBuf[4096];
1504 /*strcpy(shareNameList[num_shares], "all");
1505 strcpy(pathNameList[num_shares++], "/afs");*/
1506 fprintf(stderr, "The following shares are available:\n");
1507 fprintf(stderr, "Share Name (AFS Path)\n");
1508 fprintf(stderr, "---------------------\n");
1509 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1512 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1513 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1515 strcpy(sbmtpath, cm_confDir);
1517 strcat(sbmtpath, "/afsdsbmt.ini");
1518 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1519 shareBuf, sizeof(shareBuf),
1525 this_share = shareBuf;
1529 /*strcpy(shareNameList[num_shares], this_share);*/
1530 len = GetPrivateProfileString("AFS Submounts", this_share,
1537 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1540 if (*p == '\\') *p = '/'; /* change to / */
1544 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1545 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1548 while (*this_share != 0) this_share++; /* find next NUL */
1549 this_share++; /* skip past the NUL */
1550 } while (*this_share != 0); /* stop at final NUL */
1556 typedef struct smb_findShare_rock {
1560 } smb_findShare_rock_t;
1562 #define SMB_FINDSHARE_EXACT_MATCH 1
1563 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1565 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1569 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1570 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1571 if(!stricmp(dep->name, vrock->shareName))
1572 matchType = SMB_FINDSHARE_EXACT_MATCH;
1574 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1575 if(vrock->match) free(vrock->match);
1576 vrock->match = strdup(dep->name);
1577 vrock->matchType = matchType;
1579 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1580 return CM_ERROR_STOPNOW;
1586 /* find a shareName in the table of submounts */
1587 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1591 char pathName[1024];
1596 char sbmtpath[MAX_PATH];
1601 DWORD allSubmount = 1;
1603 /* if allSubmounts == 0, only return the //mountRoot/all share
1604 * if in fact it has been been created in the subMounts table.
1605 * This is to allow sites that want to restrict access to the
1608 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1609 0, KEY_QUERY_VALUE, &parmKey);
1610 if (code == ERROR_SUCCESS) {
1611 len = sizeof(allSubmount);
1612 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1613 (BYTE *) &allSubmount, &len);
1614 if (code != ERROR_SUCCESS) {
1617 RegCloseKey (parmKey);
1620 if (allSubmount && _stricmp(shareName, "all") == 0) {
1625 /* In case, the all share is disabled we need to still be able
1626 * to handle ioctl requests
1628 if (_stricmp(shareName, "ioctl$") == 0) {
1629 *pathNamep = strdup("/.__ioctl__");
1633 if (_stricmp(shareName, "IPC$") == 0 ||
1634 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1635 _stricmp(shareName, "DESKTOP.INI") == 0
1642 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1643 0, KEY_QUERY_VALUE, &parmKey);
1644 if (code == ERROR_SUCCESS) {
1645 len = sizeof(pathName);
1646 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1647 (BYTE *) pathName, &len);
1648 if (code != ERROR_SUCCESS)
1650 RegCloseKey (parmKey);
1655 strcpy(sbmtpath, cm_confDir);
1656 strcat(sbmtpath, "/afsdsbmt.ini");
1657 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1658 pathName, sizeof(pathName), sbmtpath);
1660 if (len != 0 && len != sizeof(pathName) - 1) {
1661 /* We can accept either unix or PC style AFS pathnames. Convert
1662 * Unix-style to PC style here for internal use.
1665 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1666 p += strlen(cm_mountRoot); /* skip mount path */
1669 if (*q == '/') *q = '\\'; /* change to \ */
1675 if (var = smb_stristr(p, VNUserName)) {
1676 if (uidp && uidp->unp)
1677 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1679 smb_subst(p, var, sizeof(VNUserName)," ");
1681 else if (var = smb_stristr(p, VNLCUserName))
1683 if (uidp && uidp->unp)
1684 strcpy(temp, uidp->unp->name);
1688 smb_subst(p, var, sizeof(VNLCUserName), temp);
1690 else if (var = smb_stristr(p, VNComputerName))
1692 sizeTemp = sizeof(temp);
1693 GetComputerName((LPTSTR)temp, &sizeTemp);
1694 smb_subst(p, var, sizeof(VNComputerName), temp);
1696 else if (var = smb_stristr(p, VNLCComputerName))
1698 sizeTemp = sizeof(temp);
1699 GetComputerName((LPTSTR)temp, &sizeTemp);
1701 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1706 *pathNamep = strdup(p);
1711 /* First lookup shareName in root.afs */
1713 smb_findShare_rock_t vrock;
1715 char * p = shareName;
1718 /* attempt to locate a partial match in root.afs. This is because
1719 when using the ANSI RAP calls, the share name is limited to 13 chars
1720 and hence is truncated. Of course we prefer exact matches. */
1722 thyper.HighPart = 0;
1725 vrock.shareName = shareName;
1727 vrock.matchType = 0;
1729 cm_HoldSCache(cm_data.rootSCachep);
1730 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1731 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1732 cm_ReleaseSCache(cm_data.rootSCachep);
1734 if (vrock.matchType) {
1735 sprintf(pathName,"/%s/",vrock.match);
1736 *pathNamep = strdup(strlwr(pathName));
1741 /* if we get here, there was no match for the share in root.afs */
1742 /* so try to create \\<netbiosName>\<cellname> */
1747 /* Get the full name for this cell */
1748 code = cm_SearchCellFile(p, temp, 0, 0);
1749 #ifdef AFS_AFSDB_ENV
1750 if (code && cm_dnsEnabled) {
1752 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1755 /* construct the path */
1757 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1758 *pathNamep = strdup(strlwr(pathName));
1767 /* Client-side offline caching policy types */
1768 #define CSC_POLICY_MANUAL 0
1769 #define CSC_POLICY_DOCUMENTS 1
1770 #define CSC_POLICY_PROGRAMS 2
1771 #define CSC_POLICY_DISABLE 3
1773 int smb_FindShareCSCPolicy(char *shareName)
1779 int retval = CSC_POLICY_MANUAL;
1781 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1782 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1785 REG_OPTION_NON_VOLATILE,
1791 len = sizeof(policy);
1792 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1794 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1796 else if (stricmp(policy, "documents") == 0)
1798 retval = CSC_POLICY_DOCUMENTS;
1800 else if (stricmp(policy, "programs") == 0)
1802 retval = CSC_POLICY_PROGRAMS;
1804 else if (stricmp(policy, "disable") == 0)
1806 retval = CSC_POLICY_DISABLE;
1809 RegCloseKey(hkCSCPolicy);
1813 /* find a dir search structure by cookie value, and return it held.
1814 * Must be called with smb_globalLock held.
1816 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1818 smb_dirSearch_t *dsp;
1820 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1821 if (dsp->cookie == cookie) {
1822 if (dsp != smb_firstDirSearchp) {
1823 /* move to head of LRU queue, too, if we're not already there */
1824 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1825 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1826 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1827 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1828 if (!smb_lastDirSearchp)
1829 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1831 lock_ObtainMutex(&dsp->mx);
1833 lock_ReleaseMutex(&dsp->mx);
1839 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1840 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1841 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1847 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1849 lock_ObtainWrite(&smb_globalLock);
1850 lock_ObtainMutex(&dsp->mx);
1851 dsp->flags |= SMB_DIRSEARCH_DELETE;
1852 if (dsp->scp != NULL) {
1853 lock_ObtainMutex(&dsp->scp->mx);
1854 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1855 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1856 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1857 dsp->scp->bulkStatProgress = hones;
1859 lock_ReleaseMutex(&dsp->scp->mx);
1861 lock_ReleaseMutex(&dsp->mx);
1862 lock_ReleaseWrite(&smb_globalLock);
1865 /* Must be called with the smb_globalLock held */
1866 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1868 cm_scache_t *scp = NULL;
1870 lock_ObtainMutex(&dsp->mx);
1871 osi_assert(dsp->refCount-- > 0);
1872 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1873 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1874 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1875 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1876 lock_ReleaseMutex(&dsp->mx);
1877 lock_FinalizeMutex(&dsp->mx);
1881 lock_ReleaseMutex(&dsp->mx);
1883 /* do this now to avoid spurious locking hierarchy creation */
1885 cm_ReleaseSCache(scp);
1888 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1890 lock_ObtainWrite(&smb_globalLock);
1891 smb_ReleaseDirSearchNoLock(dsp);
1892 lock_ReleaseWrite(&smb_globalLock);
1895 /* find a dir search structure by cookie value, and return it held */
1896 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1898 smb_dirSearch_t *dsp;
1900 lock_ObtainWrite(&smb_globalLock);
1901 dsp = smb_FindDirSearchNoLock(cookie);
1902 lock_ReleaseWrite(&smb_globalLock);
1906 /* GC some dir search entries, in the address space expected by the specific protocol.
1907 * Must be called with smb_globalLock held; release the lock temporarily.
1909 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1910 void smb_GCDirSearches(int isV3)
1912 smb_dirSearch_t *prevp;
1913 smb_dirSearch_t *tp;
1914 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1918 victimCount = 0; /* how many have we got so far */
1919 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1920 /* we'll move tp from queue, so
1923 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1924 /* if no one is using this guy, and we're either in the new protocol,
1925 * or we're in the old one and this is a small enough ID to be useful
1926 * to the old protocol, GC this guy.
1928 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1929 /* hold and delete */
1930 tp->flags |= SMB_DIRSEARCH_DELETE;
1931 victimsp[victimCount++] = tp;
1935 /* don't do more than this */
1936 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1940 /* now release them */
1941 for (i = 0; i < victimCount; i++) {
1942 smb_ReleaseDirSearchNoLock(victimsp[i]);
1946 /* function for allocating a dir search entry. We need these to remember enough context
1947 * since we don't get passed the path from call to call during a directory search.
1949 * Returns a held dir search structure, and bumps the reference count on the vnode,
1950 * since it saves a pointer to the vnode.
1952 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1954 smb_dirSearch_t *dsp;
1960 lock_ObtainWrite(&smb_globalLock);
1963 /* what's the biggest ID allowed in this version of the protocol */
1964 maxAllowed = isV3 ? 65535 : 255;
1965 if (smb_dirSearchCounter > maxAllowed)
1966 smb_dirSearchCounter = 1;
1968 start = smb_dirSearchCounter;
1971 /* twice so we have enough tries to find guys we GC after one pass;
1972 * 10 extra is just in case I mis-counted.
1974 if (++counter > 2*maxAllowed+10)
1975 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1977 if (smb_dirSearchCounter > maxAllowed) {
1978 smb_dirSearchCounter = 1;
1980 if (smb_dirSearchCounter == start) {
1982 smb_GCDirSearches(isV3);
1985 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1987 /* don't need to watch for refcount zero and deleted, since
1988 * we haven't dropped the global lock.
1990 lock_ObtainMutex(&dsp->mx);
1992 lock_ReleaseMutex(&dsp->mx);
1993 ++smb_dirSearchCounter;
1997 dsp = malloc(sizeof(*dsp));
1998 memset(dsp, 0, sizeof(*dsp));
1999 dsp->cookie = smb_dirSearchCounter;
2000 ++smb_dirSearchCounter;
2002 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2003 dsp->lastTime = osi_Time();
2004 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2005 if (!smb_lastDirSearchp)
2006 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2009 lock_ReleaseWrite(&smb_globalLock);
2013 static smb_packet_t *GetPacket(void)
2017 unsigned int npar, seg, tb_sel;
2020 lock_ObtainWrite(&smb_globalLock);
2021 tbp = smb_packetFreeListp;
2023 smb_packetFreeListp = tbp->nextp;
2024 lock_ReleaseWrite(&smb_globalLock);
2027 tbp = calloc(65540,1);
2029 tbp = malloc(sizeof(smb_packet_t));
2031 tbp->magic = SMB_PACKETMAGIC;
2034 tbp->resumeCode = 0;
2040 tbp->ncb_length = 0;
2045 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
2048 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2050 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
2052 osi_panic("",__FILE__,__LINE__);
2055 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
2060 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
2061 tbp->dos_pkt_sel = tb_sel;
2064 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2069 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2073 memcpy(tbp, pkt, sizeof(smb_packet_t));
2074 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2076 smb_HoldVC(tbp->vcp);
2080 static NCB *GetNCB(void)
2085 unsigned int npar, seg, tb_sel;
2088 lock_ObtainWrite(&smb_globalLock);
2089 tbp = smb_ncbFreeListp;
2091 smb_ncbFreeListp = tbp->nextp;
2092 lock_ReleaseWrite(&smb_globalLock);
2095 tbp = calloc(sizeof(*tbp),1);
2097 tbp = malloc(sizeof(*tbp));
2098 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
2101 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
2103 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
2105 osi_panic("",__FILE__,__LINE__);
2107 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
2112 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
2113 tbp->dos_ncb_sel = tb_sel;
2115 tbp->magic = SMB_NCBMAGIC;
2118 osi_assert(tbp->magic == SMB_NCBMAGIC);
2120 memset(&tbp->ncb, 0, sizeof(NCB));
2123 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
2128 void smb_FreePacket(smb_packet_t *tbp)
2130 smb_vc_t * vcp = NULL;
2131 osi_assert(tbp->magic == SMB_PACKETMAGIC);
2133 lock_ObtainWrite(&smb_globalLock);
2134 tbp->nextp = smb_packetFreeListp;
2135 smb_packetFreeListp = tbp;
2136 tbp->magic = SMB_PACKETMAGIC;
2140 tbp->resumeCode = 0;
2146 tbp->ncb_length = 0;
2148 lock_ReleaseWrite(&smb_globalLock);
2154 static void FreeNCB(NCB *bufferp)
2158 tbp = (smb_ncb_t *) bufferp;
2159 osi_assert(tbp->magic == SMB_NCBMAGIC);
2161 lock_ObtainWrite(&smb_globalLock);
2162 tbp->nextp = smb_ncbFreeListp;
2163 smb_ncbFreeListp = tbp;
2164 lock_ReleaseWrite(&smb_globalLock);
2167 /* get a ptr to the data part of a packet, and its count */
2168 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2172 unsigned char *afterParmsp;
2174 parmBytes = *smbp->wctp << 1;
2175 afterParmsp = smbp->wctp + parmBytes + 1;
2177 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2178 if (nbytesp) *nbytesp = dataBytes;
2180 /* don't forget to skip the data byte count, since it follows
2181 * the parameters; that's where the "2" comes from below.
2183 return (unsigned char *) (afterParmsp + 2);
2186 /* must set all the returned parameters before playing around with the
2187 * data region, since the data region is located past the end of the
2188 * variable number of parameters.
2190 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2192 unsigned char *afterParmsp;
2194 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2196 *afterParmsp++ = dsize & 0xff;
2197 *afterParmsp = (dsize>>8) & 0xff;
2200 /* return the parm'th parameter in the smbp packet */
2201 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2204 unsigned char *parmDatap;
2206 parmCount = *smbp->wctp;
2208 if (parm >= parmCount) {
2211 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2212 parm, parmCount, smbp->ncb_length);
2213 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2214 parm, parmCount, smbp->ncb_length);
2216 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2217 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2219 osi_panic(s, __FILE__, __LINE__);
2221 parmDatap = smbp->wctp + (2*parm) + 1;
2223 return parmDatap[0] + (parmDatap[1] << 8);
2226 /* return the parm'th parameter in the smbp packet */
2227 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2230 unsigned char *parmDatap;
2232 parmCount = *smbp->wctp;
2234 if (parm * 2 + offset >= parmCount * 2) {
2237 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2238 parm, offset, parmCount, smbp->ncb_length);
2240 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2241 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2243 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2244 parm, offset, parmCount, smbp->ncb_length);
2245 osi_panic(s, __FILE__, __LINE__);
2247 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2249 return parmDatap[0] + (parmDatap[1] << 8);
2252 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2256 /* make sure we have enough slots */
2257 if (*smbp->wctp <= slot)
2258 *smbp->wctp = slot+1;
2260 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2261 *parmDatap++ = parmValue & 0xff;
2262 *parmDatap = (parmValue>>8) & 0xff;
2265 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2269 /* make sure we have enough slots */
2270 if (*smbp->wctp <= slot)
2271 *smbp->wctp = slot+2;
2273 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2274 *parmDatap++ = parmValue & 0xff;
2275 *parmDatap++ = (parmValue>>8) & 0xff;
2276 *parmDatap++ = (parmValue>>16) & 0xff;
2277 *parmDatap++ = (parmValue>>24) & 0xff;
2280 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2285 /* make sure we have enough slots */
2286 if (*smbp->wctp <= slot)
2287 *smbp->wctp = slot+4;
2289 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2291 *parmDatap++ = *parmValuep++;
2294 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2298 /* make sure we have enough slots */
2299 if (*smbp->wctp <= slot) {
2300 if (smbp->oddByte) {
2302 *smbp->wctp = slot+1;
2307 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2308 *parmDatap++ = parmValue & 0xff;
2311 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2315 lastSlashp = strrchr(inPathp, '\\');
2317 *lastComponentp = lastSlashp;
2320 if (inPathp == lastSlashp)
2322 *outPathp++ = *inPathp++;
2331 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2336 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2341 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2347 tlen = inp[0] + (inp[1]<<8);
2348 inp += 2; /* skip length field */
2351 *chainpp = inp + tlen;
2360 /* format a packet as a response */
2361 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2366 outp = (smb_t *) op;
2368 /* zero the basic structure through the smb_wct field, and zero the data
2369 * size field, assuming that wct stays zero; otherwise, you have to
2370 * explicitly set the data size field, too.
2372 inSmbp = (smb_t *) inp;
2373 memset(outp, 0, sizeof(smb_t)+2);
2379 outp->com = inSmbp->com;
2380 outp->tid = inSmbp->tid;
2381 outp->pid = inSmbp->pid;
2382 outp->uid = inSmbp->uid;
2383 outp->mid = inSmbp->mid;
2384 outp->res[0] = inSmbp->res[0];
2385 outp->res[1] = inSmbp->res[1];
2386 op->inCom = inSmbp->com;
2388 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2389 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2391 /* copy fields in generic packet area */
2392 op->wctp = &outp->wct;
2395 /* send a (probably response) packet; vcp tells us to whom to send it.
2396 * we compute the length by looking at wct and bcc fields.
2398 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2415 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2418 memset((char *)ncbp, 0, sizeof(NCB));
2420 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2421 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2422 extra += tp[0] + (tp[1]<<8);
2423 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2424 extra += 3; /* wct and length fields */
2426 ncbp->ncb_length = extra; /* bytes to send */
2427 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2428 ncbp->ncb_lana_num = vcp->lana;
2429 ncbp->ncb_command = NCBSEND; /* op means send data */
2431 ncbp->ncb_buffer = (char *) inp;/* packet */
2432 code = Netbios(ncbp);
2434 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2435 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2437 /* copy header information from virtual to DOS address space */
2438 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2439 code = Netbios(ncbp, dos_ncb);
2443 const char * s = ncb_error_string(code);
2444 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2446 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2449 osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
2453 osi_Log1(smb_logp,"Previous dead_vcp %x", dead_vcp);
2454 smb_CleanupDeadVC(dead_vcp);
2455 smb_ReleaseVC(dead_vcp);
2458 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2465 void smb_MapNTError(long code, unsigned long *NTStatusp)
2467 unsigned long NTStatus;
2469 /* map CM_ERROR_* errors to NT 32-bit status codes */
2470 /* NT Status codes are listed in ntstatus.h not winerror.h */
2471 if (code == CM_ERROR_NOSUCHCELL) {
2472 NTStatus = 0xC000000FL; /* No such file */
2474 else if (code == CM_ERROR_NOSUCHVOLUME) {
2475 NTStatus = 0xC000000FL; /* No such file */
2477 else if (code == CM_ERROR_TIMEDOUT) {
2479 NTStatus = 0xC00000CFL; /* Sharing Paused */
2481 NTStatus = 0x00000102L; /* Timeout */
2484 else if (code == CM_ERROR_RETRY) {
2485 NTStatus = 0xC000022DL; /* Retry */
2487 else if (code == CM_ERROR_NOACCESS) {
2488 NTStatus = 0xC0000022L; /* Access denied */
2490 else if (code == CM_ERROR_READONLY) {
2491 NTStatus = 0xC00000A2L; /* Write protected */
2493 else if (code == CM_ERROR_NOSUCHFILE) {
2494 NTStatus = 0xC000000FL; /* No such file */
2496 else if (code == CM_ERROR_NOSUCHPATH) {
2497 NTStatus = 0xC000003AL; /* Object path not found */
2499 else if (code == CM_ERROR_TOOBIG) {
2500 NTStatus = 0xC000007BL; /* Invalid image format */
2502 else if (code == CM_ERROR_INVAL) {
2503 NTStatus = 0xC000000DL; /* Invalid parameter */
2505 else if (code == CM_ERROR_BADFD) {
2506 NTStatus = 0xC0000008L; /* Invalid handle */
2508 else if (code == CM_ERROR_BADFDOP) {
2509 NTStatus = 0xC0000022L; /* Access denied */
2511 else if (code == CM_ERROR_EXISTS) {
2512 NTStatus = 0xC0000035L; /* Object name collision */
2514 else if (code == CM_ERROR_NOTEMPTY) {
2515 NTStatus = 0xC0000101L; /* Directory not empty */
2517 else if (code == CM_ERROR_CROSSDEVLINK) {
2518 NTStatus = 0xC00000D4L; /* Not same device */
2520 else if (code == CM_ERROR_NOTDIR) {
2521 NTStatus = 0xC0000103L; /* Not a directory */
2523 else if (code == CM_ERROR_ISDIR) {
2524 NTStatus = 0xC00000BAL; /* File is a directory */
2526 else if (code == CM_ERROR_BADOP) {
2528 /* I have no idea where this comes from */
2529 NTStatus = 0xC09820FFL; /* SMB no support */
2531 NTStatus = 0xC00000BBL; /* Not supported */
2532 #endif /* COMMENT */
2534 else if (code == CM_ERROR_BADSHARENAME) {
2535 NTStatus = 0xC00000CCL; /* Bad network name */
2537 else if (code == CM_ERROR_NOIPC) {
2539 NTStatus = 0xC0000022L; /* Access Denied */
2541 NTStatus = 0xC000013DL; /* Remote Resources */
2544 else if (code == CM_ERROR_CLOCKSKEW) {
2545 NTStatus = 0xC0000133L; /* Time difference at DC */
2547 else if (code == CM_ERROR_BADTID) {
2548 NTStatus = 0xC0982005L; /* SMB bad TID */
2550 else if (code == CM_ERROR_USESTD) {
2551 NTStatus = 0xC09820FBL; /* SMB use standard */
2553 else if (code == CM_ERROR_QUOTA) {
2555 NTStatus = 0xC0000044L; /* Quota exceeded */
2557 NTStatus = 0xC000007FL; /* Disk full */
2560 else if (code == CM_ERROR_SPACE) {
2561 NTStatus = 0xC000007FL; /* Disk full */
2563 else if (code == CM_ERROR_ATSYS) {
2564 NTStatus = 0xC0000033L; /* Object name invalid */
2566 else if (code == CM_ERROR_BADNTFILENAME) {
2567 NTStatus = 0xC0000033L; /* Object name invalid */
2569 else if (code == CM_ERROR_WOULDBLOCK) {
2570 NTStatus = 0xC0000055L; /* Lock not granted */
2572 else if (code == CM_ERROR_SHARING_VIOLATION) {
2573 NTStatus = 0xC0000043L; /* Sharing violation */
2575 else if (code == CM_ERROR_LOCK_CONFLICT) {
2576 NTStatus = 0xC0000054L; /* Lock conflict */
2578 else if (code == CM_ERROR_PARTIALWRITE) {
2579 NTStatus = 0xC000007FL; /* Disk full */
2581 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2582 NTStatus = 0xC0000023L; /* Buffer too small */
2584 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2585 NTStatus = 0xC0000035L; /* Object name collision */
2587 else if (code == CM_ERROR_BADPASSWORD) {
2588 NTStatus = 0xC000006DL; /* unknown username or bad password */
2590 else if (code == CM_ERROR_BADLOGONTYPE) {
2591 NTStatus = 0xC000015BL; /* logon type not granted */
2593 else if (code == CM_ERROR_GSSCONTINUE) {
2594 NTStatus = 0xC0000016L; /* more processing required */
2596 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2598 NTStatus = 0xC0000280L; /* reparse point not resolved */
2600 NTStatus = 0xC0000022L; /* Access Denied */
2603 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2604 NTStatus = 0xC0000257L; /* Path Not Covered */
2607 else if (code == CM_ERROR_ALLBUSY) {
2608 NTStatus = 0xC00000BFL; /* Network Busy */
2610 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2611 NTStatus = 0xC0000350L; /* Remote Host Down */
2614 /* we do not want to be telling the SMB/CIFS client that
2615 * the AFS Client Service is busy or down.
2617 else if (code == CM_ERROR_ALLBUSY ||
2618 code == CM_ERROR_ALLOFFLINE ||
2619 code == CM_ERROR_ALLDOWN) {
2620 NTStatus = 0xC00000BEL; /* Bad Network Path */
2623 else if (code == RXKADUNKNOWNKEY) {
2624 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2626 NTStatus = 0xC0982001L; /* SMB non-specific error */
2629 *NTStatusp = NTStatus;
2630 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2633 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2634 unsigned char *classp)
2636 unsigned char class;
2637 unsigned short error;
2639 /* map CM_ERROR_* errors to SMB errors */
2640 if (code == CM_ERROR_NOSUCHCELL) {
2642 error = 3; /* bad path */
2644 else if (code == CM_ERROR_NOSUCHVOLUME) {
2646 error = 3; /* bad path */
2648 else if (code == CM_ERROR_TIMEDOUT) {
2650 error = 81; /* server is paused */
2652 else if (code == CM_ERROR_RETRY) {
2653 class = 2; /* shouldn't happen */
2656 else if (code == CM_ERROR_NOACCESS) {
2658 error = 4; /* bad access */
2660 else if (code == CM_ERROR_READONLY) {
2662 error = 19; /* read only */
2664 else if (code == CM_ERROR_NOSUCHFILE) {
2666 error = 2; /* ENOENT! */
2668 else if (code == CM_ERROR_NOSUCHPATH) {
2670 error = 3; /* Bad path */
2672 else if (code == CM_ERROR_TOOBIG) {
2674 error = 11; /* bad format */
2676 else if (code == CM_ERROR_INVAL) {
2677 class = 2; /* server non-specific error code */
2680 else if (code == CM_ERROR_BADFD) {
2682 error = 6; /* invalid file handle */
2684 else if (code == CM_ERROR_BADFDOP) {
2685 class = 1; /* invalid op on FD */
2688 else if (code == CM_ERROR_EXISTS) {
2690 error = 80; /* file already exists */
2692 else if (code == CM_ERROR_NOTEMPTY) {
2694 error = 5; /* delete directory not empty */
2696 else if (code == CM_ERROR_CROSSDEVLINK) {
2698 error = 17; /* EXDEV */
2700 else if (code == CM_ERROR_NOTDIR) {
2701 class = 1; /* bad path */
2704 else if (code == CM_ERROR_ISDIR) {
2705 class = 1; /* access denied; DOS doesn't have a good match */
2708 else if (code == CM_ERROR_BADOP) {
2712 else if (code == CM_ERROR_BADSHARENAME) {
2716 else if (code == CM_ERROR_NOIPC) {
2718 error = 4; /* bad access */
2720 else if (code == CM_ERROR_CLOCKSKEW) {
2721 class = 1; /* invalid function */
2724 else if (code == CM_ERROR_BADTID) {
2728 else if (code == CM_ERROR_USESTD) {
2732 else if (code == CM_ERROR_REMOTECONN) {
2736 else if (code == CM_ERROR_QUOTA) {
2737 if (vcp->flags & SMB_VCFLAG_USEV3) {
2739 error = 39; /* disk full */
2743 error = 5; /* access denied */
2746 else if (code == CM_ERROR_SPACE) {
2747 if (vcp->flags & SMB_VCFLAG_USEV3) {
2749 error = 39; /* disk full */
2753 error = 5; /* access denied */
2756 else if (code == CM_ERROR_PARTIALWRITE) {
2758 error = 39; /* disk full */
2760 else if (code == CM_ERROR_ATSYS) {
2762 error = 2; /* ENOENT */
2764 else if (code == CM_ERROR_WOULDBLOCK) {
2766 error = 33; /* lock conflict */
2768 else if (code == CM_ERROR_LOCK_CONFLICT) {
2770 error = 33; /* lock conflict */
2772 else if (code == CM_ERROR_SHARING_VIOLATION) {
2774 error = 33; /* lock conflict */
2776 else if (code == CM_ERROR_NOFILES) {
2778 error = 18; /* no files in search */
2780 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2782 error = 183; /* Samba uses this */
2784 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2785 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2787 error = 2; /* bad password */
2789 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2791 error = 3; /* bad path */
2800 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2803 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2805 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2806 return CM_ERROR_BADOP;
2809 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2811 unsigned short EchoCount, i;
2812 char *data, *outdata;
2815 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2817 for (i=1; i<=EchoCount; i++) {
2818 data = smb_GetSMBData(inp, &dataSize);
2819 smb_SetSMBParm(outp, 0, i);
2820 smb_SetSMBDataLength(outp, dataSize);
2821 outdata = smb_GetSMBData(outp, NULL);
2822 memcpy(outdata, data, dataSize);
2823 smb_SendPacket(vcp, outp);
2829 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2832 long count, minCount, finalCount;
2837 cm_user_t *userp = NULL;
2841 char *rawBuf = NULL;
2843 dos_ptr rawBuf = NULL;
2850 fd = smb_GetSMBParm(inp, 0);
2851 count = smb_GetSMBParm(inp, 3);
2852 minCount = smb_GetSMBParm(inp, 4);
2853 offset.HighPart = 0; /* too bad */
2854 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2856 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2857 fd, offset.LowPart, count);
2859 fidp = smb_FindFID(vcp, fd, 0);
2863 pid = ((smb_t *) inp)->pid;
2865 LARGE_INTEGER LOffset, LLength;
2868 key = cm_GenerateKey(vcp->vcID, pid, fd);
2870 LOffset.HighPart = 0;
2871 LOffset.LowPart = offset.LowPart;
2872 LLength.HighPart = 0;
2873 LLength.LowPart = count;
2875 lock_ObtainMutex(&fidp->scp->mx);
2876 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2877 lock_ReleaseMutex(&fidp->scp->mx);
2883 lock_ObtainMutex(&smb_RawBufLock);
2885 /* Get a raw buf, from head of list */
2886 rawBuf = smb_RawBufs;
2888 smb_RawBufs = *(char **)smb_RawBufs;
2890 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2893 lock_ReleaseMutex(&smb_RawBufLock);
2897 if (fidp->flags & SMB_FID_IOCTL)
2900 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2902 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2905 /* Give back raw buffer */
2906 lock_ObtainMutex(&smb_RawBufLock);
2908 *((char **) rawBuf) = smb_RawBufs;
2910 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2913 smb_RawBufs = rawBuf;
2914 lock_ReleaseMutex(&smb_RawBufLock);
2917 smb_ReleaseFID(fidp);
2921 userp = smb_GetUser(vcp, inp);
2924 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2926 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2927 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2928 userp, &finalCount, TRUE /* rawFlag */);
2935 cm_ReleaseUser(userp);
2938 smb_ReleaseFID(fidp);
2943 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2945 memset((char *)ncbp, 0, sizeof(NCB));
2947 ncbp->ncb_length = (unsigned short) finalCount;
2948 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2949 ncbp->ncb_lana_num = vcp->lana;
2950 ncbp->ncb_command = NCBSEND;
2951 ncbp->ncb_buffer = rawBuf;
2954 code = Netbios(ncbp);
2956 code = Netbios(ncbp, dos_ncb);
2959 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2962 /* Give back raw buffer */
2963 lock_ObtainMutex(&smb_RawBufLock);
2965 *((char **) rawBuf) = smb_RawBufs;
2967 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2970 smb_RawBufs = rawBuf;
2971 lock_ReleaseMutex(&smb_RawBufLock);
2977 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2979 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2984 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2986 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2991 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2998 int protoIndex; /* index we're using */
3003 char protocol_array[10][1024]; /* protocol signature of the client */
3004 int caps; /* capabilities */
3007 TIME_ZONE_INFORMATION tzi;
3009 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3013 DWORD now = GetTickCount();
3014 if (now - last_msg_time >= 30000) {
3015 smb_vc_t *avcp = active_vcp;
3017 osi_Log1(smb_logp,"Setting dead_vcp %x", avcp);
3019 osi_Log1(smb_logp,"Previous dead_vcp %x", dead_vcp);
3020 smb_CleanupDeadVC(dead_vcp);
3021 smb_ReleaseVC(dead_vcp);
3025 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3026 smb_ReleaseVC(avcp);
3031 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
3033 namep = smb_GetSMBData(inp, &dbytes);
3036 coreProtoIndex = -1; /* not found */
3039 while(namex < dbytes) {
3040 osi_Log1(smb_logp, "Protocol %s",
3041 osi_LogSaveString(smb_logp, namep+1));
3042 strcpy(protocol_array[tcounter], namep+1);
3044 /* namep points at the first protocol, or really, a 0x02
3045 * byte preceding the null-terminated ASCII name.
3047 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3048 coreProtoIndex = tcounter;
3050 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3051 v3ProtoIndex = tcounter;
3053 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3054 NTProtoIndex = tcounter;
3057 /* compute size of protocol entry */
3058 entryLength = (int)strlen(namep+1);
3059 entryLength += 2; /* 0x02 bytes and null termination */
3061 /* advance over this protocol entry */
3062 namex += entryLength;
3063 namep += entryLength;
3064 tcounter++; /* which proto entry we're looking at */
3067 if (NTProtoIndex != -1) {
3068 protoIndex = NTProtoIndex;
3069 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3071 else if (v3ProtoIndex != -1) {
3072 protoIndex = v3ProtoIndex;
3073 vcp->flags |= SMB_VCFLAG_USEV3;
3075 else if (coreProtoIndex != -1) {
3076 protoIndex = coreProtoIndex;
3077 vcp->flags |= SMB_VCFLAG_USECORE;
3079 else protoIndex = -1;
3081 if (protoIndex == -1)
3082 return CM_ERROR_INVAL;
3083 else if (NTProtoIndex != -1) {
3084 smb_SetSMBParm(outp, 0, protoIndex);
3085 if (smb_authType != SMB_AUTH_NONE) {
3086 smb_SetSMBParmByte(outp, 1,
3087 NEGOTIATE_SECURITY_USER_LEVEL |
3088 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3090 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3092 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3093 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3094 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3095 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3096 /* The session key is not a well documented field however most clients
3097 * will echo back the session key to the server. Currently we are using
3098 * the same value for all sessions. We should generate a random value
3099 * and store it into the vcp
3101 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3102 smb_SetSMBParm(outp, 8, 1);
3104 * Tried changing the capabilities to support for W2K - defect 117695
3105 * Maybe something else needs to be changed here?
3109 smb_SetSMBParmLong(outp, 9, 0x43fd);
3111 smb_SetSMBParmLong(outp, 9, 0x251);
3114 * 32-bit error codes *
3119 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3121 NTNEGOTIATE_CAPABILITY_DFS |
3123 NTNEGOTIATE_CAPABILITY_NTFIND |
3124 NTNEGOTIATE_CAPABILITY_RAWMODE |
3125 NTNEGOTIATE_CAPABILITY_NTSMB;
3127 if ( smb_authType == SMB_AUTH_EXTENDED )
3128 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3130 smb_SetSMBParmLong(outp, 9, caps);
3132 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3133 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3134 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3136 GetTimeZoneInformation(&tzi);
3137 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3139 if (smb_authType == SMB_AUTH_NTLM) {
3140 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3141 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3142 /* paste in encryption key */
3143 datap = smb_GetSMBData(outp, NULL);
3144 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3145 /* and the faux domain name */
3146 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3147 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3151 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3153 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3155 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3157 datap = smb_GetSMBData(outp, NULL);
3158 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3161 datap += sizeof(smb_ServerGUID);
3162 memcpy(datap, secBlob, secBlobLength);
3166 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3167 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3170 else if (v3ProtoIndex != -1) {
3171 smb_SetSMBParm(outp, 0, protoIndex);
3173 /* NOTE: Extended authentication cannot be negotiated with v3
3174 * therefore we fail over to NTLM
3176 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3177 smb_SetSMBParm(outp, 1,
3178 NEGOTIATE_SECURITY_USER_LEVEL |
3179 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3181 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3183 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3184 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3185 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3186 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3187 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3188 smb_SetSMBParm(outp, 7, 1);
3190 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3191 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3192 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3194 GetTimeZoneInformation(&tzi);
3195 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3197 /* NOTE: Extended authentication cannot be negotiated with v3
3198 * therefore we fail over to NTLM
3200 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3201 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3202 smb_SetSMBParm(outp, 12, 0); /* resvd */
3203 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3204 datap = smb_GetSMBData(outp, NULL);
3205 /* paste in a new encryption key */
3206 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3207 /* and the faux domain name */
3208 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3210 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3211 smb_SetSMBParm(outp, 12, 0); /* resvd */
3212 smb_SetSMBDataLength(outp, 0);
3215 else if (coreProtoIndex != -1) { /* not really supported anymore */
3216 smb_SetSMBParm(outp, 0, protoIndex);
3217 smb_SetSMBDataLength(outp, 0);
3222 void smb_Daemon(void *parmp)
3224 afs_uint32 count = 0;
3226 while(smbShutdownFlag == 0) {
3230 if (smbShutdownFlag == 1)
3233 if ((count % 72) == 0) { /* every five minutes */
3235 time_t old_localZero = smb_localZero;
3237 /* Initialize smb_localZero */
3238 myTime.tm_isdst = -1; /* compute whether on DST or not */
3239 myTime.tm_year = 70;
3245 smb_localZero = mktime(&myTime);
3247 #ifndef USE_NUMERIC_TIME_CONV
3248 smb_CalculateNowTZ();
3249 #endif /* USE_NUMERIC_TIME_CONV */
3250 #ifdef AFS_FREELANCE
3251 if ( smb_localZero != old_localZero )
3252 cm_noteLocalMountPointChange();
3255 /* XXX GC dir search entries */
3259 void smb_WaitingLocksDaemon()
3261 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3262 smb_waitingLock_t *wl, *wlNext;
3265 smb_packet_t *inp, *outp;
3269 while (smbShutdownFlag == 0) {
3270 lock_ObtainWrite(&smb_globalLock);
3271 nwlRequest = smb_allWaitingLocks;
3272 if (nwlRequest == NULL) {
3273 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3278 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3285 lock_ObtainWrite(&smb_globalLock);
3287 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3289 wlRequest = nwlRequest;
3290 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3291 lock_ReleaseWrite(&smb_globalLock);
3295 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3296 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3299 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3301 /* wl->state is either _DONE or _WAITING. _ERROR
3302 would no longer be on the queue. */
3303 code = cm_RetryLock( wl->lockp,
3304 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3307 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3308 } else if (code != CM_ERROR_WOULDBLOCK) {
3309 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3314 if (code == CM_ERROR_WOULDBLOCK) {
3317 if (wlRequest->timeRemaining != 0xffffffff
3318 && (wlRequest->timeRemaining -= 1000) < 0)
3330 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3333 scp = wlRequest->scp;
3337 lock_ObtainMutex(&scp->mx);
3339 for (wl = wlRequest->locks; wl; wl = wlNext) {
3340 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3342 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3343 wl->LLength, wl->key, NULL, &req);
3345 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3350 lock_ReleaseMutex(&scp->mx);
3354 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3357 for (wl = wlRequest->locks; wl; wl = wlNext) {
3358 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3359 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3364 vcp = wlRequest->vcp;
3365 inp = wlRequest->inp;
3366 outp = wlRequest->outp;
3368 ncbp->ncb_length = inp->ncb_length;
3369 inp->spacep = cm_GetSpace();
3371 /* Remove waitingLock from list */
3372 lock_ObtainWrite(&smb_globalLock);
3373 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3375 lock_ReleaseWrite(&smb_globalLock);
3377 /* Resume packet processing */
3379 smb_SetSMBDataLength(outp, 0);
3380 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3381 outp->resumeCode = code;
3383 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3386 cm_FreeSpace(inp->spacep);
3387 smb_FreePacket(inp);
3388 smb_FreePacket(outp);
3390 cm_ReleaseSCache(wlRequest->scp);
3393 } while (nwlRequest && smbShutdownFlag == 0);
3398 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3400 osi_Log0(smb_logp, "SMB receive get disk attributes");
3402 smb_SetSMBParm(outp, 0, 32000);
3403 smb_SetSMBParm(outp, 1, 64);
3404 smb_SetSMBParm(outp, 2, 1024);
3405 smb_SetSMBParm(outp, 3, 30000);
3406 smb_SetSMBParm(outp, 4, 0);
3407 smb_SetSMBDataLength(outp, 0);
3411 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3415 unsigned short newTid;
3416 char shareName[256];
3424 osi_Log0(smb_logp, "SMB receive tree connect");
3426 /* parse input parameters */
3427 tp = smb_GetSMBData(inp, NULL);
3428 pathp = smb_ParseASCIIBlock(tp, &tp);
3429 if (smb_StoreAnsiFilenames)
3430 OemToChar(pathp,pathp);
3431 passwordp = smb_ParseASCIIBlock(tp, &tp);
3432 tp = strrchr(pathp, '\\');
3434 return CM_ERROR_BADSMB;
3435 strcpy(shareName, tp+1);
3437 userp = smb_GetUser(vcp, inp);
3439 lock_ObtainMutex(&vcp->mx);
3440 newTid = vcp->tidCounter++;
3441 lock_ReleaseMutex(&vcp->mx);
3443 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3444 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3445 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3447 smb_ReleaseUID(uidp);
3449 smb_ReleaseTID(tidp);
3450 return CM_ERROR_BADSHARENAME;
3452 lock_ObtainMutex(&tidp->mx);
3453 tidp->userp = userp;
3454 tidp->pathname = sharePath;
3455 lock_ReleaseMutex(&tidp->mx);
3456 smb_ReleaseTID(tidp);
3458 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3459 smb_SetSMBParm(rsp, 1, newTid);
3460 smb_SetSMBDataLength(rsp, 0);
3462 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3466 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3470 if (*inp++ != 0x1) return NULL;
3471 tlen = inp[0] + (inp[1]<<8);
3472 inp += 2; /* skip length field */
3475 *chainpp = inp + tlen;
3478 if (lengthp) *lengthp = tlen;
3483 /* set maskp to the mask part of the incoming path.
3484 * Mask is 11 bytes long (8.3 with the dot elided).
3485 * Returns true if succeeds with a valid name, otherwise it does
3486 * its best, but returns false.
3488 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3496 /* starts off valid */
3499 /* mask starts out all blanks */
3500 memset(maskp, ' ', 11);
3502 /* find last backslash, or use whole thing if there is none */
3503 tp = strrchr(pathp, '\\');
3504 if (!tp) tp = pathp;
3505 else tp++; /* skip slash */
3509 /* names starting with a dot are illegal */
3510 if (*tp == '.') valid8Dot3 = 0;
3514 if (tc == 0) return valid8Dot3;
3515 if (tc == '.' || tc == '"') break;
3516 if (i < 8) *up++ = tc;
3517 else valid8Dot3 = 0;
3520 /* if we get here, tp point after the dot */
3521 up = maskp+8; /* ext goes here */
3528 if (tc == '.' || tc == '"')
3531 /* copy extension if not too long */
3541 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3551 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3553 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3557 /* otherwise, we have a valid 8.3 name; see if we have a match,
3558 * treating '?' as a wildcard in maskp (but not in the file name).
3560 tp1 = umask; /* real name, in mask format */
3561 tp2 = maskp; /* mask, in mask format */
3562 for(i=0; i<11; i++) {
3563 tc1 = *tp1++; /* char from real name */
3564 tc2 = *tp2++; /* char from mask */
3565 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3566 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3569 if (tc2 == '?' && tc1 != ' ')
3576 /* we got a match */
3580 char *smb_FindMask(char *pathp)
3584 tp = strrchr(pathp, '\\'); /* find last slash */
3587 return tp+1; /* skip the slash */
3589 return pathp; /* no slash, return the entire path */
3592 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3594 unsigned char *pathp;
3596 unsigned char mask[11];
3597 unsigned char *statBlockp;
3598 unsigned char initStatBlock[21];
3601 osi_Log0(smb_logp, "SMB receive search volume");
3603 /* pull pathname and stat block out of request */
3604 tp = smb_GetSMBData(inp, NULL);
3605 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3606 osi_assert(pathp != NULL);
3607 if (smb_StoreAnsiFilenames)
3608 OemToChar(pathp,pathp);
3609 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3610 osi_assert(statBlockp != NULL);
3612 statBlockp = initStatBlock;
3616 /* for returning to caller */
3617 smb_Get8Dot3MaskFromPath(mask, pathp);
3619 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3620 tp = smb_GetSMBData(outp, NULL);
3622 *tp++ = 43; /* bytes in a dir entry */
3623 *tp++ = 0; /* high byte in counter */
3625 /* now marshall the dir entry, starting with the search status */
3626 *tp++ = statBlockp[0]; /* Reserved */
3627 memcpy(tp, mask, 11); tp += 11; /* FileName */
3629 /* now pass back server use info, with 1st byte non-zero */
3631 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3633 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3635 *tp++ = 0x8; /* attribute: volume */
3645 /* 4 byte file size */
3651 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3652 memset(tp, ' ', 13);
3655 /* set the length of the data part of the packet to 43 + 3, for the dir
3656 * entry plus the 5 and the length fields.
3658 smb_SetSMBDataLength(outp, 46);
3662 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3663 cm_user_t *userp, cm_req_t *reqp)
3671 smb_dirListPatch_t *patchp;
3672 smb_dirListPatch_t *npatchp;
3674 for (patchp = *dirPatchespp; patchp; patchp =
3675 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3677 dptr = patchp->dptr;
3679 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3681 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3682 *dptr++ = SMB_ATTR_HIDDEN;
3685 lock_ObtainMutex(&scp->mx);
3686 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3687 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3689 lock_ReleaseMutex(&scp->mx);
3690 cm_ReleaseSCache(scp);
3691 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3692 *dptr++ = SMB_ATTR_HIDDEN;
3696 attr = smb_Attributes(scp);
3697 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3698 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3699 attr |= SMB_ATTR_HIDDEN;
3703 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3706 shortTemp = (unsigned short) (dosTime & 0xffff);
3707 *((u_short *)dptr) = shortTemp;
3710 /* and copy out date */
3711 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3712 *((u_short *)dptr) = shortTemp;
3715 /* copy out file length */
3716 *((u_long *)dptr) = scp->length.LowPart;
3718 lock_ReleaseMutex(&scp->mx);
3719 cm_ReleaseSCache(scp);
3722 /* now free the patches */
3723 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3724 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3728 /* and mark the list as empty */
3729 *dirPatchespp = NULL;
3734 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3743 smb_dirListPatch_t *dirListPatchesp;
3744 smb_dirListPatch_t *curPatchp;