2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
17 #include <sys/timeb.h>
29 #include <rx/rx_prototypes.h>
32 #include <WINNT\afsreg.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 **NCBShutdown;
101 EVENT_HANDLE *smb_ServerShutdown;
102 DWORD NCBsessions[NCBmax];
104 struct smb_packet *bufs[NCBmax];
106 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
107 EVENT_HANDLE SessionEvents[Sessionmax];
108 unsigned short LSNs[Sessionmax];
109 int lanas[Sessionmax];
110 BOOL dead_sessions[Sessionmax];
114 osi_mutex_t smb_RawBufLock;
116 #define SMB_RAW_BUFS 4
118 int smb_RawBufSel[SMB_RAW_BUFS];
123 #define SMB_MASKFLAG_TILDE 1
124 #define SMB_MASKFLAG_CASEFOLD 2
126 #define RAWTIMEOUT INFINITE
129 typedef struct raw_write_cont {
142 /* dir search stuff */
143 long smb_dirSearchCounter = 1;
144 smb_dirSearch_t *smb_firstDirSearchp;
145 smb_dirSearch_t *smb_lastDirSearchp;
147 /* hide dot files? */
148 int smb_hideDotFiles;
150 /* global state about V3 protocols */
151 int smb_useV3; /* try to negotiate V3 */
154 static showErrors = 1;
155 /* MessageBox or something like it */
156 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
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 #define USE_NUMERIC_TIME_CONV 1
167 #ifndef USE_NUMERIC_TIME_CONV
168 /* Time difference for converting to kludge-GMT */
169 afs_uint32 smb_NowTZ;
170 #endif /* USE_NUMERIC_TIME_CONV */
172 char *smb_localNamep = NULL;
174 smb_vc_t *smb_allVCsp;
176 smb_username_t *usernamesp = NULL;
178 smb_waitingLock_t *smb_allWaitingLocks;
181 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
182 NCB *ncbp, raw_write_cont_t *rwcp);
183 void smb_NetbiosInit();
185 #ifndef AFS_WIN95_ENV
186 DWORD smb_ServerExceptionFilter(void);
189 extern char cm_HostName[];
190 extern char cm_confDir[];
194 #define LPTSTR char *
195 #define GetComputerName(str, sizep) \
196 strcpy((str), cm_HostName); \
197 *(sizep) = strlen(cm_HostName)
201 void smb_LogPacket(smb_packet_t *packet);
202 #endif /* LOG_PACKET */
204 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
205 int smb_ServerDomainNameLength = 0;
206 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
207 int smb_ServerOSLength = sizeof(smb_ServerOS);
208 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
209 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
211 /* Faux server GUID. This is never checked. */
212 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
214 char * myCrt_Dispatch(int i)
219 return "(00)ReceiveCoreMakeDir";
221 return "(01)ReceiveCoreRemoveDir";
223 return "(02)ReceiveCoreOpen";
225 return "(03)ReceiveCoreCreate";
227 return "(04)ReceiveCoreClose";
229 return "(05)ReceiveCoreFlush";
231 return "(06)ReceiveCoreUnlink";
233 return "(07)ReceiveCoreRename";
235 return "(08)ReceiveCoreGetFileAttributes";
237 return "(09)ReceiveCoreSetFileAttributes";
239 return "(0a)ReceiveCoreRead";
241 return "(0b)ReceiveCoreWrite";
243 return "(0c)ReceiveCoreLockRecord";
245 return "(0d)ReceiveCoreUnlockRecord";
247 return "(0e)SendCoreBadOp";
249 return "(0f)ReceiveCoreCreate";
251 return "(10)ReceiveCoreCheckPath";
253 return "(11)SendCoreBadOp";
255 return "(12)ReceiveCoreSeek";
257 return "(1a)ReceiveCoreReadRaw";
259 return "(1d)ReceiveCoreWriteRawDummy";
261 return "(22)ReceiveV3SetAttributes";
263 return "(23)ReceiveV3GetAttributes";
265 return "(24)ReceiveV3LockingX";
267 return "(25)ReceiveV3Trans";
269 return "(26)ReceiveV3Trans[aux]";
271 return "(29)SendCoreBadOp";
273 return "(2b)ReceiveCoreEcho";
275 return "(2d)ReceiveV3OpenX";
277 return "(2e)ReceiveV3ReadX";
279 return "(32)ReceiveV3Tran2A";
281 return "(33)ReceiveV3Tran2A[aux]";
283 return "(34)ReceiveV3FindClose";
285 return "(35)ReceiveV3FindNotifyClose";
287 return "(70)ReceiveCoreTreeConnect";
289 return "(71)ReceiveCoreTreeDisconnect";
291 return "(72)ReceiveNegotiate";
293 return "(73)ReceiveV3SessionSetupX";
295 return "(74)ReceiveV3UserLogoffX";
297 return "(75)ReceiveV3TreeConnectX";
299 return "(80)ReceiveCoreGetDiskAttributes";
301 return "(81)ReceiveCoreSearchDir";
305 return "(83)FindUnique";
307 return "(84)FindClose";
309 return "(A0)ReceiveNTTransact";
311 return "(A2)ReceiveNTCreateX";
313 return "(A4)ReceiveNTCancel";
315 return "(A5)ReceiveNTRename";
317 return "(C0)OpenPrintFile";
319 return "(C1)WritePrintFile";
321 return "(C2)ClosePrintFile";
323 return "(C3)GetPrintQueue";
325 return "(D8)ReadBulk";
327 return "(D9)WriteBulk";
329 return "(DA)WriteBulkData";
331 return "unknown SMB op";
335 char * myCrt_2Dispatch(int i)
340 return "unknown SMB op-2";
342 return "S(00)CreateFile";
344 return "S(01)FindFirst";
346 return "S(02)FindNext"; /* FindNext */
348 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
352 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
354 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
356 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
358 return "S(08)??_ReceiveTran2SetFileInfo";
360 return "S(09)??_ReceiveTran2FSCTL";
362 return "S(0a)_ReceiveTran2IOCTL";
364 return "S(0b)_ReceiveTran2FindNotifyFirst";
366 return "S(0c)_ReceiveTran2FindNotifyNext";
368 return "S(0d)_ReceiveTran2CreateDirectory";
370 return "S(0e)_ReceiveTran2SessionSetup";
372 return "S(10)_ReceiveTran2GetDfsReferral";
374 return "S(11)_ReceiveTran2ReportDfsInconsistency";
378 char * myCrt_RapDispatch(int i)
383 return "unknown RAP OP";
385 return "RAP(0)NetShareEnum";
387 return "RAP(1)NetShareGetInfo";
389 return "RAP(13)NetServerGetInfo";
391 return "RAP(63)NetWkStaGetInfo";
395 /* scache must be locked */
396 unsigned int smb_Attributes(cm_scache_t *scp)
400 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
401 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
402 scp->fileType == CM_SCACHETYPE_INVALID)
404 attrs = SMB_ATTR_DIRECTORY;
405 #ifdef SPECIAL_FOLDERS
406 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
407 #endif /* SPECIAL_FOLDERS */
408 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
409 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
414 * We used to mark a file RO if it was in an RO volume, but that
415 * turns out to be impolitic in NT. See defect 10007.
418 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
419 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
421 if ((scp->unixModeBits & 0222) == 0)
422 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
428 /* Check if the named file/dir is a dotfile/dotdir */
429 /* String pointed to by lastComp can have leading slashes, but otherwise should have
430 no other patch components */
431 unsigned int smb_IsDotFile(char *lastComp) {
434 /* skip over slashes */
435 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
440 /* nulls, curdir and parent dir doesn't count */
446 if(*(s+1) == '.' && !*(s + 2))
453 static int ExtractBits(WORD bits, short start, short len)
460 num = bits << (16 - end);
461 num = num >> ((16 - end) + start);
467 void ShowUnixTime(char *FuncName, time_t unixTime)
472 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
474 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
475 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
477 int day, month, year, sec, min, hour;
480 day = ExtractBits(wDate, 0, 5);
481 month = ExtractBits(wDate, 5, 4);
482 year = ExtractBits(wDate, 9, 7) + 1980;
484 sec = ExtractBits(wTime, 0, 5);
485 min = ExtractBits(wTime, 5, 6);
486 hour = ExtractBits(wTime, 11, 5);
488 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
489 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
495 /* Determine if we are observing daylight savings time */
496 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
498 TIME_ZONE_INFORMATION timeZoneInformation;
499 SYSTEMTIME utc, local, localDST;
501 /* Get the time zone info. NT uses this to calc if we are in DST. */
502 GetTimeZoneInformation(&timeZoneInformation);
504 /* Return the daylight bias */
505 *pDstBias = timeZoneInformation.DaylightBias;
507 /* Return the bias */
508 *pBias = timeZoneInformation.Bias;
510 /* Now determine if DST is being observed */
512 /* Get the UTC (GMT) time */
515 /* Convert UTC time to local time using the time zone info. If we are
516 observing DST, the calculated local time will include this.
518 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
520 /* Set the daylight bias to 0. The daylight bias is the amount of change
521 * in time that we use for daylight savings time. By setting this to 0
522 * we cause there to be no change in time during daylight savings time.
524 timeZoneInformation.DaylightBias = 0;
526 /* Convert the utc time to local time again, but this time without any
527 adjustment for daylight savings time.
529 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
531 /* If the two times are different, then it means that the localDST that
532 we calculated includes the daylight bias, and therefore we are
533 observing daylight savings time.
535 *pDST = localDST.wHour != local.wHour;
538 /* Determine if we are observing daylight savings time */
539 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
545 *pDstBias = -60; /* where can this be different? */
551 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
553 BOOL dst; /* Will be TRUE if observing DST */
554 LONG dstBias; /* Offset from local time if observing DST */
555 LONG bias; /* Offset from GMT for local time */
558 * This function will adjust the last write time to compensate
559 * for two bugs in the smb client:
561 * 1) During Daylight Savings Time, the LastWriteTime is ahead
562 * in time by the DaylightBias (ignoring the sign - the
563 * DaylightBias is always stored as a negative number). If
564 * the DaylightBias is -60, then the LastWriteTime will be
565 * ahead by 60 minutes.
567 * 2) If the local time zone is a positive offset from GMT, then
568 * the LastWriteTime will be the correct local time plus the
569 * Bias (ignoring the sign - a positive offset from GMT is
570 * always stored as a negative Bias). If the Bias is -120,
571 * then the LastWriteTime will be ahead by 120 minutes.
573 * These bugs can occur at the same time.
576 GetTimeZoneInfo(&dst, &dstBias, &bias);
578 /* First adjust for DST */
580 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
582 /* Now adjust for a positive offset from GMT (a negative bias). */
584 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
587 #ifndef USE_NUMERIC_TIME_CONV
589 * Calculate the difference (in seconds) between local time and GMT.
590 * This enables us to convert file times to kludge-GMT.
596 struct tm gmt_tm, local_tm;
597 int days, hours, minutes, seconds;
600 gmt_tm = *(gmtime(&t));
601 local_tm = *(localtime(&t));
603 days = local_tm.tm_yday - gmt_tm.tm_yday;
604 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
605 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
606 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
610 #endif /* USE_NUMERIC_TIME_CONV */
613 #ifdef USE_NUMERIC_TIME_CONV
614 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
616 // Note that LONGLONG is a 64-bit value
619 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
620 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
621 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
624 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
629 time_t ersatz_unixTime;
632 * Must use kludge-GMT instead of real GMT.
633 * kludge-GMT is computed by adding time zone difference to localtime.
636 * ltp = gmtime(&unixTime);
638 ersatz_unixTime = unixTime - smb_NowTZ;
639 ltp = localtime(&ersatz_unixTime);
641 /* if we fail, make up something */
644 localJunk.tm_year = 89 - 20;
645 localJunk.tm_mon = 4;
646 localJunk.tm_mday = 12;
647 localJunk.tm_hour = 0;
648 localJunk.tm_min = 0;
649 localJunk.tm_sec = 0;
652 stm.wYear = ltp->tm_year + 1900;
653 stm.wMonth = ltp->tm_mon + 1;
654 stm.wDayOfWeek = ltp->tm_wday;
655 stm.wDay = ltp->tm_mday;
656 stm.wHour = ltp->tm_hour;
657 stm.wMinute = ltp->tm_min;
658 stm.wSecond = ltp->tm_sec;
659 stm.wMilliseconds = 0;
661 SystemTimeToFileTime(&stm, largeTimep);
663 #endif /* USE_NUMERIC_TIME_CONV */
665 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
667 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
668 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
669 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
671 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
673 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
674 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
676 *ft = LargeIntegerMultiplyByLong(*ft, 60);
677 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
680 ut = ConvertLongToLargeInteger(unixTime);
681 ut = LargeIntegerMultiplyByLong(ut, 10000000);
682 *ft = LargeIntegerAdd(*ft, ut);
687 #ifdef USE_NUMERIC_TIME_CONV
688 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
690 // Note that LONGLONG is a 64-bit value
693 ll = largeTimep->dwHighDateTime;
695 ll += largeTimep->dwLowDateTime;
697 ll -= 116444736000000000;
700 *unixTimep = (DWORD)ll;
702 #else /* USE_NUMERIC_TIME_CONV */
703 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
709 FileTimeToSystemTime(largeTimep, &stm);
711 lt.tm_year = stm.wYear - 1900;
712 lt.tm_mon = stm.wMonth - 1;
713 lt.tm_wday = stm.wDayOfWeek;
714 lt.tm_mday = stm.wDay;
715 lt.tm_hour = stm.wHour;
716 lt.tm_min = stm.wMinute;
717 lt.tm_sec = stm.wSecond;
720 save_timezone = _timezone;
721 _timezone += smb_NowTZ;
722 *unixTimep = mktime(<);
723 _timezone = save_timezone;
725 #endif /* USE_NUMERIC_TIME_CONV */
727 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
729 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
730 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
731 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
735 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
736 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
737 a = LargeIntegerMultiplyByLong(a, 60);
738 a = LargeIntegerMultiplyByLong(a, 10000000);
740 /* subtract it from ft */
741 a = LargeIntegerSubtract(*ft, a);
743 /* divide down to seconds */
744 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
748 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
756 ltp = localtime((time_t*) &t);
758 /* if we fail, make up something */
761 localJunk.tm_year = 89 - 20;
762 localJunk.tm_mon = 4;
763 localJunk.tm_mday = 12;
764 localJunk.tm_hour = 0;
765 localJunk.tm_min = 0;
766 localJunk.tm_sec = 0;
769 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
770 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
771 *searchTimep = (dosDate<<16) | dosTime;
774 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
776 unsigned short dosDate;
777 unsigned short dosTime;
780 dosDate = (unsigned short) (searchTime & 0xffff);
781 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
783 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
784 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
785 localTm.tm_mday = (dosDate) & 0x1f;
786 localTm.tm_hour = (dosTime>>11) & 0x1f;
787 localTm.tm_min = (dosTime >> 5) & 0x3f;
788 localTm.tm_sec = (dosTime & 0x1f) * 2;
789 localTm.tm_isdst = -1; /* compute whether DST in effect */
791 *unixTimep = mktime(&localTm);
794 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
796 *dosUTimep = unixTime - smb_localZero;
799 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
802 *unixTimep = dosTime + smb_localZero;
804 /* dosTime seems to be already adjusted for GMT */
805 *unixTimep = dosTime;
809 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
813 lock_ObtainWrite(&smb_rctLock);
814 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
815 if (lsn == vcp->lsn && lana == vcp->lana) {
816 smb_HoldVCNoLock(vcp);
820 if (!vcp && (flags & SMB_FLAG_CREATE)) {
821 vcp = malloc(sizeof(*vcp));
822 memset(vcp, 0, sizeof(*vcp));
823 vcp->vcID = numVCs++;
827 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
828 vcp->nextp = smb_allVCsp;
830 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
835 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
836 /* We must obtain a challenge for extended auth
837 * in case the client negotiates smb v3
839 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
840 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
841 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
842 ULONG lsaRespSize = 0;
844 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
846 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
853 if (nts != STATUS_SUCCESS)
854 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
855 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
856 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
858 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
859 LsaFreeReturnBuffer(lsaResp);
862 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
864 lock_ReleaseWrite(&smb_rctLock);
868 int smb_IsStarMask(char *maskp)
873 for(i=0; i<11; i++) {
875 if (tc == '?' || tc == '*' || tc == '>') return 1;
880 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
882 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
884 osi_assert(vcp->refCount-- != 0);
890 void smb_ReleaseVC(smb_vc_t *vcp)
892 lock_ObtainWrite(&smb_rctLock);
893 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
895 osi_assert(vcp->refCount-- != 0);
899 lock_ReleaseWrite(&smb_rctLock);
902 void smb_HoldVCNoLock(smb_vc_t *vcp)
905 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
908 void smb_HoldVC(smb_vc_t *vcp)
910 lock_ObtainWrite(&smb_rctLock);
912 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
913 lock_ReleaseWrite(&smb_rctLock);
916 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
920 lock_ObtainWrite(&smb_rctLock);
921 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
922 if (tid == tidp->tid) {
927 if (!tidp && (flags & SMB_FLAG_CREATE)) {
928 tidp = malloc(sizeof(*tidp));
929 memset(tidp, 0, sizeof(*tidp));
930 tidp->nextp = vcp->tidsp;
933 smb_HoldVCNoLock(vcp);
935 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
938 lock_ReleaseWrite(&smb_rctLock);
942 void smb_ReleaseTID(smb_tid_t *tidp)
949 lock_ObtainWrite(&smb_rctLock);
950 osi_assert(tidp->refCount-- > 0);
951 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
952 ltpp = &tidp->vcp->tidsp;
953 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
957 osi_assert(tp != NULL);
959 lock_FinalizeMutex(&tidp->mx);
960 userp = tidp->userp; /* remember to drop ref later */
962 smb_ReleaseVCNoLock(tidp->vcp);
965 lock_ReleaseWrite(&smb_rctLock);
967 cm_ReleaseUser(userp);
970 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
972 smb_user_t *uidp = NULL;
974 lock_ObtainWrite(&smb_rctLock);
975 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
976 if (uid == uidp->userID) {
978 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
979 (int)vcp, uidp->userID,
980 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
984 if (!uidp && (flags & SMB_FLAG_CREATE)) {
985 uidp = malloc(sizeof(*uidp));
986 memset(uidp, 0, sizeof(*uidp));
987 uidp->nextp = vcp->usersp;
990 smb_HoldVCNoLock(vcp);
992 lock_InitializeMutex(&uidp->mx, "user_t mutex");
994 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 : ""));
996 lock_ReleaseWrite(&smb_rctLock);
1000 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1002 smb_username_t *unp= NULL;
1004 lock_ObtainWrite(&smb_rctLock);
1005 for(unp = usernamesp; unp; unp = unp->nextp) {
1006 if (stricmp(unp->name, usern) == 0 &&
1007 stricmp(unp->machine, machine) == 0) {
1012 if (!unp && (flags & SMB_FLAG_CREATE)) {
1013 unp = malloc(sizeof(*unp));
1014 memset(unp, 0, sizeof(*unp));
1016 unp->nextp = usernamesp;
1017 unp->name = strdup(usern);
1018 unp->machine = strdup(machine);
1020 lock_InitializeMutex(&unp->mx, "username_t mutex");
1022 lock_ReleaseWrite(&smb_rctLock);
1026 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1028 smb_user_t *uidp= NULL;
1030 lock_ObtainWrite(&smb_rctLock);
1031 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1034 if (stricmp(uidp->unp->name, usern) == 0) {
1036 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
1041 lock_ReleaseWrite(&smb_rctLock);
1044 void smb_ReleaseUID(smb_user_t *uidp)
1051 lock_ObtainWrite(&smb_rctLock);
1052 osi_assert(uidp->refCount-- > 0);
1053 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1054 lupp = &uidp->vcp->usersp;
1055 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1059 osi_assert(up != NULL);
1061 lock_FinalizeMutex(&uidp->mx);
1063 userp = uidp->unp->userp; /* avoid deadlock by releasing */
1064 uidp->unp->userp = NULL; /* after releasing the lock */
1066 smb_ReleaseVCNoLock(uidp->vcp);
1069 lock_ReleaseWrite(&smb_rctLock);
1071 cm_ReleaseUserVCRef(userp);
1072 cm_ReleaseUser(userp);
1077 /* retrieve a held reference to a user structure corresponding to an incoming
1079 * corresponding release function is cm_ReleaseUser.
1081 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1087 smbp = (smb_t *) inp;
1088 uidp = smb_FindUID(vcp, smbp->uid, 0);
1089 if ((!uidp) || (!uidp->unp))
1092 lock_ObtainMutex(&uidp->mx);
1093 up = uidp->unp->userp;
1095 lock_ReleaseMutex(&uidp->mx);
1097 smb_ReleaseUID(uidp);
1103 * Return a pointer to a pathname extracted from a TID structure. The
1104 * TID structure is not held; assume it won't go away.
1106 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1111 tidp = smb_FindTID(vcp, tid, 0);
1115 if (tidp->flags & SMB_TIDFLAG_IPC) {
1116 code = CM_ERROR_TIDIPC;
1117 /* tidp->pathname would be NULL, but that's fine */
1119 *treepath = tidp->pathname;
1120 smb_ReleaseTID(tidp);
1125 /* check to see if we have a chained fid, that is, a fid that comes from an
1126 * OpenAndX message that ran earlier in this packet. In this case, the fid
1127 * field in a read, for example, request, isn't set, since the value is
1128 * supposed to be inherited from the openAndX call.
1130 int smb_ChainFID(int fid, smb_packet_t *inp)
1132 if (inp->fid == 0 || inp->inCount == 0)
1138 /* are we a priv'd user? What does this mean on NT? */
1139 int smb_SUser(cm_user_t *userp)
1144 /* find a file ID. If we pass in 0 we select an used File ID.
1145 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1146 * smb_fid_t data structure if desired File ID cannot be found.
1148 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1153 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1156 lock_ObtainWrite(&smb_rctLock);
1157 /* figure out if we need to allocate a new file ID */
1160 fid = vcp->fidCounter;
1164 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1165 if (fid == fidp->fid) {
1176 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1177 char eventName[MAX_PATH];
1179 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1180 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1181 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1182 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1183 thrd_CloseHandle(event);
1190 fidp = malloc(sizeof(*fidp));
1191 memset(fidp, 0, sizeof(*fidp));
1192 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1195 smb_HoldVCNoLock(vcp);
1196 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1198 fidp->curr_chunk = fidp->prev_chunk = -2;
1199 fidp->raw_write_event = event;
1201 vcp->fidCounter = fid+1;
1202 if (vcp->fidCounter == 0)
1203 vcp->fidCounter = 1;
1206 lock_ReleaseWrite(&smb_rctLock);
1210 void smb_ReleaseFID(smb_fid_t *fidp)
1213 smb_vc_t *vcp = NULL;
1214 smb_ioctl_t *ioctlp;
1220 lock_ObtainWrite(&smb_rctLock);
1221 osi_assert(fidp->refCount-- > 0);
1222 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1225 scp = fidp->scp; /* release after lock is released */
1228 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1229 thrd_CloseHandle(fidp->raw_write_event);
1231 /* and see if there is ioctl stuff to free */
1232 ioctlp = fidp->ioctlp;
1235 cm_FreeSpace(ioctlp->prefix);
1236 if (ioctlp->inAllocp)
1237 free(ioctlp->inAllocp);
1238 if (ioctlp->outAllocp)
1239 free(ioctlp->outAllocp);
1245 smb_ReleaseVCNoLock(vcp);
1247 lock_ReleaseWrite(&smb_rctLock);
1249 /* now release the scache structure */
1251 cm_ReleaseSCache(scp);
1255 * Case-insensitive search for one string in another;
1256 * used to find variable names in submount pathnames.
1258 static char *smb_stristr(char *str1, char *str2)
1262 for (cursor = str1; *cursor; cursor++)
1263 if (stricmp(cursor, str2) == 0)
1270 * Substitute a variable value for its name in a submount pathname. Variable
1271 * name has been identified by smb_stristr() and is in substr. Variable name
1272 * length (plus one) is in substr_size. Variable value is in newstr.
1274 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1279 strcpy(temp, substr + substr_size - 1);
1280 strcpy(substr, newstr);
1284 char VNUserName[] = "%USERNAME%";
1285 char VNLCUserName[] = "%LCUSERNAME%";
1286 char VNComputerName[] = "%COMPUTERNAME%";
1287 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1290 /* List available shares */
1291 int smb_ListShares()
1295 char shareBuf[4096];
1303 /*strcpy(shareNameList[num_shares], "all");
1304 strcpy(pathNameList[num_shares++], "/afs");*/
1305 fprintf(stderr, "The following shares are available:\n");
1306 fprintf(stderr, "Share Name (AFS Path)\n");
1307 fprintf(stderr, "---------------------\n");
1308 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1311 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1312 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1314 strcpy(sbmtpath, cm_confDir);
1316 strcat(sbmtpath, "/afsdsbmt.ini");
1317 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1318 shareBuf, sizeof(shareBuf),
1324 this_share = shareBuf;
1328 /*strcpy(shareNameList[num_shares], this_share);*/
1329 len = GetPrivateProfileString("AFS Submounts", this_share,
1336 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1339 if (*p == '\\') *p = '/'; /* change to / */
1343 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1344 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1347 while (*this_share != 0) this_share++; /* find next NUL */
1348 this_share++; /* skip past the NUL */
1349 } while (*this_share != 0); /* stop at final NUL */
1355 typedef struct smb_findShare_rock {
1359 } smb_findShare_rock_t;
1361 #define SMB_FINDSHARE_EXACT_MATCH 1
1362 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1364 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1368 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1369 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1370 if(!stricmp(dep->name, vrock->shareName))
1371 matchType = SMB_FINDSHARE_EXACT_MATCH;
1373 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1374 if(vrock->match) free(vrock->match);
1375 vrock->match = strdup(dep->name);
1376 vrock->matchType = matchType;
1378 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1379 return CM_ERROR_STOPNOW;
1385 /* find a shareName in the table of submounts */
1386 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1390 char pathName[1024];
1395 char sbmtpath[MAX_PATH];
1400 DWORD allSubmount = 1;
1402 /* if allSubmounts == 0, only return the //mountRoot/all share
1403 * if in fact it has been been created in the subMounts table.
1404 * This is to allow sites that want to restrict access to the
1407 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1408 0, KEY_QUERY_VALUE, &parmKey);
1409 if (code == ERROR_SUCCESS) {
1410 len = sizeof(allSubmount);
1411 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1412 (BYTE *) &allSubmount, &len);
1413 if (code != ERROR_SUCCESS) {
1416 RegCloseKey (parmKey);
1419 if (allSubmount && _stricmp(shareName, "all") == 0) {
1424 /* In case, the all share is disabled we need to still be able
1425 * to handle ioctl requests
1427 if (_stricmp(shareName, "ioctl$") == 0) {
1428 *pathNamep = strdup("/.__ioctl__");
1432 if (_stricmp(shareName, "IPC$") == 0 ||
1433 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1434 _stricmp(shareName, "DESKTOP.INI") == 0
1441 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1442 0, KEY_QUERY_VALUE, &parmKey);
1443 if (code == ERROR_SUCCESS) {
1444 len = sizeof(pathName);
1445 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1446 (BYTE *) pathName, &len);
1447 if (code != ERROR_SUCCESS)
1449 RegCloseKey (parmKey);
1454 strcpy(sbmtpath, cm_confDir);
1455 strcat(sbmtpath, "/afsdsbmt.ini");
1456 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1457 pathName, sizeof(pathName), sbmtpath);
1459 if (len != 0 && len != sizeof(pathName) - 1) {
1460 /* We can accept either unix or PC style AFS pathnames. Convert
1461 * Unix-style to PC style here for internal use.
1464 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1465 p += strlen(cm_mountRoot); /* skip mount path */
1468 if (*q == '/') *q = '\\'; /* change to \ */
1474 if (var = smb_stristr(p, VNUserName)) {
1475 if (uidp && uidp->unp)
1476 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1478 smb_subst(p, var, sizeof(VNUserName)," ");
1480 else if (var = smb_stristr(p, VNLCUserName))
1482 if (uidp && uidp->unp)
1483 strcpy(temp, uidp->unp->name);
1487 smb_subst(p, var, sizeof(VNLCUserName), temp);
1489 else if (var = smb_stristr(p, VNComputerName))
1491 sizeTemp = sizeof(temp);
1492 GetComputerName((LPTSTR)temp, &sizeTemp);
1493 smb_subst(p, var, sizeof(VNComputerName), temp);
1495 else if (var = smb_stristr(p, VNLCComputerName))
1497 sizeTemp = sizeof(temp);
1498 GetComputerName((LPTSTR)temp, &sizeTemp);
1500 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1505 *pathNamep = strdup(p);
1510 /* First lookup shareName in root.afs */
1512 smb_findShare_rock_t vrock;
1514 char * p = shareName;
1517 /* attempt to locate a partial match in root.afs. This is because
1518 when using the ANSI RAP calls, the share name is limited to 13 chars
1519 and hence is truncated. Of course we prefer exact matches. */
1521 thyper.HighPart = 0;
1524 vrock.shareName = shareName;
1526 vrock.matchType = 0;
1528 cm_HoldSCache(cm_data.rootSCachep);
1529 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1530 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1531 cm_ReleaseSCache(cm_data.rootSCachep);
1533 if (vrock.matchType) {
1534 sprintf(pathName,"/%s/",vrock.match);
1535 *pathNamep = strdup(strlwr(pathName));
1540 /* if we get here, there was no match for the share in root.afs */
1541 /* so try to create \\<netbiosName>\<cellname> */
1546 /* Get the full name for this cell */
1547 code = cm_SearchCellFile(p, temp, 0, 0);
1548 #ifdef AFS_AFSDB_ENV
1549 if (code && cm_dnsEnabled) {
1551 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1554 /* construct the path */
1556 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1557 *pathNamep = strdup(strlwr(pathName));
1566 /* Client-side offline caching policy types */
1567 #define CSC_POLICY_MANUAL 0
1568 #define CSC_POLICY_DOCUMENTS 1
1569 #define CSC_POLICY_PROGRAMS 2
1570 #define CSC_POLICY_DISABLE 3
1572 int smb_FindShareCSCPolicy(char *shareName)
1578 int retval = CSC_POLICY_MANUAL;
1580 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1581 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1584 REG_OPTION_NON_VOLATILE,
1590 len = sizeof(policy);
1591 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1593 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1595 else if (stricmp(policy, "documents") == 0)
1597 retval = CSC_POLICY_DOCUMENTS;
1599 else if (stricmp(policy, "programs") == 0)
1601 retval = CSC_POLICY_PROGRAMS;
1603 else if (stricmp(policy, "disable") == 0)
1605 retval = CSC_POLICY_DISABLE;
1608 RegCloseKey(hkCSCPolicy);
1612 /* find a dir search structure by cookie value, and return it held.
1613 * Must be called with smb_globalLock held.
1615 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1617 smb_dirSearch_t *dsp;
1619 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1620 if (dsp->cookie == cookie) {
1621 if (dsp != smb_firstDirSearchp) {
1622 /* move to head of LRU queue, too, if we're not already there */
1623 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1624 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1625 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1626 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1627 if (!smb_lastDirSearchp)
1628 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1630 lock_ObtainMutex(&dsp->mx);
1632 lock_ReleaseMutex(&dsp->mx);
1638 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1639 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1640 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1646 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1648 lock_ObtainWrite(&smb_globalLock);
1649 lock_ObtainMutex(&dsp->mx);
1650 dsp->flags |= SMB_DIRSEARCH_DELETE;
1651 if (dsp->scp != NULL) {
1652 lock_ObtainMutex(&dsp->scp->mx);
1653 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1654 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1655 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1656 dsp->scp->bulkStatProgress = hones;
1658 lock_ReleaseMutex(&dsp->scp->mx);
1660 lock_ReleaseMutex(&dsp->mx);
1661 lock_ReleaseWrite(&smb_globalLock);
1664 /* Must be called with the smb_globalLock held */
1665 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1667 cm_scache_t *scp = NULL;
1669 lock_ObtainMutex(&dsp->mx);
1670 osi_assert(dsp->refCount-- > 0);
1671 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1672 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1673 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1674 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1675 lock_ReleaseMutex(&dsp->mx);
1676 lock_FinalizeMutex(&dsp->mx);
1680 lock_ReleaseMutex(&dsp->mx);
1682 /* do this now to avoid spurious locking hierarchy creation */
1683 if (scp) cm_ReleaseSCache(scp);
1686 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1688 lock_ObtainWrite(&smb_globalLock);
1689 smb_ReleaseDirSearchNoLock(dsp);
1690 lock_ReleaseWrite(&smb_globalLock);
1693 /* find a dir search structure by cookie value, and return it held */
1694 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1696 smb_dirSearch_t *dsp;
1698 lock_ObtainWrite(&smb_globalLock);
1699 dsp = smb_FindDirSearchNoLock(cookie);
1700 lock_ReleaseWrite(&smb_globalLock);
1704 /* GC some dir search entries, in the address space expected by the specific protocol.
1705 * Must be called with smb_globalLock held; release the lock temporarily.
1707 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1708 void smb_GCDirSearches(int isV3)
1710 smb_dirSearch_t *prevp;
1711 smb_dirSearch_t *tp;
1712 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1716 victimCount = 0; /* how many have we got so far */
1717 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1718 /* we'll move tp from queue, so
1721 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1722 /* if no one is using this guy, and we're either in the new protocol,
1723 * or we're in the old one and this is a small enough ID to be useful
1724 * to the old protocol, GC this guy.
1726 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1727 /* hold and delete */
1728 tp->flags |= SMB_DIRSEARCH_DELETE;
1729 victimsp[victimCount++] = tp;
1733 /* don't do more than this */
1734 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1738 /* now release them */
1739 for (i = 0; i < victimCount; i++) {
1740 smb_ReleaseDirSearchNoLock(victimsp[i]);
1744 /* function for allocating a dir search entry. We need these to remember enough context
1745 * since we don't get passed the path from call to call during a directory search.
1747 * Returns a held dir search structure, and bumps the reference count on the vnode,
1748 * since it saves a pointer to the vnode.
1750 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1752 smb_dirSearch_t *dsp;
1758 lock_ObtainWrite(&smb_globalLock);
1761 /* what's the biggest ID allowed in this version of the protocol */
1762 maxAllowed = isV3 ? 65535 : 255;
1763 if (smb_dirSearchCounter > maxAllowed)
1764 smb_dirSearchCounter = 1;
1766 start = smb_dirSearchCounter;
1769 /* twice so we have enough tries to find guys we GC after one pass;
1770 * 10 extra is just in case I mis-counted.
1772 if (++counter > 2*maxAllowed+10)
1773 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1775 if (smb_dirSearchCounter > maxAllowed) {
1776 smb_dirSearchCounter = 1;
1778 if (smb_dirSearchCounter == start) {
1780 smb_GCDirSearches(isV3);
1783 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1785 /* don't need to watch for refcount zero and deleted, since
1786 * we haven't dropped the global lock.
1788 lock_ObtainMutex(&dsp->mx);
1790 lock_ReleaseMutex(&dsp->mx);
1791 ++smb_dirSearchCounter;
1795 dsp = malloc(sizeof(*dsp));
1796 memset(dsp, 0, sizeof(*dsp));
1797 dsp->cookie = smb_dirSearchCounter;
1798 ++smb_dirSearchCounter;
1800 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1801 dsp->lastTime = osi_Time();
1802 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1803 if (!smb_lastDirSearchp)
1804 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1807 lock_ReleaseWrite(&smb_globalLock);
1811 static smb_packet_t *GetPacket(void)
1815 unsigned int npar, seg, tb_sel;
1818 lock_ObtainWrite(&smb_globalLock);
1819 tbp = smb_packetFreeListp;
1821 smb_packetFreeListp = tbp->nextp;
1822 lock_ReleaseWrite(&smb_globalLock);
1825 tbp = calloc(65540,1);
1827 tbp = malloc(sizeof(smb_packet_t));
1829 tbp->magic = SMB_PACKETMAGIC;
1832 tbp->resumeCode = 0;
1838 tbp->ncb_length = 0;
1843 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1846 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1848 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1850 osi_panic("",__FILE__,__LINE__);
1853 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1858 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1859 tbp->dos_pkt_sel = tb_sel;
1862 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1867 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1871 memcpy(tbp, pkt, sizeof(smb_packet_t));
1872 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1874 smb_HoldVC(tbp->vcp);
1878 static NCB *GetNCB(void)
1883 unsigned int npar, seg, tb_sel;
1886 lock_ObtainWrite(&smb_globalLock);
1887 tbp = smb_ncbFreeListp;
1889 smb_ncbFreeListp = tbp->nextp;
1890 lock_ReleaseWrite(&smb_globalLock);
1893 tbp = calloc(sizeof(*tbp),1);
1895 tbp = malloc(sizeof(*tbp));
1896 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1899 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1901 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1903 osi_panic("",__FILE__,__LINE__);
1905 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1910 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1911 tbp->dos_ncb_sel = tb_sel;
1913 tbp->magic = SMB_NCBMAGIC;
1916 osi_assert(tbp->magic == SMB_NCBMAGIC);
1918 memset(&tbp->ncb, 0, sizeof(NCB));
1921 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1926 void smb_FreePacket(smb_packet_t *tbp)
1928 smb_vc_t * vcp = NULL;
1929 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1931 lock_ObtainWrite(&smb_globalLock);
1932 tbp->nextp = smb_packetFreeListp;
1933 smb_packetFreeListp = tbp;
1934 tbp->magic = SMB_PACKETMAGIC;
1938 tbp->resumeCode = 0;
1944 tbp->ncb_length = 0;
1946 lock_ReleaseWrite(&smb_globalLock);
1952 static void FreeNCB(NCB *bufferp)
1956 tbp = (smb_ncb_t *) bufferp;
1957 osi_assert(tbp->magic == SMB_NCBMAGIC);
1959 lock_ObtainWrite(&smb_globalLock);
1960 tbp->nextp = smb_ncbFreeListp;
1961 smb_ncbFreeListp = tbp;
1962 lock_ReleaseWrite(&smb_globalLock);
1965 /* get a ptr to the data part of a packet, and its count */
1966 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1970 unsigned char *afterParmsp;
1972 parmBytes = *smbp->wctp << 1;
1973 afterParmsp = smbp->wctp + parmBytes + 1;
1975 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1976 if (nbytesp) *nbytesp = dataBytes;
1978 /* don't forget to skip the data byte count, since it follows
1979 * the parameters; that's where the "2" comes from below.
1981 return (unsigned char *) (afterParmsp + 2);
1984 /* must set all the returned parameters before playing around with the
1985 * data region, since the data region is located past the end of the
1986 * variable number of parameters.
1988 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1990 unsigned char *afterParmsp;
1992 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1994 *afterParmsp++ = dsize & 0xff;
1995 *afterParmsp = (dsize>>8) & 0xff;
1998 /* return the parm'th parameter in the smbp packet */
1999 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2002 unsigned char *parmDatap;
2004 parmCount = *smbp->wctp;
2006 if (parm >= parmCount) {
2011 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2013 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2014 parm, parmCount, smbp->ncb_length);
2017 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2018 1, smbp->ncb_length, ptbuf, smbp);
2019 DeregisterEventSource(h);
2021 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2022 parm, parmCount, smbp->ncb_length);
2023 osi_panic(s, __FILE__, __LINE__);
2025 parmDatap = smbp->wctp + (2*parm) + 1;
2027 return parmDatap[0] + (parmDatap[1] << 8);
2030 /* return the parm'th parameter in the smbp packet */
2031 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2034 unsigned char *parmDatap;
2036 parmCount = *smbp->wctp;
2038 if (parm * 2 + offset >= parmCount * 2) {
2043 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2045 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2046 parm, offset, parmCount, smbp->ncb_length);
2049 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2050 1, smbp->ncb_length, ptbuf, smbp);
2051 DeregisterEventSource(h);
2053 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2054 parm, offset, parmCount, smbp->ncb_length);
2055 osi_panic(s, __FILE__, __LINE__);
2057 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2059 return parmDatap[0] + (parmDatap[1] << 8);
2062 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2066 /* make sure we have enough slots */
2067 if (*smbp->wctp <= slot)
2068 *smbp->wctp = slot+1;
2070 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2071 *parmDatap++ = parmValue & 0xff;
2072 *parmDatap = (parmValue>>8) & 0xff;
2075 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2079 /* make sure we have enough slots */
2080 if (*smbp->wctp <= slot)
2081 *smbp->wctp = slot+2;
2083 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2084 *parmDatap++ = parmValue & 0xff;
2085 *parmDatap++ = (parmValue>>8) & 0xff;
2086 *parmDatap++ = (parmValue>>16) & 0xff;
2087 *parmDatap++ = (parmValue>>24) & 0xff;
2090 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2095 /* make sure we have enough slots */
2096 if (*smbp->wctp <= slot)
2097 *smbp->wctp = slot+4;
2099 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2101 *parmDatap++ = *parmValuep++;
2104 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2108 /* make sure we have enough slots */
2109 if (*smbp->wctp <= slot) {
2110 if (smbp->oddByte) {
2112 *smbp->wctp = slot+1;
2117 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2118 *parmDatap++ = parmValue & 0xff;
2121 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2125 lastSlashp = strrchr(inPathp, '\\');
2127 *lastComponentp = lastSlashp;
2130 if (inPathp == lastSlashp)
2132 *outPathp++ = *inPathp++;
2141 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2146 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2151 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2157 tlen = inp[0] + (inp[1]<<8);
2158 inp += 2; /* skip length field */
2161 *chainpp = inp + tlen;
2170 /* format a packet as a response */
2171 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2176 outp = (smb_t *) op;
2178 /* zero the basic structure through the smb_wct field, and zero the data
2179 * size field, assuming that wct stays zero; otherwise, you have to
2180 * explicitly set the data size field, too.
2182 inSmbp = (smb_t *) inp;
2183 memset(outp, 0, sizeof(smb_t)+2);
2189 outp->com = inSmbp->com;
2190 outp->tid = inSmbp->tid;
2191 outp->pid = inSmbp->pid;
2192 outp->uid = inSmbp->uid;
2193 outp->mid = inSmbp->mid;
2194 outp->res[0] = inSmbp->res[0];
2195 outp->res[1] = inSmbp->res[1];
2196 op->inCom = inSmbp->com;
2198 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2199 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2201 /* copy fields in generic packet area */
2202 op->wctp = &outp->wct;
2205 /* send a (probably response) packet; vcp tells us to whom to send it.
2206 * we compute the length by looking at wct and bcc fields.
2208 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2225 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2228 memset((char *)ncbp, 0, sizeof(NCB));
2230 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2231 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2232 extra += tp[0] + (tp[1]<<8);
2233 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2234 extra += 3; /* wct and length fields */
2236 ncbp->ncb_length = extra; /* bytes to send */
2237 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2238 ncbp->ncb_lana_num = vcp->lana;
2239 ncbp->ncb_command = NCBSEND; /* op means send data */
2241 ncbp->ncb_buffer = (char *) inp;/* packet */
2242 code = Netbios(ncbp);
2244 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2245 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2247 /* copy header information from virtual to DOS address space */
2248 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2249 code = Netbios(ncbp, dos_ncb);
2253 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2259 void smb_MapNTError(long code, unsigned long *NTStatusp)
2261 unsigned long NTStatus;
2263 /* map CM_ERROR_* errors to NT 32-bit status codes */
2264 /* NT Status codes are listed in ntstatus.h not winerror.h */
2265 if (code == CM_ERROR_NOSUCHCELL) {
2266 NTStatus = 0xC000000FL; /* No such file */
2268 else if (code == CM_ERROR_NOSUCHVOLUME) {
2269 NTStatus = 0xC000000FL; /* No such file */
2271 else if (code == CM_ERROR_TIMEDOUT) {
2272 NTStatus = 0xC00000CFL; /* Sharing Paused */
2274 else if (code == CM_ERROR_RETRY) {
2275 NTStatus = 0xC000022DL; /* Retry */
2277 else if (code == CM_ERROR_NOACCESS) {
2278 NTStatus = 0xC0000022L; /* Access denied */
2280 else if (code == CM_ERROR_READONLY) {
2281 NTStatus = 0xC00000A2L; /* Write protected */
2283 else if (code == CM_ERROR_NOSUCHFILE) {
2284 NTStatus = 0xC000000FL; /* No such file */
2286 else if (code == CM_ERROR_NOSUCHPATH) {
2287 NTStatus = 0xC000003AL; /* Object path not found */
2289 else if (code == CM_ERROR_TOOBIG) {
2290 NTStatus = 0xC000007BL; /* Invalid image format */
2292 else if (code == CM_ERROR_INVAL) {
2293 NTStatus = 0xC000000DL; /* Invalid parameter */
2295 else if (code == CM_ERROR_BADFD) {
2296 NTStatus = 0xC0000008L; /* Invalid handle */
2298 else if (code == CM_ERROR_BADFDOP) {
2299 NTStatus = 0xC0000022L; /* Access denied */
2301 else if (code == CM_ERROR_EXISTS) {
2302 NTStatus = 0xC0000035L; /* Object name collision */
2304 else if (code == CM_ERROR_NOTEMPTY) {
2305 NTStatus = 0xC0000101L; /* Directory not empty */
2307 else if (code == CM_ERROR_CROSSDEVLINK) {
2308 NTStatus = 0xC00000D4L; /* Not same device */
2310 else if (code == CM_ERROR_NOTDIR) {
2311 NTStatus = 0xC0000103L; /* Not a directory */
2313 else if (code == CM_ERROR_ISDIR) {
2314 NTStatus = 0xC00000BAL; /* File is a directory */
2316 else if (code == CM_ERROR_BADOP) {
2318 /* I have no idea where this comes from */
2319 NTStatus = 0xC09820FFL; /* SMB no support */
2321 NTStatus = 0xC00000BBL; /* Not supported */
2322 #endif /* COMMENT */
2324 else if (code == CM_ERROR_BADSHARENAME) {
2325 NTStatus = 0xC00000CCL; /* Bad network name */
2327 else if (code == CM_ERROR_NOIPC) {
2329 NTStatus = 0xC0000022L; /* Access Denied */
2331 NTStatus = 0xC000013DL; /* Remote Resources */
2334 else if (code == CM_ERROR_CLOCKSKEW) {
2335 NTStatus = 0xC0000133L; /* Time difference at DC */
2337 else if (code == CM_ERROR_BADTID) {
2338 NTStatus = 0xC0982005L; /* SMB bad TID */
2340 else if (code == CM_ERROR_USESTD) {
2341 NTStatus = 0xC09820FBL; /* SMB use standard */
2343 else if (code == CM_ERROR_QUOTA) {
2345 NTStatus = 0xC0000044L; /* Quota exceeded */
2347 NTStatus = 0xC000007FL; /* Disk full */
2350 else if (code == CM_ERROR_SPACE) {
2351 NTStatus = 0xC000007FL; /* Disk full */
2353 else if (code == CM_ERROR_ATSYS) {
2354 NTStatus = 0xC0000033L; /* Object name invalid */
2356 else if (code == CM_ERROR_BADNTFILENAME) {
2357 NTStatus = 0xC0000033L; /* Object name invalid */
2359 else if (code == CM_ERROR_WOULDBLOCK) {
2360 NTStatus = 0xC0000055L; /* Lock not granted */
2362 else if (code == CM_ERROR_PARTIALWRITE) {
2363 NTStatus = 0xC000007FL; /* Disk full */
2365 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2366 NTStatus = 0xC0000023L; /* Buffer too small */
2368 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2369 NTStatus = 0xC0000035L; /* Object name collision */
2371 else if (code == CM_ERROR_BADPASSWORD) {
2372 NTStatus = 0xC000006DL; /* unknown username or bad password */
2374 else if (code == CM_ERROR_BADLOGONTYPE) {
2375 NTStatus = 0xC000015BL; /* logon type not granted */
2377 else if (code == CM_ERROR_GSSCONTINUE) {
2378 NTStatus = 0xC0000016L; /* more processing required */
2380 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2382 NTStatus = 0xC0000280L; /* reparse point not resolved */
2384 NTStatus = 0xC0000022L; /* Access Denied */
2387 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2388 NTStatus = 0xC0000257L; /* Path Not Covered */
2390 else if (code == CM_ERROR_ALLBUSY) {
2391 NTStatus = 0xC00000BFL; /* Network Busy */
2393 NTStatus = 0xC0982001L; /* SMB non-specific error */
2396 *NTStatusp = NTStatus;
2397 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2400 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2401 unsigned char *classp)
2403 unsigned char class;
2404 unsigned short error;
2406 /* map CM_ERROR_* errors to SMB errors */
2407 if (code == CM_ERROR_NOSUCHCELL) {
2409 error = 3; /* bad path */
2411 else if (code == CM_ERROR_NOSUCHVOLUME) {
2413 error = 3; /* bad path */
2415 else if (code == CM_ERROR_TIMEDOUT) {
2417 error = 81; /* server is paused */
2419 else if (code == CM_ERROR_RETRY) {
2420 class = 2; /* shouldn't happen */
2423 else if (code == CM_ERROR_NOACCESS) {
2425 error = 4; /* bad access */
2427 else if (code == CM_ERROR_READONLY) {
2429 error = 19; /* read only */
2431 else if (code == CM_ERROR_NOSUCHFILE) {
2433 error = 2; /* ENOENT! */
2435 else if (code == CM_ERROR_NOSUCHPATH) {
2437 error = 3; /* Bad path */
2439 else if (code == CM_ERROR_TOOBIG) {
2441 error = 11; /* bad format */
2443 else if (code == CM_ERROR_INVAL) {
2444 class = 2; /* server non-specific error code */
2447 else if (code == CM_ERROR_BADFD) {
2449 error = 6; /* invalid file handle */
2451 else if (code == CM_ERROR_BADFDOP) {
2452 class = 1; /* invalid op on FD */
2455 else if (code == CM_ERROR_EXISTS) {
2457 error = 80; /* file already exists */
2459 else if (code == CM_ERROR_NOTEMPTY) {
2461 error = 5; /* delete directory not empty */
2463 else if (code == CM_ERROR_CROSSDEVLINK) {
2465 error = 17; /* EXDEV */
2467 else if (code == CM_ERROR_NOTDIR) {
2468 class = 1; /* bad path */
2471 else if (code == CM_ERROR_ISDIR) {
2472 class = 1; /* access denied; DOS doesn't have a good match */
2475 else if (code == CM_ERROR_BADOP) {
2479 else if (code == CM_ERROR_BADSHARENAME) {
2483 else if (code == CM_ERROR_NOIPC) {
2485 error = 4; /* bad access */
2487 else if (code == CM_ERROR_CLOCKSKEW) {
2488 class = 1; /* invalid function */
2491 else if (code == CM_ERROR_BADTID) {
2495 else if (code == CM_ERROR_USESTD) {
2499 else if (code == CM_ERROR_REMOTECONN) {
2503 else if (code == CM_ERROR_QUOTA) {
2504 if (vcp->flags & SMB_VCFLAG_USEV3) {
2506 error = 39; /* disk full */
2510 error = 5; /* access denied */
2513 else if (code == CM_ERROR_SPACE) {
2514 if (vcp->flags & SMB_VCFLAG_USEV3) {
2516 error = 39; /* disk full */
2520 error = 5; /* access denied */
2523 else if (code == CM_ERROR_PARTIALWRITE) {
2525 error = 39; /* disk full */
2527 else if (code == CM_ERROR_ATSYS) {
2529 error = 2; /* ENOENT */
2531 else if (code == CM_ERROR_WOULDBLOCK) {
2533 error = 33; /* lock conflict */
2535 else if (code == CM_ERROR_NOFILES) {
2537 error = 18; /* no files in search */
2539 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2541 error = 183; /* Samba uses this */
2543 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2544 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2546 error = 2; /* bad password */
2548 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2550 error = 3; /* bad path */
2559 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2562 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2564 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2565 return CM_ERROR_BADOP;
2568 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2570 unsigned short EchoCount, i;
2571 char *data, *outdata;
2574 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2576 for (i=1; i<=EchoCount; i++) {
2577 data = smb_GetSMBData(inp, &dataSize);
2578 smb_SetSMBParm(outp, 0, i);
2579 smb_SetSMBDataLength(outp, dataSize);
2580 outdata = smb_GetSMBData(outp, NULL);
2581 memcpy(outdata, data, dataSize);
2582 smb_SendPacket(vcp, outp);
2588 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2591 long count, minCount, finalCount;
2595 cm_user_t *userp = NULL;
2599 char *rawBuf = NULL;
2601 dos_ptr rawBuf = NULL;
2608 fd = smb_GetSMBParm(inp, 0);
2609 count = smb_GetSMBParm(inp, 3);
2610 minCount = smb_GetSMBParm(inp, 4);
2611 offset.HighPart = 0; /* too bad */
2612 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2614 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2615 fd, offset.LowPart, count);
2617 fidp = smb_FindFID(vcp, fd, 0);
2621 lock_ObtainMutex(&smb_RawBufLock);
2623 /* Get a raw buf, from head of list */
2624 rawBuf = smb_RawBufs;
2626 smb_RawBufs = *(char **)smb_RawBufs;
2628 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2631 lock_ReleaseMutex(&smb_RawBufLock);
2635 if (fidp->flags & SMB_FID_IOCTL)
2638 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2640 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2643 /* Give back raw buffer */
2644 lock_ObtainMutex(&smb_RawBufLock);
2646 *((char **) rawBuf) = smb_RawBufs;
2648 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2651 smb_RawBufs = rawBuf;
2652 lock_ReleaseMutex(&smb_RawBufLock);
2655 smb_ReleaseFID(fidp);
2659 userp = smb_GetUser(vcp, inp);
2662 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2664 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2665 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2666 userp, &finalCount, TRUE /* rawFlag */);
2673 cm_ReleaseUser(userp);
2676 smb_ReleaseFID(fidp);
2681 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2683 memset((char *)ncbp, 0, sizeof(NCB));
2685 ncbp->ncb_length = (unsigned short) finalCount;
2686 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2687 ncbp->ncb_lana_num = vcp->lana;
2688 ncbp->ncb_command = NCBSEND;
2689 ncbp->ncb_buffer = rawBuf;
2692 code = Netbios(ncbp);
2694 code = Netbios(ncbp, dos_ncb);
2697 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2700 /* Give back raw buffer */
2701 lock_ObtainMutex(&smb_RawBufLock);
2703 *((char **) rawBuf) = smb_RawBufs;
2705 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2708 smb_RawBufs = rawBuf;
2709 lock_ReleaseMutex(&smb_RawBufLock);
2715 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2717 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2722 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2724 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2729 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2736 int protoIndex; /* index we're using */
2741 char protocol_array[10][1024]; /* protocol signature of the client */
2742 int caps; /* capabilities */
2745 TIME_ZONE_INFORMATION tzi;
2747 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2751 DWORD now = GetCurrentTime();
2752 if (now - last_msg_time >= 30000
2753 && now - last_msg_time <= 90000) {
2755 "Setting dead_vcp %x", active_vcp);
2757 smb_ReleaseVC(dead_vcp);
2759 "Previous dead_vcp %x", dead_vcp);
2761 smb_HoldVC(active_vcp);
2762 dead_vcp = active_vcp;
2763 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2768 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2770 namep = smb_GetSMBData(inp, &dbytes);
2773 coreProtoIndex = -1; /* not found */
2776 while(namex < dbytes) {
2777 osi_Log1(smb_logp, "Protocol %s",
2778 osi_LogSaveString(smb_logp, namep+1));
2779 strcpy(protocol_array[tcounter], namep+1);
2781 /* namep points at the first protocol, or really, a 0x02
2782 * byte preceding the null-terminated ASCII name.
2784 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2785 coreProtoIndex = tcounter;
2787 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2788 v3ProtoIndex = tcounter;
2790 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2791 NTProtoIndex = tcounter;
2794 /* compute size of protocol entry */
2795 entryLength = strlen(namep+1);
2796 entryLength += 2; /* 0x02 bytes and null termination */
2798 /* advance over this protocol entry */
2799 namex += entryLength;
2800 namep += entryLength;
2801 tcounter++; /* which proto entry we're looking at */
2804 if (NTProtoIndex != -1) {
2805 protoIndex = NTProtoIndex;
2806 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2808 else if (v3ProtoIndex != -1) {
2809 protoIndex = v3ProtoIndex;
2810 vcp->flags |= SMB_VCFLAG_USEV3;
2812 else if (coreProtoIndex != -1) {
2813 protoIndex = coreProtoIndex;
2814 vcp->flags |= SMB_VCFLAG_USECORE;
2816 else protoIndex = -1;
2818 if (protoIndex == -1)
2819 return CM_ERROR_INVAL;
2820 else if (NTProtoIndex != -1) {
2821 smb_SetSMBParm(outp, 0, protoIndex);
2822 if (smb_authType != SMB_AUTH_NONE) {
2823 smb_SetSMBParmByte(outp, 1,
2824 NEGOTIATE_SECURITY_USER_LEVEL |
2825 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2827 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2829 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2830 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2831 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2832 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2833 /* The session key is not a well documented field however most clients
2834 * will echo back the session key to the server. Currently we are using
2835 * the same value for all sessions. We should generate a random value
2836 * and store it into the vcp
2838 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2839 smb_SetSMBParm(outp, 8, 1);
2841 * Tried changing the capabilities to support for W2K - defect 117695
2842 * Maybe something else needs to be changed here?
2846 smb_SetSMBParmLong(outp, 9, 0x43fd);
2848 smb_SetSMBParmLong(outp, 9, 0x251);
2851 * 32-bit error codes *
2856 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2858 NTNEGOTIATE_CAPABILITY_DFS |
2860 NTNEGOTIATE_CAPABILITY_NTFIND |
2861 NTNEGOTIATE_CAPABILITY_RAWMODE |
2862 NTNEGOTIATE_CAPABILITY_NTSMB;
2864 if ( smb_authType == SMB_AUTH_EXTENDED )
2865 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2867 smb_SetSMBParmLong(outp, 9, caps);
2869 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2870 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2871 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2873 GetTimeZoneInformation(&tzi);
2874 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2876 if (smb_authType == SMB_AUTH_NTLM) {
2877 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2878 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2879 /* paste in encryption key */
2880 datap = smb_GetSMBData(outp, NULL);
2881 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2882 /* and the faux domain name */
2883 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2884 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2888 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2890 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2892 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2894 datap = smb_GetSMBData(outp, NULL);
2895 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2898 datap += sizeof(smb_ServerGUID);
2899 memcpy(datap, secBlob, secBlobLength);
2903 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2904 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2907 else if (v3ProtoIndex != -1) {
2908 smb_SetSMBParm(outp, 0, protoIndex);
2910 /* NOTE: Extended authentication cannot be negotiated with v3
2911 * therefore we fail over to NTLM
2913 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2914 smb_SetSMBParm(outp, 1,
2915 NEGOTIATE_SECURITY_USER_LEVEL |
2916 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2918 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2920 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2921 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2922 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2923 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2924 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2925 smb_SetSMBParm(outp, 7, 1);
2927 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2928 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2929 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2931 GetTimeZoneInformation(&tzi);
2932 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2934 /* NOTE: Extended authentication cannot be negotiated with v3
2935 * therefore we fail over to NTLM
2937 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2938 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2939 smb_SetSMBParm(outp, 12, 0); /* resvd */
2940 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2941 datap = smb_GetSMBData(outp, NULL);
2942 /* paste in a new encryption key */
2943 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2944 /* and the faux domain name */
2945 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2947 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2948 smb_SetSMBParm(outp, 12, 0); /* resvd */
2949 smb_SetSMBDataLength(outp, 0);
2952 else if (coreProtoIndex != -1) { /* not really supported anymore */
2953 smb_SetSMBParm(outp, 0, protoIndex);
2954 smb_SetSMBDataLength(outp, 0);
2959 void smb_Daemon(void *parmp)
2961 afs_uint32 count = 0;
2963 while(smbShutdownFlag == 0) {
2967 if (smbShutdownFlag == 1)
2970 if ((count % 72) == 0) { /* every five minutes */
2972 time_t old_localZero = smb_localZero;
2974 /* Initialize smb_localZero */
2975 myTime.tm_isdst = -1; /* compute whether on DST or not */
2976 myTime.tm_year = 70;
2982 smb_localZero = mktime(&myTime);
2984 #ifndef USE_NUMERIC_TIME_CONV
2985 smb_CalculateNowTZ();
2986 #endif /* USE_NUMERIC_TIME_CONV */
2987 #ifdef AFS_FREELANCE
2988 if ( smb_localZero != old_localZero )
2989 cm_noteLocalMountPointChange();
2992 /* XXX GC dir search entries */
2996 void smb_WaitingLocksDaemon()
2998 smb_waitingLock_t *wL, *nwL;
3001 smb_packet_t *inp, *outp;
3005 while (smbShutdownFlag == 0) {
3006 lock_ObtainWrite(&smb_globalLock);
3007 nwL = smb_allWaitingLocks;
3009 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
3019 lock_ObtainWrite(&smb_globalLock);
3021 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
3022 lock_ReleaseWrite(&smb_globalLock);
3023 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
3024 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
3025 if (code == CM_ERROR_WOULDBLOCK) {
3027 if (wL->timeRemaining != 0xffffffff
3028 && (wL->timeRemaining -= 1000) < 0)
3038 ncbp->ncb_length = inp->ncb_length;
3039 inp->spacep = cm_GetSpace();
3041 /* Remove waitingLock from list */
3042 lock_ObtainWrite(&smb_globalLock);
3043 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3045 lock_ReleaseWrite(&smb_globalLock);
3047 /* Resume packet processing */
3049 smb_SetSMBDataLength(outp, 0);
3050 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3051 outp->resumeCode = code;
3053 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3056 cm_FreeSpace(inp->spacep);
3057 smb_FreePacket(inp);
3058 smb_FreePacket(outp);
3062 } while (nwL && smbShutdownFlag == 0);
3067 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3069 osi_Log0(smb_logp, "SMB receive get disk attributes");
3071 smb_SetSMBParm(outp, 0, 32000);
3072 smb_SetSMBParm(outp, 1, 64);
3073 smb_SetSMBParm(outp, 2, 1024);
3074 smb_SetSMBParm(outp, 3, 30000);
3075 smb_SetSMBParm(outp, 4, 0);
3076 smb_SetSMBDataLength(outp, 0);
3080 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3084 unsigned short newTid;
3085 char shareName[256];
3093 osi_Log0(smb_logp, "SMB receive tree connect");
3095 /* parse input parameters */
3096 tp = smb_GetSMBData(inp, NULL);
3097 pathp = smb_ParseASCIIBlock(tp, &tp);
3098 if (smb_StoreAnsiFilenames)
3099 OemToChar(pathp,pathp);
3100 passwordp = smb_ParseASCIIBlock(tp, &tp);
3101 tp = strrchr(pathp, '\\');
3103 return CM_ERROR_BADSMB;
3104 strcpy(shareName, tp+1);
3106 userp = smb_GetUser(vcp, inp);
3108 lock_ObtainMutex(&vcp->mx);
3109 newTid = vcp->tidCounter++;
3110 lock_ReleaseMutex(&vcp->mx);
3112 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3113 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3114 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3116 smb_ReleaseUID(uidp);
3118 smb_ReleaseTID(tidp);
3119 return CM_ERROR_BADSHARENAME;
3121 lock_ObtainMutex(&tidp->mx);
3122 tidp->userp = userp;
3123 tidp->pathname = sharePath;
3124 lock_ReleaseMutex(&tidp->mx);
3125 smb_ReleaseTID(tidp);
3127 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3128 smb_SetSMBParm(rsp, 1, newTid);
3129 smb_SetSMBDataLength(rsp, 0);
3131 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3135 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3139 if (*inp++ != 0x1) return NULL;
3140 tlen = inp[0] + (inp[1]<<8);
3141 inp += 2; /* skip length field */
3144 *chainpp = inp + tlen;
3147 if (lengthp) *lengthp = tlen;
3152 /* set maskp to the mask part of the incoming path.
3153 * Mask is 11 bytes long (8.3 with the dot elided).
3154 * Returns true if succeeds with a valid name, otherwise it does
3155 * its best, but returns false.
3157 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3165 /* starts off valid */
3168 /* mask starts out all blanks */
3169 memset(maskp, ' ', 11);
3171 /* find last backslash, or use whole thing if there is none */
3172 tp = strrchr(pathp, '\\');
3173 if (!tp) tp = pathp;
3174 else tp++; /* skip slash */
3178 /* names starting with a dot are illegal */
3179 if (*tp == '.') valid8Dot3 = 0;
3183 if (tc == 0) return valid8Dot3;
3184 if (tc == '.' || tc == '"') break;
3185 if (i < 8) *up++ = tc;
3186 else valid8Dot3 = 0;
3189 /* if we get here, tp point after the dot */
3190 up = maskp+8; /* ext goes here */
3197 if (tc == '.' || tc == '"')
3200 /* copy extension if not too long */
3210 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3220 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3222 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3226 /* otherwise, we have a valid 8.3 name; see if we have a match,
3227 * treating '?' as a wildcard in maskp (but not in the file name).
3229 tp1 = umask; /* real name, in mask format */
3230 tp2 = maskp; /* mask, in mask format */
3231 for(i=0; i<11; i++) {
3232 tc1 = *tp1++; /* char from real name */
3233 tc2 = *tp2++; /* char from mask */
3234 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3235 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3238 if (tc2 == '?' && tc1 != ' ')
3245 /* we got a match */
3249 char *smb_FindMask(char *pathp)
3253 tp = strrchr(pathp, '\\'); /* find last slash */
3256 return tp+1; /* skip the slash */
3258 return pathp; /* no slash, return the entire path */
3261 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3263 unsigned char *pathp;
3265 unsigned char mask[11];
3266 unsigned char *statBlockp;
3267 unsigned char initStatBlock[21];
3270 osi_Log0(smb_logp, "SMB receive search volume");
3272 /* pull pathname and stat block out of request */
3273 tp = smb_GetSMBData(inp, NULL);
3274 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3275 osi_assert(pathp != NULL);
3276 if (smb_StoreAnsiFilenames)
3277 OemToChar(pathp,pathp);
3278 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3279 osi_assert(statBlockp != NULL);
3281 statBlockp = initStatBlock;
3285 /* for returning to caller */
3286 smb_Get8Dot3MaskFromPath(mask, pathp);
3288 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3289 tp = smb_GetSMBData(outp, NULL);
3291 *tp++ = 43; /* bytes in a dir entry */
3292 *tp++ = 0; /* high byte in counter */
3294 /* now marshall the dir entry, starting with the search status */
3295 *tp++ = statBlockp[0]; /* Reserved */
3296 memcpy(tp, mask, 11); tp += 11; /* FileName */
3298 /* now pass back server use info, with 1st byte non-zero */
3300 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3302 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3304 *tp++ = 0x8; /* attribute: volume */
3314 /* 4 byte file size */
3320 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3321 memset(tp, ' ', 13);
3324 /* set the length of the data part of the packet to 43 + 3, for the dir
3325 * entry plus the 5 and the length fields.
3327 smb_SetSMBDataLength(outp, 46);
3331 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3332 cm_user_t *userp, cm_req_t *reqp)
3340 smb_dirListPatch_t *patchp;
3341 smb_dirListPatch_t *npatchp;
3343 for (patchp = *dirPatchespp; patchp; patchp =
3344 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3346 dptr = patchp->dptr;
3348 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3350 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3351 *dptr++ = SMB_ATTR_HIDDEN;
3354 lock_ObtainMutex(&scp->mx);
3355 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3356 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3358 lock_ReleaseMutex(&scp->mx);
3359 cm_ReleaseSCache(scp);
3360 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3361 *dptr++ = SMB_ATTR_HIDDEN;
3365 attr = smb_Attributes(scp);
3366 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3367 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3368 attr |= SMB_ATTR_HIDDEN;
3372 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3375 shortTemp = (unsigned short) (dosTime & 0xffff);
3376 *((u_short *)dptr) = shortTemp;
3379 /* and copy out date */
3380 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3381 *((u_short *)dptr) = shortTemp;
3384 /* copy out file length */
3385 *((u_long *)dptr) = scp->length.LowPart;
3387 lock_ReleaseMutex(&scp->mx);
3388 cm_ReleaseSCache(scp);
3391 /* now free the patches */
3392 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3393 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3397 /* and mark the list as empty */
3398 *dirPatchespp = NULL;
3403 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3412 smb_dirListPatch_t *dirListPatchesp;
3413 smb_dirListPatch_t *curPatchp;
3417 osi_hyper_t dirLength;
3418 osi_hyper_t bufferOffset;
3419 osi_hyper_t curOffset;
3421 unsigned char *inCookiep;
3422 smb_dirSearch_t *dsp;
3426 unsigned long clientCookie;
3427 cm_pageHeader_t *pageHeaderp;
3428 cm_user_t *userp = NULL;
3435 long nextEntryCookie;
3436 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3437 char resByte; /* reserved byte from the cookie */
3438 char *op; /* output data ptr */
3439 char *origOp; /* original value of op */
3440 cm_space_t *spacep; /* for pathname buffer */
3451 maxCount = smb_GetSMBParm(inp, 0);
3453 dirListPatchesp = NULL;
3455 caseFold = CM_FLAG_CASEFOLD;
3457 tp = smb_GetSMBData(inp, NULL);
3458 pathp = smb_ParseASCIIBlock(tp, &tp);
3459 if (smb_StoreAnsiFilenames)
3460 OemToChar(pathp,pathp);
3461 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3463 /* bail out if request looks bad */
3464 if (!tp || !pathp) {
3465 return CM_ERROR_BADSMB;
3468 /* We can handle long names */
3469 if (vcp->flags & SMB_VCFLAG_USENT)
3470 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3472 /* make sure we got a whole search status */
3473 if (dataLength < 21) {
3474 nextCookie = 0; /* start at the beginning of the dir */
3477 attribute = smb_GetSMBParm(inp, 1);
3479 /* handle volume info in another function */
3480 if (attribute & 0x8)
3481 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3483 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3484 maxCount, osi_LogSaveString(smb_logp, pathp));
3486 if (*pathp == 0) { /* null pathp, treat as root dir */
3487 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3488 return CM_ERROR_NOFILES;
3492 dsp = smb_NewDirSearch(0);
3493 dsp->attribute = attribute;
3494 smb_Get8Dot3MaskFromPath(mask, pathp);
3495 memcpy(dsp->mask, mask, 11);
3497 /* track if this is likely to match a lot of entries */
3498 if (smb_IsStarMask(mask))
3503 /* pull the next cookie value out of the search status block */
3504 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3505 + (inCookiep[16]<<24);
3506 dsp = smb_FindDirSearch(inCookiep[12]);
3508 /* can't find dir search status; fatal error */
3509 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3510 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3511 return CM_ERROR_BADFD;
3513 attribute = dsp->attribute;
3514 resByte = inCookiep[0];
3516 /* copy out client cookie, in host byte order. Don't bother
3517 * interpreting it, since we're just passing it through, anyway.
3519 memcpy(&clientCookie, &inCookiep[17], 4);
3521 memcpy(mask, dsp->mask, 11);
3523 /* assume we're doing a star match if it has continued for more
3529 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3530 nextCookie, dsp->cookie, attribute);
3532 userp = smb_GetUser(vcp, inp);
3534 /* try to get the vnode for the path name next */
3535 lock_ObtainMutex(&dsp->mx);
3541 spacep = inp->spacep;
3542 smb_StripLastComponent(spacep->data, NULL, pathp);
3543 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3545 lock_ReleaseMutex(&dsp->mx);
3546 cm_ReleaseUser(userp);
3547 smb_DeleteDirSearch(dsp);
3548 smb_ReleaseDirSearch(dsp);
3549 return CM_ERROR_NOFILES;
3551 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3552 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3555 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3556 cm_ReleaseSCache(scp);
3557 lock_ReleaseMutex(&dsp->mx);
3558 cm_ReleaseUser(userp);
3559 smb_DeleteDirSearch(dsp);
3560 smb_ReleaseDirSearch(dsp);
3561 if ( WANTS_DFS_PATHNAMES(inp) )
3562 return CM_ERROR_PATH_NOT_COVERED;
3564 return CM_ERROR_BADSHARENAME;
3566 #endif /* DFS_SUPPORT */
3569 /* we need one hold for the entry we just stored into,
3570 * and one for our own processing. When we're done with this
3571 * function, we'll drop the one for our own processing.
3572 * We held it once from the namei call, and so we do another hold
3576 lock_ObtainMutex(&scp->mx);
3577 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3578 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3579 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3580 dsp->flags |= SMB_DIRSEARCH_BULKST;
3582 lock_ReleaseMutex(&scp->mx);
3585 lock_ReleaseMutex(&dsp->mx);
3587 cm_ReleaseUser(userp);
3588 smb_DeleteDirSearch(dsp);
3589 smb_ReleaseDirSearch(dsp);
3593 /* reserves space for parameter; we'll adjust it again later to the
3594 * real count of the # of entries we returned once we've actually
3595 * assembled the directory listing.
3597 smb_SetSMBParm(outp, 0, 0);
3599 /* get the directory size */
3600 lock_ObtainMutex(&scp->mx);
3601 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3602 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3604 lock_ReleaseMutex(&scp->mx);
3605 cm_ReleaseSCache(scp);
3606 cm_ReleaseUser(userp);
3607 smb_DeleteDirSearch(dsp);
3608 smb_ReleaseDirSearch(dsp);
3612 dirLength = scp->length;
3614 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3615 curOffset.HighPart = 0;
3616 curOffset.LowPart = nextCookie;
3617 origOp = op = smb_GetSMBData(outp, NULL);
3618 /* and write out the basic header */
3619 *op++ = 5; /* variable block */
3620 op += 2; /* skip vbl block length; we'll fill it in later */
3624 /* make sure that curOffset.LowPart doesn't point to the first
3625 * 32 bytes in the 2nd through last dir page, and that it doesn't
3626 * point at the first 13 32-byte chunks in the first dir page,
3627 * since those are dir and page headers, and don't contain useful
3630 temp = curOffset.LowPart & (2048-1);
3631 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3632 /* we're in the first page */
3633 if (temp < 13*32) temp = 13*32;
3636 /* we're in a later dir page */
3637 if (temp < 32) temp = 32;
3640 /* make sure the low order 5 bits are zero */
3643 /* now put temp bits back ito curOffset.LowPart */
3644 curOffset.LowPart &= ~(2048-1);
3645 curOffset.LowPart |= temp;
3647 /* check if we've returned all the names that will fit in the
3650 if (returnedNames >= maxCount) {
3651 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3652 returnedNames, maxCount);
3656 /* check if we've passed the dir's EOF */
3657 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3659 /* see if we can use the bufferp we have now; compute in which page
3660 * the current offset would be, and check whether that's the offset
3661 * of the buffer we have. If not, get the buffer.
3663 thyper.HighPart = curOffset.HighPart;
3664 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3665 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3668 buf_Release(bufferp);
3671 lock_ReleaseMutex(&scp->mx);
3672 lock_ObtainRead(&scp->bufCreateLock);
3673 code = buf_Get(scp, &thyper, &bufferp);
3674 lock_ReleaseRead(&scp->bufCreateLock);
3675 lock_ObtainMutex(&dsp->mx);
3677 /* now, if we're doing a star match, do bulk fetching of all of
3678 * the status info for files in the dir.
3681 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3682 lock_ObtainMutex(&scp->mx);
3683 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3684 LargeIntegerGreaterThanOrEqualTo(thyper,
3685 scp->bulkStatProgress)) {
3686 /* Don't bulk stat if risking timeout */
3687 int now = GetCurrentTime();
3688 if (now - req.startTime > 5000) {
3689 scp->bulkStatProgress = thyper;
3690 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3691 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3693 cm_TryBulkStat(scp, &thyper, userp, &req);
3696 lock_ObtainMutex(&scp->mx);
3698 lock_ReleaseMutex(&dsp->mx);
3700 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3704 bufferOffset = thyper;
3706 /* now get the data in the cache */
3708 code = cm_SyncOp(scp, bufferp, userp, &req,
3710 CM_SCACHESYNC_NEEDCALLBACK |
3711 CM_SCACHESYNC_READ);
3713 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3717 if (cm_HaveBuffer(scp, bufferp, 0)) {
3718 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3722 /* otherwise, load the buffer and try again */
3723 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3725 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3726 scp, bufferp, code);
3731 buf_Release(bufferp);
3735 } /* if (wrong buffer) ... */
3737 /* now we have the buffer containing the entry we're interested in; copy