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
12 #include <afs/param.h>
18 #include <sys/timeb.h>
34 #include "lanahelper.h"
36 /* These characters are illegal in Windows filenames */
37 static char *illegalChars = "\\/:*?\"<>|";
38 BOOL isWindows2000 = FALSE;
40 smb_vc_t *dead_vcp = NULL;
41 smb_vc_t *active_vcp = NULL;
43 /* TODO; logout mechanism needs to be thread-safe */
44 char *loggedOutName = NULL;
45 smb_user_t *loggedOutUserp = NULL;
48 int smbShutdownFlag = 0;
50 int smb_LogoffTokenTransfer;
51 time_t smb_LogoffTransferTimeout;
53 DWORD last_msg_time = 0;
57 unsigned int sessionGen = 0;
59 extern void afsi_log(char *pattern, ...);
60 extern HANDLE afsi_file;
62 osi_hyper_t hzero = {0, 0};
63 osi_hyper_t hones = {0xFFFFFFFF, -1};
66 osi_rwlock_t smb_globalLock;
67 osi_rwlock_t smb_rctLock;
68 osi_mutex_t smb_ListenerLock;
71 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
74 long smb_maxObsConcurrentCalls=0;
75 long smb_concurrentCalls=0;
77 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
79 smb_packet_t *smb_packetFreeListp;
80 smb_ncb_t *smb_ncbFreeListp;
82 int smb_NumServerThreads;
84 int numNCBs, numSessions, numVCs;
86 int smb_maxVCPerServer;
87 int smb_maxMpxRequests;
89 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
91 ULONG smb_lsaSecPackage;
92 LSA_STRING smb_lsaLogonOrigin;
94 #define NCBmax MAXIMUM_WAIT_OBJECTS
95 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
96 EVENT_HANDLE **NCBreturns;
97 DWORD NCBsessions[NCBmax];
99 struct smb_packet *bufs[NCBmax];
101 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
102 EVENT_HANDLE SessionEvents[Sessionmax];
103 unsigned short LSNs[Sessionmax];
104 int lanas[Sessionmax];
105 BOOL dead_sessions[Sessionmax];
109 osi_mutex_t smb_RawBufLock;
111 #define SMB_RAW_BUFS 4
113 int smb_RawBufSel[SMB_RAW_BUFS];
118 #define SMB_MASKFLAG_TILDE 1
119 #define SMB_MASKFLAG_CASEFOLD 2
121 #define RAWTIMEOUT INFINITE
124 typedef struct raw_write_cont {
137 /* dir search stuff */
138 long smb_dirSearchCounter = 1;
139 smb_dirSearch_t *smb_firstDirSearchp;
140 smb_dirSearch_t *smb_lastDirSearchp;
142 /* hide dot files? */
143 int smb_hideDotFiles;
145 /* global state about V3 protocols */
146 int smb_useV3; /* try to negotiate V3 */
149 static showErrors = 1;
150 /* MessageBox or something like it */
151 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
152 extern HANDLE WaitToTerminate;
156 * Time in Unix format of midnight, 1/1/1970 local time.
157 * When added to dosUTime, gives Unix (AFS) time.
159 long smb_localZero = 0;
161 /* Time difference for converting to kludge-GMT */
164 char *smb_localNamep = NULL;
166 smb_vc_t *smb_allVCsp;
168 smb_username_t *usernamesp = NULL;
170 smb_waitingLock_t *smb_allWaitingLocks;
173 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
174 NCB *ncbp, raw_write_cont_t *rwcp);
175 void smb_NetbiosInit();
177 #ifndef AFS_WIN95_ENV
178 DWORD smb_ServerExceptionFilter(void);
181 extern char cm_HostName[];
182 extern char cm_confDir[];
186 #define LPTSTR char *
187 #define GetComputerName(str, sizep) \
188 strcpy((str), cm_HostName); \
189 *(sizep) = strlen(cm_HostName)
192 extern char AFSConfigKeyName[];
194 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
195 int smb_ServerDomainNameLength = 0;
196 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
197 int smb_ServerOSLength = sizeof(smb_ServerOS);
198 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
199 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
201 /* Faux server GUID. This is never checked. */
202 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
207 * To build an expiring version, comment out the definition of NOEXPIRE,
208 * and set the definition of EXPIREDATE to the desired value.
211 #define EXPIREDATE 834000000 /* Wed Jun 5 1996 */
214 char * myCrt_Dispatch(int i)
219 return "unknown SMB op";
221 return "(00)ReceiveCoreMakeDir";
223 return "(01)ReceiveCoreRemoveDir";
225 return "(02)ReceiveCoreOpen";
227 return "(03)ReceiveCoreCreate";
229 return "(04)ReceiveCoreClose";
231 return "(05)ReceiveCoreFlush";
233 return "(06)ReceiveCoreUnlink";
235 return "(07)ReceiveCoreRename";
237 return "(08)ReceiveCoreGetFileAttributes";
239 return "(09)ReceiveCoreSetFileAttributes";
241 return "(0a)ReceiveCoreRead";
243 return "(0b)ReceiveCoreWrite";
245 return "(0c)ReceiveCoreLockRecord";
247 return "(0d)ReceiveCoreUnlockRecord";
249 return "(0e)SendCoreBadOp";
251 return "(0f)ReceiveCoreCreate";
253 return "(10)ReceiveCoreCheckPath";
255 return "(11)SendCoreBadOp";
257 return "(12)ReceiveCoreSeek";
259 return "(1a)ReceiveCoreReadRaw";
261 return "(1d)ReceiveCoreWriteRawDummy";
263 return "(22)ReceiveV3SetAttributes";
265 return "(23)ReceiveV3GetAttributes";
267 return "(24)ReceiveV3LockingX";
269 return "(25)ReceiveV3Trans";
271 return "(26)ReceiveV3Trans[aux]";
273 return "(29)SendCoreBadOp";
275 return "(2b)ReceiveCoreEcho";
277 return "(2d)ReceiveV3OpenX";
279 return "(2e)ReceiveV3ReadX";
281 return "(32)ReceiveV3Tran2A";
283 return "(33)ReceiveV3Tran2A[aux]";
285 return "(34)ReceiveV3FindClose";
287 return "(35)ReceiveV3FindNotifyClose";
289 return "(70)ReceiveCoreTreeConnect";
291 return "(71)ReceiveCoreTreeDisconnect";
293 return "(72)ReceiveNegotiate";
295 return "(73)ReceiveV3SessionSetupX";
297 return "(74)ReceiveV3UserLogoffX";
299 return "(75)ReceiveV3TreeConnectX";
301 return "(80)ReceiveCoreGetDiskAttributes";
303 return "(81)ReceiveCoreSearchDir";
305 return "(A0)ReceiveNTTransact";
307 return "(A2)ReceiveNTCreateX";
309 return "(A4)ReceiveNTCancel";
311 return "(c0)SendCoreBadOp";
313 return "(c1)SendCoreBadOp";
315 return "(c2)SendCoreBadOp";
317 return "(c3)SendCoreBadOp";
321 char * myCrt_2Dispatch(int i)
326 return "unknown SMB op-2";
328 return "S(00)CreateFile";
330 return "S(01)FindFirst";
332 return "S(02)FindNext"; /* FindNext */
334 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
338 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
340 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
342 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
344 return "S(08)??_ReceiveTran2SetFileInfo";
346 return "S(09)??_ReceiveTran2FSCTL";
348 return "S(0a)_ReceiveTran2IOCTL";
350 return "S(0b)_ReceiveTran2FindNotifyFirst";
352 return "S(0c)_ReceiveTran2FindNotifyNext";
354 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
358 char * myCrt_RapDispatch(int i)
363 return "unknown RAP OP";
365 return "RAP(0)NetShareEnum";
367 return "RAP(1)NetShareGetInfo";
369 return "RAP(13)NetServerGetInfo";
371 return "RAP(63)NetWkStaGetInfo";
375 /* scache must be locked */
376 unsigned int smb_Attributes(cm_scache_t *scp)
380 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
381 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
382 attrs = SMB_ATTR_DIRECTORY;
387 * We used to mark a file RO if it was in an RO volume, but that
388 * turns out to be impolitic in NT. See defect 10007.
391 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
393 if ((scp->unixModeBits & 0222) == 0)
394 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
399 /* Check if the named file/dir is a dotfile/dotdir */
400 /* String pointed to by lastComp can have leading slashes, but otherwise should have
401 no other patch components */
402 unsigned int smb_IsDotFile(char *lastComp) {
405 /* skip over slashes */
406 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
411 /* nulls, curdir and parent dir doesn't count */
414 if(!*(s + 1)) return 0;
415 if(*(s+1) == '.' && !*(s + 2)) return 0;
421 static int ExtractBits(WORD bits, short start, short len)
428 num = bits << (16 - end);
429 num = num >> ((16 - end) + start);
435 void ShowUnixTime(char *FuncName, time_t unixTime)
440 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
442 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
443 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
445 int day, month, year, sec, min, hour;
448 day = ExtractBits(wDate, 0, 5);
449 month = ExtractBits(wDate, 5, 4);
450 year = ExtractBits(wDate, 9, 7) + 1980;
452 sec = ExtractBits(wTime, 0, 5);
453 min = ExtractBits(wTime, 5, 6);
454 hour = ExtractBits(wTime, 11, 5);
456 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
457 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
463 /* Determine if we are observing daylight savings time */
464 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
466 TIME_ZONE_INFORMATION timeZoneInformation;
467 SYSTEMTIME utc, local, localDST;
469 /* Get the time zone info. NT uses this to calc if we are in DST. */
470 GetTimeZoneInformation(&timeZoneInformation);
472 /* Return the daylight bias */
473 *pDstBias = timeZoneInformation.DaylightBias;
475 /* Return the bias */
476 *pBias = timeZoneInformation.Bias;
478 /* Now determine if DST is being observed */
480 /* Get the UTC (GMT) time */
483 /* Convert UTC time to local time using the time zone info. If we are
484 observing DST, the calculated local time will include this.
486 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
488 /* Set the daylight bias to 0. The daylight bias is the amount of change
489 in time that we use for daylight savings time. By setting this to 0
490 we cause there to be no change in time during daylight savings time.
492 timeZoneInformation.DaylightBias = 0;
494 /* Convert the utc time to local time again, but this time without any
495 adjustment for daylight savings time.
497 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
499 /* If the two times are different, then it means that the localDST that
500 we calculated includes the daylight bias, and therefore we are
501 observing daylight savings time.
503 *pDST = localDST.wHour != local.wHour;
506 /* Determine if we are observing daylight savings time */
507 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
513 *pDstBias = -60; /* where can this be different? */
519 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
521 BOOL dst; /* Will be TRUE if observing DST */
522 LONG dstBias; /* Offset from local time if observing DST */
523 LONG bias; /* Offset from GMT for local time */
526 * This function will adjust the last write time to compensate
527 * for two bugs in the smb client:
529 * 1) During Daylight Savings Time, the LastWriteTime is ahead
530 * in time by the DaylightBias (ignoring the sign - the
531 * DaylightBias is always stored as a negative number). If
532 * the DaylightBias is -60, then the LastWriteTime will be
533 * ahead by 60 minutes.
535 * 2) If the local time zone is a positive offset from GMT, then
536 * the LastWriteTime will be the correct local time plus the
537 * Bias (ignoring the sign - a positive offset from GMT is
538 * always stored as a negative Bias). If the Bias is -120,
539 * then the LastWriteTime will be ahead by 120 minutes.
541 * These bugs can occur at the same time.
544 GetTimeZoneInfo(&dst, &dstBias, &bias);
546 /* First adjust for DST */
548 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
550 /* Now adjust for a positive offset from GMT (a negative bias). */
552 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
556 * Calculate the difference (in seconds) between local time and GMT.
557 * This enables us to convert file times to kludge-GMT.
563 struct tm gmt_tm, local_tm;
564 int days, hours, minutes, seconds;
567 gmt_tm = *(gmtime(&t));
568 local_tm = *(localtime(&t));
570 days = local_tm.tm_yday - gmt_tm.tm_yday;
571 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
573 /* There is a problem with DST immediately after the time change
574 * which may continue to exist until the machine is rebooted
576 - (local_tm.tm_isdst ? 1 : 0)
579 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
580 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
586 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
591 time_t ersatz_unixTime;
594 * Must use kludge-GMT instead of real GMT.
595 * kludge-GMT is computed by adding time zone difference to localtime.
598 * ltp = gmtime(&unixTime);
600 ersatz_unixTime = unixTime - smb_NowTZ;
601 ltp = localtime(&ersatz_unixTime);
603 /* if we fail, make up something */
606 localJunk.tm_year = 89 - 20;
607 localJunk.tm_mon = 4;
608 localJunk.tm_mday = 12;
609 localJunk.tm_hour = 0;
610 localJunk.tm_min = 0;
611 localJunk.tm_sec = 0;
614 stm.wYear = ltp->tm_year + 1900;
615 stm.wMonth = ltp->tm_mon + 1;
616 stm.wDayOfWeek = ltp->tm_wday;
617 stm.wDay = ltp->tm_mday;
618 stm.wHour = ltp->tm_hour;
619 stm.wMinute = ltp->tm_min;
620 stm.wSecond = ltp->tm_sec;
621 stm.wMilliseconds = 0;
623 SystemTimeToFileTime(&stm, largeTimep);
626 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
628 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
629 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
630 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
632 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
634 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
635 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
637 *ft = LargeIntegerMultiplyByLong(*ft, 60);
638 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
641 ut = ConvertLongToLargeInteger(unixTime);
642 ut = LargeIntegerMultiplyByLong(ut, 10000000);
643 *ft = LargeIntegerAdd(*ft, ut);
648 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
654 FileTimeToSystemTime(largeTimep, &stm);
656 lt.tm_year = stm.wYear - 1900;
657 lt.tm_mon = stm.wMonth - 1;
658 lt.tm_wday = stm.wDayOfWeek;
659 lt.tm_mday = stm.wDay;
660 lt.tm_hour = stm.wHour;
661 lt.tm_min = stm.wMinute;
662 lt.tm_sec = stm.wSecond;
665 save_timezone = _timezone;
666 _timezone += smb_NowTZ;
667 *unixTimep = mktime(<);
668 _timezone = save_timezone;
671 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
673 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
674 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
675 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
679 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
680 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
681 a = LargeIntegerMultiplyByLong(a, 60);
682 a = LargeIntegerMultiplyByLong(a, 10000000);
684 /* subtract it from ft */
685 a = LargeIntegerSubtract(*ft, a);
687 /* divide down to seconds */
688 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
692 void smb_SearchTimeFromUnixTime(long *dosTimep, time_t unixTime)
700 ltp = localtime((time_t*) &t);
702 /* if we fail, make up something */
705 localJunk.tm_year = 89 - 20;
706 localJunk.tm_mon = 4;
707 localJunk.tm_mday = 12;
708 localJunk.tm_hour = 0;
709 localJunk.tm_min = 0;
710 localJunk.tm_sec = 0;
713 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
714 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
715 *dosTimep = (dosDate<<16) | dosTime;
718 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
720 unsigned short dosDate;
721 unsigned short dosTime;
724 dosDate = searchTime & 0xffff;
725 dosTime = (searchTime >> 16) & 0xffff;
727 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
728 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
729 localTm.tm_mday = (dosDate) & 0x1f;
730 localTm.tm_hour = (dosTime>>11) & 0x1f;
731 localTm.tm_min = (dosTime >> 5) & 0x3f;
732 localTm.tm_sec = (dosTime & 0x1f) * 2;
733 localTm.tm_isdst = -1; /* compute whether DST in effect */
735 *unixTimep = mktime(&localTm);
738 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
740 *dosUTimep = unixTime - smb_localZero;
743 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
746 *unixTimep = dosTime + smb_localZero;
748 /* dosTime seems to be already adjusted for GMT */
749 *unixTimep = dosTime;
753 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
757 lock_ObtainWrite(&smb_rctLock);
758 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
759 if (lsn == vcp->lsn && lana == vcp->lana) {
764 if (!vcp && (flags & SMB_FLAG_CREATE)) {
765 vcp = malloc(sizeof(*vcp));
766 memset(vcp, 0, sizeof(*vcp));
767 vcp->vcID = numVCs++;
771 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
772 vcp->nextp = smb_allVCsp;
774 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
779 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
780 /* We must obtain a challenge for extended auth
781 * in case the client negotiates smb v3
784 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
785 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
788 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
790 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
797 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
799 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
800 LsaFreeReturnBuffer(lsaResp);
803 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
805 lock_ReleaseWrite(&smb_rctLock);
809 int smb_IsStarMask(char *maskp)
814 for(i=0; i<11; i++) {
816 if (tc == '?' || tc == '*' || tc == '>') return 1;
821 void smb_ReleaseVC(smb_vc_t *vcp)
823 lock_ObtainWrite(&smb_rctLock);
824 osi_assert(vcp->refCount-- > 0);
825 lock_ReleaseWrite(&smb_rctLock);
828 void smb_HoldVC(smb_vc_t *vcp)
830 lock_ObtainWrite(&smb_rctLock);
832 lock_ReleaseWrite(&smb_rctLock);
835 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
839 lock_ObtainWrite(&smb_rctLock);
840 for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
841 if (tid == tidp->tid) {
846 if (!tidp && (flags & SMB_FLAG_CREATE)) {
847 tidp = malloc(sizeof(*tidp));
848 memset(tidp, 0, sizeof(*tidp));
849 tidp->nextp = vcp->tidsp;
854 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
857 lock_ReleaseWrite(&smb_rctLock);
861 void smb_ReleaseTID(smb_tid_t *tidp)
870 lock_ObtainWrite(&smb_rctLock);
871 osi_assert(tidp->refCount-- > 0);
872 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
873 ltpp = &tidp->vcp->tidsp;
874 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
875 if (tp == tidp) break;
877 osi_assert(tp != NULL);
879 lock_FinalizeMutex(&tidp->mx);
880 userp = tidp->userp; /* remember to drop ref later */
883 lock_ReleaseWrite(&smb_rctLock);
885 cm_ReleaseUser(userp);
892 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
894 smb_user_t *uidp = NULL;
896 lock_ObtainWrite(&smb_rctLock);
897 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
898 if (uid == uidp->userID) {
900 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
901 (int)vcp, uidp->userID,
902 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
906 if (!uidp && (flags & SMB_FLAG_CREATE)) {
907 uidp = malloc(sizeof(*uidp));
908 memset(uidp, 0, sizeof(*uidp));
909 uidp->nextp = vcp->usersp;
914 lock_InitializeMutex(&uidp->mx, "user_t mutex");
916 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 : ""));
918 lock_ReleaseWrite(&smb_rctLock);
922 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
924 smb_username_t *unp= NULL;
926 lock_ObtainWrite(&smb_rctLock);
927 for(unp = usernamesp; unp; unp = unp->nextp) {
928 if (stricmp(unp->name, usern) == 0 &&
929 stricmp(unp->machine, machine) == 0) {
934 if (!unp && (flags & SMB_FLAG_CREATE)) {
935 unp = malloc(sizeof(*unp));
936 memset(unp, 0, sizeof(*unp));
938 unp->nextp = usernamesp;
939 unp->name = strdup(usern);
940 unp->machine = strdup(machine);
942 lock_InitializeMutex(&unp->mx, "username_t mutex");
944 lock_ReleaseWrite(&smb_rctLock);
948 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
950 smb_user_t *uidp= NULL;
952 lock_ObtainWrite(&smb_rctLock);
953 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
956 if (stricmp(uidp->unp->name, usern) == 0) {
958 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
963 lock_ReleaseWrite(&smb_rctLock);
966 void smb_ReleaseUID(smb_user_t *uidp)
975 lock_ObtainWrite(&smb_rctLock);
976 osi_assert(uidp->refCount-- > 0);
977 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
978 lupp = &uidp->vcp->usersp;
979 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
980 if (up == uidp) break;
982 osi_assert(up != NULL);
984 lock_FinalizeMutex(&uidp->mx);
986 userp = uidp->unp->userp; /* remember to drop ref later */
987 uidp->unp->userp = NULL;
992 lock_ReleaseWrite(&smb_rctLock);
994 cm_ReleaseUserVCRef(userp);
995 cm_ReleaseUser(userp);
1002 /* retrieve a held reference to a user structure corresponding to an incoming
1004 * corresponding release function is cm_ReleaseUser.
1006 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1012 smbp = (smb_t *) inp;
1013 uidp = smb_FindUID(vcp, smbp->uid, 0);
1014 if ((!uidp) || (!uidp->unp))
1017 lock_ObtainMutex(&uidp->mx);
1018 up = uidp->unp->userp;
1020 lock_ReleaseMutex(&uidp->mx);
1022 smb_ReleaseUID(uidp);
1028 * Return a pointer to a pathname extracted from a TID structure. The
1029 * TID structure is not held; assume it won't go away.
1031 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1036 tidp = smb_FindTID(vcp, tid, 0);
1040 if(tidp->flags & SMB_TIDFLAG_IPC) {
1041 code = CM_ERROR_TIDIPC;
1042 /* tidp->pathname would be NULL, but that's fine */
1044 *treepath = tidp->pathname;
1045 smb_ReleaseTID(tidp);
1050 /* check to see if we have a chained fid, that is, a fid that comes from an
1051 * OpenAndX message that ran earlier in this packet. In this case, the fid
1052 * field in a read, for example, request, isn't set, since the value is
1053 * supposed to be inherited from the openAndX call.
1055 int smb_ChainFID(int fid, smb_packet_t *inp)
1057 if (inp->fid == 0 || inp->inCount == 0)
1063 /* are we a priv'd user? What does this mean on NT? */
1064 int smb_SUser(cm_user_t *userp)
1069 /* find a file ID. If we pass in 0 we select an used File ID.
1070 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1071 * smb_fid_t data structure if desired File ID cannot be found.
1073 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1078 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1081 lock_ObtainWrite(&smb_rctLock);
1082 /* figure out if we need to allocate a new file ID */
1085 fid = vcp->fidCounter;
1089 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1090 if (fid == fidp->fid) {
1101 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1102 char eventName[MAX_PATH];
1104 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1105 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1106 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1107 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1108 thrd_CloseHandle(event);
1115 fidp = malloc(sizeof(*fidp));
1116 memset(fidp, 0, sizeof(*fidp));
1117 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1121 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1123 fidp->curr_chunk = fidp->prev_chunk = -2;
1124 fidp->raw_write_event = event;
1126 vcp->fidCounter = fid+1;
1127 if (vcp->fidCounter == 0)
1128 vcp->fidCounter = 1;
1131 lock_ReleaseWrite(&smb_rctLock);
1135 void smb_ReleaseFID(smb_fid_t *fidp)
1138 smb_vc_t *vcp = NULL;
1139 smb_ioctl_t *ioctlp;
1145 lock_ObtainWrite(&smb_rctLock);
1146 osi_assert(fidp->refCount-- > 0);
1147 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1149 if (!(fidp->flags & SMB_FID_IOCTL))
1151 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1152 thrd_CloseHandle(fidp->raw_write_event);
1154 /* and see if there is ioctl stuff to free */
1155 ioctlp = fidp->ioctlp;
1157 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1158 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1159 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1165 /* do not call smb_ReleaseVC() because we already have the lock */
1168 lock_ReleaseWrite(&smb_rctLock);
1170 /* now release the scache structure */
1172 cm_ReleaseSCache(scp);
1176 * Case-insensitive search for one string in another;
1177 * used to find variable names in submount pathnames.
1179 static char *smb_stristr(char *str1, char *str2)
1183 for (cursor = str1; *cursor; cursor++)
1184 if (stricmp(cursor, str2) == 0)
1191 * Substitute a variable value for its name in a submount pathname. Variable
1192 * name has been identified by smb_stristr() and is in substr. Variable name
1193 * length (plus one) is in substr_size. Variable value is in newstr.
1195 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1200 strcpy(temp, substr + substr_size - 1);
1201 strcpy(substr, newstr);
1205 char VNUserName[] = "%USERNAME%";
1206 char VNLCUserName[] = "%LCUSERNAME%";
1207 char VNComputerName[] = "%COMPUTERNAME%";
1208 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1211 /* List available shares */
1212 int smb_ListShares()
1216 char shareBuf[4096];
1224 /*strcpy(shareNameList[num_shares], "all");
1225 strcpy(pathNameList[num_shares++], "/afs");*/
1226 fprintf(stderr, "The following shares are available:\n");
1227 fprintf(stderr, "Share Name (AFS Path)\n");
1228 fprintf(stderr, "---------------------\n");
1229 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1232 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1233 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1235 strcpy(sbmtpath, cm_confDir);
1237 strcat(sbmtpath, "/afsdsbmt.ini");
1238 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1239 shareBuf, sizeof(shareBuf),
1245 this_share = shareBuf;
1249 /*strcpy(shareNameList[num_shares], this_share);*/
1250 len = GetPrivateProfileString("AFS Submounts", this_share,
1257 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1260 if (*p == '\\') *p = '/'; /* change to / */
1264 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1265 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1268 while (*this_share != 0) this_share++; /* find next NUL */
1269 this_share++; /* skip past the NUL */
1270 } while (*this_share != 0); /* stop at final NUL */
1276 typedef struct smb_findShare_rock {
1280 } smb_findShare_rock_t;
1282 #define SMB_FINDSHARE_EXACT_MATCH 1
1283 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1285 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1289 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1290 if(!strnicmp(dep->name, vrock->shareName, 12)) {
1291 if(!stricmp(dep->name, vrock->shareName))
1292 matchType = SMB_FINDSHARE_EXACT_MATCH;
1294 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1295 if(vrock->match) free(vrock->match);
1296 vrock->match = strdup(dep->name);
1297 vrock->matchType = matchType;
1299 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1300 return CM_ERROR_STOPNOW;
1306 /* find a shareName in the table of submounts */
1307 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1311 char pathName[1024];
1316 char sbmtpath[MAX_PATH];
1321 DWORD allSubmount = 1;
1323 /* if allSubmounts == 0, only return the //mountRoot/all share
1324 * if in fact it has been been created in the subMounts table.
1325 * This is to allow sites that want to restrict access to the
1328 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1329 0, KEY_QUERY_VALUE, &parmKey);
1330 if (code == ERROR_SUCCESS) {
1331 len = sizeof(allSubmount);
1332 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1333 (BYTE *) &allSubmount, &len);
1334 if (code != ERROR_SUCCESS) {
1337 RegCloseKey (parmKey);
1340 if (allSubmount && _stricmp(shareName, "all") == 0) {
1345 /* In case, the all share is disabled we need to still be able
1346 * to handle ioctl requests
1348 if (_stricmp(shareName, "ioctl$") == 0) {
1349 *pathNamep = strdup("/.__ioctl__");
1353 if (_stricmp(shareName, "IPC$") == 0 ||
1354 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1355 _stricmp(shareName, "DESKTOP.INI") == 0
1362 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1363 0, KEY_QUERY_VALUE, &parmKey);
1364 if (code == ERROR_SUCCESS) {
1365 len = sizeof(pathName);
1366 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1367 (BYTE *) pathName, &len);
1368 if (code != ERROR_SUCCESS)
1370 RegCloseKey (parmKey);
1375 strcpy(sbmtpath, cm_confDir);
1376 strcat(sbmtpath, "/afsdsbmt.ini");
1377 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1378 pathName, sizeof(pathName), sbmtpath);
1380 if (len != 0 && len != sizeof(pathName) - 1) {
1381 /* We can accept either unix or PC style AFS pathnames. Convert
1382 * Unix-style to PC style here for internal use.
1385 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1386 p += strlen(cm_mountRoot); /* skip mount path */
1389 if (*q == '/') *q = '\\'; /* change to \ */
1395 if (var = smb_stristr(p, VNUserName)) {
1396 if (uidp && uidp->unp)
1397 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1399 smb_subst(p, var, sizeof(VNUserName)," ");
1401 else if (var = smb_stristr(p, VNLCUserName))
1403 if (uidp && uidp->unp)
1404 strcpy(temp, uidp->unp->name);
1408 smb_subst(p, var, sizeof(VNLCUserName), temp);
1410 else if (var = smb_stristr(p, VNComputerName))
1412 sizeTemp = sizeof(temp);
1413 GetComputerName((LPTSTR)temp, &sizeTemp);
1414 smb_subst(p, var, sizeof(VNComputerName), temp);
1416 else if (var = smb_stristr(p, VNLCComputerName))
1418 sizeTemp = sizeof(temp);
1419 GetComputerName((LPTSTR)temp, &sizeTemp);
1421 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1426 *pathNamep = strdup(p);
1431 /* First lookup shareName in root.afs */
1433 smb_findShare_rock_t vrock;
1435 char * p = shareName;
1438 /* attempt to locate a partial match in root.afs. This is because
1439 when using the ANSI RAP calls, the share name is limited to 13 chars
1440 and hence is truncated. Of course we prefer exact matches. */
1442 thyper.HighPart = 0;
1445 vrock.shareName = shareName;
1447 vrock.matchType = 0;
1449 cm_HoldSCache(cm_rootSCachep);
1450 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1451 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1452 cm_ReleaseSCache(cm_rootSCachep);
1454 if(vrock.matchType) {
1455 sprintf(pathName,"/%s/",vrock.match);
1456 *pathNamep = strdup(strlwr(pathName));
1461 /* if we get here, there was no match for the share in root.afs */
1462 /* so try to create \\<netbiosName>\<cellname> */
1467 /* Get the full name for this cell */
1468 code = cm_SearchCellFile(p, temp, 0, 0);
1469 #ifdef AFS_AFSDB_ENV
1470 if (code && cm_dnsEnabled) {
1472 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1475 /* construct the path */
1477 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1478 *pathNamep = strdup(strlwr(pathName));
1487 /* Client-side offline caching policy types */
1488 #define CSC_POLICY_MANUAL 0
1489 #define CSC_POLICY_DOCUMENTS 1
1490 #define CSC_POLICY_PROGRAMS 2
1491 #define CSC_POLICY_DISABLE 3
1493 int smb_FindShareCSCPolicy(char *shareName)
1499 int retval = CSC_POLICY_MANUAL;
1501 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1502 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1505 REG_OPTION_NON_VOLATILE,
1511 len = sizeof(policy);
1512 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1514 retval = CSC_POLICY_MANUAL;
1516 else if (stricmp(policy, "documents") == 0)
1518 retval = CSC_POLICY_DOCUMENTS;
1520 else if (stricmp(policy, "programs") == 0)
1522 retval = CSC_POLICY_PROGRAMS;
1524 else if (stricmp(policy, "disable") == 0)
1526 retval = CSC_POLICY_DISABLE;
1529 RegCloseKey(hkCSCPolicy);
1533 /* find a dir search structure by cookie value, and return it held.
1534 * Must be called with smb_globalLock held.
1536 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1538 smb_dirSearch_t *dsp;
1540 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1541 if (dsp->cookie == cookie) {
1542 if (dsp != smb_firstDirSearchp) {
1543 /* move to head of LRU queue, too, if we're not already there */
1544 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1545 smb_lastDirSearchp = (smb_dirSearch_t *)
1547 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1548 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1549 if (!smb_lastDirSearchp)
1550 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1559 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1561 lock_ObtainWrite(&smb_globalLock);
1562 dsp->flags |= SMB_DIRSEARCH_DELETE;
1563 lock_ReleaseWrite(&smb_globalLock);
1564 lock_ObtainMutex(&dsp->mx);
1565 if(dsp->scp != NULL) {
1566 lock_ObtainMutex(&dsp->scp->mx);
1567 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1568 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1569 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1570 dsp->scp->bulkStatProgress = hones;
1572 lock_ReleaseMutex(&dsp->scp->mx);
1574 lock_ReleaseMutex(&dsp->mx);
1577 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1583 lock_ObtainWrite(&smb_globalLock);
1584 osi_assert(dsp->refCount-- > 0);
1585 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1586 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1587 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1588 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1589 lock_FinalizeMutex(&dsp->mx);
1593 lock_ReleaseWrite(&smb_globalLock);
1595 /* do this now to avoid spurious locking hierarchy creation */
1596 if (scp) cm_ReleaseSCache(scp);
1599 /* find a dir search structure by cookie value, and return it held */
1600 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1602 smb_dirSearch_t *dsp;
1604 lock_ObtainWrite(&smb_globalLock);
1605 dsp = smb_FindDirSearchNL(cookie);
1606 lock_ReleaseWrite(&smb_globalLock);
1610 /* GC some dir search entries, in the address space expected by the specific protocol.
1611 * Must be called with smb_globalLock held; release the lock temporarily.
1613 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1614 void smb_GCDirSearches(int isV3)
1616 smb_dirSearch_t *prevp;
1617 smb_dirSearch_t *tp;
1618 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1622 victimCount = 0; /* how many have we got so far */
1623 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1624 /* we'll move tp from queue, so
1627 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1628 /* if no one is using this guy, and we're either in the new protocol,
1629 * or we're in the old one and this is a small enough ID to be useful
1630 * to the old protocol, GC this guy.
1632 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1633 /* hold and delete */
1634 tp->flags |= SMB_DIRSEARCH_DELETE;
1635 victimsp[victimCount++] = tp;
1639 /* don't do more than this */
1640 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1643 /* now release them */
1644 lock_ReleaseWrite(&smb_globalLock);
1645 for(i = 0; i < victimCount; i++) {
1646 smb_ReleaseDirSearch(victimsp[i]);
1648 lock_ObtainWrite(&smb_globalLock);
1651 /* function for allocating a dir search entry. We need these to remember enough context
1652 * since we don't get passed the path from call to call during a directory search.
1654 * Returns a held dir search structure, and bumps the reference count on the vnode,
1655 * since it saves a pointer to the vnode.
1657 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1659 smb_dirSearch_t *dsp;
1663 lock_ObtainWrite(&smb_globalLock);
1666 /* what's the biggest ID allowed in this version of the protocol */
1667 if (isV3) maxAllowed = 65535;
1668 else maxAllowed = 255;
1671 /* twice so we have enough tries to find guys we GC after one pass;
1672 * 10 extra is just in case I mis-counted.
1674 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1675 __FILE__, __LINE__);
1676 if (smb_dirSearchCounter > maxAllowed) {
1677 smb_dirSearchCounter = 1;
1678 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1680 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1682 /* don't need to watch for refcount zero and deleted, since
1683 * we haven't dropped the global lock.
1686 ++smb_dirSearchCounter;
1690 dsp = malloc(sizeof(*dsp));
1691 memset(dsp, 0, sizeof(*dsp));
1692 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1693 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1694 dsp->cookie = smb_dirSearchCounter;
1695 ++smb_dirSearchCounter;
1697 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1698 dsp->lastTime = osi_Time();
1701 lock_ReleaseWrite(&smb_globalLock);
1705 static smb_packet_t *GetPacket(void)
1709 unsigned int npar, seg, tb_sel;
1712 lock_ObtainWrite(&smb_globalLock);
1713 tbp = smb_packetFreeListp;
1715 smb_packetFreeListp = tbp->nextp;
1716 lock_ReleaseWrite(&smb_globalLock);
1719 tbp = calloc(65540,1);
1721 tbp = malloc(sizeof(smb_packet_t));
1723 tbp->magic = SMB_PACKETMAGIC;
1726 tbp->resumeCode = 0;
1732 tbp->ncb_length = 0;
1737 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1740 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1742 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1744 osi_panic("",__FILE__,__LINE__);
1747 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1752 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1753 tbp->dos_pkt_sel = tb_sel;
1756 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1761 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1765 memcpy(tbp, pkt, sizeof(smb_packet_t));
1766 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1770 static NCB *GetNCB(void)
1775 unsigned int npar, seg, tb_sel;
1778 lock_ObtainWrite(&smb_globalLock);
1779 tbp = smb_ncbFreeListp;
1781 smb_ncbFreeListp = tbp->nextp;
1782 lock_ReleaseWrite(&smb_globalLock);
1785 tbp = calloc(sizeof(*tbp),1);
1787 tbp = malloc(sizeof(*tbp));
1788 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1791 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1793 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1795 osi_panic("",__FILE__,__LINE__);
1797 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1802 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1803 tbp->dos_ncb_sel = tb_sel;
1805 tbp->magic = SMB_NCBMAGIC;
1808 osi_assert(tbp->magic == SMB_NCBMAGIC);
1810 memset(&tbp->ncb, 0, sizeof(NCB));
1813 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1818 void smb_FreePacket(smb_packet_t *tbp)
1820 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1822 lock_ObtainWrite(&smb_globalLock);
1823 tbp->nextp = smb_packetFreeListp;
1824 smb_packetFreeListp = tbp;
1825 tbp->magic = SMB_PACKETMAGIC;
1828 tbp->resumeCode = 0;
1834 tbp->ncb_length = 0;
1836 lock_ReleaseWrite(&smb_globalLock);
1839 static void FreeNCB(NCB *bufferp)
1843 tbp = (smb_ncb_t *) bufferp;
1844 osi_assert(tbp->magic == SMB_NCBMAGIC);
1846 lock_ObtainWrite(&smb_globalLock);
1847 tbp->nextp = smb_ncbFreeListp;
1848 smb_ncbFreeListp = tbp;
1849 lock_ReleaseWrite(&smb_globalLock);
1852 /* get a ptr to the data part of a packet, and its count */
1853 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1857 unsigned char *afterParmsp;
1859 parmBytes = *smbp->wctp << 1;
1860 afterParmsp = smbp->wctp + parmBytes + 1;
1862 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1863 if (nbytesp) *nbytesp = dataBytes;
1865 /* don't forget to skip the data byte count, since it follows
1866 * the parameters; that's where the "2" comes from below.
1868 return (unsigned char *) (afterParmsp + 2);
1871 /* must set all the returned parameters before playing around with the
1872 * data region, since the data region is located past the end of the
1873 * variable number of parameters.
1875 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1877 unsigned char *afterParmsp;
1879 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1881 *afterParmsp++ = dsize & 0xff;
1882 *afterParmsp = (dsize>>8) & 0xff;
1885 /* return the parm'th parameter in the smbp packet */
1886 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1889 unsigned char *parmDatap;
1891 parmCount = *smbp->wctp;
1893 if (parm >= parmCount) {
1898 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1900 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1901 parm, parmCount, smbp->ncb_length);
1904 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1905 1, smbp->ncb_length, ptbuf, smbp);
1906 DeregisterEventSource(h);
1908 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1909 osi_panic(s, __FILE__, __LINE__);
1911 parmDatap = smbp->wctp + (2*parm) + 1;
1913 return parmDatap[0] + (parmDatap[1] << 8);
1916 /* return the parm'th parameter in the smbp packet */
1917 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1920 unsigned char *parmDatap;
1922 parmCount = *smbp->wctp;
1924 if (parm * 2 + offset >= parmCount * 2) {
1929 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1931 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1932 parm, offset, parmCount, smbp->ncb_length);
1935 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1936 1, smbp->ncb_length, ptbuf, smbp);
1937 DeregisterEventSource(h);
1939 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1940 osi_panic(s, __FILE__, __LINE__);
1942 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1944 return parmDatap[0] + (parmDatap[1] << 8);
1947 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1951 /* make sure we have enough slots */
1952 if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1954 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1955 *parmDatap++ = parmValue & 0xff;
1956 *parmDatap = (parmValue>>8) & 0xff;
1959 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1963 /* make sure we have enough slots */
1964 if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1966 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1967 *parmDatap++ = parmValue & 0xff;
1968 *parmDatap++ = (parmValue>>8) & 0xff;
1969 *parmDatap++ = (parmValue>>16) & 0xff;
1970 *parmDatap++ = (parmValue>>24) & 0xff;
1973 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1978 /* make sure we have enough slots */
1979 if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1981 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1983 *parmDatap++ = *parmValuep++;
1986 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1990 /* make sure we have enough slots */
1991 if (*smbp->wctp <= slot) {
1992 if (smbp->oddByte) {
1994 *smbp->wctp = slot+1;
1999 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2000 *parmDatap++ = parmValue & 0xff;
2003 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2007 lastSlashp = strrchr(inPathp, '\\');
2009 *lastComponentp = lastSlashp;
2012 if (inPathp == lastSlashp)
2014 *outPathp++ = *inPathp++;
2023 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2028 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2033 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2039 tlen = inp[0] + (inp[1]<<8);
2040 inp += 2; /* skip length field */
2043 *chainpp = inp + tlen;
2052 /* format a packet as a response */
2053 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2058 outp = (smb_t *) op;
2060 /* zero the basic structure through the smb_wct field, and zero the data
2061 * size field, assuming that wct stays zero; otherwise, you have to
2062 * explicitly set the data size field, too.
2064 inSmbp = (smb_t *) inp;
2065 memset(outp, 0, sizeof(smb_t)+2);
2071 outp->com = inSmbp->com;
2072 outp->tid = inSmbp->tid;
2073 outp->pid = inSmbp->pid;
2074 outp->uid = inSmbp->uid;
2075 outp->mid = inSmbp->mid;
2076 outp->res[0] = inSmbp->res[0];
2077 outp->res[1] = inSmbp->res[1];
2078 op->inCom = inSmbp->com;
2080 outp->reb = 0x80; /* SERVER_RESP */
2081 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2083 /* copy fields in generic packet area */
2084 op->wctp = &outp->wct;
2087 /* send a (probably response) packet; vcp tells us to whom to send it.
2088 * we compute the length by looking at wct and bcc fields.
2090 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2107 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2110 memset((char *)ncbp, 0, sizeof(NCB));
2112 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2113 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2114 extra += tp[0] + (tp[1]<<8);
2115 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2116 extra += 3; /* wct and length fields */
2118 ncbp->ncb_length = extra; /* bytes to send */
2119 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2120 ncbp->ncb_lana_num = vcp->lana;
2121 ncbp->ncb_command = NCBSEND; /* op means send data */
2123 ncbp->ncb_buffer = (char *) inp;/* packet */
2124 code = Netbios(ncbp);
2126 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2127 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2129 /* copy header information from virtual to DOS address space */
2130 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2131 code = Netbios(ncbp, dos_ncb);
2135 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2141 void smb_MapNTError(long code, unsigned long *NTStatusp)
2143 unsigned long NTStatus;
2145 /* map CM_ERROR_* errors to NT 32-bit status codes */
2146 /* NT Status codes are listed in ntstatus.h not winerror.h */
2147 if (code == CM_ERROR_NOSUCHCELL) {
2148 NTStatus = 0xC000000FL; /* No such file */
2150 else if (code == CM_ERROR_NOSUCHVOLUME) {
2151 NTStatus = 0xC000000FL; /* No such file */
2153 else if (code == CM_ERROR_TIMEDOUT) {
2154 NTStatus = 0xC00000CFL; /* Sharing Paused */
2156 else if (code == CM_ERROR_RETRY) {
2157 NTStatus = 0xC000022DL; /* Retry */
2159 else if (code == CM_ERROR_NOACCESS) {
2160 NTStatus = 0xC0000022L; /* Access denied */
2162 else if (code == CM_ERROR_READONLY) {
2163 NTStatus = 0xC00000A2L; /* Write protected */
2165 else if (code == CM_ERROR_NOSUCHFILE) {
2166 NTStatus = 0xC000000FL; /* No such file */
2168 else if (code == CM_ERROR_NOSUCHPATH) {
2169 NTStatus = 0xC000003AL; /* Object path not found */
2171 else if (code == CM_ERROR_TOOBIG) {
2172 NTStatus = 0xC000007BL; /* Invalid image format */
2174 else if (code == CM_ERROR_INVAL) {
2175 NTStatus = 0xC000000DL; /* Invalid parameter */
2177 else if (code == CM_ERROR_BADFD) {
2178 NTStatus = 0xC0000008L; /* Invalid handle */
2180 else if (code == CM_ERROR_BADFDOP) {
2181 NTStatus = 0xC0000022L; /* Access denied */
2183 else if (code == CM_ERROR_EXISTS) {
2184 NTStatus = 0xC0000035L; /* Object name collision */
2186 else if (code == CM_ERROR_NOTEMPTY) {
2187 NTStatus = 0xC0000101L; /* Directory not empty */
2189 else if (code == CM_ERROR_CROSSDEVLINK) {
2190 NTStatus = 0xC00000D4L; /* Not same device */
2192 else if (code == CM_ERROR_NOTDIR) {
2193 NTStatus = 0xC0000103L; /* Not a directory */
2195 else if (code == CM_ERROR_ISDIR) {
2196 NTStatus = 0xC00000BAL; /* File is a directory */
2198 else if (code == CM_ERROR_BADOP) {
2199 NTStatus = 0xC09820FFL; /* SMB no support */
2201 else if (code == CM_ERROR_BADSHARENAME) {
2202 NTStatus = 0xC00000CCL; /* Bad network name */
2204 else if (code == CM_ERROR_NOIPC) {
2206 NTStatus = 0xC0000022L; /* Access Denied */
2208 NTStatus = 0xC000013DL; /* Remote Resources */
2211 else if (code == CM_ERROR_CLOCKSKEW) {
2212 NTStatus = 0xC0000133L; /* Time difference at DC */
2214 else if (code == CM_ERROR_BADTID) {
2215 NTStatus = 0xC0982005L; /* SMB bad TID */
2217 else if (code == CM_ERROR_USESTD) {
2218 NTStatus = 0xC09820FBL; /* SMB use standard */
2220 else if (code == CM_ERROR_QUOTA) {
2221 NTStatus = 0xC0000044L; /* Quota exceeded */
2223 else if (code == CM_ERROR_SPACE) {
2224 NTStatus = 0xC000007FL; /* Disk full */
2226 else if (code == CM_ERROR_ATSYS) {
2227 NTStatus = 0xC0000033L; /* Object name invalid */
2229 else if (code == CM_ERROR_BADNTFILENAME) {
2230 NTStatus = 0xC0000033L; /* Object name invalid */
2232 else if (code == CM_ERROR_WOULDBLOCK) {
2233 NTStatus = 0xC0000055L; /* Lock not granted */
2235 else if (code == CM_ERROR_PARTIALWRITE) {
2236 NTStatus = 0xC000007FL; /* Disk full */
2238 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2239 NTStatus = 0xC0000023L; /* Buffer too small */
2241 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2242 NTStatus = 0xC0000035L; /* Object name collision */
2244 else if (code == CM_ERROR_BADPASSWORD) {
2245 NTStatus = 0xC000006DL; /* unknown username or bad password */
2247 else if (code == CM_ERROR_BADLOGONTYPE) {
2248 NTStatus = 0xC000015BL; /* logon type not granted */
2250 else if (code == CM_ERROR_GSSCONTINUE) {
2251 NTStatus = 0xC0000016L; /* more processing required */
2254 NTStatus = 0xC0982001L; /* SMB non-specific error */
2257 *NTStatusp = NTStatus;
2258 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2261 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2262 unsigned char *classp)
2264 unsigned char class;
2265 unsigned short error;
2267 /* map CM_ERROR_* errors to SMB errors */
2268 if (code == CM_ERROR_NOSUCHCELL) {
2270 error = 3; /* bad path */
2272 else if (code == CM_ERROR_NOSUCHVOLUME) {
2274 error = 3; /* bad path */
2276 else if (code == CM_ERROR_TIMEDOUT) {
2278 error = 81; /* server is paused */
2280 else if (code == CM_ERROR_RETRY) {
2281 class = 2; /* shouldn't happen */
2284 else if (code == CM_ERROR_NOACCESS) {
2286 error = 4; /* bad access */
2288 else if (code == CM_ERROR_READONLY) {
2290 error = 19; /* read only */
2292 else if (code == CM_ERROR_NOSUCHFILE) {
2294 error = 2; /* ENOENT! */
2296 else if (code == CM_ERROR_NOSUCHPATH) {
2298 error = 3; /* Bad path */
2300 else if (code == CM_ERROR_TOOBIG) {
2302 error = 11; /* bad format */
2304 else if (code == CM_ERROR_INVAL) {
2305 class = 2; /* server non-specific error code */
2308 else if (code == CM_ERROR_BADFD) {
2310 error = 6; /* invalid file handle */
2312 else if (code == CM_ERROR_BADFDOP) {
2313 class = 1; /* invalid op on FD */
2316 else if (code == CM_ERROR_EXISTS) {
2318 error = 80; /* file already exists */
2320 else if (code == CM_ERROR_NOTEMPTY) {
2322 error = 5; /* delete directory not empty */
2324 else if (code == CM_ERROR_CROSSDEVLINK) {
2326 error = 17; /* EXDEV */
2328 else if (code == CM_ERROR_NOTDIR) {
2329 class = 1; /* bad path */
2332 else if (code == CM_ERROR_ISDIR) {
2333 class = 1; /* access denied; DOS doesn't have a good match */
2336 else if (code == CM_ERROR_BADOP) {
2340 else if (code == CM_ERROR_BADSHARENAME) {
2344 else if (code == CM_ERROR_NOIPC) {
2346 error = 4; /* bad access */
2348 else if (code == CM_ERROR_CLOCKSKEW) {
2349 class = 1; /* invalid function */
2352 else if (code == CM_ERROR_BADTID) {
2356 else if (code == CM_ERROR_USESTD) {
2360 else if (code == CM_ERROR_REMOTECONN) {
2364 else if (code == CM_ERROR_QUOTA) {
2365 if (vcp->flags & SMB_VCFLAG_USEV3) {
2367 error = 39; /* disk full */
2371 error = 5; /* access denied */
2374 else if (code == CM_ERROR_SPACE) {
2375 if (vcp->flags & SMB_VCFLAG_USEV3) {
2377 error = 39; /* disk full */
2381 error = 5; /* access denied */
2384 else if (code == CM_ERROR_PARTIALWRITE) {
2386 error = 39; /* disk full */
2388 else if (code == CM_ERROR_ATSYS) {
2390 error = 2; /* ENOENT */
2392 else if (code == CM_ERROR_WOULDBLOCK) {
2394 error = 33; /* lock conflict */
2396 else if (code == CM_ERROR_NOFILES) {
2398 error = 18; /* no files in search */
2400 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2402 error = 183; /* Samba uses this */
2404 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2405 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2407 error = 2; /* bad password */
2416 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2419 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2421 return CM_ERROR_BADOP;
2424 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2426 unsigned short EchoCount, i;
2427 char *data, *outdata;
2430 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2432 for (i=1; i<=EchoCount; i++) {
2433 data = smb_GetSMBData(inp, &dataSize);
2434 smb_SetSMBParm(outp, 0, i);
2435 smb_SetSMBDataLength(outp, dataSize);
2436 outdata = smb_GetSMBData(outp, NULL);
2437 memcpy(outdata, data, dataSize);
2438 smb_SendPacket(vcp, outp);
2444 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2447 long count, minCount, finalCount;
2451 cm_user_t *userp = NULL;
2455 char *rawBuf = NULL;
2457 dos_ptr rawBuf = NULL;
2464 fd = smb_GetSMBParm(inp, 0);
2465 count = smb_GetSMBParm(inp, 3);
2466 minCount = smb_GetSMBParm(inp, 4);
2467 offset.HighPart = 0; /* too bad */
2468 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2470 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2471 fd, offset.LowPart, count);
2473 fidp = smb_FindFID(vcp, fd, 0);
2477 lock_ObtainMutex(&smb_RawBufLock);
2479 /* Get a raw buf, from head of list */
2480 rawBuf = smb_RawBufs;
2482 smb_RawBufs = *(char **)smb_RawBufs;
2484 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2487 lock_ReleaseMutex(&smb_RawBufLock);
2491 if (fidp->flags & SMB_FID_IOCTL)
2494 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2496 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2499 /* Give back raw buffer */
2500 lock_ObtainMutex(&smb_RawBufLock);
2502 *((char **) rawBuf) = smb_RawBufs;
2504 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2507 smb_RawBufs = rawBuf;
2508 lock_ReleaseMutex(&smb_RawBufLock);
2511 smb_ReleaseFID(fidp);
2515 userp = smb_GetUser(vcp, inp);
2518 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2520 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2521 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2522 userp, &finalCount, TRUE /* rawFlag */);
2529 cm_ReleaseUser(userp);
2532 smb_ReleaseFID(fidp);
2537 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2539 memset((char *)ncbp, 0, sizeof(NCB));
2541 ncbp->ncb_length = (unsigned short) finalCount;
2542 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2543 ncbp->ncb_lana_num = vcp->lana;
2544 ncbp->ncb_command = NCBSEND;
2545 ncbp->ncb_buffer = rawBuf;
2548 code = Netbios(ncbp);
2550 code = Netbios(ncbp, dos_ncb);
2553 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2556 /* Give back raw buffer */
2557 lock_ObtainMutex(&smb_RawBufLock);
2559 *((char **) rawBuf) = smb_RawBufs;
2561 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2564 smb_RawBufs = rawBuf;
2565 lock_ReleaseMutex(&smb_RawBufLock);
2571 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2576 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2581 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2588 int protoIndex; /* index we're using */
2593 char protocol_array[10][1024]; /* protocol signature of the client */
2594 int caps; /* capabilities */
2597 TIME_ZONE_INFORMATION tzi;
2599 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2603 DWORD now = GetCurrentTime();
2604 if (now - last_msg_time >= 30000
2605 && now - last_msg_time <= 90000) {
2607 "Setting dead_vcp %x", active_vcp);
2609 smb_ReleaseVC(dead_vcp);
2611 "Previous dead_vcp %x", dead_vcp);
2613 smb_HoldVC(active_vcp);
2614 dead_vcp = active_vcp;
2615 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2620 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2622 namep = smb_GetSMBData(inp, &dbytes);
2625 coreProtoIndex = -1; /* not found */
2628 while(namex < dbytes) {
2629 osi_Log1(smb_logp, "Protocol %s",
2630 osi_LogSaveString(smb_logp, namep+1));
2631 strcpy(protocol_array[tcounter], namep+1);
2633 /* namep points at the first protocol, or really, a 0x02
2634 * byte preceding the null-terminated ASCII name.
2636 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2637 coreProtoIndex = tcounter;
2639 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2640 v3ProtoIndex = tcounter;
2642 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2643 NTProtoIndex = tcounter;
2646 /* compute size of protocol entry */
2647 entryLength = strlen(namep+1);
2648 entryLength += 2; /* 0x02 bytes and null termination */
2650 /* advance over this protocol entry */
2651 namex += entryLength;
2652 namep += entryLength;
2653 tcounter++; /* which proto entry we're looking at */
2656 if (NTProtoIndex != -1) {
2657 protoIndex = NTProtoIndex;
2658 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2660 else if (v3ProtoIndex != -1) {
2661 protoIndex = v3ProtoIndex;
2662 vcp->flags |= SMB_VCFLAG_USEV3;
2664 else if (coreProtoIndex != -1) {
2665 protoIndex = coreProtoIndex;
2666 vcp->flags |= SMB_VCFLAG_USECORE;
2668 else protoIndex = -1;
2670 if (protoIndex == -1)
2671 return CM_ERROR_INVAL;
2672 else if (NTProtoIndex != -1) {
2673 smb_SetSMBParm(outp, 0, protoIndex);
2674 if (smb_authType != SMB_AUTH_NONE) {
2675 smb_SetSMBParmByte(outp, 1,
2676 NEGOTIATE_SECURITY_USER_LEVEL |
2677 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2679 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2681 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2682 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2683 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2684 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2685 /* The session key is not a well documented field however most clients
2686 * will echo back the session key to the server. Currently we are using
2687 * the same value for all sessions. We should generate a random value
2688 * and store it into the vcp
2690 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2691 smb_SetSMBParm(outp, 8, 1);
2693 * Tried changing the capabilities to support for W2K - defect 117695
2694 * Maybe something else needs to be changed here?
2698 smb_SetSMBParmLong(outp, 9, 0x43fd);
2700 smb_SetSMBParmLong(outp, 9, 0x251);
2703 * 32-bit error codes *
2707 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2708 NTNEGOTIATE_CAPABILITY_NTFIND |
2709 NTNEGOTIATE_CAPABILITY_RAWMODE |
2710 NTNEGOTIATE_CAPABILITY_NTSMB;
2712 if ( smb_authType == SMB_AUTH_EXTENDED )
2713 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2715 smb_SetSMBParmLong(outp, 9, caps);
2717 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2718 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2719 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2721 GetTimeZoneInformation(&tzi);
2722 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2724 if (smb_authType == SMB_AUTH_NTLM) {
2725 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2726 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2727 /* paste in encryption key */
2728 datap = smb_GetSMBData(outp, NULL);
2729 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2730 /* and the faux domain name */
2731 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2732 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2736 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2738 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2740 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2742 datap = smb_GetSMBData(outp, NULL);
2743 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2746 datap += sizeof(smb_ServerGUID);
2747 memcpy(datap, secBlob, secBlobLength);
2751 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2752 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2755 else if (v3ProtoIndex != -1) {
2756 smb_SetSMBParm(outp, 0, protoIndex);
2758 /* NOTE: Extended authentication cannot be negotiated with v3
2759 * therefore we fail over to NTLM
2761 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2762 smb_SetSMBParm(outp, 1,
2763 NEGOTIATE_SECURITY_USER_LEVEL |
2764 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2766 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2768 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2769 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2770 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2771 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2772 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2773 smb_SetSMBParm(outp, 7, 1);
2775 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2776 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2777 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2779 GetTimeZoneInformation(&tzi);
2780 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2782 /* NOTE: Extended authentication cannot be negotiated with v3
2783 * therefore we fail over to NTLM
2785 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2786 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2787 smb_SetSMBParm(outp, 12, 0); /* resvd */
2788 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2789 datap = smb_GetSMBData(outp, NULL);
2790 /* paste in a new encryption key */
2791 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2792 /* and the faux domain name */
2793 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2795 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2796 smb_SetSMBParm(outp, 12, 0); /* resvd */
2797 smb_SetSMBDataLength(outp, 0);
2800 else if (coreProtoIndex != -1) { /* not really supported anymore */
2801 smb_SetSMBParm(outp, 0, protoIndex);
2802 smb_SetSMBDataLength(outp, 0);
2807 void smb_Daemon(void *parmp)
2809 afs_uint32 count = 0;
2814 if ((count % 72) == 0) { /* every five minutes */
2816 long old_localZero = smb_localZero;
2818 /* Initialize smb_localZero */
2819 myTime.tm_isdst = -1; /* compute whether on DST or not */
2820 myTime.tm_year = 70;
2826 smb_localZero = mktime(&myTime);
2828 smb_CalculateNowTZ();
2830 #ifdef AFS_FREELANCE
2831 if ( smb_localZero != old_localZero )
2832 cm_noteLocalMountPointChange();
2835 /* XXX GC dir search entries */
2839 void smb_WaitingLocksDaemon()
2841 smb_waitingLock_t *wL, *nwL;
2844 smb_packet_t *inp, *outp;
2849 lock_ObtainWrite(&smb_globalLock);
2850 nwL = smb_allWaitingLocks;
2852 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2861 lock_ObtainWrite(&smb_globalLock);
2863 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2864 lock_ReleaseWrite(&smb_globalLock);
2865 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2866 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2867 if (code == CM_ERROR_WOULDBLOCK) {
2869 if (wL->timeRemaining != 0xffffffff
2870 && (wL->timeRemaining -= 1000) < 0)
2879 ncbp->ncb_length = inp->ncb_length;
2880 inp->spacep = cm_GetSpace();
2882 /* Remove waitingLock from list */
2883 lock_ObtainWrite(&smb_globalLock);
2884 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2886 lock_ReleaseWrite(&smb_globalLock);
2888 /* Resume packet processing */
2890 smb_SetSMBDataLength(outp, 0);
2891 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2892 outp->resumeCode = code;
2894 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2897 cm_FreeSpace(inp->spacep);
2898 smb_FreePacket(inp);
2899 smb_FreePacket(outp);
2907 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2909 osi_Log0(smb_logp, "SMB receive get disk attributes");
2911 smb_SetSMBParm(outp, 0, 32000);
2912 smb_SetSMBParm(outp, 1, 64);
2913 smb_SetSMBParm(outp, 2, 1024);
2914 smb_SetSMBParm(outp, 3, 30000);
2915 smb_SetSMBParm(outp, 4, 0);
2916 smb_SetSMBDataLength(outp, 0);
2920 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2924 unsigned short newTid;
2925 char shareName[256];
2933 osi_Log0(smb_logp, "SMB receive tree connect");
2935 /* parse input parameters */
2936 tp = smb_GetSMBData(inp, NULL);
2937 pathp = smb_ParseASCIIBlock(tp, &tp);
2938 passwordp = smb_ParseASCIIBlock(tp, &tp);
2939 tp = strrchr(pathp, '\\');
2941 return CM_ERROR_BADSMB;
2942 strcpy(shareName, tp+1);
2944 userp = smb_GetUser(vcp, inp);
2946 lock_ObtainMutex(&vcp->mx);
2947 newTid = vcp->tidCounter++;
2948 lock_ReleaseMutex(&vcp->mx);
2950 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2951 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2952 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2954 smb_ReleaseUID(uidp);
2956 smb_ReleaseTID(tidp);
2957 return CM_ERROR_BADSHARENAME;
2959 lock_ObtainMutex(&tidp->mx);
2960 tidp->userp = userp;
2961 tidp->pathname = sharePath;
2962 lock_ReleaseMutex(&tidp->mx);
2963 smb_ReleaseTID(tidp);
2965 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2966 smb_SetSMBParm(rsp, 1, newTid);
2967 smb_SetSMBDataLength(rsp, 0);
2969 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2973 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2977 if (*inp++ != 0x1) return NULL;
2978 tlen = inp[0] + (inp[1]<<8);
2979 inp += 2; /* skip length field */
2982 *chainpp = inp + tlen;
2985 if (lengthp) *lengthp = tlen;
2990 /* set maskp to the mask part of the incoming path.
2991 * Mask is 11 bytes long (8.3 with the dot elided).
2992 * Returns true if succeeds with a valid name, otherwise it does
2993 * its best, but returns false.
2995 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3003 /* starts off valid */
3006 /* mask starts out all blanks */
3007 memset(maskp, ' ', 11);
3009 /* find last backslash, or use whole thing if there is none */
3010 tp = strrchr(pathp, '\\');
3011 if (!tp) tp = pathp;
3012 else tp++; /* skip slash */
3016 /* names starting with a dot are illegal */
3017 if (*tp == '.') valid8Dot3 = 0;
3021 if (tc == 0) return valid8Dot3;
3022 if (tc == '.' || tc == '"') break;
3023 if (i < 8) *up++ = tc;
3024 else valid8Dot3 = 0;
3027 /* if we get here, tp point after the dot */
3028 up = maskp+8; /* ext goes here */
3035 if (tc == '.' || tc == '"')
3038 /* copy extension if not too long */
3048 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3058 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3060 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3064 /* otherwise, we have a valid 8.3 name; see if we have a match,
3065 * treating '?' as a wildcard in maskp (but not in the file name).
3067 tp1 = umask; /* real name, in mask format */
3068 tp2 = maskp; /* mask, in mask format */
3069 for(i=0; i<11; i++) {
3070 tc1 = *tp1++; /* char from real name */
3071 tc2 = *tp2++; /* char from mask */
3072 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3073 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3076 if (tc2 == '?' && tc1 != ' ')
3083 /* we got a match */
3087 char *smb_FindMask(char *pathp)
3091 tp = strrchr(pathp, '\\'); /* find last slash */
3094 return tp+1; /* skip the slash */
3096 return pathp; /* no slash, return the entire path */
3099 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3101 unsigned char *pathp;
3103 unsigned char mask[11];
3104 unsigned char *statBlockp;
3105 unsigned char initStatBlock[21];
3108 osi_Log0(smb_logp, "SMB receive search volume");
3110 /* pull pathname and stat block out of request */
3111 tp = smb_GetSMBData(inp, NULL);
3112 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3113 osi_assert(pathp != NULL);
3114 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3115 osi_assert(statBlockp != NULL);
3117 statBlockp = initStatBlock;
3121 /* for returning to caller */
3122 smb_Get8Dot3MaskFromPath(mask, pathp);
3124 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3125 tp = smb_GetSMBData(outp, NULL);
3127 *tp++ = 43; /* bytes in a dir entry */
3128 *tp++ = 0; /* high byte in counter */
3130 /* now marshall the dir entry, starting with the search status */
3131 *tp++ = statBlockp[0]; /* Reserved */
3132 memcpy(tp, mask, 11); tp += 11; /* FileName */
3134 /* now pass back server use info, with 1st byte non-zero */
3136 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3138 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3140 *tp++ = 0x8; /* attribute: volume */
3150 /* 4 byte file size */
3156 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3157 memset(tp, ' ', 13);
3160 /* set the length of the data part of the packet to 43 + 3, for the dir
3161 * entry plus the 5 and the length fields.
3163 smb_SetSMBDataLength(outp, 46);
3167 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3168 cm_user_t *userp, cm_req_t *reqp)
3176 smb_dirListPatch_t *patchp;
3177 smb_dirListPatch_t *npatchp;
3179 for(patchp = *dirPatchespp; patchp; patchp =
3180 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3182 dptr = patchp->dptr;
3184 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3186 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3187 *dptr++ = SMB_ATTR_HIDDEN;
3190 lock_ObtainMutex(&scp->mx);
3191 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3192 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3194 lock_ReleaseMutex(&scp->mx);
3195 cm_ReleaseSCache(scp);
3196 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3197 *dptr++ = SMB_ATTR_HIDDEN;
3201 attr = smb_Attributes(scp);
3202 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3203 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3204 attr |= SMB_ATTR_HIDDEN;
3208 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3211 shortTemp = dosTime & 0xffff;
3212 *((u_short *)dptr) = shortTemp;
3215 /* and copy out date */
3216 shortTemp = (dosTime>>16) & 0xffff;
3217 *((u_short *)dptr) = shortTemp;
3220 /* copy out file length */
3221 *((u_long *)dptr) = scp->length.LowPart;
3223 lock_ReleaseMutex(&scp->mx);
3224 cm_ReleaseSCache(scp);
3227 /* now free the patches */
3228 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3229 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3233 /* and mark the list as empty */
3234 *dirPatchespp = NULL;
3239 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3248 smb_dirListPatch_t *dirListPatchesp;
3249 smb_dirListPatch_t *curPatchp;
3253 osi_hyper_t dirLength;
3254 osi_hyper_t bufferOffset;
3255 osi_hyper_t curOffset;
3257 unsigned char *inCookiep;
3258 smb_dirSearch_t *dsp;
3262 unsigned long clientCookie;
3263 cm_pageHeader_t *pageHeaderp;
3264 cm_user_t *userp = NULL;
3271 long nextEntryCookie;
3272 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3273 char resByte; /* reserved byte from the cookie */
3274 char *op; /* output data ptr */
3275 char *origOp; /* original value of op */
3276 cm_space_t *spacep; /* for pathname buffer */
3287 maxCount = smb_GetSMBParm(inp, 0);
3289 dirListPatchesp = NULL;
3291 caseFold = CM_FLAG_CASEFOLD;
3293 tp = smb_GetSMBData(inp, NULL);
3294 pathp = smb_ParseASCIIBlock(tp, &tp);
3295 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3297 /* bail out if request looks bad */
3298 if (!tp || !pathp) {
3299 return CM_ERROR_BADSMB;
3302 /* We can handle long names */
3303 if (vcp->flags & SMB_VCFLAG_USENT)
3304 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3306 /* make sure we got a whole search status */
3307 if (dataLength < 21) {
3308 nextCookie = 0; /* start at the beginning of the dir */
3311 attribute = smb_GetSMBParm(inp, 1);
3313 /* handle volume info in another function */
3314 if (attribute & 0x8)
3315 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3317 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3318 maxCount, osi_LogSaveString(smb_logp, pathp));
3320 if (*pathp == 0) { /* null pathp, treat as root dir */
3321 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3322 return CM_ERROR_NOFILES;
3326 dsp = smb_NewDirSearch(0);
3327 dsp->attribute = attribute;
3328 smb_Get8Dot3MaskFromPath(mask, pathp);
3329 memcpy(dsp->mask, mask, 11);
3331 /* track if this is likely to match a lot of entries */
3332 if (smb_IsStarMask(mask)) starPattern = 1;
3333 else starPattern = 0;
3336 /* pull the next cookie value out of the search status block */
3337 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3338 + (inCookiep[16]<<24);
3339 dsp = smb_FindDirSearch(inCookiep[12]);
3341 /* can't find dir search status; fatal error */
3342 return CM_ERROR_BADFD;
3344 attribute = dsp->attribute;
3345 resByte = inCookiep[0];
3347 /* copy out client cookie, in host byte order. Don't bother
3348 * interpreting it, since we're just passing it through, anyway.
3350 memcpy(&clientCookie, &inCookiep[17], 4);
3352 memcpy(mask, dsp->mask, 11);
3354 /* assume we're doing a star match if it has continued for more
3360 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3361 nextCookie, dsp->cookie, attribute);
3363 userp = smb_GetUser(vcp, inp);
3365 /* try to get the vnode for the path name next */
3366 lock_ObtainMutex(&dsp->mx);
3373 spacep = inp->spacep;
3374 smb_StripLastComponent(spacep->data, NULL, pathp);
3375 lock_ReleaseMutex(&dsp->mx);
3376 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3378 lock_ReleaseMutex(&dsp->mx);
3379 cm_ReleaseUser(userp);
3380 smb_DeleteDirSearch(dsp);
3381 smb_ReleaseDirSearch(dsp);
3382 return CM_ERROR_NOFILES;
3384 code = cm_NameI(cm_rootSCachep, spacep->data,
3385 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3386 lock_ObtainMutex(&dsp->mx);
3388 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3390 /* we need one hold for the entry we just stored into,
3391 * and one for our own processing. When we're done with this
3392 * function, we'll drop the one for our own processing.
3393 * We held it once from the namei call, and so we do another hold
3397 lock_ObtainMutex(&scp->mx);
3398 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3399 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3400 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3401 dsp->flags |= SMB_DIRSEARCH_BULKST;
3403 lock_ReleaseMutex(&scp->mx);
3406 lock_ReleaseMutex(&dsp->mx);
3408 cm_ReleaseUser(userp);
3409 smb_DeleteDirSearch(dsp);
3410 smb_ReleaseDirSearch(dsp);
3414 /* reserves space for parameter; we'll adjust it again later to the
3415 * real count of the # of entries we returned once we've actually
3416 * assembled the directory listing.
3418 smb_SetSMBParm(outp, 0, 0);
3420 /* get the directory size */
3421 lock_ObtainMutex(&scp->mx);
3422 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3423 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3425 lock_ReleaseMutex(&scp->mx);
3426 cm_ReleaseSCache(scp);
3427 cm_ReleaseUser(userp);
3428 smb_DeleteDirSearch(dsp);
3429 smb_ReleaseDirSearch(dsp);
3433 dirLength = scp->length;
3435 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3436 curOffset.HighPart = 0;
3437 curOffset.LowPart = nextCookie;
3438 origOp = op = smb_GetSMBData(outp, NULL);
3439 /* and write out the basic header */
3440 *op++ = 5; /* variable block */
3441 op += 2; /* skip vbl block length; we'll fill it in later */
3445 /* make sure that curOffset.LowPart doesn't point to the first
3446 * 32 bytes in the 2nd through last dir page, and that it doesn't
3447 * point at the first 13 32-byte chunks in the first dir page,
3448 * since those are dir and page headers, and don't contain useful
3451 temp = curOffset.LowPart & (2048-1);
3452 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3453 /* we're in the first page */
3454 if (temp < 13*32) temp = 13*32;
3457 /* we're in a later dir page */
3458 if (temp < 32) temp = 32;
3461 /* make sure the low order 5 bits are zero */
3464 /* now put temp bits back ito curOffset.LowPart */
3465 curOffset.LowPart &= ~(2048-1);
3466 curOffset.LowPart |= temp;
3468 /* check if we've returned all the names that will fit in the
3471 if (returnedNames >= maxCount)
3474 /* check if we've passed the dir's EOF */
3475 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3477 /* see if we can use the bufferp we have now; compute in which page
3478 * the current offset would be, and check whether that's the offset
3479 * of the buffer we have. If not, get the buffer.
3481 thyper.HighPart = curOffset.HighPart;
3482 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3483 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3486 buf_Release(bufferp);
3489 lock_ReleaseMutex(&scp->mx);
3490 lock_ObtainRead(&scp->bufCreateLock);
3491 code = buf_Get(scp, &thyper, &bufferp);
3492 lock_ReleaseRead(&scp->bufCreateLock);
3494 /* now, if we're doing a star match, do bulk fetching of all of
3495 * the status info for files in the dir.
3498 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3500 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3501 && LargeIntegerGreaterThanOrEqualTo(thyper,
3502 scp->bulkStatProgress)) {
3503 /* Don't bulk stat if risking timeout */
3504 int now = GetCurrentTime();
3505 if (now - req.startTime > 5000) {
3506 scp->bulkStatProgress = thyper;
3507 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3508 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3510 cm_TryBulkStat(scp, &thyper, userp, &req);
3514 lock_ObtainMutex(&scp->mx);
3517 bufferOffset = thyper;
3519 /* now get the data in the cache */
3521 code = cm_SyncOp(scp, bufferp, userp, &req,
3523 CM_SCACHESYNC_NEEDCALLBACK
3524 | CM_SCACHESYNC_READ);
3527 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3529 /* otherwise, load the buffer and try again */
3530 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3535 buf_Release(bufferp);
3539 } /* if (wrong buffer) ... */
3541 /* now we have the buffer containing the entry we're interested in; copy
3542 * it out if it represents a non-deleted entry.
3544 entryInDir = curOffset.LowPart & (2048-1);
3545 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3547 /* page header will help tell us which entries are free. Page header
3548 * can change more often than once per buffer, since AFS 3 dir page size
3549 * may be less than (but not more than a buffer package buffer.
3551 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3552 temp &= ~(2048 - 1); /* turn off intra-page bits */
3553 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3555 /* now determine which entry we're looking at in the page. If it is
3556 * free (there's a free bitmap at the start of the dir), we should
3557 * skip these 32 bytes.
3559 slotInPage = (entryInDir & 0x7e0) >> 5;
3560 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3561 /* this entry is free */
3562 numDirChunks = 1; /* only skip this guy */
3566 tp = bufferp->datap + entryInBuffer;
3567 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3569 /* while we're here, compute the next entry's location, too,
3570 * since we'll need it when writing out the cookie into the dir
3573 * XXXX Probably should do more sanity checking.
3575 numDirChunks = cm_NameEntries(dep->name, NULL);
3577 /* compute the offset of the cookie representing the next entry */
3578 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3580 /* Compute 8.3 name if necessary */
3581 actualName = dep->name;
3582 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3583 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3584 actualName = shortName;
3587 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3588 /* this is one of the entries to use: it is not deleted
3589 * and it matches the star pattern we're looking for.
3592 /* Eliminate entries that don't match requested
3595 /* no hidden files */
3596 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3599 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3601 /* We have already done the cm_TryBulkStat above */
3602 fid.cell = scp->fid.cell;
3603 fid.volume = scp->fid.volume;
3604 fid.vnode = ntohl(dep->fid.vnode);
3605 fid.unique = ntohl(dep->fid.unique);
3606 fileType = cm_FindFileType(&fid);
3607 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3608 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3610 if (fileType == CM_SCACHETYPE_DIRECTORY)
3615 memcpy(op, mask, 11); op += 11;
3616 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3617 *op++ = nextEntryCookie & 0xff;
3618 *op++ = (nextEntryCookie>>8) & 0xff;
3619 *op++ = (nextEntryCookie>>16) & 0xff;
3620 *op++ = (nextEntryCookie>>24) & 0xff;
3621 memcpy(op, &clientCookie, 4); op += 4;
3623 /* now we emit the attribute. This is sort of tricky,
3624 * since we need to really stat the file to find out
3625 * what type of entry we've got. Right now, we're
3626 * copying out data from a buffer, while holding the
3627 * scp locked, so it isn't really convenient to stat
3628 * something now. We'll put in a place holder now,
3629 * and make a second pass before returning this to get
3630 * the real attributes. So, we just skip the data for
3631 * now, and adjust it later. We allocate a patch
3632 * record to make it easy to find this point later.
3633 * The replay will happen at a time when it is safe to
3634 * unlock the directory.
3636 curPatchp = malloc(sizeof(*curPatchp));
3637 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3638 curPatchp->dptr = op;
3639 curPatchp->fid.cell = scp->fid.cell;
3640 curPatchp->fid.volume = scp->fid.volume;
3641 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3642 curPatchp->fid.unique = ntohl(dep->fid.unique);
3644 /* do hidden attribute here since name won't be around when applying
3648 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3649 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3651 curPatchp->flags = 0;
3653 op += 9; /* skip attr, time, date and size */
3655 /* zero out name area. The spec says to pad with
3656 * spaces, but Samba doesn't, and neither do we.
3660 /* finally, we get to copy out the name; we know that
3661 * it fits in 8.3 or the pattern wouldn't match, but it
3662 * never hurts to be sure.
3664 strncpy(op, actualName, 13);
3666 /* Uppercase if requested by client */
3667 if ((((smb_t *)inp)->flg2 & 1) == 0)
3672 /* now, adjust the # of entries copied */
3674 } /* if we're including this name */
3677 /* and adjust curOffset to be where the new cookie is */
3678 thyper.HighPart = 0;
3679 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3680 curOffset = LargeIntegerAdd(thyper, curOffset);
3681 } /* while copying data for dir listing */
3683 /* release the mutex */
3684 lock_ReleaseMutex(&scp->mx);
3685 if (bufferp) buf_Release(bufferp);
3687 /* apply and free last set of patches; if not doing a star match, this
3688 * will be empty, but better safe (and freeing everything) than sorry.
3690 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3692 /* special return code for unsuccessful search */
3693 if (code == 0 && dataLength < 21 && returnedNames == 0)
3694 code = CM_ERROR_NOFILES;
3696 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3697 returnedNames, code);
3700 smb_DeleteDirSearch(dsp);
3701 smb_ReleaseDirSearch(dsp);
3702 cm_ReleaseSCache(scp);
3703 cm_ReleaseUser(userp);
3707 /* finalize the output buffer */
3708 smb_SetSMBParm(outp, 0, returnedNames);
3709 temp = (long) (op - origOp);
3710 smb_SetSMBDataLength(outp, temp);
3712 /* the data area is a variable block, which has a 5 (already there)
3713 * followed by the length of the # of data bytes. We now know this to
3714 * be "temp," although that includes the 3 bytes of vbl block header.
3715 * Deduct for them and fill in the length field.
3717 temp -= 3; /* deduct vbl block info */
3718 osi_assert(temp == (43 * returnedNames));
3719 origOp[1] = temp & 0xff;
3720 origOp[2] = (temp>>8) & 0xff;
3721 if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3722 smb_ReleaseDirSearch(dsp);
3723 cm_ReleaseSCache(scp);
3724 cm_ReleaseUser(userp);
3728 /* verify that this is a valid path to a directory. I don't know why they
3729 * don't use the get file attributes call.
3731 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3735 cm_scache_t *rootScp;
3736 cm_scache_t *newScp;
3745 pathp = smb_GetSMBData(inp, NULL);
3746 pathp = smb_ParseASCIIBlock(pathp, NULL);
3747 osi_Log1(smb_logp, "SMB receive check path %s",
3748 osi_LogSaveString(smb_logp, pathp));
3751 return CM_ERROR_BADFD;
3754 rootScp = cm_rootSCachep;
3756 userp = smb_GetUser(vcp, inp);
3758 caseFold = CM_FLAG_CASEFOLD;
3760 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3762 cm_ReleaseUser(userp);
3763 return CM_ERROR_NOSUCHPATH;
3765 code = cm_NameI(rootScp, pathp,
3766 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3767 userp, tidPathp, &req, &newScp);
3770 cm_ReleaseUser(userp);
3774 /* now lock the vnode with a callback; returns with newScp locked */
3775 lock_ObtainMutex(&newScp->mx);
3776 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3777 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3778 if (code && code != CM_ERROR_NOACCESS) {
3779 lock_ReleaseMutex(&newScp->mx);
3780 cm_ReleaseSCache(newScp);
3781 cm_ReleaseUser(userp);
3785 attrs = smb_Attributes(newScp);
3787 if (!(attrs & 0x10))
3788 code = CM_ERROR_NOTDIR;
3790 lock_ReleaseMutex(&newScp->mx);
3792 cm_ReleaseSCache(newScp);
3793 cm_ReleaseUser(userp);
3797 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3801 cm_scache_t *rootScp;
3802 unsigned short attribute;
3804 cm_scache_t *newScp;
3813 /* decode basic attributes we're passed */
3814 attribute = smb_GetSMBParm(inp, 0);
3815 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3817 pathp = smb_GetSMBData(inp, NULL);
3818 pathp = smb_ParseASCIIBlock(pathp, NULL);
3821 return CM_ERROR_BADSMB;
3824 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3825 dosTime, attribute);
3827 rootScp = cm_rootSCachep;
3829 userp = smb_GetUser(vcp, inp);
3831 caseFold = CM_FLAG_CASEFOLD;
3833 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3835 cm_ReleaseUser(userp);
3836 return CM_ERROR_NOSUCHFILE;
3838 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3839 tidPathp, &req, &newScp);
3842 cm_ReleaseUser(userp);
3846 /* now lock the vnode with a callback; returns with newScp locked; we
3847 * need the current status to determine what the new status is, in some
3850 lock_ObtainMutex(&newScp->mx);
3851 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3852 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3854 lock_ReleaseMutex(&newScp->mx);
3855 cm_ReleaseSCache(newScp);
3856 cm_ReleaseUser(userp);
3860 /* Check for RO volume */
3861 if (newScp->flags & CM_SCACHEFLAG_RO) {
3862 lock_ReleaseMutex(&newScp->mx);
3863 cm_ReleaseSCache(newScp);
3864 cm_ReleaseUser(userp);
3865 return CM_ERROR_READONLY;
3868 /* prepare for setattr call */
3871 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3872 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3874 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3875 /* we're told to make a writable file read-only */
3876 attr.unixModeBits = newScp->unixModeBits & ~0222;
3877 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3879 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3880 /* we're told to make a read-only file writable */
3881 attr.unixModeBits = newScp->unixModeBits | 0222;
3882 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3884 lock_ReleaseMutex(&newScp->mx);
3886 /* now call setattr */
3888 code = cm_SetAttr(newScp, &attr, userp, &req);
3892 cm_ReleaseSCache(newScp);
3893 cm_ReleaseUser(userp);
3898 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3902 cm_scache_t *rootScp;
3903 cm_scache_t *newScp, *dscp;
3915 pathp = smb_GetSMBData(inp, NULL);
3916 pathp = smb_ParseASCIIBlock(pathp, NULL);
3919 return CM_ERROR_BADSMB;
3922 if (*pathp == 0) /* null path */
3925 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3926 osi_LogSaveString(smb_logp, pathp));
3928 rootScp = cm_rootSCachep;
3930 userp = smb_GetUser(vcp, inp);
3932 /* we shouldn't need this for V3 requests, but we seem to */
3933 caseFold = CM_FLAG_CASEFOLD;
3935 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3937 cm_ReleaseUser(userp);
3938 return CM_ERROR_NOSUCHFILE;
3942 * XXX Strange hack XXX
3944 * As of Patch 5 (16 July 97), we are having the following problem:
3945 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3946 * requests to look up "desktop.ini" in all the subdirectories.
3947 * This can cause zillions of timeouts looking up non-existent cells
3948 * and volumes, especially in the top-level directory.
3950 * We have not found any way to avoid this or work around it except
3951 * to explicitly ignore the requests for mount points that haven't
3952 * yet been evaluated and for directories that haven't yet been
3955 * We should modify this hack to provide a fake desktop.ini file
3956 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3958 spacep = inp->spacep;
3959 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3960 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3961 code = cm_NameI(rootScp, spacep->data,
3962 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3963 userp, tidPathp, &req, &dscp);
3965 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3966 && !dscp->mountRootFidp)
3967 code = CM_ERROR_NOSUCHFILE;
3968 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3969 cm_buf_t *bp = buf_Find(dscp, &hzero);
3973 code = CM_ERROR_NOSUCHFILE;
3975 cm_ReleaseSCache(dscp);
3977 cm_ReleaseUser(userp);
3983 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3984 tidPathp, &req, &newScp);
3987 cm_ReleaseUser(userp);
3991 /* now lock the vnode with a callback; returns with newScp locked */
3992 lock_ObtainMutex(&newScp->mx);
3993 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3994 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3996 lock_ReleaseMutex(&newScp->mx);
3997 cm_ReleaseSCache(newScp);
3998 cm_ReleaseUser(userp);
4003 /* use smb_Attributes instead. Also the fact that a file is
4004 * in a readonly volume doesn't mean it shojuld be marked as RO
4006 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY