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 time_t diff_t = unixTime - smb_localZero;
797 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
798 osi_assert(diff_t < _UI32_MAX);
800 *dosUTimep = (afs_uint32)diff_t;
803 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
806 *unixTimep = dosTime + smb_localZero;
808 /* dosTime seems to be already adjusted for GMT */
809 *unixTimep = dosTime;
813 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
817 lock_ObtainWrite(&smb_rctLock);
818 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
819 if (lsn == vcp->lsn && lana == vcp->lana) {
820 smb_HoldVCNoLock(vcp);
824 if (!vcp && (flags & SMB_FLAG_CREATE)) {
825 vcp = malloc(sizeof(*vcp));
826 memset(vcp, 0, sizeof(*vcp));
827 vcp->vcID = numVCs++;
831 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
832 vcp->nextp = smb_allVCsp;
834 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
839 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
840 /* We must obtain a challenge for extended auth
841 * in case the client negotiates smb v3
843 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
844 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
845 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
846 ULONG lsaRespSize = 0;
848 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
850 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
857 if (nts != STATUS_SUCCESS)
858 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
859 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
860 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
862 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
863 LsaFreeReturnBuffer(lsaResp);
866 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
868 if (numVCs >= CM_SESSION_RESERVED) {
870 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
873 lock_ReleaseWrite(&smb_rctLock);
877 int smb_IsStarMask(char *maskp)
882 for(i=0; i<11; i++) {
884 if (tc == '?' || tc == '*' || tc == '>') return 1;
889 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
891 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
893 osi_assert(vcp->refCount-- != 0);
899 void smb_ReleaseVC(smb_vc_t *vcp)
901 lock_ObtainWrite(&smb_rctLock);
902 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
904 osi_assert(vcp->refCount-- != 0);
908 lock_ReleaseWrite(&smb_rctLock);
911 void smb_HoldVCNoLock(smb_vc_t *vcp)
914 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
917 void smb_HoldVC(smb_vc_t *vcp)
919 lock_ObtainWrite(&smb_rctLock);
921 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
922 lock_ReleaseWrite(&smb_rctLock);
925 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
929 lock_ObtainWrite(&smb_rctLock);
930 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
931 if (tid == tidp->tid) {
936 if (!tidp && (flags & SMB_FLAG_CREATE)) {
937 tidp = malloc(sizeof(*tidp));
938 memset(tidp, 0, sizeof(*tidp));
939 tidp->nextp = vcp->tidsp;
942 smb_HoldVCNoLock(vcp);
944 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
947 lock_ReleaseWrite(&smb_rctLock);
951 void smb_ReleaseTID(smb_tid_t *tidp)
958 lock_ObtainWrite(&smb_rctLock);
959 osi_assert(tidp->refCount-- > 0);
960 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
961 ltpp = &tidp->vcp->tidsp;
962 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
966 osi_assert(tp != NULL);
968 lock_FinalizeMutex(&tidp->mx);
969 userp = tidp->userp; /* remember to drop ref later */
971 smb_ReleaseVCNoLock(tidp->vcp);
974 lock_ReleaseWrite(&smb_rctLock);
976 cm_ReleaseUser(userp);
979 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
981 smb_user_t *uidp = NULL;
983 lock_ObtainWrite(&smb_rctLock);
984 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
985 if (uid == uidp->userID) {
987 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
989 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
993 if (!uidp && (flags & SMB_FLAG_CREATE)) {
994 uidp = malloc(sizeof(*uidp));
995 memset(uidp, 0, sizeof(*uidp));
996 uidp->nextp = vcp->usersp;
999 smb_HoldVCNoLock(vcp);
1001 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1003 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1005 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1007 lock_ReleaseWrite(&smb_rctLock);
1011 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1013 smb_username_t *unp= NULL;
1015 lock_ObtainWrite(&smb_rctLock);
1016 for(unp = usernamesp; unp; unp = unp->nextp) {
1017 if (stricmp(unp->name, usern) == 0 &&
1018 stricmp(unp->machine, machine) == 0) {
1023 if (!unp && (flags & SMB_FLAG_CREATE)) {
1024 unp = malloc(sizeof(*unp));
1025 memset(unp, 0, sizeof(*unp));
1027 unp->nextp = usernamesp;
1028 unp->name = strdup(usern);
1029 unp->machine = strdup(machine);
1031 lock_InitializeMutex(&unp->mx, "username_t mutex");
1033 lock_ReleaseWrite(&smb_rctLock);
1037 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1039 smb_user_t *uidp= NULL;
1041 lock_ObtainWrite(&smb_rctLock);
1042 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1045 if (stricmp(uidp->unp->name, usern) == 0) {
1047 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1048 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1053 lock_ReleaseWrite(&smb_rctLock);
1056 void smb_ReleaseUID(smb_user_t *uidp)
1063 lock_ObtainWrite(&smb_rctLock);
1064 osi_assert(uidp->refCount-- > 0);
1065 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1066 lupp = &uidp->vcp->usersp;
1067 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1071 osi_assert(up != NULL);
1073 lock_FinalizeMutex(&uidp->mx);
1075 userp = uidp->unp->userp; /* avoid deadlock by releasing */
1076 uidp->unp->userp = NULL; /* after releasing the lock */
1078 smb_ReleaseVCNoLock(uidp->vcp);
1081 lock_ReleaseWrite(&smb_rctLock);
1083 cm_ReleaseUserVCRef(userp);
1084 cm_ReleaseUser(userp);
1089 /* retrieve a held reference to a user structure corresponding to an incoming
1091 * corresponding release function is cm_ReleaseUser.
1093 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1099 smbp = (smb_t *) inp;
1100 uidp = smb_FindUID(vcp, smbp->uid, 0);
1101 if ((!uidp) || (!uidp->unp))
1104 lock_ObtainMutex(&uidp->mx);
1105 up = uidp->unp->userp;
1107 lock_ReleaseMutex(&uidp->mx);
1109 smb_ReleaseUID(uidp);
1115 * Return a pointer to a pathname extracted from a TID structure. The
1116 * TID structure is not held; assume it won't go away.
1118 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1123 tidp = smb_FindTID(vcp, tid, 0);
1127 if (tidp->flags & SMB_TIDFLAG_IPC) {
1128 code = CM_ERROR_TIDIPC;
1129 /* tidp->pathname would be NULL, but that's fine */
1131 *treepath = tidp->pathname;
1132 smb_ReleaseTID(tidp);
1137 /* check to see if we have a chained fid, that is, a fid that comes from an
1138 * OpenAndX message that ran earlier in this packet. In this case, the fid
1139 * field in a read, for example, request, isn't set, since the value is
1140 * supposed to be inherited from the openAndX call.
1142 int smb_ChainFID(int fid, smb_packet_t *inp)
1144 if (inp->fid == 0 || inp->inCount == 0)
1150 /* are we a priv'd user? What does this mean on NT? */
1151 int smb_SUser(cm_user_t *userp)
1156 /* find a file ID. If we pass in 0 we select an unused File ID.
1157 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1158 * smb_fid_t data structure if desired File ID cannot be found.
1160 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1165 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1168 lock_ObtainWrite(&smb_rctLock);
1169 /* figure out if we need to allocate a new file ID */
1172 fid = vcp->fidCounter;
1176 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1177 if (fid == fidp->fid) {
1189 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1190 char eventName[MAX_PATH];
1192 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1193 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1194 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1195 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1196 thrd_CloseHandle(event);
1203 fidp = malloc(sizeof(*fidp));
1204 memset(fidp, 0, sizeof(*fidp));
1205 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1208 smb_HoldVCNoLock(vcp);
1209 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1211 fidp->curr_chunk = fidp->prev_chunk = -2;
1212 fidp->raw_write_event = event;
1214 vcp->fidCounter = fid+1;
1215 if (vcp->fidCounter == 0)
1216 vcp->fidCounter = 1;
1220 lock_ReleaseWrite(&smb_rctLock);
1224 void smb_ReleaseFID(smb_fid_t *fidp)
1227 smb_vc_t *vcp = NULL;
1228 smb_ioctl_t *ioctlp;
1234 lock_ObtainWrite(&smb_rctLock);
1235 osi_assert(fidp->refCount-- > 0);
1236 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1239 scp = fidp->scp; /* release after lock is released */
1242 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1243 thrd_CloseHandle(fidp->raw_write_event);
1245 /* and see if there is ioctl stuff to free */
1246 ioctlp = fidp->ioctlp;
1249 cm_FreeSpace(ioctlp->prefix);
1250 if (ioctlp->inAllocp)
1251 free(ioctlp->inAllocp);
1252 if (ioctlp->outAllocp)
1253 free(ioctlp->outAllocp);
1259 smb_ReleaseVCNoLock(vcp);
1261 lock_ReleaseWrite(&smb_rctLock);
1263 /* now release the scache structure */
1265 cm_ReleaseSCache(scp);
1269 * Case-insensitive search for one string in another;
1270 * used to find variable names in submount pathnames.
1272 static char *smb_stristr(char *str1, char *str2)
1276 for (cursor = str1; *cursor; cursor++)
1277 if (stricmp(cursor, str2) == 0)
1284 * Substitute a variable value for its name in a submount pathname. Variable
1285 * name has been identified by smb_stristr() and is in substr. Variable name
1286 * length (plus one) is in substr_size. Variable value is in newstr.
1288 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1293 strcpy(temp, substr + substr_size - 1);
1294 strcpy(substr, newstr);
1298 char VNUserName[] = "%USERNAME%";
1299 char VNLCUserName[] = "%LCUSERNAME%";
1300 char VNComputerName[] = "%COMPUTERNAME%";
1301 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1304 /* List available shares */
1305 int smb_ListShares()
1309 char shareBuf[4096];
1317 /*strcpy(shareNameList[num_shares], "all");
1318 strcpy(pathNameList[num_shares++], "/afs");*/
1319 fprintf(stderr, "The following shares are available:\n");
1320 fprintf(stderr, "Share Name (AFS Path)\n");
1321 fprintf(stderr, "---------------------\n");
1322 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1325 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1326 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1328 strcpy(sbmtpath, cm_confDir);
1330 strcat(sbmtpath, "/afsdsbmt.ini");
1331 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1332 shareBuf, sizeof(shareBuf),
1338 this_share = shareBuf;
1342 /*strcpy(shareNameList[num_shares], this_share);*/
1343 len = GetPrivateProfileString("AFS Submounts", this_share,
1350 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1353 if (*p == '\\') *p = '/'; /* change to / */
1357 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1358 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1361 while (*this_share != 0) this_share++; /* find next NUL */
1362 this_share++; /* skip past the NUL */
1363 } while (*this_share != 0); /* stop at final NUL */
1369 typedef struct smb_findShare_rock {
1373 } smb_findShare_rock_t;
1375 #define SMB_FINDSHARE_EXACT_MATCH 1
1376 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1378 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1382 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1383 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1384 if(!stricmp(dep->name, vrock->shareName))
1385 matchType = SMB_FINDSHARE_EXACT_MATCH;
1387 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1388 if(vrock->match) free(vrock->match);
1389 vrock->match = strdup(dep->name);
1390 vrock->matchType = matchType;
1392 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1393 return CM_ERROR_STOPNOW;
1399 /* find a shareName in the table of submounts */
1400 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1404 char pathName[1024];
1409 char sbmtpath[MAX_PATH];
1414 DWORD allSubmount = 1;
1416 /* if allSubmounts == 0, only return the //mountRoot/all share
1417 * if in fact it has been been created in the subMounts table.
1418 * This is to allow sites that want to restrict access to the
1421 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1422 0, KEY_QUERY_VALUE, &parmKey);
1423 if (code == ERROR_SUCCESS) {
1424 len = sizeof(allSubmount);
1425 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1426 (BYTE *) &allSubmount, &len);
1427 if (code != ERROR_SUCCESS) {
1430 RegCloseKey (parmKey);
1433 if (allSubmount && _stricmp(shareName, "all") == 0) {
1438 /* In case, the all share is disabled we need to still be able
1439 * to handle ioctl requests
1441 if (_stricmp(shareName, "ioctl$") == 0) {
1442 *pathNamep = strdup("/.__ioctl__");
1446 if (_stricmp(shareName, "IPC$") == 0 ||
1447 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1448 _stricmp(shareName, "DESKTOP.INI") == 0
1455 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1456 0, KEY_QUERY_VALUE, &parmKey);
1457 if (code == ERROR_SUCCESS) {
1458 len = sizeof(pathName);
1459 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1460 (BYTE *) pathName, &len);
1461 if (code != ERROR_SUCCESS)
1463 RegCloseKey (parmKey);
1468 strcpy(sbmtpath, cm_confDir);
1469 strcat(sbmtpath, "/afsdsbmt.ini");
1470 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1471 pathName, sizeof(pathName), sbmtpath);
1473 if (len != 0 && len != sizeof(pathName) - 1) {
1474 /* We can accept either unix or PC style AFS pathnames. Convert
1475 * Unix-style to PC style here for internal use.
1478 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1479 p += strlen(cm_mountRoot); /* skip mount path */
1482 if (*q == '/') *q = '\\'; /* change to \ */
1488 if (var = smb_stristr(p, VNUserName)) {
1489 if (uidp && uidp->unp)
1490 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1492 smb_subst(p, var, sizeof(VNUserName)," ");
1494 else if (var = smb_stristr(p, VNLCUserName))
1496 if (uidp && uidp->unp)
1497 strcpy(temp, uidp->unp->name);
1501 smb_subst(p, var, sizeof(VNLCUserName), temp);
1503 else if (var = smb_stristr(p, VNComputerName))
1505 sizeTemp = sizeof(temp);
1506 GetComputerName((LPTSTR)temp, &sizeTemp);
1507 smb_subst(p, var, sizeof(VNComputerName), temp);
1509 else if (var = smb_stristr(p, VNLCComputerName))
1511 sizeTemp = sizeof(temp);
1512 GetComputerName((LPTSTR)temp, &sizeTemp);
1514 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1519 *pathNamep = strdup(p);
1524 /* First lookup shareName in root.afs */
1526 smb_findShare_rock_t vrock;
1528 char * p = shareName;
1531 /* attempt to locate a partial match in root.afs. This is because
1532 when using the ANSI RAP calls, the share name is limited to 13 chars
1533 and hence is truncated. Of course we prefer exact matches. */
1535 thyper.HighPart = 0;
1538 vrock.shareName = shareName;
1540 vrock.matchType = 0;
1542 cm_HoldSCache(cm_data.rootSCachep);
1543 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1544 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1545 cm_ReleaseSCache(cm_data.rootSCachep);
1547 if (vrock.matchType) {
1548 sprintf(pathName,"/%s/",vrock.match);
1549 *pathNamep = strdup(strlwr(pathName));
1554 /* if we get here, there was no match for the share in root.afs */
1555 /* so try to create \\<netbiosName>\<cellname> */
1560 /* Get the full name for this cell */
1561 code = cm_SearchCellFile(p, temp, 0, 0);
1562 #ifdef AFS_AFSDB_ENV
1563 if (code && cm_dnsEnabled) {
1565 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1568 /* construct the path */
1570 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1571 *pathNamep = strdup(strlwr(pathName));
1580 /* Client-side offline caching policy types */
1581 #define CSC_POLICY_MANUAL 0
1582 #define CSC_POLICY_DOCUMENTS 1
1583 #define CSC_POLICY_PROGRAMS 2
1584 #define CSC_POLICY_DISABLE 3
1586 int smb_FindShareCSCPolicy(char *shareName)
1592 int retval = CSC_POLICY_MANUAL;
1594 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1595 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1598 REG_OPTION_NON_VOLATILE,
1604 len = sizeof(policy);
1605 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1607 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1609 else if (stricmp(policy, "documents") == 0)
1611 retval = CSC_POLICY_DOCUMENTS;
1613 else if (stricmp(policy, "programs") == 0)
1615 retval = CSC_POLICY_PROGRAMS;
1617 else if (stricmp(policy, "disable") == 0)
1619 retval = CSC_POLICY_DISABLE;
1622 RegCloseKey(hkCSCPolicy);
1626 /* find a dir search structure by cookie value, and return it held.
1627 * Must be called with smb_globalLock held.
1629 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1631 smb_dirSearch_t *dsp;
1633 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1634 if (dsp->cookie == cookie) {
1635 if (dsp != smb_firstDirSearchp) {
1636 /* move to head of LRU queue, too, if we're not already there */
1637 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1638 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1639 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1640 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1641 if (!smb_lastDirSearchp)
1642 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1644 lock_ObtainMutex(&dsp->mx);
1646 lock_ReleaseMutex(&dsp->mx);
1652 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1653 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1654 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1660 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1662 lock_ObtainWrite(&smb_globalLock);
1663 lock_ObtainMutex(&dsp->mx);
1664 dsp->flags |= SMB_DIRSEARCH_DELETE;
1665 if (dsp->scp != NULL) {
1666 lock_ObtainMutex(&dsp->scp->mx);
1667 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1668 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1669 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1670 dsp->scp->bulkStatProgress = hones;
1672 lock_ReleaseMutex(&dsp->scp->mx);
1674 lock_ReleaseMutex(&dsp->mx);
1675 lock_ReleaseWrite(&smb_globalLock);
1678 /* Must be called with the smb_globalLock held */
1679 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1681 cm_scache_t *scp = NULL;
1683 lock_ObtainMutex(&dsp->mx);
1684 osi_assert(dsp->refCount-- > 0);
1685 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1686 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1687 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1688 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1689 lock_ReleaseMutex(&dsp->mx);
1690 lock_FinalizeMutex(&dsp->mx);
1694 lock_ReleaseMutex(&dsp->mx);
1696 /* do this now to avoid spurious locking hierarchy creation */
1698 cm_ReleaseSCache(scp);
1701 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1703 lock_ObtainWrite(&smb_globalLock);
1704 smb_ReleaseDirSearchNoLock(dsp);
1705 lock_ReleaseWrite(&smb_globalLock);
1708 /* find a dir search structure by cookie value, and return it held */
1709 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1711 smb_dirSearch_t *dsp;
1713 lock_ObtainWrite(&smb_globalLock);
1714 dsp = smb_FindDirSearchNoLock(cookie);
1715 lock_ReleaseWrite(&smb_globalLock);
1719 /* GC some dir search entries, in the address space expected by the specific protocol.
1720 * Must be called with smb_globalLock held; release the lock temporarily.
1722 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1723 void smb_GCDirSearches(int isV3)
1725 smb_dirSearch_t *prevp;
1726 smb_dirSearch_t *tp;
1727 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1731 victimCount = 0; /* how many have we got so far */
1732 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1733 /* we'll move tp from queue, so
1736 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1737 /* if no one is using this guy, and we're either in the new protocol,
1738 * or we're in the old one and this is a small enough ID to be useful
1739 * to the old protocol, GC this guy.
1741 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1742 /* hold and delete */
1743 tp->flags |= SMB_DIRSEARCH_DELETE;
1744 victimsp[victimCount++] = tp;
1748 /* don't do more than this */
1749 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1753 /* now release them */
1754 for (i = 0; i < victimCount; i++) {
1755 smb_ReleaseDirSearchNoLock(victimsp[i]);
1759 /* function for allocating a dir search entry. We need these to remember enough context
1760 * since we don't get passed the path from call to call during a directory search.
1762 * Returns a held dir search structure, and bumps the reference count on the vnode,
1763 * since it saves a pointer to the vnode.
1765 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1767 smb_dirSearch_t *dsp;
1773 lock_ObtainWrite(&smb_globalLock);
1776 /* what's the biggest ID allowed in this version of the protocol */
1777 maxAllowed = isV3 ? 65535 : 255;
1778 if (smb_dirSearchCounter > maxAllowed)
1779 smb_dirSearchCounter = 1;
1781 start = smb_dirSearchCounter;
1784 /* twice so we have enough tries to find guys we GC after one pass;
1785 * 10 extra is just in case I mis-counted.
1787 if (++counter > 2*maxAllowed+10)
1788 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1790 if (smb_dirSearchCounter > maxAllowed) {
1791 smb_dirSearchCounter = 1;
1793 if (smb_dirSearchCounter == start) {
1795 smb_GCDirSearches(isV3);
1798 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1800 /* don't need to watch for refcount zero and deleted, since
1801 * we haven't dropped the global lock.
1803 lock_ObtainMutex(&dsp->mx);
1805 lock_ReleaseMutex(&dsp->mx);
1806 ++smb_dirSearchCounter;
1810 dsp = malloc(sizeof(*dsp));
1811 memset(dsp, 0, sizeof(*dsp));
1812 dsp->cookie = smb_dirSearchCounter;
1813 ++smb_dirSearchCounter;
1815 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1816 dsp->lastTime = osi_Time();
1817 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1818 if (!smb_lastDirSearchp)
1819 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1822 lock_ReleaseWrite(&smb_globalLock);
1826 static smb_packet_t *GetPacket(void)
1830 unsigned int npar, seg, tb_sel;
1833 lock_ObtainWrite(&smb_globalLock);
1834 tbp = smb_packetFreeListp;
1836 smb_packetFreeListp = tbp->nextp;
1837 lock_ReleaseWrite(&smb_globalLock);
1840 tbp = calloc(65540,1);
1842 tbp = malloc(sizeof(smb_packet_t));
1844 tbp->magic = SMB_PACKETMAGIC;
1847 tbp->resumeCode = 0;
1853 tbp->ncb_length = 0;
1858 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1861 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1863 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1865 osi_panic("",__FILE__,__LINE__);
1868 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1873 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1874 tbp->dos_pkt_sel = tb_sel;
1877 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1882 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1886 memcpy(tbp, pkt, sizeof(smb_packet_t));
1887 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
1889 smb_HoldVC(tbp->vcp);
1893 static NCB *GetNCB(void)
1898 unsigned int npar, seg, tb_sel;
1901 lock_ObtainWrite(&smb_globalLock);
1902 tbp = smb_ncbFreeListp;
1904 smb_ncbFreeListp = tbp->nextp;
1905 lock_ReleaseWrite(&smb_globalLock);
1908 tbp = calloc(sizeof(*tbp),1);
1910 tbp = malloc(sizeof(*tbp));
1911 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1914 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1916 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1918 osi_panic("",__FILE__,__LINE__);
1920 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1925 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1926 tbp->dos_ncb_sel = tb_sel;
1928 tbp->magic = SMB_NCBMAGIC;
1931 osi_assert(tbp->magic == SMB_NCBMAGIC);
1933 memset(&tbp->ncb, 0, sizeof(NCB));
1936 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1941 void smb_FreePacket(smb_packet_t *tbp)
1943 smb_vc_t * vcp = NULL;
1944 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1946 lock_ObtainWrite(&smb_globalLock);
1947 tbp->nextp = smb_packetFreeListp;
1948 smb_packetFreeListp = tbp;
1949 tbp->magic = SMB_PACKETMAGIC;
1953 tbp->resumeCode = 0;
1959 tbp->ncb_length = 0;
1961 lock_ReleaseWrite(&smb_globalLock);
1967 static void FreeNCB(NCB *bufferp)
1971 tbp = (smb_ncb_t *) bufferp;
1972 osi_assert(tbp->magic == SMB_NCBMAGIC);
1974 lock_ObtainWrite(&smb_globalLock);
1975 tbp->nextp = smb_ncbFreeListp;
1976 smb_ncbFreeListp = tbp;
1977 lock_ReleaseWrite(&smb_globalLock);
1980 /* get a ptr to the data part of a packet, and its count */
1981 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1985 unsigned char *afterParmsp;
1987 parmBytes = *smbp->wctp << 1;
1988 afterParmsp = smbp->wctp + parmBytes + 1;
1990 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1991 if (nbytesp) *nbytesp = dataBytes;
1993 /* don't forget to skip the data byte count, since it follows
1994 * the parameters; that's where the "2" comes from below.
1996 return (unsigned char *) (afterParmsp + 2);
1999 /* must set all the returned parameters before playing around with the
2000 * data region, since the data region is located past the end of the
2001 * variable number of parameters.
2003 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2005 unsigned char *afterParmsp;
2007 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2009 *afterParmsp++ = dsize & 0xff;
2010 *afterParmsp = (dsize>>8) & 0xff;
2013 /* return the parm'th parameter in the smbp packet */
2014 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2017 unsigned char *parmDatap;
2019 parmCount = *smbp->wctp;
2021 if (parm >= parmCount) {
2024 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2025 parm, parmCount, smbp->ncb_length);
2026 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2027 parm, parmCount, smbp->ncb_length);
2029 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2030 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2032 osi_panic(s, __FILE__, __LINE__);
2034 parmDatap = smbp->wctp + (2*parm) + 1;
2036 return parmDatap[0] + (parmDatap[1] << 8);
2039 /* return the parm'th parameter in the smbp packet */
2040 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2043 unsigned char *parmDatap;
2045 parmCount = *smbp->wctp;
2047 if (parm * 2 + offset >= parmCount * 2) {
2050 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2051 parm, offset, parmCount, smbp->ncb_length);
2053 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2054 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2056 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2057 parm, offset, parmCount, smbp->ncb_length);
2058 osi_panic(s, __FILE__, __LINE__);
2060 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2062 return parmDatap[0] + (parmDatap[1] << 8);
2065 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2069 /* make sure we have enough slots */
2070 if (*smbp->wctp <= slot)
2071 *smbp->wctp = slot+1;
2073 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2074 *parmDatap++ = parmValue & 0xff;
2075 *parmDatap = (parmValue>>8) & 0xff;
2078 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2082 /* make sure we have enough slots */
2083 if (*smbp->wctp <= slot)
2084 *smbp->wctp = slot+2;
2086 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2087 *parmDatap++ = parmValue & 0xff;
2088 *parmDatap++ = (parmValue>>8) & 0xff;
2089 *parmDatap++ = (parmValue>>16) & 0xff;
2090 *parmDatap++ = (parmValue>>24) & 0xff;
2093 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2098 /* make sure we have enough slots */
2099 if (*smbp->wctp <= slot)
2100 *smbp->wctp = slot+4;
2102 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2104 *parmDatap++ = *parmValuep++;
2107 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2111 /* make sure we have enough slots */
2112 if (*smbp->wctp <= slot) {
2113 if (smbp->oddByte) {
2115 *smbp->wctp = slot+1;
2120 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2121 *parmDatap++ = parmValue & 0xff;
2124 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2128 lastSlashp = strrchr(inPathp, '\\');
2130 *lastComponentp = lastSlashp;
2133 if (inPathp == lastSlashp)
2135 *outPathp++ = *inPathp++;
2144 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2149 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2154 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2160 tlen = inp[0] + (inp[1]<<8);
2161 inp += 2; /* skip length field */
2164 *chainpp = inp + tlen;
2173 /* format a packet as a response */
2174 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2179 outp = (smb_t *) op;
2181 /* zero the basic structure through the smb_wct field, and zero the data
2182 * size field, assuming that wct stays zero; otherwise, you have to
2183 * explicitly set the data size field, too.
2185 inSmbp = (smb_t *) inp;
2186 memset(outp, 0, sizeof(smb_t)+2);
2192 outp->com = inSmbp->com;
2193 outp->tid = inSmbp->tid;
2194 outp->pid = inSmbp->pid;
2195 outp->uid = inSmbp->uid;
2196 outp->mid = inSmbp->mid;
2197 outp->res[0] = inSmbp->res[0];
2198 outp->res[1] = inSmbp->res[1];
2199 op->inCom = inSmbp->com;
2201 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2202 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2204 /* copy fields in generic packet area */
2205 op->wctp = &outp->wct;
2208 /* send a (probably response) packet; vcp tells us to whom to send it.
2209 * we compute the length by looking at wct and bcc fields.
2211 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2228 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2231 memset((char *)ncbp, 0, sizeof(NCB));
2233 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2234 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2235 extra += tp[0] + (tp[1]<<8);
2236 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2237 extra += 3; /* wct and length fields */
2239 ncbp->ncb_length = extra; /* bytes to send */
2240 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2241 ncbp->ncb_lana_num = vcp->lana;
2242 ncbp->ncb_command = NCBSEND; /* op means send data */
2244 ncbp->ncb_buffer = (char *) inp;/* packet */
2245 code = Netbios(ncbp);
2247 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2248 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2250 /* copy header information from virtual to DOS address space */
2251 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2252 code = Netbios(ncbp, dos_ncb);
2258 case 0x01: s = "llegal buffer length "; break;
2259 case 0x03: s = "illegal command "; break;
2260 case 0x05: s = "command timed out "; break;
2261 case 0x06: s = "message incomplete, issue another command"; break;
2262 case 0x07: s = "illegal buffer address "; break;
2263 case 0x08: s = "session number out of range "; break;
2264 case 0x09: s = "no resource available "; break;
2265 case 0x0a: s = "session closed "; break;
2266 case 0x0b: s = "command cancelled "; break;
2267 case 0x0d: s = "duplicate name "; break;
2268 case 0x0e: s = "name table full "; break;
2269 case 0x0f: s = "no deletions, name has active sessions "; break;
2270 case 0x11: s = "local session table full "; break;
2271 case 0x12: s = "remote session table full "; break;
2272 case 0x13: s = "illegal name number "; break;
2273 case 0x14: s = "no callname "; break;
2274 case 0x15: s = "cannot put * in NCB_NAME "; break;
2275 case 0x16: s = "name in use on remote adapter "; break;
2276 case 0x17: s = "name deleted "; break;
2277 case 0x18: s = "session ended abnormally "; break;
2278 case 0x19: s = "name conflict detected "; break;
2279 case 0x21: s = "interface busy, IRET before retrying "; break;
2280 case 0x22: s = "too many commands outstanding, retry later"; break;
2281 case 0x23: s = "ncb_lana_num field invalid "; break;
2282 case 0x24: s = "command completed while cancel occurring "; break;
2283 case 0x26: s = "command not valid to cancel "; break;
2284 case 0x30: s = "name defined by anther local process "; break;
2285 case 0x34: s = "environment undefined. RESET required "; break;
2286 case 0x35: s = "required OS resources exhausted "; break;
2287 case 0x36: s = "max number of applications exceeded "; break;
2288 case 0x37: s = "no saps available for netbios "; break;
2289 case 0x38: s = "requested resources are not available "; break;
2290 case 0x39: s = "invalid ncb address or length > segment "; break;
2291 case 0x3B: s = "invalid NCB DDID "; break;
2292 case 0x3C: s = "lock of user area failed "; break;
2293 case 0x3f: s = "NETBIOS not loaded "; break;
2294 case 0x40: s = "system error "; break;
2296 s = "unknown error";
2298 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2305 void smb_MapNTError(long code, unsigned long *NTStatusp)
2307 unsigned long NTStatus;
2309 /* map CM_ERROR_* errors to NT 32-bit status codes */
2310 /* NT Status codes are listed in ntstatus.h not winerror.h */
2311 if (code == CM_ERROR_NOSUCHCELL) {
2312 NTStatus = 0xC000000FL; /* No such file */
2314 else if (code == CM_ERROR_NOSUCHVOLUME) {
2315 NTStatus = 0xC000000FL; /* No such file */
2317 else if (code == CM_ERROR_TIMEDOUT) {
2319 NTStatus = 0xC00000CFL; /* Sharing Paused */
2321 NTStatus = 0x00000102L; /* Timeout */
2324 else if (code == CM_ERROR_RETRY) {
2325 NTStatus = 0xC000022DL; /* Retry */
2327 else if (code == CM_ERROR_NOACCESS) {
2328 NTStatus = 0xC0000022L; /* Access denied */
2330 else if (code == CM_ERROR_READONLY) {
2331 NTStatus = 0xC00000A2L; /* Write protected */
2333 else if (code == CM_ERROR_NOSUCHFILE) {
2334 NTStatus = 0xC000000FL; /* No such file */
2336 else if (code == CM_ERROR_NOSUCHPATH) {
2337 NTStatus = 0xC000003AL; /* Object path not found */
2339 else if (code == CM_ERROR_TOOBIG) {
2340 NTStatus = 0xC000007BL; /* Invalid image format */
2342 else if (code == CM_ERROR_INVAL) {
2343 NTStatus = 0xC000000DL; /* Invalid parameter */
2345 else if (code == CM_ERROR_BADFD) {
2346 NTStatus = 0xC0000008L; /* Invalid handle */
2348 else if (code == CM_ERROR_BADFDOP) {
2349 NTStatus = 0xC0000022L; /* Access denied */
2351 else if (code == CM_ERROR_EXISTS) {
2352 NTStatus = 0xC0000035L; /* Object name collision */
2354 else if (code == CM_ERROR_NOTEMPTY) {
2355 NTStatus = 0xC0000101L; /* Directory not empty */
2357 else if (code == CM_ERROR_CROSSDEVLINK) {
2358 NTStatus = 0xC00000D4L; /* Not same device */
2360 else if (code == CM_ERROR_NOTDIR) {
2361 NTStatus = 0xC0000103L; /* Not a directory */
2363 else if (code == CM_ERROR_ISDIR) {
2364 NTStatus = 0xC00000BAL; /* File is a directory */
2366 else if (code == CM_ERROR_BADOP) {
2368 /* I have no idea where this comes from */
2369 NTStatus = 0xC09820FFL; /* SMB no support */
2371 NTStatus = 0xC00000BBL; /* Not supported */
2372 #endif /* COMMENT */
2374 else if (code == CM_ERROR_BADSHARENAME) {
2375 NTStatus = 0xC00000CCL; /* Bad network name */
2377 else if (code == CM_ERROR_NOIPC) {
2379 NTStatus = 0xC0000022L; /* Access Denied */
2381 NTStatus = 0xC000013DL; /* Remote Resources */
2384 else if (code == CM_ERROR_CLOCKSKEW) {
2385 NTStatus = 0xC0000133L; /* Time difference at DC */
2387 else if (code == CM_ERROR_BADTID) {
2388 NTStatus = 0xC0982005L; /* SMB bad TID */
2390 else if (code == CM_ERROR_USESTD) {
2391 NTStatus = 0xC09820FBL; /* SMB use standard */
2393 else if (code == CM_ERROR_QUOTA) {
2395 NTStatus = 0xC0000044L; /* Quota exceeded */
2397 NTStatus = 0xC000007FL; /* Disk full */
2400 else if (code == CM_ERROR_SPACE) {
2401 NTStatus = 0xC000007FL; /* Disk full */
2403 else if (code == CM_ERROR_ATSYS) {
2404 NTStatus = 0xC0000033L; /* Object name invalid */
2406 else if (code == CM_ERROR_BADNTFILENAME) {
2407 NTStatus = 0xC0000033L; /* Object name invalid */
2409 else if (code == CM_ERROR_WOULDBLOCK) {
2410 NTStatus = 0xC0000055L; /* Lock not granted */
2412 else if (code == CM_ERROR_SHARING_VIOLATION) {
2413 NTStatus = 0xC0000043L; /* Sharing violation */
2415 else if (code == CM_ERROR_LOCK_CONFLICT) {
2416 NTStatus = 0xC0000054L; /* Lock conflict */
2418 else if (code == CM_ERROR_PARTIALWRITE) {
2419 NTStatus = 0xC000007FL; /* Disk full */
2421 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2422 NTStatus = 0xC0000023L; /* Buffer too small */
2424 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2425 NTStatus = 0xC0000035L; /* Object name collision */
2427 else if (code == CM_ERROR_BADPASSWORD) {
2428 NTStatus = 0xC000006DL; /* unknown username or bad password */
2430 else if (code == CM_ERROR_BADLOGONTYPE) {
2431 NTStatus = 0xC000015BL; /* logon type not granted */
2433 else if (code == CM_ERROR_GSSCONTINUE) {
2434 NTStatus = 0xC0000016L; /* more processing required */
2436 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2438 NTStatus = 0xC0000280L; /* reparse point not resolved */
2440 NTStatus = 0xC0000022L; /* Access Denied */
2443 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2444 NTStatus = 0xC0000257L; /* Path Not Covered */
2447 else if (code == CM_ERROR_ALLBUSY) {
2448 NTStatus = 0xC00000BFL; /* Network Busy */
2450 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2451 NTStatus = 0xC0000350L; /* Remote Host Down */
2454 /* we do not want to be telling the SMB/CIFS client that
2455 * the AFS Client Service is busy or down.
2457 else if (code == CM_ERROR_ALLBUSY ||
2458 code == CM_ERROR_ALLOFFLINE ||
2459 code == CM_ERROR_ALLDOWN) {
2460 NTStatus = 0xC00000BEL; /* Bad Network Path */
2463 else if (code == RXKADUNKNOWNKEY) {
2464 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2466 NTStatus = 0xC0982001L; /* SMB non-specific error */
2469 *NTStatusp = NTStatus;
2470 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2473 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2474 unsigned char *classp)
2476 unsigned char class;
2477 unsigned short error;
2479 /* map CM_ERROR_* errors to SMB errors */
2480 if (code == CM_ERROR_NOSUCHCELL) {
2482 error = 3; /* bad path */
2484 else if (code == CM_ERROR_NOSUCHVOLUME) {
2486 error = 3; /* bad path */
2488 else if (code == CM_ERROR_TIMEDOUT) {
2490 error = 81; /* server is paused */
2492 else if (code == CM_ERROR_RETRY) {
2493 class = 2; /* shouldn't happen */
2496 else if (code == CM_ERROR_NOACCESS) {
2498 error = 4; /* bad access */
2500 else if (code == CM_ERROR_READONLY) {
2502 error = 19; /* read only */
2504 else if (code == CM_ERROR_NOSUCHFILE) {
2506 error = 2; /* ENOENT! */
2508 else if (code == CM_ERROR_NOSUCHPATH) {
2510 error = 3; /* Bad path */
2512 else if (code == CM_ERROR_TOOBIG) {
2514 error = 11; /* bad format */
2516 else if (code == CM_ERROR_INVAL) {
2517 class = 2; /* server non-specific error code */
2520 else if (code == CM_ERROR_BADFD) {
2522 error = 6; /* invalid file handle */
2524 else if (code == CM_ERROR_BADFDOP) {
2525 class = 1; /* invalid op on FD */
2528 else if (code == CM_ERROR_EXISTS) {
2530 error = 80; /* file already exists */
2532 else if (code == CM_ERROR_NOTEMPTY) {
2534 error = 5; /* delete directory not empty */
2536 else if (code == CM_ERROR_CROSSDEVLINK) {
2538 error = 17; /* EXDEV */
2540 else if (code == CM_ERROR_NOTDIR) {
2541 class = 1; /* bad path */
2544 else if (code == CM_ERROR_ISDIR) {
2545 class = 1; /* access denied; DOS doesn't have a good match */
2548 else if (code == CM_ERROR_BADOP) {
2552 else if (code == CM_ERROR_BADSHARENAME) {
2556 else if (code == CM_ERROR_NOIPC) {
2558 error = 4; /* bad access */
2560 else if (code == CM_ERROR_CLOCKSKEW) {
2561 class = 1; /* invalid function */
2564 else if (code == CM_ERROR_BADTID) {
2568 else if (code == CM_ERROR_USESTD) {
2572 else if (code == CM_ERROR_REMOTECONN) {
2576 else if (code == CM_ERROR_QUOTA) {
2577 if (vcp->flags & SMB_VCFLAG_USEV3) {
2579 error = 39; /* disk full */
2583 error = 5; /* access denied */
2586 else if (code == CM_ERROR_SPACE) {
2587 if (vcp->flags & SMB_VCFLAG_USEV3) {
2589 error = 39; /* disk full */
2593 error = 5; /* access denied */
2596 else if (code == CM_ERROR_PARTIALWRITE) {
2598 error = 39; /* disk full */
2600 else if (code == CM_ERROR_ATSYS) {
2602 error = 2; /* ENOENT */
2604 else if (code == CM_ERROR_WOULDBLOCK) {
2606 error = 33; /* lock conflict */
2608 else if (code == CM_ERROR_LOCK_CONFLICT) {
2610 error = 33; /* lock conflict */
2612 else if (code == CM_ERROR_SHARING_VIOLATION) {
2614 error = 33; /* lock conflict */
2616 else if (code == CM_ERROR_NOFILES) {
2618 error = 18; /* no files in search */
2620 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2622 error = 183; /* Samba uses this */
2624 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2625 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2627 error = 2; /* bad password */
2629 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2631 error = 3; /* bad path */
2640 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2643 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2645 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2646 return CM_ERROR_BADOP;
2649 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2651 unsigned short EchoCount, i;
2652 char *data, *outdata;
2655 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2657 for (i=1; i<=EchoCount; i++) {
2658 data = smb_GetSMBData(inp, &dataSize);
2659 smb_SetSMBParm(outp, 0, i);
2660 smb_SetSMBDataLength(outp, dataSize);
2661 outdata = smb_GetSMBData(outp, NULL);
2662 memcpy(outdata, data, dataSize);
2663 smb_SendPacket(vcp, outp);
2669 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2672 long count, minCount, finalCount;
2677 cm_user_t *userp = NULL;
2681 char *rawBuf = NULL;
2683 dos_ptr rawBuf = NULL;
2690 fd = smb_GetSMBParm(inp, 0);
2691 count = smb_GetSMBParm(inp, 3);
2692 minCount = smb_GetSMBParm(inp, 4);
2693 offset.HighPart = 0; /* too bad */
2694 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2696 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2697 fd, offset.LowPart, count);
2699 fidp = smb_FindFID(vcp, fd, 0);
2703 pid = ((smb_t *) inp)->pid;
2705 LARGE_INTEGER LOffset, LLength;
2708 key = cm_GenerateKey(vcp->vcID, pid, fd);
2710 LOffset.HighPart = 0;
2711 LOffset.LowPart = offset.LowPart;
2712 LLength.HighPart = 0;
2713 LLength.LowPart = count;
2715 lock_ObtainMutex(&fidp->scp->mx);
2716 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2717 lock_ReleaseMutex(&fidp->scp->mx);
2723 lock_ObtainMutex(&smb_RawBufLock);
2725 /* Get a raw buf, from head of list */
2726 rawBuf = smb_RawBufs;
2728 smb_RawBufs = *(char **)smb_RawBufs;
2730 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2733 lock_ReleaseMutex(&smb_RawBufLock);
2737 if (fidp->flags & SMB_FID_IOCTL)
2740 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2742 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2745 /* Give back raw buffer */
2746 lock_ObtainMutex(&smb_RawBufLock);
2748 *((char **) rawBuf) = smb_RawBufs;
2750 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2753 smb_RawBufs = rawBuf;
2754 lock_ReleaseMutex(&smb_RawBufLock);
2757 smb_ReleaseFID(fidp);
2761 userp = smb_GetUser(vcp, inp);
2764 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2766 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2767 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2768 userp, &finalCount, TRUE /* rawFlag */);
2775 cm_ReleaseUser(userp);
2778 smb_ReleaseFID(fidp);
2783 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2785 memset((char *)ncbp, 0, sizeof(NCB));
2787 ncbp->ncb_length = (unsigned short) finalCount;
2788 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2789 ncbp->ncb_lana_num = vcp->lana;
2790 ncbp->ncb_command = NCBSEND;
2791 ncbp->ncb_buffer = rawBuf;
2794 code = Netbios(ncbp);
2796 code = Netbios(ncbp, dos_ncb);
2799 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2802 /* Give back raw buffer */
2803 lock_ObtainMutex(&smb_RawBufLock);
2805 *((char **) rawBuf) = smb_RawBufs;
2807 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2810 smb_RawBufs = rawBuf;
2811 lock_ReleaseMutex(&smb_RawBufLock);
2817 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2819 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2824 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2826 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2831 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2838 int protoIndex; /* index we're using */
2843 char protocol_array[10][1024]; /* protocol signature of the client */
2844 int caps; /* capabilities */
2847 TIME_ZONE_INFORMATION tzi;
2849 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2853 DWORD now = GetCurrentTime();
2854 if (now - last_msg_time >= 30000
2855 && now - last_msg_time <= 90000) {
2857 "Setting dead_vcp %x", active_vcp);
2859 smb_ReleaseVC(dead_vcp);
2861 "Previous dead_vcp %x", dead_vcp);
2863 smb_HoldVC(active_vcp);
2864 dead_vcp = active_vcp;
2865 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2870 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2872 namep = smb_GetSMBData(inp, &dbytes);
2875 coreProtoIndex = -1; /* not found */
2878 while(namex < dbytes) {
2879 osi_Log1(smb_logp, "Protocol %s",
2880 osi_LogSaveString(smb_logp, namep+1));
2881 strcpy(protocol_array[tcounter], namep+1);
2883 /* namep points at the first protocol, or really, a 0x02
2884 * byte preceding the null-terminated ASCII name.
2886 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2887 coreProtoIndex = tcounter;
2889 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2890 v3ProtoIndex = tcounter;
2892 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2893 NTProtoIndex = tcounter;
2896 /* compute size of protocol entry */
2897 entryLength = (int)strlen(namep+1);
2898 entryLength += 2; /* 0x02 bytes and null termination */
2900 /* advance over this protocol entry */
2901 namex += entryLength;
2902 namep += entryLength;
2903 tcounter++; /* which proto entry we're looking at */
2906 if (NTProtoIndex != -1) {
2907 protoIndex = NTProtoIndex;
2908 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2910 else if (v3ProtoIndex != -1) {
2911 protoIndex = v3ProtoIndex;
2912 vcp->flags |= SMB_VCFLAG_USEV3;
2914 else if (coreProtoIndex != -1) {
2915 protoIndex = coreProtoIndex;
2916 vcp->flags |= SMB_VCFLAG_USECORE;
2918 else protoIndex = -1;
2920 if (protoIndex == -1)
2921 return CM_ERROR_INVAL;
2922 else if (NTProtoIndex != -1) {
2923 smb_SetSMBParm(outp, 0, protoIndex);
2924 if (smb_authType != SMB_AUTH_NONE) {
2925 smb_SetSMBParmByte(outp, 1,
2926 NEGOTIATE_SECURITY_USER_LEVEL |
2927 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2929 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2931 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2932 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2933 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2934 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2935 /* The session key is not a well documented field however most clients
2936 * will echo back the session key to the server. Currently we are using
2937 * the same value for all sessions. We should generate a random value
2938 * and store it into the vcp
2940 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2941 smb_SetSMBParm(outp, 8, 1);
2943 * Tried changing the capabilities to support for W2K - defect 117695
2944 * Maybe something else needs to be changed here?
2948 smb_SetSMBParmLong(outp, 9, 0x43fd);
2950 smb_SetSMBParmLong(outp, 9, 0x251);
2953 * 32-bit error codes *
2958 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2960 NTNEGOTIATE_CAPABILITY_DFS |
2962 NTNEGOTIATE_CAPABILITY_NTFIND |
2963 NTNEGOTIATE_CAPABILITY_RAWMODE |
2964 NTNEGOTIATE_CAPABILITY_NTSMB;
2966 if ( smb_authType == SMB_AUTH_EXTENDED )
2967 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2969 smb_SetSMBParmLong(outp, 9, caps);
2971 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2972 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2973 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2975 GetTimeZoneInformation(&tzi);
2976 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2978 if (smb_authType == SMB_AUTH_NTLM) {
2979 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2980 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2981 /* paste in encryption key */
2982 datap = smb_GetSMBData(outp, NULL);
2983 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2984 /* and the faux domain name */
2985 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2986 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2990 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2992 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2994 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2996 datap = smb_GetSMBData(outp, NULL);
2997 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3000 datap += sizeof(smb_ServerGUID);
3001 memcpy(datap, secBlob, secBlobLength);
3005 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3006 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3009 else if (v3ProtoIndex != -1) {
3010 smb_SetSMBParm(outp, 0, protoIndex);
3012 /* NOTE: Extended authentication cannot be negotiated with v3
3013 * therefore we fail over to NTLM
3015 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3016 smb_SetSMBParm(outp, 1,
3017 NEGOTIATE_SECURITY_USER_LEVEL |
3018 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3020 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3022 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3023 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3024 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3025 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3026 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3027 smb_SetSMBParm(outp, 7, 1);
3029 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3030 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3031 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3033 GetTimeZoneInformation(&tzi);
3034 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3036 /* NOTE: Extended authentication cannot be negotiated with v3
3037 * therefore we fail over to NTLM
3039 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3040 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3041 smb_SetSMBParm(outp, 12, 0); /* resvd */
3042 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3043 datap = smb_GetSMBData(outp, NULL);
3044 /* paste in a new encryption key */
3045 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3046 /* and the faux domain name */
3047 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3049 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3050 smb_SetSMBParm(outp, 12, 0); /* resvd */
3051 smb_SetSMBDataLength(outp, 0);
3054 else if (coreProtoIndex != -1) { /* not really supported anymore */
3055 smb_SetSMBParm(outp, 0, protoIndex);
3056 smb_SetSMBDataLength(outp, 0);
3061 void smb_Daemon(void *parmp)
3063 afs_uint32 count = 0;
3065 while(smbShutdownFlag == 0) {
3069 if (smbShutdownFlag == 1)
3072 if ((count % 72) == 0) { /* every five minutes */
3074 time_t old_localZero = smb_localZero;
3076 /* Initialize smb_localZero */
3077 myTime.tm_isdst = -1; /* compute whether on DST or not */
3078 myTime.tm_year = 70;
3084 smb_localZero = mktime(&myTime);
3086 #ifndef USE_NUMERIC_TIME_CONV
3087 smb_CalculateNowTZ();
3088 #endif /* USE_NUMERIC_TIME_CONV */
3089 #ifdef AFS_FREELANCE
3090 if ( smb_localZero != old_localZero )
3091 cm_noteLocalMountPointChange();
3094 /* XXX GC dir search entries */
3098 void smb_WaitingLocksDaemon()
3100 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3101 smb_waitingLock_t *wl, *wlNext;
3104 smb_packet_t *inp, *outp;
3108 while (smbShutdownFlag == 0) {
3109 lock_ObtainWrite(&smb_globalLock);
3110 nwlRequest = smb_allWaitingLocks;
3111 if (nwlRequest == NULL) {
3112 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3117 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3124 lock_ObtainWrite(&smb_globalLock);
3126 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3128 wlRequest = nwlRequest;
3129 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3130 lock_ReleaseWrite(&smb_globalLock);
3134 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3135 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3138 osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
3140 /* wl->state is either _DONE or _WAITING. _ERROR
3141 would no longer be on the queue. */
3142 code = cm_RetryLock( wl->lockp,
3143 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3146 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3147 } else if (code != CM_ERROR_WOULDBLOCK) {
3148 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3153 if (code == CM_ERROR_WOULDBLOCK) {
3156 if (wlRequest->timeRemaining != 0xffffffff
3157 && (wlRequest->timeRemaining -= 1000) < 0)
3169 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3172 scp = wlRequest->scp;
3176 lock_ObtainMutex(&scp->mx);
3178 for (wl = wlRequest->locks; wl; wl = wlNext) {
3179 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3181 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3182 wl->LLength, wl->key, NULL, &req);
3184 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3189 lock_ReleaseMutex(&scp->mx);
3193 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3196 for (wl = wlRequest->locks; wl; wl = wlNext) {
3197 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3198 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3203 vcp = wlRequest->vcp;
3204 inp = wlRequest->inp;
3205 outp = wlRequest->outp;
3207 ncbp->ncb_length = inp->ncb_length;
3208 inp->spacep = cm_GetSpace();
3210 /* Remove waitingLock from list */
3211 lock_ObtainWrite(&smb_globalLock);
3212 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3214 lock_ReleaseWrite(&smb_globalLock);
3216 /* Resume packet processing */
3218 smb_SetSMBDataLength(outp, 0);
3219 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3220 outp->resumeCode = code;
3222 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3225 cm_FreeSpace(inp->spacep);
3226 smb_FreePacket(inp);
3227 smb_FreePacket(outp);
3229 cm_ReleaseSCache(wlRequest->scp);
3232 } while (nwlRequest && smbShutdownFlag == 0);
3237 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3239 osi_Log0(smb_logp, "SMB receive get disk attributes");
3241 smb_SetSMBParm(outp, 0, 32000);
3242 smb_SetSMBParm(outp, 1, 64);
3243 smb_SetSMBParm(outp, 2, 1024);
3244 smb_SetSMBParm(outp, 3, 30000);
3245 smb_SetSMBParm(outp, 4, 0);
3246 smb_SetSMBDataLength(outp, 0);
3250 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3254 unsigned short newTid;
3255 char shareName[256];
3263 osi_Log0(smb_logp, "SMB receive tree connect");
3265 /* parse input parameters */
3266 tp = smb_GetSMBData(inp, NULL);
3267 pathp = smb_ParseASCIIBlock(tp, &tp);
3268 if (smb_StoreAnsiFilenames)
3269 OemToChar(pathp,pathp);
3270 passwordp = smb_ParseASCIIBlock(tp, &tp);
3271 tp = strrchr(pathp, '\\');
3273 return CM_ERROR_BADSMB;
3274 strcpy(shareName, tp+1);
3276 userp = smb_GetUser(vcp, inp);
3278 lock_ObtainMutex(&vcp->mx);
3279 newTid = vcp->tidCounter++;
3280 lock_ReleaseMutex(&vcp->mx);
3282 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3283 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3284 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3286 smb_ReleaseUID(uidp);
3288 smb_ReleaseTID(tidp);
3289 return CM_ERROR_BADSHARENAME;
3291 lock_ObtainMutex(&tidp->mx);
3292 tidp->userp = userp;
3293 tidp->pathname = sharePath;
3294 lock_ReleaseMutex(&tidp->mx);
3295 smb_ReleaseTID(tidp);
3297 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3298 smb_SetSMBParm(rsp, 1, newTid);
3299 smb_SetSMBDataLength(rsp, 0);
3301 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3305 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3309 if (*inp++ != 0x1) return NULL;
3310 tlen = inp[0] + (inp[1]<<8);
3311 inp += 2; /* skip length field */
3314 *chainpp = inp + tlen;
3317 if (lengthp) *lengthp = tlen;
3322 /* set maskp to the mask part of the incoming path.
3323 * Mask is 11 bytes long (8.3 with the dot elided).
3324 * Returns true if succeeds with a valid name, otherwise it does
3325 * its best, but returns false.
3327 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3335 /* starts off valid */
3338 /* mask starts out all blanks */
3339 memset(maskp, ' ', 11);
3341 /* find last backslash, or use whole thing if there is none */
3342 tp = strrchr(pathp, '\\');
3343 if (!tp) tp = pathp;
3344 else tp++; /* skip slash */
3348 /* names starting with a dot are illegal */
3349 if (*tp == '.') valid8Dot3 = 0;
3353 if (tc == 0) return valid8Dot3;
3354 if (tc == '.' || tc == '"') break;
3355 if (i < 8) *up++ = tc;
3356 else valid8Dot3 = 0;
3359 /* if we get here, tp point after the dot */
3360 up = maskp+8; /* ext goes here */
3367 if (tc == '.' || tc == '"')
3370 /* copy extension if not too long */
3380 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3390 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3392 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3396 /* otherwise, we have a valid 8.3 name; see if we have a match,
3397 * treating '?' as a wildcard in maskp (but not in the file name).
3399 tp1 = umask; /* real name, in mask format */
3400 tp2 = maskp; /* mask, in mask format */
3401 for(i=0; i<11; i++) {
3402 tc1 = *tp1++; /* char from real name */
3403 tc2 = *tp2++; /* char from mask */
3404 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3405 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3408 if (tc2 == '?' && tc1 != ' ')
3415 /* we got a match */
3419 char *smb_FindMask(char *pathp)
3423 tp = strrchr(pathp, '\\'); /* find last slash */
3426 return tp+1; /* skip the slash */
3428 return pathp; /* no slash, return the entire path */
3431 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3433 unsigned char *pathp;
3435 unsigned char mask[11];
3436 unsigned char *statBlockp;
3437 unsigned char initStatBlock[21];
3440 osi_Log0(smb_logp, "SMB receive search volume");
3442 /* pull pathname and stat block out of request */
3443 tp = smb_GetSMBData(inp, NULL);
3444 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3445 osi_assert(pathp != NULL);
3446 if (smb_StoreAnsiFilenames)
3447 OemToChar(pathp,pathp);
3448 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3449 osi_assert(statBlockp != NULL);
3451 statBlockp = initStatBlock;
3455 /* for returning to caller */
3456 smb_Get8Dot3MaskFromPath(mask, pathp);
3458 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3459 tp = smb_GetSMBData(outp, NULL);
3461 *tp++ = 43; /* bytes in a dir entry */
3462 *tp++ = 0; /* high byte in counter */
3464 /* now marshall the dir entry, starting with the search status */
3465 *tp++ = statBlockp[0]; /* Reserved */
3466 memcpy(tp, mask, 11); tp += 11; /* FileName */
3468 /* now pass back server use info, with 1st byte non-zero */
3470 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3472 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3474 *tp++ = 0x8; /* attribute: volume */
3484 /* 4 byte file size */
3490 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3491 memset(tp, ' ', 13);
3494 /* set the length of the data part of the packet to 43 + 3, for the dir
3495 * entry plus the 5 and the length fields.
3497 smb_SetSMBDataLength(outp, 46);
3501 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3502 cm_user_t *userp, cm_req_t *reqp)
3510 smb_dirListPatch_t *patchp;
3511 smb_dirListPatch_t *npatchp;
3513 for (patchp = *dirPatchespp; patchp; patchp =
3514 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3516 dptr = patchp->dptr;
3518 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3520 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3521 *dptr++ = SMB_ATTR_HIDDEN;
3524 lock_ObtainMutex(&scp->mx);
3525 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3526 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3528 lock_ReleaseMutex(&scp->mx);
3529 cm_ReleaseSCache(scp);
3530 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3531 *dptr++ = SMB_ATTR_HIDDEN;
3535 attr = smb_Attributes(scp);
3536 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3537 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3538 attr |= SMB_ATTR_HIDDEN;
3542 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3545 shortTemp = (unsigned short) (dosTime & 0xffff);
3546 *((u_short *)dptr) = shortTemp;
3549 /* and copy out date */
3550 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3551 *((u_short *)dptr) = shortTemp;
3554 /* copy out file length */
3555 *((u_long *)dptr) = scp->length.LowPart;
3557 lock_ReleaseMutex(&scp->mx);
3558 cm_ReleaseSCache(scp);
3561 /* now free the patches */
3562 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3563 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3567 /* and mark the list as empty */
3568 *dirPatchespp = NULL;
3573 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3582 smb_dirListPatch_t *dirListPatchesp;
3583 smb_dirListPatch_t *curPatchp;
3587 osi_hyper_t dirLength;
3588 osi_hyper_t bufferOffset;
3589 osi_hyper_t curOffset;
3591 unsigned char *inCookiep;
3592 smb_dirSearch_t *dsp;
3596 unsigned long clientCookie;
3597 cm_pageHeader_t *pageHeaderp;
3598 cm_user_t *userp = NULL;
3605 long nextEntryCookie;
3606 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3607 char resByte; /* reserved byte from the cookie */
3608 char *op; /* output data ptr */
3609 char *origOp; /* original value of op */
3610 cm_space_t *spacep; /* for pathname buffer */
3621 maxCount = smb_GetSMBParm(inp, 0);
3623 dirListPatchesp = NULL;
3625 caseFold = CM_FLAG_CASEFOLD;
3627 tp = smb_GetSMBData(inp, NULL);
3628 pathp = smb_ParseASCIIBlock(tp, &tp);
3629 if (smb_StoreAnsiFilenames)
3630 OemToChar(pathp,pathp);
3631 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3633 /* bail out if request looks bad */
3634 if (!tp || !pathp) {
3635 return CM_ERROR_BADSMB;
3638 /* We can handle long names */
3639 if (vcp->flags & SMB_VCFLAG_USENT)
3640 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3642 /* make sure we got a whole search status */
3643 if (dataLength < 21) {
3644 nextCookie = 0; /* start at the beginning of the dir */
3647 attribute = smb_GetSMBParm(inp, 1);
3649 /* handle volume info in another function */
3650 if (attribute & 0x8)
3651 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3653 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3654 maxCount, osi_LogSaveString(smb_logp, pathp));
3656 if (*pathp == 0) { /* null pathp, treat as root dir */
3657 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3658 return CM_ERROR_NOFILES;
3662 dsp = smb_NewDirSearch(0);
3663 dsp->attribute = attribute;
3664 smb_Get8Dot3MaskFromPath(mask, pathp);
3665 memcpy(dsp->mask, mask, 11);
3667 /* track if this is likely to match a lot of entries */
3668 if (smb_IsStarMask(mask))
3673 /* pull the next cookie value out of the search status block */
3674 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3675 + (inCookiep[16]<<24);
3676 dsp = smb_FindDirSearch(inCookiep[12]);
3678 /* can't find dir search status; fatal error */
3679 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3680 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3681 return CM_ERROR_BADFD;
3683 attribute = dsp->attribute;
3684 resByte = inCookiep[0];
3686 /* copy out client cookie, in host byte order. Don't bother
3687 * interpreting it, since we're just passing it through, anyway.
3689 memcpy(&clientCookie, &inCookiep[17], 4);
3691 memcpy(mask, dsp->mask, 11);
3693 /* assume we're doing a star match if it has continued for more
3699 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3700 nextCookie, dsp->cookie, attribute);
3702 userp = smb_GetUser(vcp, inp);
3704 /* try to get the vnode for the path name next */
3705 lock_ObtainMutex(&dsp->mx);
3711 spacep = inp->spacep;
3712 smb_StripLastComponent(spacep->data, NULL, pathp);
3713 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3715 lock_ReleaseMutex(&dsp->mx);
3716 cm_ReleaseUser(userp);
3717 smb_DeleteDirSearch(dsp);
3718 smb_ReleaseDirSearch(dsp);
3719 return CM_ERROR_NOFILES;
3721 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3722 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3725 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3726 cm_ReleaseSCache(scp);
3727 lock_ReleaseMutex(&dsp->mx);
3728 cm_ReleaseUser(userp);
3729 smb_DeleteDirSearch(dsp);
3730 smb_ReleaseDirSearch(dsp);
3731 if ( WANTS_DFS_PATHNAMES(inp) )
3732 return CM_ERROR_PATH_NOT_COVERED;
3734 return CM_ERROR_BADSHARENAME;
3736 #endif /* DFS_SUPPORT */
3739 /* we need one hold for the entry we just stored into,
3740 * and one for our own processing. When we're done with this
3741 * function, we'll drop the one for our own processing.
3742 * We held it once from the namei call, and so we do another hold
3746 lock_ObtainMutex(&scp->mx);
3747 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3748 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3749 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3750 dsp->flags |= SMB_DIRSEARCH_BULKST;
3752 lock_ReleaseMutex(&scp->mx);
3755 lock_ReleaseMutex(&dsp->mx);
3757 cm_ReleaseUser(userp);
3758 smb_DeleteDirSearch(dsp);
3759 smb_ReleaseDirSearch(dsp);
3763 /* reserves space for parameter; we'll adjust it again later to the
3764 * real count of the # of entries we returned once we've actually
3765 * assembled the directory listing.
3767 smb_SetSMBParm(outp, 0, 0);
3769 /* get the directory size */
3770 lock_ObtainMutex(&scp->mx);
3771 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3772 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3774 lock_ReleaseMutex(&scp->mx);
3775 cm_ReleaseSCache(scp);
3776 cm_ReleaseUser(userp);
3777 smb_DeleteDirSearch(dsp);
3778 smb_ReleaseDirSearch(dsp);
3782 dirLength = scp->length;
3784 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3785 curOffset.HighPart = 0;
3786 curOffset.LowPart = nextCookie;
3787 origOp = op = smb_GetSMBData(outp, NULL);
3788 /* and write out the basic header */
3789 *op++ = 5; /* variable block */
3790 op += 2; /* skip vbl block length; we'll fill it in later */
3794 /* make sure that curOffset.LowPart doesn't point to the first
3795 * 32 bytes in the 2nd through last dir page, and that it doesn't
3796 * point at the first 13 32-byte chunks in the first dir page,
3797 * since those are dir and page headers, and don't contain useful
3800 temp = curOffset.LowPart & (2048-1);
3801 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3802 /* we're in the first page */
3803 if (temp < 13*32) temp = 13*32;
3806 /* we're in a later dir page */
3807 if (temp < 32) temp = 32;
3810 /* make sure the low order 5 bits are zero */
3813 /* now put temp bits back ito curOffset.LowPart */
3814 curOffset.LowPart &= ~(2048-1);
3815 curOffset.LowPart |= temp;
3817 /* check if we've returned all the names that will fit in the
3820 if (returnedNames >= maxCount) {
3821 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3822 returnedNames, maxCount);
3826 /* check if we've passed the dir's EOF */
3827 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3829 /* see if we can use the bufferp we have now; compute in which page
3830 * the current offset would be, and check whether that's the offset
3831 * of the buffer we have. If not, get the buffer.
3833 thyper.HighPart = curOffset.HighPart;
3834 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3835 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3838 buf_Release(bufferp);
3841 lock_ReleaseMutex(&scp->mx);
3842 lock_ObtainRead(&scp->bufCreateLock);
3843 code = buf_Get(scp, &thyper, &bufferp);
3844 lock_ReleaseRead(&scp->bufCreateLock);
3845 lock_ObtainMutex(&dsp->mx);
3847 /* now, if we're doing a star match, do bulk fetching of all of
3848 * the status info for files in the dir.
3851 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3852 lock_ObtainMutex(&scp->mx);
3853 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3854 LargeIntegerGreaterThanOrEqualTo(thyper,
3855 scp->bulkStatProgress)) {
3856 /* Don't bulk stat if risking timeout */
3857 int now = GetCurrentTime();
3858 if (now - req.startTime > 5000) {
3859 scp->bulkStatProgress = thyper;
3860 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3861 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3863 cm_TryBulkStat(scp, &thyper, userp, &req);
3866 lock_ObtainMutex(&scp->mx);
3868 lock_ReleaseMutex(&dsp->mx);
3870 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3874 bufferOffset = thyper;
3876 /* now get the data in the cache */
3878 code = cm_SyncOp(scp, bufferp, userp, &req,
3880 CM_SCACHESYNC_NEEDCALLBACK |
3881 CM_SCACHESYNC_READ);
3883 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3887 if (cm_HaveBuffer(scp, bufferp, 0)) {
3888 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3892 /* otherwise, load the buffer and try again */
3893 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3895 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3896 scp, bufferp, code);
3901 buf_Release(bufferp);
3905 } /* if (wrong buffer) ... */
3907 /* now we have the buffer containing the entry we're interested in; copy
3908 * it out if it represents a non-deleted entry.
3910 entryInDir = curOffset.LowPart & (2048-1);
3911 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3913 /* page header will help tell us which entries are free. Page header
3914 * can change more often than once per buffer, since AFS 3 dir page size
3915 * may be less than (but not more than a buffer package buffer.
3917 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3918 temp &= ~(2048 - 1); /* turn off intra-page bits */
3919 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3921 /* now determine which entry we're looking at in the page. If it is
3922 * free (there's a free bitmap at the start of the dir), we should
3923 * skip these 32 bytes.
3925 slotInPage = (entryInDir & 0x7e0) >> 5;
3926 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3927 /* this entry is free */
3928 numDirChunks = 1; /* only skip this guy */
3932 tp = bufferp->datap + entryInBuffer;
3933 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3935 /* while we're here, compute the next entry's location, too,
3936 * since we'll need it when writing out the cookie into the dir
3939 * XXXX Probably should do more sanity checking.
3941 numDirChunks = cm_NameEntries(dep->name, NULL);
3943 /* compute the offset of the cookie representing the next entry */
3944 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3946 /* Compute 8.3 name if necessary */
3947 actualName = dep->name;
3948 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3949 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3950 actualName = shortName;
3953 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3954 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3955 osi_LogSaveString(smb_logp, actualName));
3957 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3958 /* this is one of the entries to use: it is not deleted
3959 * and it matches the star pattern we're looking for.
3962 /* Eliminate entries that don't match requested
3965 /* no hidden files */
3966 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3967 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3971 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3973 /* We have already done the cm_TryBulkStat above */
3974 fid.cell = scp->fid.cell;
3975 fid.volume = scp->fid.volume;
3976 fid.vnode = ntohl(dep->fid.vnode);
3977 fid.unique = ntohl(dep->fid.unique);
3978 fileType = cm_FindFileType(&fid);
3979 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3980 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3982 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3983 fileType == CM_SCACHETYPE_DFSLINK ||
3984 fileType == CM_SCACHETYPE_INVALID)
3985 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3990 memcpy(op, mask, 11); op += 11;
3991 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3992 *op++ = (char)(nextEntryCookie & 0xff);
3993 *op++ = (char)((nextEntryCookie>>8) & 0xff);
3994 *op++ = (char)((nextEntryCookie>>16) & 0xff);
3995 *op++ = (char)((nextEntryCookie>>24) & 0xff);
3996 memcpy(op, &clientCookie, 4); op += 4;
3998 /* now we emit the attribute. This is sort of tricky,
3999 * since we need to really stat the file to find out
4000 * what type of entry we've got. Right now, we're
4001 * copying out data from a buffer, while holding the
4002 * scp locked, so it isn't really convenient to stat
4003 * something now. We'll put in a place holder now,
4004 * and make a second pass before returning this to get
4005 * the real attributes. So, we just skip the data for
4006 * now, and adjust it later. We allocate a patch
4007 * record to make it easy to find this point later.
4008 * The replay will happen at a time when it is safe to
4009 * unlock the directory.
4011 curPatchp = malloc(sizeof(*curPatchp));
4012 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4013 curPatchp->dptr = op;
4014 curPatchp->fid.cell = scp->fid.cell;
4015 curPatchp->fid.volume = scp->fid.volume;
4016 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4017 curPatchp->fid.unique = ntohl(dep->fid.unique);
4019 /* do hidden attribute here since name won't be around when applying
4023 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4024 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4026 curPatchp->flags = 0;
4028 op += 9; /* skip attr, time, date and size */
4030 /* zero out name area. The spec says to pad with
4031 * spaces, but Samba doesn't, and neither do we.
4035 /* finally, we get to copy out the name; we know that
4036 * it fits in 8.3 or the pattern wouldn't match, but it
4037 * never hurts to be sure.
4039 strncpy(op, actualName, 13);
4040 if (smb_StoreAnsiFilenames)
4043 /* Uppercase if requested by client */
4044 if (!KNOWS_LONG_NAMES(inp))
4049 /* now, adjust the # of entries copied */
4051 } /* if we're including this name */
4054 /* and adjust curOffset to be where the new cookie is */
4055 thyper.HighPart = 0;
4056 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4057 curOffset = LargeIntegerAdd(thyper, curOffset);
4058 } /* while copying data for dir listing */
4060 /* release the mutex */
4061 lock_ReleaseMutex(&scp->mx);
4062 if (bufferp) buf_Release(bufferp);
4064 /* apply and free last set of patches; if not doing a star match, this
4065 * will be empty, but better safe (and freeing everything) than sorry.
4067 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4069 /* special return code for unsuccessful search */
4070 if (code == 0 && dataLength < 21 && returnedNames == 0)
4071 code = CM_ERROR_NOFILES;
4073 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4074 returnedNames, code);
4077 smb_DeleteDirSearch(dsp);
4078 smb_ReleaseDirSearch(dsp);
4079 cm_ReleaseSCache(scp);
4080 cm_ReleaseUser(userp);
4084 /* finalize the output buffer */
4085 smb_SetSMBParm(outp, 0, returnedNames);
4086 temp = (long) (op - origOp);
4087 smb_SetSMBDataLength(outp, temp);
4089 /* the data area is a variable block, which has a 5 (already there)
4090 * followed by the length of the # of data bytes. We now know this to
4091 * be "temp," although that includes the 3 bytes of vbl block header.
4092 * Deduct for them and fill in the length field.
4094 temp -= 3; /* deduct vbl block info */
4095 osi_assert(temp == (43 * returnedNames));
4096 origOp[1] = (char)(temp & 0xff);
4097 origOp[2] = (char)((temp>>8) & 0xff);
4098 if (returnedNames == 0)
4099 smb_DeleteDirSearch(dsp);
4100 smb_ReleaseDirSearch(dsp);
4101 cm_ReleaseSCache(scp);
4102 cm_ReleaseUser(userp);
4106 /* verify that this is a valid path to a directory. I don't know why they
4107 * don't use the get file attributes call.
4109 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4113 cm_scache_t *rootScp;
4114 cm_scache_t *newScp;
4123 pathp = smb_GetSMBData(inp, NULL);
4124 pathp = smb_ParseASCIIBlock(pathp, NULL);
4126 return CM_ERROR_BADFD;
4127 if (smb_StoreAnsiFilenames)
4128 OemToChar(pathp,pathp);
4129 osi_Log1(smb_logp, "SMB receive check path %s",
4130 osi_LogSaveString(smb_logp, pathp));
4132 rootScp = cm_data.rootSCachep;
4134 userp = smb_GetUser(vcp, inp);
4136 caseFold = CM_FLAG_CASEFOLD;
4138 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4140 cm_ReleaseUser(userp);
4141 return CM_ERROR_NOSUCHPATH;
4143 code = cm_NameI(rootScp, pathp,
4144 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4145 userp, tidPathp, &req, &newScp);
4148 cm_ReleaseUser(userp);
4153 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4154 cm_ReleaseSCache(newScp);
4155 cm_ReleaseUser(userp);
4156 if ( WANTS_DFS_PATHNAMES(inp) )
4157 return CM_ERROR_PATH_NOT_COVERED;
4159 return CM_ERROR_BADSHARENAME;
4161 #endif /* DFS_SUPPORT */
4163 /* now lock the vnode with a callback; returns with newScp locked */
4164 lock_ObtainMutex(&newScp->mx);
4165 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4166 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4167 if (code && code != CM_ERROR_NOACCESS) {
4168 lock_ReleaseMutex(&newScp->mx);
4169 cm_ReleaseSCache(newScp);
4170 cm_ReleaseUser(userp);
4174 attrs = smb_Attributes(newScp);
4176 if (!(attrs & SMB_ATTR_DIRECTORY))
4177 code = CM_ERROR_NOTDIR;
4179 lock_ReleaseMutex(&newScp->mx);
4181 cm_ReleaseSCache(newScp);
4182 cm_ReleaseUser(userp);
4186 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4190 cm_scache_t *rootScp;
4191 unsigned short attribute;
4193 cm_scache_t *newScp;
4202 /* decode basic attributes we're passed */
4203 attribute = smb_GetSMBParm(inp, 0);
4204 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4206 pathp = smb_GetSMBData(inp, NULL);
4207 pathp = smb_ParseASCIIBlock(pathp, NULL);
4209 return CM_ERROR_BADSMB;
4210 if (smb_StoreAnsiFilenames)
4211 OemToChar(pathp,pathp);
4213 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4214 dosTime, attribute);
4216 rootScp = cm_data.rootSCachep;
4218 userp = smb_GetUser(vcp, inp);
4220 caseFold = CM_FLAG_CASEFOLD;
4222 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4224 cm_ReleaseUser(userp);
4225 return CM_ERROR_NOSUCHFILE;
4227 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4228 tidPathp, &req, &newScp);
4231 cm_ReleaseUser(userp);
4236 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4237 cm_ReleaseSCache(newScp);
4238 cm_ReleaseUser(userp);
4239 if ( WANTS_DFS_PATHNAMES(inp) )
4240 return CM_ERROR_PATH_NOT_COVERED;
4242 return CM_ERROR_BADSHARENAME;
4244 #endif /* DFS_SUPPORT */
4246 /* now lock the vnode with a callback; returns with newScp locked; we
4247 * need the current status to determine what the new status is, in some
4250 lock_ObtainMutex(&newScp->mx);
4251 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4252 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4254 lock_ReleaseMutex(&newScp->mx);
4255 cm_ReleaseSCache(newScp);
4256 cm_ReleaseUser(userp);
4260 /* Check for RO volume */
4261 if (newScp->flags & CM_SCACHEFLAG_RO) {
4262 lock_ReleaseMutex(&newScp->mx);
4263 cm_ReleaseSCache(newScp);
4264 cm_ReleaseUser(userp);
4265 return CM_ERROR_READONLY;
4268 /* prepare for setattr call */
4271 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4272 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4274 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4275 /* we're told to make a writable file read-only */
4276 attr.unixModeBits = newScp->unixModeBits & ~0222;
4277 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4279 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4280 /* we're told to make a read-only file writable */
4281 attr.unixModeBits = newScp->unixModeBits | 0222;
4282 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4284 lock_ReleaseMutex(&newScp->mx);
4286 /* now call setattr */
4288 code = cm_SetAttr(newScp, &attr, userp, &req);
4292 cm_ReleaseSCache(newScp);
4293 cm_ReleaseUser(userp);
4298 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4302 cm_scache_t *rootScp;
4303 cm_scache_t *newScp, *dscp;
4315 pathp = smb_GetSMBData(inp, NULL);
4316 pathp = smb_ParseASCIIBlock(pathp, NULL);
4318 return CM_ERROR_BADSMB;
4320 if (*pathp == 0) /* null path */
4323 if (smb_StoreAnsiFilenames)
4324 OemToChar(pathp,pathp);
4326 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4327 osi_LogSaveString(smb_logp, pathp));
4329 rootScp = cm_data.rootSCachep;
4331 userp = smb_GetUser(vcp, inp);
4333 /* we shouldn't need this for V3 requests, but we seem to */
4334 caseFold = CM_FLAG_CASEFOLD;
4336 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4338 cm_ReleaseUser(userp);
4339 return CM_ERROR_NOSUCHFILE;
4343 * XXX Strange hack XXX
4345 * As of Patch 5 (16 July 97), we are having the following problem:
4346 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4347 * requests to look up "desktop.ini" in all the subdirectories.
4348 * This can cause zillions of timeouts looking up non-existent cells
4349 * and volumes, especially in the top-level directory.
4351 * We have not found any way to avoid this or work around it except
4352 * to explicitly ignore the requests for mount points that haven't
4353 * yet been evaluated and for directories that haven't yet been
4356 * We should modify this hack to provide a fake desktop.ini file
4357 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4359 spacep = inp->spacep;
4360 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4361 #ifndef SPECIAL_FOLDERS
4362 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4363 code = cm_NameI(rootScp, spacep->data,
4364 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4365 userp, tidPathp, &req, &dscp);
4368 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4369 if ( WANTS_DFS_PATHNAMES(inp) )
4370 return CM_ERROR_PATH_NOT_COVERED;
4372 return CM_ERROR_BADSHARENAME;
4374 #endif /* DFS_SUPPORT */
4375 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4376 code = CM_ERROR_NOSUCHFILE;
4377 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4378 cm_buf_t *bp = buf_Find(dscp, &hzero);