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 //#define NOTSERVICE 1
13 #include <afs/param.h>
19 #include <sys/timeb.h>
35 #include "lanahelper.h"
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
41 smb_vc_t *dead_vcp = NULL;
42 smb_vc_t *active_vcp = NULL;
44 /* TODO; logout mechanism needs to be thread-safe */
45 char *loggedOutName = NULL;
46 smb_user_t *loggedOutUserp = NULL;
49 int smbShutdownFlag = 0;
51 int smb_LogoffTokenTransfer;
52 time_t smb_LogoffTransferTimeout;
54 int smb_StoreAnsiFilenames = 0;
56 DWORD last_msg_time = 0;
60 unsigned int sessionGen = 0;
62 extern void afsi_log(char *pattern, ...);
63 extern HANDLE afsi_file;
65 osi_hyper_t hzero = {0, 0};
66 osi_hyper_t hones = {0xFFFFFFFF, -1};
69 osi_rwlock_t smb_globalLock;
70 osi_rwlock_t smb_rctLock;
71 osi_mutex_t smb_ListenerLock;
74 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
85 int smb_NumServerThreads;
87 int numNCBs, numSessions, numVCs;
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
92 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
94 ULONG smb_lsaSecPackage;
95 LSA_STRING smb_lsaLogonOrigin;
97 #define NCBmax MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
99 EVENT_HANDLE **NCBreturns;
100 EVENT_HANDLE *smb_ServerShutdown;
101 DWORD NCBsessions[NCBmax];
103 struct smb_packet *bufs[NCBmax];
105 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
106 EVENT_HANDLE SessionEvents[Sessionmax];
107 unsigned short LSNs[Sessionmax];
108 int lanas[Sessionmax];
109 BOOL dead_sessions[Sessionmax];
113 osi_mutex_t smb_RawBufLock;
115 #define SMB_RAW_BUFS 4
117 int smb_RawBufSel[SMB_RAW_BUFS];
122 #define SMB_MASKFLAG_TILDE 1
123 #define SMB_MASKFLAG_CASEFOLD 2
125 #define RAWTIMEOUT INFINITE
128 typedef struct raw_write_cont {
141 /* dir search stuff */
142 long smb_dirSearchCounter = 1;
143 smb_dirSearch_t *smb_firstDirSearchp;
144 smb_dirSearch_t *smb_lastDirSearchp;
146 /* hide dot files? */
147 int smb_hideDotFiles;
149 /* global state about V3 protocols */
150 int smb_useV3; /* try to negotiate V3 */
153 static showErrors = 1;
154 /* MessageBox or something like it */
155 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
156 extern HANDLE WaitToTerminate;
160 * Time in Unix format of midnight, 1/1/1970 local time.
161 * When added to dosUTime, gives Unix (AFS) time.
163 time_t smb_localZero = 0;
165 /* Time difference for converting to kludge-GMT */
168 char *smb_localNamep = NULL;
170 smb_vc_t *smb_allVCsp;
172 smb_username_t *usernamesp = NULL;
174 smb_waitingLock_t *smb_allWaitingLocks;
177 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
178 NCB *ncbp, raw_write_cont_t *rwcp);
179 void smb_NetbiosInit();
181 #ifndef AFS_WIN95_ENV
182 DWORD smb_ServerExceptionFilter(void);
185 extern char cm_HostName[];
186 extern char cm_confDir[];
190 #define LPTSTR char *
191 #define GetComputerName(str, sizep) \
192 strcpy((str), cm_HostName); \
193 *(sizep) = strlen(cm_HostName)
197 void smb_LogPacket(smb_packet_t *packet);
198 #endif /* LOG_PACKET */
199 extern char AFSConfigKeyName[];
201 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
202 int smb_ServerDomainNameLength = 0;
203 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
204 int smb_ServerOSLength = sizeof(smb_ServerOS);
205 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
206 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
208 /* Faux server GUID. This is never checked. */
209 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
211 char * myCrt_Dispatch(int i)
216 return "(00)ReceiveCoreMakeDir";
218 return "(01)ReceiveCoreRemoveDir";
220 return "(02)ReceiveCoreOpen";
222 return "(03)ReceiveCoreCreate";
224 return "(04)ReceiveCoreClose";
226 return "(05)ReceiveCoreFlush";
228 return "(06)ReceiveCoreUnlink";
230 return "(07)ReceiveCoreRename";
232 return "(08)ReceiveCoreGetFileAttributes";
234 return "(09)ReceiveCoreSetFileAttributes";
236 return "(0a)ReceiveCoreRead";
238 return "(0b)ReceiveCoreWrite";
240 return "(0c)ReceiveCoreLockRecord";
242 return "(0d)ReceiveCoreUnlockRecord";
244 return "(0e)SendCoreBadOp";
246 return "(0f)ReceiveCoreCreate";
248 return "(10)ReceiveCoreCheckPath";
250 return "(11)SendCoreBadOp";
252 return "(12)ReceiveCoreSeek";
254 return "(1a)ReceiveCoreReadRaw";
256 return "(1d)ReceiveCoreWriteRawDummy";
258 return "(22)ReceiveV3SetAttributes";
260 return "(23)ReceiveV3GetAttributes";
262 return "(24)ReceiveV3LockingX";
264 return "(25)ReceiveV3Trans";
266 return "(26)ReceiveV3Trans[aux]";
268 return "(29)SendCoreBadOp";
270 return "(2b)ReceiveCoreEcho";
272 return "(2d)ReceiveV3OpenX";
274 return "(2e)ReceiveV3ReadX";
276 return "(32)ReceiveV3Tran2A";
278 return "(33)ReceiveV3Tran2A[aux]";
280 return "(34)ReceiveV3FindClose";
282 return "(35)ReceiveV3FindNotifyClose";
284 return "(70)ReceiveCoreTreeConnect";
286 return "(71)ReceiveCoreTreeDisconnect";
288 return "(72)ReceiveNegotiate";
290 return "(73)ReceiveV3SessionSetupX";
292 return "(74)ReceiveV3UserLogoffX";
294 return "(75)ReceiveV3TreeConnectX";
296 return "(80)ReceiveCoreGetDiskAttributes";
298 return "(81)ReceiveCoreSearchDir";
302 return "(83)FindUnique";
304 return "(84)FindClose";
306 return "(A0)ReceiveNTTransact";
308 return "(A2)ReceiveNTCreateX";
310 return "(A4)ReceiveNTCancel";
312 return "(A5)ReceiveNTRename";
314 return "(C0)OpenPrintFile";
316 return "(C1)WritePrintFile";
318 return "(C2)ClosePrintFile";
320 return "(C3)GetPrintQueue";
322 return "(D8)ReadBulk";
324 return "(D9)WriteBulk";
326 return "(DA)WriteBulkData";
328 return "unknown SMB op";
332 char * myCrt_2Dispatch(int i)
337 return "unknown SMB op-2";
339 return "S(00)CreateFile";
341 return "S(01)FindFirst";
343 return "S(02)FindNext"; /* FindNext */
345 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
349 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
351 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
353 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
355 return "S(08)??_ReceiveTran2SetFileInfo";
357 return "S(09)??_ReceiveTran2FSCTL";
359 return "S(0a)_ReceiveTran2IOCTL";
361 return "S(0b)_ReceiveTran2FindNotifyFirst";
363 return "S(0c)_ReceiveTran2FindNotifyNext";
365 return "S(0d)_ReceiveTran2CreateDirectory";
367 return "S(0e)_ReceiveTran2SessionSetup";
369 return "S(10)_ReceiveTran2GetDfsReferral";
371 return "S(11)_ReceiveTran2ReportDfsInconsistency";
375 char * myCrt_RapDispatch(int i)
380 return "unknown RAP OP";
382 return "RAP(0)NetShareEnum";
384 return "RAP(1)NetShareGetInfo";
386 return "RAP(13)NetServerGetInfo";
388 return "RAP(63)NetWkStaGetInfo";
392 /* scache must be locked */
393 unsigned int smb_Attributes(cm_scache_t *scp)
397 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
398 scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
400 attrs = SMB_ATTR_DIRECTORY;
401 #ifdef SPECIAL_FOLDERS
402 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
403 #endif /* SPECIAL_FOLDERS */
408 * We used to mark a file RO if it was in an RO volume, but that
409 * turns out to be impolitic in NT. See defect 10007.
412 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
414 if ((scp->unixModeBits & 0222) == 0)
415 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
420 /* Check if the named file/dir is a dotfile/dotdir */
421 /* String pointed to by lastComp can have leading slashes, but otherwise should have
422 no other patch components */
423 unsigned int smb_IsDotFile(char *lastComp) {
426 /* skip over slashes */
427 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
432 /* nulls, curdir and parent dir doesn't count */
438 if(*(s+1) == '.' && !*(s + 2))
445 static int ExtractBits(WORD bits, short start, short len)
452 num = bits << (16 - end);
453 num = num >> ((16 - end) + start);
459 void ShowUnixTime(char *FuncName, time_t unixTime)
464 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
466 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
467 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
469 int day, month, year, sec, min, hour;
472 day = ExtractBits(wDate, 0, 5);
473 month = ExtractBits(wDate, 5, 4);
474 year = ExtractBits(wDate, 9, 7) + 1980;
476 sec = ExtractBits(wTime, 0, 5);
477 min = ExtractBits(wTime, 5, 6);
478 hour = ExtractBits(wTime, 11, 5);
480 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
481 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
487 /* Determine if we are observing daylight savings time */
488 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
490 TIME_ZONE_INFORMATION timeZoneInformation;
491 SYSTEMTIME utc, local, localDST;
493 /* Get the time zone info. NT uses this to calc if we are in DST. */
494 GetTimeZoneInformation(&timeZoneInformation);
496 /* Return the daylight bias */
497 *pDstBias = timeZoneInformation.DaylightBias;
499 /* Return the bias */
500 *pBias = timeZoneInformation.Bias;
502 /* Now determine if DST is being observed */
504 /* Get the UTC (GMT) time */
507 /* Convert UTC time to local time using the time zone info. If we are
508 observing DST, the calculated local time will include this.
510 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
512 /* Set the daylight bias to 0. The daylight bias is the amount of change
513 * in time that we use for daylight savings time. By setting this to 0
514 * we cause there to be no change in time during daylight savings time.
516 timeZoneInformation.DaylightBias = 0;
518 /* Convert the utc time to local time again, but this time without any
519 adjustment for daylight savings time.
521 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
523 /* If the two times are different, then it means that the localDST that
524 we calculated includes the daylight bias, and therefore we are
525 observing daylight savings time.
527 *pDST = localDST.wHour != local.wHour;
530 /* Determine if we are observing daylight savings time */
531 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
537 *pDstBias = -60; /* where can this be different? */
543 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
545 BOOL dst; /* Will be TRUE if observing DST */
546 LONG dstBias; /* Offset from local time if observing DST */
547 LONG bias; /* Offset from GMT for local time */
550 * This function will adjust the last write time to compensate
551 * for two bugs in the smb client:
553 * 1) During Daylight Savings Time, the LastWriteTime is ahead
554 * in time by the DaylightBias (ignoring the sign - the
555 * DaylightBias is always stored as a negative number). If
556 * the DaylightBias is -60, then the LastWriteTime will be
557 * ahead by 60 minutes.
559 * 2) If the local time zone is a positive offset from GMT, then
560 * the LastWriteTime will be the correct local time plus the
561 * Bias (ignoring the sign - a positive offset from GMT is
562 * always stored as a negative Bias). If the Bias is -120,
563 * then the LastWriteTime will be ahead by 120 minutes.
565 * These bugs can occur at the same time.
568 GetTimeZoneInfo(&dst, &dstBias, &bias);
570 /* First adjust for DST */
572 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
574 /* Now adjust for a positive offset from GMT (a negative bias). */
576 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
580 * Calculate the difference (in seconds) between local time and GMT.
581 * This enables us to convert file times to kludge-GMT.
587 struct tm gmt_tm, local_tm;
588 int days, hours, minutes, seconds;
591 gmt_tm = *(gmtime(&t));
592 local_tm = *(localtime(&t));
594 days = local_tm.tm_yday - gmt_tm.tm_yday;
595 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
597 /* There is a problem with DST immediately after the time change
598 * which may continue to exist until the machine is rebooted
600 - (local_tm.tm_isdst ? 1 : 0)
603 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
604 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
610 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
615 time_t ersatz_unixTime;
618 * Must use kludge-GMT instead of real GMT.
619 * kludge-GMT is computed by adding time zone difference to localtime.
622 * ltp = gmtime(&unixTime);
624 ersatz_unixTime = unixTime - smb_NowTZ;
625 ltp = localtime(&ersatz_unixTime);
627 /* if we fail, make up something */
630 localJunk.tm_year = 89 - 20;
631 localJunk.tm_mon = 4;
632 localJunk.tm_mday = 12;
633 localJunk.tm_hour = 0;
634 localJunk.tm_min = 0;
635 localJunk.tm_sec = 0;
638 stm.wYear = ltp->tm_year + 1900;
639 stm.wMonth = ltp->tm_mon + 1;
640 stm.wDayOfWeek = ltp->tm_wday;
641 stm.wDay = ltp->tm_mday;
642 stm.wHour = ltp->tm_hour;
643 stm.wMinute = ltp->tm_min;
644 stm.wSecond = ltp->tm_sec;
645 stm.wMilliseconds = 0;
647 SystemTimeToFileTime(&stm, largeTimep);
650 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
652 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
653 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
654 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
656 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
658 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
659 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
661 *ft = LargeIntegerMultiplyByLong(*ft, 60);
662 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
665 ut = ConvertLongToLargeInteger(unixTime);
666 ut = LargeIntegerMultiplyByLong(ut, 10000000);
667 *ft = LargeIntegerAdd(*ft, ut);
672 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
678 FileTimeToSystemTime(largeTimep, &stm);
680 lt.tm_year = stm.wYear - 1900;
681 lt.tm_mon = stm.wMonth - 1;
682 lt.tm_wday = stm.wDayOfWeek;
683 lt.tm_mday = stm.wDay;
684 lt.tm_hour = stm.wHour;
685 lt.tm_min = stm.wMinute;
686 lt.tm_sec = stm.wSecond;
689 save_timezone = _timezone;
690 _timezone += smb_NowTZ;
691 *unixTimep = mktime(<);
692 _timezone = save_timezone;
695 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
697 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
698 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
699 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
703 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
704 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
705 a = LargeIntegerMultiplyByLong(a, 60);
706 a = LargeIntegerMultiplyByLong(a, 10000000);
708 /* subtract it from ft */
709 a = LargeIntegerSubtract(*ft, a);
711 /* divide down to seconds */
712 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
716 void smb_SearchTimeFromUnixTime(time_t *dosTimep, time_t unixTime)
724 ltp = localtime((time_t*) &t);
726 /* if we fail, make up something */
729 localJunk.tm_year = 89 - 20;
730 localJunk.tm_mon = 4;
731 localJunk.tm_mday = 12;
732 localJunk.tm_hour = 0;
733 localJunk.tm_min = 0;
734 localJunk.tm_sec = 0;
737 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
738 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
739 *dosTimep = (dosDate<<16) | dosTime;
742 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
744 unsigned short dosDate;
745 unsigned short dosTime;
748 dosDate = (unsigned short) (searchTime & 0xffff);
749 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
751 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
752 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
753 localTm.tm_mday = (dosDate) & 0x1f;
754 localTm.tm_hour = (dosTime>>11) & 0x1f;
755 localTm.tm_min = (dosTime >> 5) & 0x3f;
756 localTm.tm_sec = (dosTime & 0x1f) * 2;
757 localTm.tm_isdst = -1; /* compute whether DST in effect */
759 *unixTimep = mktime(&localTm);
762 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
764 *dosUTimep = unixTime - smb_localZero;
767 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
770 *unixTimep = dosTime + smb_localZero;
772 /* dosTime seems to be already adjusted for GMT */
773 *unixTimep = dosTime;
777 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
781 lock_ObtainWrite(&smb_rctLock);
782 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
783 if (lsn == vcp->lsn && lana == vcp->lana) {
788 if (!vcp && (flags & SMB_FLAG_CREATE)) {
789 vcp = malloc(sizeof(*vcp));
790 memset(vcp, 0, sizeof(*vcp));
791 vcp->vcID = numVCs++;
795 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
796 vcp->nextp = smb_allVCsp;
798 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
803 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
804 /* We must obtain a challenge for extended auth
805 * in case the client negotiates smb v3
808 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
809 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
812 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
814 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
821 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
823 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
824 LsaFreeReturnBuffer(lsaResp);
827 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
829 lock_ReleaseWrite(&smb_rctLock);
833 int smb_IsStarMask(char *maskp)
838 for(i=0; i<11; i++) {
840 if (tc == '?' || tc == '*' || tc == '>') return 1;
845 void smb_ReleaseVC(smb_vc_t *vcp)
847 lock_ObtainWrite(&smb_rctLock);
848 osi_assert(vcp->refCount-- > 0);
849 lock_ReleaseWrite(&smb_rctLock);
852 void smb_HoldVC(smb_vc_t *vcp)
854 lock_ObtainWrite(&smb_rctLock);
856 lock_ReleaseWrite(&smb_rctLock);
859 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
863 lock_ObtainWrite(&smb_rctLock);
864 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
865 if (tid == tidp->tid) {
870 if (!tidp && (flags & SMB_FLAG_CREATE)) {
871 tidp = malloc(sizeof(*tidp));
872 memset(tidp, 0, sizeof(*tidp));
873 tidp->nextp = vcp->tidsp;
878 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
881 lock_ReleaseWrite(&smb_rctLock);
885 void smb_ReleaseTID(smb_tid_t *tidp)
894 lock_ObtainWrite(&smb_rctLock);
895 osi_assert(tidp->refCount-- > 0);
896 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
897 ltpp = &tidp->vcp->tidsp;
898 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
899 if (tp == tidp) break;
901 osi_assert(tp != NULL);
903 lock_FinalizeMutex(&tidp->mx);
904 userp = tidp->userp; /* remember to drop ref later */
907 lock_ReleaseWrite(&smb_rctLock);
909 cm_ReleaseUser(userp);
916 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
918 smb_user_t *uidp = NULL;
920 lock_ObtainWrite(&smb_rctLock);
921 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
922 if (uid == uidp->userID) {
924 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
925 (int)vcp, uidp->userID,
926 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
930 if (!uidp && (flags & SMB_FLAG_CREATE)) {
931 uidp = malloc(sizeof(*uidp));
932 memset(uidp, 0, sizeof(*uidp));
933 uidp->nextp = vcp->usersp;
938 lock_InitializeMutex(&uidp->mx, "user_t mutex");
940 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL,"VCP[%x] new-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp ? uidp->unp->name : ""));
942 lock_ReleaseWrite(&smb_rctLock);
946 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
948 smb_username_t *unp= NULL;
950 lock_ObtainWrite(&smb_rctLock);
951 for(unp = usernamesp; unp; unp = unp->nextp) {
952 if (stricmp(unp->name, usern) == 0 &&
953 stricmp(unp->machine, machine) == 0) {
958 if (!unp && (flags & SMB_FLAG_CREATE)) {
959 unp = malloc(sizeof(*unp));
960 memset(unp, 0, sizeof(*unp));
962 unp->nextp = usernamesp;
963 unp->name = strdup(usern);
964 unp->machine = strdup(machine);
966 lock_InitializeMutex(&unp->mx, "username_t mutex");
968 lock_ReleaseWrite(&smb_rctLock);
972 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
974 smb_user_t *uidp= NULL;
976 lock_ObtainWrite(&smb_rctLock);
977 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
980 if (stricmp(uidp->unp->name, usern) == 0) {
982 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
987 lock_ReleaseWrite(&smb_rctLock);
990 void smb_ReleaseUID(smb_user_t *uidp)
999 lock_ObtainWrite(&smb_rctLock);
1000 osi_assert(uidp->refCount-- > 0);
1001 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1002 lupp = &uidp->vcp->usersp;
1003 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1004 if (up == uidp) break;
1006 osi_assert(up != NULL);
1008 lock_FinalizeMutex(&uidp->mx);
1010 userp = uidp->unp->userp; /* remember to drop ref later */
1011 uidp->unp->userp = NULL;
1016 lock_ReleaseWrite(&smb_rctLock);
1018 cm_ReleaseUserVCRef(userp);
1019 cm_ReleaseUser(userp);
1026 /* retrieve a held reference to a user structure corresponding to an incoming
1028 * corresponding release function is cm_ReleaseUser.
1030 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1036 smbp = (smb_t *) inp;
1037 uidp = smb_FindUID(vcp, smbp->uid, 0);
1038 if ((!uidp) || (!uidp->unp))
1041 lock_ObtainMutex(&uidp->mx);
1042 up = uidp->unp->userp;
1044 lock_ReleaseMutex(&uidp->mx);
1046 smb_ReleaseUID(uidp);
1052 * Return a pointer to a pathname extracted from a TID structure. The
1053 * TID structure is not held; assume it won't go away.
1055 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1060 tidp = smb_FindTID(vcp, tid, 0);
1064 if(tidp->flags & SMB_TIDFLAG_IPC) {
1065 code = CM_ERROR_TIDIPC;
1066 /* tidp->pathname would be NULL, but that's fine */
1068 *treepath = tidp->pathname;
1069 smb_ReleaseTID(tidp);
1074 /* check to see if we have a chained fid, that is, a fid that comes from an
1075 * OpenAndX message that ran earlier in this packet. In this case, the fid
1076 * field in a read, for example, request, isn't set, since the value is
1077 * supposed to be inherited from the openAndX call.
1079 int smb_ChainFID(int fid, smb_packet_t *inp)
1081 if (inp->fid == 0 || inp->inCount == 0)
1087 /* are we a priv'd user? What does this mean on NT? */
1088 int smb_SUser(cm_user_t *userp)
1093 /* find a file ID. If we pass in 0 we select an used File ID.
1094 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1095 * smb_fid_t data structure if desired File ID cannot be found.
1097 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1102 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1105 lock_ObtainWrite(&smb_rctLock);
1106 /* figure out if we need to allocate a new file ID */
1109 fid = vcp->fidCounter;
1113 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1114 if (fid == fidp->fid) {
1125 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1126 char eventName[MAX_PATH];
1128 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1129 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1130 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1131 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1132 thrd_CloseHandle(event);
1139 fidp = malloc(sizeof(*fidp));
1140 memset(fidp, 0, sizeof(*fidp));
1141 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1145 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1147 fidp->curr_chunk = fidp->prev_chunk = -2;
1148 fidp->raw_write_event = event;
1150 vcp->fidCounter = fid+1;
1151 if (vcp->fidCounter == 0)
1152 vcp->fidCounter = 1;
1155 lock_ReleaseWrite(&smb_rctLock);
1159 void smb_ReleaseFID(smb_fid_t *fidp)
1162 smb_vc_t *vcp = NULL;
1163 smb_ioctl_t *ioctlp;
1169 lock_ObtainWrite(&smb_rctLock);
1170 osi_assert(fidp->refCount-- > 0);
1171 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1173 if (!(fidp->flags & SMB_FID_IOCTL))
1175 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1176 thrd_CloseHandle(fidp->raw_write_event);
1178 /* and see if there is ioctl stuff to free */
1179 ioctlp = fidp->ioctlp;
1181 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1182 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1183 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1189 /* do not call smb_ReleaseVC() because we already have the lock */
1192 lock_ReleaseWrite(&smb_rctLock);
1194 /* now release the scache structure */
1196 cm_ReleaseSCache(scp);
1200 * Case-insensitive search for one string in another;
1201 * used to find variable names in submount pathnames.
1203 static char *smb_stristr(char *str1, char *str2)
1207 for (cursor = str1; *cursor; cursor++)
1208 if (stricmp(cursor, str2) == 0)
1215 * Substitute a variable value for its name in a submount pathname. Variable
1216 * name has been identified by smb_stristr() and is in substr. Variable name
1217 * length (plus one) is in substr_size. Variable value is in newstr.
1219 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1224 strcpy(temp, substr + substr_size - 1);
1225 strcpy(substr, newstr);
1229 char VNUserName[] = "%USERNAME%";
1230 char VNLCUserName[] = "%LCUSERNAME%";
1231 char VNComputerName[] = "%COMPUTERNAME%";
1232 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1235 /* List available shares */
1236 int smb_ListShares()
1240 char shareBuf[4096];
1248 /*strcpy(shareNameList[num_shares], "all");
1249 strcpy(pathNameList[num_shares++], "/afs");*/
1250 fprintf(stderr, "The following shares are available:\n");
1251 fprintf(stderr, "Share Name (AFS Path)\n");
1252 fprintf(stderr, "---------------------\n");
1253 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1256 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1257 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1259 strcpy(sbmtpath, cm_confDir);
1261 strcat(sbmtpath, "/afsdsbmt.ini");
1262 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1263 shareBuf, sizeof(shareBuf),
1269 this_share = shareBuf;
1273 /*strcpy(shareNameList[num_shares], this_share);*/
1274 len = GetPrivateProfileString("AFS Submounts", this_share,
1281 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1284 if (*p == '\\') *p = '/'; /* change to / */
1288 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1289 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1292 while (*this_share != 0) this_share++; /* find next NUL */
1293 this_share++; /* skip past the NUL */
1294 } while (*this_share != 0); /* stop at final NUL */
1300 typedef struct smb_findShare_rock {
1304 } smb_findShare_rock_t;
1306 #define SMB_FINDSHARE_EXACT_MATCH 1
1307 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1309 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1313 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1314 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1315 if(!stricmp(dep->name, vrock->shareName))
1316 matchType = SMB_FINDSHARE_EXACT_MATCH;
1318 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1319 if(vrock->match) free(vrock->match);
1320 vrock->match = strdup(dep->name);
1321 vrock->matchType = matchType;
1323 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1324 return CM_ERROR_STOPNOW;
1330 /* find a shareName in the table of submounts */
1331 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1335 char pathName[1024];
1340 char sbmtpath[MAX_PATH];
1345 DWORD allSubmount = 1;
1347 /* if allSubmounts == 0, only return the //mountRoot/all share
1348 * if in fact it has been been created in the subMounts table.
1349 * This is to allow sites that want to restrict access to the
1352 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1353 0, KEY_QUERY_VALUE, &parmKey);
1354 if (code == ERROR_SUCCESS) {
1355 len = sizeof(allSubmount);
1356 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1357 (BYTE *) &allSubmount, &len);
1358 if (code != ERROR_SUCCESS) {
1361 RegCloseKey (parmKey);
1364 if (allSubmount && _stricmp(shareName, "all") == 0) {
1369 /* In case, the all share is disabled we need to still be able
1370 * to handle ioctl requests
1372 if (_stricmp(shareName, "ioctl$") == 0) {
1373 *pathNamep = strdup("/.__ioctl__");
1377 if (_stricmp(shareName, "IPC$") == 0 ||
1378 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1379 _stricmp(shareName, "DESKTOP.INI") == 0
1386 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1387 0, KEY_QUERY_VALUE, &parmKey);
1388 if (code == ERROR_SUCCESS) {
1389 len = sizeof(pathName);
1390 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1391 (BYTE *) pathName, &len);
1392 if (code != ERROR_SUCCESS)
1394 RegCloseKey (parmKey);
1399 strcpy(sbmtpath, cm_confDir);
1400 strcat(sbmtpath, "/afsdsbmt.ini");
1401 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1402 pathName, sizeof(pathName), sbmtpath);
1404 if (len != 0 && len != sizeof(pathName) - 1) {
1405 /* We can accept either unix or PC style AFS pathnames. Convert
1406 * Unix-style to PC style here for internal use.
1409 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1410 p += strlen(cm_mountRoot); /* skip mount path */
1413 if (*q == '/') *q = '\\'; /* change to \ */
1419 if (var = smb_stristr(p, VNUserName)) {
1420 if (uidp && uidp->unp)
1421 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1423 smb_subst(p, var, sizeof(VNUserName)," ");
1425 else if (var = smb_stristr(p, VNLCUserName))
1427 if (uidp && uidp->unp)
1428 strcpy(temp, uidp->unp->name);
1432 smb_subst(p, var, sizeof(VNLCUserName), temp);
1434 else if (var = smb_stristr(p, VNComputerName))
1436 sizeTemp = sizeof(temp);
1437 GetComputerName((LPTSTR)temp, &sizeTemp);
1438 smb_subst(p, var, sizeof(VNComputerName), temp);
1440 else if (var = smb_stristr(p, VNLCComputerName))
1442 sizeTemp = sizeof(temp);
1443 GetComputerName((LPTSTR)temp, &sizeTemp);
1445 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1450 *pathNamep = strdup(p);
1455 /* First lookup shareName in root.afs */
1457 smb_findShare_rock_t vrock;
1459 char * p = shareName;
1462 /* attempt to locate a partial match in root.afs. This is because
1463 when using the ANSI RAP calls, the share name is limited to 13 chars
1464 and hence is truncated. Of course we prefer exact matches. */
1466 thyper.HighPart = 0;
1469 vrock.shareName = shareName;
1471 vrock.matchType = 0;
1473 cm_HoldSCache(cm_rootSCachep);
1474 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1475 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1476 cm_ReleaseSCache(cm_rootSCachep);
1478 if (vrock.matchType) {
1479 sprintf(pathName,"/%s/",vrock.match);
1480 *pathNamep = strdup(strlwr(pathName));
1485 /* if we get here, there was no match for the share in root.afs */
1486 /* so try to create \\<netbiosName>\<cellname> */
1491 /* Get the full name for this cell */
1492 code = cm_SearchCellFile(p, temp, 0, 0);
1493 #ifdef AFS_AFSDB_ENV
1494 if (code && cm_dnsEnabled) {
1496 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1499 /* construct the path */
1501 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1502 *pathNamep = strdup(strlwr(pathName));
1511 /* Client-side offline caching policy types */
1512 #define CSC_POLICY_MANUAL 0
1513 #define CSC_POLICY_DOCUMENTS 1
1514 #define CSC_POLICY_PROGRAMS 2
1515 #define CSC_POLICY_DISABLE 3
1517 int smb_FindShareCSCPolicy(char *shareName)
1523 int retval = CSC_POLICY_MANUAL;
1525 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1526 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1529 REG_OPTION_NON_VOLATILE,
1535 len = sizeof(policy);
1536 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1538 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1540 else if (stricmp(policy, "documents") == 0)
1542 retval = CSC_POLICY_DOCUMENTS;
1544 else if (stricmp(policy, "programs") == 0)
1546 retval = CSC_POLICY_PROGRAMS;
1548 else if (stricmp(policy, "disable") == 0)
1550 retval = CSC_POLICY_DISABLE;
1553 RegCloseKey(hkCSCPolicy);
1557 /* find a dir search structure by cookie value, and return it held.
1558 * Must be called with smb_globalLock held.
1560 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1562 smb_dirSearch_t *dsp;
1564 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1565 if (dsp->cookie == cookie) {
1566 if (dsp != smb_firstDirSearchp) {
1567 /* move to head of LRU queue, too, if we're not already there */
1568 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1569 smb_lastDirSearchp = (smb_dirSearch_t *)
1571 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1572 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1573 if (!smb_lastDirSearchp)
1574 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1576 lock_ObtainMutex(&dsp->mx);
1578 lock_ReleaseMutex(&dsp->mx);
1585 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1587 lock_ObtainWrite(&smb_globalLock);
1588 lock_ObtainMutex(&dsp->mx);
1589 dsp->flags |= SMB_DIRSEARCH_DELETE;
1590 if (dsp->scp != NULL) {
1591 lock_ObtainMutex(&dsp->scp->mx);
1592 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1593 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1594 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1595 dsp->scp->bulkStatProgress = hones;
1597 lock_ReleaseMutex(&dsp->scp->mx);
1599 lock_ReleaseMutex(&dsp->mx);
1600 lock_ReleaseWrite(&smb_globalLock);
1603 /* Must be called with the smb_globalLock held */
1604 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1610 lock_ObtainMutex(&dsp->mx);
1611 osi_assert(dsp->refCount-- > 0);
1612 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1613 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1614 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1615 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1616 lock_ReleaseMutex(&dsp->mx);
1617 lock_FinalizeMutex(&dsp->mx);
1621 lock_ReleaseMutex(&dsp->mx);
1623 /* do this now to avoid spurious locking hierarchy creation */
1624 if (scp) cm_ReleaseSCache(scp);
1627 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1629 lock_ObtainWrite(&smb_globalLock);
1630 smb_ReleaseDirSearchNoLock(dsp);
1631 lock_ReleaseWrite(&smb_globalLock);
1634 /* find a dir search structure by cookie value, and return it held */
1635 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1637 smb_dirSearch_t *dsp;
1639 lock_ObtainWrite(&smb_globalLock);
1640 dsp = smb_FindDirSearchNoLock(cookie);
1641 lock_ReleaseWrite(&smb_globalLock);
1645 /* GC some dir search entries, in the address space expected by the specific protocol.
1646 * Must be called with smb_globalLock held; release the lock temporarily.
1648 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1649 void smb_GCDirSearches(int isV3)
1651 smb_dirSearch_t *prevp;
1652 smb_dirSearch_t *tp;
1653 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1657 victimCount = 0; /* how many have we got so far */
1658 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1659 /* we'll move tp from queue, so
1662 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1663 /* if no one is using this guy, and we're either in the new protocol,
1664 * or we're in the old one and this is a small enough ID to be useful
1665 * to the old protocol, GC this guy.
1667 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1668 /* hold and delete */
1669 tp->flags |= SMB_DIRSEARCH_DELETE;
1670 victimsp[victimCount++] = tp;
1674 /* don't do more than this */
1675 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1679 /* now release them */
1680 for (i = 0; i < victimCount; i++) {
1681 smb_ReleaseDirSearchNoLock(victimsp[i]);
1685 /* function for allocating a dir search entry. We need these to remember enough context
1686 * since we don't get passed the path from call to call during a directory search.
1688 * Returns a held dir search structure, and bumps the reference count on the vnode,
1689 * since it saves a pointer to the vnode.
1691 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1693 smb_dirSearch_t *dsp;
1697 lock_ObtainWrite(&smb_globalLock);
1700 /* what's the biggest ID allowed in this version of the protocol */
1701 maxAllowed = isV3 ? 65535 : 255;
1704 /* twice so we have enough tries to find guys we GC after one pass;
1705 * 10 extra is just in case I mis-counted.
1707 if (++counter > 2*maxAllowed+10)
1708 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1710 if (smb_dirSearchCounter > maxAllowed) {
1711 smb_dirSearchCounter = 1;
1712 smb_GCDirSearches(isV3); /* GC some */
1714 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1716 /* don't need to watch for refcount zero and deleted, since
1717 * we haven't dropped the global lock.
1719 lock_ObtainMutex(&dsp->mx);
1721 lock_ReleaseMutex(&dsp->mx);
1722 ++smb_dirSearchCounter;
1726 dsp = malloc(sizeof(*dsp));
1727 memset(dsp, 0, sizeof(*dsp));
1728 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1729 if (!smb_lastDirSearchp)
1730 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1731 dsp->cookie = smb_dirSearchCounter;
1732 ++smb_dirSearchCounter;
1734 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1735 dsp->lastTime = osi_Time();
1738 lock_ReleaseWrite(&smb_globalLock);
1742 static smb_packet_t *GetPacket(void)
1746 unsigned int npar, seg, tb_sel;
1749 lock_ObtainWrite(&smb_globalLock);
1750 tbp = smb_packetFreeListp;
1752 smb_packetFreeListp = tbp->nextp;
1753 lock_ReleaseWrite(&smb_globalLock);
1756 tbp = calloc(65540,1);
1758 tbp = malloc(sizeof(smb_packet_t));
1760 tbp->magic = SMB_PACKETMAGIC;
1763 tbp->resumeCode = 0;
1769 tbp->ncb_length = 0;
1774 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1777 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1779 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1781 osi_panic("",__FILE__,__LINE__);
1784 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1789 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1790 tbp->dos_pkt_sel = tb_sel;
1793 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1798 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1802 memcpy(tbp, pkt, sizeof(smb_packet_t));
1803 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1807 static NCB *GetNCB(void)
1812 unsigned int npar, seg, tb_sel;
1815 lock_ObtainWrite(&smb_globalLock);
1816 tbp = smb_ncbFreeListp;
1818 smb_ncbFreeListp = tbp->nextp;
1819 lock_ReleaseWrite(&smb_globalLock);
1822 tbp = calloc(sizeof(*tbp),1);
1824 tbp = malloc(sizeof(*tbp));
1825 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1828 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1830 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1832 osi_panic("",__FILE__,__LINE__);
1834 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1839 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1840 tbp->dos_ncb_sel = tb_sel;
1842 tbp->magic = SMB_NCBMAGIC;
1845 osi_assert(tbp->magic == SMB_NCBMAGIC);
1847 memset(&tbp->ncb, 0, sizeof(NCB));
1850 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1855 void smb_FreePacket(smb_packet_t *tbp)
1857 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1859 lock_ObtainWrite(&smb_globalLock);
1860 tbp->nextp = smb_packetFreeListp;
1861 smb_packetFreeListp = tbp;
1862 tbp->magic = SMB_PACKETMAGIC;
1865 tbp->resumeCode = 0;
1871 tbp->ncb_length = 0;
1873 lock_ReleaseWrite(&smb_globalLock);
1876 static void FreeNCB(NCB *bufferp)
1880 tbp = (smb_ncb_t *) bufferp;
1881 osi_assert(tbp->magic == SMB_NCBMAGIC);
1883 lock_ObtainWrite(&smb_globalLock);
1884 tbp->nextp = smb_ncbFreeListp;
1885 smb_ncbFreeListp = tbp;
1886 lock_ReleaseWrite(&smb_globalLock);
1889 /* get a ptr to the data part of a packet, and its count */
1890 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1894 unsigned char *afterParmsp;
1896 parmBytes = *smbp->wctp << 1;
1897 afterParmsp = smbp->wctp + parmBytes + 1;
1899 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1900 if (nbytesp) *nbytesp = dataBytes;
1902 /* don't forget to skip the data byte count, since it follows
1903 * the parameters; that's where the "2" comes from below.
1905 return (unsigned char *) (afterParmsp + 2);
1908 /* must set all the returned parameters before playing around with the
1909 * data region, since the data region is located past the end of the
1910 * variable number of parameters.
1912 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1914 unsigned char *afterParmsp;
1916 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1918 *afterParmsp++ = dsize & 0xff;
1919 *afterParmsp = (dsize>>8) & 0xff;
1922 /* return the parm'th parameter in the smbp packet */
1923 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1926 unsigned char *parmDatap;
1928 parmCount = *smbp->wctp;
1930 if (parm >= parmCount) {
1935 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1937 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1938 parm, parmCount, smbp->ncb_length);
1941 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1942 1, smbp->ncb_length, ptbuf, smbp);
1943 DeregisterEventSource(h);
1945 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1946 osi_panic(s, __FILE__, __LINE__);
1948 parmDatap = smbp->wctp + (2*parm) + 1;
1950 return parmDatap[0] + (parmDatap[1] << 8);
1953 /* return the parm'th parameter in the smbp packet */
1954 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1957 unsigned char *parmDatap;
1959 parmCount = *smbp->wctp;
1961 if (parm * 2 + offset >= parmCount * 2) {
1966 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1968 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1969 parm, offset, parmCount, smbp->ncb_length);
1972 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1973 1, smbp->ncb_length, ptbuf, smbp);
1974 DeregisterEventSource(h);
1976 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1977 osi_panic(s, __FILE__, __LINE__);
1979 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1981 return parmDatap[0] + (parmDatap[1] << 8);
1984 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1988 /* make sure we have enough slots */
1989 if (*smbp->wctp <= slot)
1990 *smbp->wctp = slot+1;
1992 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1993 *parmDatap++ = parmValue & 0xff;
1994 *parmDatap = (parmValue>>8) & 0xff;
1997 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2001 /* make sure we have enough slots */
2002 if (*smbp->wctp <= slot)
2003 *smbp->wctp = slot+2;
2005 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2006 *parmDatap++ = parmValue & 0xff;
2007 *parmDatap++ = (parmValue>>8) & 0xff;
2008 *parmDatap++ = (parmValue>>16) & 0xff;
2009 *parmDatap++ = (parmValue>>24) & 0xff;
2012 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2017 /* make sure we have enough slots */
2018 if (*smbp->wctp <= slot)
2019 *smbp->wctp = slot+4;
2021 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2023 *parmDatap++ = *parmValuep++;
2026 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2030 /* make sure we have enough slots */
2031 if (*smbp->wctp <= slot) {
2032 if (smbp->oddByte) {
2034 *smbp->wctp = slot+1;
2039 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2040 *parmDatap++ = parmValue & 0xff;
2043 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2047 lastSlashp = strrchr(inPathp, '\\');
2049 *lastComponentp = lastSlashp;
2052 if (inPathp == lastSlashp)
2054 *outPathp++ = *inPathp++;
2063 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2068 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2073 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2079 tlen = inp[0] + (inp[1]<<8);
2080 inp += 2; /* skip length field */
2083 *chainpp = inp + tlen;
2092 /* format a packet as a response */
2093 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2098 outp = (smb_t *) op;
2100 /* zero the basic structure through the smb_wct field, and zero the data
2101 * size field, assuming that wct stays zero; otherwise, you have to
2102 * explicitly set the data size field, too.
2104 inSmbp = (smb_t *) inp;
2105 memset(outp, 0, sizeof(smb_t)+2);
2111 outp->com = inSmbp->com;
2112 outp->tid = inSmbp->tid;
2113 outp->pid = inSmbp->pid;
2114 outp->uid = inSmbp->uid;
2115 outp->mid = inSmbp->mid;
2116 outp->res[0] = inSmbp->res[0];
2117 outp->res[1] = inSmbp->res[1];
2118 op->inCom = inSmbp->com;
2120 outp->reb = 0x80; /* SERVER_RESP */
2121 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2123 /* copy fields in generic packet area */
2124 op->wctp = &outp->wct;
2127 /* send a (probably response) packet; vcp tells us to whom to send it.
2128 * we compute the length by looking at wct and bcc fields.
2130 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2147 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2150 memset((char *)ncbp, 0, sizeof(NCB));
2152 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2153 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2154 extra += tp[0] + (tp[1]<<8);
2155 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2156 extra += 3; /* wct and length fields */
2158 ncbp->ncb_length = extra; /* bytes to send */
2159 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2160 ncbp->ncb_lana_num = vcp->lana;
2161 ncbp->ncb_command = NCBSEND; /* op means send data */
2163 ncbp->ncb_buffer = (char *) inp;/* packet */
2164 code = Netbios(ncbp);
2166 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2167 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2169 /* copy header information from virtual to DOS address space */
2170 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2171 code = Netbios(ncbp, dos_ncb);
2175 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2181 void smb_MapNTError(long code, unsigned long *NTStatusp)
2183 unsigned long NTStatus;
2185 /* map CM_ERROR_* errors to NT 32-bit status codes */
2186 /* NT Status codes are listed in ntstatus.h not winerror.h */
2187 if (code == CM_ERROR_NOSUCHCELL) {
2188 NTStatus = 0xC000000FL; /* No such file */
2190 else if (code == CM_ERROR_NOSUCHVOLUME) {
2191 NTStatus = 0xC000000FL; /* No such file */
2193 else if (code == CM_ERROR_TIMEDOUT) {
2194 NTStatus = 0xC00000CFL; /* Sharing Paused */
2196 else if (code == CM_ERROR_RETRY) {
2197 NTStatus = 0xC000022DL; /* Retry */
2199 else if (code == CM_ERROR_NOACCESS) {
2200 NTStatus = 0xC0000022L; /* Access denied */
2202 else if (code == CM_ERROR_READONLY) {
2203 NTStatus = 0xC00000A2L; /* Write protected */
2205 else if (code == CM_ERROR_NOSUCHFILE) {
2206 NTStatus = 0xC000000FL; /* No such file */
2208 else if (code == CM_ERROR_NOSUCHPATH) {
2209 NTStatus = 0xC000003AL; /* Object path not found */
2211 else if (code == CM_ERROR_TOOBIG) {
2212 NTStatus = 0xC000007BL; /* Invalid image format */
2214 else if (code == CM_ERROR_INVAL) {
2215 NTStatus = 0xC000000DL; /* Invalid parameter */
2217 else if (code == CM_ERROR_BADFD) {
2218 NTStatus = 0xC0000008L; /* Invalid handle */
2220 else if (code == CM_ERROR_BADFDOP) {
2221 NTStatus = 0xC0000022L; /* Access denied */
2223 else if (code == CM_ERROR_EXISTS) {
2224 NTStatus = 0xC0000035L; /* Object name collision */
2226 else if (code == CM_ERROR_NOTEMPTY) {
2227 NTStatus = 0xC0000101L; /* Directory not empty */
2229 else if (code == CM_ERROR_CROSSDEVLINK) {
2230 NTStatus = 0xC00000D4L; /* Not same device */
2232 else if (code == CM_ERROR_NOTDIR) {
2233 NTStatus = 0xC0000103L; /* Not a directory */
2235 else if (code == CM_ERROR_ISDIR) {
2236 NTStatus = 0xC00000BAL; /* File is a directory */
2238 else if (code == CM_ERROR_BADOP) {
2240 /* I have no idea where this comes from */
2241 NTStatus = 0xC09820FFL; /* SMB no support */
2243 NTStatus = 0xC00000BBL; /* Not supported */
2244 #endif /* COMMENT */
2246 else if (code == CM_ERROR_BADSHARENAME) {
2247 NTStatus = 0xC00000CCL; /* Bad network name */
2249 else if (code == CM_ERROR_NOIPC) {
2251 NTStatus = 0xC0000022L; /* Access Denied */
2253 NTStatus = 0xC000013DL; /* Remote Resources */
2256 else if (code == CM_ERROR_CLOCKSKEW) {
2257 NTStatus = 0xC0000133L; /* Time difference at DC */
2259 else if (code == CM_ERROR_BADTID) {
2260 NTStatus = 0xC0982005L; /* SMB bad TID */
2262 else if (code == CM_ERROR_USESTD) {
2263 NTStatus = 0xC09820FBL; /* SMB use standard */
2265 else if (code == CM_ERROR_QUOTA) {
2267 NTStatus = 0xC0000044L; /* Quota exceeded */
2269 NTStatus = 0xC000007FL; /* Disk full */
2272 else if (code == CM_ERROR_SPACE) {
2273 NTStatus = 0xC000007FL; /* Disk full */
2275 else if (code == CM_ERROR_ATSYS) {
2276 NTStatus = 0xC0000033L; /* Object name invalid */
2278 else if (code == CM_ERROR_BADNTFILENAME) {
2279 NTStatus = 0xC0000033L; /* Object name invalid */
2281 else if (code == CM_ERROR_WOULDBLOCK) {
2282 NTStatus = 0xC0000055L; /* Lock not granted */
2284 else if (code == CM_ERROR_PARTIALWRITE) {
2285 NTStatus = 0xC000007FL; /* Disk full */
2287 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2288 NTStatus = 0xC0000023L; /* Buffer too small */
2290 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2291 NTStatus = 0xC0000035L; /* Object name collision */
2293 else if (code == CM_ERROR_BADPASSWORD) {
2294 NTStatus = 0xC000006DL; /* unknown username or bad password */
2296 else if (code == CM_ERROR_BADLOGONTYPE) {
2297 NTStatus = 0xC000015BL; /* logon type not granted */
2299 else if (code == CM_ERROR_GSSCONTINUE) {
2300 NTStatus = 0xC0000016L; /* more processing required */
2302 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2304 NTStatus = 0xC0000280L; /* reparse point not resolved */
2306 NTStatus = 0xC0000022L; /* Access Denied */
2310 NTStatus = 0xC0982001L; /* SMB non-specific error */
2313 *NTStatusp = NTStatus;
2314 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2317 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2318 unsigned char *classp)
2320 unsigned char class;
2321 unsigned short error;
2323 /* map CM_ERROR_* errors to SMB errors */
2324 if (code == CM_ERROR_NOSUCHCELL) {
2326 error = 3; /* bad path */
2328 else if (code == CM_ERROR_NOSUCHVOLUME) {
2330 error = 3; /* bad path */
2332 else if (code == CM_ERROR_TIMEDOUT) {
2334 error = 81; /* server is paused */
2336 else if (code == CM_ERROR_RETRY) {
2337 class = 2; /* shouldn't happen */
2340 else if (code == CM_ERROR_NOACCESS) {
2342 error = 4; /* bad access */
2344 else if (code == CM_ERROR_READONLY) {
2346 error = 19; /* read only */
2348 else if (code == CM_ERROR_NOSUCHFILE) {
2350 error = 2; /* ENOENT! */
2352 else if (code == CM_ERROR_NOSUCHPATH) {
2354 error = 3; /* Bad path */
2356 else if (code == CM_ERROR_TOOBIG) {
2358 error = 11; /* bad format */
2360 else if (code == CM_ERROR_INVAL) {
2361 class = 2; /* server non-specific error code */
2364 else if (code == CM_ERROR_BADFD) {
2366 error = 6; /* invalid file handle */
2368 else if (code == CM_ERROR_BADFDOP) {
2369 class = 1; /* invalid op on FD */
2372 else if (code == CM_ERROR_EXISTS) {
2374 error = 80; /* file already exists */
2376 else if (code == CM_ERROR_NOTEMPTY) {
2378 error = 5; /* delete directory not empty */
2380 else if (code == CM_ERROR_CROSSDEVLINK) {
2382 error = 17; /* EXDEV */
2384 else if (code == CM_ERROR_NOTDIR) {
2385 class = 1; /* bad path */
2388 else if (code == CM_ERROR_ISDIR) {
2389 class = 1; /* access denied; DOS doesn't have a good match */
2392 else if (code == CM_ERROR_BADOP) {
2396 else if (code == CM_ERROR_BADSHARENAME) {
2400 else if (code == CM_ERROR_NOIPC) {
2402 error = 4; /* bad access */
2404 else if (code == CM_ERROR_CLOCKSKEW) {
2405 class = 1; /* invalid function */
2408 else if (code == CM_ERROR_BADTID) {
2412 else if (code == CM_ERROR_USESTD) {
2416 else if (code == CM_ERROR_REMOTECONN) {
2420 else if (code == CM_ERROR_QUOTA) {
2421 if (vcp->flags & SMB_VCFLAG_USEV3) {
2423 error = 39; /* disk full */
2427 error = 5; /* access denied */
2430 else if (code == CM_ERROR_SPACE) {
2431 if (vcp->flags & SMB_VCFLAG_USEV3) {
2433 error = 39; /* disk full */
2437 error = 5; /* access denied */
2440 else if (code == CM_ERROR_PARTIALWRITE) {
2442 error = 39; /* disk full */
2444 else if (code == CM_ERROR_ATSYS) {
2446 error = 2; /* ENOENT */
2448 else if (code == CM_ERROR_WOULDBLOCK) {
2450 error = 33; /* lock conflict */
2452 else if (code == CM_ERROR_NOFILES) {
2454 error = 18; /* no files in search */
2456 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2458 error = 183; /* Samba uses this */
2460 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2461 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2463 error = 2; /* bad password */
2472 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2475 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2477 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2478 return CM_ERROR_BADOP;
2481 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2483 unsigned short EchoCount, i;
2484 char *data, *outdata;
2487 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2489 for (i=1; i<=EchoCount; i++) {
2490 data = smb_GetSMBData(inp, &dataSize);
2491 smb_SetSMBParm(outp, 0, i);
2492 smb_SetSMBDataLength(outp, dataSize);
2493 outdata = smb_GetSMBData(outp, NULL);
2494 memcpy(outdata, data, dataSize);
2495 smb_SendPacket(vcp, outp);
2501 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2504 long count, minCount, finalCount;
2508 cm_user_t *userp = NULL;
2512 char *rawBuf = NULL;
2514 dos_ptr rawBuf = NULL;
2521 fd = smb_GetSMBParm(inp, 0);
2522 count = smb_GetSMBParm(inp, 3);
2523 minCount = smb_GetSMBParm(inp, 4);
2524 offset.HighPart = 0; /* too bad */
2525 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2527 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2528 fd, offset.LowPart, count);
2530 fidp = smb_FindFID(vcp, fd, 0);
2534 lock_ObtainMutex(&smb_RawBufLock);
2536 /* Get a raw buf, from head of list */
2537 rawBuf = smb_RawBufs;
2539 smb_RawBufs = *(char **)smb_RawBufs;
2541 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2544 lock_ReleaseMutex(&smb_RawBufLock);
2548 if (fidp->flags & SMB_FID_IOCTL)
2551 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2553 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2556 /* Give back raw buffer */
2557 lock_ObtainMutex(&smb_RawBufLock);
2559 *((char **) rawBuf) = smb_RawBufs;
2561 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2564 smb_RawBufs = rawBuf;
2565 lock_ReleaseMutex(&smb_RawBufLock);
2568 smb_ReleaseFID(fidp);
2572 userp = smb_GetUser(vcp, inp);
2575 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2577 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2578 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2579 userp, &finalCount, TRUE /* rawFlag */);
2586 cm_ReleaseUser(userp);
2589 smb_ReleaseFID(fidp);
2594 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2596 memset((char *)ncbp, 0, sizeof(NCB));
2598 ncbp->ncb_length = (unsigned short) finalCount;
2599 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2600 ncbp->ncb_lana_num = vcp->lana;
2601 ncbp->ncb_command = NCBSEND;
2602 ncbp->ncb_buffer = rawBuf;
2605 code = Netbios(ncbp);
2607 code = Netbios(ncbp, dos_ncb);
2610 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2613 /* Give back raw buffer */
2614 lock_ObtainMutex(&smb_RawBufLock);
2616 *((char **) rawBuf) = smb_RawBufs;
2618 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2621 smb_RawBufs = rawBuf;
2622 lock_ReleaseMutex(&smb_RawBufLock);
2628 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2630 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2635 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2637 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2642 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2649 int protoIndex; /* index we're using */
2654 char protocol_array[10][1024]; /* protocol signature of the client */
2655 int caps; /* capabilities */
2658 TIME_ZONE_INFORMATION tzi;
2660 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2664 DWORD now = GetCurrentTime();
2665 if (now - last_msg_time >= 30000
2666 && now - last_msg_time <= 90000) {
2668 "Setting dead_vcp %x", active_vcp);
2670 smb_ReleaseVC(dead_vcp);
2672 "Previous dead_vcp %x", dead_vcp);
2674 smb_HoldVC(active_vcp);
2675 dead_vcp = active_vcp;
2676 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2681 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2683 namep = smb_GetSMBData(inp, &dbytes);
2686 coreProtoIndex = -1; /* not found */
2689 while(namex < dbytes) {
2690 osi_Log1(smb_logp, "Protocol %s",
2691 osi_LogSaveString(smb_logp, namep+1));
2692 strcpy(protocol_array[tcounter], namep+1);
2694 /* namep points at the first protocol, or really, a 0x02
2695 * byte preceding the null-terminated ASCII name.
2697 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2698 coreProtoIndex = tcounter;
2700 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2701 v3ProtoIndex = tcounter;
2703 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2704 NTProtoIndex = tcounter;
2707 /* compute size of protocol entry */
2708 entryLength = strlen(namep+1);
2709 entryLength += 2; /* 0x02 bytes and null termination */
2711 /* advance over this protocol entry */
2712 namex += entryLength;
2713 namep += entryLength;
2714 tcounter++; /* which proto entry we're looking at */
2717 if (NTProtoIndex != -1) {
2718 protoIndex = NTProtoIndex;
2719 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2721 else if (v3ProtoIndex != -1) {
2722 protoIndex = v3ProtoIndex;
2723 vcp->flags |= SMB_VCFLAG_USEV3;
2725 else if (coreProtoIndex != -1) {
2726 protoIndex = coreProtoIndex;
2727 vcp->flags |= SMB_VCFLAG_USECORE;
2729 else protoIndex = -1;
2731 if (protoIndex == -1)
2732 return CM_ERROR_INVAL;
2733 else if (NTProtoIndex != -1) {
2734 smb_SetSMBParm(outp, 0, protoIndex);
2735 if (smb_authType != SMB_AUTH_NONE) {
2736 smb_SetSMBParmByte(outp, 1,
2737 NEGOTIATE_SECURITY_USER_LEVEL |
2738 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2740 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2742 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2743 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2744 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2745 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2746 /* The session key is not a well documented field however most clients
2747 * will echo back the session key to the server. Currently we are using
2748 * the same value for all sessions. We should generate a random value
2749 * and store it into the vcp
2751 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2752 smb_SetSMBParm(outp, 8, 1);
2754 * Tried changing the capabilities to support for W2K - defect 117695
2755 * Maybe something else needs to be changed here?
2759 smb_SetSMBParmLong(outp, 9, 0x43fd);
2761 smb_SetSMBParmLong(outp, 9, 0x251);
2764 * 32-bit error codes *
2768 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2769 NTNEGOTIATE_CAPABILITY_NTFIND |
2770 NTNEGOTIATE_CAPABILITY_RAWMODE |
2771 NTNEGOTIATE_CAPABILITY_NTSMB;
2773 if ( smb_authType == SMB_AUTH_EXTENDED )
2774 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2776 smb_SetSMBParmLong(outp, 9, caps);
2778 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2779 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2780 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2782 GetTimeZoneInformation(&tzi);
2783 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2785 if (smb_authType == SMB_AUTH_NTLM) {
2786 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2787 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2788 /* paste in encryption key */
2789 datap = smb_GetSMBData(outp, NULL);
2790 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2791 /* and the faux domain name */
2792 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2793 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2797 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2799 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2801 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2803 datap = smb_GetSMBData(outp, NULL);
2804 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2807 datap += sizeof(smb_ServerGUID);
2808 memcpy(datap, secBlob, secBlobLength);
2812 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2813 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2816 else if (v3ProtoIndex != -1) {
2817 smb_SetSMBParm(outp, 0, protoIndex);
2819 /* NOTE: Extended authentication cannot be negotiated with v3
2820 * therefore we fail over to NTLM
2822 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2823 smb_SetSMBParm(outp, 1,
2824 NEGOTIATE_SECURITY_USER_LEVEL |
2825 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2827 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2829 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2830 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2831 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2832 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2833 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2834 smb_SetSMBParm(outp, 7, 1);
2836 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2837 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2838 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2840 GetTimeZoneInformation(&tzi);
2841 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2843 /* NOTE: Extended authentication cannot be negotiated with v3
2844 * therefore we fail over to NTLM
2846 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2847 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2848 smb_SetSMBParm(outp, 12, 0); /* resvd */
2849 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2850 datap = smb_GetSMBData(outp, NULL);
2851 /* paste in a new encryption key */
2852 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2853 /* and the faux domain name */
2854 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2856 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2857 smb_SetSMBParm(outp, 12, 0); /* resvd */
2858 smb_SetSMBDataLength(outp, 0);
2861 else if (coreProtoIndex != -1) { /* not really supported anymore */
2862 smb_SetSMBParm(outp, 0, protoIndex);
2863 smb_SetSMBDataLength(outp, 0);
2868 void smb_Daemon(void *parmp)
2870 afs_uint32 count = 0;
2872 while(smbShutdownFlag == 0) {
2876 if (smbShutdownFlag == 1)
2879 if ((count % 72) == 0) { /* every five minutes */
2881 time_t old_localZero = smb_localZero;
2883 /* Initialize smb_localZero */
2884 myTime.tm_isdst = -1; /* compute whether on DST or not */
2885 myTime.tm_year = 70;
2891 smb_localZero = mktime(&myTime);
2893 smb_CalculateNowTZ();
2895 #ifdef AFS_FREELANCE
2896 if ( smb_localZero != old_localZero )
2897 cm_noteLocalMountPointChange();
2900 /* XXX GC dir search entries */
2904 void smb_WaitingLocksDaemon()
2906 smb_waitingLock_t *wL, *nwL;
2909 smb_packet_t *inp, *outp;
2914 lock_ObtainWrite(&smb_globalLock);
2915 nwL = smb_allWaitingLocks;
2917 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2926 lock_ObtainWrite(&smb_globalLock);
2928 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2929 lock_ReleaseWrite(&smb_globalLock);
2930 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2931 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2932 if (code == CM_ERROR_WOULDBLOCK) {
2934 if (wL->timeRemaining != 0xffffffff
2935 && (wL->timeRemaining -= 1000) < 0)
2944 ncbp->ncb_length = inp->ncb_length;
2945 inp->spacep = cm_GetSpace();
2947 /* Remove waitingLock from list */
2948 lock_ObtainWrite(&smb_globalLock);
2949 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2951 lock_ReleaseWrite(&smb_globalLock);
2953 /* Resume packet processing */
2955 smb_SetSMBDataLength(outp, 0);
2956 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2957 outp->resumeCode = code;
2959 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2962 cm_FreeSpace(inp->spacep);
2963 smb_FreePacket(inp);
2964 smb_FreePacket(outp);
2972 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2974 osi_Log0(smb_logp, "SMB receive get disk attributes");
2976 smb_SetSMBParm(outp, 0, 32000);
2977 smb_SetSMBParm(outp, 1, 64);
2978 smb_SetSMBParm(outp, 2, 1024);
2979 smb_SetSMBParm(outp, 3, 30000);
2980 smb_SetSMBParm(outp, 4, 0);
2981 smb_SetSMBDataLength(outp, 0);
2985 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2989 unsigned short newTid;
2990 char shareName[256];
2998 osi_Log0(smb_logp, "SMB receive tree connect");
3000 /* parse input parameters */
3001 tp = smb_GetSMBData(inp, NULL);
3002 pathp = smb_ParseASCIIBlock(tp, &tp);
3003 if (smb_StoreAnsiFilenames)
3004 OemToChar(pathp,pathp);
3005 passwordp = smb_ParseASCIIBlock(tp, &tp);
3006 tp = strrchr(pathp, '\\');
3008 return CM_ERROR_BADSMB;
3009 strcpy(shareName, tp+1);
3011 userp = smb_GetUser(vcp, inp);
3013 lock_ObtainMutex(&vcp->mx);
3014 newTid = vcp->tidCounter++;
3015 lock_ReleaseMutex(&vcp->mx);
3017 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3018 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3019 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3021 smb_ReleaseUID(uidp);
3023 smb_ReleaseTID(tidp);
3024 return CM_ERROR_BADSHARENAME;
3026 lock_ObtainMutex(&tidp->mx);
3027 tidp->userp = userp;
3028 tidp->pathname = sharePath;
3029 lock_ReleaseMutex(&tidp->mx);
3030 smb_ReleaseTID(tidp);
3032 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3033 smb_SetSMBParm(rsp, 1, newTid);
3034 smb_SetSMBDataLength(rsp, 0);
3036 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3040 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3044 if (*inp++ != 0x1) return NULL;
3045 tlen = inp[0] + (inp[1]<<8);
3046 inp += 2; /* skip length field */
3049 *chainpp = inp + tlen;
3052 if (lengthp) *lengthp = tlen;
3057 /* set maskp to the mask part of the incoming path.
3058 * Mask is 11 bytes long (8.3 with the dot elided).
3059 * Returns true if succeeds with a valid name, otherwise it does
3060 * its best, but returns false.
3062 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3070 /* starts off valid */
3073 /* mask starts out all blanks */
3074 memset(maskp, ' ', 11);
3076 /* find last backslash, or use whole thing if there is none */
3077 tp = strrchr(pathp, '\\');
3078 if (!tp) tp = pathp;
3079 else tp++; /* skip slash */
3083 /* names starting with a dot are illegal */
3084 if (*tp == '.') valid8Dot3 = 0;
3088 if (tc == 0) return valid8Dot3;
3089 if (tc == '.' || tc == '"') break;
3090 if (i < 8) *up++ = tc;
3091 else valid8Dot3 = 0;
3094 /* if we get here, tp point after the dot */
3095 up = maskp+8; /* ext goes here */
3102 if (tc == '.' || tc == '"')
3105 /* copy extension if not too long */
3115 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3125 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3127 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3131 /* otherwise, we have a valid 8.3 name; see if we have a match,
3132 * treating '?' as a wildcard in maskp (but not in the file name).
3134 tp1 = umask; /* real name, in mask format */
3135 tp2 = maskp; /* mask, in mask format */
3136 for(i=0; i<11; i++) {
3137 tc1 = *tp1++; /* char from real name */
3138 tc2 = *tp2++; /* char from mask */
3139 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3140 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3143 if (tc2 == '?' && tc1 != ' ')
3150 /* we got a match */
3154 char *smb_FindMask(char *pathp)
3158 tp = strrchr(pathp, '\\'); /* find last slash */
3161 return tp+1; /* skip the slash */
3163 return pathp; /* no slash, return the entire path */
3166 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3168 unsigned char *pathp;
3170 unsigned char mask[11];
3171 unsigned char *statBlockp;
3172 unsigned char initStatBlock[21];
3175 osi_Log0(smb_logp, "SMB receive search volume");
3177 /* pull pathname and stat block out of request */
3178 tp = smb_GetSMBData(inp, NULL);
3179 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3180 osi_assert(pathp != NULL);
3181 if (smb_StoreAnsiFilenames)
3182 OemToChar(pathp,pathp);
3183 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3184 osi_assert(statBlockp != NULL);
3186 statBlockp = initStatBlock;
3190 /* for returning to caller */
3191 smb_Get8Dot3MaskFromPath(mask, pathp);
3193 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3194 tp = smb_GetSMBData(outp, NULL);
3196 *tp++ = 43; /* bytes in a dir entry */
3197 *tp++ = 0; /* high byte in counter */
3199 /* now marshall the dir entry, starting with the search status */
3200 *tp++ = statBlockp[0]; /* Reserved */
3201 memcpy(tp, mask, 11); tp += 11; /* FileName */
3203 /* now pass back server use info, with 1st byte non-zero */
3205 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3207 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3209 *tp++ = 0x8; /* attribute: volume */
3219 /* 4 byte file size */
3225 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3226 memset(tp, ' ', 13);
3229 /* set the length of the data part of the packet to 43 + 3, for the dir
3230 * entry plus the 5 and the length fields.
3232 smb_SetSMBDataLength(outp, 46);
3236 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3237 cm_user_t *userp, cm_req_t *reqp)
3245 smb_dirListPatch_t *patchp;
3246 smb_dirListPatch_t *npatchp;
3248 for (patchp = *dirPatchespp; patchp; patchp =
3249 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3251 dptr = patchp->dptr;
3253 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3255 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3256 *dptr++ = SMB_ATTR_HIDDEN;
3259 lock_ObtainMutex(&scp->mx);
3260 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3261 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3263 lock_ReleaseMutex(&scp->mx);
3264 cm_ReleaseSCache(scp);
3265 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3266 *dptr++ = SMB_ATTR_HIDDEN;
3270 attr = smb_Attributes(scp);
3271 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3272 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3273 attr |= SMB_ATTR_HIDDEN;
3277 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3280 shortTemp = (unsigned short) (dosTime & 0xffff);
3281 *((u_short *)dptr) = shortTemp;
3284 /* and copy out date */
3285 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3286 *((u_short *)dptr) = shortTemp;
3289 /* copy out file length */
3290 *((u_long *)dptr) = scp->length.LowPart;
3292 lock_ReleaseMutex(&scp->mx);
3293 cm_ReleaseSCache(scp);
3296 /* now free the patches */
3297 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3298 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3302 /* and mark the list as empty */
3303 *dirPatchespp = NULL;
3308 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3317 smb_dirListPatch_t *dirListPatchesp;
3318 smb_dirListPatch_t *curPatchp;
3322 osi_hyper_t dirLength;
3323 osi_hyper_t bufferOffset;
3324 osi_hyper_t curOffset;
3326 unsigned char *inCookiep;
3327 smb_dirSearch_t *dsp;
3331 unsigned long clientCookie;
3332 cm_pageHeader_t *pageHeaderp;
3333 cm_user_t *userp = NULL;
3340 long nextEntryCookie;
3341 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3342 char resByte; /* reserved byte from the cookie */
3343 char *op; /* output data ptr */
3344 char *origOp; /* original value of op */
3345 cm_space_t *spacep; /* for pathname buffer */
3356 maxCount = smb_GetSMBParm(inp, 0);
3358 dirListPatchesp = NULL;
3360 caseFold = CM_FLAG_CASEFOLD;
3362 tp = smb_GetSMBData(inp, NULL);
3363 pathp = smb_ParseASCIIBlock(tp, &tp);
3364 if (smb_StoreAnsiFilenames)
3365 OemToChar(pathp,pathp);
3366 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3368 /* bail out if request looks bad */
3369 if (!tp || !pathp) {
3370 return CM_ERROR_BADSMB;
3373 /* We can handle long names */
3374 if (vcp->flags & SMB_VCFLAG_USENT)
3375 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3377 /* make sure we got a whole search status */
3378 if (dataLength < 21) {
3379 nextCookie = 0; /* start at the beginning of the dir */
3382 attribute = smb_GetSMBParm(inp, 1);
3384 /* handle volume info in another function */
3385 if (attribute & 0x8)
3386 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3388 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3389 maxCount, osi_LogSaveString(smb_logp, pathp));
3391 if (*pathp == 0) { /* null pathp, treat as root dir */
3392 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3393 return CM_ERROR_NOFILES;
3397 dsp = smb_NewDirSearch(0);
3398 dsp->attribute = attribute;
3399 smb_Get8Dot3MaskFromPath(mask, pathp);
3400 memcpy(dsp->mask, mask, 11);
3402 /* track if this is likely to match a lot of entries */
3403 if (smb_IsStarMask(mask)) starPattern = 1;
3404 else starPattern = 0;
3407 /* pull the next cookie value out of the search status block */
3408 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3409 + (inCookiep[16]<<24);
3410 dsp = smb_FindDirSearch(inCookiep[12]);
3412 /* can't find dir search status; fatal error */
3413 return CM_ERROR_BADFD;
3415 attribute = dsp->attribute;
3416 resByte = inCookiep[0];
3418 /* copy out client cookie, in host byte order. Don't bother
3419 * interpreting it, since we're just passing it through, anyway.
3421 memcpy(&clientCookie, &inCookiep[17], 4);
3423 memcpy(mask, dsp->mask, 11);
3425 /* assume we're doing a star match if it has continued for more
3431 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3432 nextCookie, dsp->cookie, attribute);
3434 userp = smb_GetUser(vcp, inp);
3436 /* try to get the vnode for the path name next */
3437 lock_ObtainMutex(&dsp->mx);
3444 spacep = inp->spacep;
3445 smb_StripLastComponent(spacep->data, NULL, pathp);
3446 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3448 lock_ReleaseMutex(&dsp->mx);
3449 cm_ReleaseUser(userp);
3450 smb_DeleteDirSearch(dsp);
3451 smb_ReleaseDirSearch(dsp);
3452 return CM_ERROR_NOFILES;
3454 code = cm_NameI(cm_rootSCachep, spacep->data,
3455 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3458 cm_ReleaseSCache(dsp->scp);
3460 /* we need one hold for the entry we just stored into,
3461 * and one for our own processing. When we're done with this
3462 * function, we'll drop the one for our own processing.
3463 * We held it once from the namei call, and so we do another hold
3467 lock_ObtainMutex(&scp->mx);
3468 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3469 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3470 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3471 dsp->flags |= SMB_DIRSEARCH_BULKST;
3473 lock_ReleaseMutex(&scp->mx);
3476 lock_ReleaseMutex(&dsp->mx);
3478 cm_ReleaseUser(userp);
3479 smb_DeleteDirSearch(dsp);
3480 smb_ReleaseDirSearch(dsp);
3484 /* reserves space for parameter; we'll adjust it again later to the
3485 * real count of the # of entries we returned once we've actually
3486 * assembled the directory listing.
3488 smb_SetSMBParm(outp, 0, 0);
3490 /* get the directory size */
3491 lock_ObtainMutex(&scp->mx);
3492 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3493 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3495 lock_ReleaseMutex(&scp->mx);
3496 cm_ReleaseSCache(scp);
3497 cm_ReleaseUser(userp);
3498 smb_DeleteDirSearch(dsp);
3499 smb_ReleaseDirSearch(dsp);
3503 dirLength = scp->length;
3505 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3506 curOffset.HighPart = 0;
3507 curOffset.LowPart = nextCookie;
3508 origOp = op = smb_GetSMBData(outp, NULL);
3509 /* and write out the basic header */
3510 *op++ = 5; /* variable block */
3511 op += 2; /* skip vbl block length; we'll fill it in later */
3515 /* make sure that curOffset.LowPart doesn't point to the first
3516 * 32 bytes in the 2nd through last dir page, and that it doesn't
3517 * point at the first 13 32-byte chunks in the first dir page,
3518 * since those are dir and page headers, and don't contain useful
3521 temp = curOffset.LowPart & (2048-1);
3522 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3523 /* we're in the first page */
3524 if (temp < 13*32) temp = 13*32;
3527 /* we're in a later dir page */
3528 if (temp < 32) temp = 32;
3531 /* make sure the low order 5 bits are zero */
3534 /* now put temp bits back ito curOffset.LowPart */
3535 curOffset.LowPart &= ~(2048-1);
3536 curOffset.LowPart |= temp;
3538 /* check if we've returned all the names that will fit in the
3541 if (returnedNames >= maxCount)
3544 /* check if we've passed the dir's EOF */
3545 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3547 /* see if we can use the bufferp we have now; compute in which page
3548 * the current offset would be, and check whether that's the offset
3549 * of the buffer we have. If not, get the buffer.
3551 thyper.HighPart = curOffset.HighPart;
3552 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3553 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3556 buf_Release(bufferp);
3559 lock_ReleaseMutex(&scp->mx);
3560 lock_ObtainRead(&scp->bufCreateLock);
3561 code = buf_Get(scp, &thyper, &bufferp);
3562 lock_ReleaseRead(&scp->bufCreateLock);
3563 lock_ObtainMutex(&dsp->mx);
3565 /* now, if we're doing a star match, do bulk fetching of all of
3566 * the status info for files in the dir.
3569 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3570 lock_ObtainMutex(&scp->mx);
3571 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3572 LargeIntegerGreaterThanOrEqualTo(thyper,
3573 scp->bulkStatProgress)) {
3574 /* Don't bulk stat if risking timeout */
3575 int now = GetCurrentTime();
3576 if (now - req.startTime > 5000) {
3577 scp->bulkStatProgress = thyper;
3578 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3579 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3581 cm_TryBulkStat(scp, &thyper, userp, &req);
3584 lock_ObtainMutex(&scp->mx);
3586 lock_ReleaseMutex(&dsp->mx);
3590 bufferOffset = thyper;
3592 /* now get the data in the cache */
3594 code = cm_SyncOp(scp, bufferp, userp, &req,
3596 CM_SCACHESYNC_NEEDCALLBACK |
3597 CM_SCACHESYNC_READ);
3600 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3602 /* otherwise, load the buffer and try again */
3603 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3607 buf_Release(bufferp);
3611 } /* if (wrong buffer) ... */
3613 /* now we have the buffer containing the entry we're interested in; copy
3614 * it out if it represents a non-deleted entry.
3616 entryInDir = curOffset.LowPart & (2048-1);
3617 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3619 /* page header will help tell us which entries are free. Page header
3620 * can change more often than once per buffer, since AFS 3 dir page size
3621 * may be less than (but not more than a buffer package buffer.
3623 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3624 temp &= ~(2048 - 1); /* turn off intra-page bits */
3625 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3627 /* now determine which entry we're looking at in the page. If it is
3628 * free (there's a free bitmap at the start of the dir), we should
3629 * skip these 32 bytes.
3631 slotInPage = (entryInDir & 0x7e0) >> 5;
3632 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3633 /* this entry is free */
3634 numDirChunks = 1; /* only skip this guy */
3638 tp = bufferp->datap + entryInBuffer;
3639 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3641 /* while we're here, compute the next entry's location, too,
3642 * since we'll need it when writing out the cookie into the dir
3645 * XXXX Probably should do more sanity checking.
3647 numDirChunks = cm_NameEntries(dep->name, NULL);
3649 /* compute the offset of the cookie representing the next entry */
3650 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3652 /* Compute 8.3 name if necessary */
3653 actualName = dep->name;
3654 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3655 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3656 actualName = shortName;
3659 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3660 /* this is one of the entries to use: it is not deleted
3661 * and it matches the star pattern we're looking for.
3664 /* Eliminate entries that don't match requested
3667 /* no hidden files */
3668 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3671 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3673 /* We have already done the cm_TryBulkStat above */
3674 fid.cell = scp->fid.cell;
3675 fid.volume = scp->fid.volume;
3676 fid.vnode = ntohl(dep->fid.vnode);
3677 fid.unique = ntohl(dep->fid.unique);
3678 fileType = cm_FindFileType(&fid);
3679 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3680 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3682 if (fileType == CM_SCACHETYPE_DIRECTORY)
3687 memcpy(op, mask, 11); op += 11;
3688 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3689 *op++ = nextEntryCookie & 0xff;
3690 *op++ = (nextEntryCookie>>8) & 0xff;
3691 *op++ = (nextEntryCookie>>16) & 0xff;
3692 *op++ = (nextEntryCookie>>24) & 0xff;
3693 memcpy(op, &clientCookie, 4); op += 4;
3695 /* now we emit the attribute. This is sort of tricky,
3696 * since we need to really stat the file to find out
3697 * what type of entry we've got. Right now, we're
3698 * copying out data from a buffer, while holding the
3699 * scp locked, so it isn't really convenient to stat
3700 * something now. We'll put in a place holder now,
3701 * and make a second pass before returning this to get
3702 * the real attributes. So, we just skip the data for
3703 * now, and adjust it later. We allocate a patch
3704 * record to make it easy to find this point later.
3705 * The replay will happen at a time when it is safe to
3706 * unlock the directory.
3708 curPatchp = malloc(sizeof(*curPatchp));
3709 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3710 curPatchp->dptr = op;
3711 curPatchp->fid.cell = scp->fid.cell;
3712 curPatchp->fid.volume = scp->fid.volume;
3713 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3714 curPatchp->fid.unique = ntohl(dep->fid.unique);
3716 /* do hidden attribute here since name won't be around when applying
3720 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3721 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;