2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
32 #include "lanahelper.h"
34 /* These characters are illegal in Windows filenames */
35 static char *illegalChars = "\\/:*?\"<>|";
37 static int smbShutdownFlag = 0;
38 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
40 int smb_LogoffTokenTransfer;
41 time_t smb_LogoffTransferTimeout;
43 int smb_StoreAnsiFilenames = 0;
45 DWORD last_msg_time = 0;
49 unsigned int sessionGen = 0;
51 extern void afsi_log(char *pattern, ...);
52 extern HANDLE afsi_file;
53 extern int powerStateSuspended;
55 osi_hyper_t hzero = {0, 0};
56 osi_hyper_t hones = {0xFFFFFFFF, -1};
59 osi_rwlock_t smb_globalLock;
60 osi_rwlock_t smb_rctLock;
61 osi_mutex_t smb_ListenerLock;
62 osi_mutex_t smb_StartedLock;
64 unsigned char smb_LANadapter = LANA_INVALID;
65 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
66 int smb_LanAdapterChangeDetected = 0;
68 BOOL isGateway = FALSE;
71 long smb_maxObsConcurrentCalls=0;
72 long smb_concurrentCalls=0;
74 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
76 smb_packet_t *smb_packetFreeListp;
77 smb_ncb_t *smb_ncbFreeListp;
79 int smb_NumServerThreads;
81 int numNCBs, numSessions, numVCs;
83 int smb_maxVCPerServer;
84 int smb_maxMpxRequests;
86 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
88 ULONG smb_lsaSecPackage;
89 LSA_STRING smb_lsaLogonOrigin;
91 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
92 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
93 EVENT_HANDLE **NCBreturns;
94 EVENT_HANDLE **NCBShutdown;
95 EVENT_HANDLE *smb_ServerShutdown;
96 EVENT_HANDLE ListenerShutdown[256];
97 DWORD NCBsessions[NCB_MAX];
99 struct smb_packet *bufs[NCB_MAX];
101 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
102 EVENT_HANDLE SessionEvents[SESSION_MAX];
103 unsigned short LSNs[SESSION_MAX];
104 int lanas[SESSION_MAX];
105 BOOL dead_sessions[SESSION_MAX];
108 osi_mutex_t smb_RawBufLock;
111 #define SMB_MASKFLAG_TILDE 1
112 #define SMB_MASKFLAG_CASEFOLD 2
114 #define RAWTIMEOUT INFINITE
117 typedef struct raw_write_cont {
126 /* dir search stuff */
127 long smb_dirSearchCounter = 1;
128 smb_dirSearch_t *smb_firstDirSearchp;
129 smb_dirSearch_t *smb_lastDirSearchp;
131 /* hide dot files? */
132 int smb_hideDotFiles;
134 /* global state about V3 protocols */
135 int smb_useV3; /* try to negotiate V3 */
137 static showErrors = 0;
138 /* MessageBox or something like it */
139 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
142 * Time in Unix format of midnight, 1/1/1970 local time.
143 * When added to dosUTime, gives Unix (AFS) time.
145 time_t smb_localZero = 0;
147 #define USE_NUMERIC_TIME_CONV 1
149 #ifndef USE_NUMERIC_TIME_CONV
150 /* Time difference for converting to kludge-GMT */
151 afs_uint32 smb_NowTZ;
152 #endif /* USE_NUMERIC_TIME_CONV */
154 char *smb_localNamep = NULL;
156 smb_vc_t *smb_allVCsp;
157 smb_vc_t *smb_deadVCsp;
159 smb_username_t *usernamesp = NULL;
161 smb_waitingLockRequest_t *smb_allWaitingLocks;
163 DWORD smb_TlsRequestSlot = -1;
166 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
167 NCB *ncbp, raw_write_cont_t *rwcp);
168 int smb_NetbiosInit(int);
171 void smb_LogPacket(smb_packet_t *packet);
172 #endif /* LOG_PACKET */
174 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
175 int smb_ServerDomainNameLength = 0;
176 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
177 int smb_ServerOSLength = sizeof(smb_ServerOS);
178 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
179 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
181 /* Faux server GUID. This is never checked. */
182 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
184 void smb_ResetServerPriority()
186 void * p = TlsGetValue(smb_TlsRequestSlot);
189 TlsSetValue(smb_TlsRequestSlot, NULL);
190 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
194 void smb_SetRequestStartTime()
196 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
198 tp = malloc(sizeof(time_t));
202 if (!TlsSetValue(smb_TlsRequestSlot, tp))
207 void smb_UpdateServerPriority()
209 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
212 time_t now = osi_Time();
214 /* Give one priority boost for each 15 seconds */
215 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
220 const char * ncb_error_string(int code)
224 case 0x01: s = "llegal buffer length"; break;
225 case 0x03: s = "illegal command"; break;
226 case 0x05: s = "command timed out"; break;
227 case 0x06: s = "message incomplete, issue another command"; break;
228 case 0x07: s = "illegal buffer address"; break;
229 case 0x08: s = "session number out of range"; break;
230 case 0x09: s = "no resource available"; break;
231 case 0x0a: s = "session closed"; break;
232 case 0x0b: s = "command cancelled"; break;
233 case 0x0d: s = "duplicate name"; break;
234 case 0x0e: s = "name table full"; break;
235 case 0x0f: s = "no deletions, name has active sessions"; break;
236 case 0x11: s = "local session table full"; break;
237 case 0x12: s = "remote session table full"; break;
238 case 0x13: s = "illegal name number"; break;
239 case 0x14: s = "no callname"; break;
240 case 0x15: s = "cannot put * in NCB_NAME"; break;
241 case 0x16: s = "name in use on remote adapter"; break;
242 case 0x17: s = "name deleted"; break;
243 case 0x18: s = "session ended abnormally"; break;
244 case 0x19: s = "name conflict detected"; break;
245 case 0x21: s = "interface busy, IRET before retrying"; break;
246 case 0x22: s = "too many commands outstanding, retry later";break;
247 case 0x23: s = "ncb_lana_num field invalid"; break;
248 case 0x24: s = "command completed while cancel occurring "; break;
249 case 0x26: s = "command not valid to cancel"; break;
250 case 0x30: s = "name defined by anther local process"; break;
251 case 0x34: s = "environment undefined. RESET required"; break;
252 case 0x35: s = "required OS resources exhausted"; break;
253 case 0x36: s = "max number of applications exceeded"; break;
254 case 0x37: s = "no saps available for netbios"; break;
255 case 0x38: s = "requested resources are not available"; break;
256 case 0x39: s = "invalid ncb address or length > segment"; break;
257 case 0x3B: s = "invalid NCB DDID"; break;
258 case 0x3C: s = "lock of user area failed"; break;
259 case 0x3f: s = "NETBIOS not loaded"; break;
260 case 0x40: s = "system error"; break;
261 default: s = "unknown error";
267 char * myCrt_Dispatch(int i)
272 return "(00)ReceiveCoreMakeDir";
274 return "(01)ReceiveCoreRemoveDir";
276 return "(02)ReceiveCoreOpen";
278 return "(03)ReceiveCoreCreate";
280 return "(04)ReceiveCoreClose";
282 return "(05)ReceiveCoreFlush";
284 return "(06)ReceiveCoreUnlink";
286 return "(07)ReceiveCoreRename";
288 return "(08)ReceiveCoreGetFileAttributes";
290 return "(09)ReceiveCoreSetFileAttributes";
292 return "(0a)ReceiveCoreRead";
294 return "(0b)ReceiveCoreWrite";
296 return "(0c)ReceiveCoreLockRecord";
298 return "(0d)ReceiveCoreUnlockRecord";
300 return "(0e)SendCoreBadOp";
302 return "(0f)ReceiveCoreCreate";
304 return "(10)ReceiveCoreCheckPath";
306 return "(11)SendCoreBadOp";
308 return "(12)ReceiveCoreSeek";
310 return "(1a)ReceiveCoreReadRaw";
312 return "(1d)ReceiveCoreWriteRawDummy";
314 return "(22)ReceiveV3SetAttributes";
316 return "(23)ReceiveV3GetAttributes";
318 return "(24)ReceiveV3LockingX";
320 return "(25)ReceiveV3Trans";
322 return "(26)ReceiveV3Trans[aux]";
324 return "(29)SendCoreBadOp";
326 return "(2b)ReceiveCoreEcho";
328 return "(2d)ReceiveV3OpenX";
330 return "(2e)ReceiveV3ReadX";
332 return "(2f)ReceiveV3WriteX";
334 return "(32)ReceiveV3Tran2A";
336 return "(33)ReceiveV3Tran2A[aux]";
338 return "(34)ReceiveV3FindClose";
340 return "(35)ReceiveV3FindNotifyClose";
342 return "(70)ReceiveCoreTreeConnect";
344 return "(71)ReceiveCoreTreeDisconnect";
346 return "(72)ReceiveNegotiate";
348 return "(73)ReceiveV3SessionSetupX";
350 return "(74)ReceiveV3UserLogoffX";
352 return "(75)ReceiveV3TreeConnectX";
354 return "(80)ReceiveCoreGetDiskAttributes";
356 return "(81)ReceiveCoreSearchDir";
360 return "(83)FindUnique";
362 return "(84)FindClose";
364 return "(A0)ReceiveNTTransact";
366 return "(A2)ReceiveNTCreateX";
368 return "(A4)ReceiveNTCancel";
370 return "(A5)ReceiveNTRename";
372 return "(C0)OpenPrintFile";
374 return "(C1)WritePrintFile";
376 return "(C2)ClosePrintFile";
378 return "(C3)GetPrintQueue";
380 return "(D8)ReadBulk";
382 return "(D9)WriteBulk";
384 return "(DA)WriteBulkData";
386 return "unknown SMB op";
390 char * myCrt_2Dispatch(int i)
395 return "unknown SMB op-2";
397 return "S(00)CreateFile_ReceiveTran2Open";
399 return "S(01)FindFirst_ReceiveTran2SearchDir";
401 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
403 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
405 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
407 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
409 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
411 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
413 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
415 return "S(09)_ReceiveTran2FSCTL";
417 return "S(0a)_ReceiveTran2IOCTL";
419 return "S(0b)_ReceiveTran2FindNotifyFirst";
421 return "S(0c)_ReceiveTran2FindNotifyNext";
423 return "S(0d)_ReceiveTran2CreateDirectory";
425 return "S(0e)_ReceiveTran2SessionSetup";
427 return "S(0f)_QueryFileSystemInformationFid";
429 return "S(10)_ReceiveTran2GetDfsReferral";
431 return "S(11)_ReceiveTran2ReportDfsInconsistency";
435 char * myCrt_RapDispatch(int i)
440 return "unknown RAP OP";
442 return "RAP(0)NetShareEnum";
444 return "RAP(1)NetShareGetInfo";
446 return "RAP(13)NetServerGetInfo";
448 return "RAP(63)NetWkStaGetInfo";
452 /* scache must be locked */
453 unsigned int smb_Attributes(cm_scache_t *scp)
457 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
458 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
459 scp->fileType == CM_SCACHETYPE_INVALID)
461 attrs = SMB_ATTR_DIRECTORY;
462 #ifdef SPECIAL_FOLDERS
463 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
464 #endif /* SPECIAL_FOLDERS */
465 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
466 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
471 * We used to mark a file RO if it was in an RO volume, but that
472 * turns out to be impolitic in NT. See defect 10007.
475 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
476 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
478 if ((scp->unixModeBits & 0222) == 0)
479 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
485 /* Check if the named file/dir is a dotfile/dotdir */
486 /* String pointed to by lastComp can have leading slashes, but otherwise should have
487 no other patch components */
488 unsigned int smb_IsDotFile(char *lastComp) {
491 /* skip over slashes */
492 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
497 /* nulls, curdir and parent dir doesn't count */
503 if(*(s+1) == '.' && !*(s + 2))
510 static int ExtractBits(WORD bits, short start, short len)
517 num = bits << (16 - end);
518 num = num >> ((16 - end) + start);
523 void ShowUnixTime(char *FuncName, time_t unixTime)
528 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
530 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
531 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
533 int day, month, year, sec, min, hour;
536 day = ExtractBits(wDate, 0, 5);
537 month = ExtractBits(wDate, 5, 4);
538 year = ExtractBits(wDate, 9, 7) + 1980;
540 sec = ExtractBits(wTime, 0, 5);
541 min = ExtractBits(wTime, 5, 6);
542 hour = ExtractBits(wTime, 11, 5);
544 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
545 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
549 /* Determine if we are observing daylight savings time */
550 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
552 TIME_ZONE_INFORMATION timeZoneInformation;
553 SYSTEMTIME utc, local, localDST;
555 /* Get the time zone info. NT uses this to calc if we are in DST. */
556 GetTimeZoneInformation(&timeZoneInformation);
558 /* Return the daylight bias */
559 *pDstBias = timeZoneInformation.DaylightBias;
561 /* Return the bias */
562 *pBias = timeZoneInformation.Bias;
564 /* Now determine if DST is being observed */
566 /* Get the UTC (GMT) time */
569 /* Convert UTC time to local time using the time zone info. If we are
570 observing DST, the calculated local time will include this.
572 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
574 /* Set the daylight bias to 0. The daylight bias is the amount of change
575 * in time that we use for daylight savings time. By setting this to 0
576 * we cause there to be no change in time during daylight savings time.
578 timeZoneInformation.DaylightBias = 0;
580 /* Convert the utc time to local time again, but this time without any
581 adjustment for daylight savings time.
583 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
585 /* If the two times are different, then it means that the localDST that
586 we calculated includes the daylight bias, and therefore we are
587 observing daylight savings time.
589 *pDST = localDST.wHour != local.wHour;
593 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
595 BOOL dst; /* Will be TRUE if observing DST */
596 LONG dstBias; /* Offset from local time if observing DST */
597 LONG bias; /* Offset from GMT for local time */
600 * This function will adjust the last write time to compensate
601 * for two bugs in the smb client:
603 * 1) During Daylight Savings Time, the LastWriteTime is ahead
604 * in time by the DaylightBias (ignoring the sign - the
605 * DaylightBias is always stored as a negative number). If
606 * the DaylightBias is -60, then the LastWriteTime will be
607 * ahead by 60 minutes.
609 * 2) If the local time zone is a positive offset from GMT, then
610 * the LastWriteTime will be the correct local time plus the
611 * Bias (ignoring the sign - a positive offset from GMT is
612 * always stored as a negative Bias). If the Bias is -120,
613 * then the LastWriteTime will be ahead by 120 minutes.
615 * These bugs can occur at the same time.
618 GetTimeZoneInfo(&dst, &dstBias, &bias);
620 /* First adjust for DST */
622 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
624 /* Now adjust for a positive offset from GMT (a negative bias). */
626 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
629 #ifndef USE_NUMERIC_TIME_CONV
631 * Calculate the difference (in seconds) between local time and GMT.
632 * This enables us to convert file times to kludge-GMT.
638 struct tm gmt_tm, local_tm;
639 int days, hours, minutes, seconds;
642 gmt_tm = *(gmtime(&t));
643 local_tm = *(localtime(&t));
645 days = local_tm.tm_yday - gmt_tm.tm_yday;
646 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
647 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
648 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
652 #endif /* USE_NUMERIC_TIME_CONV */
654 #ifdef USE_NUMERIC_TIME_CONV
655 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
657 // Note that LONGLONG is a 64-bit value
660 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
661 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
662 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
665 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
670 time_t ersatz_unixTime;
673 * Must use kludge-GMT instead of real GMT.
674 * kludge-GMT is computed by adding time zone difference to localtime.
677 * ltp = gmtime(&unixTime);
679 ersatz_unixTime = unixTime - smb_NowTZ;
680 ltp = localtime(&ersatz_unixTime);
682 /* if we fail, make up something */
685 localJunk.tm_year = 89 - 20;
686 localJunk.tm_mon = 4;
687 localJunk.tm_mday = 12;
688 localJunk.tm_hour = 0;
689 localJunk.tm_min = 0;
690 localJunk.tm_sec = 0;
693 stm.wYear = ltp->tm_year + 1900;
694 stm.wMonth = ltp->tm_mon + 1;
695 stm.wDayOfWeek = ltp->tm_wday;
696 stm.wDay = ltp->tm_mday;
697 stm.wHour = ltp->tm_hour;
698 stm.wMinute = ltp->tm_min;
699 stm.wSecond = ltp->tm_sec;
700 stm.wMilliseconds = 0;
702 SystemTimeToFileTime(&stm, largeTimep);
704 #endif /* USE_NUMERIC_TIME_CONV */
706 #ifdef USE_NUMERIC_TIME_CONV
707 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
709 // Note that LONGLONG is a 64-bit value
712 ll = largeTimep->dwHighDateTime;
714 ll += largeTimep->dwLowDateTime;
716 ll -= 116444736000000000;
719 *unixTimep = (DWORD)ll;
721 #else /* USE_NUMERIC_TIME_CONV */
722 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
728 FileTimeToSystemTime(largeTimep, &stm);
730 lt.tm_year = stm.wYear - 1900;
731 lt.tm_mon = stm.wMonth - 1;
732 lt.tm_wday = stm.wDayOfWeek;
733 lt.tm_mday = stm.wDay;
734 lt.tm_hour = stm.wHour;
735 lt.tm_min = stm.wMinute;
736 lt.tm_sec = stm.wSecond;
739 save_timezone = _timezone;
740 _timezone += smb_NowTZ;
741 *unixTimep = mktime(<);
742 _timezone = save_timezone;
744 #endif /* USE_NUMERIC_TIME_CONV */
746 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
756 /* if we fail, make up something */
759 localJunk.tm_year = 89 - 20;
760 localJunk.tm_mon = 4;
761 localJunk.tm_mday = 12;
762 localJunk.tm_hour = 0;
763 localJunk.tm_min = 0;
764 localJunk.tm_sec = 0;
767 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
768 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
769 *searchTimep = (dosDate<<16) | dosTime;
772 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
774 unsigned short dosDate;
775 unsigned short dosTime;
778 dosDate = (unsigned short) (searchTime & 0xffff);
779 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
781 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
782 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
783 localTm.tm_mday = (dosDate) & 0x1f;
784 localTm.tm_hour = (dosTime>>11) & 0x1f;
785 localTm.tm_min = (dosTime >> 5) & 0x3f;
786 localTm.tm_sec = (dosTime & 0x1f) * 2;
787 localTm.tm_isdst = -1; /* compute whether DST in effect */
789 *unixTimep = mktime(&localTm);
792 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
794 time_t diff_t = unixTime - smb_localZero;
795 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
796 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
798 *dosUTimep = (afs_uint32)diff_t;
801 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
803 *unixTimep = dosTime + smb_localZero;
806 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
810 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
811 lock_ObtainWrite(&smb_rctLock);
812 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
813 if (vcp->magic != SMB_VC_MAGIC)
814 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
817 if (lsn == vcp->lsn && lana == vcp->lana &&
818 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
819 smb_HoldVCNoLock(vcp);
823 if (!vcp && (flags & SMB_FLAG_CREATE)) {
824 vcp = malloc(sizeof(*vcp));
825 memset(vcp, 0, sizeof(*vcp));
826 vcp->vcID = ++numVCs;
827 vcp->magic = SMB_VC_MAGIC;
828 vcp->refCount = 2; /* smb_allVCsp and caller */
831 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
832 vcp->nextp = smb_allVCsp;
834 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
839 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
840 /* We must obtain a challenge for extended auth
841 * in case the client negotiates smb v3
843 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
844 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
845 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
846 ULONG lsaRespSize = 0;
848 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
850 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
857 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
858 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
859 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
860 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
861 nts, ntsEx, lsaRespSize);
863 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
865 if (ntsEx == STATUS_SUCCESS) {
866 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
867 LsaFreeReturnBuffer(lsaResp);
870 * This will cause the subsequent authentication to fail but
871 * that is better than us dereferencing a NULL pointer and
874 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
878 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
880 if (numVCs >= CM_SESSION_RESERVED) {
882 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
885 lock_ReleaseWrite(&smb_rctLock);
886 lock_ReleaseWrite(&smb_globalLock);
890 int smb_IsStarMask(char *maskp)
895 for(i=0; i<11; i++) {
897 if (tc == '?' || tc == '*' || tc == '>')
903 void smb_ReleaseVCInternal(smb_vc_t *vcp)
910 if (vcp->refCount == 0) {
911 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
912 /* remove VCP from smb_deadVCsp */
913 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
919 lock_FinalizeMutex(&vcp->mx);
920 memset(vcp,0,sizeof(smb_vc_t));
923 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
927 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
928 avcp?"not ":"",vcp, vcp->refCount);
930 GenerateMiniDump(NULL);
932 /* This is a wrong. However, I suspect that there is an undercount
933 * and I don't want to release 1.4.1 in a state that will allow
934 * smb_vc_t objects to be deallocated while still in the
935 * smb_allVCsp list. The list is supposed to keep a reference
936 * to the smb_vc_t. Put it back.
943 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
945 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
946 smb_ReleaseVCInternal(vcp);
949 void smb_ReleaseVC(smb_vc_t *vcp)
951 lock_ObtainWrite(&smb_rctLock);
952 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
953 smb_ReleaseVCInternal(vcp);
954 lock_ReleaseWrite(&smb_rctLock);
957 void smb_HoldVCNoLock(smb_vc_t *vcp)
960 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
963 void smb_HoldVC(smb_vc_t *vcp)
965 lock_ObtainWrite(&smb_rctLock);
967 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
968 lock_ReleaseWrite(&smb_rctLock);
971 void smb_CleanupDeadVC(smb_vc_t *vcp)
979 smb_user_t *uidpIter;
980 smb_user_t *uidpNext;
984 lock_ObtainMutex(&vcp->mx);
985 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
986 lock_ReleaseMutex(&vcp->mx);
987 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
990 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
991 lock_ReleaseMutex(&vcp->mx);
992 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
994 lock_ObtainWrite(&smb_rctLock);
995 /* remove VCP from smb_allVCsp */
996 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
997 if ((*vcpp)->magic != SMB_VC_MAGIC)
998 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1002 vcp->nextp = smb_deadVCsp;
1004 /* Hold onto the reference until we are done with this function */
1009 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1010 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1012 if (fidpIter->delete)
1015 fid = fidpIter->fid;
1016 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1018 smb_HoldFIDNoLock(fidpIter);
1019 lock_ReleaseWrite(&smb_rctLock);
1021 smb_CloseFID(vcp, fidpIter, NULL, 0);
1022 smb_ReleaseFID(fidpIter);
1024 lock_ObtainWrite(&smb_rctLock);
1025 fidpNext = vcp->fidsp;
1028 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1029 tidpNext = tidpIter->nextp;
1030 if (tidpIter->delete)
1032 tidpIter->delete = 1;
1034 tid = tidpIter->tid;
1035 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1037 smb_HoldTIDNoLock(tidpIter);
1038 lock_ReleaseWrite(&smb_rctLock);
1040 smb_ReleaseTID(tidpIter);
1042 lock_ObtainWrite(&smb_rctLock);
1043 tidpNext = vcp->tidsp;
1046 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1047 uidpNext = uidpIter->nextp;
1048 if (uidpIter->delete)
1050 uidpIter->delete = 1;
1052 /* do not add an additional reference count for the smb_user_t
1053 * as the smb_vc_t already is holding a reference */
1054 lock_ReleaseWrite(&smb_rctLock);
1056 smb_ReleaseUID(uidpIter);
1058 lock_ObtainWrite(&smb_rctLock);
1059 uidpNext = vcp->usersp;
1062 /* The vcp is now on the deadVCsp list. We intentionally drop the
1063 * reference so that the refcount can reach 0 and we can delete it */
1064 smb_ReleaseVCNoLock(vcp);
1066 lock_ReleaseWrite(&smb_rctLock);
1067 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1070 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1074 lock_ObtainWrite(&smb_rctLock);
1076 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1077 if (tidp->refCount == 0 && tidp->delete) {
1079 lock_ReleaseWrite(&smb_rctLock);
1080 smb_ReleaseTID(tidp);
1081 lock_ObtainWrite(&smb_rctLock);
1085 if (tid == tidp->tid) {
1090 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1091 tidp = malloc(sizeof(*tidp));
1092 memset(tidp, 0, sizeof(*tidp));
1093 tidp->nextp = vcp->tidsp;
1096 smb_HoldVCNoLock(vcp);
1098 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1101 lock_ReleaseWrite(&smb_rctLock);
1105 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1110 void smb_ReleaseTID(smb_tid_t *tidp)
1117 lock_ObtainWrite(&smb_rctLock);
1118 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1119 if (tidp->refCount == 0 && (tidp->delete)) {
1120 ltpp = &tidp->vcp->tidsp;
1121 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1125 osi_assertx(tp != NULL, "null smb_tid_t");
1127 lock_FinalizeMutex(&tidp->mx);
1128 userp = tidp->userp; /* remember to drop ref later */
1130 smb_ReleaseVCNoLock(tidp->vcp);
1133 lock_ReleaseWrite(&smb_rctLock);
1135 cm_ReleaseUser(userp);
1138 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1140 smb_user_t *uidp = NULL;
1142 lock_ObtainWrite(&smb_rctLock);
1143 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1144 if (uid == uidp->userID) {
1146 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1148 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1152 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1153 uidp = malloc(sizeof(*uidp));
1154 memset(uidp, 0, sizeof(*uidp));
1155 uidp->nextp = vcp->usersp;
1156 uidp->refCount = 2; /* one for the vcp and one for the caller */
1158 smb_HoldVCNoLock(vcp);
1160 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1162 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1164 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1166 lock_ReleaseWrite(&smb_rctLock);
1170 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1172 smb_username_t *unp= NULL;
1174 lock_ObtainWrite(&smb_rctLock);
1175 for(unp = usernamesp; unp; unp = unp->nextp) {
1176 if (stricmp(unp->name, usern) == 0 &&
1177 stricmp(unp->machine, machine) == 0) {
1182 if (!unp && (flags & SMB_FLAG_CREATE)) {
1183 unp = malloc(sizeof(*unp));
1184 memset(unp, 0, sizeof(*unp));
1186 unp->nextp = usernamesp;
1187 unp->name = strdup(usern);
1188 unp->machine = strdup(machine);
1190 lock_InitializeMutex(&unp->mx, "username_t mutex");
1191 if (flags & SMB_FLAG_AFSLOGON)
1192 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1195 lock_ReleaseWrite(&smb_rctLock);
1199 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1201 smb_user_t *uidp= NULL;
1203 lock_ObtainWrite(&smb_rctLock);
1204 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1207 if (stricmp(uidp->unp->name, usern) == 0) {
1209 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1210 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1215 lock_ReleaseWrite(&smb_rctLock);
1219 void smb_ReleaseUsername(smb_username_t *unp)
1222 smb_username_t **lupp;
1223 cm_user_t *userp = NULL;
1224 time_t now = osi_Time();
1226 lock_ObtainWrite(&smb_rctLock);
1227 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1228 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1229 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1231 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1235 osi_assertx(up != NULL, "null smb_username_t");
1237 up->nextp = NULL; /* do not remove this */
1238 lock_FinalizeMutex(&unp->mx);
1244 lock_ReleaseWrite(&smb_rctLock);
1247 cm_ReleaseUser(userp);
1251 void smb_HoldUIDNoLock(smb_user_t *uidp)
1256 void smb_ReleaseUID(smb_user_t *uidp)
1260 smb_username_t *unp = NULL;
1262 lock_ObtainWrite(&smb_rctLock);
1263 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1264 if (uidp->refCount == 0) {
1265 lupp = &uidp->vcp->usersp;
1266 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1270 osi_assertx(up != NULL, "null smb_user_t");
1272 lock_FinalizeMutex(&uidp->mx);
1274 smb_ReleaseVCNoLock(uidp->vcp);
1278 lock_ReleaseWrite(&smb_rctLock);
1282 cm_ReleaseUserVCRef(unp->userp);
1283 smb_ReleaseUsername(unp);
1287 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1289 cm_user_t *up = NULL;
1294 lock_ObtainMutex(&uidp->mx);
1296 up = uidp->unp->userp;
1299 lock_ReleaseMutex(&uidp->mx);
1305 /* retrieve a held reference to a user structure corresponding to an incoming
1307 * corresponding release function is cm_ReleaseUser.
1309 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1312 cm_user_t *up = NULL;
1315 smbp = (smb_t *) inp;
1316 uidp = smb_FindUID(vcp, smbp->uid, 0);
1320 up = smb_GetUserFromUID(uidp);
1322 smb_ReleaseUID(uidp);
1327 * Return a pointer to a pathname extracted from a TID structure. The
1328 * TID structure is not held; assume it won't go away.
1330 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1335 tidp = smb_FindTID(vcp, tid, 0);
1339 if (tidp->flags & SMB_TIDFLAG_IPC) {
1340 code = CM_ERROR_TIDIPC;
1341 /* tidp->pathname would be NULL, but that's fine */
1343 *treepath = tidp->pathname;
1344 smb_ReleaseTID(tidp);
1349 /* check to see if we have a chained fid, that is, a fid that comes from an
1350 * OpenAndX message that ran earlier in this packet. In this case, the fid
1351 * field in a read, for example, request, isn't set, since the value is
1352 * supposed to be inherited from the openAndX call.
1354 int smb_ChainFID(int fid, smb_packet_t *inp)
1356 if (inp->fid == 0 || inp->inCount == 0)
1362 /* are we a priv'd user? What does this mean on NT? */
1363 int smb_SUser(cm_user_t *userp)
1368 /* find a file ID. If we pass in 0 we select an unused File ID.
1369 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1370 * smb_fid_t data structure if desired File ID cannot be found.
1372 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1377 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1380 lock_ObtainWrite(&smb_rctLock);
1381 /* figure out if we need to allocate a new file ID */
1384 fid = vcp->fidCounter;
1388 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1389 if (fidp->refCount == 0 && fidp->delete) {
1391 lock_ReleaseWrite(&smb_rctLock);
1392 smb_ReleaseFID(fidp);
1393 lock_ObtainWrite(&smb_rctLock);
1396 if (fid == fidp->fid) {
1399 if (fid == 0xFFFF) {
1401 "New FID number wraps on vcp 0x%x", vcp);
1411 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1412 char eventName[MAX_PATH];
1414 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1415 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1416 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1417 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1418 thrd_CloseHandle(event);
1420 if (fid == 0xFFFF) {
1421 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1427 fidp = malloc(sizeof(*fidp));
1428 memset(fidp, 0, sizeof(*fidp));
1429 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1432 smb_HoldVCNoLock(vcp);
1433 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1435 fidp->curr_chunk = fidp->prev_chunk = -2;
1436 fidp->raw_write_event = event;
1438 vcp->fidCounter = fid+1;
1439 if (vcp->fidCounter == 0xFFFF) {
1440 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1442 vcp->fidCounter = 1;
1447 lock_ReleaseWrite(&smb_rctLock);
1451 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1453 smb_fid_t *fidp = NULL;
1459 lock_ObtainWrite(&smb_rctLock);
1460 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1461 if (scp == fidp->scp) {
1466 lock_ReleaseWrite(&smb_rctLock);
1470 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1476 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1477 /* the sm_fid_t->mx and smb_rctLock must not be held */
1478 void smb_ReleaseFID(smb_fid_t *fidp)
1480 cm_scache_t *scp = NULL;
1481 cm_user_t *userp = NULL;
1482 smb_vc_t *vcp = NULL;
1483 smb_ioctl_t *ioctlp;
1485 lock_ObtainMutex(&fidp->mx);
1486 lock_ObtainWrite(&smb_rctLock);
1487 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1488 if (fidp->refCount == 0 && (fidp->delete)) {
1491 scp = fidp->scp; /* release after lock is released */
1493 lock_ObtainMutex(&scp->mx);
1494 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1495 lock_ReleaseMutex(&scp->mx);
1496 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1499 userp = fidp->userp;
1503 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1504 thrd_CloseHandle(fidp->raw_write_event);
1506 /* and see if there is ioctl stuff to free */
1507 ioctlp = fidp->ioctlp;
1510 cm_FreeSpace(ioctlp->prefix);
1511 if (ioctlp->inAllocp)
1512 free(ioctlp->inAllocp);
1513 if (ioctlp->outAllocp)
1514 free(ioctlp->outAllocp);
1517 lock_ReleaseMutex(&fidp->mx);
1518 lock_FinalizeMutex(&fidp->mx);
1522 smb_ReleaseVCNoLock(vcp);
1524 lock_ReleaseMutex(&fidp->mx);
1526 lock_ReleaseWrite(&smb_rctLock);
1528 /* now release the scache structure */
1530 cm_ReleaseSCache(scp);
1533 cm_ReleaseUser(userp);
1537 * Case-insensitive search for one string in another;
1538 * used to find variable names in submount pathnames.
1540 static char *smb_stristr(char *str1, char *str2)
1544 for (cursor = str1; *cursor; cursor++)
1545 if (stricmp(cursor, str2) == 0)
1552 * Substitute a variable value for its name in a submount pathname. Variable
1553 * name has been identified by smb_stristr() and is in substr. Variable name
1554 * length (plus one) is in substr_size. Variable value is in newstr.
1556 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1561 strcpy(temp, substr + substr_size - 1);
1562 strcpy(substr, newstr);
1566 char VNUserName[] = "%USERNAME%";
1567 char VNLCUserName[] = "%LCUSERNAME%";
1568 char VNComputerName[] = "%COMPUTERNAME%";
1569 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1572 typedef struct smb_findShare_rock {
1576 } smb_findShare_rock_t;
1578 #define SMB_FINDSHARE_EXACT_MATCH 1
1579 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1581 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1585 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1586 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1587 if(!stricmp(dep->name, vrock->shareName))
1588 matchType = SMB_FINDSHARE_EXACT_MATCH;
1590 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1591 if(vrock->match) free(vrock->match);
1592 vrock->match = strdup(dep->name);
1593 vrock->matchType = matchType;
1595 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1596 return CM_ERROR_STOPNOW;
1602 /* find a shareName in the table of submounts */
1603 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1607 char pathName[1024];
1614 DWORD allSubmount = 1;
1616 /* if allSubmounts == 0, only return the //mountRoot/all share
1617 * if in fact it has been been created in the subMounts table.
1618 * This is to allow sites that want to restrict access to the
1621 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1622 0, KEY_QUERY_VALUE, &parmKey);
1623 if (code == ERROR_SUCCESS) {
1624 len = sizeof(allSubmount);
1625 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1626 (BYTE *) &allSubmount, &len);
1627 if (code != ERROR_SUCCESS) {
1630 RegCloseKey (parmKey);
1633 if (allSubmount && _stricmp(shareName, "all") == 0) {
1638 /* In case, the all share is disabled we need to still be able
1639 * to handle ioctl requests
1641 if (_stricmp(shareName, "ioctl$") == 0) {
1642 *pathNamep = strdup("/.__ioctl__");
1646 if (_stricmp(shareName, "IPC$") == 0 ||
1647 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1648 _stricmp(shareName, "DESKTOP.INI") == 0
1654 /* Check for volume references
1656 * They look like <cell>{%,#}<volume>
1658 if (strchr(shareName, '%') != NULL ||
1659 strchr(shareName, '#') != NULL) {
1660 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1661 /* make room for '/@vol:' + mountchar + NULL terminator*/
1663 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1664 osi_LogSaveString(smb_logp, shareName));
1666 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1667 "/" CM_PREFIX_VOL "%s", shareName);
1668 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1669 len = strlen(pathstr) + 1;
1671 *pathNamep = malloc(len);
1673 strcpy(*pathNamep, pathstr);
1675 osi_Log1(smb_logp, " returning pathname [%s]",
1676 osi_LogSaveString(smb_logp, *pathNamep));
1684 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1685 0, KEY_QUERY_VALUE, &parmKey);
1686 if (code == ERROR_SUCCESS) {
1687 len = sizeof(pathName);
1688 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1689 (BYTE *) pathName, &len);
1690 if (code != ERROR_SUCCESS)
1692 RegCloseKey (parmKey);
1696 if (len != 0 && len != sizeof(pathName) - 1) {
1697 /* We can accept either unix or PC style AFS pathnames. Convert
1698 * Unix-style to PC style here for internal use.
1701 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1702 p += strlen(cm_mountRoot); /* skip mount path */
1705 if (*q == '/') *q = '\\'; /* change to \ */
1711 if (var = smb_stristr(p, VNUserName)) {
1712 if (uidp && uidp->unp)
1713 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1715 smb_subst(p, var, sizeof(VNUserName)," ");
1717 else if (var = smb_stristr(p, VNLCUserName))
1719 if (uidp && uidp->unp)
1720 strcpy(temp, uidp->unp->name);
1724 smb_subst(p, var, sizeof(VNLCUserName), temp);
1726 else if (var = smb_stristr(p, VNComputerName))
1728 sizeTemp = sizeof(temp);
1729 GetComputerName((LPTSTR)temp, &sizeTemp);
1730 smb_subst(p, var, sizeof(VNComputerName), temp);
1732 else if (var = smb_stristr(p, VNLCComputerName))
1734 sizeTemp = sizeof(temp);
1735 GetComputerName((LPTSTR)temp, &sizeTemp);
1737 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1742 *pathNamep = strdup(p);
1747 /* First lookup shareName in root.afs */
1749 smb_findShare_rock_t vrock;
1751 char * p = shareName;
1754 /* attempt to locate a partial match in root.afs. This is because
1755 when using the ANSI RAP calls, the share name is limited to 13 chars
1756 and hence is truncated. Of course we prefer exact matches. */
1758 thyper.HighPart = 0;
1761 vrock.shareName = shareName;
1763 vrock.matchType = 0;
1765 cm_HoldSCache(cm_data.rootSCachep);
1766 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1767 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1768 cm_ReleaseSCache(cm_data.rootSCachep);
1770 if (vrock.matchType) {
1771 sprintf(pathName,"/%s/",vrock.match);
1772 *pathNamep = strdup(strlwr(pathName));
1777 /* if we get here, there was no match for the share in root.afs */
1778 /* so try to create \\<netbiosName>\<cellname> */
1783 /* Get the full name for this cell */
1784 code = cm_SearchCellFile(p, temp, 0, 0);
1785 #ifdef AFS_AFSDB_ENV
1786 if (code && cm_dnsEnabled) {
1788 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1791 /* construct the path */
1793 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1794 *pathNamep = strdup(strlwr(pathName));
1803 /* Client-side offline caching policy types */
1804 #define CSC_POLICY_MANUAL 0
1805 #define CSC_POLICY_DOCUMENTS 1
1806 #define CSC_POLICY_PROGRAMS 2
1807 #define CSC_POLICY_DISABLE 3
1809 int smb_FindShareCSCPolicy(char *shareName)
1815 int retval = CSC_POLICY_MANUAL;
1817 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1818 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1821 REG_OPTION_NON_VOLATILE,
1827 len = sizeof(policy);
1828 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1830 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1832 else if (stricmp(policy, "documents") == 0)
1834 retval = CSC_POLICY_DOCUMENTS;
1836 else if (stricmp(policy, "programs") == 0)
1838 retval = CSC_POLICY_PROGRAMS;
1840 else if (stricmp(policy, "disable") == 0)
1842 retval = CSC_POLICY_DISABLE;
1845 RegCloseKey(hkCSCPolicy);
1849 /* find a dir search structure by cookie value, and return it held.
1850 * Must be called with smb_globalLock held.
1852 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1854 smb_dirSearch_t *dsp;
1856 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1857 if (dsp->cookie == cookie) {
1858 if (dsp != smb_firstDirSearchp) {
1859 /* move to head of LRU queue, too, if we're not already there */
1860 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1861 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1862 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1863 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1864 if (!smb_lastDirSearchp)
1865 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1867 lock_ObtainMutex(&dsp->mx);
1869 lock_ReleaseMutex(&dsp->mx);
1875 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1876 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1877 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1883 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1885 lock_ObtainWrite(&smb_globalLock);
1886 lock_ObtainMutex(&dsp->mx);
1887 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1888 dsp->cookie, dsp, dsp->scp);
1889 dsp->flags |= SMB_DIRSEARCH_DELETE;
1890 if (dsp->scp != NULL) {
1891 lock_ObtainMutex(&dsp->scp->mx);
1892 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1893 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1894 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1895 dsp->scp->bulkStatProgress = hzero;
1897 lock_ReleaseMutex(&dsp->scp->mx);
1899 lock_ReleaseMutex(&dsp->mx);
1900 lock_ReleaseWrite(&smb_globalLock);
1903 /* Must be called with the smb_globalLock held */
1904 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1906 cm_scache_t *scp = NULL;
1908 lock_ObtainMutex(&dsp->mx);
1909 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1910 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1911 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1912 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1913 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1914 lock_ReleaseMutex(&dsp->mx);
1915 lock_FinalizeMutex(&dsp->mx);
1917 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1918 dsp->cookie, dsp, scp);
1921 lock_ReleaseMutex(&dsp->mx);
1923 /* do this now to avoid spurious locking hierarchy creation */
1925 cm_ReleaseSCache(scp);
1928 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1930 lock_ObtainWrite(&smb_globalLock);
1931 smb_ReleaseDirSearchNoLock(dsp);
1932 lock_ReleaseWrite(&smb_globalLock);
1935 /* find a dir search structure by cookie value, and return it held */
1936 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1938 smb_dirSearch_t *dsp;
1940 lock_ObtainWrite(&smb_globalLock);
1941 dsp = smb_FindDirSearchNoLock(cookie);
1942 lock_ReleaseWrite(&smb_globalLock);
1946 /* GC some dir search entries, in the address space expected by the specific protocol.
1947 * Must be called with smb_globalLock held; release the lock temporarily.
1949 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1950 void smb_GCDirSearches(int isV3)
1952 smb_dirSearch_t *prevp;
1953 smb_dirSearch_t *tp;
1954 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1958 victimCount = 0; /* how many have we got so far */
1959 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1960 /* we'll move tp from queue, so
1963 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1964 /* if no one is using this guy, and we're either in the new protocol,
1965 * or we're in the old one and this is a small enough ID to be useful
1966 * to the old protocol, GC this guy.
1968 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1969 /* hold and delete */
1970 lock_ObtainMutex(&tp->mx);
1971 tp->flags |= SMB_DIRSEARCH_DELETE;
1972 lock_ReleaseMutex(&tp->mx);
1973 victimsp[victimCount++] = tp;
1977 /* don't do more than this */
1978 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1982 /* now release them */
1983 for (i = 0; i < victimCount; i++) {
1984 smb_ReleaseDirSearchNoLock(victimsp[i]);
1988 /* function for allocating a dir search entry. We need these to remember enough context
1989 * since we don't get passed the path from call to call during a directory search.
1991 * Returns a held dir search structure, and bumps the reference count on the vnode,
1992 * since it saves a pointer to the vnode.
1994 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1996 smb_dirSearch_t *dsp;
2002 lock_ObtainWrite(&smb_globalLock);
2005 /* what's the biggest ID allowed in this version of the protocol */
2006 /* TODO: do we really want a non v3 dir search request to wrap
2007 smb_dirSearchCounter? */
2008 maxAllowed = isV3 ? 65535 : 255;
2009 if (smb_dirSearchCounter > maxAllowed)
2010 smb_dirSearchCounter = 1;
2012 start = smb_dirSearchCounter;
2015 /* twice so we have enough tries to find guys we GC after one pass;
2016 * 10 extra is just in case I mis-counted.
2018 if (++counter > 2*maxAllowed+10)
2019 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2021 if (smb_dirSearchCounter > maxAllowed) {
2022 smb_dirSearchCounter = 1;
2024 if (smb_dirSearchCounter == start) {
2026 smb_GCDirSearches(isV3);
2029 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2031 /* don't need to watch for refcount zero and deleted, since
2032 * we haven't dropped the global lock.
2034 lock_ObtainMutex(&dsp->mx);
2036 lock_ReleaseMutex(&dsp->mx);
2037 ++smb_dirSearchCounter;
2041 dsp = malloc(sizeof(*dsp));
2042 memset(dsp, 0, sizeof(*dsp));
2043 dsp->cookie = smb_dirSearchCounter;
2044 ++smb_dirSearchCounter;
2046 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2047 dsp->lastTime = osi_Time();
2048 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2049 if (!smb_lastDirSearchp)
2050 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2052 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2056 lock_ReleaseWrite(&smb_globalLock);
2060 static smb_packet_t *GetPacket(void)
2064 lock_ObtainWrite(&smb_globalLock);
2065 tbp = smb_packetFreeListp;
2067 smb_packetFreeListp = tbp->nextp;
2068 lock_ReleaseWrite(&smb_globalLock);
2070 tbp = calloc(65540,1);
2071 tbp->magic = SMB_PACKETMAGIC;
2074 tbp->resumeCode = 0;
2080 tbp->ncb_length = 0;
2085 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2090 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2094 memcpy(tbp, pkt, sizeof(smb_packet_t));
2095 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2097 smb_HoldVC(tbp->vcp);
2101 static NCB *GetNCB(void)
2106 lock_ObtainWrite(&smb_globalLock);
2107 tbp = smb_ncbFreeListp;
2109 smb_ncbFreeListp = tbp->nextp;
2110 lock_ReleaseWrite(&smb_globalLock);
2112 tbp = calloc(sizeof(*tbp),1);
2113 tbp->magic = SMB_NCBMAGIC;
2116 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2118 memset(&tbp->ncb, 0, sizeof(NCB));
2123 void smb_FreePacket(smb_packet_t *tbp)
2125 smb_vc_t * vcp = NULL;
2126 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2128 lock_ObtainWrite(&smb_globalLock);
2129 tbp->nextp = smb_packetFreeListp;
2130 smb_packetFreeListp = tbp;
2131 tbp->magic = SMB_PACKETMAGIC;
2135 tbp->resumeCode = 0;
2141 tbp->ncb_length = 0;
2143 lock_ReleaseWrite(&smb_globalLock);
2149 static void FreeNCB(NCB *bufferp)
2153 tbp = (smb_ncb_t *) bufferp;
2154 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2156 lock_ObtainWrite(&smb_globalLock);
2157 tbp->nextp = smb_ncbFreeListp;
2158 smb_ncbFreeListp = tbp;
2159 lock_ReleaseWrite(&smb_globalLock);
2162 /* get a ptr to the data part of a packet, and its count */
2163 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2167 unsigned char *afterParmsp;
2169 parmBytes = *smbp->wctp << 1;
2170 afterParmsp = smbp->wctp + parmBytes + 1;
2172 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2173 if (nbytesp) *nbytesp = dataBytes;
2175 /* don't forget to skip the data byte count, since it follows
2176 * the parameters; that's where the "2" comes from below.
2178 return (unsigned char *) (afterParmsp + 2);
2181 /* must set all the returned parameters before playing around with the
2182 * data region, since the data region is located past the end of the
2183 * variable number of parameters.
2185 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2187 unsigned char *afterParmsp;
2189 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2191 *afterParmsp++ = dsize & 0xff;
2192 *afterParmsp = (dsize>>8) & 0xff;
2195 /* return the parm'th parameter in the smbp packet */
2196 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2199 unsigned char *parmDatap;
2201 parmCount = *smbp->wctp;
2203 if (parm >= parmCount) {
2206 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2207 parm, parmCount, smbp->ncb_length);
2208 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2209 parm, parmCount, smbp->ncb_length);
2210 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2211 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2212 osi_panic(s, __FILE__, __LINE__);
2214 parmDatap = smbp->wctp + (2*parm) + 1;
2216 return parmDatap[0] + (parmDatap[1] << 8);
2219 /* return the parm'th parameter in the smbp packet */
2220 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2223 unsigned char *parmDatap;
2225 parmCount = *smbp->wctp;
2227 if (parm >= parmCount) {
2230 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2231 parm, parmCount, smbp->ncb_length);
2232 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2233 parm, parmCount, smbp->ncb_length);
2234 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2235 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2236 osi_panic(s, __FILE__, __LINE__);
2238 parmDatap = smbp->wctp + (2*parm) + 1;
2240 return parmDatap[0];
2243 /* return the parm'th parameter in the smbp packet */
2244 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2247 unsigned char *parmDatap;
2249 parmCount = *smbp->wctp;
2251 if (parm + 1 >= parmCount) {
2254 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2255 parm, parmCount, smbp->ncb_length);
2256 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2257 parm, parmCount, smbp->ncb_length);
2258 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2259 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2260 osi_panic(s, __FILE__, __LINE__);
2262 parmDatap = smbp->wctp + (2*parm) + 1;
2264 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2267 /* return the parm'th parameter in the smbp packet */
2268 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2271 unsigned char *parmDatap;
2273 parmCount = *smbp->wctp;
2275 if (parm * 2 + offset >= parmCount * 2) {
2278 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2279 parm, offset, parmCount, smbp->ncb_length);
2280 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2281 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2282 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2283 parm, offset, parmCount, smbp->ncb_length);
2284 osi_panic(s, __FILE__, __LINE__);
2286 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2288 return parmDatap[0] + (parmDatap[1] << 8);
2291 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2295 /* make sure we have enough slots */
2296 if (*smbp->wctp <= slot)
2297 *smbp->wctp = slot+1;
2299 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2300 *parmDatap++ = parmValue & 0xff;
2301 *parmDatap = (parmValue>>8) & 0xff;
2304 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2308 /* make sure we have enough slots */
2309 if (*smbp->wctp <= slot)
2310 *smbp->wctp = slot+2;
2312 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2313 *parmDatap++ = parmValue & 0xff;
2314 *parmDatap++ = (parmValue>>8) & 0xff;
2315 *parmDatap++ = (parmValue>>16) & 0xff;
2316 *parmDatap = (parmValue>>24) & 0xff;
2319 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2324 /* make sure we have enough slots */
2325 if (*smbp->wctp <= slot)
2326 *smbp->wctp = slot+4;
2328 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2330 *parmDatap++ = *parmValuep++;
2333 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2337 /* make sure we have enough slots */
2338 if (*smbp->wctp <= slot) {
2339 if (smbp->oddByte) {
2341 *smbp->wctp = slot+1;
2346 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2347 *parmDatap++ = parmValue & 0xff;
2350 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2354 lastSlashp = strrchr(inPathp, '\\');
2356 *lastComponentp = lastSlashp;
2359 if (inPathp == lastSlashp)
2361 *outPathp++ = *inPathp++;
2370 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2375 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2380 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2386 tlen = inp[0] + (inp[1]<<8);
2387 inp += 2; /* skip length field */
2390 *chainpp = inp + tlen;
2399 /* format a packet as a response */
2400 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2405 outp = (smb_t *) op;
2407 /* zero the basic structure through the smb_wct field, and zero the data
2408 * size field, assuming that wct stays zero; otherwise, you have to
2409 * explicitly set the data size field, too.
2411 inSmbp = (smb_t *) inp;
2412 memset(outp, 0, sizeof(smb_t)+2);
2418 outp->com = inSmbp->com;
2419 outp->tid = inSmbp->tid;
2420 outp->pid = inSmbp->pid;
2421 outp->uid = inSmbp->uid;
2422 outp->mid = inSmbp->mid;
2423 outp->res[0] = inSmbp->res[0];
2424 outp->res[1] = inSmbp->res[1];
2425 op->inCom = inSmbp->com;
2427 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2428 #ifdef SEND_CANONICAL_PATHNAMES
2429 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2431 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2433 /* copy fields in generic packet area */
2434 op->wctp = &outp->wct;
2437 /* send a (probably response) packet; vcp tells us to whom to send it.
2438 * we compute the length by looking at wct and bcc fields.
2440 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2454 memset((char *)ncbp, 0, sizeof(NCB));
2456 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2457 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2458 extra += tp[0] + (tp[1]<<8);
2459 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2460 extra += 3; /* wct and length fields */
2462 ncbp->ncb_length = extra; /* bytes to send */
2463 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2464 ncbp->ncb_lana_num = vcp->lana;
2465 ncbp->ncb_command = NCBSEND; /* op means send data */
2466 ncbp->ncb_buffer = (char *) inp;/* packet */
2467 code = Netbios(ncbp);
2470 const char * s = ncb_error_string(code);
2471 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2472 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2474 lock_ObtainMutex(&vcp->mx);
2475 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2476 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2478 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2479 lock_ReleaseMutex(&vcp->mx);
2480 lock_ObtainWrite(&smb_globalLock);
2481 dead_sessions[vcp->session] = TRUE;
2482 lock_ReleaseWrite(&smb_globalLock);
2483 smb_CleanupDeadVC(vcp);
2485 lock_ReleaseMutex(&vcp->mx);
2493 void smb_MapNTError(long code, unsigned long *NTStatusp)
2495 unsigned long NTStatus;
2497 /* map CM_ERROR_* errors to NT 32-bit status codes */
2498 /* NT Status codes are listed in ntstatus.h not winerror.h */
2499 if (code == CM_ERROR_NOSUCHCELL) {
2500 NTStatus = 0xC000000FL; /* No such file */
2502 else if (code == CM_ERROR_NOSUCHVOLUME) {
2503 NTStatus = 0xC000000FL; /* No such file */
2505 else if (code == CM_ERROR_TIMEDOUT) {
2507 NTStatus = 0xC00000CFL; /* Sharing Paused */
2509 NTStatus = 0x00000102L; /* Timeout */
2512 else if (code == CM_ERROR_RETRY) {
2513 NTStatus = 0xC000022DL; /* Retry */
2515 else if (code == CM_ERROR_NOACCESS) {
2516 NTStatus = 0xC0000022L; /* Access denied */
2518 else if (code == CM_ERROR_READONLY) {
2519 NTStatus = 0xC00000A2L; /* Write protected */
2521 else if (code == CM_ERROR_NOSUCHFILE ||
2522 code == CM_ERROR_BPLUS_NOMATCH) {
2523 NTStatus = 0xC000000FL; /* No such file */
2525 else if (code == CM_ERROR_NOSUCHPATH) {
2526 NTStatus = 0xC000003AL; /* Object path not found */
2528 else if (code == CM_ERROR_TOOBIG) {
2529 NTStatus = 0xC000007BL; /* Invalid image format */
2531 else if (code == CM_ERROR_INVAL) {
2532 NTStatus = 0xC000000DL; /* Invalid parameter */
2534 else if (code == CM_ERROR_BADFD) {
2535 NTStatus = 0xC0000008L; /* Invalid handle */
2537 else if (code == CM_ERROR_BADFDOP) {
2538 NTStatus = 0xC0000022L; /* Access denied */
2540 else if (code == CM_ERROR_EXISTS) {
2541 NTStatus = 0xC0000035L; /* Object name collision */
2543 else if (code == CM_ERROR_NOTEMPTY) {
2544 NTStatus = 0xC0000101L; /* Directory not empty */
2546 else if (code == CM_ERROR_CROSSDEVLINK) {
2547 NTStatus = 0xC00000D4L; /* Not same device */
2549 else if (code == CM_ERROR_NOTDIR) {
2550 NTStatus = 0xC0000103L; /* Not a directory */
2552 else if (code == CM_ERROR_ISDIR) {
2553 NTStatus = 0xC00000BAL; /* File is a directory */
2555 else if (code == CM_ERROR_BADOP) {
2557 /* I have no idea where this comes from */
2558 NTStatus = 0xC09820FFL; /* SMB no support */
2560 NTStatus = 0xC00000BBL; /* Not supported */
2561 #endif /* COMMENT */
2563 else if (code == CM_ERROR_BADSHARENAME) {
2564 NTStatus = 0xC00000CCL; /* Bad network name */
2566 else if (code == CM_ERROR_NOIPC) {
2568 NTStatus = 0xC0000022L; /* Access Denied */
2570 NTStatus = 0xC000013DL; /* Remote Resources */
2573 else if (code == CM_ERROR_CLOCKSKEW) {
2574 NTStatus = 0xC0000133L; /* Time difference at DC */
2576 else if (code == CM_ERROR_BADTID) {
2577 NTStatus = 0xC0982005L; /* SMB bad TID */
2579 else if (code == CM_ERROR_USESTD) {
2580 NTStatus = 0xC09820FBL; /* SMB use standard */
2582 else if (code == CM_ERROR_QUOTA) {
2583 NTStatus = 0xC0000044L; /* Quota exceeded */
2585 else if (code == CM_ERROR_SPACE) {
2586 NTStatus = 0xC000007FL; /* Disk full */
2588 else if (code == CM_ERROR_ATSYS) {
2589 NTStatus = 0xC0000033L; /* Object name invalid */
2591 else if (code == CM_ERROR_BADNTFILENAME) {
2592 NTStatus = 0xC0000033L; /* Object name invalid */
2594 else if (code == CM_ERROR_WOULDBLOCK) {
2595 NTStatus = 0xC0000055L; /* Lock not granted */
2597 else if (code == CM_ERROR_SHARING_VIOLATION) {
2598 NTStatus = 0xC0000043L; /* Sharing violation */
2600 else if (code == CM_ERROR_LOCK_CONFLICT) {
2601 NTStatus = 0xC0000054L; /* Lock conflict */
2603 else if (code == CM_ERROR_PARTIALWRITE) {
2604 NTStatus = 0xC000007FL; /* Disk full */
2606 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2607 NTStatus = 0xC0000023L; /* Buffer too small */
2609 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2610 NTStatus = 0xC0000035L; /* Object name collision */
2612 else if (code == CM_ERROR_BADPASSWORD) {
2613 NTStatus = 0xC000006DL; /* unknown username or bad password */
2615 else if (code == CM_ERROR_BADLOGONTYPE) {
2616 NTStatus = 0xC000015BL; /* logon type not granted */
2618 else if (code == CM_ERROR_GSSCONTINUE) {
2619 NTStatus = 0xC0000016L; /* more processing required */
2621 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2623 NTStatus = 0xC0000280L; /* reparse point not resolved */
2625 NTStatus = 0xC0000022L; /* Access Denied */
2628 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2629 NTStatus = 0xC0000257L; /* Path Not Covered */
2631 else if (code == CM_ERROR_ALLBUSY) {
2632 NTStatus = 0xC000022DL; /* Retry */
2634 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2635 NTStatus = 0xC00000BEL; /* Bad Network Path */
2637 else if (code == RXKADUNKNOWNKEY) {
2638 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2640 else if (code == CM_ERROR_BAD_LEVEL) {
2641 NTStatus = 0xC0000148L; /* Invalid Level */
2643 NTStatus = 0xC0982001L; /* SMB non-specific error */
2646 *NTStatusp = NTStatus;
2647 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2650 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2651 unsigned char *classp)
2653 unsigned char class;
2654 unsigned short error;
2656 /* map CM_ERROR_* errors to SMB errors */
2657 if (code == CM_ERROR_NOSUCHCELL) {
2659 error = 3; /* bad path */
2661 else if (code == CM_ERROR_NOSUCHVOLUME) {
2663 error = 3; /* bad path */
2665 else if (code == CM_ERROR_TIMEDOUT) {
2667 error = 81; /* server is paused */
2669 else if (code == CM_ERROR_RETRY) {
2670 class = 2; /* shouldn't happen */
2673 else if (code == CM_ERROR_NOACCESS) {
2675 error = 4; /* bad access */
2677 else if (code == CM_ERROR_READONLY) {
2679 error = 19; /* read only */
2681 else if (code == CM_ERROR_NOSUCHFILE ||
2682 code == CM_ERROR_BPLUS_NOMATCH) {
2684 error = 2; /* ENOENT! */
2686 else if (code == CM_ERROR_NOSUCHPATH) {
2688 error = 3; /* Bad path */
2690 else if (code == CM_ERROR_TOOBIG) {
2692 error = 11; /* bad format */
2694 else if (code == CM_ERROR_INVAL) {
2695 class = 2; /* server non-specific error code */
2698 else if (code == CM_ERROR_BADFD) {
2700 error = 6; /* invalid file handle */
2702 else if (code == CM_ERROR_BADFDOP) {
2703 class = 1; /* invalid op on FD */
2706 else if (code == CM_ERROR_EXISTS) {
2708 error = 80; /* file already exists */
2710 else if (code == CM_ERROR_NOTEMPTY) {
2712 error = 5; /* delete directory not empty */
2714 else if (code == CM_ERROR_CROSSDEVLINK) {
2716 error = 17; /* EXDEV */
2718 else if (code == CM_ERROR_NOTDIR) {
2719 class = 1; /* bad path */
2722 else if (code == CM_ERROR_ISDIR) {
2723 class = 1; /* access denied; DOS doesn't have a good match */
2726 else if (code == CM_ERROR_BADOP) {
2730 else if (code == CM_ERROR_BADSHARENAME) {
2734 else if (code == CM_ERROR_NOIPC) {
2736 error = 4; /* bad access */
2738 else if (code == CM_ERROR_CLOCKSKEW) {
2739 class = 1; /* invalid function */
2742 else if (code == CM_ERROR_BADTID) {
2746 else if (code == CM_ERROR_USESTD) {
2750 else if (code == CM_ERROR_REMOTECONN) {
2754 else if (code == CM_ERROR_QUOTA) {
2755 if (vcp->flags & SMB_VCFLAG_USEV3) {
2757 error = 39; /* disk full */
2761 error = 5; /* access denied */
2764 else if (code == CM_ERROR_SPACE) {
2765 if (vcp->flags & SMB_VCFLAG_USEV3) {
2767 error = 39; /* disk full */
2771 error = 5; /* access denied */
2774 else if (code == CM_ERROR_PARTIALWRITE) {
2776 error = 39; /* disk full */
2778 else if (code == CM_ERROR_ATSYS) {
2780 error = 2; /* ENOENT */
2782 else if (code == CM_ERROR_WOULDBLOCK) {
2784 error = 33; /* lock conflict */
2786 else if (code == CM_ERROR_LOCK_CONFLICT) {
2788 error = 33; /* lock conflict */
2790 else if (code == CM_ERROR_SHARING_VIOLATION) {
2792 error = 33; /* lock conflict */
2794 else if (code == CM_ERROR_NOFILES) {
2796 error = 18; /* no files in search */
2798 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2800 error = 183; /* Samba uses this */
2802 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2803 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2805 error = 2; /* bad password */
2807 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2809 error = 3; /* bad path */
2818 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2821 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2823 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2824 return CM_ERROR_BADOP;
2827 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2829 unsigned short EchoCount, i;
2830 char *data, *outdata;
2833 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2835 for (i=1; i<=EchoCount; i++) {
2836 data = smb_GetSMBData(inp, &dataSize);
2837 smb_SetSMBParm(outp, 0, i);
2838 smb_SetSMBDataLength(outp, dataSize);
2839 outdata = smb_GetSMBData(outp, NULL);
2840 memcpy(outdata, data, dataSize);
2841 smb_SendPacket(vcp, outp);
2847 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2850 long count, minCount, finalCount;
2855 cm_user_t *userp = NULL;
2858 char *rawBuf = NULL;
2863 fd = smb_GetSMBParm(inp, 0);
2864 count = smb_GetSMBParm(inp, 3);
2865 minCount = smb_GetSMBParm(inp, 4);
2866 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2868 if (*inp->wctp == 10) {
2869 /* we were sent a request with 64-bit file offsets */
2870 #ifdef AFS_LARGEFILES
2871 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2873 if (LargeIntegerLessThanZero(offset)) {
2874 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2878 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2879 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2882 offset.HighPart = 0;
2886 /* we were sent a request with 32-bit file offsets */
2887 offset.HighPart = 0;
2890 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2891 fd, offset.HighPart, offset.LowPart, count);
2893 fidp = smb_FindFID(vcp, fd, 0);
2897 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
2898 smb_CloseFID(vcp, fidp, NULL, 0);
2899 code = CM_ERROR_NOSUCHFILE;
2904 pid = ((smb_t *) inp)->pid;
2906 LARGE_INTEGER LOffset, LLength;
2909 key = cm_GenerateKey(vcp->vcID, pid, fd);
2911 LOffset.HighPart = offset.HighPart;
2912 LOffset.LowPart = offset.LowPart;
2913 LLength.HighPart = 0;
2914 LLength.LowPart = count;
2916 lock_ObtainMutex(&fidp->scp->mx);
2917 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2918 lock_ReleaseMutex(&fidp->scp->mx);
2924 lock_ObtainMutex(&smb_RawBufLock);
2926 /* Get a raw buf, from head of list */
2927 rawBuf = smb_RawBufs;
2928 smb_RawBufs = *(char **)smb_RawBufs;
2930 lock_ReleaseMutex(&smb_RawBufLock);
2934 lock_ObtainMutex(&fidp->mx);
2935 if (fidp->flags & SMB_FID_IOCTL)
2937 lock_ReleaseMutex(&fidp->mx);
2938 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2940 /* Give back raw buffer */
2941 lock_ObtainMutex(&smb_RawBufLock);
2942 *((char **) rawBuf) = smb_RawBufs;
2944 smb_RawBufs = rawBuf;
2945 lock_ReleaseMutex(&smb_RawBufLock);
2948 smb_ReleaseFID(fidp);
2951 lock_ReleaseMutex(&fidp->mx);
2953 userp = smb_GetUserFromVCP(vcp, inp);
2955 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2961 cm_ReleaseUser(userp);
2964 smb_ReleaseFID(fidp);
2968 memset((char *)ncbp, 0, sizeof(NCB));
2970 ncbp->ncb_length = (unsigned short) finalCount;
2971 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2972 ncbp->ncb_lana_num = vcp->lana;
2973 ncbp->ncb_command = NCBSEND;
2974 ncbp->ncb_buffer = rawBuf;
2976 code = Netbios(ncbp);
2978 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2981 /* Give back raw buffer */
2982 lock_ObtainMutex(&smb_RawBufLock);
2983 *((char **) rawBuf) = smb_RawBufs;
2985 smb_RawBufs = rawBuf;
2986 lock_ReleaseMutex(&smb_RawBufLock);
2992 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2994 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2999 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3001 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3006 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3013 int VistaProtoIndex;
3014 int protoIndex; /* index we're using */
3019 char protocol_array[10][1024]; /* protocol signature of the client */
3020 int caps; /* capabilities */
3023 TIME_ZONE_INFORMATION tzi;
3025 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3028 namep = smb_GetSMBData(inp, &dbytes);
3031 coreProtoIndex = -1; /* not found */
3034 VistaProtoIndex = -1;
3035 while(namex < dbytes) {
3036 osi_Log1(smb_logp, "Protocol %s",
3037 osi_LogSaveString(smb_logp, namep+1));
3038 strcpy(protocol_array[tcounter], namep+1);
3040 /* namep points at the first protocol, or really, a 0x02
3041 * byte preceding the null-terminated ASCII name.
3043 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3044 coreProtoIndex = tcounter;
3046 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3047 v3ProtoIndex = tcounter;
3049 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3050 NTProtoIndex = tcounter;
3052 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3053 VistaProtoIndex = tcounter;
3056 /* compute size of protocol entry */
3057 entryLength = (int)strlen(namep+1);
3058 entryLength += 2; /* 0x02 bytes and null termination */
3060 /* advance over this protocol entry */
3061 namex += entryLength;
3062 namep += entryLength;
3063 tcounter++; /* which proto entry we're looking at */
3066 lock_ObtainMutex(&vcp->mx);
3068 if (VistaProtoIndex != -1) {
3069 protoIndex = VistaProtoIndex;
3070 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3073 if (NTProtoIndex != -1) {
3074 protoIndex = NTProtoIndex;
3075 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3077 else if (v3ProtoIndex != -1) {
3078 protoIndex = v3ProtoIndex;
3079 vcp->flags |= SMB_VCFLAG_USEV3;
3081 else if (coreProtoIndex != -1) {
3082 protoIndex = coreProtoIndex;
3083 vcp->flags |= SMB_VCFLAG_USECORE;
3085 else protoIndex = -1;
3086 lock_ReleaseMutex(&vcp->mx);
3088 if (protoIndex == -1)
3089 return CM_ERROR_INVAL;
3090 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3091 smb_SetSMBParm(outp, 0, protoIndex);
3092 if (smb_authType != SMB_AUTH_NONE) {
3093 smb_SetSMBParmByte(outp, 1,
3094 NEGOTIATE_SECURITY_USER_LEVEL |
3095 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3097 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3099 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3100 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3101 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3102 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3103 /* The session key is not a well documented field however most clients
3104 * will echo back the session key to the server. Currently we are using
3105 * the same value for all sessions. We should generate a random value
3106 * and store it into the vcp
3108 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3109 smb_SetSMBParm(outp, 8, 1);
3111 * Tried changing the capabilities to support for W2K - defect 117695
3112 * Maybe something else needs to be changed here?
3116 smb_SetSMBParmLong(outp, 9, 0x43fd);
3118 smb_SetSMBParmLong(outp, 9, 0x251);
3121 * 32-bit error codes *
3126 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3128 NTNEGOTIATE_CAPABILITY_DFS |
3130 #ifdef AFS_LARGEFILES
3131 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3133 NTNEGOTIATE_CAPABILITY_NTFIND |
3134 NTNEGOTIATE_CAPABILITY_RAWMODE |
3135 NTNEGOTIATE_CAPABILITY_NTSMB;
3137 if ( smb_authType == SMB_AUTH_EXTENDED )
3138 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3140 smb_SetSMBParmLong(outp, 9, caps);
3142 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3143 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3144 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3146 GetTimeZoneInformation(&tzi);
3147 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3149 if (smb_authType == SMB_AUTH_NTLM) {
3150 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3151 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3152 /* paste in encryption key */
3153 datap = smb_GetSMBData(outp, NULL);
3154 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3155 /* and the faux domain name */
3156 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3157 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3161 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3163 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3165 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3167 datap = smb_GetSMBData(outp, NULL);
3168 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3171 datap += sizeof(smb_ServerGUID);
3172 memcpy(datap, secBlob, secBlobLength);
3176 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3177 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3180 else if (v3ProtoIndex != -1) {
3181 smb_SetSMBParm(outp, 0, protoIndex);
3183 /* NOTE: Extended authentication cannot be negotiated with v3
3184 * therefore we fail over to NTLM
3186 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3187 smb_SetSMBParm(outp, 1,
3188 NEGOTIATE_SECURITY_USER_LEVEL |
3189 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3191 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3193 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3194 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3195 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3196 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3197 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3198 smb_SetSMBParm(outp, 7, 1);
3200 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3201 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3202 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3204 GetTimeZoneInformation(&tzi);
3205 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3207 /* NOTE: Extended authentication cannot be negotiated with v3
3208 * therefore we fail over to NTLM
3210 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3211 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3212 smb_SetSMBParm(outp, 12, 0); /* resvd */
3213 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3214 datap = smb_GetSMBData(outp, NULL);
3215 /* paste in a new encryption key */
3216 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3217 /* and the faux domain name */
3218 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3220 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3221 smb_SetSMBParm(outp, 12, 0); /* resvd */
3222 smb_SetSMBDataLength(outp, 0);
3225 else if (coreProtoIndex != -1) { /* not really supported anymore */
3226 smb_SetSMBParm(outp, 0, protoIndex);
3227 smb_SetSMBDataLength(outp, 0);
3232 void smb_CheckVCs(void)
3234 smb_vc_t * vcp, *nextp;
3235 smb_packet_t * outp = GetPacket();
3238 lock_ObtainWrite(&smb_rctLock);
3239 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3241 if (vcp->magic != SMB_VC_MAGIC)
3242 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3243 __FILE__, __LINE__);
3247 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3250 smb_HoldVCNoLock(vcp);
3252 smb_HoldVCNoLock(nextp);
3253 smb_FormatResponsePacket(vcp, NULL, outp);
3254 smbp = (smb_t *)outp;
3255 outp->inCom = smbp->com = 0x2b /* Echo */;
3263 smb_SetSMBParm(outp, 0, 0);
3264 smb_SetSMBDataLength(outp, 0);
3265 lock_ReleaseWrite(&smb_rctLock);
3267 smb_SendPacket(vcp, outp);
3269 lock_ObtainWrite(&smb_rctLock);
3270 smb_ReleaseVCNoLock(vcp);
3272 smb_ReleaseVCNoLock(nextp);
3274 lock_ReleaseWrite(&smb_rctLock);
3275 smb_FreePacket(outp);
3278 void smb_Daemon(void *parmp)
3280 afs_uint32 count = 0;
3281 smb_username_t **unpp;
3284 while(smbShutdownFlag == 0) {
3288 if (smbShutdownFlag == 1)
3291 if ((count % 72) == 0) { /* every five minutes */
3293 time_t old_localZero = smb_localZero;
3295 /* Initialize smb_localZero */
3296 myTime.tm_isdst = -1; /* compute whether on DST or not */
3297 myTime.tm_year = 70;
3303 smb_localZero = mktime(&myTime);
3305 #ifndef USE_NUMERIC_TIME_CONV
3306 smb_CalculateNowTZ();
3307 #endif /* USE_NUMERIC_TIME_CONV */
3308 #ifdef AFS_FREELANCE
3309 if ( smb_localZero != old_localZero )
3310 cm_noteLocalMountPointChange();
3316 /* GC smb_username_t objects that will no longer be used */
3318 lock_ObtainWrite(&smb_rctLock);
3319 for ( unpp=&usernamesp; *unpp; ) {
3321 smb_username_t *unp;
3323 lock_ObtainMutex(&(*unpp)->mx);
3324 if ( (*unpp)->refCount > 0 ||
3325 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3326 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3328 else if (!smb_LogoffTokenTransfer ||
3329 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3331 lock_ReleaseMutex(&(*unpp)->mx);
3339 lock_FinalizeMutex(&unp->mx);
3345 lock_ReleaseWrite(&smb_rctLock);
3346 cm_ReleaseUser(userp);
3347 lock_ObtainWrite(&smb_rctLock);
3350 unpp = &(*unpp)->nextp;
3353 lock_ReleaseWrite(&smb_rctLock);
3355 /* XXX GC dir search entries */
3359 void smb_WaitingLocksDaemon()
3361 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3362 smb_waitingLock_t *wl, *wlNext;
3365 smb_packet_t *inp, *outp;
3369 while (smbShutdownFlag == 0) {
3370 lock_ObtainWrite(&smb_globalLock);
3371 nwlRequest = smb_allWaitingLocks;
3372 if (nwlRequest == NULL) {
3373 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3378 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3385 lock_ObtainWrite(&smb_globalLock);
3387 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3389 wlRequest = nwlRequest;
3390 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3391 lock_ReleaseWrite(&smb_globalLock);
3395 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3396 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3399 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3401 /* wl->state is either _DONE or _WAITING. _ERROR
3402 would no longer be on the queue. */
3403 code = cm_RetryLock( wl->lockp,
3404 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3407 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3408 } else if (code != CM_ERROR_WOULDBLOCK) {
3409 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3414 if (code == CM_ERROR_WOULDBLOCK) {
3417 if (wlRequest->timeRemaining != 0xffffffff
3418 && (wlRequest->timeRemaining -= 1000) < 0)
3430 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3433 scp = wlRequest->scp;
3434 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3438 lock_ObtainMutex(&scp->mx);
3440 for (wl = wlRequest->locks; wl; wl = wlNext) {
3441 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3443 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3444 wl->LLength, wl->key, NULL, &req);
3446 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3451 lock_ReleaseMutex(&scp->mx);
3455 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3458 for (wl = wlRequest->locks; wl; wl = wlNext) {
3459 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3460 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3465 vcp = wlRequest->vcp;
3466 inp = wlRequest->inp;
3467 outp = wlRequest->outp;
3469 ncbp->ncb_length = inp->ncb_length;
3470 inp->spacep = cm_GetSpace();
3472 /* Remove waitingLock from list */
3473 lock_ObtainWrite(&smb_globalLock);
3474 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3476 lock_ReleaseWrite(&smb_globalLock);
3478 /* Resume packet processing */
3480 smb_SetSMBDataLength(outp, 0);
3481 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3482 outp->resumeCode = code;
3484 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3487 cm_FreeSpace(inp->spacep);
3488 smb_FreePacket(inp);
3489 smb_FreePacket(outp);
3491 cm_ReleaseSCache(wlRequest->scp);
3494 } while (nwlRequest && smbShutdownFlag == 0);
3499 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3501 osi_Log0(smb_logp, "SMB receive get disk attributes");
3503 smb_SetSMBParm(outp, 0, 32000);
3504 smb_SetSMBParm(outp, 1, 64);
3505 smb_SetSMBParm(outp, 2, 1024);
3506 smb_SetSMBParm(outp, 3, 30000);
3507 smb_SetSMBParm(outp, 4, 0);
3508 smb_SetSMBDataLength(outp, 0);
3512 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3516 unsigned short newTid;
3517 char shareName[AFSPATHMAX];
3525 osi_Log0(smb_logp, "SMB receive tree connect");
3527 /* parse input parameters */
3528 tp = smb_GetSMBData(inp, NULL);
3529 pathp = smb_ParseASCIIBlock(tp, &tp);
3530 if (smb_StoreAnsiFilenames)
3531 OemToChar(pathp,pathp);
3532 passwordp = smb_ParseASCIIBlock(tp, &tp);
3533 tp = strrchr(pathp, '\\');
3535 return CM_ERROR_BADSMB;
3536 strcpy(shareName, tp+1);
3538 lock_ObtainMutex(&vcp->mx);
3539 newTid = vcp->tidCounter++;
3540 lock_ReleaseMutex(&vcp->mx);
3542 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3543 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3544 userp = smb_GetUserFromUID(uidp);
3545 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3547 smb_ReleaseUID(uidp);
3549 smb_ReleaseTID(tidp);
3550 return CM_ERROR_BADSHARENAME;
3552 lock_ObtainMutex(&tidp->mx);
3553 tidp->userp = userp;
3554 tidp->pathname = sharePath;
3555 lock_ReleaseMutex(&tidp->mx);
3556 smb_ReleaseTID(tidp);
3558 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3559 smb_SetSMBParm(rsp, 1, newTid);
3560 smb_SetSMBDataLength(rsp, 0);
3562 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3566 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3570 if (*inp++ != 0x1) return NULL;
3571 tlen = inp[0] + (inp[1]<<8);
3572 inp += 2; /* skip length field */
3575 *chainpp = inp + tlen;
3578 if (lengthp) *lengthp = tlen;
3583 /* set maskp to the mask part of the incoming path.
3584 * Mask is 11 bytes long (8.3 with the dot elided).
3585 * Returns true if succeeds with a valid name, otherwise it does
3586 * its best, but returns false.
3588 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3596 /* starts off valid */
3599 /* mask starts out all blanks */
3600 memset(maskp, ' ', 11);
3603 /* find last backslash, or use whole thing if there is none */
3604 tp = strrchr(pathp, '\\');
3608 tp++; /* skip slash */
3612 /* names starting with a dot are illegal */
3620 if (tc == '.' || tc == '"')
3628 /* if we get here, tp point after the dot */
3629 up = maskp+8; /* ext goes here */
3636 if (tc == '.' || tc == '"')
3639 /* copy extension if not too long */
3649 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3659 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3661 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3665 /* otherwise, we have a valid 8.3 name; see if we have a match,
3666 * treating '?' as a wildcard in maskp (but not in the file name).
3668 tp1 = umask; /* real name, in mask format */
3669 tp2 = maskp; /* mask, in mask format */
3670 for(i=0; i<11; i++) {
3671 tc1 = *tp1++; /* char from real name */
3672 tc2 = *tp2++; /* char from mask */
3673 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3674 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3677 if (tc2 == '?' && tc1 != ' ')
3684 /* we got a match */
3688 char *smb_FindMask(char *pathp)
3692 tp = strrchr(pathp, '\\'); /* find last slash */
3695 return tp+1; /* skip the slash */
3697 return pathp; /* no slash, return the entire path */
3700 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3702 unsigned char *pathp;
3704 unsigned char mask[12];
3705 unsigned char *statBlockp;
3706 unsigned char initStatBlock[21];
3709 osi_Log0(smb_logp, "SMB receive search volume");
3711 /* pull pathname and stat block out of request */
3712 tp = smb_GetSMBData(inp, NULL);
3713 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3714 osi_assertx(pathp != NULL, "null path");
3715 if (smb_StoreAnsiFilenames)
3716 OemToChar(pathp,pathp);
3717 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3718 osi_assertx(statBlockp != NULL, "null statBlock");
3720 statBlockp = initStatBlock;
3724 /* for returning to caller */
3725 smb_Get8Dot3MaskFromPath(mask, pathp);
3727 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3728 tp = smb_GetSMBData(outp, NULL);
3730 *tp++ = 43; /* bytes in a dir entry */
3731 *tp++ = 0; /* high byte in counter */
3733 /* now marshall the dir entry, starting with the search status */
3734 *tp++ = statBlockp[0]; /* Reserved */
3735 memcpy(tp, mask, 11); tp += 11; /* FileName */
3737 /* now pass back server use info, with 1st byte non-zero */
3739 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3741 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3743 *tp++ = 0x8; /* attribute: volume */
3753 /* 4 byte file size */
3759 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3760 memset(tp, ' ', 13);
3763 /* set the length of the data part of the packet to 43 + 3, for the dir
3764 * entry plus the 5 and the length fields.
3766 smb_SetSMBDataLength(outp, 46);
3771 smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3772 char * tidPathp, char * relPathp,
3773 cm_user_t *userp, cm_req_t *reqp)
3781 smb_dirListPatch_t *patchp;
3782 smb_dirListPatch_t *npatchp;
3783 char path[AFSPATHMAX];
3785 for (patchp = *dirPatchespp; patchp; patchp =
3786 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3788 dptr = patchp->dptr;
3790 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
3791 reqp->relPathp = path;
3792 reqp->tidPathp = tidPathp;
3794 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3795 reqp->relPathp = reqp->tidPathp = NULL;
3798 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3799 *dptr++ = SMB_ATTR_HIDDEN;
3802 lock_ObtainMutex(&scp->mx);
3803 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3804 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3806 lock_ReleaseMutex(&scp->mx);
3807 cm_ReleaseSCache(scp);
3808 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3809 *dptr++ = SMB_ATTR_HIDDEN;
3813 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3815 attr = smb_Attributes(scp);
3816 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3817 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3818 attr |= SMB_ATTR_HIDDEN;
3822 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3825 shortTemp = (unsigned short) (dosTime & 0xffff);
3826 *((u_short *)dptr) = shortTemp;
3829 /* and copy out date */
3830 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3831 *((u_short *)dptr) = shortTemp;
3834 /* copy out file length */
3835 *((u_long *)dptr) = scp->length.LowPart;
3837 lock_ReleaseMutex(&scp->mx);
3838 cm_ReleaseSCache(scp);
3841 /* now free the patches */
3842 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3843 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3847 /* and mark the list as empty */
3848 *dirPatchespp = NULL;
3853 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3860 cm_dirEntry_t *dep = 0;
3862 smb_dirListPatch_t *dirListPatchesp;
3863 smb_dirListPatch_t *curPatchp;
3867 osi_hyper_t dirLength;
3868 osi_hyper_t bufferOffset;
3869 osi_hyper_t curOffset;
3871 unsigned char *inCookiep;
3872 smb_dirSearch_t *dsp;
3876 unsigned long clientCookie;
3877 cm_pageHeader_t *pageHeaderp;
3878 cm_user_t *userp = NULL;
3885 long nextEntryCookie;
3886 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3887 char resByte; /* reserved byte from the cookie */
3888 char *op; /* output data ptr */
3889 char *origOp; /* original value of op */
3890 cm_space_t *spacep; /* for pathname buffer */
3901 maxCount = smb_GetSMBParm(inp, 0);
3903 dirListPatchesp = NULL;
3905 caseFold = CM_FLAG_CASEFOLD;
3907 tp = smb_GetSMBData(inp, NULL);
3908 pathp = smb_ParseASCIIBlock(tp, &tp);
3909 if (smb_StoreAnsiFilenames)
3910 OemToChar(pathp,pathp);
3911 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3913 /* bail out if request looks bad */
3914 if (!tp || !pathp) {
3915 return CM_ERROR_BADSMB;
3918 /* We can handle long names */
3919 if (vcp->flags & SMB_VCFLAG_USENT)
3920 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3922 /* make sure we got a whole search status */
3923 if (dataLength < 21) {
3924 nextCookie = 0; /* start at the beginning of the dir */
3927 attribute = smb_GetSMBParm(inp, 1);
3929 /* handle volume info in another function */
3930 if (attribute & 0x8)
3931 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3933 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3934 maxCount, osi_LogSaveString(smb_logp, pathp));
3936 if (*pathp == 0) { /* null pathp, treat as root dir */
3937 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3938 return CM_ERROR_NOFILES;
3942 dsp = smb_NewDirSearch(0);
3943 dsp->attribute = attribute;
3944 smb_Get8Dot3MaskFromPath(mask, pathp);
3945 memcpy(dsp->mask, mask, 12);
3947 /* track if this is likely to match a lot of entries */
3948 if (smb_IsStarMask(mask))
3953 /* pull the next cookie value out of the search status block */
3954 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3955 + (inCookiep[16]<<24);
3956 dsp = smb_FindDirSearch(inCookiep[12]);
3958 /* can't find dir search status; fatal error */
3959 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3960 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3961 return CM_ERROR_BADFD;
3963 attribute = dsp->attribute;
3964 resByte = inCookiep[0];
3966 /* copy out client cookie, in host byte order. Don't bother
3967 * interpreting it, since we're just passing it through, anyway.
3969 memcpy(&clientCookie, &inCookiep[17], 4);
3971 memcpy(mask, dsp->mask, 12);
3973 /* assume we're doing a star match if it has continued for more
3979 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3980 nextCookie, dsp->cookie, attribute);
3982 userp = smb_GetUserFromVCP(vcp, inp);
3984 /* try to get the vnode for the path name next */
3985 lock_ObtainMutex(&dsp->mx);
3988 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
3992 spacep = inp->spacep;
3993 smb_StripLastComponent(spacep->data, NULL, pathp);
3994 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3996 lock_ReleaseMutex(&dsp->mx);
3997 cm_ReleaseUser(userp);
3998 smb_DeleteDirSearch(dsp);
3999 smb_ReleaseDirSearch(dsp);
4000 return CM_ERROR_NOFILES;
4002 strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
4003 strcpy(dsp->relPath, spacep->data);
4005 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4006 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4009 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4010 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4011 cm_ReleaseSCache(scp);
4012 lock_ReleaseMutex(&dsp->mx);
4013 cm_ReleaseUser(userp);
4014 smb_DeleteDirSearch(dsp);
4015 smb_ReleaseDirSearch(dsp);
4016 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4017 return CM_ERROR_PATH_NOT_COVERED;
4019 return CM_ERROR_BADSHARENAME;
4021 #endif /* DFS_SUPPORT */
4024 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4025 /* we need one hold for the entry we just stored into,
4026 * and one for our own processing. When we're done with this
4027 * function, we'll drop the one for our own processing.
4028 * We held it once from the namei call, and so we do another hold
4032 lock_ObtainMutex(&scp->mx);
4033 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4034 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4035 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4036 dsp->flags |= SMB_DIRSEARCH_BULKST;
4037 dsp->scp->bulkStatProgress = hzero;
4039 lock_ReleaseMutex(&scp->mx);
4042 lock_ReleaseMutex(&dsp->mx);
4044 cm_ReleaseUser(userp);
4045 smb_DeleteDirSearch(dsp);
4046 smb_ReleaseDirSearch(dsp);
4050 /* reserves space for parameter; we'll adjust it again later to the
4051 * real count of the # of entries we returned once we've actually
4052 * assembled the directory listing.
4054 smb_SetSMBParm(outp, 0, 0);
4056 /* get the directory size */
4057 lock_ObtainMutex(&scp->mx);
4058 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4059 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4061 lock_ReleaseMutex(&scp->mx);
4062 cm_ReleaseSCache(scp);
4063 cm_ReleaseUser(userp);
4064 smb_DeleteDirSearch(dsp);
4065 smb_ReleaseDirSearch(dsp);
4069 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4071 dirLength = scp->length;
4073 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4074 curOffset.HighPart = 0;
4075 curOffset.LowPart = nextCookie;
4076 origOp = op = smb_GetSMBData(outp, NULL);
4077 /* and write out the basic header */
4078 *op++ = 5; /* variable block */
4079 op += 2; /* skip vbl block length; we'll fill it in later */
4083 /* make sure that curOffset.LowPart doesn't point to the first
4084 * 32 bytes in the 2nd through last dir page, and that it doesn't
4085 * point at the first 13 32-byte chunks in the first dir page,
4086 * since those are dir and page headers, and don't contain useful
4089 temp = curOffset.LowPart & (2048-1);
4090 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4091 /* we're in the first page */
4092 if (temp < 13*32) temp = 13*32;
4095 /* we're in a later dir page */
4096 if (temp < 32) temp = 32;
4099 /* make sure the low order 5 bits are zero */
4102 /* now put temp bits back ito curOffset.LowPart */
4103 curOffset.LowPart &= ~(2048-1);
4104 curOffset.LowPart |= temp;
4106 /* check if we've returned all the names that will fit in the
4109 if (returnedNames >= maxCount) {
4110 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4111 returnedNames, maxCount);
4115 /* check if we've passed the dir's EOF */
4116 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4118 /* see if we can use the bufferp we have now; compute in which page
4119 * the current offset would be, and check whether that's the offset
4120 * of the buffer we have. If not, get the buffer.
4122 thyper.HighPart = curOffset.HighPart;
4123 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4124 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4127 buf_Release(bufferp);
4130 lock_ReleaseMutex(&scp->mx);
4131 lock_ObtainRead(&scp->bufCreateLock);
4132 code = buf_Get(scp, &thyper, &bufferp);
4133 lock_ReleaseRead(&scp->bufCreateLock);
4134 lock_ObtainMutex(&dsp->mx);
4136 /* now, if we're doing a star match, do bulk fetching of all of
4137 * the status info for files in the dir.
4140 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4141 lock_ObtainMutex(&scp->mx);
4142 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4143 LargeIntegerGreaterThanOrEqualTo(thyper,
4144 scp->bulkStatProgress)) {
4145 /* Don't bulk stat if risking timeout */
4146 int now = GetTickCount();
4147 if (now - req.startTime > RDRtimeout * 1000) {
4148 scp->bulkStatProgress = thyper;
4149 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4150 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4151 dsp->scp->bulkStatProgress = hzero;
4153 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4156 lock_ObtainMutex(&scp->mx);
4158 lock_ReleaseMutex(&dsp->mx);
4160 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4164 bufferOffset = thyper;
4166 /* now get the data in the cache */
4168 code = cm_SyncOp(scp, bufferp, userp, &req,
4170 CM_SCACHESYNC_NEEDCALLBACK |
4171 CM_SCACHESYNC_READ);
4173 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4177 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4179 if (cm_HaveBuffer(scp, bufferp, 0)) {
4180 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4184 /* otherwise, load the buffer and try again */
4185 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4187 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4188 scp, bufferp, code);
4193 buf_Release(bufferp);
4197 } /* if (wrong buffer) ... */
4199 /* now we have the buffer containing the entry we're interested in; copy
4200 * it out if it represents a non-deleted entry.
4202 entryInDir = curOffset.LowPart & (2048-1);
4203 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4205 /* page header will help tell us which entries are free. Page header
4206 * can change more often than once per buffer, since AFS 3 dir page size
4207 * may be less than (but not more than a buffer package buffer.
4209 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4210 temp &= ~(2048 - 1); /* turn off intra-page bits */
4211 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4213 /* now determine which entry we're looking at in the page. If it is
4214 * free (there's a free bitmap at the start of the dir), we should
4215 * skip these 32 bytes.
4217 slotInPage = (entryInDir & 0x7e0) >> 5;
4218 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4219 /* this entry is free */
4220 numDirChunks = 1; /* only skip this guy */
4224 tp = bufferp->datap + entryInBuffer;
4225 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4227 /* while we're here, compute the next entry's location, too,
4228 * since we'll need it when writing out the cookie into the dir
4231 * XXXX Probably should do more sanity checking.
4233 numDirChunks = cm_NameEntries(dep->name, NULL);
4235 /* compute the offset of the cookie representing the next entry */
4236 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4238 /* Compute 8.3 name if necessary */
4239 actualName = dep->name;
4240 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4241 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4242 actualName = shortName;
4245 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4246 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4247 osi_LogSaveString(smb_logp, actualName));
4249 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4250 /* this is one of the entries to use: it is not deleted
4251 * and it matches the star pattern we're looking for.
4254 /* Eliminate entries that don't match requested
4257 /* no hidden files */
4258 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4259 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4263 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4265 /* We have already done the cm_TryBulkStat above */
4266 fid.cell = scp->fid.cell;
4267 fid.volume = scp->fid.volume;
4268 fid.vnode = ntohl(dep->fid.vnode);
4269 fid.unique = ntohl(dep->fid.unique);
4270 fileType = cm_FindFileType(&fid);
4271 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4272 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4274 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4275 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4276 fileType == CM_SCACHETYPE_DFSLINK ||
4277 fileType == CM_SCACHETYPE_INVALID)
4278 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4283 memcpy(op, mask, 11); op += 11;
4284 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4285 *op++ = (char)(nextEntryCookie & 0xff);
4286 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4287 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4288 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4289 memcpy(op, &clientCookie, 4); op += 4;
4291 /* now we emit the attribute. This is sort of tricky,
4292 * since we need to really stat the file to find out
4293 * what type of entry we've got. Right now, we're
4294 * copying out data from a buffer, while holding the
4295 * scp locked, so it isn't really convenient to stat
4296 * something now. We'll put in a place holder now,
4297 * and make a second pass before returning this to get
4298 * the real attributes. So, we just skip the data for
4299 * now, and adjust it later. We allocate a patch
4300 * record to make it easy to find this point later.
4301 * The replay will happen at a time when it is safe to
4302 * unlock the directory.
4304 curPatchp = malloc(sizeof(*curPatchp));
4305 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4306 curPatchp->dptr = op;
4307 curPatchp->fid.cell = scp->fid.cell;
4308 curPatchp->fid.volume = scp->fid.volume;
4309 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4310 curPatchp->fid.unique = ntohl(dep->fid.unique);
4312 /* do hidden attribute here since name won't be around when applying
4316 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4317 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4319 curPatchp->flags = 0;
4321 op += 9; /* skip attr, time, date and size */
4323 /* zero out name area. The spec says to pad with
4324 * spaces, but Samba doesn't, and neither do we.
4328 /* finally, we get to copy out the name; we know that
4329 * it fits in 8.3 or the pattern wouldn't match, but it
4330 * never hurts to be sure.
4332 strncpy(op, actualName, 13);
4333 if (smb_StoreAnsiFilenames)
4336 /* Uppercase if requested by client */
4337 if (!KNOWS_LONG_NAMES(inp))
4342 /* now, adjust the # of entries copied */
4344 } /* if we're including this name */
4347 /* and adjust curOffset to be where the new cookie is */
4348 thyper.HighPart = 0;
4349 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4350 curOffset = LargeIntegerAdd(thyper, curOffset);
4351 } /* while copying data for dir listing */
4353 /* release the mutex */
4354 lock_ReleaseMutex(&scp->mx);
4356 buf_Release(bufferp);
4360 /* apply and free last set of patches; if n