2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
32 #include "lanahelper.h"
34 /* These characters are illegal in Windows filenames */
35 static char *illegalChars = "\\/:*?\"<>|";
37 static int smbShutdownFlag = 0;
38 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
40 int smb_LogoffTokenTransfer;
41 time_t smb_LogoffTransferTimeout;
43 int smb_StoreAnsiFilenames = 0;
45 DWORD last_msg_time = 0;
49 unsigned int sessionGen = 0;
51 extern void afsi_log(char *pattern, ...);
52 extern HANDLE afsi_file;
53 extern int powerStateSuspended;
55 osi_hyper_t hzero = {0, 0};
56 osi_hyper_t hones = {0xFFFFFFFF, -1};
59 osi_rwlock_t smb_globalLock;
60 osi_rwlock_t smb_rctLock;
61 osi_mutex_t smb_ListenerLock;
64 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
66 BOOL isGateway = FALSE;
69 long smb_maxObsConcurrentCalls=0;
70 long smb_concurrentCalls=0;
72 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
74 smb_packet_t *smb_packetFreeListp;
75 smb_ncb_t *smb_ncbFreeListp;
77 int smb_NumServerThreads;
79 int numNCBs, numSessions, numVCs;
81 int smb_maxVCPerServer;
82 int smb_maxMpxRequests;
84 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
86 ULONG smb_lsaSecPackage;
87 LSA_STRING smb_lsaLogonOrigin;
89 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
90 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
91 EVENT_HANDLE **NCBreturns;
92 EVENT_HANDLE **NCBShutdown;
93 EVENT_HANDLE *smb_ServerShutdown;
94 DWORD NCBsessions[NCB_MAX];
96 struct smb_packet *bufs[NCB_MAX];
98 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
99 EVENT_HANDLE SessionEvents[SESSION_MAX];
100 unsigned short LSNs[SESSION_MAX];
101 int lanas[SESSION_MAX];
102 BOOL dead_sessions[SESSION_MAX];
106 osi_mutex_t smb_RawBufLock;
109 #define SMB_MASKFLAG_TILDE 1
110 #define SMB_MASKFLAG_CASEFOLD 2
112 #define RAWTIMEOUT INFINITE
115 typedef struct raw_write_cont {
124 /* dir search stuff */
125 long smb_dirSearchCounter = 1;
126 smb_dirSearch_t *smb_firstDirSearchp;
127 smb_dirSearch_t *smb_lastDirSearchp;
129 /* hide dot files? */
130 int smb_hideDotFiles;
132 /* global state about V3 protocols */
133 int smb_useV3; /* try to negotiate V3 */
135 static showErrors = 0;
136 /* MessageBox or something like it */
137 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
140 * Time in Unix format of midnight, 1/1/1970 local time.
141 * When added to dosUTime, gives Unix (AFS) time.
143 time_t smb_localZero = 0;
145 #define USE_NUMERIC_TIME_CONV 1
147 #ifndef USE_NUMERIC_TIME_CONV
148 /* Time difference for converting to kludge-GMT */
149 afs_uint32 smb_NowTZ;
150 #endif /* USE_NUMERIC_TIME_CONV */
152 char *smb_localNamep = NULL;
154 smb_vc_t *smb_allVCsp;
155 smb_vc_t *smb_deadVCsp;
157 smb_username_t *usernamesp = NULL;
159 smb_waitingLockRequest_t *smb_allWaitingLocks;
161 DWORD smb_TlsRequestSlot = -1;
164 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
165 NCB *ncbp, raw_write_cont_t *rwcp);
166 int smb_NetbiosInit(void);
169 void smb_LogPacket(smb_packet_t *packet);
170 #endif /* LOG_PACKET */
172 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
173 int smb_ServerDomainNameLength = 0;
174 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
175 int smb_ServerOSLength = sizeof(smb_ServerOS);
176 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
177 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
179 /* Faux server GUID. This is never checked. */
180 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
182 void smb_ResetServerPriority()
184 void * p = TlsGetValue(smb_TlsRequestSlot);
187 TlsSetValue(smb_TlsRequestSlot, NULL);
188 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
192 void smb_SetRequestStartTime()
194 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
196 tp = malloc(sizeof(time_t));
200 if (!TlsSetValue(smb_TlsRequestSlot, tp))
205 void smb_UpdateServerPriority()
207 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
210 time_t now = osi_Time();
212 /* Give one priority boost for each 15 seconds */
213 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
218 const char * ncb_error_string(int code)
222 case 0x01: s = "llegal buffer length"; break;
223 case 0x03: s = "illegal command"; break;
224 case 0x05: s = "command timed out"; break;
225 case 0x06: s = "message incomplete, issue another command"; break;
226 case 0x07: s = "illegal buffer address"; break;
227 case 0x08: s = "session number out of range"; break;
228 case 0x09: s = "no resource available"; break;
229 case 0x0a: s = "session closed"; break;
230 case 0x0b: s = "command cancelled"; break;
231 case 0x0d: s = "duplicate name"; break;
232 case 0x0e: s = "name table full"; break;
233 case 0x0f: s = "no deletions, name has active sessions"; break;
234 case 0x11: s = "local session table full"; break;
235 case 0x12: s = "remote session table full"; break;
236 case 0x13: s = "illegal name number"; break;
237 case 0x14: s = "no callname"; break;
238 case 0x15: s = "cannot put * in NCB_NAME"; break;
239 case 0x16: s = "name in use on remote adapter"; break;
240 case 0x17: s = "name deleted"; break;
241 case 0x18: s = "session ended abnormally"; break;
242 case 0x19: s = "name conflict detected"; break;
243 case 0x21: s = "interface busy, IRET before retrying"; break;
244 case 0x22: s = "too many commands outstanding, retry later";break;
245 case 0x23: s = "ncb_lana_num field invalid"; break;
246 case 0x24: s = "command completed while cancel occurring "; break;
247 case 0x26: s = "command not valid to cancel"; break;
248 case 0x30: s = "name defined by anther local process"; break;
249 case 0x34: s = "environment undefined. RESET required"; break;
250 case 0x35: s = "required OS resources exhausted"; break;
251 case 0x36: s = "max number of applications exceeded"; break;
252 case 0x37: s = "no saps available for netbios"; break;
253 case 0x38: s = "requested resources are not available"; break;
254 case 0x39: s = "invalid ncb address or length > segment"; break;
255 case 0x3B: s = "invalid NCB DDID"; break;
256 case 0x3C: s = "lock of user area failed"; break;
257 case 0x3f: s = "NETBIOS not loaded"; break;
258 case 0x40: s = "system error"; break;
259 default: s = "unknown error";
265 char * myCrt_Dispatch(int i)
270 return "(00)ReceiveCoreMakeDir";
272 return "(01)ReceiveCoreRemoveDir";
274 return "(02)ReceiveCoreOpen";
276 return "(03)ReceiveCoreCreate";
278 return "(04)ReceiveCoreClose";
280 return "(05)ReceiveCoreFlush";
282 return "(06)ReceiveCoreUnlink";
284 return "(07)ReceiveCoreRename";
286 return "(08)ReceiveCoreGetFileAttributes";
288 return "(09)ReceiveCoreSetFileAttributes";
290 return "(0a)ReceiveCoreRead";
292 return "(0b)ReceiveCoreWrite";
294 return "(0c)ReceiveCoreLockRecord";
296 return "(0d)ReceiveCoreUnlockRecord";
298 return "(0e)SendCoreBadOp";
300 return "(0f)ReceiveCoreCreate";
302 return "(10)ReceiveCoreCheckPath";
304 return "(11)SendCoreBadOp";
306 return "(12)ReceiveCoreSeek";
308 return "(1a)ReceiveCoreReadRaw";
310 return "(1d)ReceiveCoreWriteRawDummy";
312 return "(22)ReceiveV3SetAttributes";
314 return "(23)ReceiveV3GetAttributes";
316 return "(24)ReceiveV3LockingX";
318 return "(25)ReceiveV3Trans";
320 return "(26)ReceiveV3Trans[aux]";
322 return "(29)SendCoreBadOp";
324 return "(2b)ReceiveCoreEcho";
326 return "(2d)ReceiveV3OpenX";
328 return "(2e)ReceiveV3ReadX";
330 return "(2f)ReceiveV3WriteX";
332 return "(32)ReceiveV3Tran2A";
334 return "(33)ReceiveV3Tran2A[aux]";
336 return "(34)ReceiveV3FindClose";
338 return "(35)ReceiveV3FindNotifyClose";
340 return "(70)ReceiveCoreTreeConnect";
342 return "(71)ReceiveCoreTreeDisconnect";
344 return "(72)ReceiveNegotiate";
346 return "(73)ReceiveV3SessionSetupX";
348 return "(74)ReceiveV3UserLogoffX";
350 return "(75)ReceiveV3TreeConnectX";
352 return "(80)ReceiveCoreGetDiskAttributes";
354 return "(81)ReceiveCoreSearchDir";
358 return "(83)FindUnique";
360 return "(84)FindClose";
362 return "(A0)ReceiveNTTransact";
364 return "(A2)ReceiveNTCreateX";
366 return "(A4)ReceiveNTCancel";
368 return "(A5)ReceiveNTRename";
370 return "(C0)OpenPrintFile";
372 return "(C1)WritePrintFile";
374 return "(C2)ClosePrintFile";
376 return "(C3)GetPrintQueue";
378 return "(D8)ReadBulk";
380 return "(D9)WriteBulk";
382 return "(DA)WriteBulkData";
384 return "unknown SMB op";
388 char * myCrt_2Dispatch(int i)
393 return "unknown SMB op-2";
395 return "S(00)CreateFile_ReceiveTran2Open";
397 return "S(01)FindFirst_ReceiveTran2SearchDir";
399 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
401 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
403 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
405 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
407 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
409 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
411 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
413 return "S(09)_ReceiveTran2FSCTL";
415 return "S(0a)_ReceiveTran2IOCTL";
417 return "S(0b)_ReceiveTran2FindNotifyFirst";
419 return "S(0c)_ReceiveTran2FindNotifyNext";
421 return "S(0d)_ReceiveTran2CreateDirectory";
423 return "S(0e)_ReceiveTran2SessionSetup";
425 return "S(0f)_QueryFileSystemInformationFid";
427 return "S(10)_ReceiveTran2GetDfsReferral";
429 return "S(11)_ReceiveTran2ReportDfsInconsistency";
433 char * myCrt_RapDispatch(int i)
438 return "unknown RAP OP";
440 return "RAP(0)NetShareEnum";
442 return "RAP(1)NetShareGetInfo";
444 return "RAP(13)NetServerGetInfo";
446 return "RAP(63)NetWkStaGetInfo";
450 /* scache must be locked */
451 unsigned int smb_Attributes(cm_scache_t *scp)
455 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
456 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
457 scp->fileType == CM_SCACHETYPE_INVALID)
459 attrs = SMB_ATTR_DIRECTORY;
460 #ifdef SPECIAL_FOLDERS
461 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
462 #endif /* SPECIAL_FOLDERS */
463 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
464 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
469 * We used to mark a file RO if it was in an RO volume, but that
470 * turns out to be impolitic in NT. See defect 10007.
473 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
474 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
476 if ((scp->unixModeBits & 0222) == 0)
477 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
483 /* Check if the named file/dir is a dotfile/dotdir */
484 /* String pointed to by lastComp can have leading slashes, but otherwise should have
485 no other patch components */
486 unsigned int smb_IsDotFile(char *lastComp) {
489 /* skip over slashes */
490 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
495 /* nulls, curdir and parent dir doesn't count */
501 if(*(s+1) == '.' && !*(s + 2))
508 static int ExtractBits(WORD bits, short start, short len)
515 num = bits << (16 - end);
516 num = num >> ((16 - end) + start);
521 void ShowUnixTime(char *FuncName, time_t unixTime)
526 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
528 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
529 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
531 int day, month, year, sec, min, hour;
534 day = ExtractBits(wDate, 0, 5);
535 month = ExtractBits(wDate, 5, 4);
536 year = ExtractBits(wDate, 9, 7) + 1980;
538 sec = ExtractBits(wTime, 0, 5);
539 min = ExtractBits(wTime, 5, 6);
540 hour = ExtractBits(wTime, 11, 5);
542 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
543 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
547 /* Determine if we are observing daylight savings time */
548 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
550 TIME_ZONE_INFORMATION timeZoneInformation;
551 SYSTEMTIME utc, local, localDST;
553 /* Get the time zone info. NT uses this to calc if we are in DST. */
554 GetTimeZoneInformation(&timeZoneInformation);
556 /* Return the daylight bias */
557 *pDstBias = timeZoneInformation.DaylightBias;
559 /* Return the bias */
560 *pBias = timeZoneInformation.Bias;
562 /* Now determine if DST is being observed */
564 /* Get the UTC (GMT) time */
567 /* Convert UTC time to local time using the time zone info. If we are
568 observing DST, the calculated local time will include this.
570 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
572 /* Set the daylight bias to 0. The daylight bias is the amount of change
573 * in time that we use for daylight savings time. By setting this to 0
574 * we cause there to be no change in time during daylight savings time.
576 timeZoneInformation.DaylightBias = 0;
578 /* Convert the utc time to local time again, but this time without any
579 adjustment for daylight savings time.
581 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
583 /* If the two times are different, then it means that the localDST that
584 we calculated includes the daylight bias, and therefore we are
585 observing daylight savings time.
587 *pDST = localDST.wHour != local.wHour;
591 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
593 BOOL dst; /* Will be TRUE if observing DST */
594 LONG dstBias; /* Offset from local time if observing DST */
595 LONG bias; /* Offset from GMT for local time */
598 * This function will adjust the last write time to compensate
599 * for two bugs in the smb client:
601 * 1) During Daylight Savings Time, the LastWriteTime is ahead
602 * in time by the DaylightBias (ignoring the sign - the
603 * DaylightBias is always stored as a negative number). If
604 * the DaylightBias is -60, then the LastWriteTime will be
605 * ahead by 60 minutes.
607 * 2) If the local time zone is a positive offset from GMT, then
608 * the LastWriteTime will be the correct local time plus the
609 * Bias (ignoring the sign - a positive offset from GMT is
610 * always stored as a negative Bias). If the Bias is -120,
611 * then the LastWriteTime will be ahead by 120 minutes.
613 * These bugs can occur at the same time.
616 GetTimeZoneInfo(&dst, &dstBias, &bias);
618 /* First adjust for DST */
620 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
622 /* Now adjust for a positive offset from GMT (a negative bias). */
624 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
627 #ifndef USE_NUMERIC_TIME_CONV
629 * Calculate the difference (in seconds) between local time and GMT.
630 * This enables us to convert file times to kludge-GMT.
636 struct tm gmt_tm, local_tm;
637 int days, hours, minutes, seconds;
640 gmt_tm = *(gmtime(&t));
641 local_tm = *(localtime(&t));
643 days = local_tm.tm_yday - gmt_tm.tm_yday;
644 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
645 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
646 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
650 #endif /* USE_NUMERIC_TIME_CONV */
652 #ifdef USE_NUMERIC_TIME_CONV
653 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
655 // Note that LONGLONG is a 64-bit value
658 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
659 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
660 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
663 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
668 time_t ersatz_unixTime;
671 * Must use kludge-GMT instead of real GMT.
672 * kludge-GMT is computed by adding time zone difference to localtime.
675 * ltp = gmtime(&unixTime);
677 ersatz_unixTime = unixTime - smb_NowTZ;
678 ltp = localtime(&ersatz_unixTime);
680 /* if we fail, make up something */
683 localJunk.tm_year = 89 - 20;
684 localJunk.tm_mon = 4;
685 localJunk.tm_mday = 12;
686 localJunk.tm_hour = 0;
687 localJunk.tm_min = 0;
688 localJunk.tm_sec = 0;
691 stm.wYear = ltp->tm_year + 1900;
692 stm.wMonth = ltp->tm_mon + 1;
693 stm.wDayOfWeek = ltp->tm_wday;
694 stm.wDay = ltp->tm_mday;
695 stm.wHour = ltp->tm_hour;
696 stm.wMinute = ltp->tm_min;
697 stm.wSecond = ltp->tm_sec;
698 stm.wMilliseconds = 0;
700 SystemTimeToFileTime(&stm, largeTimep);
702 #endif /* USE_NUMERIC_TIME_CONV */
704 #ifdef USE_NUMERIC_TIME_CONV
705 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
707 // Note that LONGLONG is a 64-bit value
710 ll = largeTimep->dwHighDateTime;
712 ll += largeTimep->dwLowDateTime;
714 ll -= 116444736000000000;
717 *unixTimep = (DWORD)ll;
719 #else /* USE_NUMERIC_TIME_CONV */
720 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
726 FileTimeToSystemTime(largeTimep, &stm);
728 lt.tm_year = stm.wYear - 1900;
729 lt.tm_mon = stm.wMonth - 1;
730 lt.tm_wday = stm.wDayOfWeek;
731 lt.tm_mday = stm.wDay;
732 lt.tm_hour = stm.wHour;
733 lt.tm_min = stm.wMinute;
734 lt.tm_sec = stm.wSecond;
737 save_timezone = _timezone;
738 _timezone += smb_NowTZ;
739 *unixTimep = mktime(<);
740 _timezone = save_timezone;
742 #endif /* USE_NUMERIC_TIME_CONV */
744 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
754 /* if we fail, make up something */
757 localJunk.tm_year = 89 - 20;
758 localJunk.tm_mon = 4;
759 localJunk.tm_mday = 12;
760 localJunk.tm_hour = 0;
761 localJunk.tm_min = 0;
762 localJunk.tm_sec = 0;
765 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
766 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
767 *searchTimep = (dosDate<<16) | dosTime;
770 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
772 unsigned short dosDate;
773 unsigned short dosTime;
776 dosDate = (unsigned short) (searchTime & 0xffff);
777 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
779 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
780 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
781 localTm.tm_mday = (dosDate) & 0x1f;
782 localTm.tm_hour = (dosTime>>11) & 0x1f;
783 localTm.tm_min = (dosTime >> 5) & 0x3f;
784 localTm.tm_sec = (dosTime & 0x1f) * 2;
785 localTm.tm_isdst = -1; /* compute whether DST in effect */
787 *unixTimep = mktime(&localTm);
790 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
792 time_t diff_t = unixTime - smb_localZero;
793 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
794 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
796 *dosUTimep = (afs_uint32)diff_t;
799 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
801 *unixTimep = dosTime + smb_localZero;
804 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
808 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
809 lock_ObtainWrite(&smb_rctLock);
810 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
811 if (vcp->magic != SMB_VC_MAGIC)
812 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
815 if (lsn == vcp->lsn && lana == vcp->lana &&
816 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
817 smb_HoldVCNoLock(vcp);
821 if (!vcp && (flags & SMB_FLAG_CREATE)) {
822 vcp = malloc(sizeof(*vcp));
823 memset(vcp, 0, sizeof(*vcp));
824 vcp->vcID = ++numVCs;
825 vcp->magic = SMB_VC_MAGIC;
826 vcp->refCount = 2; /* smb_allVCsp and caller */
829 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
830 vcp->nextp = smb_allVCsp;
832 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
837 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
838 /* We must obtain a challenge for extended auth
839 * in case the client negotiates smb v3
841 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
842 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
843 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
844 ULONG lsaRespSize = 0;
846 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
848 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
855 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
856 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
857 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
858 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
859 nts, ntsEx, lsaRespSize);
861 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
863 if (ntsEx == STATUS_SUCCESS) {
864 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
865 LsaFreeReturnBuffer(lsaResp);
868 * This will cause the subsequent authentication to fail but
869 * that is better than us dereferencing a NULL pointer and
872 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
876 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
878 if (numVCs >= CM_SESSION_RESERVED) {
880 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
883 lock_ReleaseWrite(&smb_rctLock);
884 lock_ReleaseWrite(&smb_globalLock);
888 int smb_IsStarMask(char *maskp)
893 for(i=0; i<11; i++) {
895 if (tc == '?' || tc == '*' || tc == '>')
901 void smb_ReleaseVCInternal(smb_vc_t *vcp)
908 if (vcp->refCount == 0) {
909 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
910 /* remove VCP from smb_deadVCsp */
911 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
917 lock_FinalizeMutex(&vcp->mx);
918 memset(vcp,0,sizeof(smb_vc_t));
921 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
925 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
926 avcp?"not ":"",vcp, vcp->refCount);
928 GenerateMiniDump(NULL);
930 /* This is a wrong. However, I suspect that there is an undercount
931 * and I don't want to release 1.4.1 in a state that will allow
932 * smb_vc_t objects to be deallocated while still in the
933 * smb_allVCsp list. The list is supposed to keep a reference
934 * to the smb_vc_t. Put it back.
941 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
943 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
944 smb_ReleaseVCInternal(vcp);
947 void smb_ReleaseVC(smb_vc_t *vcp)
949 lock_ObtainWrite(&smb_rctLock);
950 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
951 smb_ReleaseVCInternal(vcp);
952 lock_ReleaseWrite(&smb_rctLock);
955 void smb_HoldVCNoLock(smb_vc_t *vcp)
958 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
961 void smb_HoldVC(smb_vc_t *vcp)
963 lock_ObtainWrite(&smb_rctLock);
965 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
966 lock_ReleaseWrite(&smb_rctLock);
969 void smb_CleanupDeadVC(smb_vc_t *vcp)
977 smb_user_t *uidpIter;
978 smb_user_t *uidpNext;
982 lock_ObtainMutex(&vcp->mx);
983 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
984 lock_ReleaseMutex(&vcp->mx);
985 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
988 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
989 lock_ReleaseMutex(&vcp->mx);
990 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
992 lock_ObtainWrite(&smb_rctLock);
993 /* remove VCP from smb_allVCsp */
994 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
995 if ((*vcpp)->magic != SMB_VC_MAGIC)
996 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1000 vcp->nextp = smb_deadVCsp;
1002 /* Hold onto the reference until we are done with this function */
1007 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1008 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1010 if (fidpIter->delete)
1013 fid = fidpIter->fid;
1014 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1016 smb_HoldFIDNoLock(fidpIter);
1017 lock_ReleaseWrite(&smb_rctLock);
1019 smb_CloseFID(vcp, fidpIter, NULL, 0);
1020 smb_ReleaseFID(fidpIter);
1022 lock_ObtainWrite(&smb_rctLock);
1023 fidpNext = vcp->fidsp;
1026 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1027 tidpNext = tidpIter->nextp;
1028 if (tidpIter->delete)
1030 tidpIter->delete = 1;
1032 tid = tidpIter->tid;
1033 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1035 smb_HoldTIDNoLock(tidpIter);
1036 lock_ReleaseWrite(&smb_rctLock);
1038 smb_ReleaseTID(tidpIter);
1040 lock_ObtainWrite(&smb_rctLock);
1041 tidpNext = vcp->tidsp;
1044 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1045 uidpNext = uidpIter->nextp;
1046 if (uidpIter->delete)
1048 uidpIter->delete = 1;
1050 /* do not add an additional reference count for the smb_user_t
1051 * as the smb_vc_t already is holding a reference */
1052 lock_ReleaseWrite(&smb_rctLock);
1054 smb_ReleaseUID(uidpIter);
1056 lock_ObtainWrite(&smb_rctLock);
1057 uidpNext = vcp->usersp;
1060 /* The vcp is now on the deadVCsp list. We intentionally drop the
1061 * reference so that the refcount can reach 0 and we can delete it */
1062 smb_ReleaseVCNoLock(vcp);
1064 lock_ReleaseWrite(&smb_rctLock);
1065 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1068 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1072 lock_ObtainWrite(&smb_rctLock);
1074 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1075 if (tidp->refCount == 0 && tidp->delete) {
1077 lock_ReleaseWrite(&smb_rctLock);
1078 smb_ReleaseTID(tidp);
1079 lock_ObtainWrite(&smb_rctLock);
1083 if (tid == tidp->tid) {
1088 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1089 tidp = malloc(sizeof(*tidp));
1090 memset(tidp, 0, sizeof(*tidp));
1091 tidp->nextp = vcp->tidsp;
1094 smb_HoldVCNoLock(vcp);
1096 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1099 lock_ReleaseWrite(&smb_rctLock);
1103 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1108 void smb_ReleaseTID(smb_tid_t *tidp)
1115 lock_ObtainWrite(&smb_rctLock);
1116 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1117 if (tidp->refCount == 0 && (tidp->delete)) {
1118 ltpp = &tidp->vcp->tidsp;
1119 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1123 osi_assertx(tp != NULL, "null smb_tid_t");
1125 lock_FinalizeMutex(&tidp->mx);
1126 userp = tidp->userp; /* remember to drop ref later */
1128 smb_ReleaseVCNoLock(tidp->vcp);
1131 lock_ReleaseWrite(&smb_rctLock);
1133 cm_ReleaseUser(userp);
1136 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1138 smb_user_t *uidp = NULL;
1140 lock_ObtainWrite(&smb_rctLock);
1141 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1142 if (uid == uidp->userID) {
1144 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1146 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1150 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1151 uidp = malloc(sizeof(*uidp));
1152 memset(uidp, 0, sizeof(*uidp));
1153 uidp->nextp = vcp->usersp;
1154 uidp->refCount = 2; /* one for the vcp and one for the caller */
1156 smb_HoldVCNoLock(vcp);
1158 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1160 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1162 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1164 lock_ReleaseWrite(&smb_rctLock);
1168 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1170 smb_username_t *unp= NULL;
1172 lock_ObtainWrite(&smb_rctLock);
1173 for(unp = usernamesp; unp; unp = unp->nextp) {
1174 if (stricmp(unp->name, usern) == 0 &&
1175 stricmp(unp->machine, machine) == 0) {
1180 if (!unp && (flags & SMB_FLAG_CREATE)) {
1181 unp = malloc(sizeof(*unp));
1182 memset(unp, 0, sizeof(*unp));
1184 unp->nextp = usernamesp;
1185 unp->name = strdup(usern);
1186 unp->machine = strdup(machine);
1188 lock_InitializeMutex(&unp->mx, "username_t mutex");
1189 if (flags & SMB_FLAG_AFSLOGON)
1190 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1193 lock_ReleaseWrite(&smb_rctLock);
1197 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1199 smb_user_t *uidp= NULL;
1201 lock_ObtainWrite(&smb_rctLock);
1202 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1205 if (stricmp(uidp->unp->name, usern) == 0) {
1207 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1208 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1213 lock_ReleaseWrite(&smb_rctLock);
1217 void smb_ReleaseUsername(smb_username_t *unp)
1220 smb_username_t **lupp;
1221 cm_user_t *userp = NULL;
1222 time_t now = osi_Time();
1224 lock_ObtainWrite(&smb_rctLock);
1225 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1226 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1227 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1229 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1233 osi_assertx(up != NULL, "null smb_username_t");
1235 up->nextp = NULL; /* do not remove this */
1236 lock_FinalizeMutex(&unp->mx);
1242 lock_ReleaseWrite(&smb_rctLock);
1245 cm_ReleaseUser(userp);
1249 void smb_HoldUIDNoLock(smb_user_t *uidp)
1254 void smb_ReleaseUID(smb_user_t *uidp)
1258 smb_username_t *unp = NULL;
1260 lock_ObtainWrite(&smb_rctLock);
1261 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1262 if (uidp->refCount == 0) {
1263 lupp = &uidp->vcp->usersp;
1264 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1268 osi_assertx(up != NULL, "null smb_user_t");
1270 lock_FinalizeMutex(&uidp->mx);
1272 smb_ReleaseVCNoLock(uidp->vcp);
1276 lock_ReleaseWrite(&smb_rctLock);
1280 cm_ReleaseUserVCRef(unp->userp);
1281 smb_ReleaseUsername(unp);
1285 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1287 cm_user_t *up = NULL;
1292 lock_ObtainMutex(&uidp->mx);
1294 up = uidp->unp->userp;
1297 lock_ReleaseMutex(&uidp->mx);
1303 /* retrieve a held reference to a user structure corresponding to an incoming
1305 * corresponding release function is cm_ReleaseUser.
1307 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1310 cm_user_t *up = NULL;
1313 smbp = (smb_t *) inp;
1314 uidp = smb_FindUID(vcp, smbp->uid, 0);
1318 up = smb_GetUserFromUID(uidp);
1320 smb_ReleaseUID(uidp);
1325 * Return a pointer to a pathname extracted from a TID structure. The
1326 * TID structure is not held; assume it won't go away.
1328 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1333 tidp = smb_FindTID(vcp, tid, 0);
1337 if (tidp->flags & SMB_TIDFLAG_IPC) {
1338 code = CM_ERROR_TIDIPC;
1339 /* tidp->pathname would be NULL, but that's fine */
1341 *treepath = tidp->pathname;
1342 smb_ReleaseTID(tidp);
1347 /* check to see if we have a chained fid, that is, a fid that comes from an
1348 * OpenAndX message that ran earlier in this packet. In this case, the fid
1349 * field in a read, for example, request, isn't set, since the value is
1350 * supposed to be inherited from the openAndX call.
1352 int smb_ChainFID(int fid, smb_packet_t *inp)
1354 if (inp->fid == 0 || inp->inCount == 0)
1360 /* are we a priv'd user? What does this mean on NT? */
1361 int smb_SUser(cm_user_t *userp)
1366 /* find a file ID. If we pass in 0 we select an unused File ID.
1367 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1368 * smb_fid_t data structure if desired File ID cannot be found.
1370 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1375 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1378 lock_ObtainWrite(&smb_rctLock);
1379 /* figure out if we need to allocate a new file ID */
1382 fid = vcp->fidCounter;
1386 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1387 if (fidp->refCount == 0 && fidp->delete) {
1389 lock_ReleaseWrite(&smb_rctLock);
1390 smb_ReleaseFID(fidp);
1391 lock_ObtainWrite(&smb_rctLock);
1394 if (fid == fidp->fid) {
1397 if (fid == 0xFFFF) {
1399 "New FID number wraps on vcp 0x%x", vcp);
1409 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1410 char eventName[MAX_PATH];
1412 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1413 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1414 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1415 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1416 thrd_CloseHandle(event);
1418 if (fid == 0xFFFF) {
1419 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1425 fidp = malloc(sizeof(*fidp));
1426 memset(fidp, 0, sizeof(*fidp));
1427 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1430 smb_HoldVCNoLock(vcp);
1431 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1433 fidp->curr_chunk = fidp->prev_chunk = -2;
1434 fidp->raw_write_event = event;
1436 vcp->fidCounter = fid+1;
1437 if (vcp->fidCounter == 0xFFFF) {
1438 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1440 vcp->fidCounter = 1;
1445 lock_ReleaseWrite(&smb_rctLock);
1449 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1451 smb_fid_t *fidp = NULL;
1457 lock_ObtainWrite(&smb_rctLock);
1458 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1459 if (scp == fidp->scp) {
1464 lock_ReleaseWrite(&smb_rctLock);
1468 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1474 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1475 /* the sm_fid_t->mx and smb_rctLock must not be held */
1476 void smb_ReleaseFID(smb_fid_t *fidp)
1478 cm_scache_t *scp = NULL;
1479 cm_user_t *userp = NULL;
1480 smb_vc_t *vcp = NULL;
1481 smb_ioctl_t *ioctlp;
1483 lock_ObtainMutex(&fidp->mx);
1484 lock_ObtainWrite(&smb_rctLock);
1485 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1486 if (fidp->refCount == 0 && (fidp->delete)) {
1489 scp = fidp->scp; /* release after lock is released */
1491 lock_ObtainMutex(&scp->mx);
1492 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1493 lock_ReleaseMutex(&scp->mx);
1494 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1497 userp = fidp->userp;
1501 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1502 thrd_CloseHandle(fidp->raw_write_event);
1504 /* and see if there is ioctl stuff to free */
1505 ioctlp = fidp->ioctlp;
1508 cm_FreeSpace(ioctlp->prefix);
1509 if (ioctlp->inAllocp)
1510 free(ioctlp->inAllocp);
1511 if (ioctlp->outAllocp)
1512 free(ioctlp->outAllocp);
1515 lock_ReleaseMutex(&fidp->mx);
1516 lock_FinalizeMutex(&fidp->mx);
1520 smb_ReleaseVCNoLock(vcp);
1522 lock_ReleaseMutex(&fidp->mx);
1524 lock_ReleaseWrite(&smb_rctLock);
1526 /* now release the scache structure */
1528 cm_ReleaseSCache(scp);
1531 cm_ReleaseUser(userp);
1535 * Case-insensitive search for one string in another;
1536 * used to find variable names in submount pathnames.
1538 static char *smb_stristr(char *str1, char *str2)
1542 for (cursor = str1; *cursor; cursor++)
1543 if (stricmp(cursor, str2) == 0)
1550 * Substitute a variable value for its name in a submount pathname. Variable
1551 * name has been identified by smb_stristr() and is in substr. Variable name
1552 * length (plus one) is in substr_size. Variable value is in newstr.
1554 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1559 strcpy(temp, substr + substr_size - 1);
1560 strcpy(substr, newstr);
1564 char VNUserName[] = "%USERNAME%";
1565 char VNLCUserName[] = "%LCUSERNAME%";
1566 char VNComputerName[] = "%COMPUTERNAME%";
1567 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1570 typedef struct smb_findShare_rock {
1574 } smb_findShare_rock_t;
1576 #define SMB_FINDSHARE_EXACT_MATCH 1
1577 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1579 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1583 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1584 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1585 if(!stricmp(dep->name, vrock->shareName))
1586 matchType = SMB_FINDSHARE_EXACT_MATCH;
1588 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1589 if(vrock->match) free(vrock->match);
1590 vrock->match = strdup(dep->name);
1591 vrock->matchType = matchType;
1593 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1594 return CM_ERROR_STOPNOW;
1600 /* find a shareName in the table of submounts */
1601 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1605 char pathName[1024];
1612 DWORD allSubmount = 1;
1614 /* if allSubmounts == 0, only return the //mountRoot/all share
1615 * if in fact it has been been created in the subMounts table.
1616 * This is to allow sites that want to restrict access to the
1619 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1620 0, KEY_QUERY_VALUE, &parmKey);
1621 if (code == ERROR_SUCCESS) {
1622 len = sizeof(allSubmount);
1623 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1624 (BYTE *) &allSubmount, &len);
1625 if (code != ERROR_SUCCESS) {
1628 RegCloseKey (parmKey);
1631 if (allSubmount && _stricmp(shareName, "all") == 0) {
1636 /* In case, the all share is disabled we need to still be able
1637 * to handle ioctl requests
1639 if (_stricmp(shareName, "ioctl$") == 0) {
1640 *pathNamep = strdup("/.__ioctl__");
1644 if (_stricmp(shareName, "IPC$") == 0 ||
1645 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1646 _stricmp(shareName, "DESKTOP.INI") == 0
1652 /* Check for volume references
1654 * They look like <cell>{%,#}<volume>
1656 if (strchr(shareName, '%') != NULL ||
1657 strchr(shareName, '#') != NULL) {
1658 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1659 /* make room for '/@vol:' + mountchar + NULL terminator*/
1661 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1662 osi_LogSaveString(smb_logp, shareName));
1664 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1665 "/" CM_PREFIX_VOL "%s", shareName);
1666 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1667 len = strlen(pathstr) + 1;
1669 *pathNamep = malloc(len);
1671 strcpy(*pathNamep, pathstr);
1673 osi_Log1(smb_logp, " returning pathname [%s]",
1674 osi_LogSaveString(smb_logp, *pathNamep));
1682 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1683 0, KEY_QUERY_VALUE, &parmKey);
1684 if (code == ERROR_SUCCESS) {
1685 len = sizeof(pathName);
1686 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1687 (BYTE *) pathName, &len);
1688 if (code != ERROR_SUCCESS)
1690 RegCloseKey (parmKey);
1694 if (len != 0 && len != sizeof(pathName) - 1) {
1695 /* We can accept either unix or PC style AFS pathnames. Convert
1696 * Unix-style to PC style here for internal use.
1699 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1700 p += strlen(cm_mountRoot); /* skip mount path */
1703 if (*q == '/') *q = '\\'; /* change to \ */
1709 if (var = smb_stristr(p, VNUserName)) {
1710 if (uidp && uidp->unp)
1711 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1713 smb_subst(p, var, sizeof(VNUserName)," ");
1715 else if (var = smb_stristr(p, VNLCUserName))
1717 if (uidp && uidp->unp)
1718 strcpy(temp, uidp->unp->name);
1722 smb_subst(p, var, sizeof(VNLCUserName), temp);
1724 else if (var = smb_stristr(p, VNComputerName))
1726 sizeTemp = sizeof(temp);
1727 GetComputerName((LPTSTR)temp, &sizeTemp);
1728 smb_subst(p, var, sizeof(VNComputerName), temp);
1730 else if (var = smb_stristr(p, VNLCComputerName))
1732 sizeTemp = sizeof(temp);
1733 GetComputerName((LPTSTR)temp, &sizeTemp);
1735 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1740 *pathNamep = strdup(p);
1745 /* First lookup shareName in root.afs */
1747 smb_findShare_rock_t vrock;
1749 char * p = shareName;
1752 /* attempt to locate a partial match in root.afs. This is because
1753 when using the ANSI RAP calls, the share name is limited to 13 chars
1754 and hence is truncated. Of course we prefer exact matches. */
1756 thyper.HighPart = 0;
1759 vrock.shareName = shareName;
1761 vrock.matchType = 0;
1763 cm_HoldSCache(cm_data.rootSCachep);
1764 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1765 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1766 cm_ReleaseSCache(cm_data.rootSCachep);
1768 if (vrock.matchType) {
1769 sprintf(pathName,"/%s/",vrock.match);
1770 *pathNamep = strdup(strlwr(pathName));
1775 /* if we get here, there was no match for the share in root.afs */
1776 /* so try to create \\<netbiosName>\<cellname> */
1781 /* Get the full name for this cell */
1782 code = cm_SearchCellFile(p, temp, 0, 0);
1783 #ifdef AFS_AFSDB_ENV
1784 if (code && cm_dnsEnabled) {
1786 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1789 /* construct the path */
1791 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1792 *pathNamep = strdup(strlwr(pathName));
1801 /* Client-side offline caching policy types */
1802 #define CSC_POLICY_MANUAL 0
1803 #define CSC_POLICY_DOCUMENTS 1
1804 #define CSC_POLICY_PROGRAMS 2
1805 #define CSC_POLICY_DISABLE 3
1807 int smb_FindShareCSCPolicy(char *shareName)
1813 int retval = CSC_POLICY_MANUAL;
1815 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1816 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1819 REG_OPTION_NON_VOLATILE,
1825 len = sizeof(policy);
1826 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1828 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1830 else if (stricmp(policy, "documents") == 0)
1832 retval = CSC_POLICY_DOCUMENTS;
1834 else if (stricmp(policy, "programs") == 0)
1836 retval = CSC_POLICY_PROGRAMS;
1838 else if (stricmp(policy, "disable") == 0)
1840 retval = CSC_POLICY_DISABLE;
1843 RegCloseKey(hkCSCPolicy);
1847 /* find a dir search structure by cookie value, and return it held.
1848 * Must be called with smb_globalLock held.
1850 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1852 smb_dirSearch_t *dsp;
1854 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1855 if (dsp->cookie == cookie) {
1856 if (dsp != smb_firstDirSearchp) {
1857 /* move to head of LRU queue, too, if we're not already there */
1858 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1859 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1860 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1861 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1862 if (!smb_lastDirSearchp)
1863 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1865 lock_ObtainMutex(&dsp->mx);
1867 lock_ReleaseMutex(&dsp->mx);
1873 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1874 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1875 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1881 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1883 lock_ObtainWrite(&smb_globalLock);
1884 lock_ObtainMutex(&dsp->mx);
1885 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1886 dsp->cookie, dsp, dsp->scp);
1887 dsp->flags |= SMB_DIRSEARCH_DELETE;
1888 if (dsp->scp != NULL) {
1889 lock_ObtainMutex(&dsp->scp->mx);
1890 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1891 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1892 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1893 dsp->scp->bulkStatProgress = hzero;
1895 lock_ReleaseMutex(&dsp->scp->mx);
1897 lock_ReleaseMutex(&dsp->mx);
1898 lock_ReleaseWrite(&smb_globalLock);
1901 /* Must be called with the smb_globalLock held */
1902 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1904 cm_scache_t *scp = NULL;
1906 lock_ObtainMutex(&dsp->mx);
1907 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1908 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1909 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1910 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1911 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1912 lock_ReleaseMutex(&dsp->mx);
1913 lock_FinalizeMutex(&dsp->mx);
1915 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1916 dsp->cookie, dsp, scp);
1919 lock_ReleaseMutex(&dsp->mx);
1921 /* do this now to avoid spurious locking hierarchy creation */
1923 cm_ReleaseSCache(scp);
1926 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1928 lock_ObtainWrite(&smb_globalLock);
1929 smb_ReleaseDirSearchNoLock(dsp);
1930 lock_ReleaseWrite(&smb_globalLock);
1933 /* find a dir search structure by cookie value, and return it held */
1934 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1936 smb_dirSearch_t *dsp;
1938 lock_ObtainWrite(&smb_globalLock);
1939 dsp = smb_FindDirSearchNoLock(cookie);
1940 lock_ReleaseWrite(&smb_globalLock);
1944 /* GC some dir search entries, in the address space expected by the specific protocol.
1945 * Must be called with smb_globalLock held; release the lock temporarily.
1947 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1948 void smb_GCDirSearches(int isV3)
1950 smb_dirSearch_t *prevp;
1951 smb_dirSearch_t *tp;
1952 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1956 victimCount = 0; /* how many have we got so far */
1957 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1958 /* we'll move tp from queue, so
1961 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1962 /* if no one is using this guy, and we're either in the new protocol,
1963 * or we're in the old one and this is a small enough ID to be useful
1964 * to the old protocol, GC this guy.
1966 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1967 /* hold and delete */
1968 lock_ObtainMutex(&tp->mx);
1969 tp->flags |= SMB_DIRSEARCH_DELETE;
1970 lock_ReleaseMutex(&tp->mx);
1971 victimsp[victimCount++] = tp;
1975 /* don't do more than this */
1976 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1980 /* now release them */
1981 for (i = 0; i < victimCount; i++) {
1982 smb_ReleaseDirSearchNoLock(victimsp[i]);
1986 /* function for allocating a dir search entry. We need these to remember enough context
1987 * since we don't get passed the path from call to call during a directory search.
1989 * Returns a held dir search structure, and bumps the reference count on the vnode,
1990 * since it saves a pointer to the vnode.
1992 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1994 smb_dirSearch_t *dsp;
2000 lock_ObtainWrite(&smb_globalLock);
2003 /* what's the biggest ID allowed in this version of the protocol */
2004 /* TODO: do we really want a non v3 dir search request to wrap
2005 smb_dirSearchCounter? */
2006 maxAllowed = isV3 ? 65535 : 255;
2007 if (smb_dirSearchCounter > maxAllowed)
2008 smb_dirSearchCounter = 1;
2010 start = smb_dirSearchCounter;
2013 /* twice so we have enough tries to find guys we GC after one pass;
2014 * 10 extra is just in case I mis-counted.
2016 if (++counter > 2*maxAllowed+10)
2017 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2019 if (smb_dirSearchCounter > maxAllowed) {
2020 smb_dirSearchCounter = 1;
2022 if (smb_dirSearchCounter == start) {
2024 smb_GCDirSearches(isV3);
2027 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2029 /* don't need to watch for refcount zero and deleted, since
2030 * we haven't dropped the global lock.
2032 lock_ObtainMutex(&dsp->mx);
2034 lock_ReleaseMutex(&dsp->mx);
2035 ++smb_dirSearchCounter;
2039 dsp = malloc(sizeof(*dsp));
2040 memset(dsp, 0, sizeof(*dsp));
2041 dsp->cookie = smb_dirSearchCounter;
2042 ++smb_dirSearchCounter;
2044 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2045 dsp->lastTime = osi_Time();
2046 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2047 if (!smb_lastDirSearchp)
2048 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2050 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2054 lock_ReleaseWrite(&smb_globalLock);
2058 static smb_packet_t *GetPacket(void)
2062 lock_ObtainWrite(&smb_globalLock);
2063 tbp = smb_packetFreeListp;
2065 smb_packetFreeListp = tbp->nextp;
2066 lock_ReleaseWrite(&smb_globalLock);
2068 tbp = calloc(65540,1);
2069 tbp->magic = SMB_PACKETMAGIC;
2072 tbp->resumeCode = 0;
2078 tbp->ncb_length = 0;
2083 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2088 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2092 memcpy(tbp, pkt, sizeof(smb_packet_t));
2093 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2095 smb_HoldVC(tbp->vcp);
2099 static NCB *GetNCB(void)
2104 lock_ObtainWrite(&smb_globalLock);
2105 tbp = smb_ncbFreeListp;
2107 smb_ncbFreeListp = tbp->nextp;
2108 lock_ReleaseWrite(&smb_globalLock);
2110 tbp = calloc(sizeof(*tbp),1);
2111 tbp->magic = SMB_NCBMAGIC;
2114 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2116 memset(&tbp->ncb, 0, sizeof(NCB));
2121 void smb_FreePacket(smb_packet_t *tbp)
2123 smb_vc_t * vcp = NULL;
2124 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2126 lock_ObtainWrite(&smb_globalLock);
2127 tbp->nextp = smb_packetFreeListp;
2128 smb_packetFreeListp = tbp;
2129 tbp->magic = SMB_PACKETMAGIC;
2133 tbp->resumeCode = 0;
2139 tbp->ncb_length = 0;
2141 lock_ReleaseWrite(&smb_globalLock);
2147 static void FreeNCB(NCB *bufferp)
2151 tbp = (smb_ncb_t *) bufferp;
2152 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2154 lock_ObtainWrite(&smb_globalLock);
2155 tbp->nextp = smb_ncbFreeListp;
2156 smb_ncbFreeListp = tbp;
2157 lock_ReleaseWrite(&smb_globalLock);
2160 /* get a ptr to the data part of a packet, and its count */
2161 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2165 unsigned char *afterParmsp;
2167 parmBytes = *smbp->wctp << 1;
2168 afterParmsp = smbp->wctp + parmBytes + 1;
2170 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2171 if (nbytesp) *nbytesp = dataBytes;
2173 /* don't forget to skip the data byte count, since it follows
2174 * the parameters; that's where the "2" comes from below.
2176 return (unsigned char *) (afterParmsp + 2);
2179 /* must set all the returned parameters before playing around with the
2180 * data region, since the data region is located past the end of the
2181 * variable number of parameters.
2183 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2185 unsigned char *afterParmsp;
2187 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2189 *afterParmsp++ = dsize & 0xff;
2190 *afterParmsp = (dsize>>8) & 0xff;
2193 /* return the parm'th parameter in the smbp packet */
2194 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2197 unsigned char *parmDatap;
2199 parmCount = *smbp->wctp;
2201 if (parm >= parmCount) {
2204 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2205 parm, parmCount, smbp->ncb_length);
2206 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2207 parm, parmCount, smbp->ncb_length);
2208 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2209 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2210 osi_panic(s, __FILE__, __LINE__);
2212 parmDatap = smbp->wctp + (2*parm) + 1;
2214 return parmDatap[0] + (parmDatap[1] << 8);
2217 /* return the parm'th parameter in the smbp packet */
2218 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2221 unsigned char *parmDatap;
2223 parmCount = *smbp->wctp;
2225 if (parm >= parmCount) {
2228 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2229 parm, parmCount, smbp->ncb_length);
2230 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2231 parm, parmCount, smbp->ncb_length);
2232 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2233 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2234 osi_panic(s, __FILE__, __LINE__);
2236 parmDatap = smbp->wctp + (2*parm) + 1;
2238 return parmDatap[0];
2241 /* return the parm'th parameter in the smbp packet */
2242 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2245 unsigned char *parmDatap;
2247 parmCount = *smbp->wctp;
2249 if (parm + 1 >= parmCount) {
2252 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2253 parm, parmCount, smbp->ncb_length);
2254 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2255 parm, parmCount, smbp->ncb_length);
2256 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2257 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2258 osi_panic(s, __FILE__, __LINE__);
2260 parmDatap = smbp->wctp + (2*parm) + 1;
2262 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2265 /* return the parm'th parameter in the smbp packet */
2266 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2269 unsigned char *parmDatap;
2271 parmCount = *smbp->wctp;
2273 if (parm * 2 + offset >= parmCount * 2) {
2276 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2277 parm, offset, parmCount, smbp->ncb_length);
2278 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2279 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2280 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2281 parm, offset, parmCount, smbp->ncb_length);
2282 osi_panic(s, __FILE__, __LINE__);
2284 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2286 return parmDatap[0] + (parmDatap[1] << 8);
2289 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2293 /* make sure we have enough slots */
2294 if (*smbp->wctp <= slot)
2295 *smbp->wctp = slot+1;
2297 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2298 *parmDatap++ = parmValue & 0xff;
2299 *parmDatap = (parmValue>>8) & 0xff;
2302 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2306 /* make sure we have enough slots */
2307 if (*smbp->wctp <= slot)
2308 *smbp->wctp = slot+2;
2310 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2311 *parmDatap++ = parmValue & 0xff;
2312 *parmDatap++ = (parmValue>>8) & 0xff;
2313 *parmDatap++ = (parmValue>>16) & 0xff;
2314 *parmDatap = (parmValue>>24) & 0xff;
2317 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2322 /* make sure we have enough slots */
2323 if (*smbp->wctp <= slot)
2324 *smbp->wctp = slot+4;
2326 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2328 *parmDatap++ = *parmValuep++;
2331 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2335 /* make sure we have enough slots */
2336 if (*smbp->wctp <= slot) {
2337 if (smbp->oddByte) {
2339 *smbp->wctp = slot+1;
2344 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2345 *parmDatap++ = parmValue & 0xff;
2348 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2352 lastSlashp = strrchr(inPathp, '\\');
2354 *lastComponentp = lastSlashp;
2357 if (inPathp == lastSlashp)
2359 *outPathp++ = *inPathp++;
2368 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2373 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2378 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2384 tlen = inp[0] + (inp[1]<<8);
2385 inp += 2; /* skip length field */
2388 *chainpp = inp + tlen;
2397 /* format a packet as a response */
2398 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2403 outp = (smb_t *) op;
2405 /* zero the basic structure through the smb_wct field, and zero the data
2406 * size field, assuming that wct stays zero; otherwise, you have to
2407 * explicitly set the data size field, too.
2409 inSmbp = (smb_t *) inp;
2410 memset(outp, 0, sizeof(smb_t)+2);
2416 outp->com = inSmbp->com;
2417 outp->tid = inSmbp->tid;
2418 outp->pid = inSmbp->pid;
2419 outp->uid = inSmbp->uid;
2420 outp->mid = inSmbp->mid;
2421 outp->res[0] = inSmbp->res[0];
2422 outp->res[1] = inSmbp->res[1];
2423 op->inCom = inSmbp->com;
2425 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2426 #ifdef SEND_CANONICAL_PATHNAMES
2427 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2429 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2431 /* copy fields in generic packet area */
2432 op->wctp = &outp->wct;
2435 /* send a (probably response) packet; vcp tells us to whom to send it.
2436 * we compute the length by looking at wct and bcc fields.
2438 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2452 memset((char *)ncbp, 0, sizeof(NCB));
2454 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2455 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2456 extra += tp[0] + (tp[1]<<8);
2457 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2458 extra += 3; /* wct and length fields */
2460 ncbp->ncb_length = extra; /* bytes to send */
2461 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2462 ncbp->ncb_lana_num = vcp->lana;
2463 ncbp->ncb_command = NCBSEND; /* op means send data */
2464 ncbp->ncb_buffer = (char *) inp;/* packet */
2465 code = Netbios(ncbp);
2468 const char * s = ncb_error_string(code);
2469 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2470 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2472 lock_ObtainMutex(&vcp->mx);
2473 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2474 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2476 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2477 lock_ReleaseMutex(&vcp->mx);
2478 lock_ObtainWrite(&smb_globalLock);
2479 dead_sessions[vcp->session] = TRUE;
2480 lock_ReleaseWrite(&smb_globalLock);
2481 smb_CleanupDeadVC(vcp);
2483 lock_ReleaseMutex(&vcp->mx);
2491 void smb_MapNTError(long code, unsigned long *NTStatusp)
2493 unsigned long NTStatus;
2495 /* map CM_ERROR_* errors to NT 32-bit status codes */
2496 /* NT Status codes are listed in ntstatus.h not winerror.h */
2497 if (code == CM_ERROR_NOSUCHCELL) {
2498 NTStatus = 0xC000000FL; /* No such file */
2500 else if (code == CM_ERROR_NOSUCHVOLUME) {
2501 NTStatus = 0xC000000FL; /* No such file */
2503 else if (code == CM_ERROR_TIMEDOUT) {
2505 NTStatus = 0xC00000CFL; /* Sharing Paused */
2507 NTStatus = 0x00000102L; /* Timeout */
2510 else if (code == CM_ERROR_RETRY) {
2511 NTStatus = 0xC000022DL; /* Retry */
2513 else if (code == CM_ERROR_NOACCESS) {
2514 NTStatus = 0xC0000022L; /* Access denied */
2516 else if (code == CM_ERROR_READONLY) {
2517 NTStatus = 0xC00000A2L; /* Write protected */
2519 else if (code == CM_ERROR_NOSUCHFILE ||
2520 code == CM_ERROR_BPLUS_NOMATCH) {
2521 NTStatus = 0xC000000FL; /* No such file */
2523 else if (code == CM_ERROR_NOSUCHPATH) {
2524 NTStatus = 0xC000003AL; /* Object path not found */
2526 else if (code == CM_ERROR_TOOBIG) {
2527 NTStatus = 0xC000007BL; /* Invalid image format */
2529 else if (code == CM_ERROR_INVAL) {
2530 NTStatus = 0xC000000DL; /* Invalid parameter */
2532 else if (code == CM_ERROR_BADFD) {
2533 NTStatus = 0xC0000008L; /* Invalid handle */
2535 else if (code == CM_ERROR_BADFDOP) {
2536 NTStatus = 0xC0000022L; /* Access denied */
2538 else if (code == CM_ERROR_EXISTS) {
2539 NTStatus = 0xC0000035L; /* Object name collision */
2541 else if (code == CM_ERROR_NOTEMPTY) {
2542 NTStatus = 0xC0000101L; /* Directory not empty */
2544 else if (code == CM_ERROR_CROSSDEVLINK) {
2545 NTStatus = 0xC00000D4L; /* Not same device */
2547 else if (code == CM_ERROR_NOTDIR) {
2548 NTStatus = 0xC0000103L; /* Not a directory */
2550 else if (code == CM_ERROR_ISDIR) {
2551 NTStatus = 0xC00000BAL; /* File is a directory */
2553 else if (code == CM_ERROR_BADOP) {
2555 /* I have no idea where this comes from */
2556 NTStatus = 0xC09820FFL; /* SMB no support */
2558 NTStatus = 0xC00000BBL; /* Not supported */
2559 #endif /* COMMENT */
2561 else if (code == CM_ERROR_BADSHARENAME) {
2562 NTStatus = 0xC00000CCL; /* Bad network name */
2564 else if (code == CM_ERROR_NOIPC) {
2566 NTStatus = 0xC0000022L; /* Access Denied */
2568 NTStatus = 0xC000013DL; /* Remote Resources */
2571 else if (code == CM_ERROR_CLOCKSKEW) {
2572 NTStatus = 0xC0000133L; /* Time difference at DC */
2574 else if (code == CM_ERROR_BADTID) {
2575 NTStatus = 0xC0982005L; /* SMB bad TID */
2577 else if (code == CM_ERROR_USESTD) {
2578 NTStatus = 0xC09820FBL; /* SMB use standard */
2580 else if (code == CM_ERROR_QUOTA) {
2582 NTStatus = 0xC0000044L; /* Quota exceeded */
2584 NTStatus = 0xC000007FL; /* Disk full */
2587 else if (code == CM_ERROR_SPACE) {
2588 NTStatus = 0xC000007FL; /* Disk full */
2590 else if (code == CM_ERROR_ATSYS) {
2591 NTStatus = 0xC0000033L; /* Object name invalid */
2593 else if (code == CM_ERROR_BADNTFILENAME) {
2594 NTStatus = 0xC0000033L; /* Object name invalid */
2596 else if (code == CM_ERROR_WOULDBLOCK) {
2597 NTStatus = 0xC0000055L; /* Lock not granted */
2599 else if (code == CM_ERROR_SHARING_VIOLATION) {
2600 NTStatus = 0xC0000043L; /* Sharing violation */
2602 else if (code == CM_ERROR_LOCK_CONFLICT) {
2603 NTStatus = 0xC0000054L; /* Lock conflict */
2605 else if (code == CM_ERROR_PARTIALWRITE) {
2606 NTStatus = 0xC000007FL; /* Disk full */
2608 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2609 NTStatus = 0xC0000023L; /* Buffer too small */
2611 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2612 NTStatus = 0xC0000035L; /* Object name collision */
2614 else if (code == CM_ERROR_BADPASSWORD) {
2615 NTStatus = 0xC000006DL; /* unknown username or bad password */
2617 else if (code == CM_ERROR_BADLOGONTYPE) {
2618 NTStatus = 0xC000015BL; /* logon type not granted */
2620 else if (code == CM_ERROR_GSSCONTINUE) {
2621 NTStatus = 0xC0000016L; /* more processing required */
2623 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2625 NTStatus = 0xC0000280L; /* reparse point not resolved */
2627 NTStatus = 0xC0000022L; /* Access Denied */
2630 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2631 NTStatus = 0xC0000257L; /* Path Not Covered */
2634 else if (code == CM_ERROR_ALLBUSY) {
2635 NTStatus = 0xC00000BFL; /* Network Busy */
2637 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2638 NTStatus = 0xC0000350L; /* Remote Host Down */
2641 /* we do not want to be telling the SMB/CIFS client that
2642 * the AFS Client Service is busy or down.
2644 else if (code == CM_ERROR_ALLBUSY ||
2645 code == CM_ERROR_ALLOFFLINE ||
2646 code == CM_ERROR_ALLDOWN) {
2647 NTStatus = 0xC00000BEL; /* Bad Network Path */
2650 else if (code == RXKADUNKNOWNKEY) {
2651 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2653 else if (code == CM_ERROR_BAD_LEVEL) {
2654 NTStatus = 0xC0000148L; /* Invalid Level */
2656 NTStatus = 0xC0982001L; /* SMB non-specific error */
2659 *NTStatusp = NTStatus;
2660 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2663 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2664 unsigned char *classp)
2666 unsigned char class;
2667 unsigned short error;
2669 /* map CM_ERROR_* errors to SMB errors */
2670 if (code == CM_ERROR_NOSUCHCELL) {
2672 error = 3; /* bad path */
2674 else if (code == CM_ERROR_NOSUCHVOLUME) {
2676 error = 3; /* bad path */
2678 else if (code == CM_ERROR_TIMEDOUT) {
2680 error = 81; /* server is paused */
2682 else if (code == CM_ERROR_RETRY) {
2683 class = 2; /* shouldn't happen */
2686 else if (code == CM_ERROR_NOACCESS) {
2688 error = 4; /* bad access */
2690 else if (code == CM_ERROR_READONLY) {
2692 error = 19; /* read only */
2694 else if (code == CM_ERROR_NOSUCHFILE ||
2695 code == CM_ERROR_BPLUS_NOMATCH) {
2697 error = 2; /* ENOENT! */
2699 else if (code == CM_ERROR_NOSUCHPATH) {
2701 error = 3; /* Bad path */
2703 else if (code == CM_ERROR_TOOBIG) {
2705 error = 11; /* bad format */
2707 else if (code == CM_ERROR_INVAL) {
2708 class = 2; /* server non-specific error code */
2711 else if (code == CM_ERROR_BADFD) {
2713 error = 6; /* invalid file handle */
2715 else if (code == CM_ERROR_BADFDOP) {
2716 class = 1; /* invalid op on FD */
2719 else if (code == CM_ERROR_EXISTS) {
2721 error = 80; /* file already exists */
2723 else if (code == CM_ERROR_NOTEMPTY) {
2725 error = 5; /* delete directory not empty */
2727 else if (code == CM_ERROR_CROSSDEVLINK) {
2729 error = 17; /* EXDEV */
2731 else if (code == CM_ERROR_NOTDIR) {
2732 class = 1; /* bad path */
2735 else if (code == CM_ERROR_ISDIR) {
2736 class = 1; /* access denied; DOS doesn't have a good match */
2739 else if (code == CM_ERROR_BADOP) {
2743 else if (code == CM_ERROR_BADSHARENAME) {
2747 else if (code == CM_ERROR_NOIPC) {
2749 error = 4; /* bad access */
2751 else if (code == CM_ERROR_CLOCKSKEW) {
2752 class = 1; /* invalid function */
2755 else if (code == CM_ERROR_BADTID) {
2759 else if (code == CM_ERROR_USESTD) {
2763 else if (code == CM_ERROR_REMOTECONN) {
2767 else if (code == CM_ERROR_QUOTA) {
2768 if (vcp->flags & SMB_VCFLAG_USEV3) {
2770 error = 39; /* disk full */
2774 error = 5; /* access denied */
2777 else if (code == CM_ERROR_SPACE) {
2778 if (vcp->flags & SMB_VCFLAG_USEV3) {
2780 error = 39; /* disk full */
2784 error = 5; /* access denied */
2787 else if (code == CM_ERROR_PARTIALWRITE) {
2789 error = 39; /* disk full */
2791 else if (code == CM_ERROR_ATSYS) {
2793 error = 2; /* ENOENT */
2795 else if (code == CM_ERROR_WOULDBLOCK) {
2797 error = 33; /* lock conflict */
2799 else if (code == CM_ERROR_LOCK_CONFLICT) {
2801 error = 33; /* lock conflict */
2803 else if (code == CM_ERROR_SHARING_VIOLATION) {
2805 error = 33; /* lock conflict */
2807 else if (code == CM_ERROR_NOFILES) {
2809 error = 18; /* no files in search */
2811 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2813 error = 183; /* Samba uses this */
2815 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2816 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2818 error = 2; /* bad password */
2820 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2822 error = 3; /* bad path */
2831 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2834 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2836 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2837 return CM_ERROR_BADOP;
2840 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2842 unsigned short EchoCount, i;
2843 char *data, *outdata;
2846 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2848 for (i=1; i<=EchoCount; i++) {
2849 data = smb_GetSMBData(inp, &dataSize);
2850 smb_SetSMBParm(outp, 0, i);
2851 smb_SetSMBDataLength(outp, dataSize);
2852 outdata = smb_GetSMBData(outp, NULL);
2853 memcpy(outdata, data, dataSize);
2854 smb_SendPacket(vcp, outp);
2860 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2863 long count, minCount, finalCount;
2868 cm_user_t *userp = NULL;
2871 char *rawBuf = NULL;
2876 fd = smb_GetSMBParm(inp, 0);
2877 count = smb_GetSMBParm(inp, 3);
2878 minCount = smb_GetSMBParm(inp, 4);
2879 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2881 if (*inp->wctp == 10) {
2882 /* we were sent a request with 64-bit file offsets */
2883 #ifdef AFS_LARGEFILES
2884 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2886 if (LargeIntegerLessThanZero(offset)) {
2887 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2891 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2892 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2895 offset.HighPart = 0;
2899 /* we were sent a request with 32-bit file offsets */
2900 offset.HighPart = 0;
2903 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2904 fd, offset.HighPart, offset.LowPart, count);
2906 fidp = smb_FindFID(vcp, fd, 0);
2910 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
2911 smb_CloseFID(vcp, fidp, NULL, 0);
2912 code = CM_ERROR_NOSUCHFILE;
2917 pid = ((smb_t *) inp)->pid;
2919 LARGE_INTEGER LOffset, LLength;
2922 key = cm_GenerateKey(vcp->vcID, pid, fd);
2924 LOffset.HighPart = offset.HighPart;
2925 LOffset.LowPart = offset.LowPart;
2926 LLength.HighPart = 0;
2927 LLength.LowPart = count;
2929 lock_ObtainMutex(&fidp->scp->mx);
2930 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2931 lock_ReleaseMutex(&fidp->scp->mx);
2937 lock_ObtainMutex(&smb_RawBufLock);
2939 /* Get a raw buf, from head of list */
2940 rawBuf = smb_RawBufs;
2941 smb_RawBufs = *(char **)smb_RawBufs;
2943 lock_ReleaseMutex(&smb_RawBufLock);
2947 lock_ObtainMutex(&fidp->mx);
2948 if (fidp->flags & SMB_FID_IOCTL)
2950 lock_ReleaseMutex(&fidp->mx);
2951 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2953 /* Give back raw buffer */
2954 lock_ObtainMutex(&smb_RawBufLock);
2955 *((char **) rawBuf) = smb_RawBufs;
2957 smb_RawBufs = rawBuf;
2958 lock_ReleaseMutex(&smb_RawBufLock);
2961 smb_ReleaseFID(fidp);
2964 lock_ReleaseMutex(&fidp->mx);
2966 userp = smb_GetUserFromVCP(vcp, inp);
2968 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2974 cm_ReleaseUser(userp);
2977 smb_ReleaseFID(fidp);
2981 memset((char *)ncbp, 0, sizeof(NCB));
2983 ncbp->ncb_length = (unsigned short) finalCount;
2984 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2985 ncbp->ncb_lana_num = vcp->lana;
2986 ncbp->ncb_command = NCBSEND;
2987 ncbp->ncb_buffer = rawBuf;
2989 code = Netbios(ncbp);
2991 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2994 /* Give back raw buffer */
2995 lock_ObtainMutex(&smb_RawBufLock);
2996 *((char **) rawBuf) = smb_RawBufs;
2998 smb_RawBufs = rawBuf;
2999 lock_ReleaseMutex(&smb_RawBufLock);
3005 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3007 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3012 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3014 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3019 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3026 int VistaProtoIndex;
3027 int protoIndex; /* index we're using */
3032 char protocol_array[10][1024]; /* protocol signature of the client */
3033 int caps; /* capabilities */
3036 TIME_ZONE_INFORMATION tzi;
3038 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3041 namep = smb_GetSMBData(inp, &dbytes);
3044 coreProtoIndex = -1; /* not found */
3047 VistaProtoIndex = -1;
3048 while(namex < dbytes) {
3049 osi_Log1(smb_logp, "Protocol %s",
3050 osi_LogSaveString(smb_logp, namep+1));
3051 strcpy(protocol_array[tcounter], namep+1);
3053 /* namep points at the first protocol, or really, a 0x02
3054 * byte preceding the null-terminated ASCII name.
3056 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3057 coreProtoIndex = tcounter;
3059 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3060 v3ProtoIndex = tcounter;
3062 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3063 NTProtoIndex = tcounter;
3065 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3066 VistaProtoIndex = tcounter;
3069 /* compute size of protocol entry */
3070 entryLength = (int)strlen(namep+1);
3071 entryLength += 2; /* 0x02 bytes and null termination */
3073 /* advance over this protocol entry */
3074 namex += entryLength;
3075 namep += entryLength;
3076 tcounter++; /* which proto entry we're looking at */
3079 lock_ObtainMutex(&vcp->mx);
3081 if (VistaProtoIndex != -1) {
3082 protoIndex = VistaProtoIndex;
3083 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3086 if (NTProtoIndex != -1) {
3087 protoIndex = NTProtoIndex;
3088 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3090 else if (v3ProtoIndex != -1) {
3091 protoIndex = v3ProtoIndex;
3092 vcp->flags |= SMB_VCFLAG_USEV3;
3094 else if (coreProtoIndex != -1) {
3095 protoIndex = coreProtoIndex;
3096 vcp->flags |= SMB_VCFLAG_USECORE;
3098 else protoIndex = -1;
3099 lock_ReleaseMutex(&vcp->mx);
3101 if (protoIndex == -1)
3102 return CM_ERROR_INVAL;
3103 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3104 smb_SetSMBParm(outp, 0, protoIndex);
3105 if (smb_authType != SMB_AUTH_NONE) {
3106 smb_SetSMBParmByte(outp, 1,
3107 NEGOTIATE_SECURITY_USER_LEVEL |
3108 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3110 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3112 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3113 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3114 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3115 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3116 /* The session key is not a well documented field however most clients
3117 * will echo back the session key to the server. Currently we are using
3118 * the same value for all sessions. We should generate a random value
3119 * and store it into the vcp
3121 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3122 smb_SetSMBParm(outp, 8, 1);
3124 * Tried changing the capabilities to support for W2K - defect 117695
3125 * Maybe something else needs to be changed here?
3129 smb_SetSMBParmLong(outp, 9, 0x43fd);
3131 smb_SetSMBParmLong(outp, 9, 0x251);
3134 * 32-bit error codes *
3139 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3141 NTNEGOTIATE_CAPABILITY_DFS |
3143 #ifdef AFS_LARGEFILES
3144 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3146 NTNEGOTIATE_CAPABILITY_NTFIND |
3147 NTNEGOTIATE_CAPABILITY_RAWMODE |
3148 NTNEGOTIATE_CAPABILITY_NTSMB;
3150 if ( smb_authType == SMB_AUTH_EXTENDED )
3151 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3153 smb_SetSMBParmLong(outp, 9, caps);
3155 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3156 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3157 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3159 GetTimeZoneInformation(&tzi);
3160 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3162 if (smb_authType == SMB_AUTH_NTLM) {
3163 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3164 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3165 /* paste in encryption key */
3166 datap = smb_GetSMBData(outp, NULL);
3167 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3168 /* and the faux domain name */
3169 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3170 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3174 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3176 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3178 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3180 datap = smb_GetSMBData(outp, NULL);
3181 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3184 datap += sizeof(smb_ServerGUID);
3185 memcpy(datap, secBlob, secBlobLength);
3189 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3190 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3193 else if (v3ProtoIndex != -1) {
3194 smb_SetSMBParm(outp, 0, protoIndex);
3196 /* NOTE: Extended authentication cannot be negotiated with v3
3197 * therefore we fail over to NTLM
3199 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3200 smb_SetSMBParm(outp, 1,
3201 NEGOTIATE_SECURITY_USER_LEVEL |
3202 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3204 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3206 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3207 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3208 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3209 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3210 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3211 smb_SetSMBParm(outp, 7, 1);
3213 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3214 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3215 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3217 GetTimeZoneInformation(&tzi);
3218 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3220 /* NOTE: Extended authentication cannot be negotiated with v3
3221 * therefore we fail over to NTLM
3223 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3224 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3225 smb_SetSMBParm(outp, 12, 0); /* resvd */
3226 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3227 datap = smb_GetSMBData(outp, NULL);
3228 /* paste in a new encryption key */
3229 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3230 /* and the faux domain name */
3231 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3233 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3234 smb_SetSMBParm(outp, 12, 0); /* resvd */
3235 smb_SetSMBDataLength(outp, 0);
3238 else if (coreProtoIndex != -1) { /* not really supported anymore */
3239 smb_SetSMBParm(outp, 0, protoIndex);
3240 smb_SetSMBDataLength(outp, 0);
3245 void smb_CheckVCs(void)
3247 smb_vc_t * vcp, *nextp;
3248 smb_packet_t * outp = GetPacket();
3251 lock_ObtainWrite(&smb_rctLock);
3252 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3254 if (vcp->magic != SMB_VC_MAGIC)
3255 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3256 __FILE__, __LINE__);
3260 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3263 smb_HoldVCNoLock(vcp);
3265 smb_HoldVCNoLock(nextp);
3266 smb_FormatResponsePacket(vcp, NULL, outp);
3267 smbp = (smb_t *)outp;
3268 outp->inCom = smbp->com = 0x2b /* Echo */;
3276 smb_SetSMBParm(outp, 0, 0);
3277 smb_SetSMBDataLength(outp, 0);
3278 lock_ReleaseWrite(&smb_rctLock);
3280 smb_SendPacket(vcp, outp);
3282 lock_ObtainWrite(&smb_rctLock);
3283 smb_ReleaseVCNoLock(vcp);
3285 smb_ReleaseVCNoLock(nextp);
3287 lock_ReleaseWrite(&smb_rctLock);
3288 smb_FreePacket(outp);
3291 void smb_Daemon(void *parmp)
3293 afs_uint32 count = 0;
3294 smb_username_t **unpp;
3297 while(smbShutdownFlag == 0) {
3301 if (smbShutdownFlag == 1)
3304 if ((count % 72) == 0) { /* every five minutes */
3306 time_t old_localZero = smb_localZero;
3308 /* Initialize smb_localZero */
3309 myTime.tm_isdst = -1; /* compute whether on DST or not */
3310 myTime.tm_year = 70;
3316 smb_localZero = mktime(&myTime);
3318 #ifndef USE_NUMERIC_TIME_CONV
3319 smb_CalculateNowTZ();
3320 #endif /* USE_NUMERIC_TIME_CONV */
3321 #ifdef AFS_FREELANCE
3322 if ( smb_localZero != old_localZero )
3323 cm_noteLocalMountPointChange();
3329 /* GC smb_username_t objects that will no longer be used */
3331 lock_ObtainWrite(&smb_rctLock);
3332 for ( unpp=&usernamesp; *unpp; ) {
3334 smb_username_t *unp;
3336 lock_ObtainMutex(&(*unpp)->mx);
3337 if ( (*unpp)->refCount > 0 ||
3338 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3339 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3341 else if (!smb_LogoffTokenTransfer ||
3342 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3344 lock_ReleaseMutex(&(*unpp)->mx);
3352 lock_FinalizeMutex(&unp->mx);
3358 lock_ReleaseWrite(&smb_rctLock);
3359 cm_ReleaseUser(userp);
3360 lock_ObtainWrite(&smb_rctLock);
3363 unpp = &(*unpp)->nextp;
3366 lock_ReleaseWrite(&smb_rctLock);
3368 /* XXX GC dir search entries */
3372 void smb_WaitingLocksDaemon()
3374 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3375 smb_waitingLock_t *wl, *wlNext;
3378 smb_packet_t *inp, *outp;
3382 while (smbShutdownFlag == 0) {
3383 lock_ObtainWrite(&smb_globalLock);
3384 nwlRequest = smb_allWaitingLocks;
3385 if (nwlRequest == NULL) {
3386 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3391 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3398 lock_ObtainWrite(&smb_globalLock);
3400 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3402 wlRequest = nwlRequest;
3403 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3404 lock_ReleaseWrite(&smb_globalLock);
3408 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3409 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3412 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3414 /* wl->state is either _DONE or _WAITING. _ERROR
3415 would no longer be on the queue. */
3416 code = cm_RetryLock( wl->lockp,
3417 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3420 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3421 } else if (code != CM_ERROR_WOULDBLOCK) {
3422 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3427 if (code == CM_ERROR_WOULDBLOCK) {
3430 if (wlRequest->timeRemaining != 0xffffffff
3431 && (wlRequest->timeRemaining -= 1000) < 0)
3443 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3446 scp = wlRequest->scp;
3447 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3451 lock_ObtainMutex(&scp->mx);
3453 for (wl = wlRequest->locks; wl; wl = wlNext) {
3454 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3456 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3457 wl->LLength, wl->key, NULL, &req);
3459 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3464 lock_ReleaseMutex(&scp->mx);
3468 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3471 for (wl = wlRequest->locks; wl; wl = wlNext) {
3472 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3473 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3478 vcp = wlRequest->vcp;
3479 inp = wlRequest->inp;
3480 outp = wlRequest->outp;
3482 ncbp->ncb_length = inp->ncb_length;
3483 inp->spacep = cm_GetSpace();
3485 /* Remove waitingLock from list */
3486 lock_ObtainWrite(&smb_globalLock);
3487 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3489 lock_ReleaseWrite(&smb_globalLock);
3491 /* Resume packet processing */
3493 smb_SetSMBDataLength(outp, 0);
3494 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3495 outp->resumeCode = code;
3497 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3500 cm_FreeSpace(inp->spacep);
3501 smb_FreePacket(inp);
3502 smb_FreePacket(outp);
3504 cm_ReleaseSCache(wlRequest->scp);
3507 } while (nwlRequest && smbShutdownFlag == 0);
3512 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3514 osi_Log0(smb_logp, "SMB receive get disk attributes");
3516 smb_SetSMBParm(outp, 0, 32000);
3517 smb_SetSMBParm(outp, 1, 64);
3518 smb_SetSMBParm(outp, 2, 1024);
3519 smb_SetSMBParm(outp, 3, 30000);
3520 smb_SetSMBParm(outp, 4, 0);
3521 smb_SetSMBDataLength(outp, 0);
3525 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3529 unsigned short newTid;
3530 char shareName[AFSPATHMAX];
3538 osi_Log0(smb_logp, "SMB receive tree connect");
3540 /* parse input parameters */
3541 tp = smb_GetSMBData(inp, NULL);
3542 pathp = smb_ParseASCIIBlock(tp, &tp);
3543 if (smb_StoreAnsiFilenames)
3544 OemToChar(pathp,pathp);
3545 passwordp = smb_ParseASCIIBlock(tp, &tp);
3546 tp = strrchr(pathp, '\\');
3548 return CM_ERROR_BADSMB;
3549 strcpy(shareName, tp+1);
3551 lock_ObtainMutex(&vcp->mx);
3552 newTid = vcp->tidCounter++;
3553 lock_ReleaseMutex(&vcp->mx);
3555 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3556 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3557 userp = smb_GetUserFromUID(uidp);
3558 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3560 smb_ReleaseUID(uidp);
3562 smb_ReleaseTID(tidp);
3563 return CM_ERROR_BADSHARENAME;
3565 lock_ObtainMutex(&tidp->mx);
3566 tidp->userp = userp;
3567 tidp->pathname = sharePath;
3568 lock_ReleaseMutex(&tidp->mx);
3569 smb_ReleaseTID(tidp);
3571 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3572 smb_SetSMBParm(rsp, 1, newTid);
3573 smb_SetSMBDataLength(rsp, 0);
3575 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3579 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3583 if (*inp++ != 0x1) return NULL;
3584 tlen = inp[0] + (inp[1]<<8);
3585 inp += 2; /* skip length field */
3588 *chainpp = inp + tlen;
3591 if (lengthp) *lengthp = tlen;
3596 /* set maskp to the mask part of the incoming path.
3597 * Mask is 11 bytes long (8.3 with the dot elided).
3598 * Returns true if succeeds with a valid name, otherwise it does
3599 * its best, but returns false.
3601 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3609 /* starts off valid */
3612 /* mask starts out all blanks */
3613 memset(maskp, ' ', 11);
3615 /* find last backslash, or use whole thing if there is none */
3616 tp = strrchr(pathp, '\\');
3617 if (!tp) tp = pathp;
3618 else tp++; /* skip slash */
3622 /* names starting with a dot are illegal */
3623 if (*tp == '.') valid8Dot3 = 0;
3627 if (tc == 0) return valid8Dot3;
3628 if (tc == '.' || tc == '"') break;
3629 if (i < 8) *up++ = tc;
3630 else valid8Dot3 = 0;
3633 /* if we get here, tp point after the dot */
3634 up = maskp+8; /* ext goes here */
3641 if (tc == '.' || tc == '"')
3644 /* copy extension if not too long */
3654 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3664 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3666 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3670 /* otherwise, we have a valid 8.3 name; see if we have a match,
3671 * treating '?' as a wildcard in maskp (but not in the file name).
3673 tp1 = umask; /* real name, in mask format */
3674 tp2 = maskp; /* mask, in mask format */
3675 for(i=0; i<11; i++) {
3676 tc1 = *tp1++; /* char from real name */
3677 tc2 = *tp2++; /* char from mask */
3678 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3679 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3682 if (tc2 == '?' && tc1 != ' ')
3689 /* we got a match */
3693 char *smb_FindMask(char *pathp)
3697 tp = strrchr(pathp, '\\'); /* find last slash */
3700 return tp+1; /* skip the slash */
3702 return pathp; /* no slash, return the entire path */
3705 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3707 unsigned char *pathp;
3709 unsigned char mask[11];
3710 unsigned char *statBlockp;
3711 unsigned char initStatBlock[21];
3714 osi_Log0(smb_logp, "SMB receive search volume");
3716 /* pull pathname and stat block out of request */
3717 tp = smb_GetSMBData(inp, NULL);
3718 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3719 osi_assertx(pathp != NULL, "null path");
3720 if (smb_StoreAnsiFilenames)
3721 OemToChar(pathp,pathp);
3722 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3723 osi_assertx(statBlockp != NULL, "null statBlock");
3725 statBlockp = initStatBlock;
3729 /* for returning to caller */
3730 smb_Get8Dot3MaskFromPath(mask, pathp);
3732 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3733 tp = smb_GetSMBData(outp, NULL);
3735 *tp++ = 43; /* bytes in a dir entry */
3736 *tp++ = 0; /* high byte in counter */
3738 /* now marshall the dir entry, starting with the search status */
3739 *tp++ = statBlockp[0]; /* Reserved */
3740 memcpy(tp, mask, 11); tp += 11; /* FileName */
3742 /* now pass back server use info, with 1st byte non-zero */
3744 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3746 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3748 *tp++ = 0x8; /* attribute: volume */
3758 /* 4 byte file size */
3764 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3765 memset(tp, ' ', 13);
3768 /* set the length of the data part of the packet to 43 + 3, for the dir
3769 * entry plus the 5 and the length fields.
3771 smb_SetSMBDataLength(outp, 46);
3775 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3776 cm_user_t *userp, cm_req_t *reqp)
3784 smb_dirListPatch_t *patchp;
3785 smb_dirListPatch_t *npatchp;
3787 for (patchp = *dirPatchespp; patchp; patchp =
3788 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3790 dptr = patchp->dptr;
3792 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3794 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3795 *dptr++ = SMB_ATTR_HIDDEN;
3798 lock_ObtainMutex(&scp->mx);
3799 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3800 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3802 lock_ReleaseMutex(&scp->mx);
3803 cm_ReleaseSCache(scp);
3804 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3805 *dptr++ = SMB_ATTR_HIDDEN;
3809 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3811 attr = smb_Attributes(scp);
3812 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3813 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3814 attr |= SMB_ATTR_HIDDEN;
3818 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3821 shortTemp = (unsigned short) (dosTime & 0xffff);
3822 *((u_short *)dptr) = shortTemp;
3825 /* and copy out date */
3826 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3827 *((u_short *)dptr) = shortTemp;
3830 /* copy out file length */
3831 *((u_long *)dptr) = scp->length.LowPart;
3833 lock_ReleaseMutex(&scp->mx);
3834 cm_ReleaseSCache(scp);
3837 /* now free the patches */
3838 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3839 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3843 /* and mark the list as empty */
3844 *dirPatchespp = NULL;
3849 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3858 smb_dirListPatch_t *dirListPatchesp;
3859 smb_dirListPatch_t *curPatchp;
3863 osi_hyper_t dirLength;
3864 osi_hyper_t bufferOffset;
3865 osi_hyper_t curOffset;
3867 unsigned char *inCookiep;
3868 smb_dirSearch_t *dsp;
3872 unsigned long clientCookie;
3873 cm_pageHeader_t *pageHeaderp;
3874 cm_user_t *userp = NULL;
3881 long nextEntryCookie;
3882 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3883 char resByte; /* reserved byte from the cookie */
3884 char *op; /* output data ptr */
3885 char *origOp; /* original value of op */
3886 cm_space_t *spacep; /* for pathname buffer */
3897 maxCount = smb_GetSMBParm(inp, 0);
3899 dirListPatchesp = NULL;
3901 caseFold = CM_FLAG_CASEFOLD;
3903 tp = smb_GetSMBData(inp, NULL);
3904 pathp = smb_ParseASCIIBlock(tp, &tp);
3905 if (smb_StoreAnsiFilenames)
3906 OemToChar(pathp,pathp);
3907 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3909 /* bail out if request looks bad */
3910 if (!tp || !pathp) {
3911 return CM_ERROR_BADSMB;
3914 /* We can handle long names */
3915 if (vcp->flags & SMB_VCFLAG_USENT)
3916 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3918 /* make sure we got a whole search status */
3919 if (dataLength < 21) {
3920 nextCookie = 0; /* start at the beginning of the dir */
3923 attribute = smb_GetSMBParm(inp, 1);
3925 /* handle volume info in another function */
3926 if (attribute & 0x8)
3927 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3929 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3930 maxCount, osi_LogSaveString(smb_logp, pathp));
3932 if (*pathp == 0) { /* null pathp, treat as root dir */
3933 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3934 return CM_ERROR_NOFILES;
3938 dsp = smb_NewDirSearch(0);
3939 dsp->attribute = attribute;
3940 smb_Get8Dot3MaskFromPath(mask, pathp);
3941 memcpy(dsp->mask, mask, 11);
3943 /* track if this is likely to match a lot of entries */
3944 if (smb_IsStarMask(mask))
3949 /* pull the next cookie value out of the search status block */
3950 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3951 + (inCookiep[16]<<24);
3952 dsp = smb_FindDirSearch(inCookiep[12]);
3954 /* can't find dir search status; fatal error */
3955 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3956 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3957 return CM_ERROR_BADFD;
3959 attribute = dsp->attribute;
3960 resByte = inCookiep[0];
3962 /* copy out client cookie, in host byte order. Don't bother
3963 * interpreting it, since we're just passing it through, anyway.
3965 memcpy(&clientCookie, &inCookiep[17], 4);
3967 memcpy(mask, dsp->mask, 11);
3969 /* assume we're doing a star match if it has continued for more
3975 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3976 nextCookie, dsp->cookie, attribute);
3978 userp = smb_GetUserFromVCP(vcp, inp);
3980 /* try to get the vnode for the path name next */
3981 lock_ObtainMutex(&dsp->mx);
3984 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
3988 spacep = inp->spacep;
3989 smb_StripLastComponent(spacep->data, NULL, pathp);
3990 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3992 lock_ReleaseMutex(&dsp->mx);
3993 cm_ReleaseUser(userp);
3994 smb_DeleteDirSearch(dsp);
3995 smb_ReleaseDirSearch(dsp);
3996 return CM_ERROR_NOFILES;
3998 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3999 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4002 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4003 cm_ReleaseSCache(scp);
4004 lock_ReleaseMutex(&dsp->mx);
4005 cm_ReleaseUser(userp);
4006 smb_DeleteDirSearch(dsp);
4007 smb_ReleaseDirSearch(dsp);
4008 if ( WANTS_DFS_PATHNAMES(inp) )
4009 return CM_ERROR_PATH_NOT_COVERED;
4011 return CM_ERROR_BADSHARENAME;
4013 #endif /* DFS_SUPPORT */
4016 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4017 /* we need one hold for the entry we just stored into,
4018 * and one for our own processing. When we're done with this
4019 * function, we'll drop the one for our own processing.
4020 * We held it once from the namei call, and so we do another hold
4024 lock_ObtainMutex(&scp->mx);
4025 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4026 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4027 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4028 dsp->flags |= SMB_DIRSEARCH_BULKST;
4029 dsp->scp->bulkStatProgress = hzero;
4031 lock_ReleaseMutex(&scp->mx);
4034 lock_ReleaseMutex(&dsp->mx);
4036 cm_ReleaseUser(userp);
4037 smb_DeleteDirSearch(dsp);
4038 smb_ReleaseDirSearch(dsp);
4042 /* reserves space for parameter; we'll adjust it again later to the
4043 * real count of the # of entries we returned once we've actually
4044 * assembled the directory listing.
4046 smb_SetSMBParm(outp, 0, 0);
4048 /* get the directory size */
4049 lock_ObtainMutex(&scp->mx);
4050 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4051 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4053 lock_ReleaseMutex(&scp->mx);
4054 cm_ReleaseSCache(scp);
4055 cm_ReleaseUser(userp);
4056 smb_DeleteDirSearch(dsp);
4057 smb_ReleaseDirSearch(dsp);
4061 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4063 dirLength = scp->length;
4065 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4066 curOffset.HighPart = 0;
4067 curOffset.LowPart = nextCookie;
4068 origOp = op = smb_GetSMBData(outp, NULL);
4069 /* and write out the basic header */
4070 *op++ = 5; /* variable block */
4071 op += 2; /* skip vbl block length; we'll fill it in later */
4075 /* make sure that curOffset.LowPart doesn't point to the first
4076 * 32 bytes in the 2nd through last dir page, and that it doesn't
4077 * point at the first 13 32-byte chunks in the first dir page,
4078 * since those are dir and page headers, and don't contain useful
4081 temp = curOffset.LowPart & (2048-1);
4082 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4083 /* we're in the first page */
4084 if (temp < 13*32) temp = 13*32;
4087 /* we're in a later dir page */
4088 if (temp < 32) temp = 32;
4091 /* make sure the low order 5 bits are zero */
4094 /* now put temp bits back ito curOffset.LowPart */
4095 curOffset.LowPart &= ~(2048-1);
4096 curOffset.LowPart |= temp;
4098 /* check if we've returned all the names that will fit in the
4101 if (returnedNames >= maxCount) {
4102 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4103 returnedNames, maxCount);
4107 /* check if we've passed the dir's EOF */
4108 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4110 /* see if we can use the bufferp we have now; compute in which page
4111 * the current offset would be, and check whether that's the offset
4112 * of the buffer we have. If not, get the buffer.
4114 thyper.HighPart = curOffset.HighPart;
4115 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4116 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4119 buf_Release(bufferp);
4122 lock_ReleaseMutex(&scp->mx);
4123 lock_ObtainRead(&scp->bufCreateLock);
4124 code = buf_Get(scp, &thyper, &bufferp);
4125 lock_ReleaseRead(&scp->bufCreateLock);
4126 lock_ObtainMutex(&dsp->mx);
4128 /* now, if we're doing a star match, do bulk fetching of all of
4129 * the status info for files in the dir.
4132 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4133 lock_ObtainMutex(&scp->mx);
4134 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4135 LargeIntegerGreaterThanOrEqualTo(thyper,
4136 scp->bulkStatProgress)) {
4137 /* Don't bulk stat if risking timeout */
4138 int now = GetTickCount();
4139 if (now - req.startTime > RDRtimeout * 1000) {
4140 scp->bulkStatProgress = thyper;
4141 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4142 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4143 dsp->scp->bulkStatProgress = hzero;
4145 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4148 lock_ObtainMutex(&scp->mx);
4150 lock_ReleaseMutex(&dsp->mx);
4152 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4156 bufferOffset = thyper;
4158 /* now get the data in the cache */
4160 code = cm_SyncOp(scp, bufferp, userp, &req,
4162 CM_SCACHESYNC_NEEDCALLBACK |
4163 CM_SCACHESYNC_READ);
4165 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4169 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4171 if (cm_HaveBuffer(scp, bufferp, 0)) {
4172 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4176 /* otherwise, load the buffer and try again */
4177 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4179 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4180 scp, bufferp, code);
4185 buf_Release(bufferp);
4189 } /* if (wrong buffer) ... */
4191 /* now we have the buffer containing the entry we're interested in; copy
4192 * it out if it represents a non-deleted entry.
4194 entryInDir = curOffset.LowPart & (2048-1);
4195 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4197 /* page header will help tell us which entries are free. Page header
4198 * can change more often than once per buffer, since AFS 3 dir page size
4199 * may be less than (but not more than a buffer package buffer.
4201 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4202 temp &= ~(2048 - 1); /* turn off intra-page bits */
4203 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4205 /* now determine which entry we're looking at in the page. If it is
4206 * free (there's a free bitmap at the start of the dir), we should
4207 * skip these 32 bytes.
4209 slotInPage = (entryInDir & 0x7e0) >> 5;
4210 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4211 /* this entry is free */
4212 numDirChunks = 1; /* only skip this guy */
4216 tp = bufferp->datap + entryInBuffer;
4217 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4219 /* while we're here, compute the next entry's location, too,
4220 * since we'll need it when writing out the cookie into the dir
4223 * XXXX Probably should do more sanity checking.
4225 numDirChunks = cm_NameEntries(dep->name, NULL);
4227 /* compute the offset of the cookie representing the next entry */
4228 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4230 /* Compute 8.3 name if necessary */
4231 actualName = dep->name;
4232 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4233 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4234 actualName = shortName;
4237 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4238 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4239 osi_LogSaveString(smb_logp, actualName));
4241 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4242 /* this is one of the entries to use: it is not deleted
4243 * and it matches the star pattern we're looking for.
4246 /* Eliminate entries that don't match requested
4249 /* no hidden files */
4250 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4251 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4255 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4257 /* We have already done the cm_TryBulkStat above */
4258 fid.cell = scp->fid.cell;
4259 fid.volume = scp->fid.volume;
4260 fid.vnode = ntohl(dep->fid.vnode);
4261 fid.unique = ntohl(dep->fid.unique);
4262 fileType = cm_FindFileType(&fid);
4263 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4264 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4266 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4267 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4268 fileType == CM_SCACHETYPE_DFSLINK ||
4269 fileType == CM_SCACHETYPE_INVALID)
4270 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4275 memcpy(op, mask, 11); op += 11;
4276 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4277 *op++ = (char)(nextEntryCookie & 0xff);
4278 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4279 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4280 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4281 memcpy(op, &clientCookie, 4); op += 4;
4283 /* now we emit the attribute. This is sort of tricky,
4284 * since we need to really stat the file to find out
4285 * what type of entry we've got. Right now, we're
4286 * copying out data from a buffer, while holding the
4287 * scp locked, so it isn't really convenient to stat
4288 * something now. We'll put in a place holder now,
4289 * and make a second pass before returning this to get
4290 * the real attributes. So, we just skip the data for
4291 * now, and adjust it later. We allocate a patch
4292 * record to make it easy to find this point later.
4293 * The replay will happen at a time when it is safe to
4294 * unlock the directory.
4296 curPatchp = malloc(sizeof(*curPatchp));
4297 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4298 curPatchp->dptr = op;
4299 curPatchp->fid.cell = scp->fid.cell;
4300 curPatchp->fid.volume = scp->fid.volume;
4301 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4302 curPatchp->fid.unique = ntohl(dep->fid.unique);
4304 /* do hidden attribute here since name won't be around when applying
4308 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4309 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4311 curPatchp->flags = 0;
4313 op += 9; /* skip attr, time, date and size */
4315 /* zero out name area. The spec says to pad with
4316 * spaces, but Samba doesn't, and neither do we.
4320 /* finally, we get to copy out the name; we know that
4321 * it fits in 8.3 or the pattern wouldn't match, but it
4322 * never hurts to be sure.
4324 strncpy(op, actualName, 13);
4325 if (smb_StoreAnsiFilenames)
4328 /* Uppercase if requested by client */
4329 if (!KNOWS_LONG_NAMES(inp))
4334 /* now, adjust the # of entries copied */
4336 } /* if we're including this name */
4339 /* and adjust curOffset to be where the new cookie is */
4340 thyper.HighPart = 0;
4341 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4342 curOffset = LargeIntegerAdd(thyper, curOffset);
4343 } /* while copying data for dir listing */
4345 /* release the mutex */
4346 lock_ReleaseMutex(&scp->mx);
4348 buf_Release(bufferp);
4352 /* apply and free last set of patches; if not doing a star match, this
4353 * will be empty, but better safe (and freeing everything) than sorry.
4355 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4357 /* special return code for unsuccessful search */
4358 if (code == 0 && dataLength < 21 && returnedNames == 0)
4359 code = CM_ERROR_NOFILES;
4361 osi_Log2(smb_logp, "SMB search