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_waitingLockRequest_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 if (numVCs >= CM_SESSION_RESERVED) {
866 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
869 lock_ReleaseWrite(&smb_rctLock);
873 int smb_IsStarMask(char *maskp)
878 for(i=0; i<11; i++) {
880 if (tc == '?' || tc == '*' || tc == '>') return 1;
885 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
887 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
889 osi_assert(vcp->refCount-- != 0);
895 void smb_ReleaseVC(smb_vc_t *vcp)
897 lock_ObtainWrite(&smb_rctLock);
898 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
900 osi_assert(vcp->refCount-- != 0);
904 lock_ReleaseWrite(&smb_rctLock);
907 void smb_HoldVCNoLock(smb_vc_t *vcp)
910 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
913 void smb_HoldVC(smb_vc_t *vcp)
915 lock_ObtainWrite(&smb_rctLock);
917 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
918 lock_ReleaseWrite(&smb_rctLock);
921 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
925 lock_ObtainWrite(&smb_rctLock);
926 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
927 if (tid == tidp->tid) {
932 if (!tidp && (flags & SMB_FLAG_CREATE)) {
933 tidp = malloc(sizeof(*tidp));
934 memset(tidp, 0, sizeof(*tidp));
935 tidp->nextp = vcp->tidsp;
938 smb_HoldVCNoLock(vcp);
940 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
943 lock_ReleaseWrite(&smb_rctLock);
947 void smb_ReleaseTID(smb_tid_t *tidp)
954 lock_ObtainWrite(&smb_rctLock);
955 osi_assert(tidp->refCount-- > 0);
956 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
957 ltpp = &tidp->vcp->tidsp;
958 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
962 osi_assert(tp != NULL);
964 lock_FinalizeMutex(&tidp->mx);
965 userp = tidp->userp; /* remember to drop ref later */
967 smb_ReleaseVCNoLock(tidp->vcp);
970 lock_ReleaseWrite(&smb_rctLock);
972 cm_ReleaseUser(userp);
975 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
977 smb_user_t *uidp = NULL;
979 lock_ObtainWrite(&smb_rctLock);
980 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
981 if (uid == uidp->userID) {
983 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
984 (int)vcp, uidp->userID,
985 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
989 if (!uidp && (flags & SMB_FLAG_CREATE)) {
990 uidp = malloc(sizeof(*uidp));
991 memset(uidp, 0, sizeof(*uidp));
992 uidp->nextp = vcp->usersp;
995 smb_HoldVCNoLock(vcp);
997 lock_InitializeMutex(&uidp->mx, "user_t mutex");
999 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 : ""));
1001 lock_ReleaseWrite(&smb_rctLock);
1005 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1007 smb_username_t *unp= NULL;
1009 lock_ObtainWrite(&smb_rctLock);
1010 for(unp = usernamesp; unp; unp = unp->nextp) {
1011 if (stricmp(unp->name, usern) == 0 &&
1012 stricmp(unp->machine, machine) == 0) {
1017 if (!unp && (flags & SMB_FLAG_CREATE)) {
1018 unp = malloc(sizeof(*unp));
1019 memset(unp, 0, sizeof(*unp));
1021 unp->nextp = usernamesp;
1022 unp->name = strdup(usern);
1023 unp->machine = strdup(machine);
1025 lock_InitializeMutex(&unp->mx, "username_t mutex");
1027 lock_ReleaseWrite(&smb_rctLock);
1031 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1033 smb_user_t *uidp= NULL;
1035 lock_ObtainWrite(&smb_rctLock);
1036 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1039 if (stricmp(uidp->unp->name, usern) == 0) {
1041 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
1046 lock_ReleaseWrite(&smb_rctLock);
1049 void smb_ReleaseUID(smb_user_t *uidp)
1056 lock_ObtainWrite(&smb_rctLock);
1057 osi_assert(uidp->refCount-- > 0);
1058 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1059 lupp = &uidp->vcp->usersp;
1060 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1064 osi_assert(up != NULL);
1066 lock_FinalizeMutex(&uidp->mx);
1068 userp = uidp->unp->userp; /* avoid deadlock by releasing */
1069 uidp->unp->userp = NULL; /* after releasing the lock */
1071 smb_ReleaseVCNoLock(uidp->vcp);
1074 lock_ReleaseWrite(&smb_rctLock);
1076 cm_ReleaseUserVCRef(userp);
1077 cm_ReleaseUser(userp);
1082 /* retrieve a held reference to a user structure corresponding to an incoming
1084 * corresponding release function is cm_ReleaseUser.
1086 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1092 smbp = (smb_t *) inp;
1093 uidp = smb_FindUID(vcp, smbp->uid, 0);
1094 if ((!uidp) || (!uidp->unp))
1097 lock_ObtainMutex(&uidp->mx);
1098 up = uidp->unp->userp;
1100 lock_ReleaseMutex(&uidp->mx);
1102 smb_ReleaseUID(uidp);
1108 * Return a pointer to a pathname extracted from a TID structure. The
1109 * TID structure is not held; assume it won't go away.
1111 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1116 tidp = smb_FindTID(vcp, tid, 0);
1120 if (tidp->flags & SMB_TIDFLAG_IPC) {
1121 code = CM_ERROR_TIDIPC;
1122 /* tidp->pathname would be NULL, but that's fine */
1124 *treepath = tidp->pathname;
1125 smb_ReleaseTID(tidp);
1130 /* check to see if we have a chained fid, that is, a fid that comes from an
1131 * OpenAndX message that ran earlier in this packet. In this case, the fid
1132 * field in a read, for example, request, isn't set, since the value is
1133 * supposed to be inherited from the openAndX call.
1135 int smb_ChainFID(int fid, smb_packet_t *inp)
1137 if (inp->fid == 0 || inp->inCount == 0)
1143 /* are we a priv'd user? What does this mean on NT? */
1144 int smb_SUser(cm_user_t *userp)
1149 /* find a file ID. If we pass in 0 we select an unused File ID.
1150 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1151 * smb_fid_t data structure if desired File ID cannot be found.
1153 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1158 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1161 lock_ObtainWrite(&smb_rctLock);
1162 /* figure out if we need to allocate a new file ID */
1165 fid = vcp->fidCounter;
1169 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1170 if (fid == fidp->fid) {
1182 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1183 char eventName[MAX_PATH];
1185 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1186 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1187 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1188 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1189 thrd_CloseHandle(event);
1196 fidp = malloc(sizeof(*fidp));
1197 memset(fidp, 0, sizeof(*fidp));
1198 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1201 smb_HoldVCNoLock(vcp);
1202 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1204 fidp->curr_chunk = fidp->prev_chunk = -2;
1205 fidp->raw_write_event = event;
1207 vcp->fidCounter = fid+1;
1208 if (vcp->fidCounter == 0)
1209 vcp->fidCounter = 1;
1213 lock_ReleaseWrite(&smb_rctLock);
1217 void smb_ReleaseFID(smb_fid_t *fidp)
1220 smb_vc_t *vcp = NULL;
1221 smb_ioctl_t *ioctlp;
1227 lock_ObtainWrite(&smb_rctLock);
1228 osi_assert(fidp->refCount-- > 0);
1229 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1232 scp = fidp->scp; /* release after lock is released */
1235 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1236 thrd_CloseHandle(fidp->raw_write_event);
1238 /* and see if there is ioctl stuff to free */
1239 ioctlp = fidp->ioctlp;
1242 cm_FreeSpace(ioctlp->prefix);
1243 if (ioctlp->inAllocp)
1244 free(ioctlp->inAllocp);
1245 if (ioctlp->outAllocp)
1246 free(ioctlp->outAllocp);
1252 smb_ReleaseVCNoLock(vcp);
1254 lock_ReleaseWrite(&smb_rctLock);
1256 /* now release the scache structure */
1258 cm_ReleaseSCache(scp);
1262 * Case-insensitive search for one string in another;
1263 * used to find variable names in submount pathnames.
1265 static char *smb_stristr(char *str1, char *str2)
1269 for (cursor = str1; *cursor; cursor++)
1270 if (stricmp(cursor, str2) == 0)
1277 * Substitute a variable value for its name in a submount pathname. Variable
1278 * name has been identified by smb_stristr() and is in substr. Variable name
1279 * length (plus one) is in substr_size. Variable value is in newstr.
1281 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1286 strcpy(temp, substr + substr_size - 1);
1287 strcpy(substr, newstr);
1291 char VNUserName[] = "%USERNAME%";
1292 char VNLCUserName[] = "%LCUSERNAME%";
1293 char VNComputerName[] = "%COMPUTERNAME%";
1294 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1297 /* List available shares */
1298 int smb_ListShares()
1302 char shareBuf[4096];
1310 /*strcpy(shareNameList[num_shares], "all");
1311 strcpy(pathNameList[num_shares++], "/afs");*/
1312 fprintf(stderr, "The following shares are available:\n");
1313 fprintf(stderr, "Share Name (AFS Path)\n");
1314 fprintf(stderr, "---------------------\n");
1315 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1318 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1319 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1321 strcpy(sbmtpath, cm_confDir);
1323 strcat(sbmtpath, "/afsdsbmt.ini");
1324 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1325 shareBuf, sizeof(shareBuf),
1331 this_share = shareBuf;
1335 /*strcpy(shareNameList[num_shares], this_share);*/
1336 len = GetPrivateProfileString("AFS Submounts", this_share,
1343 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1346 if (*p == '\\') *p = '/'; /* change to / */
1350 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1351 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1354 while (*this_share != 0) this_share++; /* find next NUL */
1355 this_share++; /* skip past the NUL */
1356 } while (*this_share != 0); /* stop at final NUL */
1362 typedef struct smb_findShare_rock {
1366 } smb_findShare_rock_t;
1368 #define SMB_FINDSHARE_EXACT_MATCH 1
1369 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1371 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1375 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1376 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1377 if(!stricmp(dep->name, vrock->shareName))
1378 matchType = SMB_FINDSHARE_EXACT_MATCH;
1380 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1381 if(vrock->match) free(vrock->match);
1382 vrock->match = strdup(dep->name);
1383 vrock->matchType = matchType;
1385 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1386 return CM_ERROR_STOPNOW;
1392 /* find a shareName in the table of submounts */
1393 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1397 char pathName[1024];
1402 char sbmtpath[MAX_PATH];
1407 DWORD allSubmount = 1;
1409 /* if allSubmounts == 0, only return the //mountRoot/all share
1410 * if in fact it has been been created in the subMounts table.
1411 * This is to allow sites that want to restrict access to the
1414 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1415 0, KEY_QUERY_VALUE, &parmKey);
1416 if (code == ERROR_SUCCESS) {
1417 len = sizeof(allSubmount);
1418 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1419 (BYTE *) &allSubmount, &len);
1420 if (code != ERROR_SUCCESS) {
1423 RegCloseKey (parmKey);
1426 if (allSubmount && _stricmp(shareName, "all") == 0) {
1431 /* In case, the all share is disabled we need to still be able
1432 * to handle ioctl requests
1434 if (_stricmp(shareName, "ioctl$") == 0) {
1435 *pathNamep = strdup("/.__ioctl__");
1439 if (_stricmp(shareName, "IPC$") == 0 ||
1440 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1441 _stricmp(shareName, "DESKTOP.INI") == 0
1448 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1449 0, KEY_QUERY_VALUE, &parmKey);
1450 if (code == ERROR_SUCCESS) {
1451 len = sizeof(pathName);
1452 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1453 (BYTE *) pathName, &len);
1454 if (code != ERROR_SUCCESS)
1456 RegCloseKey (parmKey);
1461 strcpy(sbmtpath, cm_confDir);
1462 strcat(sbmtpath, "/afsdsbmt.ini");
1463 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1464 pathName, sizeof(pathName), sbmtpath);
1466 if (len != 0 && len != sizeof(pathName) - 1) {
1467 /* We can accept either unix or PC style AFS pathnames. Convert
1468 * Unix-style to PC style here for internal use.
1471 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1472 p += strlen(cm_mountRoot); /* skip mount path */
1475 if (*q == '/') *q = '\\'; /* change to \ */
1481 if (var = smb_stristr(p, VNUserName)) {
1482 if (uidp && uidp->unp)
1483 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1485 smb_subst(p, var, sizeof(VNUserName)," ");
1487 else if (var = smb_stristr(p, VNLCUserName))
1489 if (uidp && uidp->unp)
1490 strcpy(temp, uidp->unp->name);
1494 smb_subst(p, var, sizeof(VNLCUserName), temp);
1496 else if (var = smb_stristr(p, VNComputerName))
1498 sizeTemp = sizeof(temp);
1499 GetComputerName((LPTSTR)temp, &sizeTemp);
1500 smb_subst(p, var, sizeof(VNComputerName), temp);
1502 else if (var = smb_stristr(p, VNLCComputerName))
1504 sizeTemp = sizeof(temp);
1505 GetComputerName((LPTSTR)temp, &sizeTemp);
1507 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1512 *pathNamep = strdup(p);
1517 /* First lookup shareName in root.afs */
1519 smb_findShare_rock_t vrock;
1521 char * p = shareName;
1524 /* attempt to locate a partial match in root.afs. This is because
1525 when using the ANSI RAP calls, the share name is limited to 13 chars
1526 and hence is truncated. Of course we prefer exact matches. */
1528 thyper.HighPart = 0;
1531 vrock.shareName = shareName;
1533 vrock.matchType = 0;
1535 cm_HoldSCache(cm_data.rootSCachep);
1536 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1537 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1538 cm_ReleaseSCache(cm_data.rootSCachep);
1540 if (vrock.matchType) {
1541 sprintf(pathName,"/%s/",vrock.match);
1542 *pathNamep = strdup(strlwr(pathName));
1547 /* if we get here, there was no match for the share in root.afs */
1548 /* so try to create \\<netbiosName>\<cellname> */
1553 /* Get the full name for this cell */
1554 code = cm_SearchCellFile(p, temp, 0, 0);
1555 #ifdef AFS_AFSDB_ENV
1556 if (code && cm_dnsEnabled) {
1558 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1561 /* construct the path */
1563 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1564 *pathNamep = strdup(strlwr(pathName));
1573 /* Client-side offline caching policy types */
1574 #define CSC_POLICY_MANUAL 0
1575 #define CSC_POLICY_DOCUMENTS 1
1576 #define CSC_POLICY_PROGRAMS 2
1577 #define CSC_POLICY_DISABLE 3
1579 int smb_FindShareCSCPolicy(char *shareName)
1585 int retval = CSC_POLICY_MANUAL;
1587 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1588 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1591 REG_OPTION_NON_VOLATILE,
1597 len = sizeof(policy);
1598 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1600 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1602 else if (stricmp(policy, "documents") == 0)
1604 retval = CSC_POLICY_DOCUMENTS;
1606 else if (stricmp(policy, "programs") == 0)
1608 retval = CSC_POLICY_PROGRAMS;
1610 else if (stricmp(policy, "disable") == 0)
1612 retval = CSC_POLICY_DISABLE;
1615 RegCloseKey(hkCSCPolicy);
1619 /* find a dir search structure by cookie value, and return it held.
1620 * Must be called with smb_globalLock held.
1622 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1624 smb_dirSearch_t *dsp;
1626 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1627 if (dsp->cookie == cookie) {
1628 if (dsp != smb_firstDirSearchp) {
1629 /* move to head of LRU queue, too, if we're not already there */
1630 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1631 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1632 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1633 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1634 if (!smb_lastDirSearchp)
1635 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1637 lock_ObtainMutex(&dsp->mx);
1639 lock_ReleaseMutex(&dsp->mx);
1645 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1646 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1647 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1653 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1655 lock_ObtainWrite(&smb_globalLock);
1656 lock_ObtainMutex(&dsp->mx);
1657 dsp->flags |= SMB_DIRSEARCH_DELETE;
1658 if (dsp->scp != NULL) {
1659 lock_ObtainMutex(&dsp->scp->mx);
1660 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1661 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1662 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1663 dsp->scp->bulkStatProgress = hones;
1665 lock_ReleaseMutex(&dsp->scp->mx);
1667 lock_ReleaseMutex(&dsp->mx);
1668 lock_ReleaseWrite(&smb_globalLock);
1671 /* Must be called with the smb_globalLock held */
1672 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1674 cm_scache_t *scp = NULL;
1676 lock_ObtainMutex(&dsp->mx);
1677 osi_assert(dsp->refCount-- > 0);
1678 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1679 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1680 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1681 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1682 lock_ReleaseMutex(&dsp->mx);
1683 lock_FinalizeMutex(&dsp->mx);
1687 lock_ReleaseMutex(&dsp->mx);
1689 /* do this now to avoid spurious locking hierarchy creation */
1691 cm_ReleaseSCache(scp);
1694 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1696 lock_ObtainWrite(&smb_globalLock);
1697 smb_ReleaseDirSearchNoLock(dsp);
1698 lock_ReleaseWrite(&smb_globalLock);
1701 /* find a dir search structure by cookie value, and return it held */
1702 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1704 smb_dirSearch_t *dsp;
1706 lock_ObtainWrite(&smb_globalLock);
1707 dsp = smb_FindDirSearchNoLock(cookie);
1708 lock_ReleaseWrite(&smb_globalLock);
1712 /* GC some dir search entries, in the address space expected by the specific protocol.
1713 * Must be called with smb_globalLock held; release the lock temporarily.
1715 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1716 void smb_GCDirSearches(int isV3)
1718 smb_dirSearch_t *prevp;
1719 smb_dirSearch_t *tp;
1720 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1724 victimCount = 0; /* how many have we got so far */
1725 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1726 /* we'll move tp from queue, so
1729 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1730 /* if no one is using this guy, and we're either in the new protocol,
1731 * or we're in the old one and this is a small enough ID to be useful
1732 * to the old protocol, GC this guy.
1734 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1735 /* hold and delete */
1736 tp->flags |= SMB_DIRSEARCH_DELETE;
1737 victimsp[victimCount++] = tp;
1741 /* don't do more than this */
1742 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1746 /* now release them */
1747 for (i = 0; i < victimCount; i++) {
1748 smb_ReleaseDirSearchNoLock(victimsp[i]);
1752 /* function for allocating a dir search entry. We need these to remember enough context
1753 * since we don't get passed the path from call to call during a directory search.
1755 * Returns a held dir search structure, and bumps the reference count on the vnode,
1756 * since it saves a pointer to the vnode.
1758 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1760 smb_dirSearch_t *dsp;
1766 lock_ObtainWrite(&smb_globalLock);
1769 /* what's the biggest ID allowed in this version of the protocol */
1770 maxAllowed = isV3 ? 65535 : 255;
1771 if (smb_dirSearchCounter > maxAllowed)
1772 smb_dirSearchCounter = 1;
1774 start = smb_dirSearchCounter;
1777 /* twice so we have enough tries to find guys we GC after one pass;
1778 * 10 extra is just in case I mis-counted.
1780 if (++counter > 2*maxAllowed+10)
1781 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1783 if (smb_dirSearchCounter > maxAllowed) {
1784 smb_dirSearchCounter = 1;
1786 if (smb_dirSearchCounter == start) {
1788 smb_GCDirSearches(isV3);
1791 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1793 /* don't need to watch for refcount zero and deleted, since
1794 * we haven't dropped the global lock.
1796 lock_ObtainMutex(&dsp->mx);
1798 lock_ReleaseMutex(&dsp->mx);
1799 ++smb_dirSearchCounter;
1803 dsp = malloc(sizeof(*dsp));
1804 memset(dsp, 0, sizeof(*dsp));
1805 dsp->cookie = smb_dirSearchCounter;
1806 ++smb_dirSearchCounter;
1808 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1809 dsp->lastTime = osi_Time();
1810 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1811 if (!smb_lastDirSearchp)
1812 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1815 lock_ReleaseWrite(&smb_globalLock);
1819 static smb_packet_t *GetPacket(void)
1823 unsigned int npar, seg, tb_sel;
1826 lock_ObtainWrite(&smb_globalLock);
1827 tbp = smb_packetFreeListp;
1829 smb_packetFreeListp = tbp->nextp;
1830 lock_ReleaseWrite(&smb_globalLock);
1833 tbp = calloc(65540,1);
1835 tbp = malloc(sizeof(smb_packet_t));
1837 tbp->magic = SMB_PACKETMAGIC;
1840 tbp->resumeCode = 0;
1846 tbp->ncb_length = 0;
1851 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1854 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1856 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1858 osi_panic("",__FILE__,__LINE__);
1861 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1866 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1867 tbp->dos_pkt_sel = tb_sel;
1870 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1875 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1879 memcpy(tbp, pkt, sizeof(smb_packet_t));
1880 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1882 smb_HoldVC(tbp->vcp);
1886 static NCB *GetNCB(void)
1891 unsigned int npar, seg, tb_sel;
1894 lock_ObtainWrite(&smb_globalLock);
1895 tbp = smb_ncbFreeListp;
1897 smb_ncbFreeListp = tbp->nextp;
1898 lock_ReleaseWrite(&smb_globalLock);
1901 tbp = calloc(sizeof(*tbp),1);
1903 tbp = malloc(sizeof(*tbp));
1904 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1907 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1909 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1911 osi_panic("",__FILE__,__LINE__);
1913 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1918 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1919 tbp->dos_ncb_sel = tb_sel;
1921 tbp->magic = SMB_NCBMAGIC;
1924 osi_assert(tbp->magic == SMB_NCBMAGIC);
1926 memset(&tbp->ncb, 0, sizeof(NCB));
1929 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1934 void smb_FreePacket(smb_packet_t *tbp)
1936 smb_vc_t * vcp = NULL;
1937 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1939 lock_ObtainWrite(&smb_globalLock);
1940 tbp->nextp = smb_packetFreeListp;
1941 smb_packetFreeListp = tbp;
1942 tbp->magic = SMB_PACKETMAGIC;
1946 tbp->resumeCode = 0;
1952 tbp->ncb_length = 0;
1954 lock_ReleaseWrite(&smb_globalLock);
1960 static void FreeNCB(NCB *bufferp)
1964 tbp = (smb_ncb_t *) bufferp;
1965 osi_assert(tbp->magic == SMB_NCBMAGIC);
1967 lock_ObtainWrite(&smb_globalLock);
1968 tbp->nextp = smb_ncbFreeListp;
1969 smb_ncbFreeListp = tbp;
1970 lock_ReleaseWrite(&smb_globalLock);
1973 /* get a ptr to the data part of a packet, and its count */
1974 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1978 unsigned char *afterParmsp;
1980 parmBytes = *smbp->wctp << 1;
1981 afterParmsp = smbp->wctp + parmBytes + 1;
1983 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1984 if (nbytesp) *nbytesp = dataBytes;
1986 /* don't forget to skip the data byte count, since it follows
1987 * the parameters; that's where the "2" comes from below.
1989 return (unsigned char *) (afterParmsp + 2);
1992 /* must set all the returned parameters before playing around with the
1993 * data region, since the data region is located past the end of the
1994 * variable number of parameters.
1996 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1998 unsigned char *afterParmsp;
2000 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2002 *afterParmsp++ = dsize & 0xff;
2003 *afterParmsp = (dsize>>8) & 0xff;
2006 /* return the parm'th parameter in the smbp packet */
2007 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2010 unsigned char *parmDatap;
2012 parmCount = *smbp->wctp;
2014 if (parm >= parmCount) {
2019 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2021 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2022 parm, parmCount, smbp->ncb_length);
2025 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2026 1, smbp->ncb_length, ptbuf, smbp);
2027 DeregisterEventSource(h);
2029 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2030 parm, parmCount, smbp->ncb_length);
2031 osi_panic(s, __FILE__, __LINE__);
2033 parmDatap = smbp->wctp + (2*parm) + 1;
2035 return parmDatap[0] + (parmDatap[1] << 8);
2038 /* return the parm'th parameter in the smbp packet */
2039 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2042 unsigned char *parmDatap;
2044 parmCount = *smbp->wctp;
2046 if (parm * 2 + offset >= parmCount * 2) {
2051 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2053 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2054 parm, offset, parmCount, smbp->ncb_length);
2057 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2058 1, smbp->ncb_length, ptbuf, smbp);
2059 DeregisterEventSource(h);
2061 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2062 parm, offset, parmCount, smbp->ncb_length);
2063 osi_panic(s, __FILE__, __LINE__);
2065 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2067 return parmDatap[0] + (parmDatap[1] << 8);
2070 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2074 /* make sure we have enough slots */
2075 if (*smbp->wctp <= slot)
2076 *smbp->wctp = slot+1;
2078 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2079 *parmDatap++ = parmValue & 0xff;
2080 *parmDatap = (parmValue>>8) & 0xff;
2083 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2087 /* make sure we have enough slots */
2088 if (*smbp->wctp <= slot)
2089 *smbp->wctp = slot+2;
2091 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2092 *parmDatap++ = parmValue & 0xff;
2093 *parmDatap++ = (parmValue>>8) & 0xff;
2094 *parmDatap++ = (parmValue>>16) & 0xff;
2095 *parmDatap++ = (parmValue>>24) & 0xff;
2098 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2103 /* make sure we have enough slots */
2104 if (*smbp->wctp <= slot)
2105 *smbp->wctp = slot+4;
2107 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2109 *parmDatap++ = *parmValuep++;
2112 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2116 /* make sure we have enough slots */
2117 if (*smbp->wctp <= slot) {
2118 if (smbp->oddByte) {
2120 *smbp->wctp = slot+1;
2125 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2126 *parmDatap++ = parmValue & 0xff;
2129 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2133 lastSlashp = strrchr(inPathp, '\\');
2135 *lastComponentp = lastSlashp;
2138 if (inPathp == lastSlashp)
2140 *outPathp++ = *inPathp++;
2149 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2154 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2159 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2165 tlen = inp[0] + (inp[1]<<8);
2166 inp += 2; /* skip length field */
2169 *chainpp = inp + tlen;
2178 /* format a packet as a response */
2179 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2184 outp = (smb_t *) op;
2186 /* zero the basic structure through the smb_wct field, and zero the data
2187 * size field, assuming that wct stays zero; otherwise, you have to
2188 * explicitly set the data size field, too.
2190 inSmbp = (smb_t *) inp;
2191 memset(outp, 0, sizeof(smb_t)+2);
2197 outp->com = inSmbp->com;
2198 outp->tid = inSmbp->tid;
2199 outp->pid = inSmbp->pid;
2200 outp->uid = inSmbp->uid;
2201 outp->mid = inSmbp->mid;
2202 outp->res[0] = inSmbp->res[0];
2203 outp->res[1] = inSmbp->res[1];
2204 op->inCom = inSmbp->com;
2206 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2207 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2209 /* copy fields in generic packet area */
2210 op->wctp = &outp->wct;
2213 /* send a (probably response) packet; vcp tells us to whom to send it.
2214 * we compute the length by looking at wct and bcc fields.
2216 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2233 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2236 memset((char *)ncbp, 0, sizeof(NCB));
2238 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2239 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2240 extra += tp[0] + (tp[1]<<8);
2241 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2242 extra += 3; /* wct and length fields */
2244 ncbp->ncb_length = extra; /* bytes to send */
2245 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2246 ncbp->ncb_lana_num = vcp->lana;
2247 ncbp->ncb_command = NCBSEND; /* op means send data */
2249 ncbp->ncb_buffer = (char *) inp;/* packet */
2250 code = Netbios(ncbp);
2252 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2253 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2255 /* copy header information from virtual to DOS address space */
2256 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2257 code = Netbios(ncbp, dos_ncb);
2263 case 0x01: s = "llegal buffer length "; break;
2264 case 0x03: s = "illegal command "; break;
2265 case 0x05: s = "command timed out "; break;
2266 case 0x06: s = "message incomplete, issue another command"; break;
2267 case 0x07: s = "illegal buffer address "; break;
2268 case 0x08: s = "session number out of range "; break;
2269 case 0x09: s = "no resource available "; break;
2270 case 0x0a: s = "session closed "; break;
2271 case 0x0b: s = "command cancelled "; break;
2272 case 0x0d: s = "duplicate name "; break;
2273 case 0x0e: s = "name table full "; break;
2274 case 0x0f: s = "no deletions, name has active sessions "; break;
2275 case 0x11: s = "local session table full "; break;
2276 case 0x12: s = "remote session table full "; break;
2277 case 0x13: s = "illegal name number "; break;
2278 case 0x14: s = "no callname "; break;
2279 case 0x15: s = "cannot put * in NCB_NAME "; break;
2280 case 0x16: s = "name in use on remote adapter "; break;
2281 case 0x17: s = "name deleted "; break;
2282 case 0x18: s = "session ended abnormally "; break;
2283 case 0x19: s = "name conflict detected "; break;
2284 case 0x21: s = "interface busy, IRET before retrying "; break;
2285 case 0x22: s = "too many commands outstanding, retry later"; break;
2286 case 0x23: s = "ncb_lana_num field invalid "; break;
2287 case 0x24: s = "command completed while cancel occurring "; break;
2288 case 0x26: s = "command not valid to cancel "; break;
2289 case 0x30: s = "name defined by anther local process "; break;
2290 case 0x34: s = "environment undefined. RESET required "; break;
2291 case 0x35: s = "required OS resources exhausted "; break;
2292 case 0x36: s = "max number of applications exceeded "; break;
2293 case 0x37: s = "no saps available for netbios "; break;
2294 case 0x38: s = "requested resources are not available "; break;
2295 case 0x39: s = "invalid ncb address or length > segment "; break;
2296 case 0x3B: s = "invalid NCB DDID "; break;
2297 case 0x3C: s = "lock of user area failed "; break;
2298 case 0x3f: s = "NETBIOS not loaded "; break;
2299 case 0x40: s = "system error "; break;
2301 s = "unknown error";
2303 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2310 void smb_MapNTError(long code, unsigned long *NTStatusp)
2312 unsigned long NTStatus;
2314 /* map CM_ERROR_* errors to NT 32-bit status codes */
2315 /* NT Status codes are listed in ntstatus.h not winerror.h */
2316 if (code == CM_ERROR_NOSUCHCELL) {
2317 NTStatus = 0xC000000FL; /* No such file */
2319 else if (code == CM_ERROR_NOSUCHVOLUME) {
2320 NTStatus = 0xC000000FL; /* No such file */
2322 else if (code == CM_ERROR_TIMEDOUT) {
2324 NTStatus = 0xC00000CFL; /* Sharing Paused */
2326 NTStatus = 0x00000102L; /* Timeout */
2329 else if (code == CM_ERROR_RETRY) {
2330 NTStatus = 0xC000022DL; /* Retry */
2332 else if (code == CM_ERROR_NOACCESS) {
2333 NTStatus = 0xC0000022L; /* Access denied */
2335 else if (code == CM_ERROR_READONLY) {
2336 NTStatus = 0xC00000A2L; /* Write protected */
2338 else if (code == CM_ERROR_NOSUCHFILE) {
2339 NTStatus = 0xC000000FL; /* No such file */
2341 else if (code == CM_ERROR_NOSUCHPATH) {
2342 NTStatus = 0xC000003AL; /* Object path not found */
2344 else if (code == CM_ERROR_TOOBIG) {
2345 NTStatus = 0xC000007BL; /* Invalid image format */
2347 else if (code == CM_ERROR_INVAL) {
2348 NTStatus = 0xC000000DL; /* Invalid parameter */
2350 else if (code == CM_ERROR_BADFD) {
2351 NTStatus = 0xC0000008L; /* Invalid handle */
2353 else if (code == CM_ERROR_BADFDOP) {
2354 NTStatus = 0xC0000022L; /* Access denied */
2356 else if (code == CM_ERROR_EXISTS) {
2357 NTStatus = 0xC0000035L; /* Object name collision */
2359 else if (code == CM_ERROR_NOTEMPTY) {
2360 NTStatus = 0xC0000101L; /* Directory not empty */
2362 else if (code == CM_ERROR_CROSSDEVLINK) {
2363 NTStatus = 0xC00000D4L; /* Not same device */
2365 else if (code == CM_ERROR_NOTDIR) {
2366 NTStatus = 0xC0000103L; /* Not a directory */
2368 else if (code == CM_ERROR_ISDIR) {
2369 NTStatus = 0xC00000BAL; /* File is a directory */
2371 else if (code == CM_ERROR_BADOP) {
2373 /* I have no idea where this comes from */
2374 NTStatus = 0xC09820FFL; /* SMB no support */
2376 NTStatus = 0xC00000BBL; /* Not supported */
2377 #endif /* COMMENT */
2379 else if (code == CM_ERROR_BADSHARENAME) {
2380 NTStatus = 0xC00000CCL; /* Bad network name */
2382 else if (code == CM_ERROR_NOIPC) {
2384 NTStatus = 0xC0000022L; /* Access Denied */
2386 NTStatus = 0xC000013DL; /* Remote Resources */
2389 else if (code == CM_ERROR_CLOCKSKEW) {
2390 NTStatus = 0xC0000133L; /* Time difference at DC */
2392 else if (code == CM_ERROR_BADTID) {
2393 NTStatus = 0xC0982005L; /* SMB bad TID */
2395 else if (code == CM_ERROR_USESTD) {
2396 NTStatus = 0xC09820FBL; /* SMB use standard */
2398 else if (code == CM_ERROR_QUOTA) {
2400 NTStatus = 0xC0000044L; /* Quota exceeded */
2402 NTStatus = 0xC000007FL; /* Disk full */
2405 else if (code == CM_ERROR_SPACE) {
2406 NTStatus = 0xC000007FL; /* Disk full */
2408 else if (code == CM_ERROR_ATSYS) {
2409 NTStatus = 0xC0000033L; /* Object name invalid */
2411 else if (code == CM_ERROR_BADNTFILENAME) {
2412 NTStatus = 0xC0000033L; /* Object name invalid */
2414 else if (code == CM_ERROR_WOULDBLOCK) {
2415 NTStatus = 0xC0000055L; /* Lock not granted */
2417 else if (code == CM_ERROR_SHARING_VIOLATION) {
2418 NTStatus = 0xC0000043L; /* Sharing violation */
2420 else if (code == CM_ERROR_LOCK_CONFLICT) {
2421 NTStatus = 0xC0000054L; /* Lock conflict */
2423 else if (code == CM_ERROR_PARTIALWRITE) {
2424 NTStatus = 0xC000007FL; /* Disk full */
2426 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2427 NTStatus = 0xC0000023L; /* Buffer too small */
2429 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2430 NTStatus = 0xC0000035L; /* Object name collision */
2432 else if (code == CM_ERROR_BADPASSWORD) {
2433 NTStatus = 0xC000006DL; /* unknown username or bad password */
2435 else if (code == CM_ERROR_BADLOGONTYPE) {
2436 NTStatus = 0xC000015BL; /* logon type not granted */
2438 else if (code == CM_ERROR_GSSCONTINUE) {
2439 NTStatus = 0xC0000016L; /* more processing required */
2441 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2443 NTStatus = 0xC0000280L; /* reparse point not resolved */
2445 NTStatus = 0xC0000022L; /* Access Denied */
2448 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2449 NTStatus = 0xC0000257L; /* Path Not Covered */
2452 else if (code == CM_ERROR_ALLBUSY) {
2453 NTStatus = 0xC00000BFL; /* Network Busy */
2455 else if (code == CM_ERROR_ALLOFFLINE) {
2456 NTStatus = 0xC0000350L; /* Remote Host Down */
2459 /* we do not want to be telling the SMB/CIFS client that
2460 * the AFS Client Service is busy or down.
2462 else if (code == CM_ERROR_ALLBUSY ||
2463 code == CM_ERROR_ALLOFFLINE) {
2464 NTStatus = 0xC00000BEL; /* Bad Network Path */
2468 NTStatus = 0xC0982001L; /* SMB non-specific error */
2471 *NTStatusp = NTStatus;
2472 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2475 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2476 unsigned char *classp)
2478 unsigned char class;
2479 unsigned short error;
2481 /* map CM_ERROR_* errors to SMB errors */
2482 if (code == CM_ERROR_NOSUCHCELL) {
2484 error = 3; /* bad path */
2486 else if (code == CM_ERROR_NOSUCHVOLUME) {
2488 error = 3; /* bad path */
2490 else if (code == CM_ERROR_TIMEDOUT) {
2492 error = 81; /* server is paused */
2494 else if (code == CM_ERROR_RETRY) {
2495 class = 2; /* shouldn't happen */
2498 else if (code == CM_ERROR_NOACCESS) {
2500 error = 4; /* bad access */
2502 else if (code == CM_ERROR_READONLY) {
2504 error = 19; /* read only */
2506 else if (code == CM_ERROR_NOSUCHFILE) {
2508 error = 2; /* ENOENT! */
2510 else if (code == CM_ERROR_NOSUCHPATH) {
2512 error = 3; /* Bad path */
2514 else if (code == CM_ERROR_TOOBIG) {
2516 error = 11; /* bad format */
2518 else if (code == CM_ERROR_INVAL) {
2519 class = 2; /* server non-specific error code */
2522 else if (code == CM_ERROR_BADFD) {
2524 error = 6; /* invalid file handle */
2526 else if (code == CM_ERROR_BADFDOP) {
2527 class = 1; /* invalid op on FD */
2530 else if (code == CM_ERROR_EXISTS) {
2532 error = 80; /* file already exists */
2534 else if (code == CM_ERROR_NOTEMPTY) {
2536 error = 5; /* delete directory not empty */
2538 else if (code == CM_ERROR_CROSSDEVLINK) {
2540 error = 17; /* EXDEV */
2542 else if (code == CM_ERROR_NOTDIR) {
2543 class = 1; /* bad path */
2546 else if (code == CM_ERROR_ISDIR) {
2547 class = 1; /* access denied; DOS doesn't have a good match */
2550 else if (code == CM_ERROR_BADOP) {
2554 else if (code == CM_ERROR_BADSHARENAME) {
2558 else if (code == CM_ERROR_NOIPC) {
2560 error = 4; /* bad access */
2562 else if (code == CM_ERROR_CLOCKSKEW) {
2563 class = 1; /* invalid function */
2566 else if (code == CM_ERROR_BADTID) {
2570 else if (code == CM_ERROR_USESTD) {
2574 else if (code == CM_ERROR_REMOTECONN) {
2578 else if (code == CM_ERROR_QUOTA) {
2579 if (vcp->flags & SMB_VCFLAG_USEV3) {
2581 error = 39; /* disk full */
2585 error = 5; /* access denied */
2588 else if (code == CM_ERROR_SPACE) {
2589 if (vcp->flags & SMB_VCFLAG_USEV3) {
2591 error = 39; /* disk full */
2595 error = 5; /* access denied */
2598 else if (code == CM_ERROR_PARTIALWRITE) {
2600 error = 39; /* disk full */
2602 else if (code == CM_ERROR_ATSYS) {
2604 error = 2; /* ENOENT */
2606 else if (code == CM_ERROR_WOULDBLOCK) {
2608 error = 33; /* lock conflict */
2610 else if (code == CM_ERROR_LOCK_CONFLICT) {
2612 error = 33; /* lock conflict */
2614 else if (code == CM_ERROR_SHARING_VIOLATION) {
2616 error = 33; /* lock conflict */
2618 else if (code == CM_ERROR_NOFILES) {
2620 error = 18; /* no files in search */
2622 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2624 error = 183; /* Samba uses this */
2626 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2627 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2629 error = 2; /* bad password */
2631 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2633 error = 3; /* bad path */
2642 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2645 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2647 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2648 return CM_ERROR_BADOP;
2651 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2653 unsigned short EchoCount, i;
2654 char *data, *outdata;
2657 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2659 for (i=1; i<=EchoCount; i++) {
2660 data = smb_GetSMBData(inp, &dataSize);
2661 smb_SetSMBParm(outp, 0, i);
2662 smb_SetSMBDataLength(outp, dataSize);
2663 outdata = smb_GetSMBData(outp, NULL);
2664 memcpy(outdata, data, dataSize);
2665 smb_SendPacket(vcp, outp);
2671 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2674 long count, minCount, finalCount;
2679 cm_user_t *userp = NULL;
2683 char *rawBuf = NULL;
2685 dos_ptr rawBuf = NULL;
2692 fd = smb_GetSMBParm(inp, 0);
2693 count = smb_GetSMBParm(inp, 3);
2694 minCount = smb_GetSMBParm(inp, 4);
2695 offset.HighPart = 0; /* too bad */
2696 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2698 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2699 fd, offset.LowPart, count);
2701 fidp = smb_FindFID(vcp, fd, 0);
2705 pid = ((smb_t *) inp)->pid;
2707 LARGE_INTEGER LOffset, LLength;
2710 key = cm_GenerateKey(vcp->vcID, pid, fd);
2712 LOffset.HighPart = 0;
2713 LOffset.LowPart = offset.LowPart;
2714 LLength.HighPart = 0;
2715 LLength.LowPart = count;
2717 lock_ObtainMutex(&fidp->scp->mx);
2718 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2719 lock_ReleaseMutex(&fidp->scp->mx);
2725 lock_ObtainMutex(&smb_RawBufLock);
2727 /* Get a raw buf, from head of list */
2728 rawBuf = smb_RawBufs;
2730 smb_RawBufs = *(char **)smb_RawBufs;
2732 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2735 lock_ReleaseMutex(&smb_RawBufLock);
2739 if (fidp->flags & SMB_FID_IOCTL)
2742 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2744 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2747 /* Give back raw buffer */
2748 lock_ObtainMutex(&smb_RawBufLock);
2750 *((char **) rawBuf) = smb_RawBufs;
2752 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2755 smb_RawBufs = rawBuf;
2756 lock_ReleaseMutex(&smb_RawBufLock);
2759 smb_ReleaseFID(fidp);
2763 userp = smb_GetUser(vcp, inp);
2766 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2768 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2769 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2770 userp, &finalCount, TRUE /* rawFlag */);
2777 cm_ReleaseUser(userp);
2780 smb_ReleaseFID(fidp);
2785 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2787 memset((char *)ncbp, 0, sizeof(NCB));
2789 ncbp->ncb_length = (unsigned short) finalCount;
2790 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2791 ncbp->ncb_lana_num = vcp->lana;
2792 ncbp->ncb_command = NCBSEND;
2793 ncbp->ncb_buffer = rawBuf;
2796 code = Netbios(ncbp);
2798 code = Netbios(ncbp, dos_ncb);
2801 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2804 /* Give back raw buffer */
2805 lock_ObtainMutex(&smb_RawBufLock);
2807 *((char **) rawBuf) = smb_RawBufs;
2809 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2812 smb_RawBufs = rawBuf;
2813 lock_ReleaseMutex(&smb_RawBufLock);
2819 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2821 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2826 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2828 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2833 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2840 int protoIndex; /* index we're using */
2845 char protocol_array[10][1024]; /* protocol signature of the client */
2846 int caps; /* capabilities */
2849 TIME_ZONE_INFORMATION tzi;
2851 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2855 DWORD now = GetCurrentTime();
2856 if (now - last_msg_time >= 30000
2857 && now - last_msg_time <= 90000) {
2859 "Setting dead_vcp %x", active_vcp);
2861 smb_ReleaseVC(dead_vcp);
2863 "Previous dead_vcp %x", dead_vcp);
2865 smb_HoldVC(active_vcp);
2866 dead_vcp = active_vcp;
2867 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2872 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2874 namep = smb_GetSMBData(inp, &dbytes);
2877 coreProtoIndex = -1; /* not found */
2880 while(namex < dbytes) {
2881 osi_Log1(smb_logp, "Protocol %s",
2882 osi_LogSaveString(smb_logp, namep+1));
2883 strcpy(protocol_array[tcounter], namep+1);
2885 /* namep points at the first protocol, or really, a 0x02
2886 * byte preceding the null-terminated ASCII name.
2888 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2889 coreProtoIndex = tcounter;
2891 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2892 v3ProtoIndex = tcounter;
2894 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2895 NTProtoIndex = tcounter;
2898 /* compute size of protocol entry */
2899 entryLength = strlen(namep+1);
2900 entryLength += 2; /* 0x02 bytes and null termination */
2902 /* advance over this protocol entry */
2903 namex += entryLength;
2904 namep += entryLength;
2905 tcounter++; /* which proto entry we're looking at */
2908 if (NTProtoIndex != -1) {
2909 protoIndex = NTProtoIndex;
2910 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2912 else if (v3ProtoIndex != -1) {
2913 protoIndex = v3ProtoIndex;
2914 vcp->flags |= SMB_VCFLAG_USEV3;
2916 else if (coreProtoIndex != -1) {
2917 protoIndex = coreProtoIndex;
2918 vcp->flags |= SMB_VCFLAG_USECORE;
2920 else protoIndex = -1;
2922 if (protoIndex == -1)
2923 return CM_ERROR_INVAL;
2924 else if (NTProtoIndex != -1) {
2925 smb_SetSMBParm(outp, 0, protoIndex);
2926 if (smb_authType != SMB_AUTH_NONE) {
2927 smb_SetSMBParmByte(outp, 1,
2928 NEGOTIATE_SECURITY_USER_LEVEL |
2929 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2931 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2933 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2934 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2935 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2936 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2937 /* The session key is not a well documented field however most clients
2938 * will echo back the session key to the server. Currently we are using
2939 * the same value for all sessions. We should generate a random value
2940 * and store it into the vcp
2942 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2943 smb_SetSMBParm(outp, 8, 1);
2945 * Tried changing the capabilities to support for W2K - defect 117695
2946 * Maybe something else needs to be changed here?
2950 smb_SetSMBParmLong(outp, 9, 0x43fd);
2952 smb_SetSMBParmLong(outp, 9, 0x251);
2955 * 32-bit error codes *
2960 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2962 NTNEGOTIATE_CAPABILITY_DFS |
2964 NTNEGOTIATE_CAPABILITY_NTFIND |
2965 NTNEGOTIATE_CAPABILITY_RAWMODE |
2966 NTNEGOTIATE_CAPABILITY_NTSMB;
2968 if ( smb_authType == SMB_AUTH_EXTENDED )
2969 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2971 smb_SetSMBParmLong(outp, 9, caps);
2973 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2974 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2975 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2977 GetTimeZoneInformation(&tzi);
2978 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2980 if (smb_authType == SMB_AUTH_NTLM) {
2981 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2982 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2983 /* paste in encryption key */
2984 datap = smb_GetSMBData(outp, NULL);
2985 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2986 /* and the faux domain name */
2987 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2988 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2992 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2994 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2996 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2998 datap = smb_GetSMBData(outp, NULL);
2999 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3002 datap += sizeof(smb_ServerGUID);
3003 memcpy(datap, secBlob, secBlobLength);
3007 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3008 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3011 else if (v3ProtoIndex != -1) {
3012 smb_SetSMBParm(outp, 0, protoIndex);
3014 /* NOTE: Extended authentication cannot be negotiated with v3
3015 * therefore we fail over to NTLM
3017 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3018 smb_SetSMBParm(outp, 1,
3019 NEGOTIATE_SECURITY_USER_LEVEL |
3020 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3022 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3024 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3025 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3026 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3027 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3028 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3029 smb_SetSMBParm(outp, 7, 1);
3031 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3032 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3033 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3035 GetTimeZoneInformation(&tzi);
3036 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3038 /* NOTE: Extended authentication cannot be negotiated with v3
3039 * therefore we fail over to NTLM
3041 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3042 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3043 smb_SetSMBParm(outp, 12, 0); /* resvd */
3044 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3045 datap = smb_GetSMBData(outp, NULL);
3046 /* paste in a new encryption key */
3047 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3048 /* and the faux domain name */
3049 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3051 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3052 smb_SetSMBParm(outp, 12, 0); /* resvd */
3053 smb_SetSMBDataLength(outp, 0);
3056 else if (coreProtoIndex != -1) { /* not really supported anymore */
3057 smb_SetSMBParm(outp, 0, protoIndex);
3058 smb_SetSMBDataLength(outp, 0);
3063 void smb_Daemon(void *parmp)
3065 afs_uint32 count = 0;
3067 while(smbShutdownFlag == 0) {
3071 if (smbShutdownFlag == 1)
3074 if ((count % 72) == 0) { /* every five minutes */
3076 time_t old_localZero = smb_localZero;
3078 /* Initialize smb_localZero */
3079 myTime.tm_isdst = -1; /* compute whether on DST or not */
3080 myTime.tm_year = 70;
3086 smb_localZero = mktime(&myTime);
3088 #ifndef USE_NUMERIC_TIME_CONV
3089 smb_CalculateNowTZ();
3090 #endif /* USE_NUMERIC_TIME_CONV */
3091 #ifdef AFS_FREELANCE
3092 if ( smb_localZero != old_localZero )
3093 cm_noteLocalMountPointChange();
3096 /* XXX GC dir search entries */
3100 void smb_WaitingLocksDaemon()
3102 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3103 smb_waitingLock_t *wl, *wlNext;
3106 smb_packet_t *inp, *outp;
3110 while (smbShutdownFlag == 0) {
3111 lock_ObtainWrite(&smb_globalLock);
3112 nwlRequest = smb_allWaitingLocks;
3113 if (nwlRequest == NULL) {
3114 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
3124 lock_ObtainWrite(&smb_globalLock);
3126 wlRequest = nwlRequest;
3127 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3128 lock_ReleaseWrite(&smb_globalLock);
3132 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3133 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3136 /* wl->state is either _DONE or _WAITING. _ERROR
3137 would no longer be on the queue. */
3138 code = cm_RetryLock( wl->lockp,
3139 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3142 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3143 } else if (code != CM_ERROR_WOULDBLOCK) {
3144 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3149 if (code == CM_ERROR_WOULDBLOCK) {
3152 if (wlRequest->timeRemaining != 0xffffffff
3153 && (wlRequest->timeRemaining -= 1000) < 0)
3165 scp = wlRequest->scp;
3169 lock_ObtainMutex(&scp->mx);
3171 for (wl = wlRequest->locks; wl; wl = wlNext) {
3172 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3174 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3175 wl->LLength, wl->key, NULL, &req);
3177 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3182 lock_ReleaseMutex(&scp->mx);
3185 for (wl = wlRequest->locks; wl; wl = wlNext) {
3186 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3187 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3192 vcp = wlRequest->vcp;
3193 inp = wlRequest->inp;
3194 outp = wlRequest->outp;
3196 ncbp->ncb_length = inp->ncb_length;
3197 inp->spacep = cm_GetSpace();
3199 /* Remove waitingLock from list */
3200 lock_ObtainWrite(&smb_globalLock);
3201 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3203 lock_ReleaseWrite(&smb_globalLock);
3205 /* Resume packet processing */
3207 smb_SetSMBDataLength(outp, 0);
3208 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3209 outp->resumeCode = code;
3211 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3214 cm_FreeSpace(inp->spacep);
3215 smb_FreePacket(inp);
3216 smb_FreePacket(outp);
3218 cm_ReleaseSCache(wlRequest->scp);
3221 } while (nwlRequest && smbShutdownFlag == 0);
3226 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3228 osi_Log0(smb_logp, "SMB receive get disk attributes");
3230 smb_SetSMBParm(outp, 0, 32000);
3231 smb_SetSMBParm(outp, 1, 64);
3232 smb_SetSMBParm(outp, 2, 1024);
3233 smb_SetSMBParm(outp, 3, 30000);
3234 smb_SetSMBParm(outp, 4, 0);
3235 smb_SetSMBDataLength(outp, 0);
3239 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3243 unsigned short newTid;
3244 char shareName[256];
3252 osi_Log0(smb_logp, "SMB receive tree connect");
3254 /* parse input parameters */
3255 tp = smb_GetSMBData(inp, NULL);
3256 pathp = smb_ParseASCIIBlock(tp, &tp);
3257 if (smb_StoreAnsiFilenames)
3258 OemToChar(pathp,pathp);
3259 passwordp = smb_ParseASCIIBlock(tp, &tp);
3260 tp = strrchr(pathp, '\\');
3262 return CM_ERROR_BADSMB;
3263 strcpy(shareName, tp+1);
3265 userp = smb_GetUser(vcp, inp);
3267 lock_ObtainMutex(&vcp->mx);
3268 newTid = vcp->tidCounter++;
3269 lock_ReleaseMutex(&vcp->mx);
3271 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3272 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3273 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3275 smb_ReleaseUID(uidp);
3277 smb_ReleaseTID(tidp);
3278 return CM_ERROR_BADSHARENAME;
3280 lock_ObtainMutex(&tidp->mx);
3281 tidp->userp = userp;
3282 tidp->pathname = sharePath;
3283 lock_ReleaseMutex(&tidp->mx);
3284 smb_ReleaseTID(tidp);
3286 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3287 smb_SetSMBParm(rsp, 1, newTid);
3288 smb_SetSMBDataLength(rsp, 0);
3290 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3294 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3298 if (*inp++ != 0x1) return NULL;
3299 tlen = inp[0] + (inp[1]<<8);
3300 inp += 2; /* skip length field */
3303 *chainpp = inp + tlen;
3306 if (lengthp) *lengthp = tlen;
3311 /* set maskp to the mask part of the incoming path.
3312 * Mask is 11 bytes long (8.3 with the dot elided).
3313 * Returns true if succeeds with a valid name, otherwise it does
3314 * its best, but returns false.
3316 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3324 /* starts off valid */
3327 /* mask starts out all blanks */
3328 memset(maskp, ' ', 11);
3330 /* find last backslash, or use whole thing if there is none */
3331 tp = strrchr(pathp, '\\');
3332 if (!tp) tp = pathp;
3333 else tp++; /* skip slash */
3337 /* names starting with a dot are illegal */
3338 if (*tp == '.') valid8Dot3 = 0;
3342 if (tc == 0) return valid8Dot3;
3343 if (tc == '.' || tc == '"') break;
3344 if (i < 8) *up++ = tc;
3345 else valid8Dot3 = 0;
3348 /* if we get here, tp point after the dot */
3349 up = maskp+8; /* ext goes here */
3356 if (tc == '.' || tc == '"')
3359 /* copy extension if not too long */
3369 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3379 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3381 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3385 /* otherwise, we have a valid 8.3 name; see if we have a match,
3386 * treating '?' as a wildcard in maskp (but not in the file name).
3388 tp1 = umask; /* real name, in mask format */
3389 tp2 = maskp; /* mask, in mask format */
3390 for(i=0; i<11; i++) {
3391 tc1 = *tp1++; /* char from real name */
3392 tc2 = *tp2++; /* char from mask */
3393 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3394 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3397 if (tc2 == '?' && tc1 != ' ')
3404 /* we got a match */
3408 char *smb_FindMask(char *pathp)
3412 tp = strrchr(pathp, '\\'); /* find last slash */
3415 return tp+1; /* skip the slash */
3417 return pathp; /* no slash, return the entire path */
3420 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3422 unsigned char *pathp;
3424 unsigned char mask[11];
3425 unsigned char *statBlockp;
3426 unsigned char initStatBlock[21];
3429 osi_Log0(smb_logp, "SMB receive search volume");
3431 /* pull pathname and stat block out of request */
3432 tp = smb_GetSMBData(inp, NULL);
3433 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3434 osi_assert(pathp != NULL);
3435 if (smb_StoreAnsiFilenames)
3436 OemToChar(pathp,pathp);
3437 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3438 osi_assert(statBlockp != NULL);
3440 statBlockp = initStatBlock;
3444 /* for returning to caller */
3445 smb_Get8Dot3MaskFromPath(mask, pathp);
3447 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3448 tp = smb_GetSMBData(outp, NULL);
3450 *tp++ = 43; /* bytes in a dir entry */
3451 *tp++ = 0; /* high byte in counter */
3453 /* now marshall the dir entry, starting with the search status */
3454 *tp++ = statBlockp[0]; /* Reserved */
3455 memcpy(tp, mask, 11); tp += 11; /* FileName */
3457 /* now pass back server use info, with 1st byte non-zero */
3459 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3461 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3463 *tp++ = 0x8; /* attribute: volume */
3473 /* 4 byte file size */
3479 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3480 memset(tp, ' ', 13);
3483 /* set the length of the data part of the packet to 43 + 3, for the dir
3484 * entry plus the 5 and the length fields.
3486 smb_SetSMBDataLength(outp, 46);
3490 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3491 cm_user_t *userp, cm_req_t *reqp)
3499 smb_dirListPatch_t *patchp;
3500 smb_dirListPatch_t *npatchp;
3502 for (patchp = *dirPatchespp; patchp; patchp =
3503 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3505 dptr = patchp->dptr;
3507 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3509 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3510 *dptr++ = SMB_ATTR_HIDDEN;
3513 lock_ObtainMutex(&scp->mx);
3514 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3515 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3517 lock_ReleaseMutex(&scp->mx);
3518 cm_ReleaseSCache(scp);
3519 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3520 *dptr++ = SMB_ATTR_HIDDEN;
3524 attr = smb_Attributes(scp);
3525 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3526 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3527 attr |= SMB_ATTR_HIDDEN;
3531 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3534 shortTemp = (unsigned short) (dosTime & 0xffff);
3535 *((u_short *)dptr) = shortTemp;
3538 /* and copy out date */
3539 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3540 *((u_short *)dptr) = shortTemp;
3543 /* copy out file length */
3544 *((u_long *)dptr) = scp->length.LowPart;
3546 lock_ReleaseMutex(&scp->mx);
3547 cm_ReleaseSCache(scp);
3550 /* now free the patches */
3551 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3552 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3556 /* and mark the list as empty */
3557 *dirPatchespp = NULL;
3562 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3571 smb_dirListPatch_t *dirListPatchesp;
3572 smb_dirListPatch_t *curPatchp;
3576 osi_hyper_t dirLength;
3577 osi_hyper_t bufferOffset;
3578 osi_hyper_t curOffset;
3580 unsigned char *inCookiep;
3581 smb_dirSearch_t *dsp;
3585 unsigned long clientCookie;
3586 cm_pageHeader_t *pageHeaderp;
3587 cm_user_t *userp = NULL;
3594 long nextEntryCookie;
3595 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3596 char resByte; /* reserved byte from the cookie */
3597 char *op; /* output data ptr */
3598 char *origOp; /* original value of op */
3599 cm_space_t *spacep; /* for pathname buffer */
3610 maxCount = smb_GetSMBParm(inp, 0);
3612 dirListPatchesp = NULL;
3614 caseFold = CM_FLAG_CASEFOLD;
3616 tp = smb_GetSMBData(inp, NULL);
3617 pathp = smb_ParseASCIIBlock(tp, &tp);
3618 if (smb_StoreAnsiFilenames)
3619 OemToChar(pathp,pathp);
3620 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3622 /* bail out if request looks bad */
3623 if (!tp || !pathp) {
3624 return CM_ERROR_BADSMB;
3627 /* We can handle long names */
3628 if (vcp->flags & SMB_VCFLAG_USENT)
3629 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3631 /* make sure we got a whole search status */
3632 if (dataLength < 21) {
3633 nextCookie = 0; /* start at the beginning of the dir */
3636 attribute = smb_GetSMBParm(inp, 1);
3638 /* handle volume info in another function */
3639 if (attribute & 0x8)
3640 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3642 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3643 maxCount, osi_LogSaveString(smb_logp, pathp));
3645 if (*pathp == 0) { /* null pathp, treat as root dir */
3646 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3647 return CM_ERROR_NOFILES;
3651 dsp = smb_NewDirSearch(0);
3652 dsp->attribute = attribute;
3653 smb_Get8Dot3MaskFromPath(mask, pathp);
3654 memcpy(dsp->mask, mask, 11);
3656 /* track if this is likely to match a lot of entries */
3657 if (smb_IsStarMask(mask))
3662 /* pull the next cookie value out of the search status block */
3663 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3664 + (inCookiep[16]<<24);
3665 dsp = smb_FindDirSearch(inCookiep[12]);
3667 /* can't find dir search status; fatal error */
3668 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3669 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3670 return CM_ERROR_BADFD;
3672 attribute = dsp->attribute;
3673 resByte = inCookiep[0];
3675 /* copy out client cookie, in host byte order. Don't bother
3676 * interpreting it, since we're just passing it through, anyway.
3678 memcpy(&clientCookie, &inCookiep[17], 4);
3680 memcpy(mask, dsp->mask, 11);
3682 /* assume we're doing a star match if it has continued for more
3688 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3689 nextCookie, dsp->cookie, attribute);
3691 userp = smb_GetUser(vcp, inp);
3693 /* try to get the vnode for the path name next */
3694 lock_ObtainMutex(&dsp->mx);
3700 spacep = inp->spacep;
3701 smb_StripLastComponent(spacep->data, NULL, pathp);
3702 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3704 lock_ReleaseMutex(&dsp->mx);
3705 cm_ReleaseUser(userp);
3706 smb_DeleteDirSearch(dsp);
3707 smb_ReleaseDirSearch(dsp);
3708 return CM_ERROR_NOFILES;
3710 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3711 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3714 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3715 cm_ReleaseSCache(scp);
3716 lock_ReleaseMutex(&dsp->mx);
3717 cm_ReleaseUser(userp);
3718 smb_DeleteDirSearch(dsp);
3719 smb_ReleaseDirSearch(dsp);
3720 if ( WANTS_DFS_PATHNAMES(inp) )
3721 return CM_ERROR_PATH_NOT_COVERED;
3723 return CM_ERROR_BADSHARENAME;
3725 #endif /* DFS_SUPPORT */
3728 /* we need one hold for the entry we just stored into,
3729 * and one for our own processing. When we're done with this
3730 * function, we'll drop the one for our own processing.
3731 * We held it once from the namei call, and so we do another hold