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 DWORD last_msg_time = 0;
58 unsigned int sessionGen = 0;
60 extern void afsi_log(char *pattern, ...);
61 extern HANDLE afsi_file;
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t smb_ListenerLock;
72 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
75 long smb_maxObsConcurrentCalls=0;
76 long smb_concurrentCalls=0;
78 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
80 smb_packet_t *smb_packetFreeListp;
81 smb_ncb_t *smb_ncbFreeListp;
83 int smb_NumServerThreads;
85 int numNCBs, numSessions, numVCs;
87 int smb_maxVCPerServer;
88 int smb_maxMpxRequests;
90 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
92 ULONG smb_lsaSecPackage;
93 LSA_STRING smb_lsaLogonOrigin;
95 #define NCBmax MAXIMUM_WAIT_OBJECTS
96 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
97 EVENT_HANDLE **NCBreturns;
98 DWORD NCBsessions[NCBmax];
100 struct smb_packet *bufs[NCBmax];
102 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
103 EVENT_HANDLE SessionEvents[Sessionmax];
104 unsigned short LSNs[Sessionmax];
105 int lanas[Sessionmax];
106 BOOL dead_sessions[Sessionmax];
110 osi_mutex_t smb_RawBufLock;
112 #define SMB_RAW_BUFS 4
114 int smb_RawBufSel[SMB_RAW_BUFS];
119 #define SMB_MASKFLAG_TILDE 1
120 #define SMB_MASKFLAG_CASEFOLD 2
122 #define RAWTIMEOUT INFINITE
125 typedef struct raw_write_cont {
138 /* dir search stuff */
139 long smb_dirSearchCounter = 1;
140 smb_dirSearch_t *smb_firstDirSearchp;
141 smb_dirSearch_t *smb_lastDirSearchp;
143 /* hide dot files? */
144 int smb_hideDotFiles;
146 /* global state about V3 protocols */
147 int smb_useV3; /* try to negotiate V3 */
150 static showErrors = 1;
151 /* MessageBox or something like it */
152 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
153 extern HANDLE WaitToTerminate;
157 * Time in Unix format of midnight, 1/1/1970 local time.
158 * When added to dosUTime, gives Unix (AFS) time.
160 long smb_localZero = 0;
162 /* Time difference for converting to kludge-GMT */
165 char *smb_localNamep = NULL;
167 smb_vc_t *smb_allVCsp;
169 smb_username_t *usernamesp = NULL;
171 smb_waitingLock_t *smb_allWaitingLocks;
174 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
175 NCB *ncbp, raw_write_cont_t *rwcp);
176 void smb_NetbiosInit();
178 #ifndef AFS_WIN95_ENV
179 DWORD smb_ServerExceptionFilter(void);
182 extern char cm_HostName[];
183 extern char cm_confDir[];
187 #define LPTSTR char *
188 #define GetComputerName(str, sizep) \
189 strcpy((str), cm_HostName); \
190 *(sizep) = strlen(cm_HostName)
194 void smb_LogPacket(smb_packet_t *packet);
195 #endif /* LOG_PACKET */
196 extern char AFSConfigKeyName[];
198 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
199 int smb_ServerDomainNameLength = 0;
200 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
201 int smb_ServerOSLength = sizeof(smb_ServerOS);
202 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
203 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
205 /* Faux server GUID. This is never checked. */
206 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
208 char * myCrt_Dispatch(int i)
213 return "(00)ReceiveCoreMakeDir";
215 return "(01)ReceiveCoreRemoveDir";
217 return "(02)ReceiveCoreOpen";
219 return "(03)ReceiveCoreCreate";
221 return "(04)ReceiveCoreClose";
223 return "(05)ReceiveCoreFlush";
225 return "(06)ReceiveCoreUnlink";
227 return "(07)ReceiveCoreRename";
229 return "(08)ReceiveCoreGetFileAttributes";
231 return "(09)ReceiveCoreSetFileAttributes";
233 return "(0a)ReceiveCoreRead";
235 return "(0b)ReceiveCoreWrite";
237 return "(0c)ReceiveCoreLockRecord";
239 return "(0d)ReceiveCoreUnlockRecord";
241 return "(0e)SendCoreBadOp";
243 return "(0f)ReceiveCoreCreate";
245 return "(10)ReceiveCoreCheckPath";
247 return "(11)SendCoreBadOp";
249 return "(12)ReceiveCoreSeek";
251 return "(1a)ReceiveCoreReadRaw";
253 return "(1d)ReceiveCoreWriteRawDummy";
255 return "(22)ReceiveV3SetAttributes";
257 return "(23)ReceiveV3GetAttributes";
259 return "(24)ReceiveV3LockingX";
261 return "(25)ReceiveV3Trans";
263 return "(26)ReceiveV3Trans[aux]";
265 return "(29)SendCoreBadOp";
267 return "(2b)ReceiveCoreEcho";
269 return "(2d)ReceiveV3OpenX";
271 return "(2e)ReceiveV3ReadX";
273 return "(32)ReceiveV3Tran2A";
275 return "(33)ReceiveV3Tran2A[aux]";
277 return "(34)ReceiveV3FindClose";
279 return "(35)ReceiveV3FindNotifyClose";
281 return "(70)ReceiveCoreTreeConnect";
283 return "(71)ReceiveCoreTreeDisconnect";
285 return "(72)ReceiveNegotiate";
287 return "(73)ReceiveV3SessionSetupX";
289 return "(74)ReceiveV3UserLogoffX";
291 return "(75)ReceiveV3TreeConnectX";
293 return "(80)ReceiveCoreGetDiskAttributes";
295 return "(81)ReceiveCoreSearchDir";
299 return "(83)FindUnique";
301 return "(84)FindClose";
303 return "(A0)ReceiveNTTransact";
305 return "(A2)ReceiveNTCreateX";
307 return "(A4)ReceiveNTCancel";
309 return "(A5)ReceiveNTRename";
311 return "(C0)OpenPrintFile";
313 return "(C1)WritePrintFile";
315 return "(C2)ClosePrintFile";
317 return "(C3)GetPrintQueue";
319 return "(D8)ReadBulk";
321 return "(D9)WriteBulk";
323 return "(DA)WriteBulkData";
325 return "unknown SMB op";
329 char * myCrt_2Dispatch(int i)
334 return "unknown SMB op-2";
336 return "S(00)CreateFile";
338 return "S(01)FindFirst";
340 return "S(02)FindNext"; /* FindNext */
342 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
346 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
348 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
350 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
352 return "S(08)??_ReceiveTran2SetFileInfo";
354 return "S(09)??_ReceiveTran2FSCTL";
356 return "S(0a)_ReceiveTran2IOCTL";
358 return "S(0b)_ReceiveTran2FindNotifyFirst";
360 return "S(0c)_ReceiveTran2FindNotifyNext";
362 return "S(0d)_ReceiveTran2CreateDirectory";
364 return "S(0e)_ReceiveTran2SessionSetup";
368 char * myCrt_RapDispatch(int i)
373 return "unknown RAP OP";
375 return "RAP(0)NetShareEnum";
377 return "RAP(1)NetShareGetInfo";
379 return "RAP(13)NetServerGetInfo";
381 return "RAP(63)NetWkStaGetInfo";
385 /* scache must be locked */
386 unsigned int smb_Attributes(cm_scache_t *scp)
390 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
391 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
392 attrs = SMB_ATTR_DIRECTORY;
397 * We used to mark a file RO if it was in an RO volume, but that
398 * turns out to be impolitic in NT. See defect 10007.
401 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
403 if ((scp->unixModeBits & 0222) == 0)
404 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
409 /* Check if the named file/dir is a dotfile/dotdir */
410 /* String pointed to by lastComp can have leading slashes, but otherwise should have
411 no other patch components */
412 unsigned int smb_IsDotFile(char *lastComp) {
415 /* skip over slashes */
416 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
421 /* nulls, curdir and parent dir doesn't count */
427 if(*(s+1) == '.' && !*(s + 2))
434 static int ExtractBits(WORD bits, short start, short len)
441 num = bits << (16 - end);
442 num = num >> ((16 - end) + start);
448 void ShowUnixTime(char *FuncName, time_t unixTime)
453 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
455 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
456 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
458 int day, month, year, sec, min, hour;
461 day = ExtractBits(wDate, 0, 5);
462 month = ExtractBits(wDate, 5, 4);
463 year = ExtractBits(wDate, 9, 7) + 1980;
465 sec = ExtractBits(wTime, 0, 5);
466 min = ExtractBits(wTime, 5, 6);
467 hour = ExtractBits(wTime, 11, 5);
469 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
470 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
476 /* Determine if we are observing daylight savings time */
477 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
479 TIME_ZONE_INFORMATION timeZoneInformation;
480 SYSTEMTIME utc, local, localDST;
482 /* Get the time zone info. NT uses this to calc if we are in DST. */
483 GetTimeZoneInformation(&timeZoneInformation);
485 /* Return the daylight bias */
486 *pDstBias = timeZoneInformation.DaylightBias;
488 /* Return the bias */
489 *pBias = timeZoneInformation.Bias;
491 /* Now determine if DST is being observed */
493 /* Get the UTC (GMT) time */
496 /* Convert UTC time to local time using the time zone info. If we are
497 observing DST, the calculated local time will include this.
499 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
501 /* Set the daylight bias to 0. The daylight bias is the amount of change
502 * in time that we use for daylight savings time. By setting this to 0
503 * we cause there to be no change in time during daylight savings time.
505 timeZoneInformation.DaylightBias = 0;
507 /* Convert the utc time to local time again, but this time without any
508 adjustment for daylight savings time.
510 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
512 /* If the two times are different, then it means that the localDST that
513 we calculated includes the daylight bias, and therefore we are
514 observing daylight savings time.
516 *pDST = localDST.wHour != local.wHour;
519 /* Determine if we are observing daylight savings time */
520 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
526 *pDstBias = -60; /* where can this be different? */
532 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
534 BOOL dst; /* Will be TRUE if observing DST */
535 LONG dstBias; /* Offset from local time if observing DST */
536 LONG bias; /* Offset from GMT for local time */
539 * This function will adjust the last write time to compensate
540 * for two bugs in the smb client:
542 * 1) During Daylight Savings Time, the LastWriteTime is ahead
543 * in time by the DaylightBias (ignoring the sign - the
544 * DaylightBias is always stored as a negative number). If
545 * the DaylightBias is -60, then the LastWriteTime will be
546 * ahead by 60 minutes.
548 * 2) If the local time zone is a positive offset from GMT, then
549 * the LastWriteTime will be the correct local time plus the
550 * Bias (ignoring the sign - a positive offset from GMT is
551 * always stored as a negative Bias). If the Bias is -120,
552 * then the LastWriteTime will be ahead by 120 minutes.
554 * These bugs can occur at the same time.
557 GetTimeZoneInfo(&dst, &dstBias, &bias);
559 /* First adjust for DST */
561 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
563 /* Now adjust for a positive offset from GMT (a negative bias). */
565 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
569 * Calculate the difference (in seconds) between local time and GMT.
570 * This enables us to convert file times to kludge-GMT.
576 struct tm gmt_tm, local_tm;
577 int days, hours, minutes, seconds;
580 gmt_tm = *(gmtime(&t));
581 local_tm = *(localtime(&t));
583 days = local_tm.tm_yday - gmt_tm.tm_yday;
584 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
586 /* There is a problem with DST immediately after the time change
587 * which may continue to exist until the machine is rebooted
589 - (local_tm.tm_isdst ? 1 : 0)
592 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
593 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
599 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
604 time_t ersatz_unixTime;
607 * Must use kludge-GMT instead of real GMT.
608 * kludge-GMT is computed by adding time zone difference to localtime.
611 * ltp = gmtime(&unixTime);
613 ersatz_unixTime = unixTime - smb_NowTZ;
614 ltp = localtime(&ersatz_unixTime);
616 /* if we fail, make up something */
619 localJunk.tm_year = 89 - 20;
620 localJunk.tm_mon = 4;
621 localJunk.tm_mday = 12;
622 localJunk.tm_hour = 0;
623 localJunk.tm_min = 0;
624 localJunk.tm_sec = 0;
627 stm.wYear = ltp->tm_year + 1900;
628 stm.wMonth = ltp->tm_mon + 1;
629 stm.wDayOfWeek = ltp->tm_wday;
630 stm.wDay = ltp->tm_mday;
631 stm.wHour = ltp->tm_hour;
632 stm.wMinute = ltp->tm_min;
633 stm.wSecond = ltp->tm_sec;
634 stm.wMilliseconds = 0;
636 SystemTimeToFileTime(&stm, largeTimep);
639 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
641 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
642 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
643 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
645 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
647 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
648 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
650 *ft = LargeIntegerMultiplyByLong(*ft, 60);
651 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
654 ut = ConvertLongToLargeInteger(unixTime);
655 ut = LargeIntegerMultiplyByLong(ut, 10000000);
656 *ft = LargeIntegerAdd(*ft, ut);
661 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
667 FileTimeToSystemTime(largeTimep, &stm);
669 lt.tm_year = stm.wYear - 1900;
670 lt.tm_mon = stm.wMonth - 1;
671 lt.tm_wday = stm.wDayOfWeek;
672 lt.tm_mday = stm.wDay;
673 lt.tm_hour = stm.wHour;
674 lt.tm_min = stm.wMinute;
675 lt.tm_sec = stm.wSecond;
678 save_timezone = _timezone;
679 _timezone += smb_NowTZ;
680 *unixTimep = mktime(<);
681 _timezone = save_timezone;
684 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
686 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
687 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
688 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
692 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
693 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
694 a = LargeIntegerMultiplyByLong(a, 60);
695 a = LargeIntegerMultiplyByLong(a, 10000000);
697 /* subtract it from ft */
698 a = LargeIntegerSubtract(*ft, a);
700 /* divide down to seconds */
701 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
705 void smb_SearchTimeFromUnixTime(long *dosTimep, time_t unixTime)
713 ltp = localtime((time_t*) &t);
715 /* if we fail, make up something */
718 localJunk.tm_year = 89 - 20;
719 localJunk.tm_mon = 4;
720 localJunk.tm_mday = 12;
721 localJunk.tm_hour = 0;
722 localJunk.tm_min = 0;
723 localJunk.tm_sec = 0;
726 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
727 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
728 *dosTimep = (dosDate<<16) | dosTime;
731 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
733 unsigned short dosDate;
734 unsigned short dosTime;
737 dosDate = searchTime & 0xffff;
738 dosTime = (searchTime >> 16) & 0xffff;
740 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
741 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
742 localTm.tm_mday = (dosDate) & 0x1f;
743 localTm.tm_hour = (dosTime>>11) & 0x1f;
744 localTm.tm_min = (dosTime >> 5) & 0x3f;
745 localTm.tm_sec = (dosTime & 0x1f) * 2;
746 localTm.tm_isdst = -1; /* compute whether DST in effect */
748 *unixTimep = mktime(&localTm);
751 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
753 *dosUTimep = unixTime - smb_localZero;
756 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
759 *unixTimep = dosTime + smb_localZero;
761 /* dosTime seems to be already adjusted for GMT */
762 *unixTimep = dosTime;
766 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
770 lock_ObtainWrite(&smb_rctLock);
771 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
772 if (lsn == vcp->lsn && lana == vcp->lana) {
777 if (!vcp && (flags & SMB_FLAG_CREATE)) {
778 vcp = malloc(sizeof(*vcp));
779 memset(vcp, 0, sizeof(*vcp));
780 vcp->vcID = numVCs++;
784 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
785 vcp->nextp = smb_allVCsp;
787 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
792 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
793 /* We must obtain a challenge for extended auth
794 * in case the client negotiates smb v3
797 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
798 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
801 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
803 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
810 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
812 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
813 LsaFreeReturnBuffer(lsaResp);
816 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
818 lock_ReleaseWrite(&smb_rctLock);
822 int smb_IsStarMask(char *maskp)
827 for(i=0; i<11; i++) {
829 if (tc == '?' || tc == '*' || tc == '>') return 1;
834 void smb_ReleaseVC(smb_vc_t *vcp)
836 lock_ObtainWrite(&smb_rctLock);
837 osi_assert(vcp->refCount-- > 0);
838 lock_ReleaseWrite(&smb_rctLock);
841 void smb_HoldVC(smb_vc_t *vcp)
843 lock_ObtainWrite(&smb_rctLock);
845 lock_ReleaseWrite(&smb_rctLock);
848 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
852 lock_ObtainWrite(&smb_rctLock);
853 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
854 if (tid == tidp->tid) {
859 if (!tidp && (flags & SMB_FLAG_CREATE)) {
860 tidp = malloc(sizeof(*tidp));
861 memset(tidp, 0, sizeof(*tidp));
862 tidp->nextp = vcp->tidsp;
867 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
870 lock_ReleaseWrite(&smb_rctLock);
874 void smb_ReleaseTID(smb_tid_t *tidp)
883 lock_ObtainWrite(&smb_rctLock);
884 osi_assert(tidp->refCount-- > 0);
885 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
886 ltpp = &tidp->vcp->tidsp;
887 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
888 if (tp == tidp) break;
890 osi_assert(tp != NULL);
892 lock_FinalizeMutex(&tidp->mx);
893 userp = tidp->userp; /* remember to drop ref later */
896 lock_ReleaseWrite(&smb_rctLock);
898 cm_ReleaseUser(userp);
905 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
907 smb_user_t *uidp = NULL;
909 lock_ObtainWrite(&smb_rctLock);
910 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
911 if (uid == uidp->userID) {
913 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
914 (int)vcp, uidp->userID,
915 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
919 if (!uidp && (flags & SMB_FLAG_CREATE)) {
920 uidp = malloc(sizeof(*uidp));
921 memset(uidp, 0, sizeof(*uidp));
922 uidp->nextp = vcp->usersp;
927 lock_InitializeMutex(&uidp->mx, "user_t mutex");
929 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 : ""));
931 lock_ReleaseWrite(&smb_rctLock);
935 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
937 smb_username_t *unp= NULL;
939 lock_ObtainWrite(&smb_rctLock);
940 for(unp = usernamesp; unp; unp = unp->nextp) {
941 if (stricmp(unp->name, usern) == 0 &&
942 stricmp(unp->machine, machine) == 0) {
947 if (!unp && (flags & SMB_FLAG_CREATE)) {
948 unp = malloc(sizeof(*unp));
949 memset(unp, 0, sizeof(*unp));
951 unp->nextp = usernamesp;
952 unp->name = strdup(usern);
953 unp->machine = strdup(machine);
955 lock_InitializeMutex(&unp->mx, "username_t mutex");
957 lock_ReleaseWrite(&smb_rctLock);
961 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
963 smb_user_t *uidp= NULL;
965 lock_ObtainWrite(&smb_rctLock);
966 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
969 if (stricmp(uidp->unp->name, usern) == 0) {
971 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
976 lock_ReleaseWrite(&smb_rctLock);
979 void smb_ReleaseUID(smb_user_t *uidp)
988 lock_ObtainWrite(&smb_rctLock);
989 osi_assert(uidp->refCount-- > 0);
990 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
991 lupp = &uidp->vcp->usersp;
992 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
993 if (up == uidp) break;
995 osi_assert(up != NULL);
997 lock_FinalizeMutex(&uidp->mx);
999 userp = uidp->unp->userp; /* remember to drop ref later */
1000 uidp->unp->userp = NULL;
1005 lock_ReleaseWrite(&smb_rctLock);
1007 cm_ReleaseUserVCRef(userp);
1008 cm_ReleaseUser(userp);
1015 /* retrieve a held reference to a user structure corresponding to an incoming
1017 * corresponding release function is cm_ReleaseUser.
1019 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1025 smbp = (smb_t *) inp;
1026 uidp = smb_FindUID(vcp, smbp->uid, 0);
1027 if ((!uidp) || (!uidp->unp))
1030 lock_ObtainMutex(&uidp->mx);
1031 up = uidp->unp->userp;
1033 lock_ReleaseMutex(&uidp->mx);
1035 smb_ReleaseUID(uidp);
1041 * Return a pointer to a pathname extracted from a TID structure. The
1042 * TID structure is not held; assume it won't go away.
1044 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1049 tidp = smb_FindTID(vcp, tid, 0);
1053 if(tidp->flags & SMB_TIDFLAG_IPC) {
1054 code = CM_ERROR_TIDIPC;
1055 /* tidp->pathname would be NULL, but that's fine */
1057 *treepath = tidp->pathname;
1058 smb_ReleaseTID(tidp);
1063 /* check to see if we have a chained fid, that is, a fid that comes from an
1064 * OpenAndX message that ran earlier in this packet. In this case, the fid
1065 * field in a read, for example, request, isn't set, since the value is
1066 * supposed to be inherited from the openAndX call.
1068 int smb_ChainFID(int fid, smb_packet_t *inp)
1070 if (inp->fid == 0 || inp->inCount == 0)
1076 /* are we a priv'd user? What does this mean on NT? */
1077 int smb_SUser(cm_user_t *userp)
1082 /* find a file ID. If we pass in 0 we select an used File ID.
1083 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1084 * smb_fid_t data structure if desired File ID cannot be found.
1086 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1091 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1094 lock_ObtainWrite(&smb_rctLock);
1095 /* figure out if we need to allocate a new file ID */
1098 fid = vcp->fidCounter;
1102 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1103 if (fid == fidp->fid) {
1114 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1115 char eventName[MAX_PATH];
1117 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1118 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1119 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1120 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1121 thrd_CloseHandle(event);
1128 fidp = malloc(sizeof(*fidp));
1129 memset(fidp, 0, sizeof(*fidp));
1130 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1134 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1136 fidp->curr_chunk = fidp->prev_chunk = -2;
1137 fidp->raw_write_event = event;
1139 vcp->fidCounter = fid+1;
1140 if (vcp->fidCounter == 0)
1141 vcp->fidCounter = 1;
1144 lock_ReleaseWrite(&smb_rctLock);
1148 void smb_ReleaseFID(smb_fid_t *fidp)
1151 smb_vc_t *vcp = NULL;
1152 smb_ioctl_t *ioctlp;
1158 lock_ObtainWrite(&smb_rctLock);
1159 osi_assert(fidp->refCount-- > 0);
1160 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1162 if (!(fidp->flags & SMB_FID_IOCTL))
1164 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1165 thrd_CloseHandle(fidp->raw_write_event);
1167 /* and see if there is ioctl stuff to free */
1168 ioctlp = fidp->ioctlp;
1170 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1171 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1172 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1178 /* do not call smb_ReleaseVC() because we already have the lock */
1181 lock_ReleaseWrite(&smb_rctLock);
1183 /* now release the scache structure */
1185 cm_ReleaseSCache(scp);
1189 * Case-insensitive search for one string in another;
1190 * used to find variable names in submount pathnames.
1192 static char *smb_stristr(char *str1, char *str2)
1196 for (cursor = str1; *cursor; cursor++)
1197 if (stricmp(cursor, str2) == 0)
1204 * Substitute a variable value for its name in a submount pathname. Variable
1205 * name has been identified by smb_stristr() and is in substr. Variable name
1206 * length (plus one) is in substr_size. Variable value is in newstr.
1208 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1213 strcpy(temp, substr + substr_size - 1);
1214 strcpy(substr, newstr);
1218 char VNUserName[] = "%USERNAME%";
1219 char VNLCUserName[] = "%LCUSERNAME%";
1220 char VNComputerName[] = "%COMPUTERNAME%";
1221 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1224 /* List available shares */
1225 int smb_ListShares()
1229 char shareBuf[4096];
1237 /*strcpy(shareNameList[num_shares], "all");
1238 strcpy(pathNameList[num_shares++], "/afs");*/
1239 fprintf(stderr, "The following shares are available:\n");
1240 fprintf(stderr, "Share Name (AFS Path)\n");
1241 fprintf(stderr, "---------------------\n");
1242 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1245 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1246 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1248 strcpy(sbmtpath, cm_confDir);
1250 strcat(sbmtpath, "/afsdsbmt.ini");
1251 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1252 shareBuf, sizeof(shareBuf),
1258 this_share = shareBuf;
1262 /*strcpy(shareNameList[num_shares], this_share);*/
1263 len = GetPrivateProfileString("AFS Submounts", this_share,
1270 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1273 if (*p == '\\') *p = '/'; /* change to / */
1277 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1278 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1281 while (*this_share != 0) this_share++; /* find next NUL */
1282 this_share++; /* skip past the NUL */
1283 } while (*this_share != 0); /* stop at final NUL */
1289 typedef struct smb_findShare_rock {
1293 } smb_findShare_rock_t;
1295 #define SMB_FINDSHARE_EXACT_MATCH 1
1296 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1298 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1302 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1303 if(!strnicmp(dep->name, vrock->shareName, 12)) {
1304 if(!stricmp(dep->name, vrock->shareName))
1305 matchType = SMB_FINDSHARE_EXACT_MATCH;
1307 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1308 if(vrock->match) free(vrock->match);
1309 vrock->match = strdup(dep->name);
1310 vrock->matchType = matchType;
1312 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1313 return CM_ERROR_STOPNOW;
1319 /* find a shareName in the table of submounts */
1320 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1324 char pathName[1024];
1329 char sbmtpath[MAX_PATH];
1334 DWORD allSubmount = 1;
1336 /* if allSubmounts == 0, only return the //mountRoot/all share
1337 * if in fact it has been been created in the subMounts table.
1338 * This is to allow sites that want to restrict access to the
1341 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1342 0, KEY_QUERY_VALUE, &parmKey);
1343 if (code == ERROR_SUCCESS) {
1344 len = sizeof(allSubmount);
1345 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1346 (BYTE *) &allSubmount, &len);
1347 if (code != ERROR_SUCCESS) {
1350 RegCloseKey (parmKey);
1353 if (allSubmount && _stricmp(shareName, "all") == 0) {
1358 /* In case, the all share is disabled we need to still be able
1359 * to handle ioctl requests
1361 if (_stricmp(shareName, "ioctl$") == 0) {
1362 *pathNamep = strdup("/.__ioctl__");
1366 if (_stricmp(shareName, "IPC$") == 0 ||
1367 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1368 _stricmp(shareName, "DESKTOP.INI") == 0
1375 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1376 0, KEY_QUERY_VALUE, &parmKey);
1377 if (code == ERROR_SUCCESS) {
1378 len = sizeof(pathName);
1379 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1380 (BYTE *) pathName, &len);
1381 if (code != ERROR_SUCCESS)
1383 RegCloseKey (parmKey);
1388 strcpy(sbmtpath, cm_confDir);
1389 strcat(sbmtpath, "/afsdsbmt.ini");
1390 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1391 pathName, sizeof(pathName), sbmtpath);
1393 if (len != 0 && len != sizeof(pathName) - 1) {
1394 /* We can accept either unix or PC style AFS pathnames. Convert
1395 * Unix-style to PC style here for internal use.
1398 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1399 p += strlen(cm_mountRoot); /* skip mount path */
1402 if (*q == '/') *q = '\\'; /* change to \ */
1408 if (var = smb_stristr(p, VNUserName)) {
1409 if (uidp && uidp->unp)
1410 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1412 smb_subst(p, var, sizeof(VNUserName)," ");
1414 else if (var = smb_stristr(p, VNLCUserName))
1416 if (uidp && uidp->unp)
1417 strcpy(temp, uidp->unp->name);
1421 smb_subst(p, var, sizeof(VNLCUserName), temp);
1423 else if (var = smb_stristr(p, VNComputerName))
1425 sizeTemp = sizeof(temp);
1426 GetComputerName((LPTSTR)temp, &sizeTemp);
1427 smb_subst(p, var, sizeof(VNComputerName), temp);
1429 else if (var = smb_stristr(p, VNLCComputerName))
1431 sizeTemp = sizeof(temp);
1432 GetComputerName((LPTSTR)temp, &sizeTemp);
1434 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1439 *pathNamep = strdup(p);
1444 /* First lookup shareName in root.afs */
1446 smb_findShare_rock_t vrock;
1448 char * p = shareName;
1451 /* attempt to locate a partial match in root.afs. This is because
1452 when using the ANSI RAP calls, the share name is limited to 13 chars
1453 and hence is truncated. Of course we prefer exact matches. */
1455 thyper.HighPart = 0;
1458 vrock.shareName = shareName;
1460 vrock.matchType = 0;
1462 cm_HoldSCache(cm_rootSCachep);
1463 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1464 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1465 cm_ReleaseSCache(cm_rootSCachep);
1467 if(vrock.matchType) {
1468 sprintf(pathName,"/%s/",vrock.match);
1469 *pathNamep = strdup(strlwr(pathName));
1474 /* if we get here, there was no match for the share in root.afs */
1475 /* so try to create \\<netbiosName>\<cellname> */
1480 /* Get the full name for this cell */
1481 code = cm_SearchCellFile(p, temp, 0, 0);
1482 #ifdef AFS_AFSDB_ENV
1483 if (code && cm_dnsEnabled) {
1485 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1488 /* construct the path */
1490 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1491 *pathNamep = strdup(strlwr(pathName));
1500 /* Client-side offline caching policy types */
1501 #define CSC_POLICY_MANUAL 0
1502 #define CSC_POLICY_DOCUMENTS 1
1503 #define CSC_POLICY_PROGRAMS 2
1504 #define CSC_POLICY_DISABLE 3
1506 int smb_FindShareCSCPolicy(char *shareName)
1512 int retval = CSC_POLICY_MANUAL;
1514 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1515 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1518 REG_OPTION_NON_VOLATILE,
1524 len = sizeof(policy);
1525 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1527 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1529 else if (stricmp(policy, "documents") == 0)
1531 retval = CSC_POLICY_DOCUMENTS;
1533 else if (stricmp(policy, "programs") == 0)
1535 retval = CSC_POLICY_PROGRAMS;
1537 else if (stricmp(policy, "disable") == 0)
1539 retval = CSC_POLICY_DISABLE;
1542 RegCloseKey(hkCSCPolicy);
1546 /* find a dir search structure by cookie value, and return it held.
1547 * Must be called with smb_globalLock held.
1549 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1551 smb_dirSearch_t *dsp;
1553 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1554 if (dsp->cookie == cookie) {
1555 if (dsp != smb_firstDirSearchp) {
1556 /* move to head of LRU queue, too, if we're not already there */
1557 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1558 smb_lastDirSearchp = (smb_dirSearch_t *)
1560 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1561 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1562 if (!smb_lastDirSearchp)
1563 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1572 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1574 lock_ObtainWrite(&smb_globalLock);
1575 dsp->flags |= SMB_DIRSEARCH_DELETE;
1576 lock_ReleaseWrite(&smb_globalLock);
1577 lock_ObtainMutex(&dsp->mx);
1578 if(dsp->scp != NULL) {
1579 lock_ObtainMutex(&dsp->scp->mx);
1580 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1581 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1582 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1583 dsp->scp->bulkStatProgress = hones;
1585 lock_ReleaseMutex(&dsp->scp->mx);
1587 lock_ReleaseMutex(&dsp->mx);
1590 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1596 lock_ObtainWrite(&smb_globalLock);
1597 osi_assert(dsp->refCount-- > 0);
1598 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1599 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1600 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1601 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1602 lock_FinalizeMutex(&dsp->mx);
1606 lock_ReleaseWrite(&smb_globalLock);
1608 /* do this now to avoid spurious locking hierarchy creation */
1609 if (scp) cm_ReleaseSCache(scp);
1612 /* find a dir search structure by cookie value, and return it held */
1613 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1615 smb_dirSearch_t *dsp;
1617 lock_ObtainWrite(&smb_globalLock);
1618 dsp = smb_FindDirSearchNL(cookie);
1619 lock_ReleaseWrite(&smb_globalLock);
1623 /* GC some dir search entries, in the address space expected by the specific protocol.
1624 * Must be called with smb_globalLock held; release the lock temporarily.
1626 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1627 void smb_GCDirSearches(int isV3)
1629 smb_dirSearch_t *prevp;
1630 smb_dirSearch_t *tp;
1631 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1635 victimCount = 0; /* how many have we got so far */
1636 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1637 /* we'll move tp from queue, so
1640 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1641 /* if no one is using this guy, and we're either in the new protocol,
1642 * or we're in the old one and this is a small enough ID to be useful
1643 * to the old protocol, GC this guy.
1645 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1646 /* hold and delete */
1647 tp->flags |= SMB_DIRSEARCH_DELETE;
1648 victimsp[victimCount++] = tp;
1652 /* don't do more than this */
1653 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1656 /* now release them */
1657 lock_ReleaseWrite(&smb_globalLock);
1658 for(i = 0; i < victimCount; i++) {
1659 smb_ReleaseDirSearch(victimsp[i]);
1661 lock_ObtainWrite(&smb_globalLock);
1664 /* function for allocating a dir search entry. We need these to remember enough context
1665 * since we don't get passed the path from call to call during a directory search.
1667 * Returns a held dir search structure, and bumps the reference count on the vnode,
1668 * since it saves a pointer to the vnode.
1670 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1672 smb_dirSearch_t *dsp;
1676 lock_ObtainWrite(&smb_globalLock);
1679 /* what's the biggest ID allowed in this version of the protocol */
1680 if (isV3) maxAllowed = 65535;
1681 else maxAllowed = 255;
1684 /* twice so we have enough tries to find guys we GC after one pass;
1685 * 10 extra is just in case I mis-counted.
1687 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1688 __FILE__, __LINE__);
1689 if (smb_dirSearchCounter > maxAllowed) {
1690 smb_dirSearchCounter = 1;
1691 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1693 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1695 /* don't need to watch for refcount zero and deleted, since
1696 * we haven't dropped the global lock.
1699 ++smb_dirSearchCounter;
1703 dsp = malloc(sizeof(*dsp));
1704 memset(dsp, 0, sizeof(*dsp));
1705 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1706 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1707 dsp->cookie = smb_dirSearchCounter;
1708 ++smb_dirSearchCounter;
1710 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1711 dsp->lastTime = osi_Time();
1714 lock_ReleaseWrite(&smb_globalLock);
1718 static smb_packet_t *GetPacket(void)
1722 unsigned int npar, seg, tb_sel;
1725 lock_ObtainWrite(&smb_globalLock);
1726 tbp = smb_packetFreeListp;
1728 smb_packetFreeListp = tbp->nextp;
1729 lock_ReleaseWrite(&smb_globalLock);
1732 tbp = calloc(65540,1);
1734 tbp = malloc(sizeof(smb_packet_t));
1736 tbp->magic = SMB_PACKETMAGIC;
1739 tbp->resumeCode = 0;
1745 tbp->ncb_length = 0;
1750 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1753 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1755 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1757 osi_panic("",__FILE__,__LINE__);
1760 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1765 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1766 tbp->dos_pkt_sel = tb_sel;
1769 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1774 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1778 memcpy(tbp, pkt, sizeof(smb_packet_t));
1779 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1783 static NCB *GetNCB(void)
1788 unsigned int npar, seg, tb_sel;
1791 lock_ObtainWrite(&smb_globalLock);
1792 tbp = smb_ncbFreeListp;
1794 smb_ncbFreeListp = tbp->nextp;
1795 lock_ReleaseWrite(&smb_globalLock);
1798 tbp = calloc(sizeof(*tbp),1);
1800 tbp = malloc(sizeof(*tbp));
1801 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1804 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1806 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1808 osi_panic("",__FILE__,__LINE__);
1810 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1815 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1816 tbp->dos_ncb_sel = tb_sel;
1818 tbp->magic = SMB_NCBMAGIC;
1821 osi_assert(tbp->magic == SMB_NCBMAGIC);
1823 memset(&tbp->ncb, 0, sizeof(NCB));
1826 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1831 void smb_FreePacket(smb_packet_t *tbp)
1833 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1835 lock_ObtainWrite(&smb_globalLock);
1836 tbp->nextp = smb_packetFreeListp;
1837 smb_packetFreeListp = tbp;
1838 tbp->magic = SMB_PACKETMAGIC;
1841 tbp->resumeCode = 0;
1847 tbp->ncb_length = 0;
1849 lock_ReleaseWrite(&smb_globalLock);
1852 static void FreeNCB(NCB *bufferp)
1856 tbp = (smb_ncb_t *) bufferp;
1857 osi_assert(tbp->magic == SMB_NCBMAGIC);
1859 lock_ObtainWrite(&smb_globalLock);
1860 tbp->nextp = smb_ncbFreeListp;
1861 smb_ncbFreeListp = tbp;
1862 lock_ReleaseWrite(&smb_globalLock);
1865 /* get a ptr to the data part of a packet, and its count */
1866 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1870 unsigned char *afterParmsp;
1872 parmBytes = *smbp->wctp << 1;
1873 afterParmsp = smbp->wctp + parmBytes + 1;
1875 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1876 if (nbytesp) *nbytesp = dataBytes;
1878 /* don't forget to skip the data byte count, since it follows
1879 * the parameters; that's where the "2" comes from below.
1881 return (unsigned char *) (afterParmsp + 2);
1884 /* must set all the returned parameters before playing around with the
1885 * data region, since the data region is located past the end of the
1886 * variable number of parameters.
1888 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1890 unsigned char *afterParmsp;
1892 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1894 *afterParmsp++ = dsize & 0xff;
1895 *afterParmsp = (dsize>>8) & 0xff;
1898 /* return the parm'th parameter in the smbp packet */
1899 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1902 unsigned char *parmDatap;
1904 parmCount = *smbp->wctp;
1906 if (parm >= parmCount) {
1911 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1913 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1914 parm, parmCount, smbp->ncb_length);
1917 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1918 1, smbp->ncb_length, ptbuf, smbp);
1919 DeregisterEventSource(h);
1921 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1922 osi_panic(s, __FILE__, __LINE__);
1924 parmDatap = smbp->wctp + (2*parm) + 1;
1926 return parmDatap[0] + (parmDatap[1] << 8);
1929 /* return the parm'th parameter in the smbp packet */
1930 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1933 unsigned char *parmDatap;
1935 parmCount = *smbp->wctp;
1937 if (parm * 2 + offset >= parmCount * 2) {
1942 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1944 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1945 parm, offset, parmCount, smbp->ncb_length);
1948 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1949 1, smbp->ncb_length, ptbuf, smbp);
1950 DeregisterEventSource(h);
1952 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1953 osi_panic(s, __FILE__, __LINE__);
1955 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1957 return parmDatap[0] + (parmDatap[1] << 8);
1960 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1964 /* make sure we have enough slots */
1965 if (*smbp->wctp <= slot)
1966 *smbp->wctp = slot+1;
1968 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1969 *parmDatap++ = parmValue & 0xff;
1970 *parmDatap = (parmValue>>8) & 0xff;
1973 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1977 /* make sure we have enough slots */
1978 if (*smbp->wctp <= slot)
1979 *smbp->wctp = slot+2;
1981 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1982 *parmDatap++ = parmValue & 0xff;
1983 *parmDatap++ = (parmValue>>8) & 0xff;
1984 *parmDatap++ = (parmValue>>16) & 0xff;
1985 *parmDatap++ = (parmValue>>24) & 0xff;
1988 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1993 /* make sure we have enough slots */
1994 if (*smbp->wctp <= slot)
1995 *smbp->wctp = slot+4;
1997 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1999 *parmDatap++ = *parmValuep++;
2002 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2006 /* make sure we have enough slots */
2007 if (*smbp->wctp <= slot) {
2008 if (smbp->oddByte) {
2010 *smbp->wctp = slot+1;
2015 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2016 *parmDatap++ = parmValue & 0xff;
2019 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2023 lastSlashp = strrchr(inPathp, '\\');
2025 *lastComponentp = lastSlashp;
2028 if (inPathp == lastSlashp)
2030 *outPathp++ = *inPathp++;
2039 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2044 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2049 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2055 tlen = inp[0] + (inp[1]<<8);
2056 inp += 2; /* skip length field */
2059 *chainpp = inp + tlen;
2068 /* format a packet as a response */
2069 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2074 outp = (smb_t *) op;
2076 /* zero the basic structure through the smb_wct field, and zero the data
2077 * size field, assuming that wct stays zero; otherwise, you have to
2078 * explicitly set the data size field, too.
2080 inSmbp = (smb_t *) inp;
2081 memset(outp, 0, sizeof(smb_t)+2);
2087 outp->com = inSmbp->com;
2088 outp->tid = inSmbp->tid;
2089 outp->pid = inSmbp->pid;
2090 outp->uid = inSmbp->uid;
2091 outp->mid = inSmbp->mid;
2092 outp->res[0] = inSmbp->res[0];
2093 outp->res[1] = inSmbp->res[1];
2094 op->inCom = inSmbp->com;
2096 outp->reb = 0x80; /* SERVER_RESP */
2097 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2099 /* copy fields in generic packet area */
2100 op->wctp = &outp->wct;
2103 /* send a (probably response) packet; vcp tells us to whom to send it.
2104 * we compute the length by looking at wct and bcc fields.
2106 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2123 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2126 memset((char *)ncbp, 0, sizeof(NCB));
2128 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2129 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2130 extra += tp[0] + (tp[1]<<8);
2131 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2132 extra += 3; /* wct and length fields */
2134 ncbp->ncb_length = extra; /* bytes to send */
2135 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2136 ncbp->ncb_lana_num = vcp->lana;
2137 ncbp->ncb_command = NCBSEND; /* op means send data */
2139 ncbp->ncb_buffer = (char *) inp;/* packet */
2140 code = Netbios(ncbp);
2142 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2143 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2145 /* copy header information from virtual to DOS address space */
2146 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2147 code = Netbios(ncbp, dos_ncb);
2151 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2157 void smb_MapNTError(long code, unsigned long *NTStatusp)
2159 unsigned long NTStatus;
2161 /* map CM_ERROR_* errors to NT 32-bit status codes */
2162 /* NT Status codes are listed in ntstatus.h not winerror.h */
2163 if (code == CM_ERROR_NOSUCHCELL) {
2164 NTStatus = 0xC000000FL; /* No such file */
2166 else if (code == CM_ERROR_NOSUCHVOLUME) {
2167 NTStatus = 0xC000000FL; /* No such file */
2169 else if (code == CM_ERROR_TIMEDOUT) {
2170 NTStatus = 0xC00000CFL; /* Sharing Paused */
2172 else if (code == CM_ERROR_RETRY) {
2173 NTStatus = 0xC000022DL; /* Retry */
2175 else if (code == CM_ERROR_NOACCESS) {
2176 NTStatus = 0xC0000022L; /* Access denied */
2178 else if (code == CM_ERROR_READONLY) {
2179 NTStatus = 0xC00000A2L; /* Write protected */
2181 else if (code == CM_ERROR_NOSUCHFILE) {
2182 NTStatus = 0xC000000FL; /* No such file */
2184 else if (code == CM_ERROR_NOSUCHPATH) {
2185 NTStatus = 0xC000003AL; /* Object path not found */
2187 else if (code == CM_ERROR_TOOBIG) {
2188 NTStatus = 0xC000007BL; /* Invalid image format */
2190 else if (code == CM_ERROR_INVAL) {
2191 NTStatus = 0xC000000DL; /* Invalid parameter */
2193 else if (code == CM_ERROR_BADFD) {
2194 NTStatus = 0xC0000008L; /* Invalid handle */
2196 else if (code == CM_ERROR_BADFDOP) {
2197 NTStatus = 0xC0000022L; /* Access denied */
2199 else if (code == CM_ERROR_EXISTS) {
2200 NTStatus = 0xC0000035L; /* Object name collision */
2202 else if (code == CM_ERROR_NOTEMPTY) {
2203 NTStatus = 0xC0000101L; /* Directory not empty */
2205 else if (code == CM_ERROR_CROSSDEVLINK) {
2206 NTStatus = 0xC00000D4L; /* Not same device */
2208 else if (code == CM_ERROR_NOTDIR) {
2209 NTStatus = 0xC0000103L; /* Not a directory */
2211 else if (code == CM_ERROR_ISDIR) {
2212 NTStatus = 0xC00000BAL; /* File is a directory */
2214 else if (code == CM_ERROR_BADOP) {
2216 /* I have no idea where this comes from */
2217 NTStatus = 0xC09820FFL; /* SMB no support */
2219 NTStatus = 0xC00000BBL; /* Not supported */
2220 #endif /* COMMENT */
2222 else if (code == CM_ERROR_BADSHARENAME) {
2223 NTStatus = 0xC00000CCL; /* Bad network name */
2225 else if (code == CM_ERROR_NOIPC) {
2227 NTStatus = 0xC0000022L; /* Access Denied */
2229 NTStatus = 0xC000013DL; /* Remote Resources */
2232 else if (code == CM_ERROR_CLOCKSKEW) {
2233 NTStatus = 0xC0000133L; /* Time difference at DC */
2235 else if (code == CM_ERROR_BADTID) {
2236 NTStatus = 0xC0982005L; /* SMB bad TID */
2238 else if (code == CM_ERROR_USESTD) {
2239 NTStatus = 0xC09820FBL; /* SMB use standard */
2241 else if (code == CM_ERROR_QUOTA) {
2243 NTStatus = 0xC0000044L; /* Quota exceeded */
2245 NTStatus = 0xC000007FL; /* Disk full */
2248 else if (code == CM_ERROR_SPACE) {
2249 NTStatus = 0xC000007FL; /* Disk full */
2251 else if (code == CM_ERROR_ATSYS) {
2252 NTStatus = 0xC0000033L; /* Object name invalid */
2254 else if (code == CM_ERROR_BADNTFILENAME) {
2255 NTStatus = 0xC0000033L; /* Object name invalid */
2257 else if (code == CM_ERROR_WOULDBLOCK) {
2258 NTStatus = 0xC0000055L; /* Lock not granted */
2260 else if (code == CM_ERROR_PARTIALWRITE) {
2261 NTStatus = 0xC000007FL; /* Disk full */
2263 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2264 NTStatus = 0xC0000023L; /* Buffer too small */
2266 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2267 NTStatus = 0xC0000035L; /* Object name collision */
2269 else if (code == CM_ERROR_BADPASSWORD) {
2270 NTStatus = 0xC000006DL; /* unknown username or bad password */
2272 else if (code == CM_ERROR_BADLOGONTYPE) {
2273 NTStatus = 0xC000015BL; /* logon type not granted */
2275 else if (code == CM_ERROR_GSSCONTINUE) {
2276 NTStatus = 0xC0000016L; /* more processing required */
2279 NTStatus = 0xC0982001L; /* SMB non-specific error */
2282 *NTStatusp = NTStatus;
2283 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2286 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2287 unsigned char *classp)
2289 unsigned char class;
2290 unsigned short error;
2292 /* map CM_ERROR_* errors to SMB errors */
2293 if (code == CM_ERROR_NOSUCHCELL) {
2295 error = 3; /* bad path */
2297 else if (code == CM_ERROR_NOSUCHVOLUME) {
2299 error = 3; /* bad path */
2301 else if (code == CM_ERROR_TIMEDOUT) {
2303 error = 81; /* server is paused */
2305 else if (code == CM_ERROR_RETRY) {
2306 class = 2; /* shouldn't happen */
2309 else if (code == CM_ERROR_NOACCESS) {
2311 error = 4; /* bad access */
2313 else if (code == CM_ERROR_READONLY) {
2315 error = 19; /* read only */
2317 else if (code == CM_ERROR_NOSUCHFILE) {
2319 error = 2; /* ENOENT! */
2321 else if (code == CM_ERROR_NOSUCHPATH) {
2323 error = 3; /* Bad path */
2325 else if (code == CM_ERROR_TOOBIG) {
2327 error = 11; /* bad format */
2329 else if (code == CM_ERROR_INVAL) {
2330 class = 2; /* server non-specific error code */
2333 else if (code == CM_ERROR_BADFD) {
2335 error = 6; /* invalid file handle */
2337 else if (code == CM_ERROR_BADFDOP) {
2338 class = 1; /* invalid op on FD */
2341 else if (code == CM_ERROR_EXISTS) {
2343 error = 80; /* file already exists */
2345 else if (code == CM_ERROR_NOTEMPTY) {
2347 error = 5; /* delete directory not empty */
2349 else if (code == CM_ERROR_CROSSDEVLINK) {
2351 error = 17; /* EXDEV */
2353 else if (code == CM_ERROR_NOTDIR) {
2354 class = 1; /* bad path */
2357 else if (code == CM_ERROR_ISDIR) {
2358 class = 1; /* access denied; DOS doesn't have a good match */
2361 else if (code == CM_ERROR_BADOP) {
2365 else if (code == CM_ERROR_BADSHARENAME) {
2369 else if (code == CM_ERROR_NOIPC) {
2371 error = 4; /* bad access */
2373 else if (code == CM_ERROR_CLOCKSKEW) {
2374 class = 1; /* invalid function */
2377 else if (code == CM_ERROR_BADTID) {
2381 else if (code == CM_ERROR_USESTD) {
2385 else if (code == CM_ERROR_REMOTECONN) {
2389 else if (code == CM_ERROR_QUOTA) {
2390 if (vcp->flags & SMB_VCFLAG_USEV3) {
2392 error = 39; /* disk full */
2396 error = 5; /* access denied */
2399 else if (code == CM_ERROR_SPACE) {
2400 if (vcp->flags & SMB_VCFLAG_USEV3) {
2402 error = 39; /* disk full */
2406 error = 5; /* access denied */
2409 else if (code == CM_ERROR_PARTIALWRITE) {
2411 error = 39; /* disk full */
2413 else if (code == CM_ERROR_ATSYS) {
2415 error = 2; /* ENOENT */
2417 else if (code == CM_ERROR_WOULDBLOCK) {
2419 error = 33; /* lock conflict */
2421 else if (code == CM_ERROR_NOFILES) {
2423 error = 18; /* no files in search */
2425 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2427 error = 183; /* Samba uses this */
2429 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2430 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2432 error = 2; /* bad password */
2441 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2444 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2446 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2447 return CM_ERROR_BADOP;
2450 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2452 unsigned short EchoCount, i;
2453 char *data, *outdata;
2456 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2458 for (i=1; i<=EchoCount; i++) {
2459 data = smb_GetSMBData(inp, &dataSize);
2460 smb_SetSMBParm(outp, 0, i);
2461 smb_SetSMBDataLength(outp, dataSize);
2462 outdata = smb_GetSMBData(outp, NULL);
2463 memcpy(outdata, data, dataSize);
2464 smb_SendPacket(vcp, outp);
2470 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2473 long count, minCount, finalCount;
2477 cm_user_t *userp = NULL;
2481 char *rawBuf = NULL;
2483 dos_ptr rawBuf = NULL;
2490 fd = smb_GetSMBParm(inp, 0);
2491 count = smb_GetSMBParm(inp, 3);
2492 minCount = smb_GetSMBParm(inp, 4);
2493 offset.HighPart = 0; /* too bad */
2494 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2496 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2497 fd, offset.LowPart, count);
2499 fidp = smb_FindFID(vcp, fd, 0);
2503 lock_ObtainMutex(&smb_RawBufLock);
2505 /* Get a raw buf, from head of list */
2506 rawBuf = smb_RawBufs;
2508 smb_RawBufs = *(char **)smb_RawBufs;
2510 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2513 lock_ReleaseMutex(&smb_RawBufLock);
2517 if (fidp->flags & SMB_FID_IOCTL)
2520 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2522 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2525 /* Give back raw buffer */
2526 lock_ObtainMutex(&smb_RawBufLock);
2528 *((char **) rawBuf) = smb_RawBufs;
2530 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2533 smb_RawBufs = rawBuf;
2534 lock_ReleaseMutex(&smb_RawBufLock);
2537 smb_ReleaseFID(fidp);
2541 userp = smb_GetUser(vcp, inp);
2544 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2546 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2547 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2548 userp, &finalCount, TRUE /* rawFlag */);
2555 cm_ReleaseUser(userp);
2558 smb_ReleaseFID(fidp);
2563 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2565 memset((char *)ncbp, 0, sizeof(NCB));
2567 ncbp->ncb_length = (unsigned short) finalCount;
2568 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2569 ncbp->ncb_lana_num = vcp->lana;
2570 ncbp->ncb_command = NCBSEND;
2571 ncbp->ncb_buffer = rawBuf;
2574 code = Netbios(ncbp);
2576 code = Netbios(ncbp, dos_ncb);
2579 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2582 /* Give back raw buffer */
2583 lock_ObtainMutex(&smb_RawBufLock);
2585 *((char **) rawBuf) = smb_RawBufs;
2587 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2590 smb_RawBufs = rawBuf;
2591 lock_ReleaseMutex(&smb_RawBufLock);
2597 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2599 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2604 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2606 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2611 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2618 int protoIndex; /* index we're using */
2623 char protocol_array[10][1024]; /* protocol signature of the client */
2624 int caps; /* capabilities */
2627 TIME_ZONE_INFORMATION tzi;
2629 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2633 DWORD now = GetCurrentTime();
2634 if (now - last_msg_time >= 30000
2635 && now - last_msg_time <= 90000) {
2637 "Setting dead_vcp %x", active_vcp);
2639 smb_ReleaseVC(dead_vcp);
2641 "Previous dead_vcp %x", dead_vcp);
2643 smb_HoldVC(active_vcp);
2644 dead_vcp = active_vcp;
2645 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2650 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2652 namep = smb_GetSMBData(inp, &dbytes);
2655 coreProtoIndex = -1; /* not found */
2658 while(namex < dbytes) {
2659 osi_Log1(smb_logp, "Protocol %s",
2660 osi_LogSaveString(smb_logp, namep+1));
2661 strcpy(protocol_array[tcounter], namep+1);
2663 /* namep points at the first protocol, or really, a 0x02
2664 * byte preceding the null-terminated ASCII name.
2666 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2667 coreProtoIndex = tcounter;
2669 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2670 v3ProtoIndex = tcounter;
2672 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2673 NTProtoIndex = tcounter;
2676 /* compute size of protocol entry */
2677 entryLength = strlen(namep+1);
2678 entryLength += 2; /* 0x02 bytes and null termination */
2680 /* advance over this protocol entry */
2681 namex += entryLength;
2682 namep += entryLength;
2683 tcounter++; /* which proto entry we're looking at */
2686 if (NTProtoIndex != -1) {
2687 protoIndex = NTProtoIndex;
2688 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2690 else if (v3ProtoIndex != -1) {
2691 protoIndex = v3ProtoIndex;
2692 vcp->flags |= SMB_VCFLAG_USEV3;
2694 else if (coreProtoIndex != -1) {
2695 protoIndex = coreProtoIndex;
2696 vcp->flags |= SMB_VCFLAG_USECORE;
2698 else protoIndex = -1;
2700 if (protoIndex == -1)
2701 return CM_ERROR_INVAL;
2702 else if (NTProtoIndex != -1) {
2703 smb_SetSMBParm(outp, 0, protoIndex);
2704 if (smb_authType != SMB_AUTH_NONE) {
2705 smb_SetSMBParmByte(outp, 1,
2706 NEGOTIATE_SECURITY_USER_LEVEL |
2707 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2709 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2711 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2712 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2713 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2714 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2715 /* The session key is not a well documented field however most clients
2716 * will echo back the session key to the server. Currently we are using
2717 * the same value for all sessions. We should generate a random value
2718 * and store it into the vcp
2720 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2721 smb_SetSMBParm(outp, 8, 1);
2723 * Tried changing the capabilities to support for W2K - defect 117695
2724 * Maybe something else needs to be changed here?
2728 smb_SetSMBParmLong(outp, 9, 0x43fd);
2730 smb_SetSMBParmLong(outp, 9, 0x251);
2733 * 32-bit error codes *
2737 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2738 NTNEGOTIATE_CAPABILITY_NTFIND |
2739 NTNEGOTIATE_CAPABILITY_RAWMODE |
2740 NTNEGOTIATE_CAPABILITY_NTSMB;
2742 if ( smb_authType == SMB_AUTH_EXTENDED )
2743 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2745 smb_SetSMBParmLong(outp, 9, caps);
2747 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2748 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2749 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2751 GetTimeZoneInformation(&tzi);
2752 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2754 if (smb_authType == SMB_AUTH_NTLM) {
2755 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2756 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2757 /* paste in encryption key */
2758 datap = smb_GetSMBData(outp, NULL);
2759 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2760 /* and the faux domain name */
2761 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2762 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2766 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2768 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2770 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2772 datap = smb_GetSMBData(outp, NULL);
2773 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2776 datap += sizeof(smb_ServerGUID);
2777 memcpy(datap, secBlob, secBlobLength);
2781 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2782 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2785 else if (v3ProtoIndex != -1) {
2786 smb_SetSMBParm(outp, 0, protoIndex);
2788 /* NOTE: Extended authentication cannot be negotiated with v3
2789 * therefore we fail over to NTLM
2791 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2792 smb_SetSMBParm(outp, 1,
2793 NEGOTIATE_SECURITY_USER_LEVEL |
2794 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2796 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2798 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2799 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2800 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2801 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2802 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2803 smb_SetSMBParm(outp, 7, 1);
2805 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2806 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2807 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2809 GetTimeZoneInformation(&tzi);
2810 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2812 /* NOTE: Extended authentication cannot be negotiated with v3
2813 * therefore we fail over to NTLM
2815 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2816 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2817 smb_SetSMBParm(outp, 12, 0); /* resvd */
2818 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2819 datap = smb_GetSMBData(outp, NULL);
2820 /* paste in a new encryption key */
2821 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2822 /* and the faux domain name */
2823 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2825 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2826 smb_SetSMBParm(outp, 12, 0); /* resvd */
2827 smb_SetSMBDataLength(outp, 0);
2830 else if (coreProtoIndex != -1) { /* not really supported anymore */
2831 smb_SetSMBParm(outp, 0, protoIndex);
2832 smb_SetSMBDataLength(outp, 0);
2837 void smb_Daemon(void *parmp)
2839 afs_uint32 count = 0;
2844 if ((count % 72) == 0) { /* every five minutes */
2846 long old_localZero = smb_localZero;
2848 /* Initialize smb_localZero */
2849 myTime.tm_isdst = -1; /* compute whether on DST or not */
2850 myTime.tm_year = 70;
2856 smb_localZero = mktime(&myTime);
2858 smb_CalculateNowTZ();
2860 #ifdef AFS_FREELANCE
2861 if ( smb_localZero != old_localZero )
2862 cm_noteLocalMountPointChange();
2865 /* XXX GC dir search entries */
2869 void smb_WaitingLocksDaemon()
2871 smb_waitingLock_t *wL, *nwL;
2874 smb_packet_t *inp, *outp;
2879 lock_ObtainWrite(&smb_globalLock);
2880 nwL = smb_allWaitingLocks;
2882 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2891 lock_ObtainWrite(&smb_globalLock);
2893 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2894 lock_ReleaseWrite(&smb_globalLock);
2895 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2896 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2897 if (code == CM_ERROR_WOULDBLOCK) {
2899 if (wL->timeRemaining != 0xffffffff
2900 && (wL->timeRemaining -= 1000) < 0)
2909 ncbp->ncb_length = inp->ncb_length;
2910 inp->spacep = cm_GetSpace();
2912 /* Remove waitingLock from list */
2913 lock_ObtainWrite(&smb_globalLock);
2914 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2916 lock_ReleaseWrite(&smb_globalLock);
2918 /* Resume packet processing */
2920 smb_SetSMBDataLength(outp, 0);
2921 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2922 outp->resumeCode = code;
2924 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2927 cm_FreeSpace(inp->spacep);
2928 smb_FreePacket(inp);
2929 smb_FreePacket(outp);
2937 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2939 osi_Log0(smb_logp, "SMB receive get disk attributes");
2941 smb_SetSMBParm(outp, 0, 32000);
2942 smb_SetSMBParm(outp, 1, 64);
2943 smb_SetSMBParm(outp, 2, 1024);
2944 smb_SetSMBParm(outp, 3, 30000);
2945 smb_SetSMBParm(outp, 4, 0);
2946 smb_SetSMBDataLength(outp, 0);
2950 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2954 unsigned short newTid;
2955 char shareName[256];
2963 osi_Log0(smb_logp, "SMB receive tree connect");
2965 /* parse input parameters */
2966 tp = smb_GetSMBData(inp, NULL);
2967 pathp = smb_ParseASCIIBlock(tp, &tp);
2968 passwordp = smb_ParseASCIIBlock(tp, &tp);
2969 tp = strrchr(pathp, '\\');
2971 return CM_ERROR_BADSMB;
2972 strcpy(shareName, tp+1);
2974 userp = smb_GetUser(vcp, inp);
2976 lock_ObtainMutex(&vcp->mx);
2977 newTid = vcp->tidCounter++;
2978 lock_ReleaseMutex(&vcp->mx);
2980 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2981 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2982 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2984 smb_ReleaseUID(uidp);
2986 smb_ReleaseTID(tidp);
2987 return CM_ERROR_BADSHARENAME;
2989 lock_ObtainMutex(&tidp->mx);
2990 tidp->userp = userp;
2991 tidp->pathname = sharePath;
2992 lock_ReleaseMutex(&tidp->mx);
2993 smb_ReleaseTID(tidp);
2995 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2996 smb_SetSMBParm(rsp, 1, newTid);
2997 smb_SetSMBDataLength(rsp, 0);
2999 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3003 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3007 if (*inp++ != 0x1) return NULL;
3008 tlen = inp[0] + (inp[1]<<8);
3009 inp += 2; /* skip length field */
3012 *chainpp = inp + tlen;
3015 if (lengthp) *lengthp = tlen;
3020 /* set maskp to the mask part of the incoming path.
3021 * Mask is 11 bytes long (8.3 with the dot elided).
3022 * Returns true if succeeds with a valid name, otherwise it does
3023 * its best, but returns false.
3025 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3033 /* starts off valid */
3036 /* mask starts out all blanks */
3037 memset(maskp, ' ', 11);
3039 /* find last backslash, or use whole thing if there is none */
3040 tp = strrchr(pathp, '\\');
3041 if (!tp) tp = pathp;
3042 else tp++; /* skip slash */
3046 /* names starting with a dot are illegal */
3047 if (*tp == '.') valid8Dot3 = 0;
3051 if (tc == 0) return valid8Dot3;
3052 if (tc == '.' || tc == '"') break;
3053 if (i < 8) *up++ = tc;
3054 else valid8Dot3 = 0;
3057 /* if we get here, tp point after the dot */
3058 up = maskp+8; /* ext goes here */
3065 if (tc == '.' || tc == '"')
3068 /* copy extension if not too long */
3078 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3088 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3090 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3094 /* otherwise, we have a valid 8.3 name; see if we have a match,
3095 * treating '?' as a wildcard in maskp (but not in the file name).
3097 tp1 = umask; /* real name, in mask format */
3098 tp2 = maskp; /* mask, in mask format */
3099 for(i=0; i<11; i++) {
3100 tc1 = *tp1++; /* char from real name */
3101 tc2 = *tp2++; /* char from mask */
3102 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3103 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3106 if (tc2 == '?' && tc1 != ' ')
3113 /* we got a match */
3117 char *smb_FindMask(char *pathp)
3121 tp = strrchr(pathp, '\\'); /* find last slash */
3124 return tp+1; /* skip the slash */
3126 return pathp; /* no slash, return the entire path */
3129 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3131 unsigned char *pathp;
3133 unsigned char mask[11];
3134 unsigned char *statBlockp;
3135 unsigned char initStatBlock[21];
3138 osi_Log0(smb_logp, "SMB receive search volume");
3140 /* pull pathname and stat block out of request */
3141 tp = smb_GetSMBData(inp, NULL);
3142 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3143 osi_assert(pathp != NULL);
3144 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3145 osi_assert(statBlockp != NULL);
3147 statBlockp = initStatBlock;
3151 /* for returning to caller */
3152 smb_Get8Dot3MaskFromPath(mask, pathp);
3154 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3155 tp = smb_GetSMBData(outp, NULL);
3157 *tp++ = 43; /* bytes in a dir entry */
3158 *tp++ = 0; /* high byte in counter */
3160 /* now marshall the dir entry, starting with the search status */
3161 *tp++ = statBlockp[0]; /* Reserved */
3162 memcpy(tp, mask, 11); tp += 11; /* FileName */
3164 /* now pass back server use info, with 1st byte non-zero */
3166 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3168 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3170 *tp++ = 0x8; /* attribute: volume */
3180 /* 4 byte file size */
3186 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3187 memset(tp, ' ', 13);
3190 /* set the length of the data part of the packet to 43 + 3, for the dir
3191 * entry plus the 5 and the length fields.
3193 smb_SetSMBDataLength(outp, 46);
3197 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3198 cm_user_t *userp, cm_req_t *reqp)
3206 smb_dirListPatch_t *patchp;
3207 smb_dirListPatch_t *npatchp;
3209 for (patchp = *dirPatchespp; patchp; patchp =
3210 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3212 dptr = patchp->dptr;
3214 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3216 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3217 *dptr++ = SMB_ATTR_HIDDEN;
3220 lock_ObtainMutex(&scp->mx);
3221 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3222 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3224 lock_ReleaseMutex(&scp->mx);
3225 cm_ReleaseSCache(scp);
3226 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3227 *dptr++ = SMB_ATTR_HIDDEN;
3231 attr = smb_Attributes(scp);
3232 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3233 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3234 attr |= SMB_ATTR_HIDDEN;
3238 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3241 shortTemp = dosTime & 0xffff;
3242 *((u_short *)dptr) = shortTemp;
3245 /* and copy out date */
3246 shortTemp = (dosTime>>16) & 0xffff;
3247 *((u_short *)dptr) = shortTemp;
3250 /* copy out file length */
3251 *((u_long *)dptr) = scp->length.LowPart;
3253 lock_ReleaseMutex(&scp->mx);
3254 cm_ReleaseSCache(scp);
3257 /* now free the patches */
3258 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3259 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3263 /* and mark the list as empty */
3264 *dirPatchespp = NULL;
3269 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3278 smb_dirListPatch_t *dirListPatchesp;
3279 smb_dirListPatch_t *curPatchp;
3283 osi_hyper_t dirLength;
3284 osi_hyper_t bufferOffset;
3285 osi_hyper_t curOffset;
3287 unsigned char *inCookiep;
3288 smb_dirSearch_t *dsp;
3292 unsigned long clientCookie;
3293 cm_pageHeader_t *pageHeaderp;
3294 cm_user_t *userp = NULL;
3301 long nextEntryCookie;
3302 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3303 char resByte; /* reserved byte from the cookie */
3304 char *op; /* output data ptr */
3305 char *origOp; /* original value of op */
3306 cm_space_t *spacep; /* for pathname buffer */
3317 maxCount = smb_GetSMBParm(inp, 0);
3319 dirListPatchesp = NULL;
3321 caseFold = CM_FLAG_CASEFOLD;
3323 tp = smb_GetSMBData(inp, NULL);
3324 pathp = smb_ParseASCIIBlock(tp, &tp);
3325 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3327 /* bail out if request looks bad */
3328 if (!tp || !pathp) {
3329 return CM_ERROR_BADSMB;
3332 /* We can handle long names */
3333 if (vcp->flags & SMB_VCFLAG_USENT)
3334 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3336 /* make sure we got a whole search status */
3337 if (dataLength < 21) {
3338 nextCookie = 0; /* start at the beginning of the dir */
3341 attribute = smb_GetSMBParm(inp, 1);
3343 /* handle volume info in another function */
3344 if (attribute & 0x8)
3345 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3347 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3348 maxCount, osi_LogSaveString(smb_logp, pathp));
3350 if (*pathp == 0) { /* null pathp, treat as root dir */
3351 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3352 return CM_ERROR_NOFILES;
3356 dsp = smb_NewDirSearch(0);
3357 dsp->attribute = attribute;
3358 smb_Get8Dot3MaskFromPath(mask, pathp);
3359 memcpy(dsp->mask, mask, 11);
3361 /* track if this is likely to match a lot of entries */
3362 if (smb_IsStarMask(mask)) starPattern = 1;
3363 else starPattern = 0;
3366 /* pull the next cookie value out of the search status block */
3367 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3368 + (inCookiep[16]<<24);
3369 dsp = smb_FindDirSearch(inCookiep[12]);
3371 /* can't find dir search status; fatal error */
3372 return CM_ERROR_BADFD;
3374 attribute = dsp->attribute;
3375 resByte = inCookiep[0];
3377 /* copy out client cookie, in host byte order. Don't bother
3378 * interpreting it, since we're just passing it through, anyway.
3380 memcpy(&clientCookie, &inCookiep[17], 4);
3382 memcpy(mask, dsp->mask, 11);
3384 /* assume we're doing a star match if it has continued for more
3390 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3391 nextCookie, dsp->cookie, attribute);
3393 userp = smb_GetUser(vcp, inp);
3395 /* try to get the vnode for the path name next */
3396 lock_ObtainMutex(&dsp->mx);
3403 spacep = inp->spacep;
3404 smb_StripLastComponent(spacep->data, NULL, pathp);
3405 lock_ReleaseMutex(&dsp->mx);
3406 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3408 lock_ReleaseMutex(&dsp->mx);
3409 cm_ReleaseUser(userp);
3410 smb_DeleteDirSearch(dsp);
3411 smb_ReleaseDirSearch(dsp);
3412 return CM_ERROR_NOFILES;
3414 code = cm_NameI(cm_rootSCachep, spacep->data,
3415 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3416 lock_ObtainMutex(&dsp->mx);
3418 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3420 /* we need one hold for the entry we just stored into,
3421 * and one for our own processing. When we're done with this
3422 * function, we'll drop the one for our own processing.
3423 * We held it once from the namei call, and so we do another hold
3427 lock_ObtainMutex(&scp->mx);
3428 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3429 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3430 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3431 dsp->flags |= SMB_DIRSEARCH_BULKST;
3433 lock_ReleaseMutex(&scp->mx);
3436 lock_ReleaseMutex(&dsp->mx);
3438 cm_ReleaseUser(userp);
3439 smb_DeleteDirSearch(dsp);
3440 smb_ReleaseDirSearch(dsp);
3444 /* reserves space for parameter; we'll adjust it again later to the
3445 * real count of the # of entries we returned once we've actually
3446 * assembled the directory listing.
3448 smb_SetSMBParm(outp, 0, 0);
3450 /* get the directory size */
3451 lock_ObtainMutex(&scp->mx);
3452 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3453 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3455 lock_ReleaseMutex(&scp->mx);
3456 cm_ReleaseSCache(scp);
3457 cm_ReleaseUser(userp);
3458 smb_DeleteDirSearch(dsp);
3459 smb_ReleaseDirSearch(dsp);
3463 dirLength = scp->length;
3465 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3466 curOffset.HighPart = 0;
3467 curOffset.LowPart = nextCookie;
3468 origOp = op = smb_GetSMBData(outp, NULL);
3469 /* and write out the basic header */
3470 *op++ = 5; /* variable block */
3471 op += 2; /* skip vbl block length; we'll fill it in later */
3475 /* make sure that curOffset.LowPart doesn't point to the first
3476 * 32 bytes in the 2nd through last dir page, and that it doesn't
3477 * point at the first 13 32-byte chunks in the first dir page,
3478 * since those are dir and page headers, and don't contain useful
3481 temp = curOffset.LowPart & (2048-1);
3482 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3483 /* we're in the first page */
3484 if (temp < 13*32) temp = 13*32;
3487 /* we're in a later dir page */
3488 if (temp < 32) temp = 32;
3491 /* make sure the low order 5 bits are zero */
3494 /* now put temp bits back ito curOffset.LowPart */
3495 curOffset.LowPart &= ~(2048-1);
3496 curOffset.LowPart |= temp;
3498 /* check if we've returned all the names that will fit in the
3501 if (returnedNames >= maxCount)
3504 /* check if we've passed the dir's EOF */
3505 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3507 /* see if we can use the bufferp we have now; compute in which page
3508 * the current offset would be, and check whether that's the offset
3509 * of the buffer we have. If not, get the buffer.
3511 thyper.HighPart = curOffset.HighPart;
3512 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3513 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3516 buf_Release(bufferp);
3519 lock_ReleaseMutex(&scp->mx);
3520 lock_ObtainRead(&scp->bufCreateLock);
3521 code = buf_Get(scp, &thyper, &bufferp);
3522 lock_ReleaseRead(&scp->bufCreateLock);
3524 /* now, if we're doing a star match, do bulk fetching of all of
3525 * the status info for files in the dir.
3528 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3530 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3531 LargeIntegerGreaterThanOrEqualTo(thyper,
3532 scp->bulkStatProgress)) {
3533 /* Don't bulk stat if risking timeout */
3534 int now = GetCurrentTime();
3535 if (now - req.startTime > 5000) {
3536 scp->bulkStatProgress = thyper;
3537 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3538 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3540 cm_TryBulkStat(scp, &thyper, userp, &req);
3544 lock_ObtainMutex(&scp->mx);
3547 bufferOffset = thyper;
3549 /* now get the data in the cache */
3551 code = cm_SyncOp(scp, bufferp, userp, &req,
3553 CM_SCACHESYNC_NEEDCALLBACK |
3554 CM_SCACHESYNC_READ);
3557 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3559 /* otherwise, load the buffer and try again */
3560 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3564 buf_Release(bufferp);
3568 } /* if (wrong buffer) ... */
3570 /* now we have the buffer containing the entry we're interested in; copy
3571 * it out if it represents a non-deleted entry.
3573 entryInDir = curOffset.LowPart & (2048-1);
3574 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3576 /* page header will help tell us which entries are free. Page header
3577 * can change more often than once per buffer, since AFS 3 dir page size
3578 * may be less than (but not more than a buffer package buffer.
3580 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3581 temp &= ~(2048 - 1); /* turn off intra-page bits */
3582 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3584 /* now determine which entry we're looking at in the page. If it is
3585 * free (there's a free bitmap at the start of the dir), we should
3586 * skip these 32 bytes.
3588 slotInPage = (entryInDir & 0x7e0) >> 5;
3589 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3590 /* this entry is free */
3591 numDirChunks = 1; /* only skip this guy */
3595 tp = bufferp->datap + entryInBuffer;
3596 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3598 /* while we're here, compute the next entry's location, too,
3599 * since we'll need it when writing out the cookie into the dir
3602 * XXXX Probably should do more sanity checking.
3604 numDirChunks = cm_NameEntries(dep->name, NULL);
3606 /* compute the offset of the cookie representing the next entry */
3607 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3609 /* Compute 8.3 name if necessary */
3610 actualName = dep->name;
3611 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3612 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3613 actualName = shortName;
3616 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3617 /* this is one of the entries to use: it is not deleted
3618 * and it matches the star pattern we're looking for.
3621 /* Eliminate entries that don't match requested
3624 /* no hidden files */
3625 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3628 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3630 /* We have already done the cm_TryBulkStat above */
3631 fid.cell = scp->fid.cell;
3632 fid.volume = scp->fid.volume;
3633 fid.vnode = ntohl(dep->fid.vnode);
3634 fid.unique = ntohl(dep->fid.unique);
3635 fileType = cm_FindFileType(&fid);
3636 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3637 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3639 if (fileType == CM_SCACHETYPE_DIRECTORY)
3644 memcpy(op, mask, 11); op += 11;
3645 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3646 *op++ = nextEntryCookie & 0xff;
3647 *op++ = (nextEntryCookie>>8) & 0xff;
3648 *op++ = (nextEntryCookie>>16) & 0xff;
3649 *op++ = (nextEntryCookie>>24) & 0xff;
3650 memcpy(op, &clientCookie, 4); op += 4;
3652 /* now we emit the attribute. This is sort of tricky,
3653 * since we need to really stat the file to find out
3654 * what type of entry we've got. Right now, we're
3655 * copying out data from a buffer, while holding the
3656 * scp locked, so it isn't really convenient to stat
3657 * something now. We'll put in a place holder now,
3658 * and make a second pass before returning this to get
3659 * the real attributes. So, we just skip the data for
3660 * now, and adjust it later. We allocate a patch
3661 * record to make it easy to find this point later.
3662 * The replay will happen at a time when it is safe to
3663 * unlock the directory.
3665 curPatchp = malloc(sizeof(*curPatchp));
3666 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3667 curPatchp->dptr = op;
3668 curPatchp->fid.cell = scp->fid.cell;
3669 curPatchp->fid.volume = scp->fid.volume;
3670 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3671 curPatchp->fid.unique = ntohl(dep->fid.unique);
3673 /* do hidden attribute here since name won't be around when applying
3677 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3678 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3680 curPatchp->flags = 0;
3682 op += 9; /* skip attr, time, date and size */
3684 /* zero out name area. The spec says to pad with
3685 * spaces, but Samba doesn't, and neither do we.
3689 /* finally, we get to copy out the name; we know that
3690 * it fits in 8.3 or the pattern wouldn't match, but it
3691 * never hurts to be sure.
3693 strncpy(op, actualName, 13);
3695 /* Uppercase if requested by client */
3696 if ((((smb_t *)inp)->flg2 & 1) == 0)
3701 /* now, adjust the # of entries copied */
3703 } /* if we're including this name */
3706 /* and adjust curOffset to be where the new cookie is */
3707 thyper.HighPart = 0;
3708 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3709 curOffset = LargeIntegerAdd(thyper, curOffset);
3710 } /* while copying data for dir listing */
3712 /* release the mutex */
3713 lock_ReleaseMutex(&scp->mx);
3714 if (bufferp) buf_Release(bufferp);
3716 /* apply and free last set of patches; if not doing a star match, this
3717 * will be empty, but better safe (and freeing everything) than sorry.