2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
32 #include "lanahelper.h"
34 /* These characters are illegal in Windows filenames */
35 static char *illegalChars = "\\/:*?\"<>|";
37 static int smbShutdownFlag = 0;
38 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
40 int smb_LogoffTokenTransfer;
41 time_t smb_LogoffTransferTimeout;
43 int smb_StoreAnsiFilenames = 0;
45 DWORD last_msg_time = 0;
49 unsigned int sessionGen = 0;
51 extern void afsi_log(char *pattern, ...);
52 extern HANDLE afsi_file;
53 extern int powerStateSuspended;
55 osi_hyper_t hzero = {0, 0};
56 osi_hyper_t hones = {0xFFFFFFFF, -1};
59 osi_rwlock_t smb_globalLock;
60 osi_rwlock_t smb_rctLock;
61 osi_mutex_t smb_ListenerLock;
64 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
66 BOOL isGateway = FALSE;
69 long smb_maxObsConcurrentCalls=0;
70 long smb_concurrentCalls=0;
72 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
74 smb_packet_t *smb_packetFreeListp;
75 smb_ncb_t *smb_ncbFreeListp;
77 int smb_NumServerThreads;
79 int numNCBs, numSessions, numVCs;
81 int smb_maxVCPerServer;
82 int smb_maxMpxRequests;
84 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
86 ULONG smb_lsaSecPackage;
87 LSA_STRING smb_lsaLogonOrigin;
89 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
90 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
91 EVENT_HANDLE **NCBreturns;
92 EVENT_HANDLE **NCBShutdown;
93 EVENT_HANDLE *smb_ServerShutdown;
94 DWORD NCBsessions[NCB_MAX];
96 struct smb_packet *bufs[NCB_MAX];
98 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
99 EVENT_HANDLE SessionEvents[SESSION_MAX];
100 unsigned short LSNs[SESSION_MAX];
101 int lanas[SESSION_MAX];
102 BOOL dead_sessions[SESSION_MAX];
106 osi_mutex_t smb_RawBufLock;
109 #define SMB_MASKFLAG_TILDE 1
110 #define SMB_MASKFLAG_CASEFOLD 2
112 #define RAWTIMEOUT INFINITE
115 typedef struct raw_write_cont {
124 /* dir search stuff */
125 long smb_dirSearchCounter = 1;
126 smb_dirSearch_t *smb_firstDirSearchp;
127 smb_dirSearch_t *smb_lastDirSearchp;
129 /* hide dot files? */
130 int smb_hideDotFiles;
132 /* global state about V3 protocols */
133 int smb_useV3; /* try to negotiate V3 */
135 static showErrors = 0;
136 /* MessageBox or something like it */
137 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
140 * Time in Unix format of midnight, 1/1/1970 local time.
141 * When added to dosUTime, gives Unix (AFS) time.
143 time_t smb_localZero = 0;
145 #define USE_NUMERIC_TIME_CONV 1
147 #ifndef USE_NUMERIC_TIME_CONV
148 /* Time difference for converting to kludge-GMT */
149 afs_uint32 smb_NowTZ;
150 #endif /* USE_NUMERIC_TIME_CONV */
152 char *smb_localNamep = NULL;
154 smb_vc_t *smb_allVCsp;
155 smb_vc_t *smb_deadVCsp;
157 smb_username_t *usernamesp = NULL;
159 smb_waitingLockRequest_t *smb_allWaitingLocks;
161 DWORD smb_TlsRequestSlot = -1;
164 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
165 NCB *ncbp, raw_write_cont_t *rwcp);
166 int smb_NetbiosInit(void);
169 void smb_LogPacket(smb_packet_t *packet);
170 #endif /* LOG_PACKET */
172 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
173 int smb_ServerDomainNameLength = 0;
174 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
175 int smb_ServerOSLength = sizeof(smb_ServerOS);
176 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
177 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
179 /* Faux server GUID. This is never checked. */
180 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
182 void smb_ResetServerPriority()
184 void * p = TlsGetValue(smb_TlsRequestSlot);
187 TlsSetValue(smb_TlsRequestSlot, NULL);
188 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
192 void smb_SetRequestStartTime()
194 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
196 tp = malloc(sizeof(time_t));
200 if (!TlsSetValue(smb_TlsRequestSlot, tp))
205 void smb_UpdateServerPriority()
207 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
210 time_t now = osi_Time();
212 /* Give one priority boost for each 15 seconds */
213 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
218 const char * ncb_error_string(int code)
222 case 0x01: s = "llegal buffer length"; break;
223 case 0x03: s = "illegal command"; break;
224 case 0x05: s = "command timed out"; break;
225 case 0x06: s = "message incomplete, issue another command"; break;
226 case 0x07: s = "illegal buffer address"; break;
227 case 0x08: s = "session number out of range"; break;
228 case 0x09: s = "no resource available"; break;
229 case 0x0a: s = "session closed"; break;
230 case 0x0b: s = "command cancelled"; break;
231 case 0x0d: s = "duplicate name"; break;
232 case 0x0e: s = "name table full"; break;
233 case 0x0f: s = "no deletions, name has active sessions"; break;
234 case 0x11: s = "local session table full"; break;
235 case 0x12: s = "remote session table full"; break;
236 case 0x13: s = "illegal name number"; break;
237 case 0x14: s = "no callname"; break;
238 case 0x15: s = "cannot put * in NCB_NAME"; break;
239 case 0x16: s = "name in use on remote adapter"; break;
240 case 0x17: s = "name deleted"; break;
241 case 0x18: s = "session ended abnormally"; break;
242 case 0x19: s = "name conflict detected"; break;
243 case 0x21: s = "interface busy, IRET before retrying"; break;
244 case 0x22: s = "too many commands outstanding, retry later";break;
245 case 0x23: s = "ncb_lana_num field invalid"; break;
246 case 0x24: s = "command completed while cancel occurring "; break;
247 case 0x26: s = "command not valid to cancel"; break;
248 case 0x30: s = "name defined by anther local process"; break;
249 case 0x34: s = "environment undefined. RESET required"; break;
250 case 0x35: s = "required OS resources exhausted"; break;
251 case 0x36: s = "max number of applications exceeded"; break;
252 case 0x37: s = "no saps available for netbios"; break;
253 case 0x38: s = "requested resources are not available"; break;
254 case 0x39: s = "invalid ncb address or length > segment"; break;
255 case 0x3B: s = "invalid NCB DDID"; break;
256 case 0x3C: s = "lock of user area failed"; break;
257 case 0x3f: s = "NETBIOS not loaded"; break;
258 case 0x40: s = "system error"; break;
259 default: s = "unknown error";
265 char * myCrt_Dispatch(int i)
270 return "(00)ReceiveCoreMakeDir";
272 return "(01)ReceiveCoreRemoveDir";
274 return "(02)ReceiveCoreOpen";
276 return "(03)ReceiveCoreCreate";
278 return "(04)ReceiveCoreClose";
280 return "(05)ReceiveCoreFlush";
282 return "(06)ReceiveCoreUnlink";
284 return "(07)ReceiveCoreRename";
286 return "(08)ReceiveCoreGetFileAttributes";
288 return "(09)ReceiveCoreSetFileAttributes";
290 return "(0a)ReceiveCoreRead";
292 return "(0b)ReceiveCoreWrite";
294 return "(0c)ReceiveCoreLockRecord";
296 return "(0d)ReceiveCoreUnlockRecord";
298 return "(0e)SendCoreBadOp";
300 return "(0f)ReceiveCoreCreate";
302 return "(10)ReceiveCoreCheckPath";
304 return "(11)SendCoreBadOp";
306 return "(12)ReceiveCoreSeek";
308 return "(1a)ReceiveCoreReadRaw";
310 return "(1d)ReceiveCoreWriteRawDummy";
312 return "(22)ReceiveV3SetAttributes";
314 return "(23)ReceiveV3GetAttributes";
316 return "(24)ReceiveV3LockingX";
318 return "(25)ReceiveV3Trans";
320 return "(26)ReceiveV3Trans[aux]";
322 return "(29)SendCoreBadOp";
324 return "(2b)ReceiveCoreEcho";
326 return "(2d)ReceiveV3OpenX";
328 return "(2e)ReceiveV3ReadX";
330 return "(2f)ReceiveV3WriteX";
332 return "(32)ReceiveV3Tran2A";
334 return "(33)ReceiveV3Tran2A[aux]";
336 return "(34)ReceiveV3FindClose";
338 return "(35)ReceiveV3FindNotifyClose";
340 return "(70)ReceiveCoreTreeConnect";
342 return "(71)ReceiveCoreTreeDisconnect";
344 return "(72)ReceiveNegotiate";
346 return "(73)ReceiveV3SessionSetupX";
348 return "(74)ReceiveV3UserLogoffX";
350 return "(75)ReceiveV3TreeConnectX";
352 return "(80)ReceiveCoreGetDiskAttributes";
354 return "(81)ReceiveCoreSearchDir";
358 return "(83)FindUnique";
360 return "(84)FindClose";
362 return "(A0)ReceiveNTTransact";
364 return "(A2)ReceiveNTCreateX";
366 return "(A4)ReceiveNTCancel";
368 return "(A5)ReceiveNTRename";
370 return "(C0)OpenPrintFile";
372 return "(C1)WritePrintFile";
374 return "(C2)ClosePrintFile";
376 return "(C3)GetPrintQueue";
378 return "(D8)ReadBulk";
380 return "(D9)WriteBulk";
382 return "(DA)WriteBulkData";
384 return "unknown SMB op";
388 char * myCrt_2Dispatch(int i)
393 return "unknown SMB op-2";
395 return "S(00)CreateFile_ReceiveTran2Open";
397 return "S(01)FindFirst_ReceiveTran2SearchDir";
399 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
401 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
403 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
405 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
407 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
409 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
411 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
413 return "S(09)_ReceiveTran2FSCTL";
415 return "S(0a)_ReceiveTran2IOCTL";
417 return "S(0b)_ReceiveTran2FindNotifyFirst";
419 return "S(0c)_ReceiveTran2FindNotifyNext";
421 return "S(0d)_ReceiveTran2CreateDirectory";
423 return "S(0e)_ReceiveTran2SessionSetup";
425 return "S(0f)_QueryFileSystemInformationFid";
427 return "S(10)_ReceiveTran2GetDfsReferral";
429 return "S(11)_ReceiveTran2ReportDfsInconsistency";
433 char * myCrt_RapDispatch(int i)
438 return "unknown RAP OP";
440 return "RAP(0)NetShareEnum";
442 return "RAP(1)NetShareGetInfo";
444 return "RAP(13)NetServerGetInfo";
446 return "RAP(63)NetWkStaGetInfo";
450 /* scache must be locked */
451 unsigned int smb_Attributes(cm_scache_t *scp)
455 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
456 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
457 scp->fileType == CM_SCACHETYPE_INVALID)
459 attrs = SMB_ATTR_DIRECTORY;
460 #ifdef SPECIAL_FOLDERS
461 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
462 #endif /* SPECIAL_FOLDERS */
463 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
464 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
469 * We used to mark a file RO if it was in an RO volume, but that
470 * turns out to be impolitic in NT. See defect 10007.
473 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
474 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
476 if ((scp->unixModeBits & 0222) == 0)
477 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
483 /* Check if the named file/dir is a dotfile/dotdir */
484 /* String pointed to by lastComp can have leading slashes, but otherwise should have
485 no other patch components */
486 unsigned int smb_IsDotFile(char *lastComp) {
489 /* skip over slashes */
490 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
495 /* nulls, curdir and parent dir doesn't count */
501 if(*(s+1) == '.' && !*(s + 2))
508 static int ExtractBits(WORD bits, short start, short len)
515 num = bits << (16 - end);
516 num = num >> ((16 - end) + start);
521 void ShowUnixTime(char *FuncName, time_t unixTime)
526 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
528 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
529 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
531 int day, month, year, sec, min, hour;
534 day = ExtractBits(wDate, 0, 5);
535 month = ExtractBits(wDate, 5, 4);
536 year = ExtractBits(wDate, 9, 7) + 1980;
538 sec = ExtractBits(wTime, 0, 5);
539 min = ExtractBits(wTime, 5, 6);
540 hour = ExtractBits(wTime, 11, 5);
542 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
543 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
547 /* Determine if we are observing daylight savings time */
548 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
550 TIME_ZONE_INFORMATION timeZoneInformation;
551 SYSTEMTIME utc, local, localDST;
553 /* Get the time zone info. NT uses this to calc if we are in DST. */
554 GetTimeZoneInformation(&timeZoneInformation);
556 /* Return the daylight bias */
557 *pDstBias = timeZoneInformation.DaylightBias;
559 /* Return the bias */
560 *pBias = timeZoneInformation.Bias;
562 /* Now determine if DST is being observed */
564 /* Get the UTC (GMT) time */
567 /* Convert UTC time to local time using the time zone info. If we are
568 observing DST, the calculated local time will include this.
570 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
572 /* Set the daylight bias to 0. The daylight bias is the amount of change
573 * in time that we use for daylight savings time. By setting this to 0
574 * we cause there to be no change in time during daylight savings time.
576 timeZoneInformation.DaylightBias = 0;
578 /* Convert the utc time to local time again, but this time without any
579 adjustment for daylight savings time.
581 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
583 /* If the two times are different, then it means that the localDST that
584 we calculated includes the daylight bias, and therefore we are
585 observing daylight savings time.
587 *pDST = localDST.wHour != local.wHour;
591 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
593 BOOL dst; /* Will be TRUE if observing DST */
594 LONG dstBias; /* Offset from local time if observing DST */
595 LONG bias; /* Offset from GMT for local time */
598 * This function will adjust the last write time to compensate
599 * for two bugs in the smb client:
601 * 1) During Daylight Savings Time, the LastWriteTime is ahead
602 * in time by the DaylightBias (ignoring the sign - the
603 * DaylightBias is always stored as a negative number). If
604 * the DaylightBias is -60, then the LastWriteTime will be
605 * ahead by 60 minutes.
607 * 2) If the local time zone is a positive offset from GMT, then
608 * the LastWriteTime will be the correct local time plus the
609 * Bias (ignoring the sign - a positive offset from GMT is
610 * always stored as a negative Bias). If the Bias is -120,
611 * then the LastWriteTime will be ahead by 120 minutes.
613 * These bugs can occur at the same time.
616 GetTimeZoneInfo(&dst, &dstBias, &bias);
618 /* First adjust for DST */
620 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
622 /* Now adjust for a positive offset from GMT (a negative bias). */
624 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
627 #ifndef USE_NUMERIC_TIME_CONV
629 * Calculate the difference (in seconds) between local time and GMT.
630 * This enables us to convert file times to kludge-GMT.
636 struct tm gmt_tm, local_tm;
637 int days, hours, minutes, seconds;
640 gmt_tm = *(gmtime(&t));
641 local_tm = *(localtime(&t));
643 days = local_tm.tm_yday - gmt_tm.tm_yday;
644 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
645 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
646 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
650 #endif /* USE_NUMERIC_TIME_CONV */
652 #ifdef USE_NUMERIC_TIME_CONV
653 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
655 // Note that LONGLONG is a 64-bit value
658 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
659 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
660 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
663 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
668 time_t ersatz_unixTime;
671 * Must use kludge-GMT instead of real GMT.
672 * kludge-GMT is computed by adding time zone difference to localtime.
675 * ltp = gmtime(&unixTime);
677 ersatz_unixTime = unixTime - smb_NowTZ;
678 ltp = localtime(&ersatz_unixTime);
680 /* if we fail, make up something */
683 localJunk.tm_year = 89 - 20;
684 localJunk.tm_mon = 4;
685 localJunk.tm_mday = 12;
686 localJunk.tm_hour = 0;
687 localJunk.tm_min = 0;
688 localJunk.tm_sec = 0;
691 stm.wYear = ltp->tm_year + 1900;
692 stm.wMonth = ltp->tm_mon + 1;
693 stm.wDayOfWeek = ltp->tm_wday;
694 stm.wDay = ltp->tm_mday;
695 stm.wHour = ltp->tm_hour;
696 stm.wMinute = ltp->tm_min;
697 stm.wSecond = ltp->tm_sec;
698 stm.wMilliseconds = 0;
700 SystemTimeToFileTime(&stm, largeTimep);
702 #endif /* USE_NUMERIC_TIME_CONV */
704 #ifdef USE_NUMERIC_TIME_CONV
705 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
707 // Note that LONGLONG is a 64-bit value
710 ll = largeTimep->dwHighDateTime;
712 ll += largeTimep->dwLowDateTime;
714 ll -= 116444736000000000;
717 *unixTimep = (DWORD)ll;
719 #else /* USE_NUMERIC_TIME_CONV */
720 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
726 FileTimeToSystemTime(largeTimep, &stm);
728 lt.tm_year = stm.wYear - 1900;
729 lt.tm_mon = stm.wMonth - 1;
730 lt.tm_wday = stm.wDayOfWeek;
731 lt.tm_mday = stm.wDay;
732 lt.tm_hour = stm.wHour;
733 lt.tm_min = stm.wMinute;
734 lt.tm_sec = stm.wSecond;
737 save_timezone = _timezone;
738 _timezone += smb_NowTZ;
739 *unixTimep = mktime(<);
740 _timezone = save_timezone;
742 #endif /* USE_NUMERIC_TIME_CONV */
744 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
754 /* if we fail, make up something */
757 localJunk.tm_year = 89 - 20;
758 localJunk.tm_mon = 4;
759 localJunk.tm_mday = 12;
760 localJunk.tm_hour = 0;
761 localJunk.tm_min = 0;
762 localJunk.tm_sec = 0;
765 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
766 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
767 *searchTimep = (dosDate<<16) | dosTime;
770 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
772 unsigned short dosDate;
773 unsigned short dosTime;
776 dosDate = (unsigned short) (searchTime & 0xffff);
777 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
779 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
780 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
781 localTm.tm_mday = (dosDate) & 0x1f;
782 localTm.tm_hour = (dosTime>>11) & 0x1f;
783 localTm.tm_min = (dosTime >> 5) & 0x3f;
784 localTm.tm_sec = (dosTime & 0x1f) * 2;
785 localTm.tm_isdst = -1; /* compute whether DST in effect */
787 *unixTimep = mktime(&localTm);
790 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
792 time_t diff_t = unixTime - smb_localZero;
793 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
794 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
796 *dosUTimep = (afs_uint32)diff_t;
799 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
801 *unixTimep = dosTime + smb_localZero;
804 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
808 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
809 lock_ObtainWrite(&smb_rctLock);
810 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
811 if (vcp->magic != SMB_VC_MAGIC)
812 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
815 if (lsn == vcp->lsn && lana == vcp->lana &&
816 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
817 smb_HoldVCNoLock(vcp);
821 if (!vcp && (flags & SMB_FLAG_CREATE)) {
822 vcp = malloc(sizeof(*vcp));
823 memset(vcp, 0, sizeof(*vcp));
824 vcp->vcID = ++numVCs;
825 vcp->magic = SMB_VC_MAGIC;
826 vcp->refCount = 2; /* smb_allVCsp and caller */
829 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
830 vcp->nextp = smb_allVCsp;
832 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
837 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
838 /* We must obtain a challenge for extended auth
839 * in case the client negotiates smb v3
841 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
842 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
843 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
844 ULONG lsaRespSize = 0;
846 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
848 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
855 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
856 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
857 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
858 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
859 nts, ntsEx, lsaRespSize);
861 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
863 if (ntsEx == STATUS_SUCCESS) {
864 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
865 LsaFreeReturnBuffer(lsaResp);
868 * This will cause the subsequent authentication to fail but
869 * that is better than us dereferencing a NULL pointer and
872 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
876 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
878 if (numVCs >= CM_SESSION_RESERVED) {
880 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
883 lock_ReleaseWrite(&smb_rctLock);
884 lock_ReleaseWrite(&smb_globalLock);
888 int smb_IsStarMask(char *maskp)
893 for(i=0; i<11; i++) {
895 if (tc == '?' || tc == '*' || tc == '>')
901 void smb_ReleaseVCInternal(smb_vc_t *vcp)
908 if (vcp->refCount == 0) {
909 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
910 /* remove VCP from smb_deadVCsp */
911 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
917 lock_FinalizeMutex(&vcp->mx);
918 memset(vcp,0,sizeof(smb_vc_t));
921 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
925 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
926 avcp?"not ":"",vcp, vcp->refCount);
928 GenerateMiniDump(NULL);
930 /* This is a wrong. However, I suspect that there is an undercount
931 * and I don't want to release 1.4.1 in a state that will allow
932 * smb_vc_t objects to be deallocated while still in the
933 * smb_allVCsp list. The list is supposed to keep a reference
934 * to the smb_vc_t. Put it back.
941 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
943 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
944 smb_ReleaseVCInternal(vcp);
947 void smb_ReleaseVC(smb_vc_t *vcp)
949 lock_ObtainWrite(&smb_rctLock);
950 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
951 smb_ReleaseVCInternal(vcp);
952 lock_ReleaseWrite(&smb_rctLock);
955 void smb_HoldVCNoLock(smb_vc_t *vcp)
958 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
961 void smb_HoldVC(smb_vc_t *vcp)
963 lock_ObtainWrite(&smb_rctLock);
965 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
966 lock_ReleaseWrite(&smb_rctLock);
969 void smb_CleanupDeadVC(smb_vc_t *vcp)
977 smb_user_t *uidpIter;
978 smb_user_t *uidpNext;
982 lock_ObtainMutex(&vcp->mx);
983 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
984 lock_ReleaseMutex(&vcp->mx);
985 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
988 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
989 lock_ReleaseMutex(&vcp->mx);
990 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
992 lock_ObtainWrite(&smb_rctLock);
993 /* remove VCP from smb_allVCsp */
994 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
995 if ((*vcpp)->magic != SMB_VC_MAGIC)
996 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1000 vcp->nextp = smb_deadVCsp;
1002 /* Hold onto the reference until we are done with this function */
1007 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1008 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1010 if (fidpIter->delete)
1013 fid = fidpIter->fid;
1014 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1016 smb_HoldFIDNoLock(fidpIter);
1017 lock_ReleaseWrite(&smb_rctLock);
1019 smb_CloseFID(vcp, fidpIter, NULL, 0);
1020 smb_ReleaseFID(fidpIter);
1022 lock_ObtainWrite(&smb_rctLock);
1023 fidpNext = vcp->fidsp;
1026 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1027 tidpNext = tidpIter->nextp;
1028 if (tidpIter->delete)
1030 tidpIter->delete = 1;
1032 tid = tidpIter->tid;
1033 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1035 smb_HoldTIDNoLock(tidpIter);
1036 lock_ReleaseWrite(&smb_rctLock);
1038 smb_ReleaseTID(tidpIter);
1040 lock_ObtainWrite(&smb_rctLock);
1041 tidpNext = vcp->tidsp;
1044 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1045 uidpNext = uidpIter->nextp;
1046 if (uidpIter->delete)
1048 uidpIter->delete = 1;
1050 /* do not add an additional reference count for the smb_user_t
1051 * as the smb_vc_t already is holding a reference */
1052 lock_ReleaseWrite(&smb_rctLock);
1054 smb_ReleaseUID(uidpIter);
1056 lock_ObtainWrite(&smb_rctLock);
1057 uidpNext = vcp->usersp;
1060 /* The vcp is now on the deadVCsp list. We intentionally drop the
1061 * reference so that the refcount can reach 0 and we can delete it */
1062 smb_ReleaseVCNoLock(vcp);
1064 lock_ReleaseWrite(&smb_rctLock);
1065 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1068 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1072 lock_ObtainWrite(&smb_rctLock);
1074 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1075 if (tidp->refCount == 0 && tidp->delete) {
1077 lock_ReleaseWrite(&smb_rctLock);
1078 smb_ReleaseTID(tidp);
1079 lock_ObtainWrite(&smb_rctLock);
1083 if (tid == tidp->tid) {
1088 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1089 tidp = malloc(sizeof(*tidp));
1090 memset(tidp, 0, sizeof(*tidp));
1091 tidp->nextp = vcp->tidsp;
1094 smb_HoldVCNoLock(vcp);
1096 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1099 lock_ReleaseWrite(&smb_rctLock);
1103 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1108 void smb_ReleaseTID(smb_tid_t *tidp)
1115 lock_ObtainWrite(&smb_rctLock);
1116 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1117 if (tidp->refCount == 0 && (tidp->delete)) {
1118 ltpp = &tidp->vcp->tidsp;
1119 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1123 osi_assertx(tp != NULL, "null smb_tid_t");
1125 lock_FinalizeMutex(&tidp->mx);
1126 userp = tidp->userp; /* remember to drop ref later */
1128 smb_ReleaseVCNoLock(tidp->vcp);
1131 lock_ReleaseWrite(&smb_rctLock);
1133 cm_ReleaseUser(userp);
1136 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1138 smb_user_t *uidp = NULL;
1140 lock_ObtainWrite(&smb_rctLock);
1141 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1142 if (uid == uidp->userID) {
1144 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1146 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1150 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1151 uidp = malloc(sizeof(*uidp));
1152 memset(uidp, 0, sizeof(*uidp));
1153 uidp->nextp = vcp->usersp;
1154 uidp->refCount = 2; /* one for the vcp and one for the caller */
1156 smb_HoldVCNoLock(vcp);
1158 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1160 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1162 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1164 lock_ReleaseWrite(&smb_rctLock);
1168 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1170 smb_username_t *unp= NULL;
1172 lock_ObtainWrite(&smb_rctLock);
1173 for(unp = usernamesp; unp; unp = unp->nextp) {
1174 if (stricmp(unp->name, usern) == 0 &&
1175 stricmp(unp->machine, machine) == 0) {
1180 if (!unp && (flags & SMB_FLAG_CREATE)) {
1181 unp = malloc(sizeof(*unp));
1182 memset(unp, 0, sizeof(*unp));
1184 unp->nextp = usernamesp;
1185 unp->name = strdup(usern);
1186 unp->machine = strdup(machine);
1188 lock_InitializeMutex(&unp->mx, "username_t mutex");
1189 if (flags & SMB_FLAG_AFSLOGON)
1190 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1193 lock_ReleaseWrite(&smb_rctLock);
1197 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1199 smb_user_t *uidp= NULL;
1201 lock_ObtainWrite(&smb_rctLock);
1202 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1205 if (stricmp(uidp->unp->name, usern) == 0) {
1207 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1208 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1213 lock_ReleaseWrite(&smb_rctLock);
1217 void smb_ReleaseUsername(smb_username_t *unp)
1220 smb_username_t **lupp;
1221 cm_user_t *userp = NULL;
1222 time_t now = osi_Time();
1224 lock_ObtainWrite(&smb_rctLock);
1225 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1226 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1227 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1229 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1233 osi_assertx(up != NULL, "null smb_username_t");
1235 up->nextp = NULL; /* do not remove this */
1236 lock_FinalizeMutex(&unp->mx);
1242 lock_ReleaseWrite(&smb_rctLock);
1245 cm_ReleaseUser(userp);
1249 void smb_HoldUIDNoLock(smb_user_t *uidp)
1254 void smb_ReleaseUID(smb_user_t *uidp)
1258 smb_username_t *unp = NULL;
1260 lock_ObtainWrite(&smb_rctLock);
1261 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1262 if (uidp->refCount == 0) {
1263 lupp = &uidp->vcp->usersp;
1264 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1268 osi_assertx(up != NULL, "null smb_user_t");
1270 lock_FinalizeMutex(&uidp->mx);
1272 smb_ReleaseVCNoLock(uidp->vcp);
1276 lock_ReleaseWrite(&smb_rctLock);
1280 cm_ReleaseUserVCRef(unp->userp);
1281 smb_ReleaseUsername(unp);
1285 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1287 cm_user_t *up = NULL;
1292 lock_ObtainMutex(&uidp->mx);
1294 up = uidp->unp->userp;
1297 lock_ReleaseMutex(&uidp->mx);
1303 /* retrieve a held reference to a user structure corresponding to an incoming
1305 * corresponding release function is cm_ReleaseUser.
1307 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1310 cm_user_t *up = NULL;
1313 smbp = (smb_t *) inp;
1314 uidp = smb_FindUID(vcp, smbp->uid, 0);
1318 up = smb_GetUserFromUID(uidp);
1320 smb_ReleaseUID(uidp);
1325 * Return a pointer to a pathname extracted from a TID structure. The
1326 * TID structure is not held; assume it won't go away.
1328 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1333 tidp = smb_FindTID(vcp, tid, 0);
1337 if (tidp->flags & SMB_TIDFLAG_IPC) {
1338 code = CM_ERROR_TIDIPC;
1339 /* tidp->pathname would be NULL, but that's fine */
1341 *treepath = tidp->pathname;
1342 smb_ReleaseTID(tidp);
1347 /* check to see if we have a chained fid, that is, a fid that comes from an
1348 * OpenAndX message that ran earlier in this packet. In this case, the fid
1349 * field in a read, for example, request, isn't set, since the value is
1350 * supposed to be inherited from the openAndX call.
1352 int smb_ChainFID(int fid, smb_packet_t *inp)
1354 if (inp->fid == 0 || inp->inCount == 0)
1360 /* are we a priv'd user? What does this mean on NT? */
1361 int smb_SUser(cm_user_t *userp)
1366 /* find a file ID. If we pass in 0 we select an unused File ID.
1367 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1368 * smb_fid_t data structure if desired File ID cannot be found.
1370 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1375 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1378 lock_ObtainWrite(&smb_rctLock);
1379 /* figure out if we need to allocate a new file ID */
1382 fid = vcp->fidCounter;
1386 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1387 if (fidp->refCount == 0 && fidp->delete) {
1389 lock_ReleaseWrite(&smb_rctLock);
1390 smb_ReleaseFID(fidp);
1391 lock_ObtainWrite(&smb_rctLock);
1394 if (fid == fidp->fid) {
1397 if (fid == 0xFFFF) {
1399 "New FID number wraps on vcp 0x%x", vcp);
1409 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1410 char eventName[MAX_PATH];
1412 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1413 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1414 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1415 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1416 thrd_CloseHandle(event);
1418 if (fid == 0xFFFF) {
1419 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1425 fidp = malloc(sizeof(*fidp));
1426 memset(fidp, 0, sizeof(*fidp));
1427 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1430 smb_HoldVCNoLock(vcp);
1431 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1433 fidp->curr_chunk = fidp->prev_chunk = -2;
1434 fidp->raw_write_event = event;
1436 vcp->fidCounter = fid+1;
1437 if (vcp->fidCounter == 0xFFFF) {
1438 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1440 vcp->fidCounter = 1;
1445 lock_ReleaseWrite(&smb_rctLock);
1449 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1451 smb_fid_t *fidp = NULL;
1457 lock_ObtainWrite(&smb_rctLock);
1458 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1459 if (scp == fidp->scp) {
1464 lock_ReleaseWrite(&smb_rctLock);
1468 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1474 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1475 /* the sm_fid_t->mx and smb_rctLock must not be held */
1476 void smb_ReleaseFID(smb_fid_t *fidp)
1478 cm_scache_t *scp = NULL;
1479 cm_user_t *userp = NULL;
1480 smb_vc_t *vcp = NULL;
1481 smb_ioctl_t *ioctlp;
1483 lock_ObtainMutex(&fidp->mx);
1484 lock_ObtainWrite(&smb_rctLock);
1485 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1486 if (fidp->refCount == 0 && (fidp->delete)) {
1489 scp = fidp->scp; /* release after lock is released */
1491 lock_ObtainMutex(&scp->mx);
1492 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1493 lock_ReleaseMutex(&scp->mx);
1494 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1497 userp = fidp->userp;
1501 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1502 thrd_CloseHandle(fidp->raw_write_event);
1504 /* and see if there is ioctl stuff to free */
1505 ioctlp = fidp->ioctlp;
1508 cm_FreeSpace(ioctlp->prefix);
1509 if (ioctlp->inAllocp)
1510 free(ioctlp->inAllocp);
1511 if (ioctlp->outAllocp)
1512 free(ioctlp->outAllocp);
1515 lock_ReleaseMutex(&fidp->mx);
1516 lock_FinalizeMutex(&fidp->mx);
1520 smb_ReleaseVCNoLock(vcp);
1522 lock_ReleaseMutex(&fidp->mx);
1524 lock_ReleaseWrite(&smb_rctLock);
1526 /* now release the scache structure */
1528 cm_ReleaseSCache(scp);
1531 cm_ReleaseUser(userp);
1535 * Case-insensitive search for one string in another;
1536 * used to find variable names in submount pathnames.
1538 static char *smb_stristr(char *str1, char *str2)
1542 for (cursor = str1; *cursor; cursor++)
1543 if (stricmp(cursor, str2) == 0)
1550 * Substitute a variable value for its name in a submount pathname. Variable
1551 * name has been identified by smb_stristr() and is in substr. Variable name
1552 * length (plus one) is in substr_size. Variable value is in newstr.
1554 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1559 strcpy(temp, substr + substr_size - 1);
1560 strcpy(substr, newstr);
1564 char VNUserName[] = "%USERNAME%";
1565 char VNLCUserName[] = "%LCUSERNAME%";
1566 char VNComputerName[] = "%COMPUTERNAME%";
1567 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1570 typedef struct smb_findShare_rock {
1574 } smb_findShare_rock_t;
1576 #define SMB_FINDSHARE_EXACT_MATCH 1
1577 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1579 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1583 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1584 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1585 if(!stricmp(dep->name, vrock->shareName))
1586 matchType = SMB_FINDSHARE_EXACT_MATCH;
1588 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1589 if(vrock->match) free(vrock->match);
1590 vrock->match = strdup(dep->name);
1591 vrock->matchType = matchType;
1593 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1594 return CM_ERROR_STOPNOW;
1600 /* find a shareName in the table of submounts */
1601 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1605 char pathName[1024];
1612 DWORD allSubmount = 1;
1614 /* if allSubmounts == 0, only return the //mountRoot/all share
1615 * if in fact it has been been created in the subMounts table.
1616 * This is to allow sites that want to restrict access to the
1619 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1620 0, KEY_QUERY_VALUE, &parmKey);
1621 if (code == ERROR_SUCCESS) {
1622 len = sizeof(allSubmount);
1623 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1624 (BYTE *) &allSubmount, &len);
1625 if (code != ERROR_SUCCESS) {
1628 RegCloseKey (parmKey);
1631 if (allSubmount && _stricmp(shareName, "all") == 0) {
1636 /* In case, the all share is disabled we need to still be able
1637 * to handle ioctl requests
1639 if (_stricmp(shareName, "ioctl$") == 0) {
1640 *pathNamep = strdup("/.__ioctl__");
1644 if (_stricmp(shareName, "IPC$") == 0 ||
1645 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1646 _stricmp(shareName, "DESKTOP.INI") == 0
1652 /* Check for volume references
1654 * They look like <cell>{%,#}<volume>
1656 if (strchr(shareName, '%') != NULL ||
1657 strchr(shareName, '#') != NULL) {
1658 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1659 /* make room for '/@vol:' + mountchar + NULL terminator*/
1661 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1662 osi_LogSaveString(smb_logp, shareName));
1664 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1665 "/" CM_PREFIX_VOL "%s", shareName);
1666 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1667 len = strlen(pathstr) + 1;
1669 *pathNamep = malloc(len);
1671 strcpy(*pathNamep, pathstr);
1673 osi_Log1(smb_logp, " returning pathname [%s]",
1674 osi_LogSaveString(smb_logp, *pathNamep));
1682 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1683 0, KEY_QUERY_VALUE, &parmKey);
1684 if (code == ERROR_SUCCESS) {
1685 len = sizeof(pathName);
1686 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1687 (BYTE *) pathName, &len);
1688 if (code != ERROR_SUCCESS)
1690 RegCloseKey (parmKey);
1694 if (len != 0 && len != sizeof(pathName) - 1) {
1695 /* We can accept either unix or PC style AFS pathnames. Convert
1696 * Unix-style to PC style here for internal use.
1699 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1700 p += strlen(cm_mountRoot); /* skip mount path */
1703 if (*q == '/') *q = '\\'; /* change to \ */
1709 if (var = smb_stristr(p, VNUserName)) {
1710 if (uidp && uidp->unp)
1711 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1713 smb_subst(p, var, sizeof(VNUserName)," ");
1715 else if (var = smb_stristr(p, VNLCUserName))
1717 if (uidp && uidp->unp)
1718 strcpy(temp, uidp->unp->name);
1722 smb_subst(p, var, sizeof(VNLCUserName), temp);
1724 else if (var = smb_stristr(p, VNComputerName))
1726 sizeTemp = sizeof(temp);
1727 GetComputerName((LPTSTR)temp, &sizeTemp);
1728 smb_subst(p, var, sizeof(VNComputerName), temp);
1730 else if (var = smb_stristr(p, VNLCComputerName))
1732 sizeTemp = sizeof(temp);
1733 GetComputerName((LPTSTR)temp, &sizeTemp);
1735 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1740 *pathNamep = strdup(p);
1745 /* First lookup shareName in root.afs */
1747 smb_findShare_rock_t vrock;
1749 char * p = shareName;
1752 /* attempt to locate a partial match in root.afs. This is because
1753 when using the ANSI RAP calls, the share name is limited to 13 chars
1754 and hence is truncated. Of course we prefer exact matches. */
1756 thyper.HighPart = 0;
1759 vrock.shareName = shareName;
1761 vrock.matchType = 0;
1763 cm_HoldSCache(cm_data.rootSCachep);
1764 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1765 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1766 cm_ReleaseSCache(cm_data.rootSCachep);
1768 if (vrock.matchType) {
1769 sprintf(pathName,"/%s/",vrock.match);
1770 *pathNamep = strdup(strlwr(pathName));
1775 /* if we get here, there was no match for the share in root.afs */
1776 /* so try to create \\<netbiosName>\<cellname> */
1781 /* Get the full name for this cell */
1782 code = cm_SearchCellFile(p, temp, 0, 0);
1783 #ifdef AFS_AFSDB_ENV
1784 if (code && cm_dnsEnabled) {
1786 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1789 /* construct the path */
1791 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1792 *pathNamep = strdup(strlwr(pathName));
1801 /* Client-side offline caching policy types */
1802 #define CSC_POLICY_MANUAL 0
1803 #define CSC_POLICY_DOCUMENTS 1
1804 #define CSC_POLICY_PROGRAMS 2
1805 #define CSC_POLICY_DISABLE 3
1807 int smb_FindShareCSCPolicy(char *shareName)
1813 int retval = CSC_POLICY_MANUAL;
1815 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1816 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1819 REG_OPTION_NON_VOLATILE,
1825 len = sizeof(policy);
1826 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1828 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1830 else if (stricmp(policy, "documents") == 0)
1832 retval = CSC_POLICY_DOCUMENTS;
1834 else if (stricmp(policy, "programs") == 0)
1836 retval = CSC_POLICY_PROGRAMS;
1838 else if (stricmp(policy, "disable") == 0)
1840 retval = CSC_POLICY_DISABLE;
1843 RegCloseKey(hkCSCPolicy);
1847 /* find a dir search structure by cookie value, and return it held.
1848 * Must be called with smb_globalLock held.
1850 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1852 smb_dirSearch_t *dsp;
1854 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1855 if (dsp->cookie == cookie) {
1856 if (dsp != smb_firstDirSearchp) {
1857 /* move to head of LRU queue, too, if we're not already there */
1858 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1859 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1860 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1861 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1862 if (!smb_lastDirSearchp)
1863 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1865 lock_ObtainMutex(&dsp->mx);
1867 lock_ReleaseMutex(&dsp->mx);
1873 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1874 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1875 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1881 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1883 lock_ObtainWrite(&smb_globalLock);
1884 lock_ObtainMutex(&dsp->mx);
1885 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1886 dsp->cookie, dsp, dsp->scp);
1887 dsp->flags |= SMB_DIRSEARCH_DELETE;
1888 if (dsp->scp != NULL) {
1889 lock_ObtainMutex(&dsp->scp->mx);
1890 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1891 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1892 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1893 dsp->scp->bulkStatProgress = hzero;
1895 lock_ReleaseMutex(&dsp->scp->mx);
1897 lock_ReleaseMutex(&dsp->mx);
1898 lock_ReleaseWrite(&smb_globalLock);
1901 /* Must be called with the smb_globalLock held */
1902 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1904 cm_scache_t *scp = NULL;
1906 lock_ObtainMutex(&dsp->mx);
1907 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1908 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1909 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1910 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1911 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1912 lock_ReleaseMutex(&dsp->mx);
1913 lock_FinalizeMutex(&dsp->mx);
1915 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1916 dsp->cookie, dsp, scp);
1919 lock_ReleaseMutex(&dsp->mx);
1921 /* do this now to avoid spurious locking hierarchy creation */
1923 cm_ReleaseSCache(scp);
1926 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1928 lock_ObtainWrite(&smb_globalLock);
1929 smb_ReleaseDirSearchNoLock(dsp);
1930 lock_ReleaseWrite(&smb_globalLock);
1933 /* find a dir search structure by cookie value, and return it held */
1934 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1936 smb_dirSearch_t *dsp;
1938 lock_ObtainWrite(&smb_globalLock);
1939 dsp = smb_FindDirSearchNoLock(cookie);
1940 lock_ReleaseWrite(&smb_globalLock);
1944 /* GC some dir search entries, in the address space expected by the specific protocol.
1945 * Must be called with smb_globalLock held; release the lock temporarily.
1947 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1948 void smb_GCDirSearches(int isV3)
1950 smb_dirSearch_t *prevp;
1951 smb_dirSearch_t *tp;
1952 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1956 victimCount = 0; /* how many have we got so far */
1957 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1958 /* we'll move tp from queue, so
1961 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1962 /* if no one is using this guy, and we're either in the new protocol,
1963 * or we're in the old one and this is a small enough ID to be useful
1964 * to the old protocol, GC this guy.
1966 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1967 /* hold and delete */
1968 lock_ObtainMutex(&tp->mx);
1969 tp->flags |= SMB_DIRSEARCH_DELETE;
1970 lock_ReleaseMutex(&tp->mx);
1971 victimsp[victimCount++] = tp;
1975 /* don't do more than this */
1976 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1980 /* now release them */
1981 for (i = 0; i < victimCount; i++) {
1982 smb_ReleaseDirSearchNoLock(victimsp[i]);
1986 /* function for allocating a dir search entry. We need these to remember enough context
1987 * since we don't get passed the path from call to call during a directory search.
1989 * Returns a held dir search structure, and bumps the reference count on the vnode,
1990 * since it saves a pointer to the vnode.
1992 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1994 smb_dirSearch_t *dsp;
2000 lock_ObtainWrite(&smb_globalLock);
2003 /* what's the biggest ID allowed in this version of the protocol */
2004 /* TODO: do we really want a non v3 dir search request to wrap
2005 smb_dirSearchCounter? */
2006 maxAllowed = isV3 ? 65535 : 255;
2007 if (smb_dirSearchCounter > maxAllowed)
2008 smb_dirSearchCounter = 1;
2010 start = smb_dirSearchCounter;
2013 /* twice so we have enough tries to find guys we GC after one pass;
2014 * 10 extra is just in case I mis-counted.
2016 if (++counter > 2*maxAllowed+10)
2017 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2019 if (smb_dirSearchCounter > maxAllowed) {
2020 smb_dirSearchCounter = 1;
2022 if (smb_dirSearchCounter == start) {
2024 smb_GCDirSearches(isV3);
2027 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2029 /* don't need to watch for refcount zero and deleted, since
2030 * we haven't dropped the global lock.
2032 lock_ObtainMutex(&dsp->mx);
2034 lock_ReleaseMutex(&dsp->mx);
2035 ++smb_dirSearchCounter;
2039 dsp = malloc(sizeof(*dsp));
2040 memset(dsp, 0, sizeof(*dsp));
2041 dsp->cookie = smb_dirSearchCounter;
2042 ++smb_dirSearchCounter;
2044 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2045 dsp->lastTime = osi_Time();
2046 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2047 if (!smb_lastDirSearchp)
2048 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2050 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2054 lock_ReleaseWrite(&smb_globalLock);
2058 static smb_packet_t *GetPacket(void)
2062 lock_ObtainWrite(&smb_globalLock);
2063 tbp = smb_packetFreeListp;
2065 smb_packetFreeListp = tbp->nextp;
2066 lock_ReleaseWrite(&smb_globalLock);
2068 tbp = calloc(65540,1);
2069 tbp->magic = SMB_PACKETMAGIC;
2072 tbp->resumeCode = 0;
2078 tbp->ncb_length = 0;
2083 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2088 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2092 memcpy(tbp, pkt, sizeof(smb_packet_t));
2093 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2095 smb_HoldVC(tbp->vcp);
2099 static NCB *GetNCB(void)
2104 lock_ObtainWrite(&smb_globalLock);
2105 tbp = smb_ncbFreeListp;
2107 smb_ncbFreeListp = tbp->nextp;
2108 lock_ReleaseWrite(&smb_globalLock);
2110 tbp = calloc(sizeof(*tbp),1);
2111 tbp->magic = SMB_NCBMAGIC;
2114 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2116 memset(&tbp->ncb, 0, sizeof(NCB));
2121 void smb_FreePacket(smb_packet_t *tbp)
2123 smb_vc_t * vcp = NULL;
2124 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2126 lock_ObtainWrite(&smb_globalLock);
2127 tbp->nextp = smb_packetFreeListp;
2128 smb_packetFreeListp = tbp;
2129 tbp->magic = SMB_PACKETMAGIC;
2133 tbp->resumeCode = 0;
2139 tbp->ncb_length = 0;
2141 lock_ReleaseWrite(&smb_globalLock);
2147 static void FreeNCB(NCB *bufferp)
2151 tbp = (smb_ncb_t *) bufferp;
2152 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2154 lock_ObtainWrite(&smb_globalLock);
2155 tbp->nextp = smb_ncbFreeListp;
2156 smb_ncbFreeListp = tbp;
2157 lock_ReleaseWrite(&smb_globalLock);
2160 /* get a ptr to the data part of a packet, and its count */
2161 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2165 unsigned char *afterParmsp;
2167 parmBytes = *smbp->wctp << 1;
2168 afterParmsp = smbp->wctp + parmBytes + 1;
2170 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2171 if (nbytesp) *nbytesp = dataBytes;
2173 /* don't forget to skip the data byte count, since it follows
2174 * the parameters; that's where the "2" comes from below.
2176 return (unsigned char *) (afterParmsp + 2);
2179 /* must set all the returned parameters before playing around with the
2180 * data region, since the data region is located past the end of the
2181 * variable number of parameters.
2183 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2185 unsigned char *afterParmsp;
2187 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2189 *afterParmsp++ = dsize & 0xff;
2190 *afterParmsp = (dsize>>8) & 0xff;
2193 /* return the parm'th parameter in the smbp packet */
2194 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2197 unsigned char *parmDatap;
2199 parmCount = *smbp->wctp;
2201 if (parm >= parmCount) {
2204 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2205 parm, parmCount, smbp->ncb_length);
2206 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2207 parm, parmCount, smbp->ncb_length);
2208 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2209 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2210 osi_panic(s, __FILE__, __LINE__);
2212 parmDatap = smbp->wctp + (2*parm) + 1;
2214 return parmDatap[0] + (parmDatap[1] << 8);
2217 /* return the parm'th parameter in the smbp packet */
2218 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2221 unsigned char *parmDatap;
2223 parmCount = *smbp->wctp;
2225 if (parm >= parmCount) {
2228 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2229 parm, parmCount, smbp->ncb_length);
2230 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2231 parm, parmCount, smbp->ncb_length);
2232 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2233 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2234 osi_panic(s, __FILE__, __LINE__);
2236 parmDatap = smbp->wctp + (2*parm) + 1;
2238 return parmDatap[0];
2241 /* return the parm'th parameter in the smbp packet */
2242 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2245 unsigned char *parmDatap;
2247 parmCount = *smbp->wctp;
2249 if (parm + 1 >= parmCount) {
2252 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2253 parm, parmCount, smbp->ncb_length);
2254 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2255 parm, parmCount, smbp->ncb_length);
2256 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2257 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2258 osi_panic(s, __FILE__, __LINE__);
2260 parmDatap = smbp->wctp + (2*parm) + 1;
2262 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2265 /* return the parm'th parameter in the smbp packet */
2266 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2269 unsigned char *parmDatap;
2271 parmCount = *smbp->wctp;
2273 if (parm * 2 + offset >= parmCount * 2) {
2276 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2277 parm, offset, parmCount, smbp->ncb_length);
2278 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2279 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2280 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2281 parm, offset, parmCount, smbp->ncb_length);
2282 osi_panic(s, __FILE__, __LINE__);
2284 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2286 return parmDatap[0] + (parmDatap[1] << 8);
2289 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2293 /* make sure we have enough slots */
2294 if (*smbp->wctp <= slot)
2295 *smbp->wctp = slot+1;
2297 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2298 *parmDatap++ = parmValue & 0xff;
2299 *parmDatap = (parmValue>>8) & 0xff;
2302 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2306 /* make sure we have enough slots */
2307 if (*smbp->wctp <= slot)
2308 *smbp->wctp = slot+2;
2310 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2311 *parmDatap++ = parmValue & 0xff;
2312 *parmDatap++ = (parmValue>>8) & 0xff;
2313 *parmDatap++ = (parmValue>>16) & 0xff;
2314 *parmDatap = (parmValue>>24) & 0xff;
2317 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2322 /* make sure we have enough slots */
2323 if (*smbp->wctp <= slot)
2324 *smbp->wctp = slot+4;
2326 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2328 *parmDatap++ = *parmValuep++;
2331 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2335 /* make sure we have enough slots */
2336 if (*smbp->wctp <= slot) {
2337 if (smbp->oddByte) {
2339 *smbp->wctp = slot+1;
2344 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2345 *parmDatap++ = parmValue & 0xff;
2348 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2352 lastSlashp = strrchr(inPathp, '\\');
2354 *lastComponentp = lastSlashp;
2357 if (inPathp == lastSlashp)
2359 *outPathp++ = *inPathp++;
2368 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2373 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2378 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2384 tlen = inp[0] + (inp[1]<<8);
2385 inp += 2; /* skip length field */
2388 *chainpp = inp + tlen;
2397 /* format a packet as a response */
2398 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2403 outp = (smb_t *) op;
2405 /* zero the basic structure through the smb_wct field, and zero the data
2406 * size field, assuming that wct stays zero; otherwise, you have to
2407 * explicitly set the data size field, too.
2409 inSmbp = (smb_t *) inp;
2410 memset(outp, 0, sizeof(smb_t)+2);
2416 outp->com = inSmbp->com;
2417 outp->tid = inSmbp->tid;
2418 outp->pid = inSmbp->pid;
2419 outp->uid = inSmbp->uid;
2420 outp->mid = inSmbp->mid;
2421 outp->res[0] = inSmbp->res[0];
2422 outp->res[1] = inSmbp->res[1];
2423 op->inCom = inSmbp->com;
2425 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2426 #ifdef SEND_CANONICAL_PATHNAMES
2427 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2429 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2431 /* copy fields in generic packet area */
2432 op->wctp = &outp->wct;
2435 /* send a (probably response) packet; vcp tells us to whom to send it.
2436 * we compute the length by looking at wct and bcc fields.
2438 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2452 memset((char *)ncbp, 0, sizeof(NCB));
2454 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2455 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2456 extra += tp[0] + (tp[1]<<8);
2457 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2458 extra += 3; /* wct and length fields */
2460 ncbp->ncb_length = extra; /* bytes to send */
2461 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2462 ncbp->ncb_lana_num = vcp->lana;
2463 ncbp->ncb_command = NCBSEND; /* op means send data */
2464 ncbp->ncb_buffer = (char *) inp;/* packet */
2465 code = Netbios(ncbp);
2468 const char * s = ncb_error_string(code);
2469 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2470 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2472 lock_ObtainMutex(&vcp->mx);
2473 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2474 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2476 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2477 lock_ReleaseMutex(&vcp->mx);
2478 lock_ObtainWrite(&smb_globalLock);
2479 dead_sessions[vcp->session] = TRUE;
2480 lock_ReleaseWrite(&smb_globalLock);
2481 smb_CleanupDeadVC(vcp);
2483 lock_ReleaseMutex(&vcp->mx);
2491 void smb_MapNTError(long code, unsigned long *NTStatusp)
2493 unsigned long NTStatus;
2495 /* map CM_ERROR_* errors to NT 32-bit status codes */
2496 /* NT Status codes are listed in ntstatus.h not winerror.h */
2497 if (code == CM_ERROR_NOSUCHCELL) {
2498 NTStatus = 0xC000000FL; /* No such file */
2500 else if (code == CM_ERROR_NOSUCHVOLUME) {
2501 NTStatus = 0xC000000FL; /* No such file */
2503 else if (code == CM_ERROR_TIMEDOUT) {
2505 NTStatus = 0xC00000CFL; /* Sharing Paused */
2507 NTStatus = 0x00000102L; /* Timeout */
2510 else if (code == CM_ERROR_RETRY) {
2511 NTStatus = 0xC000022DL; /* Retry */
2513 else if (code == CM_ERROR_NOACCESS) {
2514 NTStatus = 0xC0000022L; /* Access denied */
2516 else if (code == CM_ERROR_READONLY) {
2517 NTStatus = 0xC00000A2L; /* Write protected */
2519 else if (code == CM_ERROR_NOSUCHFILE ||
2520 code == CM_ERROR_BPLUS_NOMATCH) {
2521 NTStatus = 0xC000000FL; /* No such file */
2523 else if (code == CM_ERROR_NOSUCHPATH) {
2524 NTStatus = 0xC000003AL; /* Object path not found */
2526 else if (code == CM_ERROR_TOOBIG) {
2527 NTStatus = 0xC000007BL; /* Invalid image format */
2529 else if (code == CM_ERROR_INVAL) {
2530 NTStatus = 0xC000000DL; /* Invalid parameter */
2532 else if (code == CM_ERROR_BADFD) {
2533 NTStatus = 0xC0000008L; /* Invalid handle */
2535 else if (code == CM_ERROR_BADFDOP) {
2536 NTStatus = 0xC0000022L; /* Access denied */
2538 else if (code == CM_ERROR_EXISTS) {
2539 NTStatus = 0xC0000035L; /* Object name collision */
2541 else if (code == CM_ERROR_NOTEMPTY) {
2542 NTStatus = 0xC0000101L; /* Directory not empty */
2544 else if (code == CM_ERROR_CROSSDEVLINK) {
2545 NTStatus = 0xC00000D4L; /* Not same device */
2547 else if (code == CM_ERROR_NOTDIR) {
2548 NTStatus = 0xC0000103L; /* Not a directory */
2550 else if (code == CM_ERROR_ISDIR) {
2551 NTStatus = 0xC00000BAL; /* File is a directory */
2553 else if (code == CM_ERROR_BADOP) {
2555 /* I have no idea where this comes from */
2556 NTStatus = 0xC09820FFL; /* SMB no support */
2558 NTStatus = 0xC00000BBL; /* Not supported */
2559 #endif /* COMMENT */
2561 else if (code == CM_ERROR_BADSHARENAME) {
2562 NTStatus = 0xC00000CCL; /* Bad network name */
2564 else if (code == CM_ERROR_NOIPC) {
2566 NTStatus = 0xC0000022L; /* Access Denied */
2568 NTStatus = 0xC000013DL; /* Remote Resources */
2571 else if (code == CM_ERROR_CLOCKSKEW) {
2572 NTStatus = 0xC0000133L; /* Time difference at DC */
2574 else if (code == CM_ERROR_BADTID) {
2575 NTStatus = 0xC0982005L; /* SMB bad TID */
2577 else if (code == CM_ERROR_USESTD) {
2578 NTStatus = 0xC09820FBL; /* SMB use standard */
2580 else if (code == CM_ERROR_QUOTA) {
2582 NTStatus = 0xC0000044L; /* Quota exceeded */
2584 NTStatus = 0xC000007FL; /* Disk full */
2587 else if (code == CM_ERROR_SPACE) {
2588 NTStatus = 0xC000007FL; /* Disk full */
2590 else if (code == CM_ERROR_ATSYS) {
2591 NTStatus = 0xC0000033L; /* Object name invalid */
2593 else if (code == CM_ERROR_BADNTFILENAME) {
2594 NTStatus = 0xC0000033L; /* Object name invalid */
2596 else if (code == CM_ERROR_WOULDBLOCK) {
2597 NTStatus = 0xC0000055L; /* Lock not granted */
2599 else if (code == CM_ERROR_SHARING_VIOLATION) {
2600 NTStatus = 0xC0000043L; /* Sharing violation */
2602 else if (code == CM_ERROR_LOCK_CONFLICT) {
2603 NTStatus = 0xC0000054L; /* Lock conflict */
2605 else if (code == CM_ERROR_PARTIALWRITE) {
2606 NTStatus = 0xC000007FL; /* Disk full */
2608 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2609 NTStatus = 0xC0000023L; /* Buffer too small */
2611 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2612 NTStatus = 0xC0000035L; /* Object name collision */
2614 else if (code == CM_ERROR_BADPASSWORD) {
2615 NTStatus = 0xC000006DL; /* unknown username or bad password */
2617 else if (code == CM_ERROR_BADLOGONTYPE) {
2618 NTStatus = 0xC000015BL; /* logon type not granted */
2620 else if (code == CM_ERROR_GSSCONTINUE) {
2621 NTStatus = 0xC0000016L; /* more processing required */
2623 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2625 NTStatus = 0xC0000280L; /* reparse point not resolved */
2627 NTStatus = 0xC0000022L; /* Access Denied */
2630 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2631 NTStatus = 0xC0000257L; /* Path Not Covered */
2633 else if (code == CM_ERROR_ALLBUSY) {
2634 NTStatus = 0xC000022DL; /* Retry */
2636 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2637 NTStatus = 0xC00000BEL; /* Bad Network Path */
2639 else if (code == RXKADUNKNOWNKEY) {
2640 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2642 else if (code == CM_ERROR_BAD_LEVEL) {
2643 NTStatus = 0xC0000148L; /* Invalid Level */
2645 NTStatus = 0xC0982001L; /* SMB non-specific error */
2648 *NTStatusp = NTStatus;
2649 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2652 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2653 unsigned char *classp)
2655 unsigned char class;
2656 unsigned short error;
2658 /* map CM_ERROR_* errors to SMB errors */
2659 if (code == CM_ERROR_NOSUCHCELL) {
2661 error = 3; /* bad path */
2663 else if (code == CM_ERROR_NOSUCHVOLUME) {
2665 error = 3; /* bad path */
2667 else if (code == CM_ERROR_TIMEDOUT) {
2669 error = 81; /* server is paused */
2671 else if (code == CM_ERROR_RETRY) {
2672 class = 2; /* shouldn't happen */
2675 else if (code == CM_ERROR_NOACCESS) {
2677 error = 4; /* bad access */
2679 else if (code == CM_ERROR_READONLY) {
2681 error = 19; /* read only */
2683 else if (code == CM_ERROR_NOSUCHFILE ||
2684 code == CM_ERROR_BPLUS_NOMATCH) {
2686 error = 2; /* ENOENT! */
2688 else if (code == CM_ERROR_NOSUCHPATH) {
2690 error = 3; /* Bad path */
2692 else if (code == CM_ERROR_TOOBIG) {
2694 error = 11; /* bad format */
2696 else if (code == CM_ERROR_INVAL) {
2697 class = 2; /* server non-specific error code */
2700 else if (code == CM_ERROR_BADFD) {
2702 error = 6; /* invalid file handle */
2704 else if (code == CM_ERROR_BADFDOP) {
2705 class = 1; /* invalid op on FD */
2708 else if (code == CM_ERROR_EXISTS) {
2710 error = 80; /* file already exists */
2712 else if (code == CM_ERROR_NOTEMPTY) {
2714 error = 5; /* delete directory not empty */
2716 else if (code == CM_ERROR_CROSSDEVLINK) {
2718 error = 17; /* EXDEV */
2720 else if (code == CM_ERROR_NOTDIR) {
2721 class = 1; /* bad path */
2724 else if (code == CM_ERROR_ISDIR) {
2725 class = 1; /* access denied; DOS doesn't have a good match */
2728 else if (code == CM_ERROR_BADOP) {
2732 else if (code == CM_ERROR_BADSHARENAME) {
2736 else if (code == CM_ERROR_NOIPC) {
2738 error = 4; /* bad access */
2740 else if (code == CM_ERROR_CLOCKSKEW) {
2741 class = 1; /* invalid function */
2744 else if (code == CM_ERROR_BADTID) {
2748 else if (code == CM_ERROR_USESTD) {
2752 else if (code == CM_ERROR_REMOTECONN) {
2756 else if (code == CM_ERROR_QUOTA) {
2757 if (vcp->flags & SMB_VCFLAG_USEV3) {
2759 error = 39; /* disk full */
2763 error = 5; /* access denied */
2766 else if (code == CM_ERROR_SPACE) {
2767 if (vcp->flags & SMB_VCFLAG_USEV3) {
2769 error = 39; /* disk full */
2773 error = 5; /* access denied */
2776 else if (code == CM_ERROR_PARTIALWRITE) {
2778 error = 39; /* disk full */
2780 else if (code == CM_ERROR_ATSYS) {
2782 error = 2; /* ENOENT */
2784 else if (code == CM_ERROR_WOULDBLOCK) {
2786 error = 33; /* lock conflict */
2788 else if (code == CM_ERROR_LOCK_CONFLICT) {
2790 error = 33; /* lock conflict */
2792 else if (code == CM_ERROR_SHARING_VIOLATION) {
2794 error = 33; /* lock conflict */
2796 else if (code == CM_ERROR_NOFILES) {
2798 error = 18; /* no files in search */
2800 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2802 error = 183; /* Samba uses this */
2804 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2805 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2807 error = 2; /* bad password */
2809 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2811 error = 3; /* bad path */
2820 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2823 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2825 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2826 return CM_ERROR_BADOP;
2829 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2831 unsigned short EchoCount, i;
2832 char *data, *outdata;
2835 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2837 for (i=1; i<=EchoCount; i++) {
2838 data = smb_GetSMBData(inp, &dataSize);
2839 smb_SetSMBParm(outp, 0, i);
2840 smb_SetSMBDataLength(outp, dataSize);
2841 outdata = smb_GetSMBData(outp, NULL);
2842 memcpy(outdata, data, dataSize);
2843 smb_SendPacket(vcp, outp);
2849 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2852 long count, minCount, finalCount;
2857 cm_user_t *userp = NULL;
2860 char *rawBuf = NULL;
2865 fd = smb_GetSMBParm(inp, 0);
2866 count = smb_GetSMBParm(inp, 3);
2867 minCount = smb_GetSMBParm(inp, 4);
2868 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2870 if (*inp->wctp == 10) {
2871 /* we were sent a request with 64-bit file offsets */
2872 #ifdef AFS_LARGEFILES
2873 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2875 if (LargeIntegerLessThanZero(offset)) {
2876 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2880 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2881 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2884 offset.HighPart = 0;
2888 /* we were sent a request with 32-bit file offsets */
2889 offset.HighPart = 0;
2892 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2893 fd, offset.HighPart, offset.LowPart, count);
2895 fidp = smb_FindFID(vcp, fd, 0);
2899 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
2900 smb_CloseFID(vcp, fidp, NULL, 0);
2901 code = CM_ERROR_NOSUCHFILE;
2906 pid = ((smb_t *) inp)->pid;
2908 LARGE_INTEGER LOffset, LLength;
2911 key = cm_GenerateKey(vcp->vcID, pid, fd);
2913 LOffset.HighPart = offset.HighPart;
2914 LOffset.LowPart = offset.LowPart;
2915 LLength.HighPart = 0;
2916 LLength.LowPart = count;
2918 lock_ObtainMutex(&fidp->scp->mx);
2919 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2920 lock_ReleaseMutex(&fidp->scp->mx);
2926 lock_ObtainMutex(&smb_RawBufLock);
2928 /* Get a raw buf, from head of list */
2929 rawBuf = smb_RawBufs;
2930 smb_RawBufs = *(char **)smb_RawBufs;
2932 lock_ReleaseMutex(&smb_RawBufLock);
2936 lock_ObtainMutex(&fidp->mx);
2937 if (fidp->flags & SMB_FID_IOCTL)
2939 lock_ReleaseMutex(&fidp->mx);
2940 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2942 /* Give back raw buffer */
2943 lock_ObtainMutex(&smb_RawBufLock);
2944 *((char **) rawBuf) = smb_RawBufs;
2946 smb_RawBufs = rawBuf;
2947 lock_ReleaseMutex(&smb_RawBufLock);
2950 smb_ReleaseFID(fidp);
2953 lock_ReleaseMutex(&fidp->mx);
2955 userp = smb_GetUserFromVCP(vcp, inp);
2957 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2963 cm_ReleaseUser(userp);
2966 smb_ReleaseFID(fidp);
2970 memset((char *)ncbp, 0, sizeof(NCB));
2972 ncbp->ncb_length = (unsigned short) finalCount;
2973 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2974 ncbp->ncb_lana_num = vcp->lana;
2975 ncbp->ncb_command = NCBSEND;
2976 ncbp->ncb_buffer = rawBuf;
2978 code = Netbios(ncbp);
2980 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2983 /* Give back raw buffer */
2984 lock_ObtainMutex(&smb_RawBufLock);
2985 *((char **) rawBuf) = smb_RawBufs;
2987 smb_RawBufs = rawBuf;
2988 lock_ReleaseMutex(&smb_RawBufLock);
2994 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2996 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3001 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3003 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3008 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3015 int VistaProtoIndex;
3016 int protoIndex; /* index we're using */
3021 char protocol_array[10][1024]; /* protocol signature of the client */
3022 int caps; /* capabilities */
3025 TIME_ZONE_INFORMATION tzi;
3027 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3030 namep = smb_GetSMBData(inp, &dbytes);
3033 coreProtoIndex = -1; /* not found */
3036 VistaProtoIndex = -1;
3037 while(namex < dbytes) {
3038 osi_Log1(smb_logp, "Protocol %s",
3039 osi_LogSaveString(smb_logp, namep+1));
3040 strcpy(protocol_array[tcounter], namep+1);
3042 /* namep points at the first protocol, or really, a 0x02
3043 * byte preceding the null-terminated ASCII name.
3045 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3046 coreProtoIndex = tcounter;
3048 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3049 v3ProtoIndex = tcounter;
3051 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3052 NTProtoIndex = tcounter;
3054 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3055 VistaProtoIndex = tcounter;
3058 /* compute size of protocol entry */
3059 entryLength = (int)strlen(namep+1);
3060 entryLength += 2; /* 0x02 bytes and null termination */
3062 /* advance over this protocol entry */
3063 namex += entryLength;
3064 namep += entryLength;
3065 tcounter++; /* which proto entry we're looking at */
3068 lock_ObtainMutex(&vcp->mx);
3070 if (VistaProtoIndex != -1) {
3071 protoIndex = VistaProtoIndex;
3072 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3075 if (NTProtoIndex != -1) {
3076 protoIndex = NTProtoIndex;
3077 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3079 else if (v3ProtoIndex != -1) {
3080 protoIndex = v3ProtoIndex;
3081 vcp->flags |= SMB_VCFLAG_USEV3;
3083 else if (coreProtoIndex != -1) {
3084 protoIndex = coreProtoIndex;
3085 vcp->flags |= SMB_VCFLAG_USECORE;
3087 else protoIndex = -1;
3088 lock_ReleaseMutex(&vcp->mx);
3090 if (protoIndex == -1)
3091 return CM_ERROR_INVAL;
3092 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3093 smb_SetSMBParm(outp, 0, protoIndex);
3094 if (smb_authType != SMB_AUTH_NONE) {
3095 smb_SetSMBParmByte(outp, 1,
3096 NEGOTIATE_SECURITY_USER_LEVEL |
3097 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3099 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3101 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3102 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3103 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3104 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3105 /* The session key is not a well documented field however most clients
3106 * will echo back the session key to the server. Currently we are using
3107 * the same value for all sessions. We should generate a random value
3108 * and store it into the vcp
3110 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3111 smb_SetSMBParm(outp, 8, 1);
3113 * Tried changing the capabilities to support for W2K - defect 117695
3114 * Maybe something else needs to be changed here?
3118 smb_SetSMBParmLong(outp, 9, 0x43fd);
3120 smb_SetSMBParmLong(outp, 9, 0x251);
3123 * 32-bit error codes *
3128 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3130 NTNEGOTIATE_CAPABILITY_DFS |
3132 #ifdef AFS_LARGEFILES
3133 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3135 NTNEGOTIATE_CAPABILITY_NTFIND |
3136 NTNEGOTIATE_CAPABILITY_RAWMODE |
3137 NTNEGOTIATE_CAPABILITY_NTSMB;
3139 if ( smb_authType == SMB_AUTH_EXTENDED )
3140 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3142 smb_SetSMBParmLong(outp, 9, caps);
3144 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3145 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3146 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3148 GetTimeZoneInformation(&tzi);
3149 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3151 if (smb_authType == SMB_AUTH_NTLM) {
3152 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3153 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3154 /* paste in encryption key */
3155 datap = smb_GetSMBData(outp, NULL);
3156 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3157 /* and the faux domain name */
3158 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3159 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3163 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3165 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3167 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3169 datap = smb_GetSMBData(outp, NULL);
3170 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3173 datap += sizeof(smb_ServerGUID);
3174 memcpy(datap, secBlob, secBlobLength);
3178 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3179 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3182 else if (v3ProtoIndex != -1) {
3183 smb_SetSMBParm(outp, 0, protoIndex);
3185 /* NOTE: Extended authentication cannot be negotiated with v3
3186 * therefore we fail over to NTLM
3188 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3189 smb_SetSMBParm(outp, 1,
3190 NEGOTIATE_SECURITY_USER_LEVEL |
3191 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3193 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3195 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3196 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3197 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3198 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3199 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3200 smb_SetSMBParm(outp, 7, 1);
3202 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3203 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3204 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3206 GetTimeZoneInformation(&tzi);
3207 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3209 /* NOTE: Extended authentication cannot be negotiated with v3
3210 * therefore we fail over to NTLM
3212 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3213 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3214 smb_SetSMBParm(outp, 12, 0); /* resvd */
3215 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3216 datap = smb_GetSMBData(outp, NULL);
3217 /* paste in a new encryption key */
3218 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3219 /* and the faux domain name */
3220 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3222 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3223 smb_SetSMBParm(outp, 12, 0); /* resvd */
3224 smb_SetSMBDataLength(outp, 0);
3227 else if (coreProtoIndex != -1) { /* not really supported anymore */
3228 smb_SetSMBParm(outp, 0, protoIndex);
3229 smb_SetSMBDataLength(outp, 0);
3234 void smb_CheckVCs(void)
3236 smb_vc_t * vcp, *nextp;
3237 smb_packet_t * outp = GetPacket();
3240 lock_ObtainWrite(&smb_rctLock);
3241 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3243 if (vcp->magic != SMB_VC_MAGIC)
3244 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3245 __FILE__, __LINE__);
3249 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3252 smb_HoldVCNoLock(vcp);
3254 smb_HoldVCNoLock(nextp);
3255 smb_FormatResponsePacket(vcp, NULL, outp);
3256 smbp = (smb_t *)outp;
3257 outp->inCom = smbp->com = 0x2b /* Echo */;
3265 smb_SetSMBParm(outp, 0, 0);
3266 smb_SetSMBDataLength(outp, 0);
3267 lock_ReleaseWrite(&smb_rctLock);
3269 smb_SendPacket(vcp, outp);
3271 lock_ObtainWrite(&smb_rctLock);
3272 smb_ReleaseVCNoLock(vcp);
3274 smb_ReleaseVCNoLock(nextp);
3276 lock_ReleaseWrite(&smb_rctLock);
3277 smb_FreePacket(outp);
3280 void smb_Daemon(void *parmp)
3282 afs_uint32 count = 0;
3283 smb_username_t **unpp;
3286 while(smbShutdownFlag == 0) {
3290 if (smbShutdownFlag == 1)
3293 if ((count % 72) == 0) { /* every five minutes */
3295 time_t old_localZero = smb_localZero;
3297 /* Initialize smb_localZero */
3298 myTime.tm_isdst = -1; /* compute whether on DST or not */
3299 myTime.tm_year = 70;
3305 smb_localZero = mktime(&myTime);
3307 #ifndef USE_NUMERIC_TIME_CONV
3308 smb_CalculateNowTZ();
3309 #endif /* USE_NUMERIC_TIME_CONV */
3310 #ifdef AFS_FREELANCE
3311 if ( smb_localZero != old_localZero )
3312 cm_noteLocalMountPointChange();
3318 /* GC smb_username_t objects that will no longer be used */
3320 lock_ObtainWrite(&smb_rctLock);
3321 for ( unpp=&usernamesp; *unpp; ) {
3323 smb_username_t *unp;
3325 lock_ObtainMutex(&(*unpp)->mx);
3326 if ( (*unpp)->refCount > 0 ||
3327 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3328 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3330 else if (!smb_LogoffTokenTransfer ||
3331 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3333 lock_ReleaseMutex(&(*unpp)->mx);
3341 lock_FinalizeMutex(&unp->mx);
3347 lock_ReleaseWrite(&smb_rctLock);
3348 cm_ReleaseUser(userp);
3349 lock_ObtainWrite(&smb_rctLock);
3352 unpp = &(*unpp)->nextp;
3355 lock_ReleaseWrite(&smb_rctLock);
3357 /* XXX GC dir search entries */
3361 void smb_WaitingLocksDaemon()
3363 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3364 smb_waitingLock_t *wl, *wlNext;
3367 smb_packet_t *inp, *outp;
3371 while (smbShutdownFlag == 0) {
3372 lock_ObtainWrite(&smb_globalLock);
3373 nwlRequest = smb_allWaitingLocks;
3374 if (nwlRequest == NULL) {
3375 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3380 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3387 lock_ObtainWrite(&smb_globalLock);
3389 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3391 wlRequest = nwlRequest;
3392 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3393 lock_ReleaseWrite(&smb_globalLock);
3397 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3398 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3401 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3403 /* wl->state is either _DONE or _WAITING. _ERROR
3404 would no longer be on the queue. */
3405 code = cm_RetryLock( wl->lockp,
3406 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3409 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3410 } else if (code != CM_ERROR_WOULDBLOCK) {
3411 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3416 if (code == CM_ERROR_WOULDBLOCK) {
3419 if (wlRequest->timeRemaining != 0xffffffff
3420 && (wlRequest->timeRemaining -= 1000) < 0)
3432 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3435 scp = wlRequest->scp;
3436 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3440 lock_ObtainMutex(&scp->mx);
3442 for (wl = wlRequest->locks; wl; wl = wlNext) {
3443 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3445 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3446 wl->LLength, wl->key, NULL, &req);
3448 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3453 lock_ReleaseMutex(&scp->mx);
3457 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3460 for (wl = wlRequest->locks; wl; wl = wlNext) {
3461 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3462 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3467 vcp = wlRequest->vcp;
3468 inp = wlRequest->inp;
3469 outp = wlRequest->outp;
3471 ncbp->ncb_length = inp->ncb_length;
3472 inp->spacep = cm_GetSpace();
3474 /* Remove waitingLock from list */
3475 lock_ObtainWrite(&smb_globalLock);
3476 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3478 lock_ReleaseWrite(&smb_globalLock);
3480 /* Resume packet processing */
3482 smb_SetSMBDataLength(outp, 0);
3483 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3484 outp->resumeCode = code;
3486 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3489 cm_FreeSpace(inp->spacep);
3490 smb_FreePacket(inp);
3491 smb_FreePacket(outp);
3493 cm_ReleaseSCache(wlRequest->scp);
3496 } while (nwlRequest && smbShutdownFlag == 0);
3501 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3503 osi_Log0(smb_logp, "SMB receive get disk attributes");
3505 smb_SetSMBParm(outp, 0, 32000);
3506 smb_SetSMBParm(outp, 1, 64);
3507 smb_SetSMBParm(outp, 2, 1024);
3508 smb_SetSMBParm(outp, 3, 30000);
3509 smb_SetSMBParm(outp, 4, 0);
3510 smb_SetSMBDataLength(outp, 0);
3514 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3518 unsigned short newTid;
3519 char shareName[AFSPATHMAX];
3527 osi_Log0(smb_logp, "SMB receive tree connect");
3529 /* parse input parameters */
3530 tp = smb_GetSMBData(inp, NULL);
3531 pathp = smb_ParseASCIIBlock(tp, &tp);
3532 if (smb_StoreAnsiFilenames)
3533 OemToChar(pathp,pathp);
3534 passwordp = smb_ParseASCIIBlock(tp, &tp);
3535 tp = strrchr(pathp, '\\');
3537 return CM_ERROR_BADSMB;
3538 strcpy(shareName, tp+1);
3540 lock_ObtainMutex(&vcp->mx);
3541 newTid = vcp->tidCounter++;
3542 lock_ReleaseMutex(&vcp->mx);
3544 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3545 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3546 userp = smb_GetUserFromUID(uidp);
3547 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3549 smb_ReleaseUID(uidp);
3551 smb_ReleaseTID(tidp);
3552 return CM_ERROR_BADSHARENAME;
3554 lock_ObtainMutex(&tidp->mx);
3555 tidp->userp = userp;
3556 tidp->pathname = sharePath;
3557 lock_ReleaseMutex(&tidp->mx);
3558 smb_ReleaseTID(tidp);
3560 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3561 smb_SetSMBParm(rsp, 1, newTid);
3562 smb_SetSMBDataLength(rsp, 0);
3564 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3568 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3572 if (*inp++ != 0x1) return NULL;
3573 tlen = inp[0] + (inp[1]<<8);
3574 inp += 2; /* skip length field */
3577 *chainpp = inp + tlen;
3580 if (lengthp) *lengthp = tlen;
3585 /* set maskp to the mask part of the incoming path.
3586 * Mask is 11 bytes long (8.3 with the dot elided).
3587 * Returns true if succeeds with a valid name, otherwise it does
3588 * its best, but returns false.
3590 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3598 /* starts off valid */
3601 /* mask starts out all blanks */
3602 memset(maskp, ' ', 11);
3605 /* find last backslash, or use whole thing if there is none */
3606 tp = strrchr(pathp, '\\');
3610 tp++; /* skip slash */
3614 /* names starting with a dot are illegal */
3622 if (tc == '.' || tc == '"')
3630 /* if we get here, tp point after the dot */
3631 up = maskp+8; /* ext goes here */
3638 if (tc == '.' || tc == '"')
3641 /* copy extension if not too long */
3651 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3661 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3663 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3667 /* otherwise, we have a valid 8.3 name; see if we have a match,
3668 * treating '?' as a wildcard in maskp (but not in the file name).
3670 tp1 = umask; /* real name, in mask format */
3671 tp2 = maskp; /* mask, in mask format */
3672 for(i=0; i<11; i++) {
3673 tc1 = *tp1++; /* char from real name */
3674 tc2 = *tp2++; /* char from mask */
3675 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3676 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3679 if (tc2 == '?' && tc1 != ' ')
3686 /* we got a match */
3690 char *smb_FindMask(char *pathp)
3694 tp = strrchr(pathp, '\\'); /* find last slash */
3697 return tp+1; /* skip the slash */
3699 return pathp; /* no slash, return the entire path */
3702 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3704 unsigned char *pathp;
3706 unsigned char mask[12];
3707 unsigned char *statBlockp;
3708 unsigned char initStatBlock[21];
3711 osi_Log0(smb_logp, "SMB receive search volume");
3713 /* pull pathname and stat block out of request */
3714 tp = smb_GetSMBData(inp, NULL);
3715 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3716 osi_assertx(pathp != NULL, "null path");
3717 if (smb_StoreAnsiFilenames)
3718 OemToChar(pathp,pathp);
3719 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3720 osi_assertx(statBlockp != NULL, "null statBlock");
3722 statBlockp = initStatBlock;
3726 /* for returning to caller */
3727 smb_Get8Dot3MaskFromPath(mask, pathp);
3729 smb_SetSMBParm(outp, 0, 1); /* we're