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>
30 #include <WINNT\afsreg.h>
33 #include "lanahelper.h"
35 /* These characters are illegal in Windows filenames */
36 static char *illegalChars = "\\/:*?\"<>|";
37 BOOL isWindows2000 = FALSE;
39 smb_vc_t *dead_vcp = NULL;
40 smb_vc_t *active_vcp = NULL;
42 /* TODO; logout mechanism needs to be thread-safe */
43 char *loggedOutName = NULL;
44 smb_user_t *loggedOutUserp = NULL;
47 int smbShutdownFlag = 0;
49 int smb_LogoffTokenTransfer;
50 time_t smb_LogoffTransferTimeout;
52 int smb_StoreAnsiFilenames = 0;
54 DWORD last_msg_time = 0;
58 unsigned int sessionGen = 0;
60 extern void afsi_log(char *pattern, ...);
61 extern HANDLE afsi_file;
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t smb_ListenerLock;
72 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
75 long smb_maxObsConcurrentCalls=0;
76 long smb_concurrentCalls=0;
78 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
80 smb_packet_t *smb_packetFreeListp;
81 smb_ncb_t *smb_ncbFreeListp;
83 int smb_NumServerThreads;
85 int numNCBs, numSessions, numVCs;
87 int smb_maxVCPerServer;
88 int smb_maxMpxRequests;
90 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
92 ULONG smb_lsaSecPackage;
93 LSA_STRING smb_lsaLogonOrigin;
95 #define NCBmax MAXIMUM_WAIT_OBJECTS
96 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
97 EVENT_HANDLE **NCBreturns;
98 EVENT_HANDLE **NCBShutdown;
99 EVENT_HANDLE *smb_ServerShutdown;
100 DWORD NCBsessions[NCBmax];
102 struct smb_packet *bufs[NCBmax];
104 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
105 EVENT_HANDLE SessionEvents[Sessionmax];
106 unsigned short LSNs[Sessionmax];
107 int lanas[Sessionmax];
108 BOOL dead_sessions[Sessionmax];
112 osi_mutex_t smb_RawBufLock;
114 #define SMB_RAW_BUFS 4
116 int smb_RawBufSel[SMB_RAW_BUFS];
121 #define SMB_MASKFLAG_TILDE 1
122 #define SMB_MASKFLAG_CASEFOLD 2
124 #define RAWTIMEOUT INFINITE
127 typedef struct raw_write_cont {
140 /* dir search stuff */
141 long smb_dirSearchCounter = 1;
142 smb_dirSearch_t *smb_firstDirSearchp;
143 smb_dirSearch_t *smb_lastDirSearchp;
145 /* hide dot files? */
146 int smb_hideDotFiles;
148 /* global state about V3 protocols */
149 int smb_useV3; /* try to negotiate V3 */
152 static showErrors = 1;
153 /* MessageBox or something like it */
154 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
155 extern HANDLE WaitToTerminate;
159 * Time in Unix format of midnight, 1/1/1970 local time.
160 * When added to dosUTime, gives Unix (AFS) time.
162 time_t smb_localZero = 0;
164 #define USE_NUMERIC_TIME_CONV 1
166 #ifndef USE_NUMERIC_TIME_CONV
167 /* Time difference for converting to kludge-GMT */
168 afs_uint32 smb_NowTZ;
169 #endif /* USE_NUMERIC_TIME_CONV */
171 char *smb_localNamep = NULL;
173 smb_vc_t *smb_allVCsp;
175 smb_username_t *usernamesp = NULL;
177 smb_waitingLock_t *smb_allWaitingLocks;
180 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
181 NCB *ncbp, raw_write_cont_t *rwcp);
182 void smb_NetbiosInit();
184 #ifndef AFS_WIN95_ENV
185 DWORD smb_ServerExceptionFilter(void);
188 extern char cm_HostName[];
189 extern char cm_confDir[];
193 #define LPTSTR char *
194 #define GetComputerName(str, sizep) \
195 strcpy((str), cm_HostName); \
196 *(sizep) = strlen(cm_HostName)
200 void smb_LogPacket(smb_packet_t *packet);
201 #endif /* LOG_PACKET */
203 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
204 int smb_ServerDomainNameLength = 0;
205 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
206 int smb_ServerOSLength = sizeof(smb_ServerOS);
207 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
208 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
210 /* Faux server GUID. This is never checked. */
211 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
213 char * myCrt_Dispatch(int i)
218 return "(00)ReceiveCoreMakeDir";
220 return "(01)ReceiveCoreRemoveDir";
222 return "(02)ReceiveCoreOpen";
224 return "(03)ReceiveCoreCreate";
226 return "(04)ReceiveCoreClose";
228 return "(05)ReceiveCoreFlush";
230 return "(06)ReceiveCoreUnlink";
232 return "(07)ReceiveCoreRename";
234 return "(08)ReceiveCoreGetFileAttributes";
236 return "(09)ReceiveCoreSetFileAttributes";
238 return "(0a)ReceiveCoreRead";
240 return "(0b)ReceiveCoreWrite";
242 return "(0c)ReceiveCoreLockRecord";
244 return "(0d)ReceiveCoreUnlockRecord";
246 return "(0e)SendCoreBadOp";
248 return "(0f)ReceiveCoreCreate";
250 return "(10)ReceiveCoreCheckPath";
252 return "(11)SendCoreBadOp";
254 return "(12)ReceiveCoreSeek";
256 return "(1a)ReceiveCoreReadRaw";
258 return "(1d)ReceiveCoreWriteRawDummy";
260 return "(22)ReceiveV3SetAttributes";
262 return "(23)ReceiveV3GetAttributes";
264 return "(24)ReceiveV3LockingX";
266 return "(25)ReceiveV3Trans";
268 return "(26)ReceiveV3Trans[aux]";
270 return "(29)SendCoreBadOp";
272 return "(2b)ReceiveCoreEcho";
274 return "(2d)ReceiveV3OpenX";
276 return "(2e)ReceiveV3ReadX";
278 return "(32)ReceiveV3Tran2A";
280 return "(33)ReceiveV3Tran2A[aux]";
282 return "(34)ReceiveV3FindClose";
284 return "(35)ReceiveV3FindNotifyClose";
286 return "(70)ReceiveCoreTreeConnect";
288 return "(71)ReceiveCoreTreeDisconnect";
290 return "(72)ReceiveNegotiate";
292 return "(73)ReceiveV3SessionSetupX";
294 return "(74)ReceiveV3UserLogoffX";
296 return "(75)ReceiveV3TreeConnectX";
298 return "(80)ReceiveCoreGetDiskAttributes";
300 return "(81)ReceiveCoreSearchDir";
304 return "(83)FindUnique";
306 return "(84)FindClose";
308 return "(A0)ReceiveNTTransact";
310 return "(A2)ReceiveNTCreateX";
312 return "(A4)ReceiveNTCancel";
314 return "(A5)ReceiveNTRename";
316 return "(C0)OpenPrintFile";
318 return "(C1)WritePrintFile";
320 return "(C2)ClosePrintFile";
322 return "(C3)GetPrintQueue";
324 return "(D8)ReadBulk";
326 return "(D9)WriteBulk";
328 return "(DA)WriteBulkData";
330 return "unknown SMB op";
334 char * myCrt_2Dispatch(int i)
339 return "unknown SMB op-2";
341 return "S(00)CreateFile";
343 return "S(01)FindFirst";
345 return "S(02)FindNext"; /* FindNext */
347 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
351 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
353 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
355 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
357 return "S(08)??_ReceiveTran2SetFileInfo";
359 return "S(09)??_ReceiveTran2FSCTL";
361 return "S(0a)_ReceiveTran2IOCTL";
363 return "S(0b)_ReceiveTran2FindNotifyFirst";
365 return "S(0c)_ReceiveTran2FindNotifyNext";
367 return "S(0d)_ReceiveTran2CreateDirectory";
369 return "S(0e)_ReceiveTran2SessionSetup";
371 return "S(10)_ReceiveTran2GetDfsReferral";
373 return "S(11)_ReceiveTran2ReportDfsInconsistency";
377 char * myCrt_RapDispatch(int i)
382 return "unknown RAP OP";
384 return "RAP(0)NetShareEnum";
386 return "RAP(1)NetShareGetInfo";
388 return "RAP(13)NetServerGetInfo";
390 return "RAP(63)NetWkStaGetInfo";
394 /* scache must be locked */
395 unsigned int smb_Attributes(cm_scache_t *scp)
399 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
400 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
401 scp->fileType == CM_SCACHETYPE_INVALID)
403 attrs = SMB_ATTR_DIRECTORY;
404 #ifdef SPECIAL_FOLDERS
405 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
406 #endif /* SPECIAL_FOLDERS */
407 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
408 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
413 * We used to mark a file RO if it was in an RO volume, but that
414 * turns out to be impolitic in NT. See defect 10007.
417 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
418 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
420 if ((scp->unixModeBits & 0222) == 0)
421 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
427 /* Check if the named file/dir is a dotfile/dotdir */
428 /* String pointed to by lastComp can have leading slashes, but otherwise should have
429 no other patch components */
430 unsigned int smb_IsDotFile(char *lastComp) {
433 /* skip over slashes */
434 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
439 /* nulls, curdir and parent dir doesn't count */
445 if(*(s+1) == '.' && !*(s + 2))
452 static int ExtractBits(WORD bits, short start, short len)
459 num = bits << (16 - end);
460 num = num >> ((16 - end) + start);
466 void ShowUnixTime(char *FuncName, time_t unixTime)
471 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
473 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
474 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
476 int day, month, year, sec, min, hour;
479 day = ExtractBits(wDate, 0, 5);
480 month = ExtractBits(wDate, 5, 4);
481 year = ExtractBits(wDate, 9, 7) + 1980;
483 sec = ExtractBits(wTime, 0, 5);
484 min = ExtractBits(wTime, 5, 6);
485 hour = ExtractBits(wTime, 11, 5);
487 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
488 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
494 /* Determine if we are observing daylight savings time */
495 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
497 TIME_ZONE_INFORMATION timeZoneInformation;
498 SYSTEMTIME utc, local, localDST;
500 /* Get the time zone info. NT uses this to calc if we are in DST. */
501 GetTimeZoneInformation(&timeZoneInformation);
503 /* Return the daylight bias */
504 *pDstBias = timeZoneInformation.DaylightBias;
506 /* Return the bias */
507 *pBias = timeZoneInformation.Bias;
509 /* Now determine if DST is being observed */
511 /* Get the UTC (GMT) time */
514 /* Convert UTC time to local time using the time zone info. If we are
515 observing DST, the calculated local time will include this.
517 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
519 /* Set the daylight bias to 0. The daylight bias is the amount of change
520 * in time that we use for daylight savings time. By setting this to 0
521 * we cause there to be no change in time during daylight savings time.
523 timeZoneInformation.DaylightBias = 0;
525 /* Convert the utc time to local time again, but this time without any
526 adjustment for daylight savings time.
528 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
530 /* If the two times are different, then it means that the localDST that
531 we calculated includes the daylight bias, and therefore we are
532 observing daylight savings time.
534 *pDST = localDST.wHour != local.wHour;
537 /* Determine if we are observing daylight savings time */
538 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
544 *pDstBias = -60; /* where can this be different? */
550 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
552 BOOL dst; /* Will be TRUE if observing DST */
553 LONG dstBias; /* Offset from local time if observing DST */
554 LONG bias; /* Offset from GMT for local time */
557 * This function will adjust the last write time to compensate
558 * for two bugs in the smb client:
560 * 1) During Daylight Savings Time, the LastWriteTime is ahead
561 * in time by the DaylightBias (ignoring the sign - the
562 * DaylightBias is always stored as a negative number). If
563 * the DaylightBias is -60, then the LastWriteTime will be
564 * ahead by 60 minutes.
566 * 2) If the local time zone is a positive offset from GMT, then
567 * the LastWriteTime will be the correct local time plus the
568 * Bias (ignoring the sign - a positive offset from GMT is
569 * always stored as a negative Bias). If the Bias is -120,
570 * then the LastWriteTime will be ahead by 120 minutes.
572 * These bugs can occur at the same time.
575 GetTimeZoneInfo(&dst, &dstBias, &bias);
577 /* First adjust for DST */
579 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
581 /* Now adjust for a positive offset from GMT (a negative bias). */
583 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
586 #ifndef USE_NUMERIC_TIME_CONV
588 * Calculate the difference (in seconds) between local time and GMT.
589 * This enables us to convert file times to kludge-GMT.
595 struct tm gmt_tm, local_tm;
596 int days, hours, minutes, seconds;
599 gmt_tm = *(gmtime(&t));
600 local_tm = *(localtime(&t));
602 days = local_tm.tm_yday - gmt_tm.tm_yday;
603 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
604 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
605 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
609 #endif /* USE_NUMERIC_TIME_CONV */
612 #ifdef USE_NUMERIC_TIME_CONV
613 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
615 // Note that LONGLONG is a 64-bit value
618 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
619 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
620 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
623 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
628 time_t ersatz_unixTime;
631 * Must use kludge-GMT instead of real GMT.
632 * kludge-GMT is computed by adding time zone difference to localtime.
635 * ltp = gmtime(&unixTime);
637 ersatz_unixTime = unixTime - smb_NowTZ;
638 ltp = localtime(&ersatz_unixTime);
640 /* if we fail, make up something */
643 localJunk.tm_year = 89 - 20;
644 localJunk.tm_mon = 4;
645 localJunk.tm_mday = 12;
646 localJunk.tm_hour = 0;
647 localJunk.tm_min = 0;
648 localJunk.tm_sec = 0;
651 stm.wYear = ltp->tm_year + 1900;
652 stm.wMonth = ltp->tm_mon + 1;
653 stm.wDayOfWeek = ltp->tm_wday;
654 stm.wDay = ltp->tm_mday;
655 stm.wHour = ltp->tm_hour;
656 stm.wMinute = ltp->tm_min;
657 stm.wSecond = ltp->tm_sec;
658 stm.wMilliseconds = 0;
660 SystemTimeToFileTime(&stm, largeTimep);
662 #endif /* USE_NUMERIC_TIME_CONV */
664 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
666 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
667 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
668 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
670 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
672 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
673 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
675 *ft = LargeIntegerMultiplyByLong(*ft, 60);
676 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
679 ut = ConvertLongToLargeInteger(unixTime);
680 ut = LargeIntegerMultiplyByLong(ut, 10000000);
681 *ft = LargeIntegerAdd(*ft, ut);
686 #ifdef USE_NUMERIC_TIME_CONV
687 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
689 // Note that LONGLONG is a 64-bit value
692 ll = largeTimep->dwHighDateTime;
694 ll += largeTimep->dwLowDateTime;
696 ll -= 116444736000000000;
699 *unixTimep = (DWORD)ll;
701 #else /* USE_NUMERIC_TIME_CONV */
702 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
708 FileTimeToSystemTime(largeTimep, &stm);
710 lt.tm_year = stm.wYear - 1900;
711 lt.tm_mon = stm.wMonth - 1;
712 lt.tm_wday = stm.wDayOfWeek;
713 lt.tm_mday = stm.wDay;
714 lt.tm_hour = stm.wHour;
715 lt.tm_min = stm.wMinute;
716 lt.tm_sec = stm.wSecond;
719 save_timezone = _timezone;
720 _timezone += smb_NowTZ;
721 *unixTimep = mktime(<);
722 _timezone = save_timezone;
724 #endif /* USE_NUMERIC_TIME_CONV */
726 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
728 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
729 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
730 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
734 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
735 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
736 a = LargeIntegerMultiplyByLong(a, 60);
737 a = LargeIntegerMultiplyByLong(a, 10000000);
739 /* subtract it from ft */
740 a = LargeIntegerSubtract(*ft, a);
742 /* divide down to seconds */
743 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
747 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
755 ltp = localtime((time_t*) &t);
757 /* if we fail, make up something */
760 localJunk.tm_year = 89 - 20;
761 localJunk.tm_mon = 4;
762 localJunk.tm_mday = 12;
763 localJunk.tm_hour = 0;
764 localJunk.tm_min = 0;
765 localJunk.tm_sec = 0;
768 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
769 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
770 *searchTimep = (dosDate<<16) | dosTime;
773 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
775 unsigned short dosDate;
776 unsigned short dosTime;
779 dosDate = (unsigned short) (searchTime & 0xffff);
780 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
782 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
783 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
784 localTm.tm_mday = (dosDate) & 0x1f;
785 localTm.tm_hour = (dosTime>>11) & 0x1f;
786 localTm.tm_min = (dosTime >> 5) & 0x3f;
787 localTm.tm_sec = (dosTime & 0x1f) * 2;
788 localTm.tm_isdst = -1; /* compute whether DST in effect */
790 *unixTimep = mktime(&localTm);
793 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
795 *dosUTimep = unixTime - smb_localZero;
798 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
801 *unixTimep = dosTime + smb_localZero;
803 /* dosTime seems to be already adjusted for GMT */
804 *unixTimep = dosTime;
808 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
812 lock_ObtainWrite(&smb_rctLock);
813 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
814 if (lsn == vcp->lsn && lana == vcp->lana) {
815 smb_HoldVCNoLock(vcp);
819 if (!vcp && (flags & SMB_FLAG_CREATE)) {
820 vcp = malloc(sizeof(*vcp));
821 memset(vcp, 0, sizeof(*vcp));
822 vcp->vcID = numVCs++;
826 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
827 vcp->nextp = smb_allVCsp;
829 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
834 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
835 /* We must obtain a challenge for extended auth
836 * in case the client negotiates smb v3
838 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
839 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
840 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
841 ULONG lsaRespSize = 0;
843 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
845 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
852 if (nts != STATUS_SUCCESS)
853 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
854 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
855 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
857 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
858 LsaFreeReturnBuffer(lsaResp);
861 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
863 lock_ReleaseWrite(&smb_rctLock);
867 int smb_IsStarMask(char *maskp)
872 for(i=0; i<11; i++) {
874 if (tc == '?' || tc == '*' || tc == '>') return 1;
879 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
881 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
883 osi_assert(vcp->refCount-- != 0);
889 void smb_ReleaseVC(smb_vc_t *vcp)
891 lock_ObtainWrite(&smb_rctLock);
892 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
894 osi_assert(vcp->refCount-- != 0);
898 lock_ReleaseWrite(&smb_rctLock);
901 void smb_HoldVCNoLock(smb_vc_t *vcp)
904 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
907 void smb_HoldVC(smb_vc_t *vcp)
909 lock_ObtainWrite(&smb_rctLock);
911 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
912 lock_ReleaseWrite(&smb_rctLock);
915 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
919 lock_ObtainWrite(&smb_rctLock);
920 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
921 if (tid == tidp->tid) {
926 if (!tidp && (flags & SMB_FLAG_CREATE)) {
927 tidp = malloc(sizeof(*tidp));
928 memset(tidp, 0, sizeof(*tidp));
929 tidp->nextp = vcp->tidsp;
932 smb_HoldVCNoLock(vcp);
934 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
937 lock_ReleaseWrite(&smb_rctLock);
941 void smb_ReleaseTID(smb_tid_t *tidp)
948 lock_ObtainWrite(&smb_rctLock);
949 osi_assert(tidp->refCount-- > 0);
950 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
951 ltpp = &tidp->vcp->tidsp;
952 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
956 osi_assert(tp != NULL);
958 lock_FinalizeMutex(&tidp->mx);
959 userp = tidp->userp; /* remember to drop ref later */
961 smb_ReleaseVCNoLock(tidp->vcp);
964 lock_ReleaseWrite(&smb_rctLock);
966 cm_ReleaseUser(userp);
969 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
971 smb_user_t *uidp = NULL;
973 lock_ObtainWrite(&smb_rctLock);
974 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
975 if (uid == uidp->userID) {
977 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
978 (int)vcp, uidp->userID,
979 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
983 if (!uidp && (flags & SMB_FLAG_CREATE)) {
984 uidp = malloc(sizeof(*uidp));
985 memset(uidp, 0, sizeof(*uidp));
986 uidp->nextp = vcp->usersp;
989 smb_HoldVCNoLock(vcp);
991 lock_InitializeMutex(&uidp->mx, "user_t mutex");
993 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL,"VCP[%x] new-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp ? uidp->unp->name : ""));
995 lock_ReleaseWrite(&smb_rctLock);
999 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1001 smb_username_t *unp= NULL;
1003 lock_ObtainWrite(&smb_rctLock);
1004 for(unp = usernamesp; unp; unp = unp->nextp) {
1005 if (stricmp(unp->name, usern) == 0 &&
1006 stricmp(unp->machine, machine) == 0) {
1011 if (!unp && (flags & SMB_FLAG_CREATE)) {
1012 unp = malloc(sizeof(*unp));
1013 memset(unp, 0, sizeof(*unp));
1015 unp->nextp = usernamesp;
1016 unp->name = strdup(usern);
1017 unp->machine = strdup(machine);
1019 lock_InitializeMutex(&unp->mx, "username_t mutex");
1021 lock_ReleaseWrite(&smb_rctLock);
1025 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1027 smb_user_t *uidp= NULL;
1029 lock_ObtainWrite(&smb_rctLock);
1030 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1033 if (stricmp(uidp->unp->name, usern) == 0) {
1035 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
1040 lock_ReleaseWrite(&smb_rctLock);
1043 void smb_ReleaseUID(smb_user_t *uidp)
1050 lock_ObtainWrite(&smb_rctLock);
1051 osi_assert(uidp->refCount-- > 0);
1052 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1053 lupp = &uidp->vcp->usersp;
1054 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1058 osi_assert(up != NULL);
1060 lock_FinalizeMutex(&uidp->mx);
1062 userp = uidp->unp->userp; /* avoid deadlock by releasing */
1063 uidp->unp->userp = NULL; /* after releasing the lock */
1065 smb_ReleaseVCNoLock(uidp->vcp);
1068 lock_ReleaseWrite(&smb_rctLock);
1070 cm_ReleaseUserVCRef(userp);
1071 cm_ReleaseUser(userp);
1076 /* retrieve a held reference to a user structure corresponding to an incoming
1078 * corresponding release function is cm_ReleaseUser.
1080 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1086 smbp = (smb_t *) inp;
1087 uidp = smb_FindUID(vcp, smbp->uid, 0);
1088 if ((!uidp) || (!uidp->unp))
1091 lock_ObtainMutex(&uidp->mx);
1092 up = uidp->unp->userp;
1094 lock_ReleaseMutex(&uidp->mx);
1096 smb_ReleaseUID(uidp);
1102 * Return a pointer to a pathname extracted from a TID structure. The
1103 * TID structure is not held; assume it won't go away.
1105 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1110 tidp = smb_FindTID(vcp, tid, 0);
1114 if (tidp->flags & SMB_TIDFLAG_IPC) {
1115 code = CM_ERROR_TIDIPC;
1116 /* tidp->pathname would be NULL, but that's fine */
1118 *treepath = tidp->pathname;
1119 smb_ReleaseTID(tidp);
1124 /* check to see if we have a chained fid, that is, a fid that comes from an
1125 * OpenAndX message that ran earlier in this packet. In this case, the fid
1126 * field in a read, for example, request, isn't set, since the value is
1127 * supposed to be inherited from the openAndX call.
1129 int smb_ChainFID(int fid, smb_packet_t *inp)
1131 if (inp->fid == 0 || inp->inCount == 0)
1137 /* are we a priv'd user? What does this mean on NT? */
1138 int smb_SUser(cm_user_t *userp)
1143 /* find a file ID. If we pass in 0 we select an used File ID.
1144 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1145 * smb_fid_t data structure if desired File ID cannot be found.
1147 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1152 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1155 lock_ObtainWrite(&smb_rctLock);
1156 /* figure out if we need to allocate a new file ID */
1159 fid = vcp->fidCounter;
1163 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1164 if (fid == fidp->fid) {
1175 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1176 char eventName[MAX_PATH];
1178 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1179 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1180 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1181 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1182 thrd_CloseHandle(event);
1189 fidp = malloc(sizeof(*fidp));
1190 memset(fidp, 0, sizeof(*fidp));
1191 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1194 smb_HoldVCNoLock(vcp);
1195 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1197 fidp->curr_chunk = fidp->prev_chunk = -2;
1198 fidp->raw_write_event = event;
1200 vcp->fidCounter = fid+1;
1201 if (vcp->fidCounter == 0)
1202 vcp->fidCounter = 1;
1205 lock_ReleaseWrite(&smb_rctLock);
1209 void smb_ReleaseFID(smb_fid_t *fidp)
1212 smb_vc_t *vcp = NULL;
1213 smb_ioctl_t *ioctlp;
1219 lock_ObtainWrite(&smb_rctLock);
1220 osi_assert(fidp->refCount-- > 0);
1221 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1224 scp = fidp->scp; /* release after lock is released */
1227 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1228 thrd_CloseHandle(fidp->raw_write_event);
1230 /* and see if there is ioctl stuff to free */
1231 ioctlp = fidp->ioctlp;
1234 cm_FreeSpace(ioctlp->prefix);
1235 if (ioctlp->inAllocp)
1236 free(ioctlp->inAllocp);
1237 if (ioctlp->outAllocp)
1238 free(ioctlp->outAllocp);
1244 smb_ReleaseVCNoLock(vcp);
1246 lock_ReleaseWrite(&smb_rctLock);
1248 /* now release the scache structure */
1250 cm_ReleaseSCache(scp);
1254 * Case-insensitive search for one string in another;
1255 * used to find variable names in submount pathnames.
1257 static char *smb_stristr(char *str1, char *str2)
1261 for (cursor = str1; *cursor; cursor++)
1262 if (stricmp(cursor, str2) == 0)
1269 * Substitute a variable value for its name in a submount pathname. Variable
1270 * name has been identified by smb_stristr() and is in substr. Variable name
1271 * length (plus one) is in substr_size. Variable value is in newstr.
1273 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1278 strcpy(temp, substr + substr_size - 1);
1279 strcpy(substr, newstr);
1283 char VNUserName[] = "%USERNAME%";
1284 char VNLCUserName[] = "%LCUSERNAME%";
1285 char VNComputerName[] = "%COMPUTERNAME%";
1286 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1289 /* List available shares */
1290 int smb_ListShares()
1294 char shareBuf[4096];
1302 /*strcpy(shareNameList[num_shares], "all");
1303 strcpy(pathNameList[num_shares++], "/afs");*/
1304 fprintf(stderr, "The following shares are available:\n");
1305 fprintf(stderr, "Share Name (AFS Path)\n");
1306 fprintf(stderr, "---------------------\n");
1307 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1310 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1311 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1313 strcpy(sbmtpath, cm_confDir);
1315 strcat(sbmtpath, "/afsdsbmt.ini");
1316 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1317 shareBuf, sizeof(shareBuf),
1323 this_share = shareBuf;
1327 /*strcpy(shareNameList[num_shares], this_share);*/
1328 len = GetPrivateProfileString("AFS Submounts", this_share,
1335 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1338 if (*p == '\\') *p = '/'; /* change to / */
1342 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1343 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1346 while (*this_share != 0) this_share++; /* find next NUL */
1347 this_share++; /* skip past the NUL */
1348 } while (*this_share != 0); /* stop at final NUL */
1354 typedef struct smb_findShare_rock {
1358 } smb_findShare_rock_t;
1360 #define SMB_FINDSHARE_EXACT_MATCH 1
1361 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1363 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1367 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1368 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1369 if(!stricmp(dep->name, vrock->shareName))
1370 matchType = SMB_FINDSHARE_EXACT_MATCH;
1372 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1373 if(vrock->match) free(vrock->match);
1374 vrock->match = strdup(dep->name);
1375 vrock->matchType = matchType;
1377 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1378 return CM_ERROR_STOPNOW;
1384 /* find a shareName in the table of submounts */
1385 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1389 char pathName[1024];
1394 char sbmtpath[MAX_PATH];
1399 DWORD allSubmount = 1;
1401 /* if allSubmounts == 0, only return the //mountRoot/all share
1402 * if in fact it has been been created in the subMounts table.
1403 * This is to allow sites that want to restrict access to the
1406 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1407 0, KEY_QUERY_VALUE, &parmKey);
1408 if (code == ERROR_SUCCESS) {
1409 len = sizeof(allSubmount);
1410 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1411 (BYTE *) &allSubmount, &len);
1412 if (code != ERROR_SUCCESS) {
1415 RegCloseKey (parmKey);
1418 if (allSubmount && _stricmp(shareName, "all") == 0) {
1423 /* In case, the all share is disabled we need to still be able
1424 * to handle ioctl requests
1426 if (_stricmp(shareName, "ioctl$") == 0) {
1427 *pathNamep = strdup("/.__ioctl__");
1431 if (_stricmp(shareName, "IPC$") == 0 ||
1432 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1433 _stricmp(shareName, "DESKTOP.INI") == 0
1440 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1441 0, KEY_QUERY_VALUE, &parmKey);
1442 if (code == ERROR_SUCCESS) {
1443 len = sizeof(pathName);
1444 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1445 (BYTE *) pathName, &len);
1446 if (code != ERROR_SUCCESS)
1448 RegCloseKey (parmKey);
1453 strcpy(sbmtpath, cm_confDir);
1454 strcat(sbmtpath, "/afsdsbmt.ini");
1455 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1456 pathName, sizeof(pathName), sbmtpath);
1458 if (len != 0 && len != sizeof(pathName) - 1) {
1459 /* We can accept either unix or PC style AFS pathnames. Convert
1460 * Unix-style to PC style here for internal use.
1463 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1464 p += strlen(cm_mountRoot); /* skip mount path */
1467 if (*q == '/') *q = '\\'; /* change to \ */
1473 if (var = smb_stristr(p, VNUserName)) {
1474 if (uidp && uidp->unp)
1475 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1477 smb_subst(p, var, sizeof(VNUserName)," ");
1479 else if (var = smb_stristr(p, VNLCUserName))
1481 if (uidp && uidp->unp)
1482 strcpy(temp, uidp->unp->name);
1486 smb_subst(p, var, sizeof(VNLCUserName), temp);
1488 else if (var = smb_stristr(p, VNComputerName))
1490 sizeTemp = sizeof(temp);
1491 GetComputerName((LPTSTR)temp, &sizeTemp);
1492 smb_subst(p, var, sizeof(VNComputerName), temp);
1494 else if (var = smb_stristr(p, VNLCComputerName))
1496 sizeTemp = sizeof(temp);
1497 GetComputerName((LPTSTR)temp, &sizeTemp);
1499 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1504 *pathNamep = strdup(p);
1509 /* First lookup shareName in root.afs */
1511 smb_findShare_rock_t vrock;
1513 char * p = shareName;
1516 /* attempt to locate a partial match in root.afs. This is because
1517 when using the ANSI RAP calls, the share name is limited to 13 chars
1518 and hence is truncated. Of course we prefer exact matches. */
1520 thyper.HighPart = 0;
1523 vrock.shareName = shareName;
1525 vrock.matchType = 0;
1527 cm_HoldSCache(cm_data.rootSCachep);
1528 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1529 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1530 cm_ReleaseSCache(cm_data.rootSCachep);
1532 if (vrock.matchType) {
1533 sprintf(pathName,"/%s/",vrock.match);
1534 *pathNamep = strdup(strlwr(pathName));
1539 /* if we get here, there was no match for the share in root.afs */
1540 /* so try to create \\<netbiosName>\<cellname> */
1545 /* Get the full name for this cell */
1546 code = cm_SearchCellFile(p, temp, 0, 0);
1547 #ifdef AFS_AFSDB_ENV
1548 if (code && cm_dnsEnabled) {
1550 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1553 /* construct the path */
1555 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1556 *pathNamep = strdup(strlwr(pathName));
1565 /* Client-side offline caching policy types */
1566 #define CSC_POLICY_MANUAL 0
1567 #define CSC_POLICY_DOCUMENTS 1
1568 #define CSC_POLICY_PROGRAMS 2
1569 #define CSC_POLICY_DISABLE 3
1571 int smb_FindShareCSCPolicy(char *shareName)
1577 int retval = CSC_POLICY_MANUAL;
1579 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1580 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1583 REG_OPTION_NON_VOLATILE,
1589 len = sizeof(policy);
1590 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1592 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1594 else if (stricmp(policy, "documents") == 0)
1596 retval = CSC_POLICY_DOCUMENTS;
1598 else if (stricmp(policy, "programs") == 0)
1600 retval = CSC_POLICY_PROGRAMS;
1602 else if (stricmp(policy, "disable") == 0)
1604 retval = CSC_POLICY_DISABLE;
1607 RegCloseKey(hkCSCPolicy);
1611 /* find a dir search structure by cookie value, and return it held.
1612 * Must be called with smb_globalLock held.
1614 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1616 smb_dirSearch_t *dsp;
1618 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1619 if (dsp->cookie == cookie) {
1620 if (dsp != smb_firstDirSearchp) {
1621 /* move to head of LRU queue, too, if we're not already there */
1622 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1623 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1624 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1625 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1626 if (!smb_lastDirSearchp)
1627 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1629 lock_ObtainMutex(&dsp->mx);
1631 lock_ReleaseMutex(&dsp->mx);
1637 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1638 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1639 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1645 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1647 lock_ObtainWrite(&smb_globalLock);
1648 lock_ObtainMutex(&dsp->mx);
1649 dsp->flags |= SMB_DIRSEARCH_DELETE;
1650 if (dsp->scp != NULL) {
1651 lock_ObtainMutex(&dsp->scp->mx);
1652 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1653 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1654 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1655 dsp->scp->bulkStatProgress = hones;
1657 lock_ReleaseMutex(&dsp->scp->mx);
1659 lock_ReleaseMutex(&dsp->mx);
1660 lock_ReleaseWrite(&smb_globalLock);
1663 /* Must be called with the smb_globalLock held */
1664 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1666 cm_scache_t *scp = NULL;
1668 lock_ObtainMutex(&dsp->mx);
1669 osi_assert(dsp->refCount-- > 0);
1670 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1671 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1672 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1673 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1674 lock_ReleaseMutex(&dsp->mx);
1675 lock_FinalizeMutex(&dsp->mx);
1679 lock_ReleaseMutex(&dsp->mx);
1681 /* do this now to avoid spurious locking hierarchy creation */
1682 if (scp) cm_ReleaseSCache(scp);
1685 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1687 lock_ObtainWrite(&smb_globalLock);
1688 smb_ReleaseDirSearchNoLock(dsp);
1689 lock_ReleaseWrite(&smb_globalLock);
1692 /* find a dir search structure by cookie value, and return it held */
1693 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1695 smb_dirSearch_t *dsp;
1697 lock_ObtainWrite(&smb_globalLock);
1698 dsp = smb_FindDirSearchNoLock(cookie);
1699 lock_ReleaseWrite(&smb_globalLock);
1703 /* GC some dir search entries, in the address space expected by the specific protocol.
1704 * Must be called with smb_globalLock held; release the lock temporarily.
1706 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1707 void smb_GCDirSearches(int isV3)
1709 smb_dirSearch_t *prevp;
1710 smb_dirSearch_t *tp;
1711 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1715 victimCount = 0; /* how many have we got so far */
1716 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1717 /* we'll move tp from queue, so
1720 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1721 /* if no one is using this guy, and we're either in the new protocol,
1722 * or we're in the old one and this is a small enough ID to be useful
1723 * to the old protocol, GC this guy.
1725 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1726 /* hold and delete */
1727 tp->flags |= SMB_DIRSEARCH_DELETE;
1728 victimsp[victimCount++] = tp;
1732 /* don't do more than this */
1733 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1737 /* now release them */
1738 for (i = 0; i < victimCount; i++) {
1739 smb_ReleaseDirSearchNoLock(victimsp[i]);
1743 /* function for allocating a dir search entry. We need these to remember enough context
1744 * since we don't get passed the path from call to call during a directory search.
1746 * Returns a held dir search structure, and bumps the reference count on the vnode,
1747 * since it saves a pointer to the vnode.
1749 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1751 smb_dirSearch_t *dsp;
1757 lock_ObtainWrite(&smb_globalLock);
1760 /* what's the biggest ID allowed in this version of the protocol */
1761 maxAllowed = isV3 ? 65535 : 255;
1762 if (smb_dirSearchCounter > maxAllowed)
1763 smb_dirSearchCounter = 1;
1765 start = smb_dirSearchCounter;
1768 /* twice so we have enough tries to find guys we GC after one pass;
1769 * 10 extra is just in case I mis-counted.
1771 if (++counter > 2*maxAllowed+10)
1772 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1774 if (smb_dirSearchCounter > maxAllowed) {
1775 smb_dirSearchCounter = 1;
1777 if (smb_dirSearchCounter == start) {
1779 smb_GCDirSearches(isV3);
1782 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1784 /* don't need to watch for refcount zero and deleted, since
1785 * we haven't dropped the global lock.
1787 lock_ObtainMutex(&dsp->mx);
1789 lock_ReleaseMutex(&dsp->mx);
1790 ++smb_dirSearchCounter;
1794 dsp = malloc(sizeof(*dsp));
1795 memset(dsp, 0, sizeof(*dsp));
1796 dsp->cookie = smb_dirSearchCounter;
1797 ++smb_dirSearchCounter;
1799 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1800 dsp->lastTime = osi_Time();
1801 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1802 if (!smb_lastDirSearchp)
1803 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1806 lock_ReleaseWrite(&smb_globalLock);
1810 static smb_packet_t *GetPacket(void)
1814 unsigned int npar, seg, tb_sel;
1817 lock_ObtainWrite(&smb_globalLock);
1818 tbp = smb_packetFreeListp;
1820 smb_packetFreeListp = tbp->nextp;
1821 lock_ReleaseWrite(&smb_globalLock);
1824 tbp = calloc(65540,1);
1826 tbp = malloc(sizeof(smb_packet_t));
1828 tbp->magic = SMB_PACKETMAGIC;
1831 tbp->resumeCode = 0;
1837 tbp->ncb_length = 0;
1842 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1845 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1847 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1849 osi_panic("",__FILE__,__LINE__);
1852 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1857 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1858 tbp->dos_pkt_sel = tb_sel;
1861 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1866 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1870 memcpy(tbp, pkt, sizeof(smb_packet_t));
1871 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1873 smb_HoldVC(tbp->vcp);
1877 static NCB *GetNCB(void)
1882 unsigned int npar, seg, tb_sel;
1885 lock_ObtainWrite(&smb_globalLock);
1886 tbp = smb_ncbFreeListp;
1888 smb_ncbFreeListp = tbp->nextp;
1889 lock_ReleaseWrite(&smb_globalLock);
1892 tbp = calloc(sizeof(*tbp),1);
1894 tbp = malloc(sizeof(*tbp));
1895 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1898 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1900 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1902 osi_panic("",__FILE__,__LINE__);
1904 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1909 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1910 tbp->dos_ncb_sel = tb_sel;
1912 tbp->magic = SMB_NCBMAGIC;
1915 osi_assert(tbp->magic == SMB_NCBMAGIC);
1917 memset(&tbp->ncb, 0, sizeof(NCB));
1920 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1925 void smb_FreePacket(smb_packet_t *tbp)
1927 smb_vc_t * vcp = NULL;
1928 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1930 lock_ObtainWrite(&smb_globalLock);
1931 tbp->nextp = smb_packetFreeListp;
1932 smb_packetFreeListp = tbp;
1933 tbp->magic = SMB_PACKETMAGIC;
1937 tbp->resumeCode = 0;
1943 tbp->ncb_length = 0;
1945 lock_ReleaseWrite(&smb_globalLock);
1951 static void FreeNCB(NCB *bufferp)
1955 tbp = (smb_ncb_t *) bufferp;
1956 osi_assert(tbp->magic == SMB_NCBMAGIC);
1958 lock_ObtainWrite(&smb_globalLock);
1959 tbp->nextp = smb_ncbFreeListp;
1960 smb_ncbFreeListp = tbp;
1961 lock_ReleaseWrite(&smb_globalLock);
1964 /* get a ptr to the data part of a packet, and its count */
1965 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1969 unsigned char *afterParmsp;
1971 parmBytes = *smbp->wctp << 1;
1972 afterParmsp = smbp->wctp + parmBytes + 1;
1974 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1975 if (nbytesp) *nbytesp = dataBytes;
1977 /* don't forget to skip the data byte count, since it follows
1978 * the parameters; that's where the "2" comes from below.
1980 return (unsigned char *) (afterParmsp + 2);
1983 /* must set all the returned parameters before playing around with the
1984 * data region, since the data region is located past the end of the
1985 * variable number of parameters.
1987 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1989 unsigned char *afterParmsp;
1991 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1993 *afterParmsp++ = dsize & 0xff;
1994 *afterParmsp = (dsize>>8) & 0xff;
1997 /* return the parm'th parameter in the smbp packet */
1998 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2001 unsigned char *parmDatap;
2003 parmCount = *smbp->wctp;
2005 if (parm >= parmCount) {
2010 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2012 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2013 parm, parmCount, smbp->ncb_length);
2016 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2017 1, smbp->ncb_length, ptbuf, smbp);
2018 DeregisterEventSource(h);
2020 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2021 parm, parmCount, smbp->ncb_length);
2022 osi_panic(s, __FILE__, __LINE__);
2024 parmDatap = smbp->wctp + (2*parm) + 1;
2026 return parmDatap[0] + (parmDatap[1] << 8);
2029 /* return the parm'th parameter in the smbp packet */
2030 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2033 unsigned char *parmDatap;
2035 parmCount = *smbp->wctp;
2037 if (parm * 2 + offset >= parmCount * 2) {
2042 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2044 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2045 parm, offset, parmCount, smbp->ncb_length);
2048 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2049 1, smbp->ncb_length, ptbuf, smbp);
2050 DeregisterEventSource(h);
2052 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2053 parm, offset, parmCount, smbp->ncb_length);
2054 osi_panic(s, __FILE__, __LINE__);
2056 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2058 return parmDatap[0] + (parmDatap[1] << 8);
2061 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2065 /* make sure we have enough slots */
2066 if (*smbp->wctp <= slot)
2067 *smbp->wctp = slot+1;
2069 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2070 *parmDatap++ = parmValue & 0xff;
2071 *parmDatap = (parmValue>>8) & 0xff;
2074 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2078 /* make sure we have enough slots */
2079 if (*smbp->wctp <= slot)
2080 *smbp->wctp = slot+2;
2082 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2083 *parmDatap++ = parmValue & 0xff;
2084 *parmDatap++ = (parmValue>>8) & 0xff;
2085 *parmDatap++ = (parmValue>>16) & 0xff;
2086 *parmDatap++ = (parmValue>>24) & 0xff;
2089 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2094 /* make sure we have enough slots */
2095 if (*smbp->wctp <= slot)
2096 *smbp->wctp = slot+4;
2098 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2100 *parmDatap++ = *parmValuep++;
2103 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2107 /* make sure we have enough slots */
2108 if (*smbp->wctp <= slot) {
2109 if (smbp->oddByte) {
2111 *smbp->wctp = slot+1;
2116 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2117 *parmDatap++ = parmValue & 0xff;
2120 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2124 lastSlashp = strrchr(inPathp, '\\');
2126 *lastComponentp = lastSlashp;
2129 if (inPathp == lastSlashp)
2131 *outPathp++ = *inPathp++;
2140 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2145 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2150 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2156 tlen = inp[0] + (inp[1]<<8);
2157 inp += 2; /* skip length field */
2160 *chainpp = inp + tlen;
2169 /* format a packet as a response */
2170 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2175 outp = (smb_t *) op;
2177 /* zero the basic structure through the smb_wct field, and zero the data
2178 * size field, assuming that wct stays zero; otherwise, you have to
2179 * explicitly set the data size field, too.
2181 inSmbp = (smb_t *) inp;
2182 memset(outp, 0, sizeof(smb_t)+2);
2188 outp->com = inSmbp->com;
2189 outp->tid = inSmbp->tid;
2190 outp->pid = inSmbp->pid;
2191 outp->uid = inSmbp->uid;
2192 outp->mid = inSmbp->mid;
2193 outp->res[0] = inSmbp->res[0];
2194 outp->res[1] = inSmbp->res[1];
2195 op->inCom = inSmbp->com;
2197 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2198 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2200 /* copy fields in generic packet area */
2201 op->wctp = &outp->wct;
2204 /* send a (probably response) packet; vcp tells us to whom to send it.
2205 * we compute the length by looking at wct and bcc fields.
2207 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2224 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2227 memset((char *)ncbp, 0, sizeof(NCB));
2229 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2230 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2231 extra += tp[0] + (tp[1]<<8);
2232 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2233 extra += 3; /* wct and length fields */
2235 ncbp->ncb_length = extra; /* bytes to send */
2236 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2237 ncbp->ncb_lana_num = vcp->lana;
2238 ncbp->ncb_command = NCBSEND; /* op means send data */
2240 ncbp->ncb_buffer = (char *) inp;/* packet */
2241 code = Netbios(ncbp);
2243 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2244 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2246 /* copy header information from virtual to DOS address space */
2247 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2248 code = Netbios(ncbp, dos_ncb);
2252 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2258 void smb_MapNTError(long code, unsigned long *NTStatusp)
2260 unsigned long NTStatus;
2262 /* map CM_ERROR_* errors to NT 32-bit status codes */
2263 /* NT Status codes are listed in ntstatus.h not winerror.h */
2264 if (code == CM_ERROR_NOSUCHCELL) {
2265 NTStatus = 0xC000000FL; /* No such file */
2267 else if (code == CM_ERROR_NOSUCHVOLUME) {
2268 NTStatus = 0xC000000FL; /* No such file */
2270 else if (code == CM_ERROR_TIMEDOUT) {
2271 NTStatus = 0xC00000CFL; /* Sharing Paused */
2273 else if (code == CM_ERROR_RETRY) {
2274 NTStatus = 0xC000022DL; /* Retry */
2276 else if (code == CM_ERROR_NOACCESS) {
2277 NTStatus = 0xC0000022L; /* Access denied */
2279 else if (code == CM_ERROR_READONLY) {
2280 NTStatus = 0xC00000A2L; /* Write protected */
2282 else if (code == CM_ERROR_NOSUCHFILE) {
2283 NTStatus = 0xC000000FL; /* No such file */
2285 else if (code == CM_ERROR_NOSUCHPATH) {
2286 NTStatus = 0xC000003AL; /* Object path not found */
2288 else if (code == CM_ERROR_TOOBIG) {
2289 NTStatus = 0xC000007BL; /* Invalid image format */
2291 else if (code == CM_ERROR_INVAL) {
2292 NTStatus = 0xC000000DL; /* Invalid parameter */
2294 else if (code == CM_ERROR_BADFD) {
2295 NTStatus = 0xC0000008L; /* Invalid handle */
2297 else if (code == CM_ERROR_BADFDOP) {
2298 NTStatus = 0xC0000022L; /* Access denied */
2300 else if (code == CM_ERROR_EXISTS) {
2301 NTStatus = 0xC0000035L; /* Object name collision */
2303 else if (code == CM_ERROR_NOTEMPTY) {
2304 NTStatus = 0xC0000101L; /* Directory not empty */
2306 else if (code == CM_ERROR_CROSSDEVLINK) {
2307 NTStatus = 0xC00000D4L; /* Not same device */
2309 else if (code == CM_ERROR_NOTDIR) {
2310 NTStatus = 0xC0000103L; /* Not a directory */
2312 else if (code == CM_ERROR_ISDIR) {
2313 NTStatus = 0xC00000BAL; /* File is a directory */
2315 else if (code == CM_ERROR_BADOP) {
2317 /* I have no idea where this comes from */
2318 NTStatus = 0xC09820FFL; /* SMB no support */
2320 NTStatus = 0xC00000BBL; /* Not supported */
2321 #endif /* COMMENT */
2323 else if (code == CM_ERROR_BADSHARENAME) {
2324 NTStatus = 0xC00000CCL; /* Bad network name */
2326 else if (code == CM_ERROR_NOIPC) {
2328 NTStatus = 0xC0000022L; /* Access Denied */
2330 NTStatus = 0xC000013DL; /* Remote Resources */
2333 else if (code == CM_ERROR_CLOCKSKEW) {
2334 NTStatus = 0xC0000133L; /* Time difference at DC */
2336 else if (code == CM_ERROR_BADTID) {
2337 NTStatus = 0xC0982005L; /* SMB bad TID */
2339 else if (code == CM_ERROR_USESTD) {
2340 NTStatus = 0xC09820FBL; /* SMB use standard */
2342 else if (code == CM_ERROR_QUOTA) {
2344 NTStatus = 0xC0000044L; /* Quota exceeded */
2346 NTStatus = 0xC000007FL; /* Disk full */
2349 else if (code == CM_ERROR_SPACE) {
2350 NTStatus = 0xC000007FL; /* Disk full */
2352 else if (code == CM_ERROR_ATSYS) {
2353 NTStatus = 0xC0000033L; /* Object name invalid */
2355 else if (code == CM_ERROR_BADNTFILENAME) {
2356 NTStatus = 0xC0000033L; /* Object name invalid */
2358 else if (code == CM_ERROR_WOULDBLOCK) {
2359 NTStatus = 0xC0000055L; /* Lock not granted */
2361 else if (code == CM_ERROR_PARTIALWRITE) {
2362 NTStatus = 0xC000007FL; /* Disk full */
2364 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2365 NTStatus = 0xC0000023L; /* Buffer too small */
2367 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2368 NTStatus = 0xC0000035L; /* Object name collision */
2370 else if (code == CM_ERROR_BADPASSWORD) {
2371 NTStatus = 0xC000006DL; /* unknown username or bad password */
2373 else if (code == CM_ERROR_BADLOGONTYPE) {
2374 NTStatus = 0xC000015BL; /* logon type not granted */
2376 else if (code == CM_ERROR_GSSCONTINUE) {
2377 NTStatus = 0xC0000016L; /* more processing required */
2379 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2381 NTStatus = 0xC0000280L; /* reparse point not resolved */
2383 NTStatus = 0xC0000022L; /* Access Denied */
2386 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2387 NTStatus = 0xC0000257L; /* Path Not Covered */
2389 else if (code == CM_ERROR_ALLBUSY) {
2390 NTStatus = 0xC00000BFL; /* Network Busy */
2392 NTStatus = 0xC0982001L; /* SMB non-specific error */
2395 *NTStatusp = NTStatus;
2396 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2399 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2400 unsigned char *classp)
2402 unsigned char class;
2403 unsigned short error;
2405 /* map CM_ERROR_* errors to SMB errors */
2406 if (code == CM_ERROR_NOSUCHCELL) {
2408 error = 3; /* bad path */
2410 else if (code == CM_ERROR_NOSUCHVOLUME) {
2412 error = 3; /* bad path */
2414 else if (code == CM_ERROR_TIMEDOUT) {
2416 error = 81; /* server is paused */
2418 else if (code == CM_ERROR_RETRY) {
2419 class = 2; /* shouldn't happen */
2422 else if (code == CM_ERROR_NOACCESS) {
2424 error = 4; /* bad access */
2426 else if (code == CM_ERROR_READONLY) {
2428 error = 19; /* read only */
2430 else if (code == CM_ERROR_NOSUCHFILE) {
2432 error = 2; /* ENOENT! */
2434 else if (code == CM_ERROR_NOSUCHPATH) {
2436 error = 3; /* Bad path */
2438 else if (code == CM_ERROR_TOOBIG) {
2440 error = 11; /* bad format */
2442 else if (code == CM_ERROR_INVAL) {
2443 class = 2; /* server non-specific error code */
2446 else if (code == CM_ERROR_BADFD) {
2448 error = 6; /* invalid file handle */
2450 else if (code == CM_ERROR_BADFDOP) {
2451 class = 1; /* invalid op on FD */
2454 else if (code == CM_ERROR_EXISTS) {
2456 error = 80; /* file already exists */
2458 else if (code == CM_ERROR_NOTEMPTY) {
2460 error = 5; /* delete directory not empty */
2462 else if (code == CM_ERROR_CROSSDEVLINK) {
2464 error = 17; /* EXDEV */
2466 else if (code == CM_ERROR_NOTDIR) {
2467 class = 1; /* bad path */
2470 else if (code == CM_ERROR_ISDIR) {
2471 class = 1; /* access denied; DOS doesn't have a good match */
2474 else if (code == CM_ERROR_BADOP) {
2478 else if (code == CM_ERROR_BADSHARENAME) {
2482 else if (code == CM_ERROR_NOIPC) {
2484 error = 4; /* bad access */
2486 else if (code == CM_ERROR_CLOCKSKEW) {
2487 class = 1; /* invalid function */
2490 else if (code == CM_ERROR_BADTID) {
2494 else if (code == CM_ERROR_USESTD) {
2498 else if (code == CM_ERROR_REMOTECONN) {
2502 else if (code == CM_ERROR_QUOTA) {
2503 if (vcp->flags & SMB_VCFLAG_USEV3) {
2505 error = 39; /* disk full */
2509 error = 5; /* access denied */
2512 else if (code == CM_ERROR_SPACE) {
2513 if (vcp->flags & SMB_VCFLAG_USEV3) {
2515 error = 39; /* disk full */
2519 error = 5; /* access denied */
2522 else if (code == CM_ERROR_PARTIALWRITE) {
2524 error = 39; /* disk full */
2526 else if (code == CM_ERROR_ATSYS) {
2528 error = 2; /* ENOENT */
2530 else if (code == CM_ERROR_WOULDBLOCK) {
2532 error = 33; /* lock conflict */
2534 else if (code == CM_ERROR_NOFILES) {
2536 error = 18; /* no files in search */
2538 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2540 error = 183; /* Samba uses this */
2542 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2543 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2545 error = 2; /* bad password */
2547 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2549 error = 3; /* bad path */
2558 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2561 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2563 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2564 return CM_ERROR_BADOP;
2567 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2569 unsigned short EchoCount, i;
2570 char *data, *outdata;
2573 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2575 for (i=1; i<=EchoCount; i++) {
2576 data = smb_GetSMBData(inp, &dataSize);
2577 smb_SetSMBParm(outp, 0, i);
2578 smb_SetSMBDataLength(outp, dataSize);
2579 outdata = smb_GetSMBData(outp, NULL);
2580 memcpy(outdata, data, dataSize);
2581 smb_SendPacket(vcp, outp);
2587 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2590 long count, minCount, finalCount;
2594 cm_user_t *userp = NULL;
2598 char *rawBuf = NULL;
2600 dos_ptr rawBuf = NULL;
2607 fd = smb_GetSMBParm(inp, 0);
2608 count = smb_GetSMBParm(inp, 3);
2609 minCount = smb_GetSMBParm(inp, 4);
2610 offset.HighPart = 0; /* too bad */
2611 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2613 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2614 fd, offset.LowPart, count);
2616 fidp = smb_FindFID(vcp, fd, 0);
2620 lock_ObtainMutex(&smb_RawBufLock);
2622 /* Get a raw buf, from head of list */
2623 rawBuf = smb_RawBufs;
2625 smb_RawBufs = *(char **)smb_RawBufs;
2627 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2630 lock_ReleaseMutex(&smb_RawBufLock);
2634 if (fidp->flags & SMB_FID_IOCTL)
2637 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2639 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2642 /* Give back raw buffer */
2643 lock_ObtainMutex(&smb_RawBufLock);
2645 *((char **) rawBuf) = smb_RawBufs;
2647 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2650 smb_RawBufs = rawBuf;
2651 lock_ReleaseMutex(&smb_RawBufLock);
2654 smb_ReleaseFID(fidp);
2658 userp = smb_GetUser(vcp, inp);
2661 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2663 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2664 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2665 userp, &finalCount, TRUE /* rawFlag */);
2672 cm_ReleaseUser(userp);
2675 smb_ReleaseFID(fidp);
2680 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2682 memset((char *)ncbp, 0, sizeof(NCB));
2684 ncbp->ncb_length = (unsigned short) finalCount;
2685 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2686 ncbp->ncb_lana_num = vcp->lana;
2687 ncbp->ncb_command = NCBSEND;
2688 ncbp->ncb_buffer = rawBuf;
2691 code = Netbios(ncbp);
2693 code = Netbios(ncbp, dos_ncb);
2696 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2699 /* Give back raw buffer */
2700 lock_ObtainMutex(&smb_RawBufLock);
2702 *((char **) rawBuf) = smb_RawBufs;
2704 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2707 smb_RawBufs = rawBuf;
2708 lock_ReleaseMutex(&smb_RawBufLock);
2714 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2716 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2721 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2723 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2728 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2735 int protoIndex; /* index we're using */
2740 char protocol_array[10][1024]; /* protocol signature of the client */
2741 int caps; /* capabilities */
2744 TIME_ZONE_INFORMATION tzi;
2746 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2750 DWORD now = GetCurrentTime();
2751 if (now - last_msg_time >= 30000
2752 && now - last_msg_time <= 90000) {
2754 "Setting dead_vcp %x", active_vcp);
2756 smb_ReleaseVC(dead_vcp);
2758 "Previous dead_vcp %x", dead_vcp);
2760 smb_HoldVC(active_vcp);
2761 dead_vcp = active_vcp;
2762 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2767 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2769 namep = smb_GetSMBData(inp, &dbytes);
2772 coreProtoIndex = -1; /* not found */
2775 while(namex < dbytes) {
2776 osi_Log1(smb_logp, "Protocol %s",
2777 osi_LogSaveString(smb_logp, namep+1));
2778 strcpy(protocol_array[tcounter], namep+1);
2780 /* namep points at the first protocol, or really, a 0x02
2781 * byte preceding the null-terminated ASCII name.
2783 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2784 coreProtoIndex = tcounter;
2786 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2787 v3ProtoIndex = tcounter;
2789 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2790 NTProtoIndex = tcounter;
2793 /* compute size of protocol entry */
2794 entryLength = strlen(namep+1);
2795 entryLength += 2; /* 0x02 bytes and null termination */
2797 /* advance over this protocol entry */
2798 namex += entryLength;
2799 namep += entryLength;
2800 tcounter++; /* which proto entry we're looking at */
2803 if (NTProtoIndex != -1) {
2804 protoIndex = NTProtoIndex;
2805 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2807 else if (v3ProtoIndex != -1) {
2808 protoIndex = v3ProtoIndex;
2809 vcp->flags |= SMB_VCFLAG_USEV3;
2811 else if (coreProtoIndex != -1) {
2812 protoIndex = coreProtoIndex;
2813 vcp->flags |= SMB_VCFLAG_USECORE;
2815 else protoIndex = -1;
2817 if (protoIndex == -1)
2818 return CM_ERROR_INVAL;
2819 else if (NTProtoIndex != -1) {
2820 smb_SetSMBParm(outp, 0, protoIndex);
2821 if (smb_authType != SMB_AUTH_NONE) {
2822 smb_SetSMBParmByte(outp, 1,
2823 NEGOTIATE_SECURITY_USER_LEVEL |
2824 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2826 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2828 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2829 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2830 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2831 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2832 /* The session key is not a well documented field however most clients
2833 * will echo back the session key to the server. Currently we are using
2834 * the same value for all sessions. We should generate a random value
2835 * and store it into the vcp
2837 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2838 smb_SetSMBParm(outp, 8, 1);
2840 * Tried changing the capabilities to support for W2K - defect 117695
2841 * Maybe something else needs to be changed here?
2845 smb_SetSMBParmLong(outp, 9, 0x43fd);
2847 smb_SetSMBParmLong(outp, 9, 0x251);
2850 * 32-bit error codes *
2855 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2857 NTNEGOTIATE_CAPABILITY_DFS |
2859 NTNEGOTIATE_CAPABILITY_NTFIND |
2860 NTNEGOTIATE_CAPABILITY_RAWMODE |
2861 NTNEGOTIATE_CAPABILITY_NTSMB;
2863 if ( smb_authType == SMB_AUTH_EXTENDED )
2864 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2866 smb_SetSMBParmLong(outp, 9, caps);
2868 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2869 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2870 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2872 GetTimeZoneInformation(&tzi);
2873 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2875 if (smb_authType == SMB_AUTH_NTLM) {
2876 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2877 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2878 /* paste in encryption key */
2879 datap = smb_GetSMBData(outp, NULL);
2880 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2881 /* and the faux domain name */
2882 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2883 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2887 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2889 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2891 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2893 datap = smb_GetSMBData(outp, NULL);
2894 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2897 datap += sizeof(smb_ServerGUID);
2898 memcpy(datap, secBlob, secBlobLength);
2902 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2903 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2906 else if (v3ProtoIndex != -1) {
2907 smb_SetSMBParm(outp, 0, protoIndex);
2909 /* NOTE: Extended authentication cannot be negotiated with v3
2910 * therefore we fail over to NTLM
2912 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2913 smb_SetSMBParm(outp, 1,
2914 NEGOTIATE_SECURITY_USER_LEVEL |
2915 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2917 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2919 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2920 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2921 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2922 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2923 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2924 smb_SetSMBParm(outp, 7, 1);
2926 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2927 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2928 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2930 GetTimeZoneInformation(&tzi);
2931 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2933 /* NOTE: Extended authentication cannot be negotiated with v3
2934 * therefore we fail over to NTLM
2936 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2937 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2938 smb_SetSMBParm(outp, 12, 0); /* resvd */
2939 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2940 datap = smb_GetSMBData(outp, NULL);
2941 /* paste in a new encryption key */
2942 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2943 /* and the faux domain name */
2944 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2946 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2947 smb_SetSMBParm(outp, 12, 0); /* resvd */
2948 smb_SetSMBDataLength(outp, 0);
2951 else if (coreProtoIndex != -1) { /* not really supported anymore */
2952 smb_SetSMBParm(outp, 0, protoIndex);
2953 smb_SetSMBDataLength(outp, 0);
2958 void smb_Daemon(void *parmp)
2960 afs_uint32 count = 0;
2962 while(smbShutdownFlag == 0) {
2966 if (smbShutdownFlag == 1)
2969 if ((count % 72) == 0) { /* every five minutes */
2971 time_t old_localZero = smb_localZero;
2973 /* Initialize smb_localZero */
2974 myTime.tm_isdst = -1; /* compute whether on DST or not */
2975 myTime.tm_year = 70;
2981 smb_localZero = mktime(&myTime);
2983 #ifndef USE_NUMERIC_TIME_CONV
2984 smb_CalculateNowTZ();
2985 #endif /* USE_NUMERIC_TIME_CONV */
2986 #ifdef AFS_FREELANCE
2987 if ( smb_localZero != old_localZero )
2988 cm_noteLocalMountPointChange();
2991 /* XXX GC dir search entries */
2995 void smb_WaitingLocksDaemon()
2997 smb_waitingLock_t *wL, *nwL;
3000 smb_packet_t *inp, *outp;
3004 while (smbShutdownFlag == 0) {
3005 lock_ObtainWrite(&smb_globalLock);
3006 nwL = smb_allWaitingLocks;
3008 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
3018 lock_ObtainWrite(&smb_globalLock);
3020 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
3021 lock_ReleaseWrite(&smb_globalLock);
3022 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
3023 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
3024 if (code == CM_ERROR_WOULDBLOCK) {
3026 if (wL->timeRemaining != 0xffffffff
3027 && (wL->timeRemaining -= 1000) < 0)
3037 ncbp->ncb_length = inp->ncb_length;
3038 inp->spacep = cm_GetSpace();
3040 /* Remove waitingLock from list */
3041 lock_ObtainWrite(&smb_globalLock);
3042 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3044 lock_ReleaseWrite(&smb_globalLock);
3046 /* Resume packet processing */
3048 smb_SetSMBDataLength(outp, 0);
3049 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3050 outp->resumeCode = code;
3052 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3055 cm_FreeSpace(inp->spacep);
3056 smb_FreePacket(inp);
3057 smb_FreePacket(outp);
3061 } while (nwL && smbShutdownFlag == 0);
3066 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3068 osi_Log0(smb_logp, "SMB receive get disk attributes");
3070 smb_SetSMBParm(outp, 0, 32000);
3071 smb_SetSMBParm(outp, 1, 64);
3072 smb_SetSMBParm(outp, 2, 1024);
3073 smb_SetSMBParm(outp, 3, 30000);
3074 smb_SetSMBParm(outp, 4, 0);
3075 smb_SetSMBDataLength(outp, 0);
3079 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3083 unsigned short newTid;
3084 char shareName[256];
3092 osi_Log0(smb_logp, "SMB receive tree connect");
3094 /* parse input parameters */
3095 tp = smb_GetSMBData(inp, NULL);
3096 pathp = smb_ParseASCIIBlock(tp, &tp);
3097 if (smb_StoreAnsiFilenames)
3098 OemToChar(pathp,pathp);
3099 passwordp = smb_ParseASCIIBlock(tp, &tp);
3100 tp = strrchr(pathp, '\\');
3102 return CM_ERROR_BADSMB;
3103 strcpy(shareName, tp+1);
3105 userp = smb_GetUser(vcp, inp);
3107 lock_ObtainMutex(&vcp->mx);
3108 newTid = vcp->tidCounter++;
3109 lock_ReleaseMutex(&vcp->mx);
3111 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3112 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3113 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3115 smb_ReleaseUID(uidp);
3117 smb_ReleaseTID(tidp);
3118 return CM_ERROR_BADSHARENAME;
3120 lock_ObtainMutex(&tidp->mx);
3121 tidp->userp = userp;
3122 tidp->pathname = sharePath;
3123 lock_ReleaseMutex(&tidp->mx);
3124 smb_ReleaseTID(tidp);
3126 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3127 smb_SetSMBParm(rsp, 1, newTid);
3128 smb_SetSMBDataLength(rsp, 0);
3130 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3134 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3138 if (*inp++ != 0x1) return NULL;
3139 tlen = inp[0] + (inp[1]<<8);
3140 inp += 2; /* skip length field */
3143 *chainpp = inp + tlen;
3146 if (lengthp) *lengthp = tlen;
3151 /* set maskp to the mask part of the incoming path.
3152 * Mask is 11 bytes long (8.3 with the dot elided).
3153 * Returns true if succeeds with a valid name, otherwise it does
3154 * its best, but returns false.
3156 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3164 /* starts off valid */
3167 /* mask starts out all blanks */
3168 memset(maskp, ' ', 11);
3170 /* find last backslash, or use whole thing if there is none */
3171 tp = strrchr(pathp, '\\');
3172 if (!tp) tp = pathp;
3173 else tp++; /* skip slash */
3177 /* names starting with a dot are illegal */
3178 if (*tp == '.') valid8Dot3 = 0;
3182 if (tc == 0) return valid8Dot3;
3183 if (tc == '.' || tc == '"') break;
3184 if (i < 8) *up++ = tc;
3185 else valid8Dot3 = 0;
3188 /* if we get here, tp point after the dot */
3189 up = maskp+8; /* ext goes here */
3196 if (tc == '.' || tc == '"')
3199 /* copy extension if not too long */
3209 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3219 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3221 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3225 /* otherwise, we have a valid 8.3 name; see if we have a match,
3226 * treating '?' as a wildcard in maskp (but not in the file name).
3228 tp1 = umask; /* real name, in mask format */
3229 tp2 = maskp; /* mask, in mask format */
3230 for(i=0; i<11; i++) {
3231 tc1 = *tp1++; /* char from real name */
3232 tc2 = *tp2++; /* char from mask */
3233 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3234 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3237 if (tc2 == '?' && tc1 != ' ')
3244 /* we got a match */
3248 char *smb_FindMask(char *pathp)
3252 tp = strrchr(pathp, '\\'); /* find last slash */
3255 return tp+1; /* skip the slash */
3257 return pathp; /* no slash, return the entire path */
3260 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3262 unsigned char *pathp;
3264 unsigned char mask[11];
3265 unsigned char *statBlockp;
3266 unsigned char initStatBlock[21];
3269 osi_Log0(smb_logp, "SMB receive search volume");
3271 /* pull pathname and stat block out of request */
3272 tp = smb_GetSMBData(inp, NULL);
3273 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3274 osi_assert(pathp != NULL);
3275 if (smb_StoreAnsiFilenames)
3276 OemToChar(pathp,pathp);
3277 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3278 osi_assert(statBlockp != NULL);
3280 statBlockp = initStatBlock;
3284 /* for returning to caller */
3285 smb_Get8Dot3MaskFromPath(mask, pathp);
3287 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3288 tp = smb_GetSMBData(outp, NULL);
3290 *tp++ = 43; /* bytes in a dir entry */
3291 *tp++ = 0; /* high byte in counter */
3293 /* now marshall the dir entry, starting with the search status */
3294 *tp++ = statBlockp[0]; /* Reserved */
3295 memcpy(tp, mask, 11); tp += 11; /* FileName */
3297 /* now pass back server use info, with 1st byte non-zero */
3299 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3301 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3303 *tp++ = 0x8; /* attribute: volume */
3313 /* 4 byte file size */
3319 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3320 memset(tp, ' ', 13);
3323 /* set the length of the data part of the packet to 43 + 3, for the dir
3324 * entry plus the 5 and the length fields.
3326 smb_SetSMBDataLength(outp, 46);
3330 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3331 cm_user_t *userp, cm_req_t *reqp)
3339 smb_dirListPatch_t *patchp;
3340 smb_dirListPatch_t *npatchp;
3342 for (patchp = *dirPatchespp; patchp; patchp =
3343 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3345 dptr = patchp->dptr;
3347 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3349 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3350 *dptr++ = SMB_ATTR_HIDDEN;
3353 lock_ObtainMutex(&scp->mx);
3354 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3355 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3357 lock_ReleaseMutex(&scp->mx);
3358 cm_ReleaseSCache(scp);
3359 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3360 *dptr++ = SMB_ATTR_HIDDEN;
3364 attr = smb_Attributes(scp);
3365 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3366 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3367 attr |= SMB_ATTR_HIDDEN;
3371 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3374 shortTemp = (unsigned short) (dosTime & 0xffff);
3375 *((u_short *)dptr) = shortTemp;
3378 /* and copy out date */
3379 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3380 *((u_short *)dptr) = shortTemp;
3383 /* copy out file length */
3384 *((u_long *)dptr) = scp->length.LowPart;
3386 lock_ReleaseMutex(&scp->mx);
3387 cm_ReleaseSCache(scp);
3390 /* now free the patches */
3391 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3392 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3396 /* and mark the list as empty */
3397 *dirPatchespp = NULL;
3402 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3411 smb_dirListPatch_t *dirListPatchesp;
3412 smb_dirListPatch_t *curPatchp;
3416 osi_hyper_t dirLength;
3417 osi_hyper_t bufferOffset;
3418 osi_hyper_t curOffset;
3420 unsigned char *inCookiep;
3421 smb_dirSearch_t *dsp;
3425 unsigned long clientCookie;
3426 cm_pageHeader_t *pageHeaderp;
3427 cm_user_t *userp = NULL;
3434 long nextEntryCookie;
3435 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3436 char resByte; /* reserved byte from the cookie */
3437 char *op; /* output data ptr */
3438 char *origOp; /* original value of op */
3439 cm_space_t *spacep; /* for pathname buffer */
3450 maxCount = smb_GetSMBParm(inp, 0);
3452 dirListPatchesp = NULL;
3454 caseFold = CM_FLAG_CASEFOLD;
3456 tp = smb_GetSMBData(inp, NULL);
3457 pathp = smb_ParseASCIIBlock(tp, &tp);
3458 if (smb_StoreAnsiFilenames)
3459 OemToChar(pathp,pathp);
3460 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3462 /* bail out if request looks bad */
3463 if (!tp || !pathp) {
3464 return CM_ERROR_BADSMB;
3467 /* We can handle long names */
3468 if (vcp->flags & SMB_VCFLAG_USENT)
3469 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3471 /* make sure we got a whole search status */
3472 if (dataLength < 21) {
3473 nextCookie = 0; /* start at the beginning of the dir */
3476 attribute = smb_GetSMBParm(inp, 1);
3478 /* handle volume info in another function */
3479 if (attribute & 0x8)
3480 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3482 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3483 maxCount, osi_LogSaveString(smb_logp, pathp));
3485 if (*pathp == 0) { /* null pathp, treat as root dir */
3486 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3487 return CM_ERROR_NOFILES;
3491 dsp = smb_NewDirSearch(0);
3492 dsp->attribute = attribute;
3493 smb_Get8Dot3MaskFromPath(mask, pathp);
3494 memcpy(dsp->mask, mask, 11);
3496 /* track if this is likely to match a lot of entries */
3497 if (smb_IsStarMask(mask))
3502 /* pull the next cookie value out of the search status block */
3503 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3504 + (inCookiep[16]<<24);
3505 dsp = smb_FindDirSearch(inCookiep[12]);
3507 /* can't find dir search status; fatal error */
3508 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3509 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3510 return CM_ERROR_BADFD;
3512 attribute = dsp->attribute;
3513 resByte = inCookiep[0];
3515 /* copy out client cookie, in host byte order. Don't bother
3516 * interpreting it, since we're just passing it through, anyway.
3518 memcpy(&clientCookie, &inCookiep[17], 4);
3520 memcpy(mask, dsp->mask, 11);
3522 /* assume we're doing a star match if it has continued for more
3528 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3529 nextCookie, dsp->cookie, attribute);
3531 userp = smb_GetUser(vcp, inp);
3533 /* try to get the vnode for the path name next */
3534 lock_ObtainMutex(&dsp->mx);
3540 spacep = inp->spacep;
3541 smb_StripLastComponent(spacep->data, NULL, pathp);
3542 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3544 lock_ReleaseMutex(&dsp->mx);
3545 cm_ReleaseUser(userp);
3546 smb_DeleteDirSearch(dsp);
3547 smb_ReleaseDirSearch(dsp);
3548 return CM_ERROR_NOFILES;
3550 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3551 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3554 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3555 cm_ReleaseSCache(scp);
3556 lock_ReleaseMutex(&dsp->mx);
3557 cm_ReleaseUser(userp);
3558 smb_DeleteDirSearch(dsp);
3559 smb_ReleaseDirSearch(dsp);
3560 if ( WANTS_DFS_PATHNAMES(inp) )
3561 return CM_ERROR_PATH_NOT_COVERED;
3563 return CM_ERROR_BADSHARENAME;
3565 #endif /* DFS_SUPPORT */
3568 /* we need one hold for the entry we just stored into,
3569 * and one for our own processing. When we're done with this
3570 * function, we'll drop the one for our own processing.
3571 * We held it once from the namei call, and so we do another hold
3575 lock_ObtainMutex(&scp->mx);
3576 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3577 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3578 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3579 dsp->flags |= SMB_DIRSEARCH_BULKST;
3581 lock_ReleaseMutex(&scp->mx);
3584 lock_ReleaseMutex(&dsp->mx);
3586 cm_ReleaseUser(userp);
3587 smb_DeleteDirSearch(dsp);
3588 smb_ReleaseDirSearch(dsp);
3592 /* reserves space for parameter; we'll adjust it again later to the
3593 * real count of the # of entries we returned once we've actually
3594 * assembled the directory listing.
3596 smb_SetSMBParm(outp, 0, 0);
3598 /* get the directory size */
3599 lock_ObtainMutex(&scp->mx);
3600 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3601 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3603 lock_ReleaseMutex(&scp->mx);
3604 cm_ReleaseSCache(scp);
3605 cm_ReleaseUser(userp);
3606 smb_DeleteDirSearch(dsp);
3607 smb_ReleaseDirSearch(dsp);
3611 dirLength = scp->length;
3613 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3614 curOffset.HighPart = 0;
3615 curOffset.LowPart = nextCookie;
3616 origOp = op = smb_GetSMBData(outp, NULL);
3617 /* and write out the basic header */
3618 *op++ = 5; /* variable block */
3619 op += 2; /* skip vbl block length; we'll fill it in later */
3623 /* make sure that curOffset.LowPart doesn't point to the first
3624 * 32 bytes in the 2nd through last dir page, and that it doesn't
3625 * point at the first 13 32-byte chunks in the first dir page,
3626 * since those are dir and page headers, and don't contain useful
3629 temp = curOffset.LowPart & (2048-1);
3630 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3631 /* we're in the first page */
3632 if (temp < 13*32) temp = 13*32;
3635 /* we're in a later dir page */
3636 if (temp < 32) temp = 32;
3639 /* make sure the low order 5 bits are zero */
3642 /* now put temp bits back ito curOffset.LowPart */
3643 curOffset.LowPart &= ~(2048-1);
3644 curOffset.LowPart |= temp;
3646 /* check if we've returned all the names that will fit in the
3649 if (returnedNames >= maxCount) {
3650 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3651 returnedNames, maxCount);
3655 /* check if we've passed the dir's EOF */
3656 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3658 /* see if we can use the bufferp we have now; compute in which page
3659 * the current offset would be, and check whether that's the offset
3660 * of the buffer we have. If not, get the buffer.
3662 thyper.HighPart = curOffset.HighPart;
3663 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3664 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3667 buf_Release(bufferp);
3670 lock_ReleaseMutex(&scp->mx);
3671 lock_ObtainRead(&scp->bufCreateLock);
3672 code = buf_Get(scp, &thyper, &bufferp);
3673 lock_ReleaseRead(&scp->bufCreateLock);
3674 lock_ObtainMutex(&dsp->mx);
3676 /* now, if we're doing a star match, do bulk fetching of all of
3677 * the status info for files in the dir.
3680 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3681 lock_ObtainMutex(&scp->mx);
3682 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3683 LargeIntegerGreaterThanOrEqualTo(thyper,
3684 scp->bulkStatProgress)) {
3685 /* Don't bulk stat if risking timeout */
3686 int now = GetCurrentTime();
3687 if (now - req.startTime > 5000) {
3688 scp->bulkStatProgress = thyper;
3689 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3690 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3692 cm_TryBulkStat(scp, &thyper, userp, &req);
3695 lock_ObtainMutex(&scp->mx);
3697 lock_ReleaseMutex(&dsp->mx);
3699 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3703 bufferOffset = thyper;
3705 /* now get the data in the cache */
3707 code = cm_SyncOp(scp, bufferp, userp, &req,
3709 CM_SCACHESYNC_NEEDCALLBACK |
3710 CM_SCACHESYNC_READ);
3712 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3716 if (cm_HaveBuffer(scp, bufferp, 0)) {
3717 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3721 /* otherwise, load the buffer and try again */
3722 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3724 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3725 scp, bufferp, code);
3730 buf_Release(bufferp);
3734 } /* if (wrong buffer) ... */
3736 /* now we have the buffer containing the entry we're interested in; copy
3737 * it out if it represents a non-deleted entry.
3739 entryInDir = curOffset.LowPart & (2048-1);
3740 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3742 /* page header will help tell us which entries are free. Page header
3743 * can change more often than once per buffer, since AFS 3 dir page size
3744 * may be less than (but not more than a buffer package buffer.
3746 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3747 temp &= ~(2048 - 1); /* turn off intra-page bits */
3748 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3750 /* now determine which entry we're looking at in the page. If it is
3751 * free (there's a free bitmap at the start of the dir), we should
3752 * skip these 32 bytes.
3754 slotInPage = (entryInDir & 0x7e0) >> 5;
3755 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3756 /* this entry is free */
3757 numDirChunks = 1; /* only skip this guy */
3761 tp = bufferp->datap + entryInBuffer;
3762 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3764 /* while we're here, compute the next entry's location, too,
3765 * since we'll need it when writing out the cookie into the dir
3768 * XXXX Probably should do more sanity checking.
3770 numDirChunks = cm_NameEntries(dep->name, NULL);
3772 /* compute the offset of the cookie representing the next entry */
3773 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3775 /* Compute 8.3 name if necessary */
3776 actualName = dep->name;
3777 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3778 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3779 actualName = shortName;
3782 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3783 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3784 osi_LogSaveString(smb_logp, actualName));
3786 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3787 /* this is one of the entries to use: it is not deleted
3788 * and it matches the star pattern we're looking for.
3791 /* Eliminate entries that don't match requested
3794 /* no hidden files */
3795 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3796 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3800 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3802 /* We have already done the cm_TryBulkStat above */
3803 fid.cell = scp->fid.cell;
3804 fid.volume = scp->fid.volume;
3805 fid.vnode = ntohl(dep->fid.vnode);
3806 fid.unique = ntohl(dep->fid.unique);
3807 fileType = cm_FindFileType(&fid);
3808 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3809 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3811 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3812 fileType == CM_SCACHETYPE_DFSLINK ||
3813 fileType == CM_SCACHETYPE_INVALID)
3814 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3819 memcpy(op, mask, 11); op += 11;
3820 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3821 *op++ = nextEntryCookie & 0xff;
3822 *op++ = (nextEntryCookie>>8) & 0xff;
3823 *op++ = (nextEntryCookie>>16) & 0xff;
3824 *op++ = (nextEntryCookie>>24) & 0xff;
3825 memcpy(op, &clientCookie, 4); op += 4;
3827 /* now we emit the attribute. This is sort of tricky,
3828 * since we need to really stat the file to find out
3829 * what type of entry we've got. Right now, we're
3830 * copying out data from a buffer, while holding the
3831 * scp locked, so it isn't really convenient to stat
3832 * something now. We'll put in a place holder now,
3833 * and make a second pass before returning this to get
3834 * the real attributes. So, we just skip the data for
3835 * now, and adjust it later. We allocate a patch
3836 * record to make it easy to find this point later.
3837 * The replay will happen at a time when it is safe to
3838 * unlock the directory.
3840 curPatchp = malloc(sizeof(*curPatchp));
3841 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3842 curPatchp->dptr = op;
3843 curPatchp->fid.cell = scp->fid.cell;
3844 curPatchp->fid.volume = scp->fid.volume;
3845 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3846 curPatchp->fid.unique = ntohl(dep->fid.unique);
3848 /* do hidden attribute here since name won't be around when applying
3852 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3853 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3855 curPatchp->flags = 0;
3857 op += 9; /* skip attr, time, date and size */
3859 /* zero out name area. The spec says to pad with
3860 * spaces, but Samba doesn't, and neither do we.
3864 /* finally, we get to copy out the name; we know that
3865 * it fits in 8.3 or the pattern wouldn't match, but it
3866 * never hurts to be sure.
3868 strncpy(op, actualName, 13);
3869 if (smb_StoreAnsiFilenames)
3872 /* Uppercase if requested by client */
3873 if (!KNOWS_LONG_NAMES(inp))
3878 /* now, adjust the # of entries copied */
3880 } /* if we're including this name */
3883 /* and adjust curOffset to be where the new cookie is */
3884 thyper.HighPart = 0;
3885 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3886 curOffset = LargeIntegerAdd(thyper, curOffset);
3887 } /* while copying data for dir listing */
3889 /* release the mutex */
3890 lock_ReleaseMutex(&scp->mx);
3891 if (bufferp) buf_Release(bufferp);
3893 /* apply and free last set of patches; if not doing a star match, this
3894 * will be empty, but better safe (and freeing everything) than sorry.
3896 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3898 /* special return code for unsuccessful search */
3899 if (code == 0 && dataLength < 21 && returnedNames == 0)
3900 code = CM_ERROR_NOFILES;
3902 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3903 returnedNames, code);
3906 smb_DeleteDirSearch(dsp);
3907 smb_ReleaseDirSearch(dsp);
3908 cm_ReleaseSCache(scp);
3909 cm_ReleaseUser(userp);
3913 /* finalize the output buffer */
3914 smb_SetSMBParm(outp, 0, returnedNames);
3915 temp = (long) (op - origOp);
3916 smb_SetSMBDataLength(outp, temp);
3918 /* the data area is a variable block, which has a 5 (already there)
3919 * followed by the length of the # of data bytes. We now know this to
3920 * be "temp," although that includes the 3 bytes of vbl block header.
3921 * Deduct for them and fill in the length field.
3923 temp -= 3; /* deduct vbl block info */
3924 osi_assert(temp == (43 * returnedNames));
3925 origOp[1] = temp & 0xff;
3926 origOp[2] = (temp>>8) & 0xff;
3927 if (returnedNames == 0)
3928 smb_DeleteDirSearch(dsp);
3929 smb_ReleaseDirSearch(dsp);
3930 cm_ReleaseSCache(scp);
3931 cm_ReleaseUser(userp);
3935 /* verify that this is a valid path to a directory. I don't know why they
3936 * don't use the get file attributes call.
3938 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3942 cm_scache_t *rootScp;
3943 cm_scache_t *newScp;
3952 pathp = smb_GetSMBData(inp, NULL);
3953 pathp = smb_ParseASCIIBlock(pathp, NULL);
3955 return CM_ERROR_BADFD;
3956 if (smb_StoreAnsiFilenames)
3957 OemToChar(pathp,pathp);
3958 osi_Log1(smb_logp, "SMB receive check path %s",
3959 osi_LogSaveString(smb_logp, pathp));
3961 rootScp = cm_data.rootSCachep;
3963 userp = smb_GetUser(vcp, inp);
3965 caseFold = CM_FLAG_CASEFOLD;
3967 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3969 cm_ReleaseUser(userp);
3970 return CM_ERROR_NOSUCHPATH;
3972 code = cm_NameI(rootScp, pathp,
3973 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3974 userp, tidPathp, &req, &newScp);
3977 cm_ReleaseUser(userp);
3982 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
3983 cm_ReleaseSCache(newScp);
3984 cm_ReleaseUser(userp);
3985 if ( WANTS_DFS_PATHNAMES(inp) )
3986 return CM_ERROR_PATH_NOT_COVERED;
3988 return CM_ERROR_BADSHARENAME;
3990 #endif /* DFS_SUPPORT */
3992 /* now lock the vnode with a callback; returns with newScp locked */
3993 lock_ObtainMutex(&newScp->mx);
3994 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3995 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3996 if (code && code != CM_ERROR_NOACCESS) {
3997 lock_ReleaseMutex(&newScp->mx);
3998 cm_ReleaseSCache(newScp);
3999 cm_ReleaseUser(userp);
4003 attrs = smb_Attributes(newScp);
4005 if (!(attrs & SMB_ATTR_DIRECTORY))
4006 code = CM_ERROR_NOTDIR;
4008 lock_ReleaseMutex(&newScp->mx);
4010 cm_ReleaseSCache(newScp);
4011 cm_ReleaseUser(userp);
4015 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4019 cm_scache_t *rootScp;
4020 unsigned short attribute;
4022 cm_scache_t *newScp;
4031 /* decode basic attributes we're passed */
4032 attribute = smb_GetSMBParm(inp, 0);
4033 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4035 pathp = smb_GetSMBData(inp, NULL);
4036 pathp = smb_ParseASCIIBlock(pathp, NULL);
4038 return CM_ERROR_BADSMB;
4039 if (smb_StoreAnsiFilenames)
4040 OemToChar(pathp,pathp);
4042 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4043 dosTime, attribute);
4045 rootScp = cm_data.rootSCachep;
4047 userp = smb_GetUser(vcp, inp);
4049 caseFold = CM_FLAG_CASEFOLD;
4051 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4053 cm_ReleaseUser(userp);
4054 return CM_ERROR_NOSUCHFILE;
4056 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4057 tidPathp, &req, &newScp);
4060 cm_ReleaseUser(userp);
4065 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4066 cm_ReleaseSCache(newScp);
4067 cm_ReleaseUser(userp);
4068 if ( WANTS_DFS_PATHNAMES(inp) )
4069 return CM_ERROR_PATH_NOT_COVERED;
4071 return CM_ERROR_BADSHARENAME;
4073 #endif /* DFS_SUPPORT */
4075 /* now lock the vnode with a callback; returns with newScp locked; we
4076 * need the current status to determine what the new status is, in some
4079 lock_ObtainMutex(&newScp->mx);
4080 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4081 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4083 lock_ReleaseMutex(&newScp->mx);
4084 cm_ReleaseSCache(newScp);
4085 cm_ReleaseUser(userp);
4089 /* Check for RO volume */
4090 if (newScp->flags & CM_SCACHEFLAG_RO) {
4091 lock_ReleaseMutex(&newScp->mx);
4092 cm_ReleaseSCache(newScp);
4093 cm_ReleaseUser(userp);
4094 return CM_ERROR_READONLY;
4097 /* prepare for setattr call */
4100 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4101 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4103 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4104 /* we're told to make a writable file read-only */
4105 attr.unixModeBits = newScp->unixModeBits & ~0222;
4106 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4108 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4109 /* we're told to make a read-only file writable */
4110 attr.unixModeBits = newScp->unixModeBits | 0222;
4111 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4113 lock_ReleaseMutex(&newScp->mx);
4115 /* now call setattr */
4117 code = cm_SetAttr(newScp, &attr, userp, &req);
4121 cm_ReleaseSCache(newScp);
4122 cm_ReleaseUser(userp);
4127 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4131 cm_scache_t *rootScp;
4132 cm_scache_t *newScp, *dscp;
4144 pathp = smb_GetSMBData(inp, NULL);
4145 pathp = smb_ParseASCIIBlock(pathp, NULL);
4147 return CM_ERROR_BADSMB;
4149 if (*pathp == 0) /* null path */
4152 if (smb_StoreAnsiFilenames)
4153 OemToChar(pathp,pathp);
4155 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4156 osi_LogSaveString(smb_logp, pathp));
4158 rootScp = cm_data.rootSCachep;
4160 userp = smb_GetUser(vcp, inp);
4162 /* we shouldn't need this for V3 requests, but we seem to */
4163 caseFold = CM_FLAG_CASEFOLD;
4165 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4167 cm_ReleaseUser(userp);
4168 return CM_ERROR_NOSUCHFILE;
4172 * XXX Strange hack XXX
4174 * As of Patch 5 (16 July 97), we are having the following problem:
4175 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4176 * requests to look up "desktop.ini" in all the subdirectories.
4177 * This can cause zillions of timeouts looking up non-existent cells
4178 * and volumes, especially in the top-level directory.
4180 * We have not found any way to avoid this or work around it except
4181 * to explicitly ignore the requests for mount points that haven't
4182 * yet been evaluated and for directories that haven't yet been
4185 * We should modify this hack to provide a fake desktop.ini file
4186 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4188 spacep = inp->spacep;
4189 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4190 #ifndef SPECIAL_FOLDERS
4191 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4192 code = cm_NameI(rootScp, spacep->data,
4193 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4194 userp, tidPathp, &req, &dscp);
4197 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4198 if ( WANTS_DFS_PATHNAMES(inp) )
4199 return CM_ERROR_PATH_NOT_COVERED;
4201 return CM_ERROR_BADSHARENAME;
4203 #endif /* DFS_SUPPORT */
4204 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4205 code = CM_ERROR_NOSUCHFILE;
4206 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4207 cm_buf_t *bp = buf_Find(dscp, &hzero);
4211 code = CM_ERROR_NOSUCHFILE;
4213 cm_ReleaseSCache(dscp);
4215 cm_ReleaseUser(userp);
4220 #endif /* SPECIAL_FOLDERS */
4222 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4223 tidPathp, &req, &newScp);
4225 cm_ReleaseUser(userp);
4230 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4231 cm_ReleaseSCache(newScp);
4232 cm_ReleaseUser(userp);
4233 if ( WANTS_DFS_PATHNAMES(inp) )
4234 return CM_ERROR_PATH_NOT_COVERED;
4236 return CM_ERROR_BADSHARENAME;
4238 #endif /* DFS_SUPPORT */
4240 /* now lock the vnode with a callback; returns with newScp locked */
4241 lock_ObtainMutex(&newScp->mx);
4242 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4243 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4245 lock_ReleaseMutex(&newScp->mx);
4246 cm_ReleaseSCache(newScp);
4247 cm_ReleaseUser(userp);
4252 /* use smb_Attributes instead. Also the fact that a file is
4253 * in a readonly volume doesn't mean it shojuld be marked as RO
4255 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4256 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4257 attrs = SMB_ATTR_DIRECTORY;
4260 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4261 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4263 attrs = smb_Attributes(newScp);
4266 smb_SetSMBParm(outp, 0, attrs);
4268 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4269 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4270 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4271 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4272 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4273 smb_SetSMBParm(outp, 5, 0);
4274 smb_SetSMBParm(outp, 6, 0);
4275 smb_SetSMBParm(outp, 7, 0);
4276 smb_SetSMBParm(outp, 8, 0);
4277 smb_SetSMBParm(outp, 9, 0);
4278 smb_SetSMBDataLength(outp, 0);
4279 lock_ReleaseMutex(&newScp->mx);
4281 cm_ReleaseSCache(newScp);
4282 cm_ReleaseUser(userp);
4287 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4291 osi_Log0(smb_logp, "SMB receive tree disconnect");
4293 /* find the tree and free it */
4294 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4296 lock_ObtainMutex(&tidp->mx);
4297 tidp->flags |= SMB_TIDFLAG_DELETE;
4298 lock_ReleaseMutex(&tidp->mx);
4299 smb_ReleaseTID(tidp);
4305 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4323 pathp = smb_GetSMBData(inp, NULL);
4324 pathp = smb_ParseASCIIBlock(pathp, NULL);
4325 if (smb_StoreAnsiFilenames)
4326 OemToChar(pathp,pathp);
4328 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4330 #ifdef DEBUG_VERBOSE
4334 hexpath = osi_HexifyString( pathp );
4335 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4340 share = smb_GetSMBParm(inp, 0);
4341 attribute = smb_GetSMBParm(inp, 1);
4343 spacep = inp->spacep;
4344 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4345 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4346 /* special case magic file name for receiving IOCTL requests
4347 * (since IOCTL calls themselves aren't getting through).
4349 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4350 smb_SetupIoctlFid(fidp, spacep);
4351 smb_SetSMBParm(outp, 0, fidp->fid);
4352 smb_SetSMBParm(outp, 1, 0); /* attrs */
4353 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4354 smb_SetSMBParm(outp, 3, 0);
4355 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4356 smb_SetSMBParm(outp, 5, 0x7fff);
4357 /* pass the open mode back */
4358 smb_SetSMBParm(outp, 6, (share & 0xf));
4359 smb_SetSMBDataLength(outp, 0);
4360 smb_ReleaseFID(fidp);
4364 userp = smb_GetUser(vcp, inp);
4366 caseFold = CM_FLAG_CASEFOLD;
4368 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4370 cm_ReleaseUser(userp);
4371 return CM_ERROR_NOSUCHPATH;
4373 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4374 tidPathp, &req, &scp);
4377 cm_ReleaseUser(userp);
4382 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4383 cm_ReleaseSCache(scp);
4384 cm_ReleaseUser(userp);
4385 if ( WANTS_DFS_PATHNAMES(inp) )
4386 return CM_ERROR_PATH_NOT_COVERED;
4388 return CM_ERROR_BADSHARENAME;
4390 #endif /* DFS_SUPPORT */
4392 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4394 cm_ReleaseSCache(scp);
4395 cm_ReleaseUser(userp);
4399 /* don't need callback to check file type, since file types never
4400 * change, and namei and cm_Lookup all stat the object at least once on
4401 * a successful return.
4403 if (scp->fileType != CM_SCACHETYPE_FILE) {
4404 cm_ReleaseSCache(scp);
4405 cm_ReleaseUser(userp);
4406 return CM_ERROR_ISDIR;
4409 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4412 /* save a pointer to the vnode */
4415 if ((share & 0xf) == 0)
4416 fidp->flags |= SMB_FID_OPENREAD;
4417 else if ((share & 0xf) == 1)
4418 fidp->flags |= SMB_FID_OPENWRITE;