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 DWORD NCBsessions[NCBmax];
100 struct smb_packet *bufs[NCBmax];
102 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
103 EVENT_HANDLE SessionEvents[Sessionmax];
104 unsigned short LSNs[Sessionmax];
105 int lanas[Sessionmax];
106 BOOL dead_sessions[Sessionmax];
110 osi_mutex_t smb_RawBufLock;
112 #define SMB_RAW_BUFS 4
114 int smb_RawBufSel[SMB_RAW_BUFS];
119 #define SMB_MASKFLAG_TILDE 1
120 #define SMB_MASKFLAG_CASEFOLD 2
122 #define RAWTIMEOUT INFINITE
125 typedef struct raw_write_cont {
138 /* dir search stuff */
139 long smb_dirSearchCounter = 1;
140 smb_dirSearch_t *smb_firstDirSearchp;
141 smb_dirSearch_t *smb_lastDirSearchp;
143 /* hide dot files? */
144 int smb_hideDotFiles;
146 /* global state about V3 protocols */
147 int smb_useV3; /* try to negotiate V3 */
150 static showErrors = 1;
151 /* MessageBox or something like it */
152 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
153 extern HANDLE WaitToTerminate;
157 * Time in Unix format of midnight, 1/1/1970 local time.
158 * When added to dosUTime, gives Unix (AFS) time.
160 long smb_localZero = 0;
162 /* Time difference for converting to kludge-GMT */
165 char *smb_localNamep = NULL;
167 smb_vc_t *smb_allVCsp;
169 smb_username_t *usernamesp = NULL;
171 smb_waitingLock_t *smb_allWaitingLocks;
174 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
175 NCB *ncbp, raw_write_cont_t *rwcp);
176 void smb_NetbiosInit();
178 #ifndef AFS_WIN95_ENV
179 DWORD smb_ServerExceptionFilter(void);
182 extern char cm_HostName[];
183 extern char cm_confDir[];
187 #define LPTSTR char *
188 #define GetComputerName(str, sizep) \
189 strcpy((str), cm_HostName); \
190 *(sizep) = strlen(cm_HostName)
194 void smb_LogPacket(smb_packet_t *packet);
195 #endif /* LOG_PACKET */
196 extern char AFSConfigKeyName[];
198 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
199 int smb_ServerDomainNameLength = 0;
200 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
201 int smb_ServerOSLength = sizeof(smb_ServerOS);
202 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
203 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
205 /* Faux server GUID. This is never checked. */
206 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
211 * To build an expiring version, comment out the definition of NOEXPIRE,
212 * and set the definition of EXPIREDATE to the desired value.
215 #define EXPIREDATE 834000000 /* Wed Jun 5 1996 */
218 char * myCrt_Dispatch(int i)
223 return "(00)ReceiveCoreMakeDir";
225 return "(01)ReceiveCoreRemoveDir";
227 return "(02)ReceiveCoreOpen";
229 return "(03)ReceiveCoreCreate";
231 return "(04)ReceiveCoreClose";
233 return "(05)ReceiveCoreFlush";
235 return "(06)ReceiveCoreUnlink";
237 return "(07)ReceiveCoreRename";
239 return "(08)ReceiveCoreGetFileAttributes";
241 return "(09)ReceiveCoreSetFileAttributes";
243 return "(0a)ReceiveCoreRead";
245 return "(0b)ReceiveCoreWrite";
247 return "(0c)ReceiveCoreLockRecord";
249 return "(0d)ReceiveCoreUnlockRecord";
251 return "(0e)SendCoreBadOp";
253 return "(0f)ReceiveCoreCreate";
255 return "(10)ReceiveCoreCheckPath";
257 return "(11)SendCoreBadOp";
259 return "(12)ReceiveCoreSeek";
261 return "(1a)ReceiveCoreReadRaw";
263 return "(1d)ReceiveCoreWriteRawDummy";
265 return "(22)ReceiveV3SetAttributes";
267 return "(23)ReceiveV3GetAttributes";
269 return "(24)ReceiveV3LockingX";
271 return "(25)ReceiveV3Trans";
273 return "(26)ReceiveV3Trans[aux]";
275 return "(29)SendCoreBadOp";
277 return "(2b)ReceiveCoreEcho";
279 return "(2d)ReceiveV3OpenX";
281 return "(2e)ReceiveV3ReadX";
283 return "(32)ReceiveV3Tran2A";
285 return "(33)ReceiveV3Tran2A[aux]";
287 return "(34)ReceiveV3FindClose";
289 return "(35)ReceiveV3FindNotifyClose";
291 return "(70)ReceiveCoreTreeConnect";
293 return "(71)ReceiveCoreTreeDisconnect";
295 return "(72)ReceiveNegotiate";
297 return "(73)ReceiveV3SessionSetupX";
299 return "(74)ReceiveV3UserLogoffX";
301 return "(75)ReceiveV3TreeConnectX";
303 return "(80)ReceiveCoreGetDiskAttributes";
305 return "(81)ReceiveCoreSearchDir";
309 return "(83)FindUnique";
311 return "(84)FindClose";
313 return "(A0)ReceiveNTTransact";
315 return "(A2)ReceiveNTCreateX";
317 return "(A4)ReceiveNTCancel";
319 return "(A5)ReceiveNTRename";
321 return "(C0)OpenPrintFile";
323 return "(C1)WritePrintFile";
325 return "(C2)ClosePrintFile";
327 return "(C3)GetPrintQueue";
329 return "(D8)ReadBulk";
331 return "(D9)WriteBulk";
333 return "(DA)WriteBulkData";
335 return "unknown SMB op";
339 char * myCrt_2Dispatch(int i)
344 return "unknown SMB op-2";
346 return "S(00)CreateFile";
348 return "S(01)FindFirst";
350 return "S(02)FindNext"; /* FindNext */
352 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
356 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
358 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
360 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
362 return "S(08)??_ReceiveTran2SetFileInfo";
364 return "S(09)??_ReceiveTran2FSCTL";
366 return "S(0a)_ReceiveTran2IOCTL";
368 return "S(0b)_ReceiveTran2FindNotifyFirst";
370 return "S(0c)_ReceiveTran2FindNotifyNext";
372 return "S(0d)_ReceiveTran2CreateDirectory";
374 return "S(0e)_ReceiveTran2SessionSetup";
378 char * myCrt_RapDispatch(int i)
383 return "unknown RAP OP";
385 return "RAP(0)NetShareEnum";
387 return "RAP(1)NetShareGetInfo";
389 return "RAP(13)NetServerGetInfo";
391 return "RAP(63)NetWkStaGetInfo";
395 /* scache must be locked */
396 unsigned int smb_Attributes(cm_scache_t *scp)
400 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
401 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
402 attrs = SMB_ATTR_DIRECTORY;
407 * We used to mark a file RO if it was in an RO volume, but that
408 * turns out to be impolitic in NT. See defect 10007.
411 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
413 if ((scp->unixModeBits & 0222) == 0)
414 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
419 /* Check if the named file/dir is a dotfile/dotdir */
420 /* String pointed to by lastComp can have leading slashes, but otherwise should have
421 no other patch components */
422 unsigned int smb_IsDotFile(char *lastComp) {
425 /* skip over slashes */
426 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
431 /* nulls, curdir and parent dir doesn't count */
434 if(!*(s + 1)) return 0;
435 if(*(s+1) == '.' && !*(s + 2)) return 0;
441 static int ExtractBits(WORD bits, short start, short len)
448 num = bits << (16 - end);
449 num = num >> ((16 - end) + start);
455 void ShowUnixTime(char *FuncName, time_t unixTime)
460 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
462 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
463 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
465 int day, month, year, sec, min, hour;
468 day = ExtractBits(wDate, 0, 5);
469 month = ExtractBits(wDate, 5, 4);
470 year = ExtractBits(wDate, 9, 7) + 1980;
472 sec = ExtractBits(wTime, 0, 5);
473 min = ExtractBits(wTime, 5, 6);
474 hour = ExtractBits(wTime, 11, 5);
476 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
477 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
483 /* Determine if we are observing daylight savings time */
484 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
486 TIME_ZONE_INFORMATION timeZoneInformation;
487 SYSTEMTIME utc, local, localDST;
489 /* Get the time zone info. NT uses this to calc if we are in DST. */
490 GetTimeZoneInformation(&timeZoneInformation);
492 /* Return the daylight bias */
493 *pDstBias = timeZoneInformation.DaylightBias;
495 /* Return the bias */
496 *pBias = timeZoneInformation.Bias;
498 /* Now determine if DST is being observed */
500 /* Get the UTC (GMT) time */
503 /* Convert UTC time to local time using the time zone info. If we are
504 observing DST, the calculated local time will include this.
506 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
508 /* Set the daylight bias to 0. The daylight bias is the amount of change
509 in time that we use for daylight savings time. By setting this to 0
510 we cause there to be no change in time during daylight savings time.
512 timeZoneInformation.DaylightBias = 0;
514 /* Convert the utc time to local time again, but this time without any
515 adjustment for daylight savings time.
517 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
519 /* If the two times are different, then it means that the localDST that
520 we calculated includes the daylight bias, and therefore we are
521 observing daylight savings time.
523 *pDST = localDST.wHour != local.wHour;
526 /* Determine if we are observing daylight savings time */
527 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
533 *pDstBias = -60; /* where can this be different? */
539 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
541 BOOL dst; /* Will be TRUE if observing DST */
542 LONG dstBias; /* Offset from local time if observing DST */
543 LONG bias; /* Offset from GMT for local time */
546 * This function will adjust the last write time to compensate
547 * for two bugs in the smb client:
549 * 1) During Daylight Savings Time, the LastWriteTime is ahead
550 * in time by the DaylightBias (ignoring the sign - the
551 * DaylightBias is always stored as a negative number). If
552 * the DaylightBias is -60, then the LastWriteTime will be
553 * ahead by 60 minutes.
555 * 2) If the local time zone is a positive offset from GMT, then
556 * the LastWriteTime will be the correct local time plus the
557 * Bias (ignoring the sign - a positive offset from GMT is
558 * always stored as a negative Bias). If the Bias is -120,
559 * then the LastWriteTime will be ahead by 120 minutes.
561 * These bugs can occur at the same time.
564 GetTimeZoneInfo(&dst, &dstBias, &bias);
566 /* First adjust for DST */
568 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
570 /* Now adjust for a positive offset from GMT (a negative bias). */
572 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
576 * Calculate the difference (in seconds) between local time and GMT.
577 * This enables us to convert file times to kludge-GMT.
583 struct tm gmt_tm, local_tm;
584 int days, hours, minutes, seconds;
587 gmt_tm = *(gmtime(&t));
588 local_tm = *(localtime(&t));
590 days = local_tm.tm_yday - gmt_tm.tm_yday;
591 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
593 /* There is a problem with DST immediately after the time change
594 * which may continue to exist until the machine is rebooted
596 - (local_tm.tm_isdst ? 1 : 0)
599 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
600 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
606 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
611 time_t ersatz_unixTime;
614 * Must use kludge-GMT instead of real GMT.
615 * kludge-GMT is computed by adding time zone difference to localtime.
618 * ltp = gmtime(&unixTime);
620 ersatz_unixTime = unixTime - smb_NowTZ;
621 ltp = localtime(&ersatz_unixTime);
623 /* if we fail, make up something */
626 localJunk.tm_year = 89 - 20;
627 localJunk.tm_mon = 4;
628 localJunk.tm_mday = 12;
629 localJunk.tm_hour = 0;
630 localJunk.tm_min = 0;
631 localJunk.tm_sec = 0;
634 stm.wYear = ltp->tm_year + 1900;
635 stm.wMonth = ltp->tm_mon + 1;
636 stm.wDayOfWeek = ltp->tm_wday;
637 stm.wDay = ltp->tm_mday;
638 stm.wHour = ltp->tm_hour;
639 stm.wMinute = ltp->tm_min;
640 stm.wSecond = ltp->tm_sec;
641 stm.wMilliseconds = 0;
643 SystemTimeToFileTime(&stm, largeTimep);
646 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
648 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
649 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
650 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
652 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
654 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
655 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
657 *ft = LargeIntegerMultiplyByLong(*ft, 60);
658 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
661 ut = ConvertLongToLargeInteger(unixTime);
662 ut = LargeIntegerMultiplyByLong(ut, 10000000);
663 *ft = LargeIntegerAdd(*ft, ut);
668 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
674 FileTimeToSystemTime(largeTimep, &stm);
676 lt.tm_year = stm.wYear - 1900;
677 lt.tm_mon = stm.wMonth - 1;
678 lt.tm_wday = stm.wDayOfWeek;
679 lt.tm_mday = stm.wDay;
680 lt.tm_hour = stm.wHour;
681 lt.tm_min = stm.wMinute;
682 lt.tm_sec = stm.wSecond;
685 save_timezone = _timezone;
686 _timezone += smb_NowTZ;
687 *unixTimep = mktime(<);
688 _timezone = save_timezone;
691 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
693 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
694 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
695 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
699 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
700 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
701 a = LargeIntegerMultiplyByLong(a, 60);
702 a = LargeIntegerMultiplyByLong(a, 10000000);
704 /* subtract it from ft */
705 a = LargeIntegerSubtract(*ft, a);
707 /* divide down to seconds */
708 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
712 void smb_SearchTimeFromUnixTime(long *dosTimep, time_t unixTime)
720 ltp = localtime((time_t*) &t);
722 /* if we fail, make up something */
725 localJunk.tm_year = 89 - 20;
726 localJunk.tm_mon = 4;
727 localJunk.tm_mday = 12;
728 localJunk.tm_hour = 0;
729 localJunk.tm_min = 0;
730 localJunk.tm_sec = 0;
733 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
734 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
735 *dosTimep = (dosDate<<16) | dosTime;
738 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
740 unsigned short dosDate;
741 unsigned short dosTime;
744 dosDate = searchTime & 0xffff;
745 dosTime = (searchTime >> 16) & 0xffff;
747 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
748 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
749 localTm.tm_mday = (dosDate) & 0x1f;
750 localTm.tm_hour = (dosTime>>11) & 0x1f;
751 localTm.tm_min = (dosTime >> 5) & 0x3f;
752 localTm.tm_sec = (dosTime & 0x1f) * 2;
753 localTm.tm_isdst = -1; /* compute whether DST in effect */
755 *unixTimep = mktime(&localTm);
758 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
760 *dosUTimep = unixTime - smb_localZero;
763 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
766 *unixTimep = dosTime + smb_localZero;
768 /* dosTime seems to be already adjusted for GMT */
769 *unixTimep = dosTime;
773 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
777 lock_ObtainWrite(&smb_rctLock);
778 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
779 if (lsn == vcp->lsn && lana == vcp->lana) {
784 if (!vcp && (flags & SMB_FLAG_CREATE)) {
785 vcp = malloc(sizeof(*vcp));
786 memset(vcp, 0, sizeof(*vcp));
787 vcp->vcID = numVCs++;
791 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
792 vcp->nextp = smb_allVCsp;
794 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
799 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
800 /* We must obtain a challenge for extended auth
801 * in case the client negotiates smb v3
804 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
805 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
808 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
810 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
817 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
819 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
820 LsaFreeReturnBuffer(lsaResp);
823 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
825 lock_ReleaseWrite(&smb_rctLock);
829 int smb_IsStarMask(char *maskp)
834 for(i=0; i<11; i++) {
836 if (tc == '?' || tc == '*' || tc == '>') return 1;
841 void smb_ReleaseVC(smb_vc_t *vcp)
843 lock_ObtainWrite(&smb_rctLock);
844 osi_assert(vcp->refCount-- > 0);
845 lock_ReleaseWrite(&smb_rctLock);
848 void smb_HoldVC(smb_vc_t *vcp)
850 lock_ObtainWrite(&smb_rctLock);
852 lock_ReleaseWrite(&smb_rctLock);
855 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
859 lock_ObtainWrite(&smb_rctLock);
860 for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
861 if (tid == tidp->tid) {
866 if (!tidp && (flags & SMB_FLAG_CREATE)) {
867 tidp = malloc(sizeof(*tidp));
868 memset(tidp, 0, sizeof(*tidp));
869 tidp->nextp = vcp->tidsp;
874 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
877 lock_ReleaseWrite(&smb_rctLock);
881 void smb_ReleaseTID(smb_tid_t *tidp)
890 lock_ObtainWrite(&smb_rctLock);
891 osi_assert(tidp->refCount-- > 0);
892 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
893 ltpp = &tidp->vcp->tidsp;
894 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
895 if (tp == tidp) break;
897 osi_assert(tp != NULL);
899 lock_FinalizeMutex(&tidp->mx);
900 userp = tidp->userp; /* remember to drop ref later */
903 lock_ReleaseWrite(&smb_rctLock);
905 cm_ReleaseUser(userp);
912 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
914 smb_user_t *uidp = NULL;
916 lock_ObtainWrite(&smb_rctLock);
917 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
918 if (uid == uidp->userID) {
920 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
921 (int)vcp, uidp->userID,
922 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
926 if (!uidp && (flags & SMB_FLAG_CREATE)) {
927 uidp = malloc(sizeof(*uidp));
928 memset(uidp, 0, sizeof(*uidp));
929 uidp->nextp = vcp->usersp;
934 lock_InitializeMutex(&uidp->mx, "user_t mutex");
936 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 : ""));
938 lock_ReleaseWrite(&smb_rctLock);
942 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
944 smb_username_t *unp= NULL;
946 lock_ObtainWrite(&smb_rctLock);
947 for(unp = usernamesp; unp; unp = unp->nextp) {
948 if (stricmp(unp->name, usern) == 0 &&
949 stricmp(unp->machine, machine) == 0) {
954 if (!unp && (flags & SMB_FLAG_CREATE)) {
955 unp = malloc(sizeof(*unp));
956 memset(unp, 0, sizeof(*unp));
958 unp->nextp = usernamesp;
959 unp->name = strdup(usern);
960 unp->machine = strdup(machine);
962 lock_InitializeMutex(&unp->mx, "username_t mutex");
964 lock_ReleaseWrite(&smb_rctLock);
968 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
970 smb_user_t *uidp= NULL;
972 lock_ObtainWrite(&smb_rctLock);
973 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
976 if (stricmp(uidp->unp->name, usern) == 0) {
978 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
983 lock_ReleaseWrite(&smb_rctLock);
986 void smb_ReleaseUID(smb_user_t *uidp)
995 lock_ObtainWrite(&smb_rctLock);
996 osi_assert(uidp->refCount-- > 0);
997 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
998 lupp = &uidp->vcp->usersp;
999 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1000 if (up == uidp) break;
1002 osi_assert(up != NULL);
1004 lock_FinalizeMutex(&uidp->mx);
1006 userp = uidp->unp->userp; /* remember to drop ref later */
1007 uidp->unp->userp = NULL;
1012 lock_ReleaseWrite(&smb_rctLock);
1014 cm_ReleaseUserVCRef(userp);
1015 cm_ReleaseUser(userp);
1022 /* retrieve a held reference to a user structure corresponding to an incoming
1024 * corresponding release function is cm_ReleaseUser.
1026 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1032 smbp = (smb_t *) inp;
1033 uidp = smb_FindUID(vcp, smbp->uid, 0);
1034 if ((!uidp) || (!uidp->unp))
1037 lock_ObtainMutex(&uidp->mx);
1038 up = uidp->unp->userp;
1040 lock_ReleaseMutex(&uidp->mx);
1042 smb_ReleaseUID(uidp);
1048 * Return a pointer to a pathname extracted from a TID structure. The
1049 * TID structure is not held; assume it won't go away.
1051 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1056 tidp = smb_FindTID(vcp, tid, 0);
1060 if(tidp->flags & SMB_TIDFLAG_IPC) {
1061 code = CM_ERROR_TIDIPC;
1062 /* tidp->pathname would be NULL, but that's fine */
1064 *treepath = tidp->pathname;
1065 smb_ReleaseTID(tidp);
1070 /* check to see if we have a chained fid, that is, a fid that comes from an
1071 * OpenAndX message that ran earlier in this packet. In this case, the fid
1072 * field in a read, for example, request, isn't set, since the value is
1073 * supposed to be inherited from the openAndX call.
1075 int smb_ChainFID(int fid, smb_packet_t *inp)
1077 if (inp->fid == 0 || inp->inCount == 0)
1083 /* are we a priv'd user? What does this mean on NT? */
1084 int smb_SUser(cm_user_t *userp)
1089 /* find a file ID. If we pass in 0 we select an used File ID.
1090 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1091 * smb_fid_t data structure if desired File ID cannot be found.
1093 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1098 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1101 lock_ObtainWrite(&smb_rctLock);
1102 /* figure out if we need to allocate a new file ID */
1105 fid = vcp->fidCounter;
1109 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1110 if (fid == fidp->fid) {
1121 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1122 char eventName[MAX_PATH];
1124 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1125 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1126 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1127 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1128 thrd_CloseHandle(event);
1135 fidp = malloc(sizeof(*fidp));
1136 memset(fidp, 0, sizeof(*fidp));
1137 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1141 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1143 fidp->curr_chunk = fidp->prev_chunk = -2;
1144 fidp->raw_write_event = event;
1146 vcp->fidCounter = fid+1;
1147 if (vcp->fidCounter == 0)
1148 vcp->fidCounter = 1;
1151 lock_ReleaseWrite(&smb_rctLock);
1155 void smb_ReleaseFID(smb_fid_t *fidp)
1158 smb_vc_t *vcp = NULL;
1159 smb_ioctl_t *ioctlp;
1165 lock_ObtainWrite(&smb_rctLock);
1166 osi_assert(fidp->refCount-- > 0);
1167 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1169 if (!(fidp->flags & SMB_FID_IOCTL))
1171 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1172 thrd_CloseHandle(fidp->raw_write_event);
1174 /* and see if there is ioctl stuff to free */
1175 ioctlp = fidp->ioctlp;
1177 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1178 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1179 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1185 /* do not call smb_ReleaseVC() because we already have the lock */
1188 lock_ReleaseWrite(&smb_rctLock);
1190 /* now release the scache structure */
1192 cm_ReleaseSCache(scp);
1196 * Case-insensitive search for one string in another;
1197 * used to find variable names in submount pathnames.
1199 static char *smb_stristr(char *str1, char *str2)
1203 for (cursor = str1; *cursor; cursor++)
1204 if (stricmp(cursor, str2) == 0)
1211 * Substitute a variable value for its name in a submount pathname. Variable
1212 * name has been identified by smb_stristr() and is in substr. Variable name
1213 * length (plus one) is in substr_size. Variable value is in newstr.
1215 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1220 strcpy(temp, substr + substr_size - 1);
1221 strcpy(substr, newstr);
1225 char VNUserName[] = "%USERNAME%";
1226 char VNLCUserName[] = "%LCUSERNAME%";
1227 char VNComputerName[] = "%COMPUTERNAME%";
1228 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1231 /* List available shares */
1232 int smb_ListShares()
1236 char shareBuf[4096];
1244 /*strcpy(shareNameList[num_shares], "all");
1245 strcpy(pathNameList[num_shares++], "/afs");*/
1246 fprintf(stderr, "The following shares are available:\n");
1247 fprintf(stderr, "Share Name (AFS Path)\n");
1248 fprintf(stderr, "---------------------\n");
1249 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1252 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1253 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1255 strcpy(sbmtpath, cm_confDir);
1257 strcat(sbmtpath, "/afsdsbmt.ini");
1258 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1259 shareBuf, sizeof(shareBuf),
1265 this_share = shareBuf;
1269 /*strcpy(shareNameList[num_shares], this_share);*/
1270 len = GetPrivateProfileString("AFS Submounts", this_share,
1277 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1280 if (*p == '\\') *p = '/'; /* change to / */
1284 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1285 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1288 while (*this_share != 0) this_share++; /* find next NUL */
1289 this_share++; /* skip past the NUL */
1290 } while (*this_share != 0); /* stop at final NUL */
1296 typedef struct smb_findShare_rock {
1300 } smb_findShare_rock_t;
1302 #define SMB_FINDSHARE_EXACT_MATCH 1
1303 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1305 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1309 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1310 if(!strnicmp(dep->name, vrock->shareName, 12)) {
1311 if(!stricmp(dep->name, vrock->shareName))
1312 matchType = SMB_FINDSHARE_EXACT_MATCH;
1314 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1315 if(vrock->match) free(vrock->match);
1316 vrock->match = strdup(dep->name);
1317 vrock->matchType = matchType;
1319 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1320 return CM_ERROR_STOPNOW;
1326 /* find a shareName in the table of submounts */
1327 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1331 char pathName[1024];
1336 char sbmtpath[MAX_PATH];
1341 DWORD allSubmount = 1;
1343 /* if allSubmounts == 0, only return the //mountRoot/all share
1344 * if in fact it has been been created in the subMounts table.
1345 * This is to allow sites that want to restrict access to the
1348 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1349 0, KEY_QUERY_VALUE, &parmKey);
1350 if (code == ERROR_SUCCESS) {
1351 len = sizeof(allSubmount);
1352 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1353 (BYTE *) &allSubmount, &len);
1354 if (code != ERROR_SUCCESS) {
1357 RegCloseKey (parmKey);
1360 if (allSubmount && _stricmp(shareName, "all") == 0) {
1365 /* In case, the all share is disabled we need to still be able
1366 * to handle ioctl requests
1368 if (_stricmp(shareName, "ioctl$") == 0) {
1369 *pathNamep = strdup("/.__ioctl__");
1373 if (_stricmp(shareName, "IPC$") == 0 ||
1374 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1375 _stricmp(shareName, "DESKTOP.INI") == 0
1382 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1383 0, KEY_QUERY_VALUE, &parmKey);
1384 if (code == ERROR_SUCCESS) {
1385 len = sizeof(pathName);
1386 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1387 (BYTE *) pathName, &len);
1388 if (code != ERROR_SUCCESS)
1390 RegCloseKey (parmKey);
1395 strcpy(sbmtpath, cm_confDir);
1396 strcat(sbmtpath, "/afsdsbmt.ini");
1397 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1398 pathName, sizeof(pathName), sbmtpath);
1400 if (len != 0 && len != sizeof(pathName) - 1) {
1401 /* We can accept either unix or PC style AFS pathnames. Convert
1402 * Unix-style to PC style here for internal use.
1405 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1406 p += strlen(cm_mountRoot); /* skip mount path */
1409 if (*q == '/') *q = '\\'; /* change to \ */
1415 if (var = smb_stristr(p, VNUserName)) {
1416 if (uidp && uidp->unp)
1417 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1419 smb_subst(p, var, sizeof(VNUserName)," ");
1421 else if (var = smb_stristr(p, VNLCUserName))
1423 if (uidp && uidp->unp)
1424 strcpy(temp, uidp->unp->name);
1428 smb_subst(p, var, sizeof(VNLCUserName), temp);
1430 else if (var = smb_stristr(p, VNComputerName))
1432 sizeTemp = sizeof(temp);
1433 GetComputerName((LPTSTR)temp, &sizeTemp);
1434 smb_subst(p, var, sizeof(VNComputerName), temp);
1436 else if (var = smb_stristr(p, VNLCComputerName))
1438 sizeTemp = sizeof(temp);
1439 GetComputerName((LPTSTR)temp, &sizeTemp);
1441 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1446 *pathNamep = strdup(p);
1451 /* First lookup shareName in root.afs */
1453 smb_findShare_rock_t vrock;
1455 char * p = shareName;
1458 /* attempt to locate a partial match in root.afs. This is because
1459 when using the ANSI RAP calls, the share name is limited to 13 chars
1460 and hence is truncated. Of course we prefer exact matches. */
1462 thyper.HighPart = 0;
1465 vrock.shareName = shareName;
1467 vrock.matchType = 0;
1469 cm_HoldSCache(cm_rootSCachep);
1470 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1471 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1472 cm_ReleaseSCache(cm_rootSCachep);
1474 if(vrock.matchType) {
1475 sprintf(pathName,"/%s/",vrock.match);
1476 *pathNamep = strdup(strlwr(pathName));
1481 /* if we get here, there was no match for the share in root.afs */
1482 /* so try to create \\<netbiosName>\<cellname> */
1487 /* Get the full name for this cell */
1488 code = cm_SearchCellFile(p, temp, 0, 0);
1489 #ifdef AFS_AFSDB_ENV
1490 if (code && cm_dnsEnabled) {
1492 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1495 /* construct the path */
1497 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1498 *pathNamep = strdup(strlwr(pathName));
1507 /* Client-side offline caching policy types */
1508 #define CSC_POLICY_MANUAL 0
1509 #define CSC_POLICY_DOCUMENTS 1
1510 #define CSC_POLICY_PROGRAMS 2
1511 #define CSC_POLICY_DISABLE 3
1513 int smb_FindShareCSCPolicy(char *shareName)
1519 int retval = CSC_POLICY_MANUAL;
1521 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1522 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1525 REG_OPTION_NON_VOLATILE,
1531 len = sizeof(policy);
1532 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1534 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1536 else if (stricmp(policy, "documents") == 0)
1538 retval = CSC_POLICY_DOCUMENTS;
1540 else if (stricmp(policy, "programs") == 0)
1542 retval = CSC_POLICY_PROGRAMS;
1544 else if (stricmp(policy, "disable") == 0)
1546 retval = CSC_POLICY_DISABLE;
1549 RegCloseKey(hkCSCPolicy);
1553 /* find a dir search structure by cookie value, and return it held.
1554 * Must be called with smb_globalLock held.
1556 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1558 smb_dirSearch_t *dsp;
1560 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1561 if (dsp->cookie == cookie) {
1562 if (dsp != smb_firstDirSearchp) {
1563 /* move to head of LRU queue, too, if we're not already there */
1564 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1565 smb_lastDirSearchp = (smb_dirSearch_t *)
1567 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1568 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1569 if (!smb_lastDirSearchp)
1570 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1579 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1581 lock_ObtainWrite(&smb_globalLock);
1582 dsp->flags |= SMB_DIRSEARCH_DELETE;
1583 lock_ReleaseWrite(&smb_globalLock);
1584 lock_ObtainMutex(&dsp->mx);
1585 if(dsp->scp != NULL) {
1586 lock_ObtainMutex(&dsp->scp->mx);
1587 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1588 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1589 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1590 dsp->scp->bulkStatProgress = hones;
1592 lock_ReleaseMutex(&dsp->scp->mx);
1594 lock_ReleaseMutex(&dsp->mx);
1597 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1603 lock_ObtainWrite(&smb_globalLock);
1604 osi_assert(dsp->refCount-- > 0);
1605 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1606 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1607 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1608 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1609 lock_FinalizeMutex(&dsp->mx);
1613 lock_ReleaseWrite(&smb_globalLock);
1615 /* do this now to avoid spurious locking hierarchy creation */
1616 if (scp) cm_ReleaseSCache(scp);
1619 /* find a dir search structure by cookie value, and return it held */
1620 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1622 smb_dirSearch_t *dsp;
1624 lock_ObtainWrite(&smb_globalLock);
1625 dsp = smb_FindDirSearchNL(cookie);
1626 lock_ReleaseWrite(&smb_globalLock);
1630 /* GC some dir search entries, in the address space expected by the specific protocol.
1631 * Must be called with smb_globalLock held; release the lock temporarily.
1633 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1634 void smb_GCDirSearches(int isV3)
1636 smb_dirSearch_t *prevp;
1637 smb_dirSearch_t *tp;
1638 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1642 victimCount = 0; /* how many have we got so far */
1643 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1644 /* we'll move tp from queue, so
1647 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1648 /* if no one is using this guy, and we're either in the new protocol,
1649 * or we're in the old one and this is a small enough ID to be useful
1650 * to the old protocol, GC this guy.
1652 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1653 /* hold and delete */
1654 tp->flags |= SMB_DIRSEARCH_DELETE;
1655 victimsp[victimCount++] = tp;
1659 /* don't do more than this */
1660 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1663 /* now release them */
1664 lock_ReleaseWrite(&smb_globalLock);
1665 for(i = 0; i < victimCount; i++) {
1666 smb_ReleaseDirSearch(victimsp[i]);
1668 lock_ObtainWrite(&smb_globalLock);
1671 /* function for allocating a dir search entry. We need these to remember enough context
1672 * since we don't get passed the path from call to call during a directory search.
1674 * Returns a held dir search structure, and bumps the reference count on the vnode,
1675 * since it saves a pointer to the vnode.
1677 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1679 smb_dirSearch_t *dsp;
1683 lock_ObtainWrite(&smb_globalLock);
1686 /* what's the biggest ID allowed in this version of the protocol */
1687 if (isV3) maxAllowed = 65535;
1688 else maxAllowed = 255;
1691 /* twice so we have enough tries to find guys we GC after one pass;
1692 * 10 extra is just in case I mis-counted.
1694 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1695 __FILE__, __LINE__);
1696 if (smb_dirSearchCounter > maxAllowed) {
1697 smb_dirSearchCounter = 1;
1698 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1700 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1702 /* don't need to watch for refcount zero and deleted, since
1703 * we haven't dropped the global lock.
1706 ++smb_dirSearchCounter;
1710 dsp = malloc(sizeof(*dsp));
1711 memset(dsp, 0, sizeof(*dsp));
1712 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1713 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1714 dsp->cookie = smb_dirSearchCounter;
1715 ++smb_dirSearchCounter;
1717 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1718 dsp->lastTime = osi_Time();
1721 lock_ReleaseWrite(&smb_globalLock);
1725 static smb_packet_t *GetPacket(void)
1729 unsigned int npar, seg, tb_sel;
1732 lock_ObtainWrite(&smb_globalLock);
1733 tbp = smb_packetFreeListp;
1735 smb_packetFreeListp = tbp->nextp;
1736 lock_ReleaseWrite(&smb_globalLock);
1739 tbp = calloc(65540,1);
1741 tbp = malloc(sizeof(smb_packet_t));
1743 tbp->magic = SMB_PACKETMAGIC;
1746 tbp->resumeCode = 0;
1752 tbp->ncb_length = 0;
1757 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1760 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1762 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1764 osi_panic("",__FILE__,__LINE__);
1767 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1772 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1773 tbp->dos_pkt_sel = tb_sel;
1776 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1781 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1785 memcpy(tbp, pkt, sizeof(smb_packet_t));
1786 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1790 static NCB *GetNCB(void)
1795 unsigned int npar, seg, tb_sel;
1798 lock_ObtainWrite(&smb_globalLock);
1799 tbp = smb_ncbFreeListp;
1801 smb_ncbFreeListp = tbp->nextp;
1802 lock_ReleaseWrite(&smb_globalLock);
1805 tbp = calloc(sizeof(*tbp),1);
1807 tbp = malloc(sizeof(*tbp));
1808 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1811 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1813 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1815 osi_panic("",__FILE__,__LINE__);
1817 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1822 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1823 tbp->dos_ncb_sel = tb_sel;
1825 tbp->magic = SMB_NCBMAGIC;
1828 osi_assert(tbp->magic == SMB_NCBMAGIC);
1830 memset(&tbp->ncb, 0, sizeof(NCB));
1833 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1838 void smb_FreePacket(smb_packet_t *tbp)
1840 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1842 lock_ObtainWrite(&smb_globalLock);
1843 tbp->nextp = smb_packetFreeListp;
1844 smb_packetFreeListp = tbp;
1845 tbp->magic = SMB_PACKETMAGIC;
1848 tbp->resumeCode = 0;
1854 tbp->ncb_length = 0;
1856 lock_ReleaseWrite(&smb_globalLock);
1859 static void FreeNCB(NCB *bufferp)
1863 tbp = (smb_ncb_t *) bufferp;
1864 osi_assert(tbp->magic == SMB_NCBMAGIC);
1866 lock_ObtainWrite(&smb_globalLock);
1867 tbp->nextp = smb_ncbFreeListp;
1868 smb_ncbFreeListp = tbp;
1869 lock_ReleaseWrite(&smb_globalLock);
1872 /* get a ptr to the data part of a packet, and its count */
1873 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1877 unsigned char *afterParmsp;
1879 parmBytes = *smbp->wctp << 1;
1880 afterParmsp = smbp->wctp + parmBytes + 1;
1882 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1883 if (nbytesp) *nbytesp = dataBytes;
1885 /* don't forget to skip the data byte count, since it follows
1886 * the parameters; that's where the "2" comes from below.
1888 return (unsigned char *) (afterParmsp + 2);
1891 /* must set all the returned parameters before playing around with the
1892 * data region, since the data region is located past the end of the
1893 * variable number of parameters.
1895 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1897 unsigned char *afterParmsp;
1899 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1901 *afterParmsp++ = dsize & 0xff;
1902 *afterParmsp = (dsize>>8) & 0xff;
1905 /* return the parm'th parameter in the smbp packet */
1906 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1909 unsigned char *parmDatap;
1911 parmCount = *smbp->wctp;
1913 if (parm >= parmCount) {
1918 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1920 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1921 parm, parmCount, smbp->ncb_length);
1924 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1925 1, smbp->ncb_length, ptbuf, smbp);
1926 DeregisterEventSource(h);
1928 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1929 osi_panic(s, __FILE__, __LINE__);
1931 parmDatap = smbp->wctp + (2*parm) + 1;
1933 return parmDatap[0] + (parmDatap[1] << 8);
1936 /* return the parm'th parameter in the smbp packet */
1937 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1940 unsigned char *parmDatap;
1942 parmCount = *smbp->wctp;
1944 if (parm * 2 + offset >= parmCount * 2) {
1949 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1951 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1952 parm, offset, parmCount, smbp->ncb_length);
1955 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1956 1, smbp->ncb_length, ptbuf, smbp);
1957 DeregisterEventSource(h);
1959 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1960 osi_panic(s, __FILE__, __LINE__);
1962 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1964 return parmDatap[0] + (parmDatap[1] << 8);
1967 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1971 /* make sure we have enough slots */
1972 if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1974 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1975 *parmDatap++ = parmValue & 0xff;
1976 *parmDatap = (parmValue>>8) & 0xff;
1979 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1983 /* make sure we have enough slots */
1984 if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1986 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1987 *parmDatap++ = parmValue & 0xff;
1988 *parmDatap++ = (parmValue>>8) & 0xff;
1989 *parmDatap++ = (parmValue>>16) & 0xff;
1990 *parmDatap++ = (parmValue>>24) & 0xff;
1993 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1998 /* make sure we have enough slots */
1999 if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
2001 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2003 *parmDatap++ = *parmValuep++;
2006 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2010 /* make sure we have enough slots */
2011 if (*smbp->wctp <= slot) {
2012 if (smbp->oddByte) {
2014 *smbp->wctp = slot+1;
2019 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2020 *parmDatap++ = parmValue & 0xff;
2023 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2027 lastSlashp = strrchr(inPathp, '\\');
2029 *lastComponentp = lastSlashp;
2032 if (inPathp == lastSlashp)
2034 *outPathp++ = *inPathp++;
2043 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2048 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2053 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2059 tlen = inp[0] + (inp[1]<<8);
2060 inp += 2; /* skip length field */
2063 *chainpp = inp + tlen;
2072 /* format a packet as a response */
2073 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2078 outp = (smb_t *) op;
2080 /* zero the basic structure through the smb_wct field, and zero the data
2081 * size field, assuming that wct stays zero; otherwise, you have to
2082 * explicitly set the data size field, too.
2084 inSmbp = (smb_t *) inp;
2085 memset(outp, 0, sizeof(smb_t)+2);
2091 outp->com = inSmbp->com;
2092 outp->tid = inSmbp->tid;
2093 outp->pid = inSmbp->pid;
2094 outp->uid = inSmbp->uid;
2095 outp->mid = inSmbp->mid;
2096 outp->res[0] = inSmbp->res[0];
2097 outp->res[1] = inSmbp->res[1];
2098 op->inCom = inSmbp->com;
2100 outp->reb = 0x80; /* SERVER_RESP */
2101 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2103 /* copy fields in generic packet area */
2104 op->wctp = &outp->wct;
2107 /* send a (probably response) packet; vcp tells us to whom to send it.
2108 * we compute the length by looking at wct and bcc fields.
2110 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2127 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2130 memset((char *)ncbp, 0, sizeof(NCB));
2132 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2133 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2134 extra += tp[0] + (tp[1]<<8);
2135 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2136 extra += 3; /* wct and length fields */
2138 ncbp->ncb_length = extra; /* bytes to send */
2139 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2140 ncbp->ncb_lana_num = vcp->lana;
2141 ncbp->ncb_command = NCBSEND; /* op means send data */
2143 ncbp->ncb_buffer = (char *) inp;/* packet */
2144 code = Netbios(ncbp);
2146 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2147 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2149 /* copy header information from virtual to DOS address space */
2150 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2151 code = Netbios(ncbp, dos_ncb);
2155 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2161 void smb_MapNTError(long code, unsigned long *NTStatusp)
2163 unsigned long NTStatus;
2165 /* map CM_ERROR_* errors to NT 32-bit status codes */
2166 /* NT Status codes are listed in ntstatus.h not winerror.h */
2167 if (code == CM_ERROR_NOSUCHCELL) {
2168 NTStatus = 0xC000000FL; /* No such file */
2170 else if (code == CM_ERROR_NOSUCHVOLUME) {
2171 NTStatus = 0xC000000FL; /* No such file */
2173 else if (code == CM_ERROR_TIMEDOUT) {
2174 NTStatus = 0xC00000CFL; /* Sharing Paused */
2176 else if (code == CM_ERROR_RETRY) {
2177 NTStatus = 0xC000022DL; /* Retry */
2179 else if (code == CM_ERROR_NOACCESS) {
2180 NTStatus = 0xC0000022L; /* Access denied */
2182 else if (code == CM_ERROR_READONLY) {
2183 NTStatus = 0xC00000A2L; /* Write protected */
2185 else if (code == CM_ERROR_NOSUCHFILE) {
2186 NTStatus = 0xC000000FL; /* No such file */
2188 else if (code == CM_ERROR_NOSUCHPATH) {
2189 NTStatus = 0xC000003AL; /* Object path not found */
2191 else if (code == CM_ERROR_TOOBIG) {
2192 NTStatus = 0xC000007BL; /* Invalid image format */
2194 else if (code == CM_ERROR_INVAL) {
2195 NTStatus = 0xC000000DL; /* Invalid parameter */
2197 else if (code == CM_ERROR_BADFD) {
2198 NTStatus = 0xC0000008L; /* Invalid handle */
2200 else if (code == CM_ERROR_BADFDOP) {
2201 NTStatus = 0xC0000022L; /* Access denied */
2203 else if (code == CM_ERROR_EXISTS) {
2204 NTStatus = 0xC0000035L; /* Object name collision */
2206 else if (code == CM_ERROR_NOTEMPTY) {
2207 NTStatus = 0xC0000101L; /* Directory not empty */
2209 else if (code == CM_ERROR_CROSSDEVLINK) {
2210 NTStatus = 0xC00000D4L; /* Not same device */
2212 else if (code == CM_ERROR_NOTDIR) {
2213 NTStatus = 0xC0000103L; /* Not a directory */
2215 else if (code == CM_ERROR_ISDIR) {
2216 NTStatus = 0xC00000BAL; /* File is a directory */
2218 else if (code == CM_ERROR_BADOP) {
2220 /* I have no idea where this comes from */
2221 NTStatus = 0xC09820FFL; /* SMB no support */
2223 NTStatus = 0xC00000BBL; /* Not supported */
2224 #endif /* COMMENT */
2226 else if (code == CM_ERROR_BADSHARENAME) {
2227 NTStatus = 0xC00000CCL; /* Bad network name */
2229 else if (code == CM_ERROR_NOIPC) {
2231 NTStatus = 0xC0000022L; /* Access Denied */
2233 NTStatus = 0xC000013DL; /* Remote Resources */
2236 else if (code == CM_ERROR_CLOCKSKEW) {
2237 NTStatus = 0xC0000133L; /* Time difference at DC */
2239 else if (code == CM_ERROR_BADTID) {
2240 NTStatus = 0xC0982005L; /* SMB bad TID */
2242 else if (code == CM_ERROR_USESTD) {
2243 NTStatus = 0xC09820FBL; /* SMB use standard */
2245 else if (code == CM_ERROR_QUOTA) {
2246 NTStatus = 0xC0000044L; /* Quota exceeded */
2248 else if (code == CM_ERROR_SPACE) {
2249 NTStatus = 0xC000007FL; /* Disk full */
2251 else if (code == CM_ERROR_ATSYS) {
2252 NTStatus = 0xC0000033L; /* Object name invalid */
2254 else if (code == CM_ERROR_BADNTFILENAME) {
2255 NTStatus = 0xC0000033L; /* Object name invalid */
2257 else if (code == CM_ERROR_WOULDBLOCK) {
2258 NTStatus = 0xC0000055L; /* Lock not granted */
2260 else if (code == CM_ERROR_PARTIALWRITE) {
2261 NTStatus = 0xC000007FL; /* Disk full */
2263 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2264 NTStatus = 0xC0000023L; /* Buffer too small */
2266 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2267 NTStatus = 0xC0000035L; /* Object name collision */
2269 else if (code == CM_ERROR_BADPASSWORD) {
2270 NTStatus = 0xC000006DL; /* unknown username or bad password */
2272 else if (code == CM_ERROR_BADLOGONTYPE) {
2273 NTStatus = 0xC000015BL; /* logon type not granted */
2275 else if (code == CM_ERROR_GSSCONTINUE) {
2276 NTStatus = 0xC0000016L; /* more processing required */
2279 NTStatus = 0xC0982001L; /* SMB non-specific error */
2282 *NTStatusp = NTStatus;
2283 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2286 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2287 unsigned char *classp)
2289 unsigned char class;
2290 unsigned short error;
2292 /* map CM_ERROR_* errors to SMB errors */
2293 if (code == CM_ERROR_NOSUCHCELL) {
2295 error = 3; /* bad path */
2297 else if (code == CM_ERROR_NOSUCHVOLUME) {
2299 error = 3; /* bad path */
2301 else if (code == CM_ERROR_TIMEDOUT) {
2303 error = 81; /* server is paused */
2305 else if (code == CM_ERROR_RETRY) {
2306 class = 2; /* shouldn't happen */
2309 else if (code == CM_ERROR_NOACCESS) {
2311 error = 4; /* bad access */
2313 else if (code == CM_ERROR_READONLY) {
2315 error = 19; /* read only */
2317 else if (code == CM_ERROR_NOSUCHFILE) {
2319 error = 2; /* ENOENT! */
2321 else if (code == CM_ERROR_NOSUCHPATH) {
2323 error = 3; /* Bad path */
2325 else if (code == CM_ERROR_TOOBIG) {
2327 error = 11; /* bad format */
2329 else if (code == CM_ERROR_INVAL) {
2330 class = 2; /* server non-specific error code */
2333 else if (code == CM_ERROR_BADFD) {
2335 error = 6; /* invalid file handle */
2337 else if (code == CM_ERROR_BADFDOP) {
2338 class = 1; /* invalid op on FD */
2341 else if (code == CM_ERROR_EXISTS) {
2343 error = 80; /* file already exists */
2345 else if (code == CM_ERROR_NOTEMPTY) {
2347 error = 5; /* delete directory not empty */
2349 else if (code == CM_ERROR_CROSSDEVLINK) {
2351 error = 17; /* EXDEV */
2353 else if (code == CM_ERROR_NOTDIR) {
2354 class = 1; /* bad path */
2357 else if (code == CM_ERROR_ISDIR) {
2358 class = 1; /* access denied; DOS doesn't have a good match */
2361 else if (code == CM_ERROR_BADOP) {
2365 else if (code == CM_ERROR_BADSHARENAME) {
2369 else if (code == CM_ERROR_NOIPC) {
2371 error = 4; /* bad access */
2373 else if (code == CM_ERROR_CLOCKSKEW) {
2374 class = 1; /* invalid function */
2377 else if (code == CM_ERROR_BADTID) {
2381 else if (code == CM_ERROR_USESTD) {
2385 else if (code == CM_ERROR_REMOTECONN) {
2389 else if (code == CM_ERROR_QUOTA) {
2390 if (vcp->flags & SMB_VCFLAG_USEV3) {
2392 error = 39; /* disk full */
2396 error = 5; /* access denied */
2399 else if (code == CM_ERROR_SPACE) {
2400 if (vcp->flags & SMB_VCFLAG_USEV3) {
2402 error = 39; /* disk full */
2406 error = 5; /* access denied */
2409 else if (code == CM_ERROR_PARTIALWRITE) {
2411 error = 39; /* disk full */
2413 else if (code == CM_ERROR_ATSYS) {
2415 error = 2; /* ENOENT */
2417 else if (code == CM_ERROR_WOULDBLOCK) {
2419 error = 33; /* lock conflict */
2421 else if (code == CM_ERROR_NOFILES) {
2423 error = 18; /* no files in search */
2425 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2427 error = 183; /* Samba uses this */
2429 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2430 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2432 error = 2; /* bad password */
2441 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2444 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2446 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2447 return CM_ERROR_BADOP;
2450 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2452 unsigned short EchoCount, i;
2453 char *data, *outdata;
2456 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2458 for (i=1; i<=EchoCount; i++) {
2459 data = smb_GetSMBData(inp, &dataSize);
2460 smb_SetSMBParm(outp, 0, i);
2461 smb_SetSMBDataLength(outp, dataSize);
2462 outdata = smb_GetSMBData(outp, NULL);
2463 memcpy(outdata, data, dataSize);
2464 smb_SendPacket(vcp, outp);
2470 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2473 long count, minCount, finalCount;
2477 cm_user_t *userp = NULL;
2481 char *rawBuf = NULL;
2483 dos_ptr rawBuf = NULL;
2490 fd = smb_GetSMBParm(inp, 0);
2491 count = smb_GetSMBParm(inp, 3);
2492 minCount = smb_GetSMBParm(inp, 4);
2493 offset.HighPart = 0; /* too bad */
2494 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2496 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2497 fd, offset.LowPart, count);
2499 fidp = smb_FindFID(vcp, fd, 0);
2503 lock_ObtainMutex(&smb_RawBufLock);
2505 /* Get a raw buf, from head of list */
2506 rawBuf = smb_RawBufs;
2508 smb_RawBufs = *(char **)smb_RawBufs;
2510 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2513 lock_ReleaseMutex(&smb_RawBufLock);
2517 if (fidp->flags & SMB_FID_IOCTL)
2520 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2522 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2525 /* Give back raw buffer */
2526 lock_ObtainMutex(&smb_RawBufLock);
2528 *((char **) rawBuf) = smb_RawBufs;
2530 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2533 smb_RawBufs = rawBuf;
2534 lock_ReleaseMutex(&smb_RawBufLock);
2537 smb_ReleaseFID(fidp);
2541 userp = smb_GetUser(vcp, inp);
2544 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2546 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2547 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2548 userp, &finalCount, TRUE /* rawFlag */);
2555 cm_ReleaseUser(userp);
2558 smb_ReleaseFID(fidp);
2563 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2565 memset((char *)ncbp, 0, sizeof(NCB));
2567 ncbp->ncb_length = (unsigned short) finalCount;
2568 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2569 ncbp->ncb_lana_num = vcp->lana;
2570 ncbp->ncb_command = NCBSEND;
2571 ncbp->ncb_buffer = rawBuf;
2574 code = Netbios(ncbp);
2576 code = Netbios(ncbp, dos_ncb);
2579 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2582 /* Give back raw buffer */
2583 lock_ObtainMutex(&smb_RawBufLock);
2585 *((char **) rawBuf) = smb_RawBufs;
2587 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2590 smb_RawBufs = rawBuf;
2591 lock_ReleaseMutex(&smb_RawBufLock);
2597 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2602 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2607 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2614 int protoIndex; /* index we're using */
2619 char protocol_array[10][1024]; /* protocol signature of the client */
2620 int caps; /* capabilities */
2623 TIME_ZONE_INFORMATION tzi;
2625 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2629 DWORD now = GetCurrentTime();
2630 if (now - last_msg_time >= 30000
2631 && now - last_msg_time <= 90000) {
2633 "Setting dead_vcp %x", active_vcp);
2635 smb_ReleaseVC(dead_vcp);
2637 "Previous dead_vcp %x", dead_vcp);
2639 smb_HoldVC(active_vcp);
2640 dead_vcp = active_vcp;
2641 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2646 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2648 namep = smb_GetSMBData(inp, &dbytes);
2651 coreProtoIndex = -1; /* not found */
2654 while(namex < dbytes) {
2655 osi_Log1(smb_logp, "Protocol %s",
2656 osi_LogSaveString(smb_logp, namep+1));
2657 strcpy(protocol_array[tcounter], namep+1);
2659 /* namep points at the first protocol, or really, a 0x02
2660 * byte preceding the null-terminated ASCII name.
2662 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2663 coreProtoIndex = tcounter;
2665 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2666 v3ProtoIndex = tcounter;
2668 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2669 NTProtoIndex = tcounter;
2672 /* compute size of protocol entry */
2673 entryLength = strlen(namep+1);
2674 entryLength += 2; /* 0x02 bytes and null termination */
2676 /* advance over this protocol entry */
2677 namex += entryLength;
2678 namep += entryLength;
2679 tcounter++; /* which proto entry we're looking at */
2682 if (NTProtoIndex != -1) {
2683 protoIndex = NTProtoIndex;
2684 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2686 else if (v3ProtoIndex != -1) {
2687 protoIndex = v3ProtoIndex;
2688 vcp->flags |= SMB_VCFLAG_USEV3;
2690 else if (coreProtoIndex != -1) {
2691 protoIndex = coreProtoIndex;
2692 vcp->flags |= SMB_VCFLAG_USECORE;
2694 else protoIndex = -1;
2696 if (protoIndex == -1)
2697 return CM_ERROR_INVAL;
2698 else if (NTProtoIndex != -1) {
2699 smb_SetSMBParm(outp, 0, protoIndex);
2700 if (smb_authType != SMB_AUTH_NONE) {
2701 smb_SetSMBParmByte(outp, 1,
2702 NEGOTIATE_SECURITY_USER_LEVEL |
2703 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2705 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2707 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2708 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2709 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2710 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2711 /* The session key is not a well documented field however most clients
2712 * will echo back the session key to the server. Currently we are using
2713 * the same value for all sessions. We should generate a random value
2714 * and store it into the vcp
2716 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2717 smb_SetSMBParm(outp, 8, 1);
2719 * Tried changing the capabilities to support for W2K - defect 117695
2720 * Maybe something else needs to be changed here?
2724 smb_SetSMBParmLong(outp, 9, 0x43fd);
2726 smb_SetSMBParmLong(outp, 9, 0x251);
2729 * 32-bit error codes *
2733 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2734 NTNEGOTIATE_CAPABILITY_NTFIND |
2735 NTNEGOTIATE_CAPABILITY_RAWMODE |
2736 NTNEGOTIATE_CAPABILITY_NTSMB;
2738 if ( smb_authType == SMB_AUTH_EXTENDED )
2739 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2741 smb_SetSMBParmLong(outp, 9, caps);
2743 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2744 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2745 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2747 GetTimeZoneInformation(&tzi);
2748 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2750 if (smb_authType == SMB_AUTH_NTLM) {
2751 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2752 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2753 /* paste in encryption key */
2754 datap = smb_GetSMBData(outp, NULL);
2755 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2756 /* and the faux domain name */
2757 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2758 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2762 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2764 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2766 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2768 datap = smb_GetSMBData(outp, NULL);
2769 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2772 datap += sizeof(smb_ServerGUID);
2773 memcpy(datap, secBlob, secBlobLength);
2777 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2778 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2781 else if (v3ProtoIndex != -1) {
2782 smb_SetSMBParm(outp, 0, protoIndex);
2784 /* NOTE: Extended authentication cannot be negotiated with v3
2785 * therefore we fail over to NTLM
2787 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2788 smb_SetSMBParm(outp, 1,
2789 NEGOTIATE_SECURITY_USER_LEVEL |
2790 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2792 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2794 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2795 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2796 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2797 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2798 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2799 smb_SetSMBParm(outp, 7, 1);
2801 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2802 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2803 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2805 GetTimeZoneInformation(&tzi);
2806 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2808 /* NOTE: Extended authentication cannot be negotiated with v3
2809 * therefore we fail over to NTLM
2811 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2812 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2813 smb_SetSMBParm(outp, 12, 0); /* resvd */
2814 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2815 datap = smb_GetSMBData(outp, NULL);
2816 /* paste in a new encryption key */
2817 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2818 /* and the faux domain name */
2819 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2821 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2822 smb_SetSMBParm(outp, 12, 0); /* resvd */
2823 smb_SetSMBDataLength(outp, 0);
2826 else if (coreProtoIndex != -1) { /* not really supported anymore */
2827 smb_SetSMBParm(outp, 0, protoIndex);
2828 smb_SetSMBDataLength(outp, 0);
2833 void smb_Daemon(void *parmp)
2835 afs_uint32 count = 0;
2840 if ((count % 72) == 0) { /* every five minutes */
2842 long old_localZero = smb_localZero;
2844 /* Initialize smb_localZero */
2845 myTime.tm_isdst = -1; /* compute whether on DST or not */
2846 myTime.tm_year = 70;
2852 smb_localZero = mktime(&myTime);
2854 smb_CalculateNowTZ();
2856 #ifdef AFS_FREELANCE
2857 if ( smb_localZero != old_localZero )
2858 cm_noteLocalMountPointChange();
2861 /* XXX GC dir search entries */
2865 void smb_WaitingLocksDaemon()
2867 smb_waitingLock_t *wL, *nwL;
2870 smb_packet_t *inp, *outp;
2875 lock_ObtainWrite(&smb_globalLock);
2876 nwL = smb_allWaitingLocks;
2878 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2887 lock_ObtainWrite(&smb_globalLock);
2889 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2890 lock_ReleaseWrite(&smb_globalLock);
2891 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2892 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2893 if (code == CM_ERROR_WOULDBLOCK) {
2895 if (wL->timeRemaining != 0xffffffff
2896 && (wL->timeRemaining -= 1000) < 0)
2905 ncbp->ncb_length = inp->ncb_length;
2906 inp->spacep = cm_GetSpace();
2908 /* Remove waitingLock from list */
2909 lock_ObtainWrite(&smb_globalLock);
2910 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2912 lock_ReleaseWrite(&smb_globalLock);
2914 /* Resume packet processing */
2916 smb_SetSMBDataLength(outp, 0);
2917 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2918 outp->resumeCode = code;
2920 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2923 cm_FreeSpace(inp->spacep);
2924 smb_FreePacket(inp);
2925 smb_FreePacket(outp);
2933 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2935 osi_Log0(smb_logp, "SMB receive get disk attributes");
2937 smb_SetSMBParm(outp, 0, 32000);
2938 smb_SetSMBParm(outp, 1, 64);
2939 smb_SetSMBParm(outp, 2, 1024);
2940 smb_SetSMBParm(outp, 3, 30000);
2941 smb_SetSMBParm(outp, 4, 0);
2942 smb_SetSMBDataLength(outp, 0);
2946 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2950 unsigned short newTid;
2951 char shareName[256];
2959 osi_Log0(smb_logp, "SMB receive tree connect");
2961 /* parse input parameters */
2962 tp = smb_GetSMBData(inp, NULL);
2963 pathp = smb_ParseASCIIBlock(tp, &tp);
2964 passwordp = smb_ParseASCIIBlock(tp, &tp);
2965 tp = strrchr(pathp, '\\');
2967 return CM_ERROR_BADSMB;
2968 strcpy(shareName, tp+1);
2970 userp = smb_GetUser(vcp, inp);
2972 lock_ObtainMutex(&vcp->mx);
2973 newTid = vcp->tidCounter++;
2974 lock_ReleaseMutex(&vcp->mx);
2976 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2977 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2978 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2980 smb_ReleaseUID(uidp);
2982 smb_ReleaseTID(tidp);
2983 return CM_ERROR_BADSHARENAME;
2985 lock_ObtainMutex(&tidp->mx);
2986 tidp->userp = userp;
2987 tidp->pathname = sharePath;
2988 lock_ReleaseMutex(&tidp->mx);
2989 smb_ReleaseTID(tidp);
2991 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2992 smb_SetSMBParm(rsp, 1, newTid);
2993 smb_SetSMBDataLength(rsp, 0);
2995 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2999 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3003 if (*inp++ != 0x1) return NULL;
3004 tlen = inp[0] + (inp[1]<<8);
3005 inp += 2; /* skip length field */
3008 *chainpp = inp + tlen;
3011 if (lengthp) *lengthp = tlen;
3016 /* set maskp to the mask part of the incoming path.
3017 * Mask is 11 bytes long (8.3 with the dot elided).
3018 * Returns true if succeeds with a valid name, otherwise it does
3019 * its best, but returns false.
3021 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3029 /* starts off valid */
3032 /* mask starts out all blanks */
3033 memset(maskp, ' ', 11);
3035 /* find last backslash, or use whole thing if there is none */
3036 tp = strrchr(pathp, '\\');
3037 if (!tp) tp = pathp;
3038 else tp++; /* skip slash */
3042 /* names starting with a dot are illegal */
3043 if (*tp == '.') valid8Dot3 = 0;
3047 if (tc == 0) return valid8Dot3;
3048 if (tc == '.' || tc == '"') break;
3049 if (i < 8) *up++ = tc;
3050 else valid8Dot3 = 0;
3053 /* if we get here, tp point after the dot */
3054 up = maskp+8; /* ext goes here */
3061 if (tc == '.' || tc == '"')
3064 /* copy extension if not too long */
3074 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3084 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3086 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3090 /* otherwise, we have a valid 8.3 name; see if we have a match,
3091 * treating '?' as a wildcard in maskp (but not in the file name).
3093 tp1 = umask; /* real name, in mask format */
3094 tp2 = maskp; /* mask, in mask format */
3095 for(i=0; i<11; i++) {
3096 tc1 = *tp1++; /* char from real name */
3097 tc2 = *tp2++; /* char from mask */
3098 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3099 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3102 if (tc2 == '?' && tc1 != ' ')
3109 /* we got a match */
3113 char *smb_FindMask(char *pathp)
3117 tp = strrchr(pathp, '\\'); /* find last slash */
3120 return tp+1; /* skip the slash */
3122 return pathp; /* no slash, return the entire path */
3125 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3127 unsigned char *pathp;
3129 unsigned char mask[11];
3130 unsigned char *statBlockp;
3131 unsigned char initStatBlock[21];
3134 osi_Log0(smb_logp, "SMB receive search volume");
3136 /* pull pathname and stat block out of request */
3137 tp = smb_GetSMBData(inp, NULL);
3138 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3139 osi_assert(pathp != NULL);
3140 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3141 osi_assert(statBlockp != NULL);
3143 statBlockp = initStatBlock;
3147 /* for returning to caller */
3148 smb_Get8Dot3MaskFromPath(mask, pathp);
3150 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3151 tp = smb_GetSMBData(outp, NULL);
3153 *tp++ = 43; /* bytes in a dir entry */
3154 *tp++ = 0; /* high byte in counter */
3156 /* now marshall the dir entry, starting with the search status */
3157 *tp++ = statBlockp[0]; /* Reserved */
3158 memcpy(tp, mask, 11); tp += 11; /* FileName */
3160 /* now pass back server use info, with 1st byte non-zero */
3162 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3164 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3166 *tp++ = 0x8; /* attribute: volume */
3176 /* 4 byte file size */
3182 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3183 memset(tp, ' ', 13);
3186 /* set the length of the data part of the packet to 43 + 3, for the dir
3187 * entry plus the 5 and the length fields.
3189 smb_SetSMBDataLength(outp, 46);
3193 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3194 cm_user_t *userp, cm_req_t *reqp)
3202 smb_dirListPatch_t *patchp;
3203 smb_dirListPatch_t *npatchp;
3205 for(patchp = *dirPatchespp; patchp; patchp =
3206 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3208 dptr = patchp->dptr;
3210 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3212 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3213 *dptr++ = SMB_ATTR_HIDDEN;
3216 lock_ObtainMutex(&scp->mx);
3217 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3218 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3220 lock_ReleaseMutex(&scp->mx);
3221 cm_ReleaseSCache(scp);
3222 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3223 *dptr++ = SMB_ATTR_HIDDEN;
3227 attr = smb_Attributes(scp);
3228 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3229 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3230 attr |= SMB_ATTR_HIDDEN;
3234 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3237 shortTemp = dosTime & 0xffff;
3238 *((u_short *)dptr) = shortTemp;
3241 /* and copy out date */
3242 shortTemp = (dosTime>>16) & 0xffff;
3243 *((u_short *)dptr) = shortTemp;
3246 /* copy out file length */
3247 *((u_long *)dptr) = scp->length.LowPart;
3249 lock_ReleaseMutex(&scp->mx);
3250 cm_ReleaseSCache(scp);
3253 /* now free the patches */
3254 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3255 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3259 /* and mark the list as empty */
3260 *dirPatchespp = NULL;
3265 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3274 smb_dirListPatch_t *dirListPatchesp;
3275 smb_dirListPatch_t *curPatchp;
3279 osi_hyper_t dirLength;
3280 osi_hyper_t bufferOffset;
3281 osi_hyper_t curOffset;
3283 unsigned char *inCookiep;
3284 smb_dirSearch_t *dsp;
3288 unsigned long clientCookie;
3289 cm_pageHeader_t *pageHeaderp;
3290 cm_user_t *userp = NULL;
3297 long nextEntryCookie;
3298 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3299 char resByte; /* reserved byte from the cookie */
3300 char *op; /* output data ptr */
3301 char *origOp; /* original value of op */
3302 cm_space_t *spacep; /* for pathname buffer */
3313 maxCount = smb_GetSMBParm(inp, 0);
3315 dirListPatchesp = NULL;
3317 caseFold = CM_FLAG_CASEFOLD;
3319 tp = smb_GetSMBData(inp, NULL);
3320 pathp = smb_ParseASCIIBlock(tp, &tp);
3321 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3323 /* bail out if request looks bad */
3324 if (!tp || !pathp) {
3325 return CM_ERROR_BADSMB;
3328 /* We can handle long names */
3329 if (vcp->flags & SMB_VCFLAG_USENT)
3330 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3332 /* make sure we got a whole search status */
3333 if (dataLength < 21) {
3334 nextCookie = 0; /* start at the beginning of the dir */
3337 attribute = smb_GetSMBParm(inp, 1);
3339 /* handle volume info in another function */
3340 if (attribute & 0x8)
3341 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3343 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3344 maxCount, osi_LogSaveString(smb_logp, pathp));
3346 if (*pathp == 0) { /* null pathp, treat as root dir */
3347 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3348 return CM_ERROR_NOFILES;
3352 dsp = smb_NewDirSearch(0);
3353 dsp->attribute = attribute;
3354 smb_Get8Dot3MaskFromPath(mask, pathp);
3355 memcpy(dsp->mask, mask, 11);
3357 /* track if this is likely to match a lot of entries */
3358 if (smb_IsStarMask(mask)) starPattern = 1;
3359 else starPattern = 0;
3362 /* pull the next cookie value out of the search status block */
3363 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3364 + (inCookiep[16]<<24);
3365 dsp = smb_FindDirSearch(inCookiep[12]);
3367 /* can't find dir search status; fatal error */
3368 return CM_ERROR_BADFD;
3370 attribute = dsp->attribute;
3371 resByte = inCookiep[0];
3373 /* copy out client cookie, in host byte order. Don't bother
3374 * interpreting it, since we're just passing it through, anyway.
3376 memcpy(&clientCookie, &inCookiep[17], 4);
3378 memcpy(mask, dsp->mask, 11);
3380 /* assume we're doing a star match if it has continued for more
3386 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3387 nextCookie, dsp->cookie, attribute);
3389 userp = smb_GetUser(vcp, inp);
3391 /* try to get the vnode for the path name next */
3392 lock_ObtainMutex(&dsp->mx);
3399 spacep = inp->spacep;
3400 smb_StripLastComponent(spacep->data, NULL, pathp);
3401 lock_ReleaseMutex(&dsp->mx);
3402 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3404 lock_ReleaseMutex(&dsp->mx);
3405 cm_ReleaseUser(userp);
3406 smb_DeleteDirSearch(dsp);
3407 smb_ReleaseDirSearch(dsp);
3408 return CM_ERROR_NOFILES;
3410 code = cm_NameI(cm_rootSCachep, spacep->data,
3411 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3412 lock_ObtainMutex(&dsp->mx);
3414 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3416 /* we need one hold for the entry we just stored into,
3417 * and one for our own processing. When we're done with this
3418 * function, we'll drop the one for our own processing.
3419 * We held it once from the namei call, and so we do another hold
3423 lock_ObtainMutex(&scp->mx);
3424 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3425 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3426 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3427 dsp->flags |= SMB_DIRSEARCH_BULKST;
3429 lock_ReleaseMutex(&scp->mx);
3432 lock_ReleaseMutex(&dsp->mx);
3434 cm_ReleaseUser(userp);
3435 smb_DeleteDirSearch(dsp);
3436 smb_ReleaseDirSearch(dsp);
3440 /* reserves space for parameter; we'll adjust it again later to the
3441 * real count of the # of entries we returned once we've actually
3442 * assembled the directory listing.
3444 smb_SetSMBParm(outp, 0, 0);
3446 /* get the directory size */
3447 lock_ObtainMutex(&scp->mx);
3448 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3449 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3451 lock_ReleaseMutex(&scp->mx);
3452 cm_ReleaseSCache(scp);
3453 cm_ReleaseUser(userp);
3454 smb_DeleteDirSearch(dsp);
3455 smb_ReleaseDirSearch(dsp);
3459 dirLength = scp->length;
3461 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3462 curOffset.HighPart = 0;
3463 curOffset.LowPart = nextCookie;
3464 origOp = op = smb_GetSMBData(outp, NULL);
3465 /* and write out the basic header */
3466 *op++ = 5; /* variable block */
3467 op += 2; /* skip vbl block length; we'll fill it in later */
3471 /* make sure that curOffset.LowPart doesn't point to the first
3472 * 32 bytes in the 2nd through last dir page, and that it doesn't
3473 * point at the first 13 32-byte chunks in the first dir page,
3474 * since those are dir and page headers, and don't contain useful
3477 temp = curOffset.LowPart & (2048-1);
3478 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3479 /* we're in the first page */
3480 if (temp < 13*32) temp = 13*32;
3483 /* we're in a later dir page */
3484 if (temp < 32) temp = 32;
3487 /* make sure the low order 5 bits are zero */
3490 /* now put temp bits back ito curOffset.LowPart */
3491 curOffset.LowPart &= ~(2048-1);
3492 curOffset.LowPart |= temp;
3494 /* check if we've returned all the names that will fit in the
3497 if (returnedNames >= maxCount)
3500 /* check if we've passed the dir's EOF */
3501 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3503 /* see if we can use the bufferp we have now; compute in which page
3504 * the current offset would be, and check whether that's the offset
3505 * of the buffer we have. If not, get the buffer.
3507 thyper.HighPart = curOffset.HighPart;
3508 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3509 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3512 buf_Release(bufferp);
3515 lock_ReleaseMutex(&scp->mx);
3516 lock_ObtainRead(&scp->bufCreateLock);
3517 code = buf_Get(scp, &thyper, &bufferp);
3518 lock_ReleaseRead(&scp->bufCreateLock);
3520 /* now, if we're doing a star match, do bulk fetching of all of
3521 * the status info for files in the dir.
3524 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3526 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3527 && LargeIntegerGreaterThanOrEqualTo(thyper,
3528 scp->bulkStatProgress)) {
3529 /* Don't bulk stat if risking timeout */
3530 int now = GetCurrentTime();
3531 if (now - req.startTime > 5000) {
3532 scp->bulkStatProgress = thyper;
3533 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3534 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3536 cm_TryBulkStat(scp, &thyper, userp, &req);
3540 lock_ObtainMutex(&scp->mx);
3543 bufferOffset = thyper;
3545 /* now get the data in the cache */
3547 code = cm_SyncOp(scp, bufferp, userp, &req,
3549 CM_SCACHESYNC_NEEDCALLBACK
3550 | CM_SCACHESYNC_READ);
3553 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3555 /* otherwise, load the buffer and try again */
3556 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3561 buf_Release(bufferp);
3565 } /* if (wrong buffer) ... */
3567 /* now we have the buffer containing the entry we're interested in; copy
3568 * it out if it represents a non-deleted entry.
3570 entryInDir = curOffset.LowPart & (2048-1);
3571 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3573 /* page header will help tell us which entries are free. Page header
3574 * can change more often than once per buffer, since AFS 3 dir page size
3575 * may be less than (but not more than a buffer package buffer.
3577 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3578 temp &= ~(2048 - 1); /* turn off intra-page bits */
3579 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3581 /* now determine which entry we're looking at in the page. If it is
3582 * free (there's a free bitmap at the start of the dir), we should
3583 * skip these 32 bytes.
3585 slotInPage = (entryInDir & 0x7e0) >> 5;
3586 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3587 /* this entry is free */
3588 numDirChunks = 1; /* only skip this guy */
3592 tp = bufferp->datap + entryInBuffer;
3593 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3595 /* while we're here, compute the next entry's location, too,
3596 * since we'll need it when writing out the cookie into the dir
3599 * XXXX Probably should do more sanity checking.
3601 numDirChunks = cm_NameEntries(dep->name, NULL);
3603 /* compute the offset of the cookie representing the next entry */
3604 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3606 /* Compute 8.3 name if necessary */
3607 actualName = dep->name;
3608 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3609 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3610 actualName = shortName;
3613 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3614 /* this is one of the entries to use: it is not deleted
3615 * and it matches the star pattern we're looking for.
3618 /* Eliminate entries that don't match requested
3621 /* no hidden files */
3622 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3625 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3627 /* We have already done the cm_TryBulkStat above */
3628 fid.cell = scp->fid.cell;
3629 fid.volume = scp->fid.volume;
3630 fid.vnode = ntohl(dep->fid.vnode);
3631 fid.unique = ntohl(dep->fid.unique);
3632 fileType = cm_FindFileType(&fid);
3633 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3634 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3636 if (fileType == CM_SCACHETYPE_DIRECTORY)
3641 memcpy(op, mask, 11); op += 11;
3642 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3643 *op++ = nextEntryCookie & 0xff;
3644 *op++ = (nextEntryCookie>>8) & 0xff;
3645 *op++ = (nextEntryCookie>>16) & 0xff;
3646 *op++ = (nextEntryCookie>>24) & 0xff;
3647 memcpy(op, &clientCookie, 4); op += 4;
3649 /* now we emit the attribute. This is sort of tricky,
3650 * since we need to really stat the file to find out
3651 * what type of entry we've got. Right now, we're
3652 * copying out data from a buffer, while holding the
3653 * scp locked, so it isn't really convenient to stat
3654 * something now. We'll put in a place holder now,
3655 * and make a second pass before returning this to get
3656 * the real attributes. So, we just skip the data for
3657 * now, and adjust it later. We allocate a patch
3658 * record to make it easy to find this point later.
3659 * The replay will happen at a time when it is safe to
3660 * unlock the directory.
3662 curPatchp = malloc(sizeof(*curPatchp));
3663 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3664 curPatchp->dptr = op;
3665 curPatchp->fid.cell = scp->fid.cell;
3666 curPatchp->fid.volume = scp->fid.volume;
3667 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3668 curPatchp->fid.unique = ntohl(dep->fid.unique);
3670 /* do hidden attribute here since name won't be around when applying
3674 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3675 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3677 curPatchp->flags = 0;
3679 op += 9; /* skip attr, time, date and size */
3681 /* zero out name area. The spec says to pad with
3682 * spaces, but Samba doesn't, and neither do we.
3686 /* finally, we get to copy out the name; we know that
3687 * it fits in 8.3 or the pattern wouldn't match, but it
3688 * never hurts to be sure.
3690 strncpy(op, actualName, 13);
3692 /* Uppercase if requested by client */
3693 if ((((smb_t *)inp)->flg2 & 1) == 0)
3698 /* now, adjust the # of entries copied */
3700 } /* if we're including this name */
3703 /* and adjust curOffset to be where the new cookie is */
3704 thyper.HighPart = 0;
3705 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3706 curOffset = LargeIntegerAdd(thyper, curOffset);
3707 } /* while copying data for dir listing */
3709 /* release the mutex */
3710 lock_ReleaseMutex(&scp->mx);
3711 if (bufferp) buf_Release(bufferp);
3713 /* apply and free last set of patches; if not doing a star match, this
3714 * will be empty, but better safe (and freeing everything) than sorry.
3716 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3718 /* special return code for unsuccessful search */
3719 if (code == 0 && dataLength < 21 && returnedNames == 0)
3720 code = CM_ERROR_NOFILES;
3722 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3723 returnedNames, code);
3726 smb_DeleteDirSearch(dsp);
3727 smb_ReleaseDirSearch(dsp);
3728 cm_ReleaseSCache(scp);
3729 cm_ReleaseUser(userp);
3733 /* finalize the output buffer */
3734 smb_SetSMBParm(outp, 0, returnedNames);
3735 temp = (long) (op - origOp);
3736 smb_SetSMBDataLength(outp, temp);
3738 /* the data area is a variable block, which has a 5 (already there)
3739 * followed by the length of the # of data bytes. We now know this to
3740 * be "temp," although that includes the 3 bytes of vbl block header.
3741 * Deduct for them and fill in the length field.
3743 temp -= 3; /* deduct vbl block info */
3744 osi_assert(temp == (43 * returnedNames));
3745 origOp[1] = temp & 0xff;
3746 origOp[2] = (temp>>8) & 0xff;
3747 if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3748 smb_ReleaseDirSearch(dsp);
3749 cm_ReleaseSCache(scp);
3750 cm_ReleaseUser(userp);
3754 /* verify that this is a valid path to a directory. I don't know why they
3755 * don't use the get file attributes call.
3757 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3761 cm_scache_t *rootScp;
3762 cm_scache_t *newScp;
3771 pathp = smb_GetSMBData(inp, NULL);
3772 pathp = smb_ParseASCIIBlock(pathp, NULL);
3773 osi_Log1(smb_logp, "SMB receive check path %s",
3774 osi_LogSaveString(smb_logp, pathp));
3777 return CM_ERROR_BADFD;
3780 rootScp = cm_rootSCachep;
3782 userp = smb_GetUser(vcp, inp);
3784 caseFold = CM_FLAG_CASEFOLD;
3786 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3788 cm_ReleaseUser(userp);
3789 return CM_ERROR_NOSUCHPATH;
3791 code = cm_NameI(rootScp, pathp,
3792 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3793 userp, tidPathp, &req, &newScp);
3796 cm_ReleaseUser(userp);
3800 /* now lock the vnode with a callback; returns with newScp locked */
3801 lock_ObtainMutex(&newScp->mx);
3802 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3803 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3804 if (code && code != CM_ERROR_NOACCESS) {
3805 lock_ReleaseMutex(&newScp->mx);
3806 cm_ReleaseSCache(newScp);
3807 cm_ReleaseUser(userp);
3811 attrs = smb_Attributes(newScp);
3813 if (!(attrs & 0x10))
3814 code = CM_ERROR_NOTDIR;
3816 lock_ReleaseMutex(&newScp->mx);
3818 cm_ReleaseSCache(newScp);
3819 cm_ReleaseUser(userp);
3823 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3827 cm_scache_t *rootScp;
3828 unsigned short attribute;
3830 cm_scache_t *newScp;
3839 /* decode basic attributes we're passed */
3840 attribute = smb_GetSMBParm(inp, 0);
3841 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3843 pathp = smb_GetSMBData(inp, NULL);
3844 pathp = smb_ParseASCIIBlock(pathp, NULL);
3847 return CM_ERROR_BADSMB;
3850 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3851 dosTime, attribute);
3853 rootScp = cm_rootSCachep;
3855 userp = smb_GetUser(vcp, inp);
3857 caseFold = CM_FLAG_CASEFOLD;
3859 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3861 cm_ReleaseUser(userp);
3862 return CM_ERROR_NOSUCHFILE;
3864 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3865 tidPathp, &req, &newScp);
3868 cm_ReleaseUser(userp);
3872 /* now lock the vnode with a callback; returns with newScp locked; we
3873 * need the current status to determine what the new status is, in some
3876 lock_ObtainMutex(&newScp->mx);
3877 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3878 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3880 lock_ReleaseMutex(&newScp->mx);
3881 cm_ReleaseSCache(newScp);
3882 cm_ReleaseUser(userp);
3886 /* Check for RO volume */
3887 if (newScp->flags & CM_SCACHEFLAG_RO) {
3888 lock_ReleaseMutex(&newScp->mx);
3889 cm_ReleaseSCache(newScp);
3890 cm_ReleaseUser(userp);
3891 return CM_ERROR_READONLY;
3894 /* prepare for setattr call */
3897 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3898 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3900 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3901 /* we're told to make a writable file read-only */
3902 attr.unixModeBits = newScp->unixModeBits & ~0222;
3903 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3905 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3906 /* we're told to make a read-only file writable */
3907 attr.unixModeBits = newScp->unixModeBits | 0222;
3908 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3910 lock_ReleaseMutex(&newScp->mx);
3912 /* now call setattr */
3914 code = cm_SetAttr(newScp, &attr, userp, &req);
3918 cm_ReleaseSCache(newScp);
3919 cm_ReleaseUser(userp);
3924 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3928 cm_scache_t *rootScp;
3929 cm_scache_t *newScp, *dscp;
3941 pathp = smb_GetSMBData(inp, NULL);
3942 pathp = smb_ParseASCIIBlock(pathp, NULL);
3945 return CM_ERROR_BADSMB;
3948 if (*pathp == 0) /* null path */
3951 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3952 osi_LogSaveString(smb_logp, pathp));
3954 rootScp = cm_rootSCachep;
3956 userp = smb_GetUser(vcp, inp);
3958 /* we shouldn't need this for V3 requests, but we seem to */
3959 caseFold = CM_FLAG_CASEFOLD;
3961 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3963 cm_ReleaseUser(userp);
3964 return CM_ERROR_NOSUCHFILE;
3968 * XXX Strange hack XXX
3970 * As of Patch 5 (16 July 97), we are having the following problem:
3971 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3972 * requests to look up "desktop.ini" in all the subdirectories.
3973 * This can cause zillions of timeouts looking up non-existent cells
3974 * and volumes, especially in the top-level directory.
3976 * We have not found any way to avoid this or work around it except
3977 * to explicitly ignore the requests for mount points that haven't
3978 * yet been evaluated and for directories that haven't yet been
3981 * We should modify this hack to provide a fake desktop.ini file
3982 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3984 spacep = inp->spacep;
3985 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3986 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3987 code = cm_NameI(rootScp, spacep->data,
3988 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3989 userp, tidPathp, &req, &dscp);
3991 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3992 && !dscp->mountRootFidp)
3993 code = CM_ERROR_NOSUCHFILE;
3994 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3995 cm_buf_t *bp = buf_Find(dscp, &hzero);
3999 code = CM_ERROR_NOSUCHFILE;
4001 cm_ReleaseSCache(dscp);
4003 cm_ReleaseUser(userp);
4009 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4010 tidPathp, &req, &newScp);
4013 cm_ReleaseUser(userp);
4017 /* now lock the vnode with a callback; returns with newScp locked */
4018 lock_ObtainMutex(&newScp->mx);
4019 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4020 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4022 lock_ReleaseMutex(&newScp->mx);
4023 cm_ReleaseSCache(newScp);
4024 cm_ReleaseUser(userp);
4029 /* use smb_Attributes instead. Also the fact that a file is
4030 * in a readonly volume doesn't mean it shojuld be marked as RO
4032 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
4033 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4034 attrs = SMB_ATTR_DIRECTORY;
4037 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4038 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4040 attrs = smb_Attributes(newScp);
4043 smb_SetSMBParm(outp, 0, attrs);