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 #define NOMOREFILESFIX 1
14 #include <afs/param.h>
20 #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;
47 unsigned long loggedOutTime;
49 int smbShutdownFlag = 0;
51 int smb_LogoffTokenTransfer;
52 unsigned long 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 #define NCBmax MAXIMUM_WAIT_OBJECTS
91 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
92 EVENT_HANDLE **NCBreturns;
93 DWORD NCBsessions[NCBmax];
95 struct smb_packet *bufs[NCBmax];
97 #define Sessionmax MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE SessionEvents[Sessionmax];
99 unsigned short LSNs[Sessionmax];
100 int lanas[Sessionmax];
101 BOOL dead_sessions[Sessionmax];
105 osi_mutex_t smb_RawBufLock;
107 #define SMB_RAW_BUFS 4
109 int smb_RawBufSel[SMB_RAW_BUFS];
114 #define SMB_MASKFLAG_TILDE 1
115 #define SMB_MASKFLAG_CASEFOLD 2
117 #define RAWTIMEOUT INFINITE
120 typedef struct raw_write_cont {
133 /* dir search stuff */
134 long smb_dirSearchCounter = 1;
135 smb_dirSearch_t *smb_firstDirSearchp;
136 smb_dirSearch_t *smb_lastDirSearchp;
138 /* hide dot files? */
139 int smb_hideDotFiles;
141 /* global state about V3 protocols */
142 int smb_useV3; /* try to negotiate V3 */
145 static showErrors = 1;
146 /* MessageBox or something like it */
147 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
148 extern HANDLE WaitToTerminate;
152 * Time in Unix format of midnight, 1/1/1970 local time.
153 * When added to dosUTime, gives Unix (AFS) time.
157 /* Time difference for converting to kludge-GMT */
160 char *smb_localNamep = NULL;
162 smb_vc_t *smb_allVCsp;
164 smb_username_t *usernamesp = NULL;
166 smb_waitingLock_t *smb_allWaitingLocks;
169 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
170 NCB *ncbp, raw_write_cont_t *rwcp);
171 void smb_NetbiosInit();
173 #ifndef AFS_WIN95_ENV
174 DWORD smb_ServerExceptionFilter(void);
177 extern char cm_HostName[];
178 extern char cm_confDir[];
182 #define LPTSTR char *
183 #define GetComputerName(str, sizep) \
184 strcpy((str), cm_HostName); \
185 *(sizep) = strlen(cm_HostName)
188 extern char AFSConfigKeyName[];
193 * To build an expiring version, comment out the definition of NOEXPIRE,
194 * and set the definition of EXPIREDATE to the desired value.
197 #define EXPIREDATE 834000000 /* Wed Jun 5 1996 */
200 char * myCrt_Dispatch(int i)
205 return "unknown SMB op";
207 return "(00)ReceiveCoreMakeDir";
209 return "(01)ReceiveCoreRemoveDir";
211 return "(02)ReceiveCoreOpen";
213 return "(03)ReceiveCoreCreate";
215 return "(04)ReceiveCoreClose";
217 return "(05)ReceiveCoreFlush";
219 return "(06)ReceiveCoreUnlink";
221 return "(07)ReceiveCoreRename";
223 return "(08)ReceiveCoreGetFileAttributes";
225 return "(09)ReceiveCoreSetFileAttributes";
227 return "(0a)ReceiveCoreRead";
229 return "(0b)ReceiveCoreWrite";
231 return "(0c)ReceiveCoreLockRecord";
233 return "(0d)ReceiveCoreUnlockRecord";
235 return "(0e)SendCoreBadOp";
237 return "(0f)ReceiveCoreCreate";
239 return "(10)ReceiveCoreCheckPath";
241 return "(11)SendCoreBadOp";
243 return "(12)ReceiveCoreSeek";
245 return "(1a)ReceiveCoreReadRaw";
247 return "(1d)ReceiveCoreWriteRawDummy";
249 return "(22)ReceiveV3SetAttributes";
251 return "(23)ReceiveV3GetAttributes";
253 return "(24)ReceiveV3LockingX";
255 return "(29)SendCoreBadOp";
257 return "(2b)ReceiveCoreEcho";
259 return "(2d)ReceiveV3OpenX";
261 return "(2e)ReceiveV3ReadX";
263 return "(32)ReceiveV3Tran2A";
265 return "(33)ReceiveV3Tran2A";
267 return "(34)ReceiveV3FindClose";
269 return "(35)ReceiveV3FindNotifyClose";
271 return "(70)ReceiveCoreTreeConnect";
273 return "(71)ReceiveCoreTreeDisconnect";
275 return "(72)ReceiveNegotiate";
277 return "(73)ReceiveV3SessionSetupX";
279 return "(74)ReceiveV3UserLogoffX";
281 return "(75)ReceiveV3TreeConnectX";
283 return "(80)ReceiveCoreGetDiskAttributes";
285 return "(81)ReceiveCoreSearchDir";
287 return "(A0)ReceiveNTTransact";
289 return "(A2)ReceiveNTCreateX";
291 return "(A4)ReceiveNTCancel";
293 return "(c0)SendCoreBadOp";
295 return "(c1)SendCoreBadOp";
297 return "(c2)SendCoreBadOp";
299 return "(c3)SendCoreBadOp";
303 char * myCrt_2Dispatch(int i)
308 return "unknown SMB op-2";
310 return "S(00)CreateFile";
312 return "S(01)FindFirst";
314 return "S(02)FindNext"; /* FindNext */
316 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
320 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
322 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
324 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
326 return "S(08)??_ReceiveTran2SetFileInfo";
328 return "S(09)??_ReceiveTran2FSCTL";
330 return "S(0a)_ReceiveTran2IOCTL";
332 return "S(0b)_ReceiveTran2FindNotifyFirst";
334 return "S(0c)_ReceiveTran2FindNotifyNext";
336 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
340 /* scache must be locked */
341 unsigned int smb_Attributes(cm_scache_t *scp)
345 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
346 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
347 attrs = SMB_ATTR_DIRECTORY;
352 * We used to mark a file RO if it was in an RO volume, but that
353 * turns out to be impolitic in NT. See defect 10007.
356 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
358 if ((scp->unixModeBits & 0222) == 0)
359 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
364 /* Check if the named file/dir is a dotfile/dotdir */
365 /* String pointed to by lastComp can have leading slashes, but otherwise should have
366 no other patch components */
367 unsigned int smb_IsDotFile(char *lastComp) {
370 /* skip over slashes */
371 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
376 /* nulls, curdir and parent dir doesn't count */
379 if(!*(s + 1)) return 0;
380 if(*(s+1) == '.' && !*(s + 2)) return 0;
386 static int ExtractBits(WORD bits, short start, short len)
393 num = bits << (16 - end);
394 num = num >> ((16 - end) + start);
400 void ShowUnixTime(char *FuncName, long unixTime)
405 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
407 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
408 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
410 int day, month, year, sec, min, hour;
413 day = ExtractBits(wDate, 0, 5);
414 month = ExtractBits(wDate, 5, 4);
415 year = ExtractBits(wDate, 9, 7) + 1980;
417 sec = ExtractBits(wTime, 0, 5);
418 min = ExtractBits(wTime, 5, 6);
419 hour = ExtractBits(wTime, 11, 5);
421 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
422 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
428 /* Determine if we are observing daylight savings time */
429 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
431 TIME_ZONE_INFORMATION timeZoneInformation;
432 SYSTEMTIME utc, local, localDST;
434 /* Get the time zone info. NT uses this to calc if we are in DST. */
435 GetTimeZoneInformation(&timeZoneInformation);
437 /* Return the daylight bias */
438 *pDstBias = timeZoneInformation.DaylightBias;
440 /* Return the bias */
441 *pBias = timeZoneInformation.Bias;
443 /* Now determine if DST is being observed */
445 /* Get the UTC (GMT) time */
448 /* Convert UTC time to local time using the time zone info. If we are
449 observing DST, the calculated local time will include this.
451 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
453 /* Set the daylight bias to 0. The daylight bias is the amount of change
454 in time that we use for daylight savings time. By setting this to 0
455 we cause there to be no change in time during daylight savings time.
457 timeZoneInformation.DaylightBias = 0;
459 /* Convert the utc time to local time again, but this time without any
460 adjustment for daylight savings time.
462 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
464 /* If the two times are different, then it means that the localDST that
465 we calculated includes the daylight bias, and therefore we are
466 observing daylight savings time.
468 *pDST = localDST.wHour != local.wHour;
471 /* Determine if we are observing daylight savings time */
472 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
478 *pDstBias = -60; /* where can this be different? */
484 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
486 BOOL dst; /* Will be TRUE if observing DST */
487 LONG dstBias; /* Offset from local time if observing DST */
488 LONG bias; /* Offset from GMT for local time */
491 * This function will adjust the last write time to compensate
492 * for two bugs in the smb client:
494 * 1) During Daylight Savings Time, the LastWriteTime is ahead
495 * in time by the DaylightBias (ignoring the sign - the
496 * DaylightBias is always stored as a negative number). If
497 * the DaylightBias is -60, then the LastWriteTime will be
498 * ahead by 60 minutes.
500 * 2) If the local time zone is a positive offset from GMT, then
501 * the LastWriteTime will be the correct local time plus the
502 * Bias (ignoring the sign - a positive offset from GMT is
503 * always stored as a negative Bias). If the Bias is -120,
504 * then the LastWriteTime will be ahead by 120 minutes.
506 * These bugs can occur at the same time.
509 GetTimeZoneInfo(&dst, &dstBias, &bias);
511 /* First adjust for DST */
513 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
515 /* Now adjust for a positive offset from GMT (a negative bias). */
517 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
521 * Calculate the difference (in seconds) between local time and GMT.
522 * This enables us to convert file times to kludge-GMT.
528 struct tm gmt_tm, local_tm;
529 int days, hours, minutes, seconds;
532 gmt_tm = *(gmtime(&t));
533 local_tm = *(localtime(&t));
535 days = local_tm.tm_yday - gmt_tm.tm_yday;
536 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
538 /* There is a problem with DST immediately after the time change
539 * which may continue to exist until the machine is rebooted
541 - (local_tm.tm_isdst ? 1 : 0)
544 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
545 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
551 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
556 long ersatz_unixTime;
559 * Must use kludge-GMT instead of real GMT.
560 * kludge-GMT is computed by adding time zone difference to localtime.
563 * ltp = gmtime(&unixTime);
565 ersatz_unixTime = unixTime - smb_NowTZ;
566 ltp = localtime(&ersatz_unixTime);
568 /* if we fail, make up something */
571 localJunk.tm_year = 89 - 20;
572 localJunk.tm_mon = 4;
573 localJunk.tm_mday = 12;
574 localJunk.tm_hour = 0;
575 localJunk.tm_min = 0;
576 localJunk.tm_sec = 0;
579 stm.wYear = ltp->tm_year + 1900;
580 stm.wMonth = ltp->tm_mon + 1;
581 stm.wDayOfWeek = ltp->tm_wday;
582 stm.wDay = ltp->tm_mday;
583 stm.wHour = ltp->tm_hour;
584 stm.wMinute = ltp->tm_min;
585 stm.wSecond = ltp->tm_sec;
586 stm.wMilliseconds = 0;
588 SystemTimeToFileTime(&stm, largeTimep);
591 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
593 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
594 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
595 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
597 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
599 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
600 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
602 *ft = LargeIntegerMultiplyByLong(*ft, 60);
603 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
606 ut = ConvertLongToLargeInteger(unixTime);
607 ut = LargeIntegerMultiplyByLong(ut, 10000000);
608 *ft = LargeIntegerAdd(*ft, ut);
613 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
619 FileTimeToSystemTime(largeTimep, &stm);
621 lt.tm_year = stm.wYear - 1900;
622 lt.tm_mon = stm.wMonth - 1;
623 lt.tm_wday = stm.wDayOfWeek;
624 lt.tm_mday = stm.wDay;
625 lt.tm_hour = stm.wHour;
626 lt.tm_min = stm.wMinute;
627 lt.tm_sec = stm.wSecond;
630 save_timezone = _timezone;
631 _timezone += smb_NowTZ;
632 *unixTimep = mktime(<);
633 _timezone = save_timezone;
636 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
638 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
639 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
640 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
644 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
645 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
646 a = LargeIntegerMultiplyByLong(a, 60);
647 a = LargeIntegerMultiplyByLong(a, 10000000);
649 /* subtract it from ft */
650 a = LargeIntegerSubtract(*ft, a);
652 /* divide down to seconds */
653 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
657 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
664 ltp = localtime((time_t*) &unixTime);
666 /* if we fail, make up something */
669 localJunk.tm_year = 89 - 20;
670 localJunk.tm_mon = 4;
671 localJunk.tm_mday = 12;
672 localJunk.tm_hour = 0;
673 localJunk.tm_min = 0;
674 localJunk.tm_sec = 0;
677 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
678 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
679 *dosTimep = (dosDate<<16) | dosTime;
682 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
684 unsigned short dosDate;
685 unsigned short dosTime;
688 dosDate = searchTime & 0xffff;
689 dosTime = (searchTime >> 16) & 0xffff;
691 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
692 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
693 localTm.tm_mday = (dosDate) & 0x1f;
694 localTm.tm_hour = (dosTime>>11) & 0x1f;
695 localTm.tm_min = (dosTime >> 5) & 0x3f;
696 localTm.tm_sec = (dosTime & 0x1f) * 2;
697 localTm.tm_isdst = -1; /* compute whether DST in effect */
699 *unixTimep = mktime(&localTm);
702 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
704 *dosUTimep = unixTime - smb_localZero;
707 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
710 *unixTimep = dosTime + smb_localZero;
712 /* dosTime seems to be already adjusted for GMT */
713 *unixTimep = dosTime;
717 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
721 lock_ObtainWrite(&smb_rctLock);
722 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
723 if (lsn == vcp->lsn && lana == vcp->lana) {
728 if (!vcp && (flags & SMB_FLAG_CREATE)) {
729 vcp = malloc(sizeof(*vcp));
730 memset(vcp, 0, sizeof(*vcp));
731 vcp->vcID = numVCs++;
735 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
736 vcp->nextp = smb_allVCsp;
738 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
742 lock_ReleaseWrite(&smb_rctLock);
746 int smb_IsStarMask(char *maskp)
751 for(i=0; i<11; i++) {
753 if (tc == '?' || tc == '*' || tc == '>') return 1;
758 void smb_ReleaseVC(smb_vc_t *vcp)
760 lock_ObtainWrite(&smb_rctLock);
761 osi_assert(vcp->refCount-- > 0);
762 lock_ReleaseWrite(&smb_rctLock);
765 void smb_HoldVC(smb_vc_t *vcp)
767 lock_ObtainWrite(&smb_rctLock);
769 lock_ReleaseWrite(&smb_rctLock);
772 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
776 lock_ObtainWrite(&smb_rctLock);
777 for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
778 if (tid == tidp->tid) {
783 if (!tidp && (flags & SMB_FLAG_CREATE)) {
784 tidp = malloc(sizeof(*tidp));
785 memset(tidp, 0, sizeof(*tidp));
786 tidp->nextp = vcp->tidsp;
791 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
794 lock_ReleaseWrite(&smb_rctLock);
798 void smb_ReleaseTID(smb_tid_t *tidp)
807 lock_ObtainWrite(&smb_rctLock);
808 osi_assert(tidp->refCount-- > 0);
809 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
810 ltpp = &tidp->vcp->tidsp;
811 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
812 if (tp == tidp) break;
814 osi_assert(tp != NULL);
816 lock_FinalizeMutex(&tidp->mx);
817 userp = tidp->userp; /* remember to drop ref later */
820 lock_ReleaseWrite(&smb_rctLock);
822 cm_ReleaseUser(userp);
829 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
831 smb_user_t *uidp = NULL;
833 lock_ObtainWrite(&smb_rctLock);
834 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
835 if (uid == uidp->userID) {
837 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp) ? uidp->unp->name : "");
841 if (!uidp && (flags & SMB_FLAG_CREATE)) {
842 uidp = malloc(sizeof(*uidp));
843 memset(uidp, 0, sizeof(*uidp));
844 uidp->nextp = vcp->usersp;
849 lock_InitializeMutex(&uidp->mx, "user_t mutex");
851 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 : ""));
853 lock_ReleaseWrite(&smb_rctLock);
857 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
859 smb_username_t *unp= NULL;
861 lock_ObtainWrite(&smb_rctLock);
862 for(unp = usernamesp; unp; unp = unp->nextp) {
863 if (stricmp(unp->name, usern) == 0 &&
864 stricmp(unp->machine, machine) == 0) {
869 if (!unp && (flags & SMB_FLAG_CREATE)) {
870 unp = malloc(sizeof(*unp));
871 memset(unp, 0, sizeof(*unp));
873 unp->nextp = usernamesp;
874 unp->name = strdup(usern);
875 unp->machine = strdup(machine);
877 lock_InitializeMutex(&unp->mx, "username_t mutex");
879 lock_ReleaseWrite(&smb_rctLock);
883 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
885 smb_user_t *uidp= NULL;
887 lock_ObtainWrite(&smb_rctLock);
888 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
891 if (stricmp(uidp->unp->name, usern) == 0) {
893 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
898 lock_ReleaseWrite(&smb_rctLock);
901 void smb_ReleaseUID(smb_user_t *uidp)
910 lock_ObtainWrite(&smb_rctLock);
911 osi_assert(uidp->refCount-- > 0);
912 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
913 lupp = &uidp->vcp->usersp;
914 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
915 if (up == uidp) break;
917 osi_assert(up != NULL);
919 lock_FinalizeMutex(&uidp->mx);
921 userp = uidp->unp->userp; /* remember to drop ref later */
922 uidp->unp->userp = NULL;
927 lock_ReleaseWrite(&smb_rctLock);
929 cm_ReleaseUserVCRef(userp);
930 cm_ReleaseUser(userp);
937 /* retrieve a held reference to a user structure corresponding to an incoming
939 * corresponding release function is cm_ReleaseUser.
941 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
947 smbp = (smb_t *) inp;
948 uidp = smb_FindUID(vcp, smbp->uid, 0);
949 if ((!uidp) || (!uidp->unp))
952 lock_ObtainMutex(&uidp->mx);
953 up = uidp->unp->userp;
955 lock_ReleaseMutex(&uidp->mx);
957 smb_ReleaseUID(uidp);
963 * Return a pointer to a pathname extracted from a TID structure. The
964 * TID structure is not held; assume it won't go away.
966 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
971 tidp = smb_FindTID(vcp, tid, 0);
974 tpath = tidp->pathname;
975 smb_ReleaseTID(tidp);
979 /* check to see if we have a chained fid, that is, a fid that comes from an
980 * OpenAndX message that ran earlier in this packet. In this case, the fid
981 * field in a read, for example, request, isn't set, since the value is
982 * supposed to be inherited from the openAndX call.
984 int smb_ChainFID(int fid, smb_packet_t *inp)
986 if (inp->fid == 0 || inp->inCount == 0)
992 /* are we a priv'd user? What does this mean on NT? */
993 int smb_SUser(cm_user_t *userp)
998 /* find a file ID. If we pass in 0 we select an used File ID.
999 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1000 * smb_fid_t data structure if desired File ID cannot be found.
1002 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1007 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1010 lock_ObtainWrite(&smb_rctLock);
1011 /* figure out if we need to allocate a new file ID */
1014 fid = vcp->fidCounter;
1018 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1019 if (fid == fidp->fid) {
1030 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1031 char eventName[MAX_PATH];
1033 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1034 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1035 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1036 afsi_log("Event Object Already Exists: %s", eventName);
1037 thrd_CloseHandle(event);
1044 fidp = malloc(sizeof(*fidp));
1045 memset(fidp, 0, sizeof(*fidp));
1046 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1050 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1052 fidp->curr_chunk = fidp->prev_chunk = -2;
1053 fidp->raw_write_event = event;
1055 vcp->fidCounter = fid+1;
1056 if (vcp->fidCounter == 0)
1057 vcp->fidCounter = 1;
1060 lock_ReleaseWrite(&smb_rctLock);
1064 void smb_ReleaseFID(smb_fid_t *fidp)
1067 smb_vc_t *vcp = NULL;
1068 smb_ioctl_t *ioctlp;
1074 lock_ObtainWrite(&smb_rctLock);
1075 osi_assert(fidp->refCount-- > 0);
1076 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1078 if (!(fidp->flags & SMB_FID_IOCTL))
1080 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1081 thrd_CloseHandle(fidp->raw_write_event);
1083 /* and see if there is ioctl stuff to free */
1084 ioctlp = fidp->ioctlp;
1086 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1087 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1088 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1094 /* do not call smb_ReleaseVC() because we already have the lock */
1097 lock_ReleaseWrite(&smb_rctLock);
1099 /* now release the scache structure */
1101 cm_ReleaseSCache(scp);
1105 * Case-insensitive search for one string in another;
1106 * used to find variable names in submount pathnames.
1108 static char *smb_stristr(char *str1, char *str2)
1112 for (cursor = str1; *cursor; cursor++)
1113 if (stricmp(cursor, str2) == 0)
1120 * Substitute a variable value for its name in a submount pathname. Variable
1121 * name has been identified by smb_stristr() and is in substr. Variable name
1122 * length (plus one) is in substr_size. Variable value is in newstr.
1124 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1129 strcpy(temp, substr + substr_size - 1);
1130 strcpy(substr, newstr);
1134 char VNUserName[] = "%USERNAME%";
1135 char VNLCUserName[] = "%LCUSERNAME%";
1136 char VNComputerName[] = "%COMPUTERNAME%";
1137 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1139 /* List available shares */
1140 int smb_ListShares()
1144 char shareBuf[4096];
1152 /*strcpy(shareNameList[num_shares], "all");
1153 strcpy(pathNameList[num_shares++], "/afs");*/
1154 fprintf(stderr, "The following shares are available:\n");
1155 fprintf(stderr, "Share Name (AFS Path)\n");
1156 fprintf(stderr, "---------------------\n");
1157 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1160 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1161 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1163 strcpy(sbmtpath, cm_confDir);
1165 strcat(sbmtpath, "/afsdsbmt.ini");
1166 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1167 shareBuf, sizeof(shareBuf),
1173 this_share = shareBuf;
1177 /*strcpy(shareNameList[num_shares], this_share);*/
1178 len = GetPrivateProfileString("AFS Submounts", this_share,
1185 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1188 if (*p == '\\') *p = '/'; /* change to / */
1192 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1193 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1196 while (*this_share != 0) this_share++; /* find next NUL */
1197 this_share++; /* skip past the NUL */
1198 } while (*this_share != 0); /* stop at final NUL */
1203 /* find a shareName in the table of submounts */
1204 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1208 char pathName[1024];
1212 char sbmtpath[MAX_PATH];
1216 DWORD allSubmount = 1;
1218 if (strcmp(shareName, "IPC$") == 0) {
1223 /* if allSubmounts == 0, only return the //mountRoot/all share
1224 * if in fact it has been been created in the subMounts table.
1225 * This is to allow sites that want to restrict access to the
1228 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1229 0, KEY_QUERY_VALUE, &parmKey);
1230 if (code == ERROR_SUCCESS) {
1231 len = sizeof(allSubmount);
1232 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1233 (BYTE *) &allSubmount, &len);
1234 if (code != ERROR_SUCCESS) {
1237 RegCloseKey (parmKey);
1240 if (allSubmount && _stricmp(shareName, "all") == 0) {
1245 /* In case, the all share is disabled we need to still be able
1246 * to handle ioctl requests
1248 if (_stricmp(shareName, "ioctl$") == 0) {
1249 *pathNamep = strdup("/.__ioctl__");
1254 strcpy(sbmtpath, "afsdsbmt.ini");
1256 strcpy(sbmtpath, cm_confDir);
1257 strcat(sbmtpath, "/afsdsbmt.ini");
1259 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1260 pathName, sizeof(pathName), sbmtpath);
1261 if (len != 0 && len != sizeof(pathName) - 1) {
1262 /* We can accept either unix or PC style AFS pathnames. Convert
1263 * Unix-style to PC style here for internal use.
1266 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1267 p += strlen(cm_mountRoot); /* skip mount path */
1270 if (*q == '/') *q = '\\'; /* change to \ */
1276 if (var = smb_stristr(p, VNUserName)) {
1277 if (uidp && uidp->unp)
1278 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1280 smb_subst(p, var, sizeof(VNUserName)," ");
1282 else if (var = smb_stristr(p, VNLCUserName))
1284 if (uidp && uidp->unp)
1285 strcpy(temp, uidp->unp->name);
1289 smb_subst(p, var, sizeof(VNLCUserName), temp);
1291 else if (var = smb_stristr(p, VNComputerName))
1293 sizeTemp = sizeof(temp);
1294 GetComputerName((LPTSTR)temp, &sizeTemp);
1295 smb_subst(p, var, sizeof(VNComputerName), temp);
1297 else if (var = smb_stristr(p, VNLCComputerName))
1299 sizeTemp = sizeof(temp);
1300 GetComputerName((LPTSTR)temp, &sizeTemp);
1302 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1307 *pathNamep = strdup(p);
1310 else /* create \\<netbiosName>\<cellname> */
1312 char * p = shareName;
1319 /* Get the full name for this cell */
1320 code = cm_SearchCellFile(p, temp, 0, 0);
1321 #ifdef AFS_AFSDB_ENV
1322 if (code && cm_dnsEnabled) {
1324 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1327 /* construct the path */
1329 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1330 *pathNamep = strdup(strlwr(pathName));
1339 /* Client-side offline caching policy types */
1340 #define CSC_POLICY_MANUAL 0
1341 #define CSC_POLICY_DOCUMENTS 1
1342 #define CSC_POLICY_PROGRAMS 2
1343 #define CSC_POLICY_DISABLE 3
1345 int smb_FindShareCSCPolicy(char *shareName)
1352 strcpy(sbmtpath, "afsdsbmt.ini");
1354 strcpy(sbmtpath, cm_confDir);
1355 strcat(sbmtpath, "/afsdsbmt.ini");
1357 len = GetPrivateProfileString("CSC Policy", shareName, "",
1358 policy, sizeof(policy), sbmtpath);
1359 if (len == 0 || len == sizeof(policy) - 1) {
1360 return CSC_POLICY_MANUAL;
1363 if (stricmp(policy, "documents") == 0)
1365 return CSC_POLICY_DOCUMENTS;
1368 if (stricmp(policy, "programs") == 0)
1370 return CSC_POLICY_PROGRAMS;
1373 if (stricmp(policy, "disable") == 0)
1375 return CSC_POLICY_DISABLE;
1378 return CSC_POLICY_MANUAL;
1381 /* find a dir search structure by cookie value, and return it held.
1382 * Must be called with smb_globalLock held.
1384 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1386 smb_dirSearch_t *dsp;
1388 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1389 if (dsp->cookie == cookie) {
1390 if (dsp != smb_firstDirSearchp) {
1391 /* move to head of LRU queue, too, if we're not already there */
1392 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1393 smb_lastDirSearchp = (smb_dirSearch_t *)
1395 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1396 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1397 if (!smb_lastDirSearchp)
1398 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1407 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1409 lock_ObtainWrite(&smb_globalLock);
1410 dsp->flags |= SMB_DIRSEARCH_DELETE;
1411 lock_ReleaseWrite(&smb_globalLock);
1412 lock_ObtainMutex(&dsp->mx);
1413 if(dsp->scp != NULL) {
1414 lock_ObtainMutex(&dsp->scp->mx);
1415 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1416 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1417 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1418 dsp->scp->bulkStatProgress = hones;
1420 lock_ReleaseMutex(&dsp->scp->mx);
1422 lock_ReleaseMutex(&dsp->mx);
1425 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1431 lock_ObtainWrite(&smb_globalLock);
1432 osi_assert(dsp->refCount-- > 0);
1433 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1434 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1435 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1436 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1437 lock_FinalizeMutex(&dsp->mx);
1441 lock_ReleaseWrite(&smb_globalLock);
1443 /* do this now to avoid spurious locking hierarchy creation */
1444 if (scp) cm_ReleaseSCache(scp);
1447 /* find a dir search structure by cookie value, and return it held */
1448 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1450 smb_dirSearch_t *dsp;
1452 lock_ObtainWrite(&smb_globalLock);
1453 dsp = smb_FindDirSearchNL(cookie);
1454 lock_ReleaseWrite(&smb_globalLock);
1458 /* GC some dir search entries, in the address space expected by the specific protocol.
1459 * Must be called with smb_globalLock held; release the lock temporarily.
1461 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1462 void smb_GCDirSearches(int isV3)
1464 smb_dirSearch_t *prevp;
1465 smb_dirSearch_t *tp;
1466 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1470 victimCount = 0; /* how many have we got so far */
1471 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1472 /* we'll move tp from queue, so
1475 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1476 /* if no one is using this guy, and we're either in the new protocol,
1477 * or we're in the old one and this is a small enough ID to be useful
1478 * to the old protocol, GC this guy.
1480 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1481 /* hold and delete */
1482 tp->flags |= SMB_DIRSEARCH_DELETE;
1483 victimsp[victimCount++] = tp;
1487 /* don't do more than this */
1488 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1491 /* now release them */
1492 lock_ReleaseWrite(&smb_globalLock);
1493 for(i = 0; i < victimCount; i++) {
1494 smb_ReleaseDirSearch(victimsp[i]);
1496 lock_ObtainWrite(&smb_globalLock);
1499 /* function for allocating a dir search entry. We need these to remember enough context
1500 * since we don't get passed the path from call to call during a directory search.
1502 * Returns a held dir search structure, and bumps the reference count on the vnode,
1503 * since it saves a pointer to the vnode.
1505 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1507 smb_dirSearch_t *dsp;
1511 lock_ObtainWrite(&smb_globalLock);
1514 /* what's the biggest ID allowed in this version of the protocol */
1515 if (isV3) maxAllowed = 65535;
1516 else maxAllowed = 255;
1519 /* twice so we have enough tries to find guys we GC after one pass;
1520 * 10 extra is just in case I mis-counted.
1522 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1523 __FILE__, __LINE__);
1524 if (smb_dirSearchCounter > maxAllowed) {
1525 smb_dirSearchCounter = 1;
1526 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1528 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1530 /* don't need to watch for refcount zero and deleted, since
1531 * we haven't dropped the global lock.
1534 ++smb_dirSearchCounter;
1538 dsp = malloc(sizeof(*dsp));
1539 memset(dsp, 0, sizeof(*dsp));
1540 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1541 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1542 dsp->cookie = smb_dirSearchCounter;
1543 ++smb_dirSearchCounter;
1545 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1546 dsp->lastTime = osi_Time();
1549 lock_ReleaseWrite(&smb_globalLock);
1553 static smb_packet_t *GetPacket(void)
1557 unsigned int npar, seg, tb_sel;
1560 lock_ObtainWrite(&smb_globalLock);
1561 tbp = smb_packetFreeListp;
1563 smb_packetFreeListp = tbp->nextp;
1564 lock_ReleaseWrite(&smb_globalLock);
1567 tbp = calloc(65540,1);
1569 tbp = malloc(sizeof(smb_packet_t));
1571 tbp->magic = SMB_PACKETMAGIC;
1574 tbp->resumeCode = 0;
1580 tbp->ncb_length = 0;
1585 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1588 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1590 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1592 osi_panic("",__FILE__,__LINE__);
1595 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1600 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1601 tbp->dos_pkt_sel = tb_sel;
1604 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1609 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1613 memcpy(tbp, pkt, sizeof(smb_packet_t));
1614 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1618 static NCB *GetNCB(void)
1623 unsigned int npar, seg, tb_sel;
1626 lock_ObtainWrite(&smb_globalLock);
1627 tbp = smb_ncbFreeListp;
1629 smb_ncbFreeListp = tbp->nextp;
1630 lock_ReleaseWrite(&smb_globalLock);
1633 tbp = calloc(sizeof(*tbp),1);
1635 tbp = malloc(sizeof(*tbp));
1636 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1639 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1641 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1643 osi_panic("",__FILE__,__LINE__);
1645 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1650 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1651 tbp->dos_ncb_sel = tb_sel;
1653 tbp->magic = SMB_NCBMAGIC;
1656 osi_assert(tbp->magic == SMB_NCBMAGIC);
1658 memset(&tbp->ncb, 0, sizeof(NCB));
1661 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1666 void smb_FreePacket(smb_packet_t *tbp)
1668 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1670 lock_ObtainWrite(&smb_globalLock);
1671 tbp->nextp = smb_packetFreeListp;
1672 smb_packetFreeListp = tbp;
1673 tbp->magic = SMB_PACKETMAGIC;
1676 tbp->resumeCode = 0;
1682 tbp->ncb_length = 0;
1684 lock_ReleaseWrite(&smb_globalLock);
1687 static void FreeNCB(NCB *bufferp)
1691 tbp = (smb_ncb_t *) bufferp;
1692 osi_assert(tbp->magic == SMB_NCBMAGIC);
1694 lock_ObtainWrite(&smb_globalLock);
1695 tbp->nextp = smb_ncbFreeListp;
1696 smb_ncbFreeListp = tbp;
1697 lock_ReleaseWrite(&smb_globalLock);
1700 /* get a ptr to the data part of a packet, and its count */
1701 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1705 unsigned char *afterParmsp;
1707 parmBytes = *smbp->wctp << 1;
1708 afterParmsp = smbp->wctp + parmBytes + 1;
1710 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1711 if (nbytesp) *nbytesp = dataBytes;
1713 /* don't forget to skip the data byte count, since it follows
1714 * the parameters; that's where the "2" comes from below.
1716 return (unsigned char *) (afterParmsp + 2);
1719 /* must set all the returned parameters before playing around with the
1720 * data region, since the data region is located past the end of the
1721 * variable number of parameters.
1723 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1725 unsigned char *afterParmsp;
1727 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1729 *afterParmsp++ = dsize & 0xff;
1730 *afterParmsp = (dsize>>8) & 0xff;
1733 /* return the parm'th parameter in the smbp packet */
1734 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1737 unsigned char *parmDatap;
1739 parmCount = *smbp->wctp;
1741 if (parm >= parmCount) {
1746 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1747 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1748 parm, parmCount, smbp->ncb_length);
1750 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1751 1, smbp->ncb_length, ptbuf, smbp);
1752 DeregisterEventSource(h);
1756 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1757 parm, parmCount, smbp->ncb_length);
1758 osi_Log0(smb_logp, s);
1760 osi_panic(s, __FILE__, __LINE__);
1762 parmDatap = smbp->wctp + (2*parm) + 1;
1764 return parmDatap[0] + (parmDatap[1] << 8);
1767 /* return the parm'th parameter in the smbp packet */
1768 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1771 unsigned char *parmDatap;
1773 parmCount = *smbp->wctp;
1775 if (parm * 2 + offset >= parmCount * 2) {
1780 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1781 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1782 parm, offset, parmCount, smbp->ncb_length);
1784 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1785 1, smbp->ncb_length, ptbuf, smbp);
1786 DeregisterEventSource(h);
1790 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1792 parm, offset, parmCount, smbp->ncb_length);
1793 osi_Log0(smb_logp, s);
1796 osi_panic(s, __FILE__, __LINE__);
1798 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1800 return parmDatap[0] + (parmDatap[1] << 8);
1803 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1807 /* make sure we have enough slots */
1808 if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1810 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1811 *parmDatap++ = parmValue & 0xff;
1812 *parmDatap = (parmValue>>8) & 0xff;
1815 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1819 /* make sure we have enough slots */
1820 if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1822 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1823 *parmDatap++ = parmValue & 0xff;
1824 *parmDatap++ = (parmValue>>8) & 0xff;
1825 *parmDatap++ = (parmValue>>16) & 0xff;
1826 *parmDatap++ = (parmValue>>24) & 0xff;
1829 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1834 /* make sure we have enough slots */
1835 if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1837 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1839 *parmDatap++ = *parmValuep++;
1842 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1846 /* make sure we have enough slots */
1847 if (*smbp->wctp <= slot) {
1848 if (smbp->oddByte) {
1850 *smbp->wctp = slot+1;
1855 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1856 *parmDatap++ = parmValue & 0xff;
1859 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1863 lastSlashp = strrchr(inPathp, '\\');
1865 *lastComponentp = lastSlashp;
1868 if (inPathp == lastSlashp)
1870 *outPathp++ = *inPathp++;
1879 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1884 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
1889 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1895 tlen = inp[0] + (inp[1]<<8);
1896 inp += 2; /* skip length field */
1899 *chainpp = inp + tlen;
1908 /* format a packet as a response */
1909 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1914 outp = (smb_t *) op;
1916 /* zero the basic structure through the smb_wct field, and zero the data
1917 * size field, assuming that wct stays zero; otherwise, you have to
1918 * explicitly set the data size field, too.
1920 inSmbp = (smb_t *) inp;
1921 memset(outp, 0, sizeof(smb_t)+2);
1927 outp->com = inSmbp->com;
1928 outp->tid = inSmbp->tid;
1929 outp->pid = inSmbp->pid;
1930 outp->uid = inSmbp->uid;
1931 outp->mid = inSmbp->mid;
1932 outp->res[0] = inSmbp->res[0];
1933 outp->res[1] = inSmbp->res[1];
1934 op->inCom = inSmbp->com;
1936 outp->reb = 0x80; /* SERVER_RESP */
1937 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
1939 /* copy fields in generic packet area */
1940 op->wctp = &outp->wct;
1943 /* send a (probably response) packet; vcp tells us to whom to send it.
1944 * we compute the length by looking at wct and bcc fields.
1946 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1963 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
1966 memset((char *)ncbp, 0, sizeof(NCB));
1968 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
1969 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
1970 extra += tp[0] + (tp[1]<<8);
1971 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
1972 extra += 3; /* wct and length fields */
1974 ncbp->ncb_length = extra; /* bytes to send */
1975 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
1976 ncbp->ncb_lana_num = vcp->lana;
1977 ncbp->ncb_command = NCBSEND; /* op means send data */
1979 ncbp->ncb_buffer = (char *) inp;/* packet */
1980 code = Netbios(ncbp);
1982 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
1983 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
1985 /* copy header information from virtual to DOS address space */
1986 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
1987 code = Netbios(ncbp, dos_ncb);
1991 osi_Log1(smb_logp, "SendPacket failure code %d", code);
1997 void smb_MapNTError(long code, unsigned long *NTStatusp)
1999 unsigned long NTStatus;
2001 /* map CM_ERROR_* errors to NT 32-bit status codes */
2002 /* NT Status codes are listed in ntstatus.h not winerror.h */
2003 if (code == CM_ERROR_NOSUCHCELL) {
2004 NTStatus = 0xC000000FL; /* No such file */
2006 else if (code == CM_ERROR_NOSUCHVOLUME) {
2007 NTStatus = 0xC000000FL; /* No such file */
2009 else if (code == CM_ERROR_TIMEDOUT) {
2010 NTStatus = 0xC00000CFL; /* Sharing Paused */
2012 else if (code == CM_ERROR_RETRY) {
2013 NTStatus = 0xC000022DL; /* Retry */
2015 else if (code == CM_ERROR_NOACCESS) {
2016 NTStatus = 0xC0000022L; /* Access denied */
2018 else if (code == CM_ERROR_READONLY) {
2019 NTStatus = 0xC00000A2L; /* Write protected */
2021 else if (code == CM_ERROR_NOSUCHFILE) {
2022 NTStatus = 0xC000000FL; /* No such file */
2024 else if (code == CM_ERROR_NOSUCHPATH) {
2025 NTStatus = 0xC000003AL; /* Object path not found */
2027 else if (code == CM_ERROR_TOOBIG) {
2028 NTStatus = 0xC000007BL; /* Invalid image format */
2030 else if (code == CM_ERROR_INVAL) {
2031 NTStatus = 0xC000000DL; /* Invalid parameter */
2033 else if (code == CM_ERROR_BADFD) {
2034 NTStatus = 0xC0000008L; /* Invalid handle */
2036 else if (code == CM_ERROR_BADFDOP) {
2037 NTStatus = 0xC0000022L; /* Access denied */
2039 else if (code == CM_ERROR_EXISTS) {
2040 NTStatus = 0xC0000035L; /* Object name collision */
2042 else if (code == CM_ERROR_NOTEMPTY) {
2043 NTStatus = 0xC0000101L; /* Directory not empty */
2045 else if (code == CM_ERROR_CROSSDEVLINK) {
2046 NTStatus = 0xC00000D4L; /* Not same device */
2048 else if (code == CM_ERROR_NOTDIR) {
2049 NTStatus = 0xC0000103L; /* Not a directory */
2051 else if (code == CM_ERROR_ISDIR) {
2052 NTStatus = 0xC00000BAL; /* File is a directory */
2054 else if (code == CM_ERROR_BADOP) {
2055 NTStatus = 0xC09820FFL; /* SMB no support */
2057 else if (code == CM_ERROR_BADSHARENAME) {
2058 NTStatus = 0xC00000CCL; /* Bad network name */
2060 else if (code == CM_ERROR_NOIPC) {
2062 NTStatus = 0xC0000022L; /* Access Denied */
2064 NTStatus = 0xC000013DL; /* Remote Resources */
2067 else if (code == CM_ERROR_CLOCKSKEW) {
2068 NTStatus = 0xC0000133L; /* Time difference at DC */
2070 else if (code == CM_ERROR_BADTID) {
2071 NTStatus = 0xC0982005L; /* SMB bad TID */
2073 else if (code == CM_ERROR_USESTD) {
2074 NTStatus = 0xC09820FBL; /* SMB use standard */
2076 else if (code == CM_ERROR_QUOTA) {
2077 NTStatus = 0xC0000044L; /* Quota exceeded */
2079 else if (code == CM_ERROR_SPACE) {
2080 NTStatus = 0xC000007FL; /* Disk full */
2082 else if (code == CM_ERROR_ATSYS) {
2083 NTStatus = 0xC0000033L; /* Object name invalid */
2085 else if (code == CM_ERROR_BADNTFILENAME) {
2086 NTStatus = 0xC0000033L; /* Object name invalid */
2088 else if (code == CM_ERROR_WOULDBLOCK) {
2089 NTStatus = 0xC0000055L; /* Lock not granted */
2091 else if (code == CM_ERROR_PARTIALWRITE) {
2092 NTStatus = 0xC000007FL; /* Disk full */
2094 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2095 NTStatus = 0xC0000023L; /* Buffer too small */
2097 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2098 NTStatus = 0xC0000035L; /* Object name collision */
2101 NTStatus = 0xC0982001L; /* SMB non-specific error */
2104 *NTStatusp = NTStatus;
2105 osi_Log2(smb_logp, "SMB SEND code %x as NT %x", code, NTStatus);
2108 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2109 unsigned char *classp)
2111 unsigned char class;
2112 unsigned short error;
2114 /* map CM_ERROR_* errors to SMB errors */
2115 if (code == CM_ERROR_NOSUCHCELL) {
2117 error = 3; /* bad path */
2119 else if (code == CM_ERROR_NOSUCHVOLUME) {
2121 error = 3; /* bad path */
2123 else if (code == CM_ERROR_TIMEDOUT) {
2125 error = 81; /* server is paused */
2127 else if (code == CM_ERROR_RETRY) {
2128 class = 2; /* shouldn't happen */
2131 else if (code == CM_ERROR_NOACCESS) {
2133 error = 4; /* bad access */
2135 else if (code == CM_ERROR_READONLY) {
2137 error = 19; /* read only */
2139 else if (code == CM_ERROR_NOSUCHFILE) {
2141 error = 2; /* ENOENT! */
2143 else if (code == CM_ERROR_NOSUCHPATH) {
2145 error = 3; /* Bad path */
2147 else if (code == CM_ERROR_TOOBIG) {
2149 error = 11; /* bad format */
2151 else if (code == CM_ERROR_INVAL) {
2152 class = 2; /* server non-specific error code */
2155 else if (code == CM_ERROR_BADFD) {
2157 error = 6; /* invalid file handle */
2159 else if (code == CM_ERROR_BADFDOP) {
2160 class = 1; /* invalid op on FD */
2163 else if (code == CM_ERROR_EXISTS) {
2165 error = 80; /* file already exists */
2167 else if (code == CM_ERROR_NOTEMPTY) {
2169 error = 5; /* delete directory not empty */
2171 else if (code == CM_ERROR_CROSSDEVLINK) {
2173 error = 17; /* EXDEV */
2175 else if (code == CM_ERROR_NOTDIR) {
2176 class = 1; /* bad path */
2179 else if (code == CM_ERROR_ISDIR) {
2180 class = 1; /* access denied; DOS doesn't have a good match */
2183 else if (code == CM_ERROR_BADOP) {
2187 else if (code == CM_ERROR_BADSHARENAME) {
2191 else if (code == CM_ERROR_NOIPC) {
2193 error = 4; /* bad access */
2195 else if (code == CM_ERROR_CLOCKSKEW) {
2196 class = 1; /* invalid function */
2199 else if (code == CM_ERROR_BADTID) {
2203 else if (code == CM_ERROR_USESTD) {
2207 else if (code == CM_ERROR_REMOTECONN) {
2211 else if (code == CM_ERROR_QUOTA) {
2212 if (vcp->flags & SMB_VCFLAG_USEV3) {
2214 error = 39; /* disk full */
2218 error = 5; /* access denied */
2221 else if (code == CM_ERROR_SPACE) {
2222 if (vcp->flags & SMB_VCFLAG_USEV3) {
2224 error = 39; /* disk full */
2228 error = 5; /* access denied */
2231 else if (code == CM_ERROR_PARTIALWRITE) {
2233 error = 39; /* disk full */
2235 else if (code == CM_ERROR_ATSYS) {
2237 error = 2; /* ENOENT */
2239 else if (code == CM_ERROR_WOULDBLOCK) {
2241 error = 33; /* lock conflict */
2243 else if (code == CM_ERROR_NOFILES) {
2245 error = 18; /* no files in search */
2247 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2249 error = 183; /* Samba uses this */
2258 osi_Log3(smb_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2261 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2263 return CM_ERROR_BADOP;
2266 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2268 unsigned short EchoCount, i;
2269 char *data, *outdata;
2272 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2274 for (i=1; i<=EchoCount; i++) {
2275 data = smb_GetSMBData(inp, &dataSize);
2276 smb_SetSMBParm(outp, 0, i);
2277 smb_SetSMBDataLength(outp, dataSize);
2278 outdata = smb_GetSMBData(outp, NULL);
2279 memcpy(outdata, data, dataSize);
2280 smb_SendPacket(vcp, outp);
2286 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2289 long count, minCount, finalCount;
2293 cm_user_t *userp = NULL;
2297 char *rawBuf = NULL;
2299 dos_ptr rawBuf = NULL;
2306 fd = smb_GetSMBParm(inp, 0);
2307 count = smb_GetSMBParm(inp, 3);
2308 minCount = smb_GetSMBParm(inp, 4);
2309 offset.HighPart = 0; /* too bad */
2310 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2312 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2313 fd, offset.LowPart, count);
2315 fidp = smb_FindFID(vcp, fd, 0);
2319 lock_ObtainMutex(&smb_RawBufLock);
2321 /* Get a raw buf, from head of list */
2322 rawBuf = smb_RawBufs;
2324 smb_RawBufs = *(char **)smb_RawBufs;
2326 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2329 lock_ReleaseMutex(&smb_RawBufLock);
2333 if (fidp->flags & SMB_FID_IOCTL)
2336 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2338 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2341 /* Give back raw buffer */
2342 lock_ObtainMutex(&smb_RawBufLock);
2344 *((char **) rawBuf) = smb_RawBufs;
2346 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2349 smb_RawBufs = rawBuf;
2350 lock_ReleaseMutex(&smb_RawBufLock);
2353 smb_ReleaseFID(fidp);
2357 userp = smb_GetUser(vcp, inp);
2360 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2362 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2363 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2364 userp, &finalCount, TRUE /* rawFlag */);
2371 cm_ReleaseUser(userp);
2374 smb_ReleaseFID(fidp);
2379 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2381 memset((char *)ncbp, 0, sizeof(NCB));
2383 ncbp->ncb_length = (unsigned short) finalCount;
2384 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2385 ncbp->ncb_lana_num = vcp->lana;
2386 ncbp->ncb_command = NCBSEND;
2387 ncbp->ncb_buffer = rawBuf;
2390 code = Netbios(ncbp);
2392 code = Netbios(ncbp, dos_ncb);
2395 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2398 /* Give back raw buffer */
2399 lock_ObtainMutex(&smb_RawBufLock);
2401 *((char **) rawBuf) = smb_RawBufs;
2403 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2406 smb_RawBufs = rawBuf;
2407 lock_ReleaseMutex(&smb_RawBufLock);
2413 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2418 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2423 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2429 int protoIndex; /* index we're using */
2434 char protocol_array[10][1024]; /* protocol signature of the client */
2437 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2441 DWORD now = GetCurrentTime();
2442 if (now - last_msg_time >= 30000
2443 && now - last_msg_time <= 90000) {
2445 "Setting dead_vcp %x", active_vcp);
2447 smb_ReleaseVC(dead_vcp);
2449 "Previous dead_vcp %x", dead_vcp);
2451 smb_HoldVC(active_vcp);
2452 dead_vcp = active_vcp;
2453 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2458 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2460 namep = smb_GetSMBData(inp, &dbytes);
2463 coreProtoIndex = -1; /* not found */
2466 while(namex < dbytes) {
2467 osi_Log1(smb_logp, "Protocol %s",
2468 osi_LogSaveString(smb_logp, namep+1));
2469 strcpy(protocol_array[tcounter], namep+1);
2471 /* namep points at the first protocol, or really, a 0x02
2472 * byte preceding the null-terminated ASCII name.
2474 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2475 coreProtoIndex = tcounter;
2477 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2478 v3ProtoIndex = tcounter;
2480 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2481 NTProtoIndex = tcounter;
2484 /* compute size of protocol entry */
2485 entryLength = strlen(namep+1);
2486 entryLength += 2; /* 0x02 bytes and null termination */
2488 /* advance over this protocol entry */
2489 namex += entryLength;
2490 namep += entryLength;
2491 tcounter++; /* which proto entry we're looking at */
2493 #ifndef NOMOREFILESFIX
2495 * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
2496 * the client is running by reading the protocol signature.
2497 * ie. the order in which it sends us the protocol list.
2499 * Special handling for Windows 2000 clients (defect 11765 )
2500 * <asanka:11Jun03> Proto signature is the same for Win XP. </>
2502 if (tcounter == 6) {
2504 smb_t *ip = (smb_t *) inp;
2505 smb_t *op = (smb_t *) outp;
2507 if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
2508 (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
2509 (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
2510 (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
2511 (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
2512 (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
2513 isWindows2000 = TRUE;
2514 osi_Log0(smb_logp, "Looks like a Windows 2000 client");
2516 * HACK: for now - just negotiate a lower protocol till we
2517 * figure out which flag/flag2 or some other field
2518 * (capabilities maybe?) to set in order for this to work
2519 * correctly with Windows 2000 clients (defect 11765)
2522 /* Things to try (after looking at tcpdump output could be
2523 * setting flags and flags2 to 0x98 and 0xc853 like this
2524 * op->reb = 0x98; op->flg2 = 0xc853;
2525 * osi_Log2(smb_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
2529 #endif /* NOMOREFILESFIX */
2531 if (NTProtoIndex != -1) {
2532 protoIndex = NTProtoIndex;
2533 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2535 else if (v3ProtoIndex != -1) {
2536 protoIndex = v3ProtoIndex;
2537 vcp->flags |= SMB_VCFLAG_USEV3;
2539 else if (coreProtoIndex != -1) {
2540 protoIndex = coreProtoIndex;
2541 vcp->flags |= SMB_VCFLAG_USECORE;
2543 else protoIndex = -1;
2545 if (protoIndex == -1)
2546 return CM_ERROR_INVAL;
2547 else if (NTProtoIndex != -1) {
2548 smb_SetSMBParm(outp, 0, protoIndex);
2549 smb_SetSMBParmByte(outp, 1, 0); /* share level security, no passwd encrypt */
2550 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2551 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2552 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2553 smb_SetSMBParmLong(outp, 5, 65536); /* raw buffer size */
2554 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2555 smb_SetSMBParm(outp, 8, 1);
2557 * Tried changing the capabilities to support for W2K - defect 117695
2558 * Maybe something else needs to be changed here?
2562 smb_SetSMBParmLong(outp, 9, 0x43fd);
2564 smb_SetSMBParmLong(outp, 9, 0x251);
2567 * 32-bit error codes *
2571 smb_SetSMBParmLong(outp, 9, 0x251);
2572 smb_SetSMBParmLong(outp, 11, 0);/* XXX server time: do we need? */
2573 smb_SetSMBParmLong(outp, 13, 0);/* XXX server date: do we need? */
2574 smb_SetSMBParm(outp, 15, 0); /* XXX server tzone: do we need? */
2575 smb_SetSMBParmByte(outp, 16, 0);/* Encryption key length */
2576 smb_SetSMBDataLength(outp, 0); /* perhaps should specify 8 bytes anyway */
2578 else if (v3ProtoIndex != -1) {
2579 smb_SetSMBParm(outp, 0, protoIndex);
2580 smb_SetSMBParm(outp, 1, 0); /* share level security, no passwd encrypt */
2581 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2582 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2583 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2584 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2585 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2586 smb_SetSMBParm(outp, 7, 1);
2587 smb_SetSMBParm(outp, 8, 0); /* XXX server time: do we need? */
2588 smb_SetSMBParm(outp, 9, 0); /* XXX server date: do we need? */
2589 smb_SetSMBParm(outp, 10, 0); /* XXX server tzone: do we need? */
2590 smb_SetSMBParm(outp, 11, 0); /* resvd */
2591 smb_SetSMBParm(outp, 12, 0); /* resvd */
2592 smb_SetSMBDataLength(outp, 0); /* perhaps should specify 8 bytes anyway */
2594 else if (coreProtoIndex != -1) {
2595 smb_SetSMBParm(outp, 0, protoIndex);
2596 smb_SetSMBDataLength(outp, 0);
2601 void smb_Daemon(void *parmp)
2608 if ((count % 360) == 0) /* every hour */
2609 smb_CalculateNowTZ();
2610 /* XXX GC dir search entries */
2614 void smb_WaitingLocksDaemon()
2616 smb_waitingLock_t *wL, *nwL;
2619 smb_packet_t *inp, *outp;
2624 lock_ObtainWrite(&smb_globalLock);
2625 nwL = smb_allWaitingLocks;
2627 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2636 lock_ObtainWrite(&smb_globalLock);
2638 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2639 lock_ReleaseWrite(&smb_globalLock);
2640 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2641 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2642 if (code == CM_ERROR_WOULDBLOCK) {
2644 if (wL->timeRemaining != 0xffffffff
2645 && (wL->timeRemaining -= 1000) < 0)
2654 ncbp->ncb_length = inp->ncb_length;
2655 inp->spacep = cm_GetSpace();
2657 /* Remove waitingLock from list */
2658 lock_ObtainWrite(&smb_globalLock);
2659 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2661 lock_ReleaseWrite(&smb_globalLock);
2663 /* Resume packet processing */
2665 smb_SetSMBDataLength(outp, 0);
2666 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2667 outp->resumeCode = code;
2669 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2672 cm_FreeSpace(inp->spacep);
2673 smb_FreePacket(inp);
2674 smb_FreePacket(outp);
2682 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2684 osi_Log0(smb_logp, "SMB receive get disk attributes");
2686 smb_SetSMBParm(outp, 0, 32000);
2687 smb_SetSMBParm(outp, 1, 64);
2688 smb_SetSMBParm(outp, 2, 1024);
2689 smb_SetSMBParm(outp, 3, 30000);
2690 smb_SetSMBParm(outp, 4, 0);
2691 smb_SetSMBDataLength(outp, 0);
2695 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2699 unsigned short newTid;
2700 char shareName[256];
2708 osi_Log0(smb_logp, "SMB receive tree connect");
2710 /* parse input parameters */
2711 tp = smb_GetSMBData(inp, NULL);
2712 pathp = smb_ParseASCIIBlock(tp, &tp);
2713 passwordp = smb_ParseASCIIBlock(tp, &tp);
2714 tp = strrchr(pathp, '\\');
2716 return CM_ERROR_BADSMB;
2717 strcpy(shareName, tp+1);
2719 userp = smb_GetUser(vcp, inp);
2721 lock_ObtainMutex(&vcp->mx);
2722 newTid = vcp->tidCounter++;
2723 lock_ReleaseMutex(&vcp->mx);
2725 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2726 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2727 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2729 smb_ReleaseUID(uidp);
2731 smb_ReleaseTID(tidp);
2732 return CM_ERROR_BADSHARENAME;
2734 lock_ObtainMutex(&tidp->mx);
2735 tidp->userp = userp;
2736 tidp->pathname = sharePath;
2737 lock_ReleaseMutex(&tidp->mx);
2738 smb_ReleaseTID(tidp);
2740 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2741 smb_SetSMBParm(rsp, 1, newTid);
2742 smb_SetSMBDataLength(rsp, 0);
2744 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2748 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2752 if (*inp++ != 0x1) return NULL;
2753 tlen = inp[0] + (inp[1]<<8);
2754 inp += 2; /* skip length field */
2757 *chainpp = inp + tlen;
2760 if (lengthp) *lengthp = tlen;
2765 /* set maskp to the mask part of the incoming path.
2766 * Mask is 11 bytes long (8.3 with the dot elided).
2767 * Returns true if succeeds with a valid name, otherwise it does
2768 * its best, but returns false.
2770 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2778 /* starts off valid */
2781 /* mask starts out all blanks */
2782 memset(maskp, ' ', 11);
2784 /* find last backslash, or use whole thing if there is none */
2785 tp = strrchr(pathp, '\\');
2786 if (!tp) tp = pathp;
2787 else tp++; /* skip slash */
2791 /* names starting with a dot are illegal */
2792 if (*tp == '.') valid8Dot3 = 0;
2796 if (tc == 0) return valid8Dot3;
2797 if (tc == '.' || tc == '"') break;
2798 if (i < 8) *up++ = tc;
2799 else valid8Dot3 = 0;
2802 /* if we get here, tp point after the dot */
2803 up = maskp+8; /* ext goes here */
2810 if (tc == '.' || tc == '"')
2813 /* copy extension if not too long */
2823 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2833 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2835 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2839 /* otherwise, we have a valid 8.3 name; see if we have a match,
2840 * treating '?' as a wildcard in maskp (but not in the file name).
2842 tp1 = umask; /* real name, in mask format */
2843 tp2 = maskp; /* mask, in mask format */
2844 for(i=0; i<11; i++) {
2845 tc1 = *tp1++; /* char from real name */
2846 tc2 = *tp2++; /* char from mask */
2847 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
2848 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
2851 if (tc2 == '?' && tc1 != ' ')
2858 /* we got a match */
2862 char *smb_FindMask(char *pathp)
2866 tp = strrchr(pathp, '\\'); /* find last slash */
2869 return tp+1; /* skip the slash */
2871 return pathp; /* no slash, return the entire path */
2874 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2876 unsigned char *pathp;
2878 unsigned char mask[11];
2879 unsigned char *statBlockp;
2880 unsigned char initStatBlock[21];
2883 osi_Log0(smb_logp, "SMB receive search volume");
2885 /* pull pathname and stat block out of request */
2886 tp = smb_GetSMBData(inp, NULL);
2887 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
2888 osi_assert(pathp != NULL);
2889 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
2890 osi_assert(statBlockp != NULL);
2892 statBlockp = initStatBlock;
2896 /* for returning to caller */
2897 smb_Get8Dot3MaskFromPath(mask, pathp);
2899 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
2900 tp = smb_GetSMBData(outp, NULL);
2902 *tp++ = 43; /* bytes in a dir entry */
2903 *tp++ = 0; /* high byte in counter */
2905 /* now marshall the dir entry, starting with the search status */
2906 *tp++ = statBlockp[0]; /* Reserved */
2907 memcpy(tp, mask, 11); tp += 11; /* FileName */
2909 /* now pass back server use info, with 1st byte non-zero */
2911 memset(tp, 0, 4); tp += 4; /* reserved for server use */
2913 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
2915 *tp++ = 0x8; /* attribute: volume */
2925 /* 4 byte file size */
2931 /* finally, null-terminated 8.3 pathname, which we set to AFS */
2932 memset(tp, ' ', 13);
2935 /* set the length of the data part of the packet to 43 + 3, for the dir
2936 * entry plus the 5 and the length fields.
2938 smb_SetSMBDataLength(outp, 46);
2942 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
2943 cm_user_t *userp, cm_req_t *reqp)
2951 smb_dirListPatch_t *patchp;
2952 smb_dirListPatch_t *npatchp;
2954 for(patchp = *dirPatchespp; patchp; patchp =
2955 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2956 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2958 lock_ObtainMutex(&scp->mx);
2959 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2960 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2962 lock_ReleaseMutex(&scp->mx);
2963 cm_ReleaseSCache(scp);
2966 dptr = patchp->dptr;
2968 attr = smb_Attributes(scp);
2969 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
2970 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2971 attr |= SMB_ATTR_HIDDEN;
2975 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2978 shortTemp = dosTime & 0xffff;
2979 *((u_short *)dptr) = shortTemp;
2982 /* and copy out date */
2983 shortTemp = (dosTime>>16) & 0xffff;
2984 *((u_short *)dptr) = shortTemp;
2987 /* copy out file length */
2988 *((u_long *)dptr) = scp->length.LowPart;
2990 lock_ReleaseMutex(&scp->mx);
2991 cm_ReleaseSCache(scp);
2994 /* now free the patches */
2995 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2996 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3000 /* and mark the list as empty */
3001 *dirPatchespp = NULL;
3006 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3015 smb_dirListPatch_t *dirListPatchesp;
3016 smb_dirListPatch_t *curPatchp;
3020 osi_hyper_t dirLength;
3021 osi_hyper_t bufferOffset;
3022 osi_hyper_t curOffset;
3024 unsigned char *inCookiep;
3025 smb_dirSearch_t *dsp;
3029 unsigned long clientCookie;
3030 cm_pageHeader_t *pageHeaderp;
3031 cm_user_t *userp = NULL;
3038 long nextEntryCookie;
3039 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3040 char resByte; /* reserved byte from the cookie */
3041 char *op; /* output data ptr */
3042 char *origOp; /* original value of op */
3043 cm_space_t *spacep; /* for pathname buffer */
3054 maxCount = smb_GetSMBParm(inp, 0);
3056 dirListPatchesp = NULL;
3058 caseFold = CM_FLAG_CASEFOLD;
3060 tp = smb_GetSMBData(inp, NULL);
3061 pathp = smb_ParseASCIIBlock(tp, &tp);
3062 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3064 /* bail out if request looks bad */
3065 if (!tp || !pathp) {
3066 return CM_ERROR_BADSMB;
3069 /* We can handle long names */
3070 if (vcp->flags & SMB_VCFLAG_USENT)
3071 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3073 /* make sure we got a whole search status */
3074 if (dataLength < 21) {
3075 nextCookie = 0; /* start at the beginning of the dir */
3078 attribute = smb_GetSMBParm(inp, 1);
3080 /* handle volume info in another function */
3081 if (attribute & 0x8)
3082 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3084 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3085 maxCount, osi_LogSaveString(smb_logp, pathp));
3087 if (*pathp == 0) { /* null pathp, treat as root dir */
3088 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3089 return CM_ERROR_NOFILES;
3093 dsp = smb_NewDirSearch(0);
3094 dsp->attribute = attribute;
3095 smb_Get8Dot3MaskFromPath(mask, pathp);
3096 memcpy(dsp->mask, mask, 11);
3098 /* track if this is likely to match a lot of entries */
3099 if (smb_IsStarMask(mask)) starPattern = 1;
3100 else starPattern = 0;
3103 /* pull the next cookie value out of the search status block */
3104 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3105 + (inCookiep[16]<<24);
3106 dsp = smb_FindDirSearch(inCookiep[12]);
3108 /* can't find dir search status; fatal error */
3109 return CM_ERROR_BADFD;
3111 attribute = dsp->attribute;
3112 resByte = inCookiep[0];
3114 /* copy out client cookie, in host byte order. Don't bother
3115 * interpreting it, since we're just passing it through, anyway.
3117 memcpy(&clientCookie, &inCookiep[17], 4);
3119 memcpy(mask, dsp->mask, 11);
3121 /* assume we're doing a star match if it has continued for more
3127 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3128 nextCookie, dsp->cookie, attribute);
3130 userp = smb_GetUser(vcp, inp);
3132 /* try to get the vnode for the path name next */
3133 lock_ObtainMutex(&dsp->mx);
3140 spacep = inp->spacep;
3141 smb_StripLastComponent(spacep->data, NULL, pathp);
3142 lock_ReleaseMutex(&dsp->mx);
3143 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3144 code = cm_NameI(cm_rootSCachep, spacep->data,
3145 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3146 lock_ObtainMutex(&dsp->mx);
3148 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3150 /* we need one hold for the entry we just stored into,
3151 * and one for our own processing. When we're done with this
3152 * function, we'll drop the one for our own processing.
3153 * We held it once from the namei call, and so we do another hold
3157 lock_ObtainMutex(&scp->mx);
3158 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3159 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3160 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3161 dsp->flags |= SMB_DIRSEARCH_BULKST;
3163 lock_ReleaseMutex(&scp->mx);
3166 lock_ReleaseMutex(&dsp->mx);
3168 cm_ReleaseUser(userp);
3169 smb_DeleteDirSearch(dsp);
3170 smb_ReleaseDirSearch(dsp);
3174 /* reserves space for parameter; we'll adjust it again later to the
3175 * real count of the # of entries we returned once we've actually
3176 * assembled the directory listing.
3178 smb_SetSMBParm(outp, 0, 0);
3180 /* get the directory size */
3181 lock_ObtainMutex(&scp->mx);
3182 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3183 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3185 lock_ReleaseMutex(&scp->mx);
3186 cm_ReleaseSCache(scp);
3187 cm_ReleaseUser(userp);
3188 smb_DeleteDirSearch(dsp);
3189 smb_ReleaseDirSearch(dsp);
3193 dirLength = scp->length;
3195 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3196 curOffset.HighPart = 0;
3197 curOffset.LowPart = nextCookie;
3198 origOp = op = smb_GetSMBData(outp, NULL);
3199 /* and write out the basic header */
3200 *op++ = 5; /* variable block */
3201 op += 2; /* skip vbl block length; we'll fill it in later */
3205 /* make sure that curOffset.LowPart doesn't point to the first
3206 * 32 bytes in the 2nd through last dir page, and that it doesn't
3207 * point at the first 13 32-byte chunks in the first dir page,
3208 * since those are dir and page headers, and don't contain useful
3211 temp = curOffset.LowPart & (2048-1);
3212 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3213 /* we're in the first page */
3214 if (temp < 13*32) temp = 13*32;
3217 /* we're in a later dir page */
3218 if (temp < 32) temp = 32;
3221 /* make sure the low order 5 bits are zero */
3224 /* now put temp bits back ito curOffset.LowPart */
3225 curOffset.LowPart &= ~(2048-1);
3226 curOffset.LowPart |= temp;
3228 /* check if we've returned all the names that will fit in the
3231 if (returnedNames >= maxCount)
3234 /* check if we've passed the dir's EOF */
3235 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3237 /* see if we can use the bufferp we have now; compute in which page
3238 * the current offset would be, and check whether that's the offset
3239 * of the buffer we have. If not, get the buffer.
3241 thyper.HighPart = curOffset.HighPart;
3242 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3243 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3246 buf_Release(bufferp);
3249 lock_ReleaseMutex(&scp->mx);
3250 lock_ObtainRead(&scp->bufCreateLock);
3251 code = buf_Get(scp, &thyper, &bufferp);
3252 lock_ReleaseRead(&scp->bufCreateLock);
3254 /* now, if we're doing a star match, do bulk fetching of all of
3255 * the status info for files in the dir.
3258 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3260 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3261 && LargeIntegerGreaterThanOrEqualTo(thyper,
3262 scp->bulkStatProgress)) {
3263 /* Don't bulk stat if risking timeout */
3264 int now = GetCurrentTime();
3265 if (now - req.startTime > 5000) {
3266 scp->bulkStatProgress = thyper;
3267 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3268 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3270 cm_TryBulkStat(scp, &thyper, userp, &req);
3274 lock_ObtainMutex(&scp->mx);
3277 bufferOffset = thyper;
3279 /* now get the data in the cache */
3281 code = cm_SyncOp(scp, bufferp, userp, &req,
3283 CM_SCACHESYNC_NEEDCALLBACK
3284 | CM_SCACHESYNC_READ);
3287 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3289 /* otherwise, load the buffer and try again */
3290 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3295 buf_Release(bufferp);
3299 } /* if (wrong buffer) ... */
3301 /* now we have the buffer containing the entry we're interested in; copy
3302 * it out if it represents a non-deleted entry.
3304 entryInDir = curOffset.LowPart & (2048-1);
3305 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3307 /* page header will help tell us which entries are free. Page header
3308 * can change more often than once per buffer, since AFS 3 dir page size
3309 * may be less than (but not more than a buffer package buffer.
3311 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3312 temp &= ~(2048 - 1); /* turn off intra-page bits */
3313 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3315 /* now determine which entry we're looking at in the page. If it is
3316 * free (there's a free bitmap at the start of the dir), we should
3317 * skip these 32 bytes.
3319 slotInPage = (entryInDir & 0x7e0) >> 5;
3320 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3321 /* this entry is free */
3322 numDirChunks = 1; /* only skip this guy */
3326 tp = bufferp->datap + entryInBuffer;
3327 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3329 /* while we're here, compute the next entry's location, too,
3330 * since we'll need it when writing out the cookie into the dir
3333 * XXXX Probably should do more sanity checking.
3335 numDirChunks = cm_NameEntries(dep->name, NULL);
3337 /* compute the offset of the cookie representing the next entry */
3338 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3340 /* Compute 8.3 name if necessary */
3341 actualName = dep->name;
3342 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3343 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3344 actualName = shortName;
3347 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3348 /* this is one of the entries to use: it is not deleted
3349 * and it matches the star pattern we're looking for.
3352 /* Eliminate entries that don't match requested
3355 /* no hidden files */
3356 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3359 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3361 /* We have already done the cm_TryBulkStat above */
3362 fid.cell = scp->fid.cell;
3363 fid.volume = scp->fid.volume;
3364 fid.vnode = ntohl(dep->fid.vnode);
3365 fid.unique = ntohl(dep->fid.unique);
3366 fileType = cm_FindFileType(&fid);
3367 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3368 "has filetype %d", dep->name,
3370 if (fileType == CM_SCACHETYPE_DIRECTORY)
3375 memcpy(op, mask, 11); op += 11;
3376 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3377 *op++ = nextEntryCookie & 0xff;
3378 *op++ = (nextEntryCookie>>8) & 0xff;
3379 *op++ = (nextEntryCookie>>16) & 0xff;
3380 *op++ = (nextEntryCookie>>24) & 0xff;
3381 memcpy(op, &clientCookie, 4); op += 4;
3383 /* now we emit the attribute. This is sort of tricky,
3384 * since we need to really stat the file to find out
3385 * what type of entry we've got. Right now, we're
3386 * copying out data from a buffer, while holding the
3387 * scp locked, so it isn't really convenient to stat
3388 * something now. We'll put in a place holder now,
3389 * and make a second pass before returning this to get
3390 * the real attributes. So, we just skip the data for
3391 * now, and adjust it later. We allocate a patch
3392 * record to make it easy to find this point later.
3393 * The replay will happen at a time when it is safe to
3394 * unlock the directory.
3396 curPatchp = malloc(sizeof(*curPatchp));
3397 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3398 curPatchp->dptr = op;
3399 curPatchp->fid.cell = scp->fid.cell;
3400 curPatchp->fid.volume = scp->fid.volume;
3401 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3402 curPatchp->fid.unique = ntohl(dep->fid.unique);
3404 /* do hidden attribute here since name won't be around when applying
3408 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3409 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3411 curPatchp->flags = 0;
3413 op += 9; /* skip attr, time, date and size */
3415 /* zero out name area. The spec says to pad with
3416 * spaces, but Samba doesn't, and neither do we.
3420 /* finally, we get to copy out the name; we know that
3421 * it fits in 8.3 or the pattern wouldn't match, but it
3422 * never hurts to be sure.
3424 strncpy(op, actualName, 13);
3426 /* Uppercase if requested by client */
3427 if ((((smb_t *)inp)->flg2 & 1) == 0)
3432 /* now, adjust the # of entries copied */
3434 } /* if we're including this name */
3437 /* and adjust curOffset to be where the new cookie is */
3438 thyper.HighPart = 0;
3439 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3440 curOffset = LargeIntegerAdd(thyper, curOffset);
3441 } /* while copying data for dir listing */
3443 /* release the mutex */
3444 lock_ReleaseMutex(&scp->mx);
3445 if (bufferp) buf_Release(bufferp);
3447 /* apply and free last set of patches; if not doing a star match, this
3448 * will be empty, but better safe (and freeing everything) than sorry.
3450 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3452 /* special return code for unsuccessful search */
3453 if (code == 0 && dataLength < 21 && returnedNames == 0)
3454 code = CM_ERROR_NOFILES;
3456 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3457 returnedNames, code);
3460 smb_DeleteDirSearch(dsp);
3461 smb_ReleaseDirSearch(dsp);
3462 cm_ReleaseSCache(scp);
3463 cm_ReleaseUser(userp);
3467 /* finalize the output buffer */
3468 smb_SetSMBParm(outp, 0, returnedNames);
3469 temp = (long) (op - origOp);
3470 smb_SetSMBDataLength(outp, temp);
3472 /* the data area is a variable block, which has a 5 (already there)
3473 * followed by the length of the # of data bytes. We now know this to
3474 * be "temp," although that includes the 3 bytes of vbl block header.
3475 * Deduct for them and fill in the length field.
3477 temp -= 3; /* deduct vbl block info */
3478 osi_assert(temp == (43 * returnedNames));
3479 origOp[1] = temp & 0xff;
3480 origOp[2] = (temp>>8) & 0xff;
3481 if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3482 smb_ReleaseDirSearch(dsp);
3483 cm_ReleaseSCache(scp);
3484 cm_ReleaseUser(userp);
3488 /* verify that this is a valid path to a directory. I don't know why they
3489 * don't use the get file attributes call.
3491 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3495 cm_scache_t *rootScp;
3496 cm_scache_t *newScp;
3505 pathp = smb_GetSMBData(inp, NULL);
3506 pathp = smb_ParseASCIIBlock(pathp, NULL);
3507 osi_Log1(smb_logp, "SMB receive check path %s",
3508 osi_LogSaveString(smb_logp, pathp));
3511 return CM_ERROR_BADFD;
3514 rootScp = cm_rootSCachep;
3516 userp = smb_GetUser(vcp, inp);
3518 caseFold = CM_FLAG_CASEFOLD;
3520 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3521 code = cm_NameI(rootScp, pathp,
3522 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3523 userp, tidPathp, &req, &newScp);
3526 cm_ReleaseUser(userp);
3530 /* now lock the vnode with a callback; returns with newScp locked */
3531 lock_ObtainMutex(&newScp->mx);
3532 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3533 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3534 if (code && code != CM_ERROR_NOACCESS) {
3535 lock_ReleaseMutex(&newScp->mx);
3536 cm_ReleaseSCache(newScp);
3537 cm_ReleaseUser(userp);
3541 attrs = smb_Attributes(newScp);
3543 if (!(attrs & 0x10))
3544 code = CM_ERROR_NOTDIR;
3546 lock_ReleaseMutex(&newScp->mx);
3548 cm_ReleaseSCache(newScp);
3549 cm_ReleaseUser(userp);
3553 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3557 cm_scache_t *rootScp;
3558 unsigned short attribute;
3560 cm_scache_t *newScp;
3569 /* decode basic attributes we're passed */
3570 attribute = smb_GetSMBParm(inp, 0);
3571 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3573 pathp = smb_GetSMBData(inp, NULL);
3574 pathp = smb_ParseASCIIBlock(pathp, NULL);
3577 return CM_ERROR_BADSMB;
3580 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3581 dosTime, attribute);
3583 rootScp = cm_rootSCachep;
3585 userp = smb_GetUser(vcp, inp);
3587 caseFold = CM_FLAG_CASEFOLD;
3589 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3590 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3591 tidPathp, &req, &newScp);
3594 cm_ReleaseUser(userp);
3598 /* now lock the vnode with a callback; returns with newScp locked; we
3599 * need the current status to determine what the new status is, in some
3602 lock_ObtainMutex(&newScp->mx);
3603 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3604 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3606 lock_ReleaseMutex(&newScp->mx);
3607 cm_ReleaseSCache(newScp);
3608 cm_ReleaseUser(userp);
3612 /* Check for RO volume */
3613 if (newScp->flags & CM_SCACHEFLAG_RO) {
3614 lock_ReleaseMutex(&newScp->mx);
3615 cm_ReleaseSCache(newScp);
3616 cm_ReleaseUser(userp);
3617 return CM_ERROR_READONLY;
3620 /* prepare for setattr call */
3623 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3624 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3626 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3627 /* we're told to make a writable file read-only */
3628 attr.unixModeBits = newScp->unixModeBits & ~0222;
3629 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3631 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3632 /* we're told to make a read-only file writable */
3633 attr.unixModeBits = newScp->unixModeBits | 0222;
3634 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3636 lock_ReleaseMutex(&newScp->mx);
3638 /* now call setattr */
3640 code = cm_SetAttr(newScp, &attr, userp, &req);
3644 cm_ReleaseSCache(newScp);
3645 cm_ReleaseUser(userp);
3650 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3654 cm_scache_t *rootScp;
3655 cm_scache_t *newScp, *dscp;
3667 pathp = smb_GetSMBData(inp, NULL);
3668 pathp = smb_ParseASCIIBlock(pathp, NULL);
3671 return CM_ERROR_BADSMB;
3674 if (*pathp == 0) /* null path */
3677 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3678 osi_LogSaveString(smb_logp, pathp));
3680 rootScp = cm_rootSCachep;
3682 userp = smb_GetUser(vcp, inp);
3684 /* we shouldn't need this for V3 requests, but we seem to */
3685 caseFold = CM_FLAG_CASEFOLD;
3687 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3690 * XXX Strange hack XXX
3692 * As of Patch 5 (16 July 97), we are having the following problem:
3693 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3694 * requests to look up "desktop.ini" in all the subdirectories.
3695 * This can cause zillions of timeouts looking up non-existent cells
3696 * and volumes, especially in the top-level directory.
3698 * We have not found any way to avoid this or work around it except
3699 * to explicitly ignore the requests for mount points that haven't
3700 * yet been evaluated and for directories that haven't yet been
3703 * We should modify this hack to provide a fake desktop.ini file
3704 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3706 spacep = inp->spacep;
3707 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3708 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3709 code = cm_NameI(rootScp, spacep->data,
3710 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3711 userp, tidPathp, &req, &dscp);
3713 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3714 && !dscp->mountRootFidp)
3715 code = CM_ERROR_NOSUCHFILE;
3716 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3717 cm_buf_t *bp = buf_Find(dscp, &hzero);
3721 code = CM_ERROR_NOSUCHFILE;
3723 cm_ReleaseSCache(dscp);
3725 cm_ReleaseUser(userp);
3731 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3732 tidPathp, &req, &newScp);
3735 cm_ReleaseUser(userp);
3739 /* now lock the vnode with a callback; returns with newScp locked */
3740 lock_ObtainMutex(&newScp->mx);
3741 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3742 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3744 lock_ReleaseMutex(&newScp->mx);
3745 cm_ReleaseSCache(newScp);
3746 cm_ReleaseUser(userp);
3751 /* use smb_Attributes instead. Also the fact that a file is
3752 * in a readonly volume doesn't mean it shojuld be marked as RO
3754 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
3755 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
3756 attrs = SMB_ATTR_DIRECTORY;
3759 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
3760 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
3762 attrs = smb_Attributes(newScp);
3765 smb_SetSMBParm(outp, 0, attrs);
3767 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
3768 smb_SetSMBParm(outp, 1, dosTime & 0xffff);
3769 smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
3770 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
3771 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
3772 smb_SetSMBParm(outp, 5, 0);
3773 smb_SetSMBParm(outp, 6, 0);
3774 smb_SetSMBParm(outp, 7, 0);
3775 smb_SetSMBParm(outp, 8, 0);
3776 smb_SetSMBParm(outp, 9, 0);
3777 smb_SetSMBDataLength(outp, 0);
3778 lock_ReleaseMutex(&newScp->mx);
3780 cm_ReleaseSCache(newScp);
3781 cm_ReleaseUser(userp);
3786 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3790 osi_Log0(smb_logp, "SMB receive tree disconnect");
3792 /* find the tree and free it */
3793 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
3795 lock_ObtainMutex(&tidp->mx);
3796 tidp->flags |= SMB_TIDFLAG_DELETE;
3797 lock_ReleaseMutex(&tidp->mx);
3798 smb_ReleaseTID(tidp);
3804 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3822 pathp = smb_GetSMBData(inp, NULL);
3823 pathp = smb_ParseASCIIBlock(pathp, NULL);
3825 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
3827 #ifdef DEBUG_VERBOSE
3831 hexpath = osi_HexifyString( pathp );
3832 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
3837 share = smb_GetSMBParm(inp, 0);
3838 attribute = smb_GetSMBParm(inp, 1);
3840 spacep = inp->spacep;
3841 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3842 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3843 /* special case magic file name for receiving IOCTL requests
3844 * (since IOCTL calls themselves aren't getting through).
3846 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3847 smb_SetupIoctlFid(fidp, spacep);
3848 smb_SetSMBParm(outp, 0, fidp->fid);
3849 smb_SetSMBParm(outp, 1, 0); /* attrs */
3850 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
3851 smb_SetSMBParm(outp, 3, 0);
3852 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
3853 smb_SetSMBParm(outp, 5, 0x7fff);
3854 /* pass the open mode back */
3855 smb_SetSMBParm(outp, 6, (share & 0xf));
3856 smb_SetSMBDataLength(outp, 0);
3857 smb_ReleaseFID(fidp);
3861 userp = smb_GetUser(vcp, inp);
3863 caseFold = CM_FLAG_CASEFOLD;
3865 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3866 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3867 tidPathp, &req, &scp);
3870 cm_ReleaseUser(userp);
3874 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
3876 cm_ReleaseSCache(scp);
3877 cm_ReleaseUser(userp);
3881 /* don't need callback to check file type, since file types never
3882 * change, and namei and cm_Lookup all stat the object at least once on
3883 * a successful return.
3885 if (scp->fileType != CM_SCACHETYPE_FILE) {
3886 cm_ReleaseSCache(scp);
3887 cm_ReleaseUser(userp);
3888 return CM_ERROR_ISDIR;
3891 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3894 /* save a pointer to the vnode */
3897 if ((share & 0xf) == 0)
3898 fidp->flags |= SMB_FID_OPENREAD;
3899 else if ((share & 0xf) == 1)
3900 fidp->flags |= SMB_FID_OPENWRITE;
3902 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
3904 lock_ObtainMutex(&scp->mx);
3905 smb_SetSMBParm(outp, 0, fidp->fid);
3906 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
3907 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
3908 smb_SetSMBParm(outp, 2, dosTime & 0xffff);
3909 smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
3910 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
3911 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
3912 /* pass the open mode back; XXXX add access checks */
3913 smb_SetSMBParm(outp, 6, (share & 0xf));
3914 smb_SetSMBDataLength(outp, 0);
3915 lock_ReleaseMutex(&scp->mx);
3918 cm_Open(scp, 0, userp);
3920 /* send and free packet */
3921 smb_ReleaseFID(fidp);
3922 cm_ReleaseUser(userp);
3923 /* don't release scp, since we've squirreled away the pointer in the fid struct */
3927 typedef struct smb_unlinkRock {
3932 char *maskp; /* pointer to the star pattern */
3937 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3940 smb_unlinkRock_t *rockp;
3948 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
3949 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
3950 caseFold |= CM_FLAG_8DOT3;
3952 matchName = dep->name;
3953 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3955 && (rockp->flags & SMB_MASKFLAG_TILDE)
3956 && !cm_Is8Dot3(dep->name)) {
3957 cm_Gen8Dot3Name(dep, shortName, NULL);
3958 matchName = shortName;
3959 /* 8.3 matches are always case insensitive */
3960 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
3963 osi_Log1(smb_logp, "Unlinking %s",
3964 osi_LogSaveString(smb_logp, matchName));
3965 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
3966 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3967 smb_NotifyChange(FILE_ACTION_REMOVED,
3968 FILE_NOTIFY_CHANGE_FILE_NAME,
3969 dscp, dep->name, NULL, TRUE);
3972 /* If we made a case sensitive exact match, we might as well quit now. */
3973 if(!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
3974 code = CM_ERROR_STOPNOW;
3982 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3991 smb_unlinkRock_t rock;
4000 attribute = smb_GetSMBParm(inp, 0);
4002 tp = smb_GetSMBData(inp, NULL);
4003 pathp = smb_ParseASCIIBlock(tp, &tp);
4005 osi_Log1(smb_logp, "SMB receive unlink %s",
4006 osi_LogSaveString(smb_logp, pathp));
4008 spacep = inp->spacep;
4009 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4011 userp = smb_GetUser(vcp, inp);
4013 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4015 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4016 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4020 cm_ReleaseUser(userp);