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 */
1684 cm_ReleaseSCache(scp);
1687 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1689 lock_ObtainWrite(&smb_globalLock);
1690 smb_ReleaseDirSearchNoLock(dsp);
1691 lock_ReleaseWrite(&smb_globalLock);
1694 /* find a dir search structure by cookie value, and return it held */
1695 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1697 smb_dirSearch_t *dsp;
1699 lock_ObtainWrite(&smb_globalLock);
1700 dsp = smb_FindDirSearchNoLock(cookie);
1701 lock_ReleaseWrite(&smb_globalLock);
1705 /* GC some dir search entries, in the address space expected by the specific protocol.
1706 * Must be called with smb_globalLock held; release the lock temporarily.
1708 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1709 void smb_GCDirSearches(int isV3)
1711 smb_dirSearch_t *prevp;
1712 smb_dirSearch_t *tp;
1713 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1717 victimCount = 0; /* how many have we got so far */
1718 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1719 /* we'll move tp from queue, so
1722 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1723 /* if no one is using this guy, and we're either in the new protocol,
1724 * or we're in the old one and this is a small enough ID to be useful
1725 * to the old protocol, GC this guy.
1727 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1728 /* hold and delete */
1729 tp->flags |= SMB_DIRSEARCH_DELETE;
1730 victimsp[victimCount++] = tp;
1734 /* don't do more than this */
1735 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1739 /* now release them */
1740 for (i = 0; i < victimCount; i++) {
1741 smb_ReleaseDirSearchNoLock(victimsp[i]);
1745 /* function for allocating a dir search entry. We need these to remember enough context
1746 * since we don't get passed the path from call to call during a directory search.
1748 * Returns a held dir search structure, and bumps the reference count on the vnode,
1749 * since it saves a pointer to the vnode.
1751 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1753 smb_dirSearch_t *dsp;
1759 lock_ObtainWrite(&smb_globalLock);
1762 /* what's the biggest ID allowed in this version of the protocol */
1763 maxAllowed = isV3 ? 65535 : 255;
1764 if (smb_dirSearchCounter > maxAllowed)
1765 smb_dirSearchCounter = 1;
1767 start = smb_dirSearchCounter;
1770 /* twice so we have enough tries to find guys we GC after one pass;
1771 * 10 extra is just in case I mis-counted.
1773 if (++counter > 2*maxAllowed+10)
1774 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1776 if (smb_dirSearchCounter > maxAllowed) {
1777 smb_dirSearchCounter = 1;
1779 if (smb_dirSearchCounter == start) {
1781 smb_GCDirSearches(isV3);
1784 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1786 /* don't need to watch for refcount zero and deleted, since
1787 * we haven't dropped the global lock.
1789 lock_ObtainMutex(&dsp->mx);
1791 lock_ReleaseMutex(&dsp->mx);
1792 ++smb_dirSearchCounter;
1796 dsp = malloc(sizeof(*dsp));
1797 memset(dsp, 0, sizeof(*dsp));
1798 dsp->cookie = smb_dirSearchCounter;
1799 ++smb_dirSearchCounter;
1801 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1802 dsp->lastTime = osi_Time();
1803 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1804 if (!smb_lastDirSearchp)
1805 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1808 lock_ReleaseWrite(&smb_globalLock);
1812 static smb_packet_t *GetPacket(void)
1816 unsigned int npar, seg, tb_sel;
1819 lock_ObtainWrite(&smb_globalLock);
1820 tbp = smb_packetFreeListp;
1822 smb_packetFreeListp = tbp->nextp;
1823 lock_ReleaseWrite(&smb_globalLock);
1826 tbp = calloc(65540,1);
1828 tbp = malloc(sizeof(smb_packet_t));
1830 tbp->magic = SMB_PACKETMAGIC;
1833 tbp->resumeCode = 0;
1839 tbp->ncb_length = 0;
1844 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1847 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1849 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1851 osi_panic("",__FILE__,__LINE__);
1854 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1859 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1860 tbp->dos_pkt_sel = tb_sel;
1863 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1868 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1872 memcpy(tbp, pkt, sizeof(smb_packet_t));
1873 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1875 smb_HoldVC(tbp->vcp);
1879 static NCB *GetNCB(void)
1884 unsigned int npar, seg, tb_sel;
1887 lock_ObtainWrite(&smb_globalLock);
1888 tbp = smb_ncbFreeListp;
1890 smb_ncbFreeListp = tbp->nextp;
1891 lock_ReleaseWrite(&smb_globalLock);
1894 tbp = calloc(sizeof(*tbp),1);
1896 tbp = malloc(sizeof(*tbp));
1897 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1900 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1902 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1904 osi_panic("",__FILE__,__LINE__);
1906 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1911 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1912 tbp->dos_ncb_sel = tb_sel;
1914 tbp->magic = SMB_NCBMAGIC;
1917 osi_assert(tbp->magic == SMB_NCBMAGIC);
1919 memset(&tbp->ncb, 0, sizeof(NCB));
1922 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1927 void smb_FreePacket(smb_packet_t *tbp)
1929 smb_vc_t * vcp = NULL;
1930 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1932 lock_ObtainWrite(&smb_globalLock);
1933 tbp->nextp = smb_packetFreeListp;
1934 smb_packetFreeListp = tbp;
1935 tbp->magic = SMB_PACKETMAGIC;
1939 tbp->resumeCode = 0;
1945 tbp->ncb_length = 0;
1947 lock_ReleaseWrite(&smb_globalLock);
1953 static void FreeNCB(NCB *bufferp)
1957 tbp = (smb_ncb_t *) bufferp;
1958 osi_assert(tbp->magic == SMB_NCBMAGIC);
1960 lock_ObtainWrite(&smb_globalLock);
1961 tbp->nextp = smb_ncbFreeListp;
1962 smb_ncbFreeListp = tbp;
1963 lock_ReleaseWrite(&smb_globalLock);
1966 /* get a ptr to the data part of a packet, and its count */
1967 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1971 unsigned char *afterParmsp;
1973 parmBytes = *smbp->wctp << 1;
1974 afterParmsp = smbp->wctp + parmBytes + 1;
1976 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1977 if (nbytesp) *nbytesp = dataBytes;
1979 /* don't forget to skip the data byte count, since it follows
1980 * the parameters; that's where the "2" comes from below.
1982 return (unsigned char *) (afterParmsp + 2);
1985 /* must set all the returned parameters before playing around with the
1986 * data region, since the data region is located past the end of the
1987 * variable number of parameters.
1989 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1991 unsigned char *afterParmsp;
1993 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1995 *afterParmsp++ = dsize & 0xff;
1996 *afterParmsp = (dsize>>8) & 0xff;
1999 /* return the parm'th parameter in the smbp packet */
2000 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2003 unsigned char *parmDatap;
2005 parmCount = *smbp->wctp;
2007 if (parm >= parmCount) {
2012 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2014 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2015 parm, parmCount, smbp->ncb_length);
2018 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2019 1, smbp->ncb_length, ptbuf, smbp);
2020 DeregisterEventSource(h);
2022 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2023 parm, parmCount, smbp->ncb_length);
2024 osi_panic(s, __FILE__, __LINE__);
2026 parmDatap = smbp->wctp + (2*parm) + 1;
2028 return parmDatap[0] + (parmDatap[1] << 8);
2031 /* return the parm'th parameter in the smbp packet */
2032 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2035 unsigned char *parmDatap;
2037 parmCount = *smbp->wctp;
2039 if (parm * 2 + offset >= parmCount * 2) {
2044 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2046 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2047 parm, offset, parmCount, smbp->ncb_length);
2050 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2051 1, smbp->ncb_length, ptbuf, smbp);
2052 DeregisterEventSource(h);
2054 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2055 parm, offset, parmCount, smbp->ncb_length);
2056 osi_panic(s, __FILE__, __LINE__);
2058 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2060 return parmDatap[0] + (parmDatap[1] << 8);
2063 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2067 /* make sure we have enough slots */
2068 if (*smbp->wctp <= slot)
2069 *smbp->wctp = slot+1;
2071 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2072 *parmDatap++ = parmValue & 0xff;
2073 *parmDatap = (parmValue>>8) & 0xff;
2076 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2080 /* make sure we have enough slots */
2081 if (*smbp->wctp <= slot)
2082 *smbp->wctp = slot+2;
2084 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2085 *parmDatap++ = parmValue & 0xff;
2086 *parmDatap++ = (parmValue>>8) & 0xff;
2087 *parmDatap++ = (parmValue>>16) & 0xff;
2088 *parmDatap++ = (parmValue>>24) & 0xff;
2091 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2096 /* make sure we have enough slots */
2097 if (*smbp->wctp <= slot)
2098 *smbp->wctp = slot+4;
2100 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2102 *parmDatap++ = *parmValuep++;
2105 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2109 /* make sure we have enough slots */
2110 if (*smbp->wctp <= slot) {
2111 if (smbp->oddByte) {
2113 *smbp->wctp = slot+1;
2118 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2119 *parmDatap++ = parmValue & 0xff;
2122 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2126 lastSlashp = strrchr(inPathp, '\\');
2128 *lastComponentp = lastSlashp;
2131 if (inPathp == lastSlashp)
2133 *outPathp++ = *inPathp++;
2142 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2147 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2152 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2158 tlen = inp[0] + (inp[1]<<8);
2159 inp += 2; /* skip length field */
2162 *chainpp = inp + tlen;
2171 /* format a packet as a response */
2172 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2177 outp = (smb_t *) op;
2179 /* zero the basic structure through the smb_wct field, and zero the data
2180 * size field, assuming that wct stays zero; otherwise, you have to
2181 * explicitly set the data size field, too.
2183 inSmbp = (smb_t *) inp;
2184 memset(outp, 0, sizeof(smb_t)+2);
2190 outp->com = inSmbp->com;
2191 outp->tid = inSmbp->tid;
2192 outp->pid = inSmbp->pid;
2193 outp->uid = inSmbp->uid;
2194 outp->mid = inSmbp->mid;
2195 outp->res[0] = inSmbp->res[0];
2196 outp->res[1] = inSmbp->res[1];
2197 op->inCom = inSmbp->com;
2199 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2200 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2202 /* copy fields in generic packet area */
2203 op->wctp = &outp->wct;
2206 /* send a (probably response) packet; vcp tells us to whom to send it.
2207 * we compute the length by looking at wct and bcc fields.
2209 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2226 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2229 memset((char *)ncbp, 0, sizeof(NCB));
2231 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2232 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2233 extra += tp[0] + (tp[1]<<8);
2234 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2235 extra += 3; /* wct and length fields */
2237 ncbp->ncb_length = extra; /* bytes to send */
2238 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2239 ncbp->ncb_lana_num = vcp->lana;
2240 ncbp->ncb_command = NCBSEND; /* op means send data */
2242 ncbp->ncb_buffer = (char *) inp;/* packet */
2243 code = Netbios(ncbp);
2245 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2246 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2248 /* copy header information from virtual to DOS address space */
2249 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2250 code = Netbios(ncbp, dos_ncb);
2256 case 0x01: s = "llegal buffer length "; break;
2257 case 0x03: s = "illegal command "; break;
2258 case 0x05: s = "command timed out "; break;
2259 case 0x06: s = "message incomplete, issue another command"; break;
2260 case 0x07: s = "illegal buffer address "; break;
2261 case 0x08: s = "session number out of range "; break;
2262 case 0x09: s = "no resource available "; break;
2263 case 0x0a: s = "session closed "; break;
2264 case 0x0b: s = "command cancelled "; break;
2265 case 0x0d: s = "duplicate name "; break;
2266 case 0x0e: s = "name table full "; break;
2267 case 0x0f: s = "no deletions, name has active sessions "; break;
2268 case 0x11: s = "local session table full "; break;
2269 case 0x12: s = "remote session table full "; break;
2270 case 0x13: s = "illegal name number "; break;
2271 case 0x14: s = "no callname "; break;
2272 case 0x15: s = "cannot put * in NCB_NAME "; break;
2273 case 0x16: s = "name in use on remote adapter "; break;
2274 case 0x17: s = "name deleted "; break;
2275 case 0x18: s = "session ended abnormally "; break;
2276 case 0x19: s = "name conflict detected "; break;
2277 case 0x21: s = "interface busy, IRET before retrying "; break;
2278 case 0x22: s = "too many commands outstanding, retry later"; break;
2279 case 0x23: s = "ncb_lana_num field invalid "; break;
2280 case 0x24: s = "command completed while cancel occurring "; break;
2281 case 0x26: s = "command not valid to cancel "; break;
2282 case 0x30: s = "name defined by anther local process "; break;
2283 case 0x34: s = "environment undefined. RESET required "; break;
2284 case 0x35: s = "required OS resources exhausted "; break;
2285 case 0x36: s = "max number of applications exceeded "; break;
2286 case 0x37: s = "no saps available for netbios "; break;
2287 case 0x38: s = "requested resources are not available "; break;
2288 case 0x39: s = "invalid ncb address or length > segment "; break;
2289 case 0x3B: s = "invalid NCB DDID "; break;
2290 case 0x3C: s = "lock of user area failed "; break;
2291 case 0x3f: s = "NETBIOS not loaded "; break;
2292 case 0x40: s = "system error "; break;
2294 s = "unknown error";
2296 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2303 void smb_MapNTError(long code, unsigned long *NTStatusp)
2305 unsigned long NTStatus;
2307 /* map CM_ERROR_* errors to NT 32-bit status codes */
2308 /* NT Status codes are listed in ntstatus.h not winerror.h */
2309 if (code == CM_ERROR_NOSUCHCELL) {
2310 NTStatus = 0xC000000FL; /* No such file */
2312 else if (code == CM_ERROR_NOSUCHVOLUME) {
2313 NTStatus = 0xC000000FL; /* No such file */
2315 else if (code == CM_ERROR_TIMEDOUT) {
2317 NTStatus = 0xC00000CFL; /* Sharing Paused */
2319 NTStatus = 0x00000102L; /* Timeout */
2322 else if (code == CM_ERROR_RETRY) {
2323 NTStatus = 0xC000022DL; /* Retry */
2325 else if (code == CM_ERROR_NOACCESS) {
2326 NTStatus = 0xC0000022L; /* Access denied */
2328 else if (code == CM_ERROR_READONLY) {
2329 NTStatus = 0xC00000A2L; /* Write protected */
2331 else if (code == CM_ERROR_NOSUCHFILE) {
2332 NTStatus = 0xC000000FL; /* No such file */
2334 else if (code == CM_ERROR_NOSUCHPATH) {
2335 NTStatus = 0xC000003AL; /* Object path not found */
2337 else if (code == CM_ERROR_TOOBIG) {
2338 NTStatus = 0xC000007BL; /* Invalid image format */
2340 else if (code == CM_ERROR_INVAL) {
2341 NTStatus = 0xC000000DL; /* Invalid parameter */
2343 else if (code == CM_ERROR_BADFD) {
2344 NTStatus = 0xC0000008L; /* Invalid handle */
2346 else if (code == CM_ERROR_BADFDOP) {
2347 NTStatus = 0xC0000022L; /* Access denied */
2349 else if (code == CM_ERROR_EXISTS) {
2350 NTStatus = 0xC0000035L; /* Object name collision */
2352 else if (code == CM_ERROR_NOTEMPTY) {
2353 NTStatus = 0xC0000101L; /* Directory not empty */
2355 else if (code == CM_ERROR_CROSSDEVLINK) {
2356 NTStatus = 0xC00000D4L; /* Not same device */
2358 else if (code == CM_ERROR_NOTDIR) {
2359 NTStatus = 0xC0000103L; /* Not a directory */
2361 else if (code == CM_ERROR_ISDIR) {
2362 NTStatus = 0xC00000BAL; /* File is a directory */
2364 else if (code == CM_ERROR_BADOP) {
2366 /* I have no idea where this comes from */
2367 NTStatus = 0xC09820FFL; /* SMB no support */
2369 NTStatus = 0xC00000BBL; /* Not supported */
2370 #endif /* COMMENT */
2372 else if (code == CM_ERROR_BADSHARENAME) {
2373 NTStatus = 0xC00000CCL; /* Bad network name */
2375 else if (code == CM_ERROR_NOIPC) {
2377 NTStatus = 0xC0000022L; /* Access Denied */
2379 NTStatus = 0xC000013DL; /* Remote Resources */
2382 else if (code == CM_ERROR_CLOCKSKEW) {
2383 NTStatus = 0xC0000133L; /* Time difference at DC */
2385 else if (code == CM_ERROR_BADTID) {
2386 NTStatus = 0xC0982005L; /* SMB bad TID */
2388 else if (code == CM_ERROR_USESTD) {
2389 NTStatus = 0xC09820FBL; /* SMB use standard */
2391 else if (code == CM_ERROR_QUOTA) {
2393 NTStatus = 0xC0000044L; /* Quota exceeded */
2395 NTStatus = 0xC000007FL; /* Disk full */
2398 else if (code == CM_ERROR_SPACE) {
2399 NTStatus = 0xC000007FL; /* Disk full */
2401 else if (code == CM_ERROR_ATSYS) {
2402 NTStatus = 0xC0000033L; /* Object name invalid */
2404 else if (code == CM_ERROR_BADNTFILENAME) {
2405 NTStatus = 0xC0000033L; /* Object name invalid */
2407 else if (code == CM_ERROR_WOULDBLOCK) {
2408 NTStatus = 0xC0000055L; /* Lock not granted */
2410 else if (code == CM_ERROR_PARTIALWRITE) {
2411 NTStatus = 0xC000007FL; /* Disk full */
2413 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2414 NTStatus = 0xC0000023L; /* Buffer too small */
2416 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2417 NTStatus = 0xC0000035L; /* Object name collision */
2419 else if (code == CM_ERROR_BADPASSWORD) {
2420 NTStatus = 0xC000006DL; /* unknown username or bad password */
2422 else if (code == CM_ERROR_BADLOGONTYPE) {
2423 NTStatus = 0xC000015BL; /* logon type not granted */
2425 else if (code == CM_ERROR_GSSCONTINUE) {
2426 NTStatus = 0xC0000016L; /* more processing required */
2428 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2430 NTStatus = 0xC0000280L; /* reparse point not resolved */
2432 NTStatus = 0xC0000022L; /* Access Denied */
2435 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2436 NTStatus = 0xC0000257L; /* Path Not Covered */
2439 else if (code == CM_ERROR_ALLBUSY) {
2440 NTStatus = 0xC00000BFL; /* Network Busy */
2442 else if (code == CM_ERROR_ALLOFFLINE) {
2443 NTStatus = 0xC0000350L; /* Remote Host Down */
2446 /* we do not want to be telling the SMB/CIFS client that
2447 * the AFS Client Service is busy or down.
2449 else if (code == CM_ERROR_ALLBUSY ||
2450 code == CM_ERROR_ALLOFFLINE) {
2451 NTStatus = 0xC00000BEL; /* Bad Network Path */
2455 NTStatus = 0xC0982001L; /* SMB non-specific error */
2458 *NTStatusp = NTStatus;
2459 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2462 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2463 unsigned char *classp)
2465 unsigned char class;
2466 unsigned short error;
2468 /* map CM_ERROR_* errors to SMB errors */
2469 if (code == CM_ERROR_NOSUCHCELL) {
2471 error = 3; /* bad path */
2473 else if (code == CM_ERROR_NOSUCHVOLUME) {
2475 error = 3; /* bad path */
2477 else if (code == CM_ERROR_TIMEDOUT) {
2479 error = 81; /* server is paused */
2481 else if (code == CM_ERROR_RETRY) {
2482 class = 2; /* shouldn't happen */
2485 else if (code == CM_ERROR_NOACCESS) {
2487 error = 4; /* bad access */
2489 else if (code == CM_ERROR_READONLY) {
2491 error = 19; /* read only */
2493 else if (code == CM_ERROR_NOSUCHFILE) {
2495 error = 2; /* ENOENT! */
2497 else if (code == CM_ERROR_NOSUCHPATH) {
2499 error = 3; /* Bad path */
2501 else if (code == CM_ERROR_TOOBIG) {
2503 error = 11; /* bad format */
2505 else if (code == CM_ERROR_INVAL) {
2506 class = 2; /* server non-specific error code */
2509 else if (code == CM_ERROR_BADFD) {
2511 error = 6; /* invalid file handle */
2513 else if (code == CM_ERROR_BADFDOP) {
2514 class = 1; /* invalid op on FD */
2517 else if (code == CM_ERROR_EXISTS) {
2519 error = 80; /* file already exists */
2521 else if (code == CM_ERROR_NOTEMPTY) {
2523 error = 5; /* delete directory not empty */
2525 else if (code == CM_ERROR_CROSSDEVLINK) {
2527 error = 17; /* EXDEV */
2529 else if (code == CM_ERROR_NOTDIR) {
2530 class = 1; /* bad path */
2533 else if (code == CM_ERROR_ISDIR) {
2534 class = 1; /* access denied; DOS doesn't have a good match */
2537 else if (code == CM_ERROR_BADOP) {
2541 else if (code == CM_ERROR_BADSHARENAME) {
2545 else if (code == CM_ERROR_NOIPC) {
2547 error = 4; /* bad access */
2549 else if (code == CM_ERROR_CLOCKSKEW) {
2550 class = 1; /* invalid function */
2553 else if (code == CM_ERROR_BADTID) {
2557 else if (code == CM_ERROR_USESTD) {
2561 else if (code == CM_ERROR_REMOTECONN) {
2565 else if (code == CM_ERROR_QUOTA) {
2566 if (vcp->flags & SMB_VCFLAG_USEV3) {
2568 error = 39; /* disk full */
2572 error = 5; /* access denied */
2575 else if (code == CM_ERROR_SPACE) {
2576 if (vcp->flags & SMB_VCFLAG_USEV3) {
2578 error = 39; /* disk full */
2582 error = 5; /* access denied */
2585 else if (code == CM_ERROR_PARTIALWRITE) {
2587 error = 39; /* disk full */
2589 else if (code == CM_ERROR_ATSYS) {
2591 error = 2; /* ENOENT */
2593 else if (code == CM_ERROR_WOULDBLOCK) {
2595 error = 33; /* lock conflict */
2597 else if (code == CM_ERROR_NOFILES) {
2599 error = 18; /* no files in search */
2601 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2603 error = 183; /* Samba uses this */
2605 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2606 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2608 error = 2; /* bad password */
2610 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2612 error = 3; /* bad path */
2621 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2624 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2626 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2627 return CM_ERROR_BADOP;
2630 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2632 unsigned short EchoCount, i;
2633 char *data, *outdata;
2636 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2638 for (i=1; i<=EchoCount; i++) {
2639 data = smb_GetSMBData(inp, &dataSize);
2640 smb_SetSMBParm(outp, 0, i);
2641 smb_SetSMBDataLength(outp, dataSize);
2642 outdata = smb_GetSMBData(outp, NULL);
2643 memcpy(outdata, data, dataSize);
2644 smb_SendPacket(vcp, outp);
2650 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2653 long count, minCount, finalCount;
2657 cm_user_t *userp = NULL;
2661 char *rawBuf = NULL;
2663 dos_ptr rawBuf = NULL;
2670 fd = smb_GetSMBParm(inp, 0);
2671 count = smb_GetSMBParm(inp, 3);
2672 minCount = smb_GetSMBParm(inp, 4);
2673 offset.HighPart = 0; /* too bad */
2674 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2676 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2677 fd, offset.LowPart, count);
2679 fidp = smb_FindFID(vcp, fd, 0);
2683 lock_ObtainMutex(&smb_RawBufLock);
2685 /* Get a raw buf, from head of list */
2686 rawBuf = smb_RawBufs;
2688 smb_RawBufs = *(char **)smb_RawBufs;
2690 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2693 lock_ReleaseMutex(&smb_RawBufLock);
2697 if (fidp->flags & SMB_FID_IOCTL)
2700 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2702 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2705 /* Give back raw buffer */
2706 lock_ObtainMutex(&smb_RawBufLock);
2708 *((char **) rawBuf) = smb_RawBufs;
2710 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2713 smb_RawBufs = rawBuf;
2714 lock_ReleaseMutex(&smb_RawBufLock);
2717 smb_ReleaseFID(fidp);
2721 userp = smb_GetUser(vcp, inp);
2724 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2726 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2727 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2728 userp, &finalCount, TRUE /* rawFlag */);
2735 cm_ReleaseUser(userp);
2738 smb_ReleaseFID(fidp);
2743 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2745 memset((char *)ncbp, 0, sizeof(NCB));
2747 ncbp->ncb_length = (unsigned short) finalCount;
2748 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2749 ncbp->ncb_lana_num = vcp->lana;
2750 ncbp->ncb_command = NCBSEND;
2751 ncbp->ncb_buffer = rawBuf;
2754 code = Netbios(ncbp);
2756 code = Netbios(ncbp, dos_ncb);
2759 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2762 /* Give back raw buffer */
2763 lock_ObtainMutex(&smb_RawBufLock);
2765 *((char **) rawBuf) = smb_RawBufs;
2767 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2770 smb_RawBufs = rawBuf;
2771 lock_ReleaseMutex(&smb_RawBufLock);
2777 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2779 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2784 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2786 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2791 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2798 int protoIndex; /* index we're using */
2803 char protocol_array[10][1024]; /* protocol signature of the client */
2804 int caps; /* capabilities */
2807 TIME_ZONE_INFORMATION tzi;
2809 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2813 DWORD now = GetCurrentTime();
2814 if (now - last_msg_time >= 30000
2815 && now - last_msg_time <= 90000) {
2817 "Setting dead_vcp %x", active_vcp);
2819 smb_ReleaseVC(dead_vcp);
2821 "Previous dead_vcp %x", dead_vcp);
2823 smb_HoldVC(active_vcp);
2824 dead_vcp = active_vcp;
2825 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2830 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2832 namep = smb_GetSMBData(inp, &dbytes);
2835 coreProtoIndex = -1; /* not found */
2838 while(namex < dbytes) {
2839 osi_Log1(smb_logp, "Protocol %s",
2840 osi_LogSaveString(smb_logp, namep+1));
2841 strcpy(protocol_array[tcounter], namep+1);
2843 /* namep points at the first protocol, or really, a 0x02
2844 * byte preceding the null-terminated ASCII name.
2846 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2847 coreProtoIndex = tcounter;
2849 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2850 v3ProtoIndex = tcounter;
2852 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2853 NTProtoIndex = tcounter;
2856 /* compute size of protocol entry */
2857 entryLength = strlen(namep+1);
2858 entryLength += 2; /* 0x02 bytes and null termination */
2860 /* advance over this protocol entry */
2861 namex += entryLength;
2862 namep += entryLength;
2863 tcounter++; /* which proto entry we're looking at */
2866 if (NTProtoIndex != -1) {
2867 protoIndex = NTProtoIndex;
2868 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2870 else if (v3ProtoIndex != -1) {
2871 protoIndex = v3ProtoIndex;
2872 vcp->flags |= SMB_VCFLAG_USEV3;
2874 else if (coreProtoIndex != -1) {
2875 protoIndex = coreProtoIndex;
2876 vcp->flags |= SMB_VCFLAG_USECORE;
2878 else protoIndex = -1;
2880 if (protoIndex == -1)
2881 return CM_ERROR_INVAL;
2882 else if (NTProtoIndex != -1) {
2883 smb_SetSMBParm(outp, 0, protoIndex);
2884 if (smb_authType != SMB_AUTH_NONE) {
2885 smb_SetSMBParmByte(outp, 1,
2886 NEGOTIATE_SECURITY_USER_LEVEL |
2887 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2889 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2891 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2892 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2893 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2894 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2895 /* The session key is not a well documented field however most clients
2896 * will echo back the session key to the server. Currently we are using
2897 * the same value for all sessions. We should generate a random value
2898 * and store it into the vcp
2900 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2901 smb_SetSMBParm(outp, 8, 1);
2903 * Tried changing the capabilities to support for W2K - defect 117695
2904 * Maybe something else needs to be changed here?
2908 smb_SetSMBParmLong(outp, 9, 0x43fd);
2910 smb_SetSMBParmLong(outp, 9, 0x251);
2913 * 32-bit error codes *
2918 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2920 NTNEGOTIATE_CAPABILITY_DFS |
2922 NTNEGOTIATE_CAPABILITY_NTFIND |
2923 NTNEGOTIATE_CAPABILITY_RAWMODE |
2924 NTNEGOTIATE_CAPABILITY_NTSMB;
2926 if ( smb_authType == SMB_AUTH_EXTENDED )
2927 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2929 smb_SetSMBParmLong(outp, 9, caps);
2931 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2932 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2933 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2935 GetTimeZoneInformation(&tzi);
2936 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2938 if (smb_authType == SMB_AUTH_NTLM) {
2939 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2940 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2941 /* paste in encryption key */
2942 datap = smb_GetSMBData(outp, NULL);
2943 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2944 /* and the faux domain name */
2945 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2946 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2950 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2952 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2954 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2956 datap = smb_GetSMBData(outp, NULL);
2957 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2960 datap += sizeof(smb_ServerGUID);
2961 memcpy(datap, secBlob, secBlobLength);
2965 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2966 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2969 else if (v3ProtoIndex != -1) {
2970 smb_SetSMBParm(outp, 0, protoIndex);
2972 /* NOTE: Extended authentication cannot be negotiated with v3
2973 * therefore we fail over to NTLM
2975 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2976 smb_SetSMBParm(outp, 1,
2977 NEGOTIATE_SECURITY_USER_LEVEL |
2978 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2980 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2982 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2983 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2984 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2985 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2986 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2987 smb_SetSMBParm(outp, 7, 1);
2989 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2990 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2991 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2993 GetTimeZoneInformation(&tzi);
2994 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2996 /* NOTE: Extended authentication cannot be negotiated with v3
2997 * therefore we fail over to NTLM
2999 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3000 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3001 smb_SetSMBParm(outp, 12, 0); /* resvd */
3002 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3003 datap = smb_GetSMBData(outp, NULL);
3004 /* paste in a new encryption key */
3005 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3006 /* and the faux domain name */
3007 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3009 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3010 smb_SetSMBParm(outp, 12, 0); /* resvd */
3011 smb_SetSMBDataLength(outp, 0);
3014 else if (coreProtoIndex != -1) { /* not really supported anymore */
3015 smb_SetSMBParm(outp, 0, protoIndex);
3016 smb_SetSMBDataLength(outp, 0);
3021 void smb_Daemon(void *parmp)
3023 afs_uint32 count = 0;
3025 while(smbShutdownFlag == 0) {
3029 if (smbShutdownFlag == 1)
3032 if ((count % 72) == 0) { /* every five minutes */
3034 time_t old_localZero = smb_localZero;
3036 /* Initialize smb_localZero */
3037 myTime.tm_isdst = -1; /* compute whether on DST or not */
3038 myTime.tm_year = 70;
3044 smb_localZero = mktime(&myTime);
3046 #ifndef USE_NUMERIC_TIME_CONV
3047 smb_CalculateNowTZ();
3048 #endif /* USE_NUMERIC_TIME_CONV */
3049 #ifdef AFS_FREELANCE
3050 if ( smb_localZero != old_localZero )
3051 cm_noteLocalMountPointChange();
3054 /* XXX GC dir search entries */
3058 void smb_WaitingLocksDaemon()
3060 smb_waitingLock_t *wL, *nwL;
3063 smb_packet_t *inp, *outp;
3067 while (smbShutdownFlag == 0) {
3068 lock_ObtainWrite(&smb_globalLock);
3069 nwL = smb_allWaitingLocks;
3071 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
3081 lock_ObtainWrite(&smb_globalLock);
3083 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
3084 lock_ReleaseWrite(&smb_globalLock);
3085 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
3086 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
3087 if (code == CM_ERROR_WOULDBLOCK) {
3089 if (wL->timeRemaining != 0xffffffff
3090 && (wL->timeRemaining -= 1000) < 0)
3100 ncbp->ncb_length = inp->ncb_length;
3101 inp->spacep = cm_GetSpace();
3103 /* Remove waitingLock from list */
3104 lock_ObtainWrite(&smb_globalLock);
3105 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3107 lock_ReleaseWrite(&smb_globalLock);
3109 /* Resume packet processing */
3111 smb_SetSMBDataLength(outp, 0);
3112 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3113 outp->resumeCode = code;
3115 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3118 cm_FreeSpace(inp->spacep);
3119 smb_FreePacket(inp);
3120 smb_FreePacket(outp);
3124 } while (nwL && smbShutdownFlag == 0);
3129 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3131 osi_Log0(smb_logp, "SMB receive get disk attributes");
3133 smb_SetSMBParm(outp, 0, 32000);
3134 smb_SetSMBParm(outp, 1, 64);
3135 smb_SetSMBParm(outp, 2, 1024);
3136 smb_SetSMBParm(outp, 3, 30000);
3137 smb_SetSMBParm(outp, 4, 0);
3138 smb_SetSMBDataLength(outp, 0);
3142 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3146 unsigned short newTid;
3147 char shareName[256];
3155 osi_Log0(smb_logp, "SMB receive tree connect");
3157 /* parse input parameters */
3158 tp = smb_GetSMBData(inp, NULL);
3159 pathp = smb_ParseASCIIBlock(tp, &tp);
3160 if (smb_StoreAnsiFilenames)
3161 OemToChar(pathp,pathp);
3162 passwordp = smb_ParseASCIIBlock(tp, &tp);
3163 tp = strrchr(pathp, '\\');
3165 return CM_ERROR_BADSMB;
3166 strcpy(shareName, tp+1);
3168 userp = smb_GetUser(vcp, inp);
3170 lock_ObtainMutex(&vcp->mx);
3171 newTid = vcp->tidCounter++;
3172 lock_ReleaseMutex(&vcp->mx);
3174 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3175 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3176 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3178 smb_ReleaseUID(uidp);
3180 smb_ReleaseTID(tidp);
3181 return CM_ERROR_BADSHARENAME;
3183 lock_ObtainMutex(&tidp->mx);
3184 tidp->userp = userp;
3185 tidp->pathname = sharePath;
3186 lock_ReleaseMutex(&tidp->mx);
3187 smb_ReleaseTID(tidp);
3189 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3190 smb_SetSMBParm(rsp, 1, newTid);
3191 smb_SetSMBDataLength(rsp, 0);
3193 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3197 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3201 if (*inp++ != 0x1) return NULL;
3202 tlen = inp[0] + (inp[1]<<8);
3203 inp += 2; /* skip length field */
3206 *chainpp = inp + tlen;
3209 if (lengthp) *lengthp = tlen;
3214 /* set maskp to the mask part of the incoming path.
3215 * Mask is 11 bytes long (8.3 with the dot elided).
3216 * Returns true if succeeds with a valid name, otherwise it does
3217 * its best, but returns false.
3219 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3227 /* starts off valid */
3230 /* mask starts out all blanks */
3231 memset(maskp, ' ', 11);
3233 /* find last backslash, or use whole thing if there is none */
3234 tp = strrchr(pathp, '\\');
3235 if (!tp) tp = pathp;
3236 else tp++; /* skip slash */
3240 /* names starting with a dot are illegal */
3241 if (*tp == '.') valid8Dot3 = 0;
3245 if (tc == 0) return valid8Dot3;
3246 if (tc == '.' || tc == '"') break;
3247 if (i < 8) *up++ = tc;
3248 else valid8Dot3 = 0;
3251 /* if we get here, tp point after the dot */
3252 up = maskp+8; /* ext goes here */
3259 if (tc == '.' || tc == '"')
3262 /* copy extension if not too long */
3272 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3282 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3284 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3288 /* otherwise, we have a valid 8.3 name; see if we have a match,
3289 * treating '?' as a wildcard in maskp (but not in the file name).
3291 tp1 = umask; /* real name, in mask format */
3292 tp2 = maskp; /* mask, in mask format */
3293 for(i=0; i<11; i++) {
3294 tc1 = *tp1++; /* char from real name */
3295 tc2 = *tp2++; /* char from mask */
3296 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3297 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3300 if (tc2 == '?' && tc1 != ' ')
3307 /* we got a match */
3311 char *smb_FindMask(char *pathp)
3315 tp = strrchr(pathp, '\\'); /* find last slash */
3318 return tp+1; /* skip the slash */
3320 return pathp; /* no slash, return the entire path */
3323 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3325 unsigned char *pathp;
3327 unsigned char mask[11];
3328 unsigned char *statBlockp;
3329 unsigned char initStatBlock[21];
3332 osi_Log0(smb_logp, "SMB receive search volume");
3334 /* pull pathname and stat block out of request */
3335 tp = smb_GetSMBData(inp, NULL);
3336 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3337 osi_assert(pathp != NULL);
3338 if (smb_StoreAnsiFilenames)
3339 OemToChar(pathp,pathp);
3340 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3341 osi_assert(statBlockp != NULL);
3343 statBlockp = initStatBlock;
3347 /* for returning to caller */
3348 smb_Get8Dot3MaskFromPath(mask, pathp);
3350 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3351 tp = smb_GetSMBData(outp, NULL);
3353 *tp++ = 43; /* bytes in a dir entry */
3354 *tp++ = 0; /* high byte in counter */
3356 /* now marshall the dir entry, starting with the search status */
3357 *tp++ = statBlockp[0]; /* Reserved */
3358 memcpy(tp, mask, 11); tp += 11; /* FileName */
3360 /* now pass back server use info, with 1st byte non-zero */
3362 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3364 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3366 *tp++ = 0x8; /* attribute: volume */
3376 /* 4 byte file size */
3382 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3383 memset(tp, ' ', 13);
3386 /* set the length of the data part of the packet to 43 + 3, for the dir
3387 * entry plus the 5 and the length fields.
3389 smb_SetSMBDataLength(outp, 46);
3393 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3394 cm_user_t *userp, cm_req_t *reqp)
3402 smb_dirListPatch_t *patchp;
3403 smb_dirListPatch_t *npatchp;
3405 for (patchp = *dirPatchespp; patchp; patchp =
3406 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3408 dptr = patchp->dptr;
3410 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3412 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3413 *dptr++ = SMB_ATTR_HIDDEN;
3416 lock_ObtainMutex(&scp->mx);
3417 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3418 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3420 lock_ReleaseMutex(&scp->mx);
3421 cm_ReleaseSCache(scp);
3422 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3423 *dptr++ = SMB_ATTR_HIDDEN;
3427 attr = smb_Attributes(scp);
3428 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3429 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3430 attr |= SMB_ATTR_HIDDEN;
3434 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3437 shortTemp = (unsigned short) (dosTime & 0xffff);
3438 *((u_short *)dptr) = shortTemp;
3441 /* and copy out date */
3442 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3443 *((u_short *)dptr) = shortTemp;
3446 /* copy out file length */
3447 *((u_long *)dptr) = scp->length.LowPart;
3449 lock_ReleaseMutex(&scp->mx);
3450 cm_ReleaseSCache(scp);
3453 /* now free the patches */
3454 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3455 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3459 /* and mark the list as empty */
3460 *dirPatchespp = NULL;
3465 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3474 smb_dirListPatch_t *dirListPatchesp;
3475 smb_dirListPatch_t *curPatchp;
3479 osi_hyper_t dirLength;
3480 osi_hyper_t bufferOffset;
3481 osi_hyper_t curOffset;
3483 unsigned char *inCookiep;
3484 smb_dirSearch_t *dsp;
3488 unsigned long clientCookie;
3489 cm_pageHeader_t *pageHeaderp;
3490 cm_user_t *userp = NULL;
3497 long nextEntryCookie;
3498 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3499 char resByte; /* reserved byte from the cookie */
3500 char *op; /* output data ptr */
3501 char *origOp; /* original value of op */
3502 cm_space_t *spacep; /* for pathname buffer */
3513 maxCount = smb_GetSMBParm(inp, 0);
3515 dirListPatchesp = NULL;
3517 caseFold = CM_FLAG_CASEFOLD;
3519 tp = smb_GetSMBData(inp, NULL);
3520 pathp = smb_ParseASCIIBlock(tp, &tp);
3521 if (smb_StoreAnsiFilenames)
3522 OemToChar(pathp,pathp);
3523 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3525 /* bail out if request looks bad */
3526 if (!tp || !pathp) {
3527 return CM_ERROR_BADSMB;
3530 /* We can handle long names */
3531 if (vcp->flags & SMB_VCFLAG_USENT)
3532 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3534 /* make sure we got a whole search status */
3535 if (dataLength < 21) {
3536 nextCookie = 0; /* start at the beginning of the dir */
3539 attribute = smb_GetSMBParm(inp, 1);
3541 /* handle volume info in another function */
3542 if (attribute & 0x8)
3543 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3545 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3546 maxCount, osi_LogSaveString(smb_logp, pathp));
3548 if (*pathp == 0) { /* null pathp, treat as root dir */
3549 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3550 return CM_ERROR_NOFILES;
3554 dsp = smb_NewDirSearch(0);
3555 dsp->attribute = attribute;
3556 smb_Get8Dot3MaskFromPath(mask, pathp);
3557 memcpy(dsp->mask, mask, 11);
3559 /* track if this is likely to match a lot of entries */
3560 if (smb_IsStarMask(mask))
3565 /* pull the next cookie value out of the search status block */
3566 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3567 + (inCookiep[16]<<24);
3568 dsp = smb_FindDirSearch(inCookiep[12]);
3570 /* can't find dir search status; fatal error */
3571 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3572 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3573 return CM_ERROR_BADFD;
3575 attribute = dsp->attribute;
3576 resByte = inCookiep[0];
3578 /* copy out client cookie, in host byte order. Don't bother
3579 * interpreting it, since we're just passing it through, anyway.
3581 memcpy(&clientCookie, &inCookiep[17], 4);
3583 memcpy(mask, dsp->mask, 11);
3585 /* assume we're doing a star match if it has continued for more
3591 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3592 nextCookie, dsp->cookie, attribute);
3594 userp = smb_GetUser(vcp, inp);
3596 /* try to get the vnode for the path name next */
3597 lock_ObtainMutex(&dsp->mx);
3603 spacep = inp->spacep;
3604 smb_StripLastComponent(spacep->data, NULL, pathp);
3605 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3607 lock_ReleaseMutex(&dsp->mx);
3608 cm_ReleaseUser(userp);
3609 smb_DeleteDirSearch(dsp);
3610 smb_ReleaseDirSearch(dsp);
3611 return CM_ERROR_NOFILES;
3613 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3614 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3617 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3618 cm_ReleaseSCache(scp);
3619 lock_ReleaseMutex(&dsp->mx);
3620 cm_ReleaseUser(userp);
3621 smb_DeleteDirSearch(dsp);
3622 smb_ReleaseDirSearch(dsp);
3623 if ( WANTS_DFS_PATHNAMES(inp) )
3624 return CM_ERROR_PATH_NOT_COVERED;
3626 return CM_ERROR_BADSHARENAME;
3628 #endif /* DFS_SUPPORT */
3631 /* we need one hold for the entry we just stored into,
3632 * and one for our own processing. When we're done with this
3633 * function, we'll drop the one for our own processing.
3634 * We held it once from the namei call, and so we do another hold
3638 lock_ObtainMutex(&scp->mx);
3639 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3640 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3641 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3642 dsp->flags |= SMB_DIRSEARCH_BULKST;
3644 lock_ReleaseMutex(&scp->mx);
3647 lock_ReleaseMutex(&dsp->mx);
3649 cm_ReleaseUser(userp);
3650 smb_DeleteDirSearch(dsp);
3651 smb_ReleaseDirSearch(dsp);
3655 /* reserves space for parameter; we'll adjust it again later to the
3656 * real count of the # of entries we returned once we've actually
3657 * assembled the directory listing.
3659 smb_SetSMBParm(outp, 0, 0);
3661 /* get the directory size */
3662 lock_ObtainMutex(&scp->mx);
3663 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3664 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3666 lock_ReleaseMutex(&scp->mx);
3667 cm_ReleaseSCache(scp);
3668 cm_ReleaseUser(userp);
3669 smb_DeleteDirSearch(dsp);
3670 smb_ReleaseDirSearch(dsp);
3674 dirLength = scp->length;
3676 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3677 curOffset.HighPart = 0;
3678 curOffset.LowPart = nextCookie;
3679 origOp = op = smb_GetSMBData(outp, NULL);
3680 /* and write out the basic header */
3681 *op++ = 5; /* variable block */
3682 op += 2; /* skip vbl block length; we'll fill it in later */
3686 /* make sure that curOffset.LowPart doesn't point to the first
3687 * 32 bytes in the 2nd through last dir page, and that it doesn't
3688 * point at the first 13 32-byte chunks in the first dir page,
3689 * since those are dir and page headers, and don't contain useful
3692 temp = curOffset.LowPart & (2048-1);
3693 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3694 /* we're in the first page */
3695 if (temp < 13*32) temp = 13*32;
3698 /* we're in a later dir page */
3699 if (temp < 32) temp = 32;
3702 /* make sure the low order 5 bits are zero */
3705 /* now put temp bits back ito curOffset.LowPart */
3706 curOffset.LowPart &= ~(2048-1);
3707 curOffset.LowPart |= temp;
3709 /* check if we've returned all the names that will fit in the
3712 if (returnedNames >= maxCount) {
3713 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3714 returnedNames, maxCount);
3718 /* check if we've passed the dir's EOF */
3719 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3721 /* see if we can use the bufferp we have now; compute in which page
3722 * the current offset would be, and check whether that's the offset
3723 * of the buffer we have. If not, get the buffer.
3725 thyper.HighPart = curOffset.HighPart;
3726 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3727 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3730 buf_Release(bufferp);
3733 lock_ReleaseMutex(&scp->mx);