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 //#define NOTSERVICE 1
13 #include <afs/param.h>
19 #include <sys/timeb.h>
35 #include "lanahelper.h"
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
41 smb_vc_t *dead_vcp = NULL;
42 smb_vc_t *active_vcp = NULL;
44 /* TODO; logout mechanism needs to be thread-safe */
45 char *loggedOutName = NULL;
46 smb_user_t *loggedOutUserp = NULL;
49 int smbShutdownFlag = 0;
51 int smb_LogoffTokenTransfer;
52 time_t smb_LogoffTransferTimeout;
54 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 *smb_ServerShutdown;
99 DWORD NCBsessions[NCBmax];
101 struct smb_packet *bufs[NCBmax];
103 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
104 EVENT_HANDLE SessionEvents[Sessionmax];
105 unsigned short LSNs[Sessionmax];
106 int lanas[Sessionmax];
107 BOOL dead_sessions[Sessionmax];
111 osi_mutex_t smb_RawBufLock;
113 #define SMB_RAW_BUFS 4
115 int smb_RawBufSel[SMB_RAW_BUFS];
120 #define SMB_MASKFLAG_TILDE 1
121 #define SMB_MASKFLAG_CASEFOLD 2
123 #define RAWTIMEOUT INFINITE
126 typedef struct raw_write_cont {
139 /* dir search stuff */
140 long smb_dirSearchCounter = 1;
141 smb_dirSearch_t *smb_firstDirSearchp;
142 smb_dirSearch_t *smb_lastDirSearchp;
144 /* hide dot files? */
145 int smb_hideDotFiles;
147 /* global state about V3 protocols */
148 int smb_useV3; /* try to negotiate V3 */
151 static showErrors = 1;
152 /* MessageBox or something like it */
153 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
154 extern HANDLE WaitToTerminate;
158 * Time in Unix format of midnight, 1/1/1970 local time.
159 * When added to dosUTime, gives Unix (AFS) time.
161 time_t smb_localZero = 0;
163 /* Time difference for converting to kludge-GMT */
166 char *smb_localNamep = NULL;
168 smb_vc_t *smb_allVCsp;
170 smb_username_t *usernamesp = NULL;
172 smb_waitingLock_t *smb_allWaitingLocks;
175 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
176 NCB *ncbp, raw_write_cont_t *rwcp);
177 void smb_NetbiosInit();
179 #ifndef AFS_WIN95_ENV
180 DWORD smb_ServerExceptionFilter(void);
183 extern char cm_HostName[];
184 extern char cm_confDir[];
188 #define LPTSTR char *
189 #define GetComputerName(str, sizep) \
190 strcpy((str), cm_HostName); \
191 *(sizep) = strlen(cm_HostName)
195 void smb_LogPacket(smb_packet_t *packet);
196 #endif /* LOG_PACKET */
197 extern char AFSConfigKeyName[];
199 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
200 int smb_ServerDomainNameLength = 0;
201 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
202 int smb_ServerOSLength = sizeof(smb_ServerOS);
203 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
204 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
206 /* Faux server GUID. This is never checked. */
207 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
209 char * myCrt_Dispatch(int i)
214 return "(00)ReceiveCoreMakeDir";
216 return "(01)ReceiveCoreRemoveDir";
218 return "(02)ReceiveCoreOpen";
220 return "(03)ReceiveCoreCreate";
222 return "(04)ReceiveCoreClose";
224 return "(05)ReceiveCoreFlush";
226 return "(06)ReceiveCoreUnlink";
228 return "(07)ReceiveCoreRename";
230 return "(08)ReceiveCoreGetFileAttributes";
232 return "(09)ReceiveCoreSetFileAttributes";
234 return "(0a)ReceiveCoreRead";
236 return "(0b)ReceiveCoreWrite";
238 return "(0c)ReceiveCoreLockRecord";
240 return "(0d)ReceiveCoreUnlockRecord";
242 return "(0e)SendCoreBadOp";
244 return "(0f)ReceiveCoreCreate";
246 return "(10)ReceiveCoreCheckPath";
248 return "(11)SendCoreBadOp";
250 return "(12)ReceiveCoreSeek";
252 return "(1a)ReceiveCoreReadRaw";
254 return "(1d)ReceiveCoreWriteRawDummy";
256 return "(22)ReceiveV3SetAttributes";
258 return "(23)ReceiveV3GetAttributes";
260 return "(24)ReceiveV3LockingX";
262 return "(25)ReceiveV3Trans";
264 return "(26)ReceiveV3Trans[aux]";
266 return "(29)SendCoreBadOp";
268 return "(2b)ReceiveCoreEcho";
270 return "(2d)ReceiveV3OpenX";
272 return "(2e)ReceiveV3ReadX";
274 return "(32)ReceiveV3Tran2A";
276 return "(33)ReceiveV3Tran2A[aux]";
278 return "(34)ReceiveV3FindClose";
280 return "(35)ReceiveV3FindNotifyClose";
282 return "(70)ReceiveCoreTreeConnect";
284 return "(71)ReceiveCoreTreeDisconnect";
286 return "(72)ReceiveNegotiate";
288 return "(73)ReceiveV3SessionSetupX";
290 return "(74)ReceiveV3UserLogoffX";
292 return "(75)ReceiveV3TreeConnectX";
294 return "(80)ReceiveCoreGetDiskAttributes";
296 return "(81)ReceiveCoreSearchDir";
300 return "(83)FindUnique";
302 return "(84)FindClose";
304 return "(A0)ReceiveNTTransact";
306 return "(A2)ReceiveNTCreateX";
308 return "(A4)ReceiveNTCancel";
310 return "(A5)ReceiveNTRename";
312 return "(C0)OpenPrintFile";
314 return "(C1)WritePrintFile";
316 return "(C2)ClosePrintFile";
318 return "(C3)GetPrintQueue";
320 return "(D8)ReadBulk";
322 return "(D9)WriteBulk";
324 return "(DA)WriteBulkData";
326 return "unknown SMB op";
330 char * myCrt_2Dispatch(int i)
335 return "unknown SMB op-2";
337 return "S(00)CreateFile";
339 return "S(01)FindFirst";
341 return "S(02)FindNext"; /* FindNext */
343 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
347 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
349 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
351 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
353 return "S(08)??_ReceiveTran2SetFileInfo";
355 return "S(09)??_ReceiveTran2FSCTL";
357 return "S(0a)_ReceiveTran2IOCTL";
359 return "S(0b)_ReceiveTran2FindNotifyFirst";
361 return "S(0c)_ReceiveTran2FindNotifyNext";
363 return "S(0d)_ReceiveTran2CreateDirectory";
365 return "S(0e)_ReceiveTran2SessionSetup";
367 return "S(10)_ReceiveTran2GetDfsReferral";
369 return "S(11)_ReceiveTran2ReportDfsInconsistency";
373 char * myCrt_RapDispatch(int i)
378 return "unknown RAP OP";
380 return "RAP(0)NetShareEnum";
382 return "RAP(1)NetShareGetInfo";
384 return "RAP(13)NetServerGetInfo";
386 return "RAP(63)NetWkStaGetInfo";
390 /* scache must be locked */
391 unsigned int smb_Attributes(cm_scache_t *scp)
395 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
396 scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
398 attrs = SMB_ATTR_DIRECTORY;
399 #ifdef SPECIAL_FOLDERS
400 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
401 #endif /* SPECIAL_FOLDERS */
406 * We used to mark a file RO if it was in an RO volume, but that
407 * turns out to be impolitic in NT. See defect 10007.
410 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
412 if ((scp->unixModeBits & 0222) == 0)
413 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
418 /* Check if the named file/dir is a dotfile/dotdir */
419 /* String pointed to by lastComp can have leading slashes, but otherwise should have
420 no other patch components */
421 unsigned int smb_IsDotFile(char *lastComp) {
424 /* skip over slashes */
425 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
430 /* nulls, curdir and parent dir doesn't count */
436 if(*(s+1) == '.' && !*(s + 2))
443 static int ExtractBits(WORD bits, short start, short len)
450 num = bits << (16 - end);
451 num = num >> ((16 - end) + start);
457 void ShowUnixTime(char *FuncName, time_t unixTime)
462 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
464 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
465 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
467 int day, month, year, sec, min, hour;
470 day = ExtractBits(wDate, 0, 5);
471 month = ExtractBits(wDate, 5, 4);
472 year = ExtractBits(wDate, 9, 7) + 1980;
474 sec = ExtractBits(wTime, 0, 5);
475 min = ExtractBits(wTime, 5, 6);
476 hour = ExtractBits(wTime, 11, 5);
478 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
479 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
485 /* Determine if we are observing daylight savings time */
486 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
488 TIME_ZONE_INFORMATION timeZoneInformation;
489 SYSTEMTIME utc, local, localDST;
491 /* Get the time zone info. NT uses this to calc if we are in DST. */
492 GetTimeZoneInformation(&timeZoneInformation);
494 /* Return the daylight bias */
495 *pDstBias = timeZoneInformation.DaylightBias;
497 /* Return the bias */
498 *pBias = timeZoneInformation.Bias;
500 /* Now determine if DST is being observed */
502 /* Get the UTC (GMT) time */
505 /* Convert UTC time to local time using the time zone info. If we are
506 observing DST, the calculated local time will include this.
508 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
510 /* Set the daylight bias to 0. The daylight bias is the amount of change
511 * in time that we use for daylight savings time. By setting this to 0
512 * we cause there to be no change in time during daylight savings time.
514 timeZoneInformation.DaylightBias = 0;
516 /* Convert the utc time to local time again, but this time without any
517 adjustment for daylight savings time.
519 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
521 /* If the two times are different, then it means that the localDST that
522 we calculated includes the daylight bias, and therefore we are
523 observing daylight savings time.
525 *pDST = localDST.wHour != local.wHour;
528 /* Determine if we are observing daylight savings time */
529 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
535 *pDstBias = -60; /* where can this be different? */
541 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
543 BOOL dst; /* Will be TRUE if observing DST */
544 LONG dstBias; /* Offset from local time if observing DST */
545 LONG bias; /* Offset from GMT for local time */
548 * This function will adjust the last write time to compensate
549 * for two bugs in the smb client:
551 * 1) During Daylight Savings Time, the LastWriteTime is ahead
552 * in time by the DaylightBias (ignoring the sign - the
553 * DaylightBias is always stored as a negative number). If
554 * the DaylightBias is -60, then the LastWriteTime will be
555 * ahead by 60 minutes.
557 * 2) If the local time zone is a positive offset from GMT, then
558 * the LastWriteTime will be the correct local time plus the
559 * Bias (ignoring the sign - a positive offset from GMT is
560 * always stored as a negative Bias). If the Bias is -120,
561 * then the LastWriteTime will be ahead by 120 minutes.
563 * These bugs can occur at the same time.
566 GetTimeZoneInfo(&dst, &dstBias, &bias);
568 /* First adjust for DST */
570 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
572 /* Now adjust for a positive offset from GMT (a negative bias). */
574 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
578 * Calculate the difference (in seconds) between local time and GMT.
579 * This enables us to convert file times to kludge-GMT.
585 struct tm gmt_tm, local_tm;
586 int days, hours, minutes, seconds;
589 gmt_tm = *(gmtime(&t));
590 local_tm = *(localtime(&t));
592 days = local_tm.tm_yday - gmt_tm.tm_yday;
593 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
595 /* There is a problem with DST immediately after the time change
596 * which may continue to exist until the machine is rebooted
598 - (local_tm.tm_isdst ? 1 : 0)
601 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
602 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
608 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
613 time_t ersatz_unixTime;
616 * Must use kludge-GMT instead of real GMT.
617 * kludge-GMT is computed by adding time zone difference to localtime.
620 * ltp = gmtime(&unixTime);
622 ersatz_unixTime = unixTime - smb_NowTZ;
623 ltp = localtime(&ersatz_unixTime);
625 /* if we fail, make up something */
628 localJunk.tm_year = 89 - 20;
629 localJunk.tm_mon = 4;
630 localJunk.tm_mday = 12;
631 localJunk.tm_hour = 0;
632 localJunk.tm_min = 0;
633 localJunk.tm_sec = 0;
636 stm.wYear = ltp->tm_year + 1900;
637 stm.wMonth = ltp->tm_mon + 1;
638 stm.wDayOfWeek = ltp->tm_wday;
639 stm.wDay = ltp->tm_mday;
640 stm.wHour = ltp->tm_hour;
641 stm.wMinute = ltp->tm_min;
642 stm.wSecond = ltp->tm_sec;
643 stm.wMilliseconds = 0;
645 SystemTimeToFileTime(&stm, largeTimep);
648 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
650 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
651 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
652 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
654 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
656 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
657 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
659 *ft = LargeIntegerMultiplyByLong(*ft, 60);
660 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
663 ut = ConvertLongToLargeInteger(unixTime);
664 ut = LargeIntegerMultiplyByLong(ut, 10000000);
665 *ft = LargeIntegerAdd(*ft, ut);
670 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
676 FileTimeToSystemTime(largeTimep, &stm);
678 lt.tm_year = stm.wYear - 1900;
679 lt.tm_mon = stm.wMonth - 1;
680 lt.tm_wday = stm.wDayOfWeek;
681 lt.tm_mday = stm.wDay;
682 lt.tm_hour = stm.wHour;
683 lt.tm_min = stm.wMinute;
684 lt.tm_sec = stm.wSecond;
687 save_timezone = _timezone;
688 _timezone += smb_NowTZ;
689 *unixTimep = mktime(<);
690 _timezone = save_timezone;
693 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
695 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
696 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
697 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
701 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
702 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
703 a = LargeIntegerMultiplyByLong(a, 60);
704 a = LargeIntegerMultiplyByLong(a, 10000000);
706 /* subtract it from ft */
707 a = LargeIntegerSubtract(*ft, a);
709 /* divide down to seconds */
710 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
714 void smb_SearchTimeFromUnixTime(time_t *dosTimep, time_t unixTime)
722 ltp = localtime((time_t*) &t);
724 /* if we fail, make up something */
727 localJunk.tm_year = 89 - 20;
728 localJunk.tm_mon = 4;
729 localJunk.tm_mday = 12;
730 localJunk.tm_hour = 0;
731 localJunk.tm_min = 0;
732 localJunk.tm_sec = 0;
735 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
736 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
737 *dosTimep = (dosDate<<16) | dosTime;
740 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
742 unsigned short dosDate;
743 unsigned short dosTime;
746 dosDate = (unsigned short) (searchTime & 0xffff);
747 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
749 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
750 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
751 localTm.tm_mday = (dosDate) & 0x1f;
752 localTm.tm_hour = (dosTime>>11) & 0x1f;
753 localTm.tm_min = (dosTime >> 5) & 0x3f;
754 localTm.tm_sec = (dosTime & 0x1f) * 2;
755 localTm.tm_isdst = -1; /* compute whether DST in effect */
757 *unixTimep = mktime(&localTm);
760 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
762 *dosUTimep = unixTime - smb_localZero;
765 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
768 *unixTimep = dosTime + smb_localZero;
770 /* dosTime seems to be already adjusted for GMT */
771 *unixTimep = dosTime;
775 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
779 lock_ObtainWrite(&smb_rctLock);
780 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
781 if (lsn == vcp->lsn && lana == vcp->lana) {
786 if (!vcp && (flags & SMB_FLAG_CREATE)) {
787 vcp = malloc(sizeof(*vcp));
788 memset(vcp, 0, sizeof(*vcp));
789 vcp->vcID = numVCs++;
793 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
794 vcp->nextp = smb_allVCsp;
796 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
801 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
802 /* We must obtain a challenge for extended auth
803 * in case the client negotiates smb v3
806 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
807 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
810 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
812 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
819 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
821 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
822 LsaFreeReturnBuffer(lsaResp);
825 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
827 lock_ReleaseWrite(&smb_rctLock);
831 int smb_IsStarMask(char *maskp)
836 for(i=0; i<11; i++) {
838 if (tc == '?' || tc == '*' || tc == '>') return 1;
843 void smb_ReleaseVC(smb_vc_t *vcp)
845 lock_ObtainWrite(&smb_rctLock);
846 osi_assert(vcp->refCount-- > 0);
847 lock_ReleaseWrite(&smb_rctLock);
850 void smb_HoldVC(smb_vc_t *vcp)
852 lock_ObtainWrite(&smb_rctLock);
854 lock_ReleaseWrite(&smb_rctLock);
857 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
861 lock_ObtainWrite(&smb_rctLock);
862 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
863 if (tid == tidp->tid) {
868 if (!tidp && (flags & SMB_FLAG_CREATE)) {
869 tidp = malloc(sizeof(*tidp));
870 memset(tidp, 0, sizeof(*tidp));
871 tidp->nextp = vcp->tidsp;
876 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
879 lock_ReleaseWrite(&smb_rctLock);
883 void smb_ReleaseTID(smb_tid_t *tidp)
892 lock_ObtainWrite(&smb_rctLock);
893 osi_assert(tidp->refCount-- > 0);
894 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
895 ltpp = &tidp->vcp->tidsp;
896 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
897 if (tp == tidp) break;
899 osi_assert(tp != NULL);
901 lock_FinalizeMutex(&tidp->mx);
902 userp = tidp->userp; /* remember to drop ref later */
905 lock_ReleaseWrite(&smb_rctLock);
907 cm_ReleaseUser(userp);
914 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
916 smb_user_t *uidp = NULL;
918 lock_ObtainWrite(&smb_rctLock);
919 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
920 if (uid == uidp->userID) {
922 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
923 (int)vcp, uidp->userID,
924 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
928 if (!uidp && (flags & SMB_FLAG_CREATE)) {
929 uidp = malloc(sizeof(*uidp));
930 memset(uidp, 0, sizeof(*uidp));
931 uidp->nextp = vcp->usersp;
936 lock_InitializeMutex(&uidp->mx, "user_t mutex");
938 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 : ""));
940 lock_ReleaseWrite(&smb_rctLock);
944 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
946 smb_username_t *unp= NULL;
948 lock_ObtainWrite(&smb_rctLock);
949 for(unp = usernamesp; unp; unp = unp->nextp) {
950 if (stricmp(unp->name, usern) == 0 &&
951 stricmp(unp->machine, machine) == 0) {
956 if (!unp && (flags & SMB_FLAG_CREATE)) {
957 unp = malloc(sizeof(*unp));
958 memset(unp, 0, sizeof(*unp));
960 unp->nextp = usernamesp;
961 unp->name = strdup(usern);
962 unp->machine = strdup(machine);
964 lock_InitializeMutex(&unp->mx, "username_t mutex");
966 lock_ReleaseWrite(&smb_rctLock);
970 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
972 smb_user_t *uidp= NULL;
974 lock_ObtainWrite(&smb_rctLock);
975 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
978 if (stricmp(uidp->unp->name, usern) == 0) {
980 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
985 lock_ReleaseWrite(&smb_rctLock);
988 void smb_ReleaseUID(smb_user_t *uidp)
997 lock_ObtainWrite(&smb_rctLock);
998 osi_assert(uidp->refCount-- > 0);
999 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1000 lupp = &uidp->vcp->usersp;
1001 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1002 if (up == uidp) break;
1004 osi_assert(up != NULL);
1006 lock_FinalizeMutex(&uidp->mx);
1008 userp = uidp->unp->userp; /* remember to drop ref later */
1009 uidp->unp->userp = NULL;
1014 lock_ReleaseWrite(&smb_rctLock);
1016 cm_ReleaseUserVCRef(userp);
1017 cm_ReleaseUser(userp);
1024 /* retrieve a held reference to a user structure corresponding to an incoming
1026 * corresponding release function is cm_ReleaseUser.
1028 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1034 smbp = (smb_t *) inp;
1035 uidp = smb_FindUID(vcp, smbp->uid, 0);
1036 if ((!uidp) || (!uidp->unp))
1039 lock_ObtainMutex(&uidp->mx);
1040 up = uidp->unp->userp;
1042 lock_ReleaseMutex(&uidp->mx);
1044 smb_ReleaseUID(uidp);
1050 * Return a pointer to a pathname extracted from a TID structure. The
1051 * TID structure is not held; assume it won't go away.
1053 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1058 tidp = smb_FindTID(vcp, tid, 0);
1062 if(tidp->flags & SMB_TIDFLAG_IPC) {
1063 code = CM_ERROR_TIDIPC;
1064 /* tidp->pathname would be NULL, but that's fine */
1066 *treepath = tidp->pathname;
1067 smb_ReleaseTID(tidp);
1072 /* check to see if we have a chained fid, that is, a fid that comes from an
1073 * OpenAndX message that ran earlier in this packet. In this case, the fid
1074 * field in a read, for example, request, isn't set, since the value is
1075 * supposed to be inherited from the openAndX call.
1077 int smb_ChainFID(int fid, smb_packet_t *inp)
1079 if (inp->fid == 0 || inp->inCount == 0)
1085 /* are we a priv'd user? What does this mean on NT? */
1086 int smb_SUser(cm_user_t *userp)
1091 /* find a file ID. If we pass in 0 we select an used File ID.
1092 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1093 * smb_fid_t data structure if desired File ID cannot be found.
1095 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1100 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1103 lock_ObtainWrite(&smb_rctLock);
1104 /* figure out if we need to allocate a new file ID */
1107 fid = vcp->fidCounter;
1111 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1112 if (fid == fidp->fid) {
1123 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1124 char eventName[MAX_PATH];
1126 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1127 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1128 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1129 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1130 thrd_CloseHandle(event);
1137 fidp = malloc(sizeof(*fidp));
1138 memset(fidp, 0, sizeof(*fidp));
1139 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1143 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1145 fidp->curr_chunk = fidp->prev_chunk = -2;
1146 fidp->raw_write_event = event;
1148 vcp->fidCounter = fid+1;
1149 if (vcp->fidCounter == 0)
1150 vcp->fidCounter = 1;
1153 lock_ReleaseWrite(&smb_rctLock);
1157 void smb_ReleaseFID(smb_fid_t *fidp)
1160 smb_vc_t *vcp = NULL;
1161 smb_ioctl_t *ioctlp;
1167 lock_ObtainWrite(&smb_rctLock);
1168 osi_assert(fidp->refCount-- > 0);
1169 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1171 if (!(fidp->flags & SMB_FID_IOCTL))
1173 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1174 thrd_CloseHandle(fidp->raw_write_event);
1176 /* and see if there is ioctl stuff to free */
1177 ioctlp = fidp->ioctlp;
1179 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1180 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1181 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1187 /* do not call smb_ReleaseVC() because we already have the lock */
1190 lock_ReleaseWrite(&smb_rctLock);
1192 /* now release the scache structure */
1194 cm_ReleaseSCache(scp);
1198 * Case-insensitive search for one string in another;
1199 * used to find variable names in submount pathnames.
1201 static char *smb_stristr(char *str1, char *str2)
1205 for (cursor = str1; *cursor; cursor++)
1206 if (stricmp(cursor, str2) == 0)
1213 * Substitute a variable value for its name in a submount pathname. Variable
1214 * name has been identified by smb_stristr() and is in substr. Variable name
1215 * length (plus one) is in substr_size. Variable value is in newstr.
1217 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1222 strcpy(temp, substr + substr_size - 1);
1223 strcpy(substr, newstr);
1227 char VNUserName[] = "%USERNAME%";
1228 char VNLCUserName[] = "%LCUSERNAME%";
1229 char VNComputerName[] = "%COMPUTERNAME%";
1230 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1233 /* List available shares */
1234 int smb_ListShares()
1238 char shareBuf[4096];
1246 /*strcpy(shareNameList[num_shares], "all");
1247 strcpy(pathNameList[num_shares++], "/afs");*/
1248 fprintf(stderr, "The following shares are available:\n");
1249 fprintf(stderr, "Share Name (AFS Path)\n");
1250 fprintf(stderr, "---------------------\n");
1251 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1254 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1255 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1257 strcpy(sbmtpath, cm_confDir);
1259 strcat(sbmtpath, "/afsdsbmt.ini");
1260 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1261 shareBuf, sizeof(shareBuf),
1267 this_share = shareBuf;
1271 /*strcpy(shareNameList[num_shares], this_share);*/
1272 len = GetPrivateProfileString("AFS Submounts", this_share,
1279 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1282 if (*p == '\\') *p = '/'; /* change to / */
1286 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1287 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1290 while (*this_share != 0) this_share++; /* find next NUL */
1291 this_share++; /* skip past the NUL */
1292 } while (*this_share != 0); /* stop at final NUL */
1298 typedef struct smb_findShare_rock {
1302 } smb_findShare_rock_t;
1304 #define SMB_FINDSHARE_EXACT_MATCH 1
1305 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1307 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1311 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1312 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1313 if(!stricmp(dep->name, vrock->shareName))
1314 matchType = SMB_FINDSHARE_EXACT_MATCH;
1316 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1317 if(vrock->match) free(vrock->match);
1318 vrock->match = strdup(dep->name);
1319 vrock->matchType = matchType;
1321 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1322 return CM_ERROR_STOPNOW;
1328 /* find a shareName in the table of submounts */
1329 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1333 char pathName[1024];
1338 char sbmtpath[MAX_PATH];
1343 DWORD allSubmount = 1;
1345 /* if allSubmounts == 0, only return the //mountRoot/all share
1346 * if in fact it has been been created in the subMounts table.
1347 * This is to allow sites that want to restrict access to the
1350 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1351 0, KEY_QUERY_VALUE, &parmKey);
1352 if (code == ERROR_SUCCESS) {
1353 len = sizeof(allSubmount);
1354 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1355 (BYTE *) &allSubmount, &len);
1356 if (code != ERROR_SUCCESS) {
1359 RegCloseKey (parmKey);
1362 if (allSubmount && _stricmp(shareName, "all") == 0) {
1367 /* In case, the all share is disabled we need to still be able
1368 * to handle ioctl requests
1370 if (_stricmp(shareName, "ioctl$") == 0) {
1371 *pathNamep = strdup("/.__ioctl__");
1375 if (_stricmp(shareName, "IPC$") == 0 ||
1376 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1377 _stricmp(shareName, "DESKTOP.INI") == 0
1384 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1385 0, KEY_QUERY_VALUE, &parmKey);
1386 if (code == ERROR_SUCCESS) {
1387 len = sizeof(pathName);
1388 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1389 (BYTE *) pathName, &len);
1390 if (code != ERROR_SUCCESS)
1392 RegCloseKey (parmKey);
1397 strcpy(sbmtpath, cm_confDir);
1398 strcat(sbmtpath, "/afsdsbmt.ini");
1399 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1400 pathName, sizeof(pathName), sbmtpath);
1402 if (len != 0 && len != sizeof(pathName) - 1) {
1403 /* We can accept either unix or PC style AFS pathnames. Convert
1404 * Unix-style to PC style here for internal use.
1407 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1408 p += strlen(cm_mountRoot); /* skip mount path */
1411 if (*q == '/') *q = '\\'; /* change to \ */
1417 if (var = smb_stristr(p, VNUserName)) {
1418 if (uidp && uidp->unp)
1419 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1421 smb_subst(p, var, sizeof(VNUserName)," ");
1423 else if (var = smb_stristr(p, VNLCUserName))
1425 if (uidp && uidp->unp)
1426 strcpy(temp, uidp->unp->name);
1430 smb_subst(p, var, sizeof(VNLCUserName), temp);
1432 else if (var = smb_stristr(p, VNComputerName))
1434 sizeTemp = sizeof(temp);
1435 GetComputerName((LPTSTR)temp, &sizeTemp);
1436 smb_subst(p, var, sizeof(VNComputerName), temp);
1438 else if (var = smb_stristr(p, VNLCComputerName))
1440 sizeTemp = sizeof(temp);
1441 GetComputerName((LPTSTR)temp, &sizeTemp);
1443 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1448 *pathNamep = strdup(p);
1453 /* First lookup shareName in root.afs */
1455 smb_findShare_rock_t vrock;
1457 char * p = shareName;
1460 /* attempt to locate a partial match in root.afs. This is because
1461 when using the ANSI RAP calls, the share name is limited to 13 chars
1462 and hence is truncated. Of course we prefer exact matches. */
1464 thyper.HighPart = 0;
1467 vrock.shareName = shareName;
1469 vrock.matchType = 0;
1471 cm_HoldSCache(cm_rootSCachep);
1472 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1473 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1474 cm_ReleaseSCache(cm_rootSCachep);
1476 if (vrock.matchType) {
1477 sprintf(pathName,"/%s/",vrock.match);
1478 *pathNamep = strdup(strlwr(pathName));
1483 /* if we get here, there was no match for the share in root.afs */
1484 /* so try to create \\<netbiosName>\<cellname> */
1489 /* Get the full name for this cell */
1490 code = cm_SearchCellFile(p, temp, 0, 0);
1491 #ifdef AFS_AFSDB_ENV
1492 if (code && cm_dnsEnabled) {
1494 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1497 /* construct the path */
1499 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1500 *pathNamep = strdup(strlwr(pathName));
1509 /* Client-side offline caching policy types */
1510 #define CSC_POLICY_MANUAL 0
1511 #define CSC_POLICY_DOCUMENTS 1
1512 #define CSC_POLICY_PROGRAMS 2
1513 #define CSC_POLICY_DISABLE 3
1515 int smb_FindShareCSCPolicy(char *shareName)
1521 int retval = CSC_POLICY_MANUAL;
1523 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1524 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1527 REG_OPTION_NON_VOLATILE,
1533 len = sizeof(policy);
1534 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1536 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1538 else if (stricmp(policy, "documents") == 0)
1540 retval = CSC_POLICY_DOCUMENTS;
1542 else if (stricmp(policy, "programs") == 0)
1544 retval = CSC_POLICY_PROGRAMS;
1546 else if (stricmp(policy, "disable") == 0)
1548 retval = CSC_POLICY_DISABLE;
1551 RegCloseKey(hkCSCPolicy);
1555 /* find a dir search structure by cookie value, and return it held.
1556 * Must be called with smb_globalLock held.
1558 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1560 smb_dirSearch_t *dsp;
1562 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1563 if (dsp->cookie == cookie) {
1564 if (dsp != smb_firstDirSearchp) {
1565 /* move to head of LRU queue, too, if we're not already there */
1566 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1567 smb_lastDirSearchp = (smb_dirSearch_t *)
1569 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1570 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1571 if (!smb_lastDirSearchp)
1572 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1574 lock_ObtainMutex(&dsp->mx);
1576 lock_ReleaseMutex(&dsp->mx);
1583 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1585 lock_ObtainWrite(&smb_globalLock);
1586 lock_ObtainMutex(&dsp->mx);
1587 dsp->flags |= SMB_DIRSEARCH_DELETE;
1588 if (dsp->scp != NULL) {
1589 lock_ObtainMutex(&dsp->scp->mx);
1590 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1591 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1592 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1593 dsp->scp->bulkStatProgress = hones;
1595 lock_ReleaseMutex(&dsp->scp->mx);
1597 lock_ReleaseMutex(&dsp->mx);
1598 lock_ReleaseWrite(&smb_globalLock);
1601 /* Must be called with the smb_globalLock held */
1602 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1608 lock_ObtainMutex(&dsp->mx);
1609 osi_assert(dsp->refCount-- > 0);
1610 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1611 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1612 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1613 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1614 lock_ReleaseMutex(&dsp->mx);
1615 lock_FinalizeMutex(&dsp->mx);
1619 lock_ReleaseMutex(&dsp->mx);
1621 /* do this now to avoid spurious locking hierarchy creation */
1622 if (scp) cm_ReleaseSCache(scp);
1625 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1627 lock_ObtainWrite(&smb_globalLock);
1628 smb_ReleaseDirSearchNoLock(dsp);
1629 lock_ReleaseWrite(&smb_globalLock);
1632 /* find a dir search structure by cookie value, and return it held */
1633 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1635 smb_dirSearch_t *dsp;
1637 lock_ObtainWrite(&smb_globalLock);
1638 dsp = smb_FindDirSearchNoLock(cookie);
1639 lock_ReleaseWrite(&smb_globalLock);
1643 /* GC some dir search entries, in the address space expected by the specific protocol.
1644 * Must be called with smb_globalLock held; release the lock temporarily.
1646 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1647 void smb_GCDirSearches(int isV3)
1649 smb_dirSearch_t *prevp;
1650 smb_dirSearch_t *tp;
1651 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1655 victimCount = 0; /* how many have we got so far */
1656 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1657 /* we'll move tp from queue, so
1660 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1661 /* if no one is using this guy, and we're either in the new protocol,
1662 * or we're in the old one and this is a small enough ID to be useful
1663 * to the old protocol, GC this guy.
1665 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1666 /* hold and delete */
1667 tp->flags |= SMB_DIRSEARCH_DELETE;
1668 victimsp[victimCount++] = tp;
1672 /* don't do more than this */
1673 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1677 /* now release them */
1678 for (i = 0; i < victimCount; i++) {
1679 smb_ReleaseDirSearchNoLock(victimsp[i]);
1683 /* function for allocating a dir search entry. We need these to remember enough context
1684 * since we don't get passed the path from call to call during a directory search.
1686 * Returns a held dir search structure, and bumps the reference count on the vnode,
1687 * since it saves a pointer to the vnode.
1689 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1691 smb_dirSearch_t *dsp;
1695 lock_ObtainWrite(&smb_globalLock);
1698 /* what's the biggest ID allowed in this version of the protocol */
1699 maxAllowed = isV3 ? 65535 : 255;
1702 /* twice so we have enough tries to find guys we GC after one pass;
1703 * 10 extra is just in case I mis-counted.
1705 if (++counter > 2*maxAllowed+10)
1706 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1708 if (smb_dirSearchCounter > maxAllowed) {
1709 smb_dirSearchCounter = 1;
1710 smb_GCDirSearches(isV3); /* GC some */
1712 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1714 /* don't need to watch for refcount zero and deleted, since
1715 * we haven't dropped the global lock.
1717 lock_ObtainMutex(&dsp->mx);
1719 lock_ReleaseMutex(&dsp->mx);
1720 ++smb_dirSearchCounter;
1724 dsp = malloc(sizeof(*dsp));
1725 memset(dsp, 0, sizeof(*dsp));
1726 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1727 if (!smb_lastDirSearchp)
1728 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1729 dsp->cookie = smb_dirSearchCounter;
1730 ++smb_dirSearchCounter;
1732 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1733 dsp->lastTime = osi_Time();
1736 lock_ReleaseWrite(&smb_globalLock);
1740 static smb_packet_t *GetPacket(void)
1744 unsigned int npar, seg, tb_sel;
1747 lock_ObtainWrite(&smb_globalLock);
1748 tbp = smb_packetFreeListp;
1750 smb_packetFreeListp = tbp->nextp;
1751 lock_ReleaseWrite(&smb_globalLock);
1754 tbp = calloc(65540,1);
1756 tbp = malloc(sizeof(smb_packet_t));
1758 tbp->magic = SMB_PACKETMAGIC;
1761 tbp->resumeCode = 0;
1767 tbp->ncb_length = 0;
1772 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1775 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1777 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1779 osi_panic("",__FILE__,__LINE__);
1782 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1787 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1788 tbp->dos_pkt_sel = tb_sel;
1791 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1796 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1800 memcpy(tbp, pkt, sizeof(smb_packet_t));
1801 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1805 static NCB *GetNCB(void)
1810 unsigned int npar, seg, tb_sel;
1813 lock_ObtainWrite(&smb_globalLock);
1814 tbp = smb_ncbFreeListp;
1816 smb_ncbFreeListp = tbp->nextp;
1817 lock_ReleaseWrite(&smb_globalLock);
1820 tbp = calloc(sizeof(*tbp),1);
1822 tbp = malloc(sizeof(*tbp));
1823 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1826 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1828 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1830 osi_panic("",__FILE__,__LINE__);
1832 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1837 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1838 tbp->dos_ncb_sel = tb_sel;
1840 tbp->magic = SMB_NCBMAGIC;
1843 osi_assert(tbp->magic == SMB_NCBMAGIC);
1845 memset(&tbp->ncb, 0, sizeof(NCB));
1848 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1853 void smb_FreePacket(smb_packet_t *tbp)
1855 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1857 lock_ObtainWrite(&smb_globalLock);
1858 tbp->nextp = smb_packetFreeListp;
1859 smb_packetFreeListp = tbp;
1860 tbp->magic = SMB_PACKETMAGIC;
1863 tbp->resumeCode = 0;
1869 tbp->ncb_length = 0;
1871 lock_ReleaseWrite(&smb_globalLock);
1874 static void FreeNCB(NCB *bufferp)
1878 tbp = (smb_ncb_t *) bufferp;
1879 osi_assert(tbp->magic == SMB_NCBMAGIC);
1881 lock_ObtainWrite(&smb_globalLock);
1882 tbp->nextp = smb_ncbFreeListp;
1883 smb_ncbFreeListp = tbp;
1884 lock_ReleaseWrite(&smb_globalLock);
1887 /* get a ptr to the data part of a packet, and its count */
1888 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1892 unsigned char *afterParmsp;
1894 parmBytes = *smbp->wctp << 1;
1895 afterParmsp = smbp->wctp + parmBytes + 1;
1897 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1898 if (nbytesp) *nbytesp = dataBytes;
1900 /* don't forget to skip the data byte count, since it follows
1901 * the parameters; that's where the "2" comes from below.
1903 return (unsigned char *) (afterParmsp + 2);
1906 /* must set all the returned parameters before playing around with the
1907 * data region, since the data region is located past the end of the
1908 * variable number of parameters.
1910 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1912 unsigned char *afterParmsp;
1914 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1916 *afterParmsp++ = dsize & 0xff;
1917 *afterParmsp = (dsize>>8) & 0xff;
1920 /* return the parm'th parameter in the smbp packet */
1921 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1924 unsigned char *parmDatap;
1926 parmCount = *smbp->wctp;
1928 if (parm >= parmCount) {
1933 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1935 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1936 parm, parmCount, smbp->ncb_length);
1939 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1940 1, smbp->ncb_length, ptbuf, smbp);
1941 DeregisterEventSource(h);
1943 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1944 osi_panic(s, __FILE__, __LINE__);
1946 parmDatap = smbp->wctp + (2*parm) + 1;
1948 return parmDatap[0] + (parmDatap[1] << 8);
1951 /* return the parm'th parameter in the smbp packet */
1952 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1955 unsigned char *parmDatap;
1957 parmCount = *smbp->wctp;
1959 if (parm * 2 + offset >= parmCount * 2) {
1964 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1966 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1967 parm, offset, parmCount, smbp->ncb_length);
1970 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1971 1, smbp->ncb_length, ptbuf, smbp);
1972 DeregisterEventSource(h);
1974 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1975 osi_panic(s, __FILE__, __LINE__);
1977 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1979 return parmDatap[0] + (parmDatap[1] << 8);
1982 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1986 /* make sure we have enough slots */
1987 if (*smbp->wctp <= slot)
1988 *smbp->wctp = slot+1;
1990 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1991 *parmDatap++ = parmValue & 0xff;
1992 *parmDatap = (parmValue>>8) & 0xff;
1995 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1999 /* make sure we have enough slots */
2000 if (*smbp->wctp <= slot)
2001 *smbp->wctp = slot+2;
2003 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2004 *parmDatap++ = parmValue & 0xff;
2005 *parmDatap++ = (parmValue>>8) & 0xff;
2006 *parmDatap++ = (parmValue>>16) & 0xff;
2007 *parmDatap++ = (parmValue>>24) & 0xff;
2010 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2015 /* make sure we have enough slots */
2016 if (*smbp->wctp <= slot)
2017 *smbp->wctp = slot+4;
2019 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2021 *parmDatap++ = *parmValuep++;
2024 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2028 /* make sure we have enough slots */
2029 if (*smbp->wctp <= slot) {
2030 if (smbp->oddByte) {
2032 *smbp->wctp = slot+1;
2037 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2038 *parmDatap++ = parmValue & 0xff;
2041 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2045 lastSlashp = strrchr(inPathp, '\\');
2047 *lastComponentp = lastSlashp;
2050 if (inPathp == lastSlashp)
2052 *outPathp++ = *inPathp++;
2061 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2066 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2071 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2077 tlen = inp[0] + (inp[1]<<8);
2078 inp += 2; /* skip length field */
2081 *chainpp = inp + tlen;
2090 /* format a packet as a response */
2091 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2096 outp = (smb_t *) op;
2098 /* zero the basic structure through the smb_wct field, and zero the data
2099 * size field, assuming that wct stays zero; otherwise, you have to
2100 * explicitly set the data size field, too.
2102 inSmbp = (smb_t *) inp;
2103 memset(outp, 0, sizeof(smb_t)+2);
2109 outp->com = inSmbp->com;
2110 outp->tid = inSmbp->tid;
2111 outp->pid = inSmbp->pid;
2112 outp->uid = inSmbp->uid;
2113 outp->mid = inSmbp->mid;
2114 outp->res[0] = inSmbp->res[0];
2115 outp->res[1] = inSmbp->res[1];
2116 op->inCom = inSmbp->com;
2118 outp->reb = 0x80; /* SERVER_RESP */
2119 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2121 /* copy fields in generic packet area */
2122 op->wctp = &outp->wct;
2125 /* send a (probably response) packet; vcp tells us to whom to send it.
2126 * we compute the length by looking at wct and bcc fields.
2128 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2145 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2148 memset((char *)ncbp, 0, sizeof(NCB));
2150 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2151 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2152 extra += tp[0] + (tp[1]<<8);
2153 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2154 extra += 3; /* wct and length fields */
2156 ncbp->ncb_length = extra; /* bytes to send */
2157 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2158 ncbp->ncb_lana_num = vcp->lana;
2159 ncbp->ncb_command = NCBSEND; /* op means send data */
2161 ncbp->ncb_buffer = (char *) inp;/* packet */
2162 code = Netbios(ncbp);
2164 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2165 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2167 /* copy header information from virtual to DOS address space */
2168 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2169 code = Netbios(ncbp, dos_ncb);
2173 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2179 void smb_MapNTError(long code, unsigned long *NTStatusp)
2181 unsigned long NTStatus;
2183 /* map CM_ERROR_* errors to NT 32-bit status codes */
2184 /* NT Status codes are listed in ntstatus.h not winerror.h */
2185 if (code == CM_ERROR_NOSUCHCELL) {
2186 NTStatus = 0xC000000FL; /* No such file */
2188 else if (code == CM_ERROR_NOSUCHVOLUME) {
2189 NTStatus = 0xC000000FL; /* No such file */
2191 else if (code == CM_ERROR_TIMEDOUT) {
2192 NTStatus = 0xC00000CFL; /* Sharing Paused */
2194 else if (code == CM_ERROR_RETRY) {
2195 NTStatus = 0xC000022DL; /* Retry */
2197 else if (code == CM_ERROR_NOACCESS) {
2198 NTStatus = 0xC0000022L; /* Access denied */
2200 else if (code == CM_ERROR_READONLY) {
2201 NTStatus = 0xC00000A2L; /* Write protected */
2203 else if (code == CM_ERROR_NOSUCHFILE) {
2204 NTStatus = 0xC000000FL; /* No such file */
2206 else if (code == CM_ERROR_NOSUCHPATH) {
2207 NTStatus = 0xC000003AL; /* Object path not found */
2209 else if (code == CM_ERROR_TOOBIG) {
2210 NTStatus = 0xC000007BL; /* Invalid image format */
2212 else if (code == CM_ERROR_INVAL) {
2213 NTStatus = 0xC000000DL; /* Invalid parameter */
2215 else if (code == CM_ERROR_BADFD) {
2216 NTStatus = 0xC0000008L; /* Invalid handle */
2218 else if (code == CM_ERROR_BADFDOP) {
2219 NTStatus = 0xC0000022L; /* Access denied */
2221 else if (code == CM_ERROR_EXISTS) {
2222 NTStatus = 0xC0000035L; /* Object name collision */
2224 else if (code == CM_ERROR_NOTEMPTY) {
2225 NTStatus = 0xC0000101L; /* Directory not empty */
2227 else if (code == CM_ERROR_CROSSDEVLINK) {
2228 NTStatus = 0xC00000D4L; /* Not same device */
2230 else if (code == CM_ERROR_NOTDIR) {
2231 NTStatus = 0xC0000103L; /* Not a directory */
2233 else if (code == CM_ERROR_ISDIR) {
2234 NTStatus = 0xC00000BAL; /* File is a directory */
2236 else if (code == CM_ERROR_BADOP) {
2238 /* I have no idea where this comes from */
2239 NTStatus = 0xC09820FFL; /* SMB no support */
2241 NTStatus = 0xC00000BBL; /* Not supported */
2242 #endif /* COMMENT */
2244 else if (code == CM_ERROR_BADSHARENAME) {
2245 NTStatus = 0xC00000CCL; /* Bad network name */
2247 else if (code == CM_ERROR_NOIPC) {
2249 NTStatus = 0xC0000022L; /* Access Denied */
2251 NTStatus = 0xC000013DL; /* Remote Resources */
2254 else if (code == CM_ERROR_CLOCKSKEW) {
2255 NTStatus = 0xC0000133L; /* Time difference at DC */
2257 else if (code == CM_ERROR_BADTID) {
2258 NTStatus = 0xC0982005L; /* SMB bad TID */
2260 else if (code == CM_ERROR_USESTD) {
2261 NTStatus = 0xC09820FBL; /* SMB use standard */
2263 else if (code == CM_ERROR_QUOTA) {
2265 NTStatus = 0xC0000044L; /* Quota exceeded */
2267 NTStatus = 0xC000007FL; /* Disk full */
2270 else if (code == CM_ERROR_SPACE) {
2271 NTStatus = 0xC000007FL; /* Disk full */
2273 else if (code == CM_ERROR_ATSYS) {
2274 NTStatus = 0xC0000033L; /* Object name invalid */
2276 else if (code == CM_ERROR_BADNTFILENAME) {
2277 NTStatus = 0xC0000033L; /* Object name invalid */
2279 else if (code == CM_ERROR_WOULDBLOCK) {
2280 NTStatus = 0xC0000055L; /* Lock not granted */
2282 else if (code == CM_ERROR_PARTIALWRITE) {
2283 NTStatus = 0xC000007FL; /* Disk full */
2285 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2286 NTStatus = 0xC0000023L; /* Buffer too small */
2288 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2289 NTStatus = 0xC0000035L; /* Object name collision */
2291 else if (code == CM_ERROR_BADPASSWORD) {
2292 NTStatus = 0xC000006DL; /* unknown username or bad password */
2294 else if (code == CM_ERROR_BADLOGONTYPE) {
2295 NTStatus = 0xC000015BL; /* logon type not granted */
2297 else if (code == CM_ERROR_GSSCONTINUE) {
2298 NTStatus = 0xC0000016L; /* more processing required */
2300 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2302 NTStatus = 0xC0000280L; /* reparse point not resolved */
2304 NTStatus = 0xC0000022L; /* Access Denied */
2308 NTStatus = 0xC0982001L; /* SMB non-specific error */
2311 *NTStatusp = NTStatus;
2312 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2315 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2316 unsigned char *classp)
2318 unsigned char class;
2319 unsigned short error;
2321 /* map CM_ERROR_* errors to SMB errors */
2322 if (code == CM_ERROR_NOSUCHCELL) {
2324 error = 3; /* bad path */
2326 else if (code == CM_ERROR_NOSUCHVOLUME) {
2328 error = 3; /* bad path */
2330 else if (code == CM_ERROR_TIMEDOUT) {
2332 error = 81; /* server is paused */
2334 else if (code == CM_ERROR_RETRY) {
2335 class = 2; /* shouldn't happen */
2338 else if (code == CM_ERROR_NOACCESS) {
2340 error = 4; /* bad access */
2342 else if (code == CM_ERROR_READONLY) {
2344 error = 19; /* read only */
2346 else if (code == CM_ERROR_NOSUCHFILE) {
2348 error = 2; /* ENOENT! */
2350 else if (code == CM_ERROR_NOSUCHPATH) {
2352 error = 3; /* Bad path */
2354 else if (code == CM_ERROR_TOOBIG) {
2356 error = 11; /* bad format */
2358 else if (code == CM_ERROR_INVAL) {
2359 class = 2; /* server non-specific error code */
2362 else if (code == CM_ERROR_BADFD) {
2364 error = 6; /* invalid file handle */
2366 else if (code == CM_ERROR_BADFDOP) {
2367 class = 1; /* invalid op on FD */
2370 else if (code == CM_ERROR_EXISTS) {
2372 error = 80; /* file already exists */
2374 else if (code == CM_ERROR_NOTEMPTY) {
2376 error = 5; /* delete directory not empty */
2378 else if (code == CM_ERROR_CROSSDEVLINK) {
2380 error = 17; /* EXDEV */
2382 else if (code == CM_ERROR_NOTDIR) {
2383 class = 1; /* bad path */
2386 else if (code == CM_ERROR_ISDIR) {
2387 class = 1; /* access denied; DOS doesn't have a good match */
2390 else if (code == CM_ERROR_BADOP) {
2394 else if (code == CM_ERROR_BADSHARENAME) {
2398 else if (code == CM_ERROR_NOIPC) {
2400 error = 4; /* bad access */
2402 else if (code == CM_ERROR_CLOCKSKEW) {
2403 class = 1; /* invalid function */
2406 else if (code == CM_ERROR_BADTID) {
2410 else if (code == CM_ERROR_USESTD) {
2414 else if (code == CM_ERROR_REMOTECONN) {
2418 else if (code == CM_ERROR_QUOTA) {
2419 if (vcp->flags & SMB_VCFLAG_USEV3) {
2421 error = 39; /* disk full */
2425 error = 5; /* access denied */
2428 else if (code == CM_ERROR_SPACE) {
2429 if (vcp->flags & SMB_VCFLAG_USEV3) {
2431 error = 39; /* disk full */
2435 error = 5; /* access denied */
2438 else if (code == CM_ERROR_PARTIALWRITE) {
2440 error = 39; /* disk full */
2442 else if (code == CM_ERROR_ATSYS) {
2444 error = 2; /* ENOENT */
2446 else if (code == CM_ERROR_WOULDBLOCK) {
2448 error = 33; /* lock conflict */
2450 else if (code == CM_ERROR_NOFILES) {
2452 error = 18; /* no files in search */
2454 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2456 error = 183; /* Samba uses this */
2458 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2459 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2461 error = 2; /* bad password */
2470 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2473 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2475 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2476 return CM_ERROR_BADOP;
2479 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2481 unsigned short EchoCount, i;
2482 char *data, *outdata;
2485 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2487 for (i=1; i<=EchoCount; i++) {
2488 data = smb_GetSMBData(inp, &dataSize);
2489 smb_SetSMBParm(outp, 0, i);
2490 smb_SetSMBDataLength(outp, dataSize);
2491 outdata = smb_GetSMBData(outp, NULL);
2492 memcpy(outdata, data, dataSize);
2493 smb_SendPacket(vcp, outp);
2499 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2502 long count, minCount, finalCount;
2506 cm_user_t *userp = NULL;
2510 char *rawBuf = NULL;
2512 dos_ptr rawBuf = NULL;
2519 fd = smb_GetSMBParm(inp, 0);
2520 count = smb_GetSMBParm(inp, 3);
2521 minCount = smb_GetSMBParm(inp, 4);
2522 offset.HighPart = 0; /* too bad */
2523 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2525 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2526 fd, offset.LowPart, count);
2528 fidp = smb_FindFID(vcp, fd, 0);
2532 lock_ObtainMutex(&smb_RawBufLock);
2534 /* Get a raw buf, from head of list */
2535 rawBuf = smb_RawBufs;
2537 smb_RawBufs = *(char **)smb_RawBufs;
2539 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2542 lock_ReleaseMutex(&smb_RawBufLock);
2546 if (fidp->flags & SMB_FID_IOCTL)
2549 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2551 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2554 /* Give back raw buffer */
2555 lock_ObtainMutex(&smb_RawBufLock);
2557 *((char **) rawBuf) = smb_RawBufs;
2559 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2562 smb_RawBufs = rawBuf;
2563 lock_ReleaseMutex(&smb_RawBufLock);
2566 smb_ReleaseFID(fidp);
2570 userp = smb_GetUser(vcp, inp);
2573 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2575 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2576 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2577 userp, &finalCount, TRUE /* rawFlag */);
2584 cm_ReleaseUser(userp);
2587 smb_ReleaseFID(fidp);
2592 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2594 memset((char *)ncbp, 0, sizeof(NCB));
2596 ncbp->ncb_length = (unsigned short) finalCount;
2597 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2598 ncbp->ncb_lana_num = vcp->lana;
2599 ncbp->ncb_command = NCBSEND;
2600 ncbp->ncb_buffer = rawBuf;
2603 code = Netbios(ncbp);
2605 code = Netbios(ncbp, dos_ncb);
2608 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2611 /* Give back raw buffer */
2612 lock_ObtainMutex(&smb_RawBufLock);
2614 *((char **) rawBuf) = smb_RawBufs;
2616 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2619 smb_RawBufs = rawBuf;
2620 lock_ReleaseMutex(&smb_RawBufLock);
2626 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2628 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2633 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2635 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2640 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2647 int protoIndex; /* index we're using */
2652 char protocol_array[10][1024]; /* protocol signature of the client */
2653 int caps; /* capabilities */
2656 TIME_ZONE_INFORMATION tzi;
2658 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2662 DWORD now = GetCurrentTime();
2663 if (now - last_msg_time >= 30000
2664 && now - last_msg_time <= 90000) {
2666 "Setting dead_vcp %x", active_vcp);
2668 smb_ReleaseVC(dead_vcp);
2670 "Previous dead_vcp %x", dead_vcp);
2672 smb_HoldVC(active_vcp);
2673 dead_vcp = active_vcp;
2674 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2679 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2681 namep = smb_GetSMBData(inp, &dbytes);
2684 coreProtoIndex = -1; /* not found */
2687 while(namex < dbytes) {
2688 osi_Log1(smb_logp, "Protocol %s",
2689 osi_LogSaveString(smb_logp, namep+1));
2690 strcpy(protocol_array[tcounter], namep+1);
2692 /* namep points at the first protocol, or really, a 0x02
2693 * byte preceding the null-terminated ASCII name.
2695 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2696 coreProtoIndex = tcounter;
2698 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2699 v3ProtoIndex = tcounter;
2701 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2702 NTProtoIndex = tcounter;
2705 /* compute size of protocol entry */
2706 entryLength = strlen(namep+1);
2707 entryLength += 2; /* 0x02 bytes and null termination */
2709 /* advance over this protocol entry */
2710 namex += entryLength;
2711 namep += entryLength;
2712 tcounter++; /* which proto entry we're looking at */
2715 if (NTProtoIndex != -1) {
2716 protoIndex = NTProtoIndex;
2717 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2719 else if (v3ProtoIndex != -1) {
2720 protoIndex = v3ProtoIndex;
2721 vcp->flags |= SMB_VCFLAG_USEV3;
2723 else if (coreProtoIndex != -1) {
2724 protoIndex = coreProtoIndex;
2725 vcp->flags |= SMB_VCFLAG_USECORE;
2727 else protoIndex = -1;
2729 if (protoIndex == -1)
2730 return CM_ERROR_INVAL;
2731 else if (NTProtoIndex != -1) {
2732 smb_SetSMBParm(outp, 0, protoIndex);
2733 if (smb_authType != SMB_AUTH_NONE) {
2734 smb_SetSMBParmByte(outp, 1,
2735 NEGOTIATE_SECURITY_USER_LEVEL |
2736 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2738 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2740 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2741 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2742 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2743 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2744 /* The session key is not a well documented field however most clients
2745 * will echo back the session key to the server. Currently we are using
2746 * the same value for all sessions. We should generate a random value
2747 * and store it into the vcp
2749 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2750 smb_SetSMBParm(outp, 8, 1);
2752 * Tried changing the capabilities to support for W2K - defect 117695
2753 * Maybe something else needs to be changed here?
2757 smb_SetSMBParmLong(outp, 9, 0x43fd);
2759 smb_SetSMBParmLong(outp, 9, 0x251);
2762 * 32-bit error codes *
2766 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2767 NTNEGOTIATE_CAPABILITY_NTFIND |
2768 NTNEGOTIATE_CAPABILITY_RAWMODE |
2769 NTNEGOTIATE_CAPABILITY_NTSMB;
2771 if ( smb_authType == SMB_AUTH_EXTENDED )
2772 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2774 smb_SetSMBParmLong(outp, 9, caps);
2776 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2777 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2778 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2780 GetTimeZoneInformation(&tzi);
2781 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2783 if (smb_authType == SMB_AUTH_NTLM) {
2784 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2785 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2786 /* paste in encryption key */
2787 datap = smb_GetSMBData(outp, NULL);
2788 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2789 /* and the faux domain name */
2790 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2791 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2795 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2797 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2799 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2801 datap = smb_GetSMBData(outp, NULL);
2802 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2805 datap += sizeof(smb_ServerGUID);
2806 memcpy(datap, secBlob, secBlobLength);
2810 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2811 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2814 else if (v3ProtoIndex != -1) {
2815 smb_SetSMBParm(outp, 0, protoIndex);
2817 /* NOTE: Extended authentication cannot be negotiated with v3
2818 * therefore we fail over to NTLM
2820 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2821 smb_SetSMBParm(outp, 1,
2822 NEGOTIATE_SECURITY_USER_LEVEL |
2823 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2825 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2827 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2828 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2829 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2830 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2831 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2832 smb_SetSMBParm(outp, 7, 1);
2834 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2835 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2836 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2838 GetTimeZoneInformation(&tzi);
2839 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2841 /* NOTE: Extended authentication cannot be negotiated with v3
2842 * therefore we fail over to NTLM
2844 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2845 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2846 smb_SetSMBParm(outp, 12, 0); /* resvd */
2847 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2848 datap = smb_GetSMBData(outp, NULL);
2849 /* paste in a new encryption key */
2850 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2851 /* and the faux domain name */
2852 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2854 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2855 smb_SetSMBParm(outp, 12, 0); /* resvd */
2856 smb_SetSMBDataLength(outp, 0);
2859 else if (coreProtoIndex != -1) { /* not really supported anymore */
2860 smb_SetSMBParm(outp, 0, protoIndex);
2861 smb_SetSMBDataLength(outp, 0);
2866 void smb_Daemon(void *parmp)
2868 afs_uint32 count = 0;
2870 while(smbShutdownFlag == 0) {
2874 if (smbShutdownFlag == 1)
2877 if ((count % 72) == 0) { /* every five minutes */
2879 time_t old_localZero = smb_localZero;
2881 /* Initialize smb_localZero */
2882 myTime.tm_isdst = -1; /* compute whether on DST or not */
2883 myTime.tm_year = 70;
2889 smb_localZero = mktime(&myTime);
2891 smb_CalculateNowTZ();
2893 #ifdef AFS_FREELANCE
2894 if ( smb_localZero != old_localZero )
2895 cm_noteLocalMountPointChange();
2898 /* XXX GC dir search entries */
2902 void smb_WaitingLocksDaemon()
2904 smb_waitingLock_t *wL, *nwL;
2907 smb_packet_t *inp, *outp;
2912 lock_ObtainWrite(&smb_globalLock);
2913 nwL = smb_allWaitingLocks;
2915 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2924 lock_ObtainWrite(&smb_globalLock);
2926 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2927 lock_ReleaseWrite(&smb_globalLock);
2928 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2929 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2930 if (code == CM_ERROR_WOULDBLOCK) {
2932 if (wL->timeRemaining != 0xffffffff
2933 && (wL->timeRemaining -= 1000) < 0)
2942 ncbp->ncb_length = inp->ncb_length;
2943 inp->spacep = cm_GetSpace();
2945 /* Remove waitingLock from list */
2946 lock_ObtainWrite(&smb_globalLock);
2947 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2949 lock_ReleaseWrite(&smb_globalLock);
2951 /* Resume packet processing */
2953 smb_SetSMBDataLength(outp, 0);
2954 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2955 outp->resumeCode = code;
2957 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2960 cm_FreeSpace(inp->spacep);
2961 smb_FreePacket(inp);
2962 smb_FreePacket(outp);
2970 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2972 osi_Log0(smb_logp, "SMB receive get disk attributes");
2974 smb_SetSMBParm(outp, 0, 32000);
2975 smb_SetSMBParm(outp, 1, 64);
2976 smb_SetSMBParm(outp, 2, 1024);
2977 smb_SetSMBParm(outp, 3, 30000);
2978 smb_SetSMBParm(outp, 4, 0);
2979 smb_SetSMBDataLength(outp, 0);
2983 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2987 unsigned short newTid;
2988 char shareName[256];
2996 osi_Log0(smb_logp, "SMB receive tree connect");
2998 /* parse input parameters */
2999 tp = smb_GetSMBData(inp, NULL);
3000 pathp = smb_ParseASCIIBlock(tp, &tp);
3001 passwordp = smb_ParseASCIIBlock(tp, &tp);
3002 tp = strrchr(pathp, '\\');
3004 return CM_ERROR_BADSMB;
3005 strcpy(shareName, tp+1);
3007 userp = smb_GetUser(vcp, inp);
3009 lock_ObtainMutex(&vcp->mx);
3010 newTid = vcp->tidCounter++;
3011 lock_ReleaseMutex(&vcp->mx);
3013 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3014 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3015 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3017 smb_ReleaseUID(uidp);
3019 smb_ReleaseTID(tidp);
3020 return CM_ERROR_BADSHARENAME;
3022 lock_ObtainMutex(&tidp->mx);
3023 tidp->userp = userp;
3024 tidp->pathname = sharePath;
3025 lock_ReleaseMutex(&tidp->mx);
3026 smb_ReleaseTID(tidp);
3028 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3029 smb_SetSMBParm(rsp, 1, newTid);
3030 smb_SetSMBDataLength(rsp, 0);
3032 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3036 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3040 if (*inp++ != 0x1) return NULL;
3041 tlen = inp[0] + (inp[1]<<8);
3042 inp += 2; /* skip length field */
3045 *chainpp = inp + tlen;
3048 if (lengthp) *lengthp = tlen;
3053 /* set maskp to the mask part of the incoming path.
3054 * Mask is 11 bytes long (8.3 with the dot elided).
3055 * Returns true if succeeds with a valid name, otherwise it does
3056 * its best, but returns false.
3058 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3066 /* starts off valid */
3069 /* mask starts out all blanks */
3070 memset(maskp, ' ', 11);
3072 /* find last backslash, or use whole thing if there is none */
3073 tp = strrchr(pathp, '\\');
3074 if (!tp) tp = pathp;
3075 else tp++; /* skip slash */
3079 /* names starting with a dot are illegal */
3080 if (*tp == '.') valid8Dot3 = 0;
3084 if (tc == 0) return valid8Dot3;
3085 if (tc == '.' || tc == '"') break;
3086 if (i < 8) *up++ = tc;
3087 else valid8Dot3 = 0;
3090 /* if we get here, tp point after the dot */
3091 up = maskp+8; /* ext goes here */
3098 if (tc == '.' || tc == '"')
3101 /* copy extension if not too long */
3111 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3121 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3123 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3127 /* otherwise, we have a valid 8.3 name; see if we have a match,
3128 * treating '?' as a wildcard in maskp (but not in the file name).
3130 tp1 = umask; /* real name, in mask format */
3131 tp2 = maskp; /* mask, in mask format */
3132 for(i=0; i<11; i++) {
3133 tc1 = *tp1++; /* char from real name */
3134 tc2 = *tp2++; /* char from mask */
3135 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3136 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3139 if (tc2 == '?' && tc1 != ' ')
3146 /* we got a match */
3150 char *smb_FindMask(char *pathp)
3154 tp = strrchr(pathp, '\\'); /* find last slash */
3157 return tp+1; /* skip the slash */
3159 return pathp; /* no slash, return the entire path */
3162 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3164 unsigned char *pathp;
3166 unsigned char mask[11];
3167 unsigned char *statBlockp;
3168 unsigned char initStatBlock[21];
3171 osi_Log0(smb_logp, "SMB receive search volume");
3173 /* pull pathname and stat block out of request */
3174 tp = smb_GetSMBData(inp, NULL);
3175 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3176 osi_assert(pathp != NULL);
3177 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3178 osi_assert(statBlockp != NULL);
3180 statBlockp = initStatBlock;
3184 /* for returning to caller */
3185 smb_Get8Dot3MaskFromPath(mask, pathp);
3187 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3188 tp = smb_GetSMBData(outp, NULL);
3190 *tp++ = 43; /* bytes in a dir entry */
3191 *tp++ = 0; /* high byte in counter */
3193 /* now marshall the dir entry, starting with the search status */
3194 *tp++ = statBlockp[0]; /* Reserved */
3195 memcpy(tp, mask, 11); tp += 11; /* FileName */
3197 /* now pass back server use info, with 1st byte non-zero */
3199 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3201 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3203 *tp++ = 0x8; /* attribute: volume */
3213 /* 4 byte file size */
3219 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3220 memset(tp, ' ', 13);
3223 /* set the length of the data part of the packet to 43 + 3, for the dir
3224 * entry plus the 5 and the length fields.
3226 smb_SetSMBDataLength(outp, 46);
3230 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3231 cm_user_t *userp, cm_req_t *reqp)
3239 smb_dirListPatch_t *patchp;
3240 smb_dirListPatch_t *npatchp;
3242 for (patchp = *dirPatchespp; patchp; patchp =
3243 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3245 dptr = patchp->dptr;
3247 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3249 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3250 *dptr++ = SMB_ATTR_HIDDEN;
3253 lock_ObtainMutex(&scp->mx);
3254 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3255 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3257 lock_ReleaseMutex(&scp->mx);
3258 cm_ReleaseSCache(scp);
3259 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3260 *dptr++ = SMB_ATTR_HIDDEN;
3264 attr = smb_Attributes(scp);
3265 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3266 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3267 attr |= SMB_ATTR_HIDDEN;
3271 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3274 shortTemp = (unsigned short) (dosTime & 0xffff);
3275 *((u_short *)dptr) = shortTemp;
3278 /* and copy out date */
3279 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3280 *((u_short *)dptr) = shortTemp;
3283 /* copy out file length */
3284 *((u_long *)dptr) = scp->length.LowPart;
3286 lock_ReleaseMutex(&scp->mx);
3287 cm_ReleaseSCache(scp);
3290 /* now free the patches */
3291 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3292 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3296 /* and mark the list as empty */
3297 *dirPatchespp = NULL;
3302 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3311 smb_dirListPatch_t *dirListPatchesp;
3312 smb_dirListPatch_t *curPatchp;
3316 osi_hyper_t dirLength;
3317 osi_hyper_t bufferOffset;
3318 osi_hyper_t curOffset;
3320 unsigned char *inCookiep;
3321 smb_dirSearch_t *dsp;
3325 unsigned long clientCookie;
3326 cm_pageHeader_t *pageHeaderp;
3327 cm_user_t *userp = NULL;
3334 long nextEntryCookie;
3335 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3336 char resByte; /* reserved byte from the cookie */
3337 char *op; /* output data ptr */
3338 char *origOp; /* original value of op */
3339 cm_space_t *spacep; /* for pathname buffer */
3350 maxCount = smb_GetSMBParm(inp, 0);
3352 dirListPatchesp = NULL;
3354 caseFold = CM_FLAG_CASEFOLD;
3356 tp = smb_GetSMBData(inp, NULL);
3357 pathp = smb_ParseASCIIBlock(tp, &tp);
3358 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3360 /* bail out if request looks bad */
3361 if (!tp || !pathp) {
3362 return CM_ERROR_BADSMB;
3365 /* We can handle long names */
3366 if (vcp->flags & SMB_VCFLAG_USENT)
3367 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3369 /* make sure we got a whole search status */
3370 if (dataLength < 21) {
3371 nextCookie = 0; /* start at the beginning of the dir */
3374 attribute = smb_GetSMBParm(inp, 1);
3376 /* handle volume info in another function */
3377 if (attribute & 0x8)
3378 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3380 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3381 maxCount, osi_LogSaveString(smb_logp, pathp));
3383 if (*pathp == 0) { /* null pathp, treat as root dir */
3384 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3385 return CM_ERROR_NOFILES;
3389 dsp = smb_NewDirSearch(0);
3390 dsp->attribute = attribute;
3391 smb_Get8Dot3MaskFromPath(mask, pathp);
3392 memcpy(dsp->mask, mask, 11);
3394 /* track if this is likely to match a lot of entries */
3395 if (smb_IsStarMask(mask)) starPattern = 1;
3396 else starPattern = 0;
3399 /* pull the next cookie value out of the search status block */
3400 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3401 + (inCookiep[16]<<24);
3402 dsp = smb_FindDirSearch(inCookiep[12]);
3404 /* can't find dir search status; fatal error */
3405 return CM_ERROR_BADFD;
3407 attribute = dsp->attribute;
3408 resByte = inCookiep[0];
3410 /* copy out client cookie, in host byte order. Don't bother
3411 * interpreting it, since we're just passing it through, anyway.
3413 memcpy(&clientCookie, &inCookiep[17], 4);
3415 memcpy(mask, dsp->mask, 11);
3417 /* assume we're doing a star match if it has continued for more
3423 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3424 nextCookie, dsp->cookie, attribute);
3426 userp = smb_GetUser(vcp, inp);
3428 /* try to get the vnode for the path name next */
3429 lock_ObtainMutex(&dsp->mx);
3436 spacep = inp->spacep;
3437 smb_StripLastComponent(spacep->data, NULL, pathp);
3438 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3440 lock_ReleaseMutex(&dsp->mx);
3441 cm_ReleaseUser(userp);
3442 smb_DeleteDirSearch(dsp);
3443 smb_ReleaseDirSearch(dsp);
3444 return CM_ERROR_NOFILES;
3446 code = cm_NameI(cm_rootSCachep, spacep->data,
3447 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3450 cm_ReleaseSCache(dsp->scp);
3452 /* we need one hold for the entry we just stored into,
3453 * and one for our own processing. When we're done with this
3454 * function, we'll drop the one for our own processing.
3455 * We held it once from the namei call, and so we do another hold
3459 lock_ObtainMutex(&scp->mx);
3460 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3461 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3462 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3463 dsp->flags |= SMB_DIRSEARCH_BULKST;
3465 lock_ReleaseMutex(&scp->mx);
3468 lock_ReleaseMutex(&dsp->mx);
3470 cm_ReleaseUser(userp);
3471 smb_DeleteDirSearch(dsp);
3472 smb_ReleaseDirSearch(dsp);
3476 /* reserves space for parameter; we'll adjust it again later to the
3477 * real count of the # of entries we returned once we've actually
3478 * assembled the directory listing.
3480 smb_SetSMBParm(outp, 0, 0);
3482 /* get the directory size */
3483 lock_ObtainMutex(&scp->mx);
3484 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3485 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3487 lock_ReleaseMutex(&scp->mx);
3488 cm_ReleaseSCache(scp);
3489 cm_ReleaseUser(userp);
3490 smb_DeleteDirSearch(dsp);
3491 smb_ReleaseDirSearch(dsp);
3495 dirLength = scp->length;
3497 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3498 curOffset.HighPart = 0;
3499 curOffset.LowPart = nextCookie;
3500 origOp = op = smb_GetSMBData(outp, NULL);
3501 /* and write out the basic header */
3502 *op++ = 5; /* variable block */
3503 op += 2; /* skip vbl block length; we'll fill it in later */
3507 /* make sure that curOffset.LowPart doesn't point to the first
3508 * 32 bytes in the 2nd through last dir page, and that it doesn't
3509 * point at the first 13 32-byte chunks in the first dir page,
3510 * since those are dir and page headers, and don't contain useful
3513 temp = curOffset.LowPart & (2048-1);
3514 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3515 /* we're in the first page */
3516 if (temp < 13*32) temp = 13*32;
3519 /* we're in a later dir page */
3520 if (temp < 32) temp = 32;
3523 /* make sure the low order 5 bits are zero */
3526 /* now put temp bits back ito curOffset.LowPart */
3527 curOffset.LowPart &= ~(2048-1);
3528 curOffset.LowPart |= temp;
3530 /* check if we've returned all the names that will fit in the
3533 if (returnedNames >= maxCount)
3536 /* check if we've passed the dir's EOF */
3537 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3539 /* see if we can use the bufferp we have now; compute in which page
3540 * the current offset would be, and check whether that's the offset
3541 * of the buffer we have. If not, get the buffer.
3543 thyper.HighPart = curOffset.HighPart;
3544 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3545 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3548 buf_Release(bufferp);
3551 lock_ReleaseMutex(&scp->mx);
3552 lock_ObtainRead(&scp->bufCreateLock);
3553 code = buf_Get(scp, &thyper, &bufferp);
3554 lock_ReleaseRead(&scp->bufCreateLock);
3555 lock_ObtainMutex(&dsp->mx);
3557 /* now, if we're doing a star match, do bulk fetching of all of
3558 * the status info for files in the dir.
3561 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3562 lock_ObtainMutex(&scp->mx);
3563 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3564 LargeIntegerGreaterThanOrEqualTo(thyper,
3565 scp->bulkStatProgress)) {
3566 /* Don't bulk stat if risking timeout */
3567 int now = GetCurrentTime();
3568 if (now - req.startTime > 5000) {
3569 scp->bulkStatProgress = thyper;
3570 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3571 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3573 cm_TryBulkStat(scp, &thyper, userp, &req);
3576 lock_ObtainMutex(&scp->mx);
3578 lock_ReleaseMutex(&dsp->mx);
3582 bufferOffset = thyper;
3584 /* now get the data in the cache */
3586 code = cm_SyncOp(scp, bufferp, userp, &req,
3588 CM_SCACHESYNC_NEEDCALLBACK |
3589 CM_SCACHESYNC_READ);
3592 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3594 /* otherwise, load the buffer and try again */
3595 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3599 buf_Release(bufferp);
3603 } /* if (wrong buffer) ... */
3605 /* now we have the buffer containing the entry we're interested in; copy
3606 * it out if it represents a non-deleted entry.
3608 entryInDir = curOffset.LowPart & (2048-1);
3609 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3611 /* page header will help tell us which entries are free. Page header
3612 * can change more often than once per buffer, since AFS 3 dir page size
3613 * may be less than (but not more than a buffer package buffer.
3615 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3616 temp &= ~(2048 - 1); /* turn off intra-page bits */
3617 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3619 /* now determine which entry we're looking at in the page. If it is
3620 * free (there's a free bitmap at the start of the dir), we should
3621 * skip these 32 bytes.
3623 slotInPage = (entryInDir & 0x7e0) >> 5;
3624 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3625 /* this entry is free */
3626 numDirChunks = 1; /* only skip this guy */
3630 tp = bufferp->datap + entryInBuffer;
3631 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3633 /* while we're here, compute the next entry's location, too,
3634 * since we'll need it when writing out the cookie into the dir
3637 * XXXX Probably should do more sanity checking.
3639 numDirChunks = cm_NameEntries(dep->name, NULL);
3641 /* compute the offset of the cookie representing the next entry */
3642 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3644 /* Compute 8.3 name if necessary */
3645 actualName = dep->name;
3646 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3647 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3648 actualName = shortName;
3651 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3652 /* this is one of the entries to use: it is not deleted
3653 * and it matches the star pattern we're looking for.
3656 /* Eliminate entries that don't match requested
3659 /* no hidden files */
3660 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3663 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3665 /* We have already done the cm_TryBulkStat above */
3666 fid.cell = scp->fid.cell;
3667 fid.volume = scp->fid.volume;
3668 fid.vnode = ntohl(dep->fid.vnode);
3669 fid.unique = ntohl(dep->fid.unique);
3670 fileType = cm_FindFileType(&fid);
3671 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3672 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3674 if (fileType == CM_SCACHETYPE_DIRECTORY)
3679 memcpy(op, mask, 11); op += 11;
3680 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3681 *op++ = nextEntryCookie & 0xff;
3682 *op++ = (nextEntryCookie>>8) & 0xff;
3683 *op++ = (nextEntryCookie>>16) & 0xff;
3684 *op++ = (nextEntryCookie>>24) & 0xff;
3685 memcpy(op, &clientCookie, 4); op += 4;
3687 /* now we emit the attribute. This is sort of tricky,
3688 * since we need to really stat the file to find out
3689 * what type of entry we've got. Right now, we're
3690 * copying out data from a buffer, while holding the
3691 * scp locked, so it isn't really convenient to stat
3692 * something now. We'll put in a place holder now,
3693 * and make a second pass before returning this to get
3694 * the real attributes. So, we just skip the data for
3695 * now, and adjust it later. We allocate a patch
3696 * record to make it easy to find this point later.
3697 * The replay will happen at a time when it is safe to
3698 * unlock the directory.
3700 curPatchp = malloc(sizeof(*curPatchp));
3701 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3702 curPatchp->dptr = op;
3703 curPatchp->fid.cell = scp->fid.cell;
3704 curPatchp->fid.volume = scp->fid.volume;
3705 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3706 curPatchp->fid.unique = ntohl(dep->fid.unique);
3708 /* do hidden attribute here since name won't be around when applying
3712 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3713 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3715 curPatchp->flags = 0;
3717 op += 9; /* skip attr, time, date and size */
3719 /* zero out name area. The spec says to pad with
3720 * spaces, but Samba doesn't, and neither do we.
3724 /* finally, we get to copy out the name; we know that
3725 * it fits in 8.3 or the pattern wouldn't match, but it
3726 * never hurts to be sure.
3728 strncpy(op, actualName, 13);
3730 /* Uppercase if requested by client */
3731 if ((((smb_t *)inp)->flg2 & 1) == 0)
3736 /* now, adjust the # of entries copied */
3738 } /* if we're including this name */
3741 /* and adjust curOffset to be where the new cookie is */
3742 thyper.HighPart = 0;
3743 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3744 curOffset = LargeIntegerAdd(thyper, curOffset);
3745 } /* while copying data for dir listing */
3747 /* release the mutex */
3748 lock_ReleaseMutex(&scp->mx);
3749 if (bufferp) buf_Release(bufferp);
3751 /* apply and free last set of patches; if not doing a star match, this
3752 * will be empty, but better safe (and freeing everything) than sorry.
3754 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3756 /* special return code for unsuccessful search */
3757 if (code == 0 && dataLength < 21 && returnedNames == 0)
3758 code = CM_ERROR_NOFILES;
3760 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3761 returnedNames, code);
3764 smb_DeleteDirSearch(dsp);
3765 smb_ReleaseDirSearch(dsp);
3766 cm_ReleaseSCache(scp);
3767 cm_ReleaseUser(userp);
3771 /* finalize the output buffer */
3772 smb_SetSMBParm(outp, 0, returnedNames);
3773 temp = (long) (op - origOp);
3774 smb_SetSMBDataLength(outp, temp);
3776 /* the data area is a variable block, which has a 5 (already there)
3777 * followed by the length of the # of data bytes. We now know this to
3778 * be "temp," although that includes the 3 bytes of vbl block header.
3779 * Deduct for them and fill in the length field.
3781 temp -= 3; /* deduct vbl block info */
3782 osi_assert(temp == (43 * returnedNames));
3783 origOp[1] = temp & 0xff;
3784 origOp[2] = (temp>>8) & 0xff;
3785 if (returnedNames == 0)
3786 smb_DeleteDirSearch(dsp);
3787 smb_ReleaseDirSearch(dsp);
3788 cm_ReleaseSCache(scp);
3789 cm_ReleaseUser(userp);
3793 /* verify that this is a valid path to a directory. I don't know why they
3794 * don't use the get file attributes call.
3796 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3800 cm_scache_t *rootScp;
3801 cm_scache_t *newScp;
3810 pathp = smb_GetSMBData(inp, NULL);
3811 pathp = smb_ParseASCIIBlock(pathp, NULL);
3812 osi_Log1(smb_logp, "SMB receive check path %s",
3813 osi_LogSaveString(smb_logp, pathp));
3816 return CM_ERROR_BADFD;
3819 rootScp = cm_rootSCachep;
3821 userp = smb_GetUser(vcp, inp);
3823 caseFold = CM_FLAG_CASEFOLD;
3825 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3827 cm_ReleaseUser(userp);
3828 return CM_ERROR_NOSUCHPATH;
3830 code = cm_NameI(rootScp, pathp,
3831 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3832 userp, tidPathp, &req, &newScp);
3835 cm_ReleaseUser(userp);
3839 /* now lock the vnode with a callback; returns with newScp locked */
3840 lock_ObtainMutex(&newScp->mx);
3841 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3842 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3843 if (code && code != CM_ERROR_NOACCESS) {
3844 lock_ReleaseMutex(&newScp->mx);
3845 cm_ReleaseSCache(newScp);
3846 cm_ReleaseUser(userp);
3850 attrs = smb_Attributes(newScp);
3852 if (!(attrs & 0x10))
3853 code = CM_ERROR_NOTDIR;
3855 lock_ReleaseMutex(&newScp->mx);
3857 cm_ReleaseSCache(newScp);
3858 cm_ReleaseUser(userp);
3862 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3866 cm_scache_t *rootScp;
3867 unsigned short attribute;
3869 cm_scache_t *newScp;
3878 /* decode basic attributes we're passed */
3879 attribute = smb_GetSMBParm(inp, 0);
3880 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3882 pathp = smb_GetSMBData(inp, NULL);
3883 pathp = smb_ParseASCIIBlock(pathp, NULL);
3886 return CM_ERROR_BADSMB;
3889 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3890 dosTime, attribute);
3892 rootScp = cm_rootSCachep;
3894 userp = smb_GetUser(vcp, inp);
3896 caseFold = CM_FLAG_CASEFOLD;
3898 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3900 cm_ReleaseUser(userp);
3901 return CM_ERROR_NOSUCHFILE;
3903 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3904 tidPathp, &req, &newScp);
3907 cm_ReleaseUser(userp);
3911 /* now lock the vnode with a callback; returns with newScp locked; we
3912 * need the current status to determine what the new status is, in some
3915 lock_ObtainMutex(&newScp->mx);
3916 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3917 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3919 lock_ReleaseMutex(&newScp->mx);
3920 cm_ReleaseSCache(newScp);
3921 cm_ReleaseUser(userp);
3925 /* Check for RO volume */
3926 if (newScp->flags & CM_SCACHEFLAG_RO) {
3927 lock_ReleaseMutex(&newScp->mx);
3928 cm_ReleaseSCache(newScp);
3929 cm_ReleaseUser(userp);
3930 return CM_ERROR_READONLY;
3933 /* prepare for setattr call */
3936 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3937 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3939 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3940 /* we're told to make a writable file read-only */
3941 attr.unixModeBits = newScp->unixModeBits & ~0222;
3942 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3944 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3945 /* we're told to make a read-only file writable */
3946 attr.unixModeBits = newScp->unixModeBits | 0222;
3947 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3949 lock_ReleaseMutex(&newScp->mx);
3951 /* now call setattr */
3953 code = cm_SetAttr(newScp, &attr, userp, &req);
3957 cm_ReleaseSCache(newScp);
3958 cm_ReleaseUser(userp);
3963 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3967 cm_scache_t *rootScp;
3968 cm_scache_t *newScp, *dscp;
3980 pathp = smb_GetSMBData(inp, NULL);
3981 pathp = smb_ParseASCIIBlock(pathp, NULL);
3984 return CM_ERROR_BADSMB;
3987 if (*pathp == 0) /* null path */
3990 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3991 osi_LogSaveString(smb_logp, pathp));
3993 rootScp = cm_rootSCachep;
3995 userp = smb_GetUser(vcp, inp);
3997 /* we shouldn't need this for V3 requests, but we seem to */
3998 caseFold = CM_FLAG_CASEFOLD;
4000 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4002 cm_ReleaseUser(userp);
4003 return CM_ERROR_NOSUCHFILE;
4007 * XXX Strange hack XXX
4009 * As of Patch 5 (16 July 97), we are having the following problem:
4010 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4011 * requests to look up "desktop.ini" in all the subdirectories.
4012 * This can cause zillions of timeouts looking up non-existent cells
4013 * and volumes, especially in the top-level directory.
4015 * We have not found any way to avoid this or work around it except
4016 * to explicitly ignore the requests for mount points that haven't
4017 * yet been evaluated and for directories that haven't yet been
4020 * We should modify this hack to provide a fake desktop.ini file
4021 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4023 spacep = inp->spacep;
4024 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4025 #ifndef SPECIAL_FOLDERS
4026 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4027 code = cm_NameI(rootScp, spacep->data,
4028 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4029 userp, tidPathp, &req, &dscp);
4031 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT &&
4032 !dscp->mountRootFidp)
4033 code = CM_ERROR_NOSUCHFILE;
4034 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4035 cm_buf_t *bp = buf_Find(dscp, &hzero);
4039 code = CM_ERROR_NOSUCHFILE;
4041 cm_ReleaseSCache(dscp);
4043 cm_ReleaseUser(userp);
4048 #endif /* SPECIAL_FOLDERS */
4050 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4051 tidPathp, &req, &newScp);
4053 cm_ReleaseUser(userp);
4057 /* now lock the vnode with a callback; returns with newScp locked */
4058 lock_ObtainMutex(&newScp->mx);
4059 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4060 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4062 lock_ReleaseMutex(&newScp->mx);
4063 cm_ReleaseSCache(newScp);
4064 cm_ReleaseUser(userp);
4069 /* use smb_Attributes instead. Also the fact that a file is
4070 * in a readonly volume doesn't mean it shojuld be marked as RO
4072 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4073 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4074 attrs = SMB_ATTR_DIRECTORY;
4077 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4078 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4080 attrs = smb_Attributes(newScp);
4083 smb_SetSMBParm(outp, 0, attrs);
4085 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4086 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4087 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4088 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4089 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4090 smb_SetSMBParm(outp, 5, 0);
4091 smb_SetSMBParm(outp, 6, 0);
4092 smb_SetSMBParm(outp, 7, 0);
4093 smb_SetSMBParm(outp, 8, 0);
4094 smb_SetSMBParm(outp, 9, 0);
4095 smb_SetSMBDataLength(outp, 0);
4096 lock_ReleaseMutex(&newScp->mx);
4098 cm_ReleaseSCache(newScp);
4099 cm_ReleaseUser(userp);
4104 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4108 osi_Log0(smb_logp, "SMB receive tree disconnect");
4110 /* find the tree and free it */
4111 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4113 lock_ObtainMutex(&tidp->mx);
4114 tidp->flags |= SMB_TIDFLAG_DELETE;
4115 lock_ReleaseMutex(&tidp->mx);
4116 smb_ReleaseTID(tidp);
4122 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4140 pathp = smb_GetSMBData(inp, NULL);
4141 pathp = smb_ParseASCIIBlock(pathp, NULL);
4143 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4145 #ifdef DEBUG_VERBOSE
4149 hexpath = osi_HexifyString( pathp );
4150 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4155 share = smb_GetSMBParm(inp, 0);
4156 attribute = smb_GetSMBParm(inp, 1);
4158 spacep = inp->spacep;
4159 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4160 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4161 /* special case magic file name for receiving IOCTL requests
4162 * (since IOCTL calls themselves aren't getting through).
4164 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4165 smb_SetupIoctlFid(fidp, spacep);
4166 smb_SetSMBParm(outp, 0, fidp->fid);
4167 smb_SetSMBParm(outp, 1, 0); /* attrs */
4168 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4169 smb_SetSMBParm(outp, 3, 0);
4170 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4171 smb_SetSMBParm(outp, 5, 0x7fff);
4172 /* pass the open mode back */
4173 smb_SetSMBParm(outp, 6, (share & 0xf));
4174 smb_SetSMBDataLength(outp, 0);
4175 smb_ReleaseFID(fidp);
4179 userp = smb_GetUser(vcp, inp);
4181 caseFold = CM_FLAG_CASEFOLD;
4183 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4185 cm_ReleaseUser(userp);
4186 return CM_ERROR_NOSUCHPATH;
4188 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4189 tidPathp, &req, &scp);
4192 cm_ReleaseUser(userp);
4196 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4198 cm_ReleaseSCache(scp);
4199 cm_ReleaseUser(userp);
4203 /* don't need callback to check file type, since file types never
4204 * change, and namei and cm_Lookup all stat the object at least once on
4205 * a successful return.
4207 if (scp->fileType != CM_SCACHETYPE_FILE) {
4208 cm_ReleaseSCache(scp);
4209 cm_ReleaseUser(userp);
4210 return CM_ERROR_ISDIR;
4213 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4216 /* save a pointer to the vnode */
4219 if ((share & 0xf) == 0)
4220 fidp->flags |= SMB_FID_OPENREAD;
4221 else if ((share & 0xf) == 1)
4222 fidp->flags |= SMB_FID_OPENWRITE;
4224 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4226 lock_ObtainMutex(&scp->mx);
4227 smb_SetSMBParm(outp, 0, fidp->fid);
4228 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4229 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4230 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4231 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4232 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4233 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4234 /* pass the open mode back; XXXX add access checks */
4235 smb_SetSMBParm(outp, 6, (share & 0xf));
4236 smb_SetSMBDataLength(outp, 0);
4237 lock_ReleaseMutex(&scp->mx);
4240 cm_Open(scp, 0, userp);
4242 /* send and free packet */
4243 smb_ReleaseFID(fidp);
4244 cm_ReleaseUser(userp);
4245 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4249 typedef struct smb_unlinkRock {
4254 char *maskp; /* pointer to the star pattern */
4259 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4262 smb_unlinkRock_t *rockp;
4270 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4271 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4272 caseFold |= CM_FLAG_8DOT3;
4274 matchName = dep->name;
4275 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4277 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4278 !cm_Is8Dot3(dep->name)) {
4279 cm_Gen8Dot3Name(dep, shortName, NULL);
4280 matchName = shortName;
4281 /* 8.3 matches are always case insensitive */
4282 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4285 osi_Log1(smb_logp, "Unlinking %s",
4286 osi_LogSaveString(smb_logp, matchName));
4287 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4288 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4289 smb_NotifyChange(FILE_ACTION_REMOVED,
4290 FILE_NOTIFY_CHANGE_FILE_NAME,
4291 dscp, dep->name, NULL, TRUE);
4295 /* If we made a case sensitive exact match, we might as well quit now. */
4296 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4297 code = CM_ERROR_STOPNOW;
4305 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4314 smb_unlinkRock_t rock;
4323 attribute = smb_GetSMBParm(inp, 0);
4325 tp = smb_GetSMBData(inp, NULL);
4326 pathp = smb_ParseASCIIBlock(tp, &tp);
4328 osi_Log1(smb_logp, "SMB receive unlink %s",
4329 osi_LogSaveString(smb_logp, pathp));
4331 spacep = inp->spacep;
4332 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4334 userp = smb_GetUser(vcp, inp);
4336 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4338 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4340 cm_ReleaseUser(userp);
4341 return CM_ERROR_NOSUCHPATH;
4343 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4347 cm_ReleaseUser(userp);
4351 /* otherwise, scp points to the parent directory. */
4358 rock.maskp = smb_FindMask(pathp);
4359 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4362 thyper.HighPart = 0;
4368 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4369 * match. If that fails, we do a case insensitve match.
4371 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4372 !smb_IsStarMask(rock.maskp)) {
4373 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4376 thyper.HighPart = 0;
4377 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4382 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4384 if (code == CM_ERROR_STOPNOW)
4387 cm_ReleaseUser(userp);
4389 cm_ReleaseSCache(dscp);
4391 if (code == 0 && !rock.any)
4392 code = CM_ERROR_NOSUCHFILE;
4396 typedef struct smb_renameRock {
4397 cm_scache_t *odscp; /* old dir */
4398 cm_scache_t *ndscp; /* new dir */
4399 cm_user_t *userp; /* user */
4400 cm_req_t *reqp; /* request struct */
4401 smb_vc_t *vcp; /* virtual circuit */
4402 char *maskp; /* pointer to star pattern of old file name */
4403 int flags; /* tilde, casefold, etc */
4404 char *newNamep; /* ptr to the new file's name */
4407 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4410 smb_renameRock_t *rockp;
4415 rockp = (smb_renameRock_t *) vrockp;
4417 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4418 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4419 caseFold |= CM_FLAG_8DOT3;
4421 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4423 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4424 !cm_Is8Dot3(dep->name)) {
4425 cm_Gen8Dot3Name(dep, shortName, NULL);
4426 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4429 code = cm_Rename(rockp->odscp, dep->name,
4430 rockp->ndscp, rockp->newNamep, rockp->userp,