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;
50 int smbShutdownFlag = 0;
53 int smb_LogoffTokenTransfer;
54 unsigned long smb_LogoffTransferTimeout;
56 DWORD last_msg_time = 0;
60 unsigned int sessionGen = 0;
62 extern void afsi_log(char *pattern, ...);
64 osi_hyper_t hzero = {0, 0};
65 osi_hyper_t hones = {0xFFFFFFFF, -1};
68 osi_rwlock_t smb_globalLock;
69 osi_rwlock_t smb_rctLock;
70 osi_mutex_t smb_ListenerLock;
73 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
76 long smb_maxObsConcurrentCalls=0;
77 long smb_concurrentCalls=0;
79 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
81 smb_packet_t *smb_packetFreeListp;
82 smb_ncb_t *smb_ncbFreeListp;
84 int smb_NumServerThreads;
86 int numNCBs, numSessions;
88 int smb_maxVCPerServer;
89 int smb_maxMpxRequests;
92 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
93 EVENT_HANDLE **NCBreturns;
94 DWORD NCBsessions[NCBmax];
96 struct smb_packet *bufs[NCBmax];
98 #define Sessionmax 100
99 EVENT_HANDLE SessionEvents[Sessionmax];
100 unsigned short LSNs[Sessionmax];
101 int lanas[Sessionmax];
102 BOOL dead_sessions[Sessionmax];
106 osi_mutex_t smb_RawBufLock;
108 #define SMB_RAW_BUFS 4
110 int smb_RawBufSel[SMB_RAW_BUFS];
115 #define RAWTIMEOUT INFINITE
118 typedef struct raw_write_cont {
131 /* dir search stuff */
132 long smb_dirSearchCounter = 1;
133 smb_dirSearch_t *smb_firstDirSearchp;
134 smb_dirSearch_t *smb_lastDirSearchp;
136 /* hide dot files? */
137 int smb_hideDotFiles;
139 /* global state about V3 protocols */
140 int smb_useV3; /* try to negotiate V3 */
143 /* MessageBox or something like it */
144 int (WINAPI *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
148 * Time in Unix format of midnight, 1/1/1970 local time.
149 * When added to dosUTime, gives Unix (AFS) time.
153 /* Time difference for converting to kludge-GMT */
156 char *smb_localNamep = NULL;
158 smb_vc_t *smb_allVCsp;
160 smb_username_t *usernamesp = NULL;
162 smb_waitingLock_t *smb_allWaitingLocks;
165 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
166 NCB *ncbp, raw_write_cont_t *rwcp);
167 void smb_NetbiosInit();
169 #ifndef AFS_WIN95_ENV
170 DWORD smb_ServerExceptionFilter(void);
173 extern char cm_HostName[];
174 extern char cm_confDir[];
178 #define LPTSTR char *
179 #define GetComputerName(str, sizep) \
180 strcpy((str), cm_HostName); \
181 *(sizep) = strlen(cm_HostName)
187 * To build an expiring version, comment out the definition of NOEXPIRE,
188 * and set the definition of EXPIREDATE to the desired value.
191 #define EXPIREDATE 834000000 /* Wed Jun 5 1996 */
194 char * myCrt_Dispatch(int i)
199 return "unknown SMB op";
201 return "(00)ReceiveCoreMakeDir";
203 return "(01)ReceiveCoreRemoveDir";
205 return "(02)ReceiveCoreOpen";
207 return "(03)ReceiveCoreCreate";
209 return "(04)ReceiveCoreClose";
211 return "(05)ReceiveCoreFlush";
213 return "(06)ReceiveCoreUnlink";
215 return "(07)ReceiveCoreRename";
217 return "(08)ReceiveCoreGetFileAttributes";
219 return "(09)ReceiveCoreSetFileAttributes";
221 return "(0a)ReceiveCoreRead";
223 return "(0b)ReceiveCoreWrite";
225 return "(0c)ReceiveCoreLockRecord";
227 return "(0d)ReceiveCoreUnlockRecord";
229 return "(0e)SendCoreBadOp";
231 return "(0f)ReceiveCoreCreate";
233 return "(10)ReceiveCoreCheckPath";
235 return "(11)SendCoreBadOp";
237 return "(12)ReceiveCoreSeek";
239 return "(1a)ReceiveCoreReadRaw";
241 return "(1d)ReceiveCoreWriteRawDummy";
243 return "(22)ReceiveV3SetAttributes";
245 return "(23)ReceiveV3GetAttributes";
247 return "(24)ReceiveV3LockingX";
249 return "(29)SendCoreBadOp";
251 return "(2b)ReceiveCoreEcho";
253 return "(2d)ReceiveV3OpenX";
255 return "(2e)ReceiveV3ReadX";
257 return "(32)ReceiveV3Tran2A";
259 return "(33)ReceiveV3Tran2A";
261 return "(34)ReceiveV3FindClose";
263 return "(35)ReceiveV3FindNotifyClose";
265 return "(70)ReceiveCoreTreeConnect";
267 return "(71)ReceiveCoreTreeDisconnect";
269 return "(72)ReceiveNegotiate";
271 return "(73)ReceiveV3SessionSetupX";
273 return "(74)ReceiveV3UserLogoffX";
275 return "(75)ReceiveV3TreeConnectX";
277 return "(80)ReceiveCoreGetDiskAttributes";
279 return "(81)ReceiveCoreSearchDir";
281 return "(A0)ReceiveNTTransact";
283 return "(A2)ReceiveNTCreateX";
285 return "(A4)ReceiveNTCancel";
287 return "(c0)SendCoreBadOp";
289 return "(c1)SendCoreBadOp";
291 return "(c2)SendCoreBadOp";
293 return "(c3)SendCoreBadOp";
297 char * myCrt_2Dispatch(int i)
302 return "unknown SMB op-2";
304 return "S(00)CreateFile";
306 return "S(01)FindFirst";
308 return "S(02)FindNext"; /* FindNext */
310 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
314 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
316 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
318 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
320 return "S(08)??_ReceiveTran2SetFileInfo";
322 return "S(09)??_ReceiveTran2FSCTL";
324 return "S(0a)_ReceiveTran2IOCTL";
326 return "S(0b)_ReceiveTran2FindNotifyFirst";
328 return "S(0c)_ReceiveTran2FindNotifyNext";
330 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
334 /* scache must be locked */
335 unsigned int smb_Attributes(cm_scache_t *scp)
339 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
340 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
341 attrs = SMB_ATTR_DIRECTORY;
346 * We used to mark a file RO if it was in an RO volume, but that
347 * turns out to be impolitic in NT. See defect 10007.
350 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
352 if ((scp->unixModeBits & 0222) == 0)
353 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
358 /* Check if the named file/dir is a dotfile/dotdir */
359 /* String pointed to by lastComp can have leading slashes, but otherwise should have
360 no other patch components */
361 unsigned int smb_IsDotFile(char *lastComp) {
364 /* skip over slashes */
365 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
370 /* nulls, curdir and parent dir doesn't count */
373 if(!*(s + 1)) return 0;
374 if(*(s+1) == '.' && !*(s + 2)) return 0;
380 static int ExtractBits(WORD bits, short start, short len)
387 num = bits << (16 - end);
388 num = num >> ((16 - end) + start);
394 void ShowUnixTime(char *FuncName, long unixTime)
399 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
401 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
402 osi_Log1(afsd_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
404 int day, month, year, sec, min, hour;
407 day = ExtractBits(wDate, 0, 5);
408 month = ExtractBits(wDate, 5, 4);
409 year = ExtractBits(wDate, 9, 7) + 1980;
411 sec = ExtractBits(wTime, 0, 5);
412 min = ExtractBits(wTime, 5, 6);
413 hour = ExtractBits(wTime, 11, 5);
415 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
416 osi_Log1(afsd_logp, "%s", osi_LogSaveString(afsd_logp, msg));
422 /* Determine if we are observing daylight savings time */
423 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
425 TIME_ZONE_INFORMATION timeZoneInformation;
426 SYSTEMTIME utc, local, localDST;
428 /* Get the time zone info. NT uses this to calc if we are in DST. */
429 GetTimeZoneInformation(&timeZoneInformation);
431 /* Return the daylight bias */
432 *pDstBias = timeZoneInformation.DaylightBias;
434 /* Return the bias */
435 *pBias = timeZoneInformation.Bias;
437 /* Now determine if DST is being observed */
439 /* Get the UTC (GMT) time */
442 /* Convert UTC time to local time using the time zone info. If we are
443 observing DST, the calculated local time will include this.
445 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
447 /* Set the daylight bias to 0. The daylight bias is the amount of change
448 in time that we use for daylight savings time. By setting this to 0
449 we cause there to be no change in time during daylight savings time.
451 timeZoneInformation.DaylightBias = 0;
453 /* Convert the utc time to local time again, but this time without any
454 adjustment for daylight savings time.
456 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
458 /* If the two times are different, then it means that the localDST that
459 we calculated includes the daylight bias, and therefore we are
460 observing daylight savings time.
462 *pDST = localDST.wHour != local.wHour;
465 /* Determine if we are observing daylight savings time */
466 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
472 *pDstBias = -60; /* where can this be different? */
478 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
480 BOOL dst; /* Will be TRUE if observing DST */
481 LONG dstBias; /* Offset from local time if observing DST */
482 LONG bias; /* Offset from GMT for local time */
485 * This function will adjust the last write time to compensate
486 * for two bugs in the smb client:
488 * 1) During Daylight Savings Time, the LastWriteTime is ahead
489 * in time by the DaylightBias (ignoring the sign - the
490 * DaylightBias is always stored as a negative number). If
491 * the DaylightBias is -60, then the LastWriteTime will be
492 * ahead by 60 minutes.
494 * 2) If the local time zone is a positive offset from GMT, then
495 * the LastWriteTime will be the correct local time plus the
496 * Bias (ignoring the sign - a positive offset from GMT is
497 * always stored as a negative Bias). If the Bias is -120,
498 * then the LastWriteTime will be ahead by 120 minutes.
500 * These bugs can occur at the same time.
503 GetTimeZoneInfo(&dst, &dstBias, &bias);
505 /* First adjust for DST */
507 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
509 /* Now adjust for a positive offset from GMT (a negative bias). */
511 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
515 * Calculate the difference (in seconds) between local time and GMT.
516 * This enables us to convert file times to kludge-GMT.
522 struct tm gmt_tm, local_tm;
523 int days, hours, minutes, seconds;
526 gmt_tm = *(gmtime(&t));
527 local_tm = *(localtime(&t));
529 days = local_tm.tm_yday - gmt_tm.tm_yday;
530 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
531 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
532 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
538 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
543 long ersatz_unixTime;
546 * Must use kludge-GMT instead of real GMT.
547 * kludge-GMT is computed by adding time zone difference to localtime.
550 * ltp = gmtime(&unixTime);
552 ersatz_unixTime = unixTime - smb_NowTZ;
553 ltp = localtime(&ersatz_unixTime);
555 /* if we fail, make up something */
558 localJunk.tm_year = 89 - 20;
559 localJunk.tm_mon = 4;
560 localJunk.tm_mday = 12;
561 localJunk.tm_hour = 0;
562 localJunk.tm_min = 0;
563 localJunk.tm_sec = 0;
566 stm.wYear = ltp->tm_year + 1900;
567 stm.wMonth = ltp->tm_mon + 1;
568 stm.wDayOfWeek = ltp->tm_wday;
569 stm.wDay = ltp->tm_mday;
570 stm.wHour = ltp->tm_hour;
571 stm.wMinute = ltp->tm_min;
572 stm.wSecond = ltp->tm_sec;
573 stm.wMilliseconds = 0;
575 SystemTimeToFileTime(&stm, largeTimep);
578 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
580 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
581 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
582 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
584 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
586 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
587 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
589 *ft = LargeIntegerMultiplyByLong(*ft, 60);
590 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
593 ut = ConvertLongToLargeInteger(unixTime);
594 ut = LargeIntegerMultiplyByLong(ut, 10000000);
595 *ft = LargeIntegerAdd(*ft, ut);
600 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
606 FileTimeToSystemTime(largeTimep, &stm);
608 lt.tm_year = stm.wYear - 1900;
609 lt.tm_mon = stm.wMonth - 1;
610 lt.tm_wday = stm.wDayOfWeek;
611 lt.tm_mday = stm.wDay;
612 lt.tm_hour = stm.wHour;
613 lt.tm_min = stm.wMinute;
614 lt.tm_sec = stm.wSecond;
617 save_timezone = _timezone;
618 _timezone += smb_NowTZ;
619 *unixTimep = mktime(<);
620 _timezone = save_timezone;
623 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
625 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
626 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
627 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
631 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
632 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60
634 a = LargeIntegerMultiplyByLong(a, 60);
635 a = LargeIntegerMultiplyByLong(a, 10000000);
637 /* subtract it from ft */
638 a = LargeIntegerSubtract(*ft, a);
640 /* divide down to seconds */
641 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
645 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
652 ltp = localtime((time_t*) &unixTime);
654 /* if we fail, make up something */
657 localJunk.tm_year = 89 - 20;
658 localJunk.tm_mon = 4;
659 localJunk.tm_mday = 12;
660 localJunk.tm_hour = 0;
661 localJunk.tm_min = 0;
662 localJunk.tm_sec = 0;
665 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
666 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
667 *dosTimep = (dosDate<<16) | dosTime;
670 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
672 unsigned short dosDate;
673 unsigned short dosTime;
676 dosDate = searchTime & 0xffff;
677 dosTime = (searchTime >> 16) & 0xffff;
679 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
680 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
681 localTm.tm_mday = (dosDate) & 0x1f;
682 localTm.tm_hour = (dosTime>>11) & 0x1f;
683 localTm.tm_min = (dosTime >> 5) & 0x3f;
684 localTm.tm_sec = (dosTime & 0x1f) * 2;
685 localTm.tm_isdst = -1; /* compute whether DST in effect */
687 *unixTimep = mktime(&localTm);
690 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
692 *dosUTimep = unixTime - smb_localZero;
695 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
698 *unixTimep = dosTime + smb_localZero;
700 /* dosTime seems to be already adjusted for GMT */
701 *unixTimep = dosTime;
705 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
709 lock_ObtainWrite(&smb_rctLock);
710 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
711 if (lsn == vcp->lsn && lana == vcp->lana) {
716 if (!vcp && (flags & SMB_FLAG_CREATE)) {
717 vcp = malloc(sizeof(*vcp));
718 memset(vcp, 0, sizeof(*vcp));
722 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
723 vcp->nextp = smb_allVCsp;
725 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
729 lock_ReleaseWrite(&smb_rctLock);
733 int smb_IsStarMask(char *maskp)
738 for(i=0; i<11; i++) {
740 if (tc == '?' || tc == '*' || tc == '>') return 1;
745 void smb_ReleaseVC(smb_vc_t *vcp)
747 lock_ObtainWrite(&smb_rctLock);
748 osi_assert(vcp->refCount-- > 0);
749 lock_ReleaseWrite(&smb_rctLock);
752 void smb_HoldVC(smb_vc_t *vcp)
754 lock_ObtainWrite(&smb_rctLock);
756 lock_ReleaseWrite(&smb_rctLock);
759 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
763 lock_ObtainWrite(&smb_rctLock);
764 for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
765 if (tid == tidp->tid) {
770 if (!tidp && (flags & SMB_FLAG_CREATE)) {
771 tidp = malloc(sizeof(*tidp));
772 memset(tidp, 0, sizeof(*tidp));
773 tidp->nextp = vcp->tidsp;
777 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
780 lock_ReleaseWrite(&smb_rctLock);
784 void smb_ReleaseTID(smb_tid_t *tidp)
791 lock_ObtainWrite(&smb_rctLock);
792 osi_assert(tidp->refCount-- > 0);
793 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
794 ltpp = &tidp->vcp->tidsp;
795 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
796 if (tp == tidp) break;
798 osi_assert(tp != NULL);
800 lock_FinalizeMutex(&tidp->mx);
801 userp = tidp->userp; /* remember to drop ref later */
803 lock_ReleaseWrite(&smb_rctLock);
805 cm_ReleaseUser(userp);
809 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
811 smb_user_t *uidp = NULL;
813 lock_ObtainWrite(&smb_rctLock);
814 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
815 if (uid == uidp->userID) {
817 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 : "");
821 if (!uidp && (flags & SMB_FLAG_CREATE)) {
822 uidp = malloc(sizeof(*uidp));
823 memset(uidp, 0, sizeof(*uidp));
824 uidp->nextp = vcp->usersp;
828 lock_InitializeMutex(&uidp->mx, "uid_t mutex");
830 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 : ""));
832 lock_ReleaseWrite(&smb_rctLock);
836 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
838 smb_username_t *unp= NULL;
840 lock_ObtainWrite(&smb_rctLock);
841 for(unp = usernamesp; unp; unp = unp->nextp) {
842 if (stricmp(unp->name, usern) == 0 &&
843 stricmp(unp->machine, machine) == 0) {
848 if (!unp && (flags & SMB_FLAG_CREATE)) {
849 unp = malloc(sizeof(*unp));
850 memset(unp, 0, sizeof(*unp));
852 unp->nextp = usernamesp;
853 unp->name = strdup(usern);
854 unp->machine = strdup(machine);
856 lock_InitializeMutex(&unp->mx, "username_t mutex");
858 lock_ReleaseWrite(&smb_rctLock);
862 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
864 smb_user_t *uidp= NULL;
866 lock_ObtainWrite(&smb_rctLock);
867 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
870 if (stricmp(uidp->unp->name, usern) == 0) {
872 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
877 lock_ReleaseWrite(&smb_rctLock);
880 void smb_ReleaseUID(smb_user_t *uidp)
887 lock_ObtainWrite(&smb_rctLock);
888 osi_assert(uidp->refCount-- > 0);
889 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
890 lupp = &uidp->vcp->usersp;
891 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
892 if (up == uidp) break;
894 osi_assert(up != NULL);
896 lock_FinalizeMutex(&uidp->mx);
898 userp = uidp->unp->userp; /* remember to drop ref later */
900 lock_ReleaseWrite(&smb_rctLock);
902 cm_ReleaseUserVCRef(userp);
903 cm_ReleaseUser(userp);
907 /* retrieve a held reference to a user structure corresponding to an incoming
909 * corresponding release function is cm_ReleaseUser.
911 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
917 smbp = (smb_t *) inp;
918 uidp = smb_FindUID(vcp, smbp->uid, 0);
919 if ((!uidp) || (!uidp->unp))
922 lock_ObtainMutex(&uidp->mx);
923 up = uidp->unp->userp;
925 lock_ReleaseMutex(&uidp->mx);
927 smb_ReleaseUID(uidp);
933 * Return a pointer to a pathname extracted from a TID structure. The
934 * TID structure is not held; assume it won't go away.
936 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
941 tidp = smb_FindTID(vcp, tid, 0);
944 tpath = tidp->pathname;
945 smb_ReleaseTID(tidp);
949 /* check to see if we have a chained fid, that is, a fid that comes from an
950 * OpenAndX message that ran earlier in this packet. In this case, the fid
951 * field in a read, for example, request, isn't set, since the value is
952 * supposed to be inherited from the openAndX call.
954 int smb_ChainFID(int fid, smb_packet_t *inp)
956 if (inp->fid == 0 || inp->inCount == 0) return fid;
957 else return inp->fid;
960 /* are we a priv'd user? What does this mean on NT? */
961 int smb_SUser(cm_user_t *userp)
966 /* find a file ID. If pass in 0, we'll allocate on on a create operation. */
967 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
972 /* figure out if we need to allocate a new file ID */
975 fid = vcp->fidCounter;
979 lock_ObtainWrite(&smb_rctLock);
981 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
982 if (fid == fidp->fid) {
985 if (fid == 0) fid = 1;
992 if (!fidp && (flags & SMB_FLAG_CREATE)) {
993 fidp = malloc(sizeof(*fidp));
994 memset(fidp, 0, sizeof(*fidp));
995 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
998 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1000 fidp->curr_chunk = fidp->prev_chunk = -2;
1001 fidp->raw_write_event = thrd_CreateEvent(NULL, FALSE, TRUE, NULL);
1003 vcp->fidCounter = fid+1;
1004 if (vcp->fidCounter == 0) vcp->fidCounter = 1;
1007 lock_ReleaseWrite(&smb_rctLock);
1011 void smb_ReleaseFID(smb_fid_t *fidp)
1015 smb_ioctl_t *ioctlp;
1021 lock_ObtainWrite(&smb_rctLock);
1022 osi_assert(fidp->refCount-- > 0);
1023 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1025 if (!(fidp->flags & SMB_FID_IOCTL))
1027 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1028 thrd_CloseHandle(fidp->raw_write_event);
1030 /* and see if there is ioctl stuff to free */
1031 ioctlp = fidp->ioctlp;
1033 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1034 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1035 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1041 lock_ReleaseWrite(&smb_rctLock);
1043 /* now release the scache structure */
1044 if (scp) cm_ReleaseSCache(scp);
1048 * Case-insensitive search for one string in another;
1049 * used to find variable names in submount pathnames.
1051 static char *smb_stristr(char *str1, char *str2)
1055 for (cursor = str1; *cursor; cursor++)
1056 if (stricmp(cursor, str2) == 0)
1063 * Substitute a variable value for its name in a submount pathname. Variable
1064 * name has been identified by smb_stristr() and is in substr. Variable name
1065 * length (plus one) is in substr_size. Variable value is in newstr.
1067 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1072 strcpy(temp, substr + substr_size - 1);
1073 strcpy(substr, newstr);
1077 char VNUserName[] = "%USERNAME%";
1078 char VNLCUserName[] = "%LCUSERNAME%";
1079 char VNComputerName[] = "%COMPUTERNAME%";
1080 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1082 /* List available shares */
1083 int smb_ListShares()
1087 char shareBuf[4096];
1095 /*strcpy(shareNameList[num_shares], "all");
1096 strcpy(pathNameList[num_shares++], "/afs");*/
1097 fprintf(stderr, "The following shares are available:\n");
1098 fprintf(stderr, "Share Name (AFS Path)\n");
1099 fprintf(stderr, "---------------------\n");
1100 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1103 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1104 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1106 strcpy(sbmtpath, cm_confDir);
1108 strcat(sbmtpath, "/afsdsbmt.ini");
1109 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1110 shareBuf, sizeof(shareBuf),
1116 this_share = shareBuf;
1120 /*strcpy(shareNameList[num_shares], this_share);*/
1121 len = GetPrivateProfileString("AFS Submounts", this_share,
1125 if (!len) return num_shares;
1127 if (strncmp(p, cm_mountRoot, 4) != 0)
1130 if (*p == '\\') *p = '/'; /* change to / */
1134 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1135 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1138 while (*this_share != 0) this_share++; /* find next NUL */
1139 this_share++; /* skip past the NUL */
1140 } while (*this_share != 0); /* stop at final NUL */
1145 /* find a shareName in the table of submounts */
1146 int smb_FindShare(smb_vc_t *vcp, smb_packet_t *inp, char *shareName,
1150 char pathName[1024];
1158 if (strcmp(shareName, "IPC$") == 0) {
1163 if (_stricmp(shareName, "all") == 0) {
1169 strcpy(sbmtpath, "afsdsbmt.ini");
1171 strcpy(sbmtpath, cm_confDir);
1172 strcat(sbmtpath, "/afsdsbmt.ini");
1174 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1175 pathName, sizeof(pathName), sbmtpath);
1176 if (len == 0 || len == sizeof(pathName) - 1) {
1181 /* We can accept either unix or PC style AFS pathnames. Convert
1182 Unix-style to PC style here for internal use. */
1184 if (strncmp(p, cm_mountRoot, 4) == 0)
1185 p += strlen(cm_mountRoot); /* skip mount path */
1188 if (*q == '/') *q = '\\'; /* change to \ */
1194 if (var = smb_stristr(p, VNUserName)) {
1195 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1196 if (uidp && uidp->unp)
1197 smb_subst(p, var, sizeof(VNUserName),
1200 smb_subst(p, var, sizeof(VNUserName),
1203 smb_ReleaseUID(uidp);
1205 else if (var = smb_stristr(p, VNLCUserName)) {
1206 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1207 if (uidp && uidp->unp)
1208 strcpy(temp, uidp->unp->name);
1209 else strcpy(temp, " ");
1211 smb_subst(p, var, sizeof(VNLCUserName), temp);
1213 smb_ReleaseUID(uidp);
1215 else if (var = smb_stristr(p, VNComputerName)) {
1216 sizeTemp = sizeof(temp);
1217 GetComputerName((LPTSTR)temp, &sizeTemp);
1218 smb_subst(p, var, sizeof(VNComputerName),
1221 else if (var = smb_stristr(p, VNLCComputerName)) {
1222 sizeTemp = sizeof(temp);
1223 GetComputerName((LPTSTR)temp, &sizeTemp);
1225 smb_subst(p, var, sizeof(VNLCComputerName),
1231 *pathNamep = strdup(p);
1235 /* find a dir search structure by cookie value, and return it held.
1236 * Must be called with smb_globalLock held.
1238 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1240 smb_dirSearch_t *dsp;
1242 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1243 if (dsp->cookie == cookie) {
1244 if (dsp != smb_firstDirSearchp) {
1245 /* move to head of LRU queue, too, if we're not already there */
1246 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1247 smb_lastDirSearchp = (smb_dirSearch_t *)
1249 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1250 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1251 if (!smb_lastDirSearchp)
1252 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1261 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1263 lock_ObtainWrite(&smb_globalLock);
1264 dsp->flags |= SMB_DIRSEARCH_DELETE;
1265 lock_ReleaseWrite(&smb_globalLock);
1266 lock_ObtainMutex(&dsp->mx);
1267 if(dsp->scp != NULL) {
1268 lock_ObtainMutex(&dsp->scp->mx);
1269 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1270 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1271 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1272 dsp->scp->bulkStatProgress = hones;
1274 lock_ReleaseMutex(&dsp->scp->mx);
1276 lock_ReleaseMutex(&dsp->mx);
1279 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1285 lock_ObtainWrite(&smb_globalLock);
1286 osi_assert(dsp->refCount-- > 0);
1287 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1288 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1289 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1290 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1291 lock_FinalizeMutex(&dsp->mx);
1295 lock_ReleaseWrite(&smb_globalLock);
1297 /* do this now to avoid spurious locking hierarchy creation */
1298 if (scp) cm_ReleaseSCache(scp);
1301 /* find a dir search structure by cookie value, and return it held */
1302 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1304 smb_dirSearch_t *dsp;
1306 lock_ObtainWrite(&smb_globalLock);
1307 dsp = smb_FindDirSearchNL(cookie);
1308 lock_ReleaseWrite(&smb_globalLock);
1312 /* GC some dir search entries, in the address space expected by the specific protocol.
1313 * Must be called with smb_globalLock held; release the lock temporarily.
1315 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1316 void smb_GCDirSearches(int isV3)
1318 smb_dirSearch_t *prevp;
1319 smb_dirSearch_t *tp;
1320 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1324 victimCount = 0; /* how many have we got so far */
1325 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1326 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q); /* we'll move tp from queue, so
1329 /* if no one is using this guy, and we're either in the new protocol,
1330 * or we're in the old one and this is a small enough ID to be useful
1331 * to the old protocol, GC this guy.
1333 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1334 /* hold and delete */
1335 tp->flags |= SMB_DIRSEARCH_DELETE;
1336 victimsp[victimCount++] = tp;
1340 /* don't do more than this */
1341 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1344 /* now release them */
1345 lock_ReleaseWrite(&smb_globalLock);
1346 for(i = 0; i < victimCount; i++) {
1347 smb_ReleaseDirSearch(victimsp[i]);
1349 lock_ObtainWrite(&smb_globalLock);
1352 /* function for allocating a dir search entry. We need these to remember enough context
1353 * since we don't get passed the path from call to call during a directory search.
1355 * Returns a held dir search structure, and bumps the reference count on the vnode,
1356 * since it saves a pointer to the vnode.
1358 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1360 smb_dirSearch_t *dsp;
1364 lock_ObtainWrite(&smb_globalLock);
1367 /* what's the biggest ID allowed in this version of the protocol */
1368 if (isV3) maxAllowed = 65535;
1369 else maxAllowed = 255;
1372 /* twice so we have enough tries to find guys we GC after one pass;
1373 * 10 extra is just in case I mis-counted.
1375 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1376 __FILE__, __LINE__);
1377 if (smb_dirSearchCounter > maxAllowed) {
1378 smb_dirSearchCounter = 1;
1379 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1381 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1383 /* don't need to watch for refcount zero and deleted, since
1384 * we haven't dropped the global lock.
1387 ++smb_dirSearchCounter;
1391 dsp = malloc(sizeof(*dsp));
1392 memset(dsp, 0, sizeof(*dsp));
1393 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1394 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1395 dsp->cookie = smb_dirSearchCounter;
1396 ++smb_dirSearchCounter;
1398 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1399 dsp->lastTime = osi_Time();
1402 lock_ReleaseWrite(&smb_globalLock);
1406 static smb_packet_t *GetPacket(void)
1410 unsigned int npar, seg, tb_sel;
1413 lock_ObtainWrite(&smb_globalLock);
1414 tbp = smb_packetFreeListp;
1416 smb_packetFreeListp = tbp->nextp;
1417 lock_ReleaseWrite(&smb_globalLock);
1420 tbp = calloc(65540,1);
1422 tbp = malloc(sizeof(smb_packet_t));
1424 tbp->magic = SMB_PACKETMAGIC;
1427 tbp->resumeCode = 0;
1433 tbp->ncb_length = 0;
1438 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1441 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1443 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1445 osi_panic("",__FILE__,__LINE__);
1448 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1453 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1454 tbp->dos_pkt_sel = tb_sel;
1457 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1462 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1466 memcpy(tbp, pkt, sizeof(smb_packet_t));
1467 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1471 static NCB *GetNCB(void)
1476 unsigned int npar, seg, tb_sel;
1479 lock_ObtainWrite(&smb_globalLock);
1480 tbp = smb_ncbFreeListp;
1482 smb_ncbFreeListp = tbp->nextp;
1483 lock_ReleaseWrite(&smb_globalLock);
1486 tbp = calloc(sizeof(*tbp),1);
1488 tbp = malloc(sizeof(*tbp));
1489 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1492 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1494 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1496 osi_panic("",__FILE__,__LINE__);
1498 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1503 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1504 tbp->dos_ncb_sel = tb_sel;
1506 tbp->magic = SMB_NCBMAGIC;
1509 osi_assert(tbp->magic == SMB_NCBMAGIC);
1511 memset(&tbp->ncb, 0, sizeof(NCB));
1514 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1519 void smb_FreePacket(smb_packet_t *tbp)
1521 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1523 lock_ObtainWrite(&smb_globalLock);
1524 tbp->nextp = smb_packetFreeListp;
1525 smb_packetFreeListp = tbp;
1526 tbp->magic = SMB_PACKETMAGIC;
1529 tbp->resumeCode = 0;
1535 tbp->ncb_length = 0;
1537 lock_ReleaseWrite(&smb_globalLock);
1540 static void FreeNCB(NCB *bufferp)
1544 tbp = (smb_ncb_t *) bufferp;
1545 osi_assert(tbp->magic == SMB_NCBMAGIC);
1547 lock_ObtainWrite(&smb_globalLock);
1548 tbp->nextp = smb_ncbFreeListp;
1549 smb_ncbFreeListp = tbp;
1550 lock_ReleaseWrite(&smb_globalLock);
1553 /* get a ptr to the data part of a packet, and its count */
1554 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1558 unsigned char *afterParmsp;
1560 parmBytes = *smbp->wctp << 1;
1561 afterParmsp = smbp->wctp + parmBytes + 1;
1563 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1564 if (nbytesp) *nbytesp = dataBytes;
1566 /* don't forget to skip the data byte count, since it follows
1567 * the parameters; that's where the "2" comes from below.
1569 return (unsigned char *) (afterParmsp + 2);
1572 /* must set all the returned parameters before playing around with the
1573 * data region, since the data region is located past the end of the
1574 * variable number of parameters.
1576 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1578 unsigned char *afterParmsp;
1580 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1582 *afterParmsp++ = dsize & 0xff;
1583 *afterParmsp = (dsize>>8) & 0xff;
1586 /* return the parm'th parameter in the smbp packet */
1587 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1590 unsigned char *parmDatap;
1592 parmCount = *smbp->wctp;
1594 if (parm >= parmCount) {
1599 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1600 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1601 parm, parmCount, smbp->ncb_length);
1603 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1604 1, smbp->ncb_length, ptbuf, smbp);
1605 DeregisterEventSource(h);
1609 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1610 parm, parmCount, smbp->ncb_length);
1611 osi_Log0(afsd_logp, s);
1613 osi_panic(s, __FILE__, __LINE__);
1615 parmDatap = smbp->wctp + (2*parm) + 1;
1617 return parmDatap[0] + (parmDatap[1] << 8);
1620 /* return the parm'th parameter in the smbp packet */
1621 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1624 unsigned char *parmDatap;
1626 parmCount = *smbp->wctp;
1628 if (parm * 2 + offset >= parmCount * 2) {
1633 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1634 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1635 parm, offset, parmCount, smbp->ncb_length);
1637 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1638 1, smbp->ncb_length, ptbuf, smbp);
1639 DeregisterEventSource(h);
1643 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1645 parm, offset, parmCount, smbp->ncb_length);
1646 osi_Log0(afsd_logp, s);
1649 osi_panic(s, __FILE__, __LINE__);
1651 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1653 return parmDatap[0] + (parmDatap[1] << 8);
1656 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1660 /* make sure we have enough slots */
1661 if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1663 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1664 *parmDatap++ = parmValue & 0xff;
1665 *parmDatap = (parmValue>>8) & 0xff;
1668 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1672 /* make sure we have enough slots */
1673 if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1675 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1676 *parmDatap++ = parmValue & 0xff;
1677 *parmDatap++ = (parmValue>>8) & 0xff;
1678 *parmDatap++ = (parmValue>>16) & 0xff;
1679 *parmDatap++ = (parmValue>>24) & 0xff;
1682 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1687 /* make sure we have enough slots */
1688 if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1690 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1692 *parmDatap++ = *parmValuep++;
1695 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1699 /* make sure we have enough slots */
1700 if (*smbp->wctp <= slot) {
1701 if (smbp->oddByte) {
1703 *smbp->wctp = slot+1;
1708 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1709 *parmDatap++ = parmValue & 0xff;
1712 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1716 lastSlashp = strrchr(inPathp, '\\');
1718 *lastComponentp = lastSlashp;
1721 if (inPathp == lastSlashp) break;
1722 *outPathp++ = *inPathp++;
1731 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1733 if (*inp++ != 0x4) return NULL;
1735 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
1740 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1744 if (*inp++ != 0x5) return NULL;
1745 tlen = inp[0] + (inp[1]<<8);
1746 inp += 2; /* skip length field */
1749 *chainpp = inp + tlen;
1752 if (lengthp) *lengthp = tlen;
1757 /* format a packet as a response */
1758 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1763 outp = (smb_t *) op;
1765 /* zero the basic structure through the smb_wct field, and zero the data
1766 * size field, assuming that wct stays zero; otherwise, you have to
1767 * explicitly set the data size field, too.
1769 inSmbp = (smb_t *) inp;
1770 memset(outp, 0, sizeof(smb_t)+2);
1776 outp->com = inSmbp->com;
1777 outp->tid = inSmbp->tid;
1778 outp->pid = inSmbp->pid;
1779 outp->uid = inSmbp->uid;
1780 outp->mid = inSmbp->mid;
1781 outp->res[0] = inSmbp->res[0];
1782 outp->res[1] = inSmbp->res[1];
1783 op->inCom = inSmbp->com;
1785 outp->reb = 0x80; /* SERVER_RESP */
1786 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
1788 /* copy fields in generic packet area */
1789 op->wctp = &outp->wct;
1792 /* send a (probably response) packet; vcp tells us to whom to send it.
1793 * we compute the length by looking at wct and bcc fields.
1795 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1812 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
1815 memset((char *)ncbp, 0, sizeof(NCB));
1817 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
1818 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
1819 extra += tp[0] + (tp[1]<<8);
1820 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
1821 extra += 3; /* wct and length fields */
1823 ncbp->ncb_length = extra; /* bytes to send */
1824 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
1825 ncbp->ncb_lana_num = vcp->lana;
1826 ncbp->ncb_command = NCBSEND; /* op means send data */
1828 ncbp->ncb_buffer = (char *) inp;/* packet */
1829 code = Netbios(ncbp);
1831 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
1832 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
1834 /* copy header information from virtual to DOS address space */
1835 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
1836 code = Netbios(ncbp, dos_ncb);
1840 osi_Log1(afsd_logp, "SendPacket failure code %d", code);
1846 void smb_MapNTError(long code, unsigned long *NTStatusp)
1848 unsigned long NTStatus;
1850 /* map CM_ERROR_* errors to NT 32-bit status codes */
1851 if (code == CM_ERROR_NOSUCHCELL) {
1852 NTStatus = 0xC000000FL; /* No such file */
1854 else if (code == CM_ERROR_NOSUCHVOLUME) {
1855 NTStatus = 0xC000000FL; /* No such file */
1857 else if (code == CM_ERROR_TIMEDOUT) {
1858 NTStatus = 0xC00000CFL; /* Sharing Paused */
1860 else if (code == CM_ERROR_RETRY) {
1861 NTStatus = 0xC000022DL; /* Retry */
1863 else if (code == CM_ERROR_NOACCESS) {
1864 NTStatus = 0xC0000022L; /* Access denied */
1866 else if (code == CM_ERROR_READONLY) {
1867 NTStatus = 0xC00000A2L; /* Write protected */
1869 else if (code == CM_ERROR_NOSUCHFILE) {
1870 NTStatus = 0xC000000FL; /* No such file */
1872 else if (code == CM_ERROR_NOSUCHPATH) {
1873 NTStatus = 0xC000003AL; /* Object path not found */
1875 else if (code == CM_ERROR_TOOBIG) {
1876 NTStatus = 0xC000007BL; /* Invalid image format */
1878 else if (code == CM_ERROR_INVAL) {
1879 NTStatus = 0xC000000DL; /* Invalid parameter */
1881 else if (code == CM_ERROR_BADFD) {
1882 NTStatus = 0xC0000008L; /* Invalid handle */
1884 else if (code == CM_ERROR_BADFDOP) {
1885 NTStatus = 0xC0000022L; /* Access denied */
1887 else if (code == CM_ERROR_EXISTS) {
1888 NTStatus = 0xC0000035L; /* Object name collision */
1890 else if (code == CM_ERROR_NOTEMPTY) {
1891 NTStatus = 0xC0000101L; /* Directory not empty */
1893 else if (code == CM_ERROR_CROSSDEVLINK) {
1894 NTStatus = 0xC00000D4L; /* Not same device */
1896 else if (code == CM_ERROR_NOTDIR) {
1897 NTStatus = 0xC0000103L; /* Not a directory */
1899 else if (code == CM_ERROR_ISDIR) {
1900 NTStatus = 0xC00000BAL; /* File is a directory */
1902 else if (code == CM_ERROR_BADOP) {
1903 NTStatus = 0xC09820FFL; /* SMB no support */
1905 else if (code == CM_ERROR_BADSHARENAME) {
1906 NTStatus = 0xC00000CCL; /* Bad network name */
1908 else if (code == CM_ERROR_NOIPC) {
1910 NTStatus = 0xC0000022L; /* Access Denied */
1912 NTStatus = 0xC000013DL; /* Remote Resources */
1915 else if (code == CM_ERROR_CLOCKSKEW) {
1916 NTStatus = 0xC0000133L; /* Time difference at DC */
1918 else if (code == CM_ERROR_BADTID) {
1919 NTStatus = 0xC0982005L; /* SMB bad TID */
1921 else if (code == CM_ERROR_USESTD) {
1922 NTStatus = 0xC09820FBL; /* SMB use standard */
1924 else if (code == CM_ERROR_QUOTA) {
1925 NTStatus = 0xC0000044L; /* Quota exceeded */
1927 else if (code == CM_ERROR_SPACE) {
1928 NTStatus = 0xC000007FL; /* Disk full */
1930 else if (code == CM_ERROR_ATSYS) {
1931 NTStatus = 0xC0000033L; /* Object name invalid */
1933 else if (code == CM_ERROR_BADNTFILENAME) {
1934 NTStatus = 0xC0000033L; /* Object name invalid */
1936 else if (code == CM_ERROR_WOULDBLOCK) {
1937 NTStatus = 0xC0000055L; /* Lock not granted */
1939 else if (code == CM_ERROR_PARTIALWRITE) {
1940 NTStatus = 0xC000007FL; /* Disk full */
1942 else if (code == CM_ERROR_BUFFERTOOSMALL) {
1943 NTStatus = 0xC0000023L; /* Buffer too small */
1946 NTStatus = 0xC0982001L; /* SMB non-specific error */
1949 *NTStatusp = NTStatus;
1950 osi_Log2(afsd_logp, "SMB SEND code %x as NT %x", code, NTStatus);
1953 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
1954 unsigned char *classp)
1956 unsigned char class;
1957 unsigned short error;
1959 /* map CM_ERROR_* errors to SMB errors */
1960 if (code == CM_ERROR_NOSUCHCELL) {
1962 error = 3; /* bad path */
1964 else if (code == CM_ERROR_NOSUCHVOLUME) {
1966 error = 3; /* bad path */
1968 else if (code == CM_ERROR_TIMEDOUT) {
1970 error = 81; /* server is paused */
1972 else if (code == CM_ERROR_RETRY) {
1973 class = 2; /* shouldn't happen */
1976 else if (code == CM_ERROR_NOACCESS) {
1978 error = 4; /* bad access */
1980 else if (code == CM_ERROR_READONLY) {
1982 error = 19; /* read only */
1984 else if (code == CM_ERROR_NOSUCHFILE) {
1986 error = 2; /* ENOENT! */
1988 else if (code == CM_ERROR_NOSUCHPATH) {
1990 error = 3; /* Bad path */
1992 else if (code == CM_ERROR_TOOBIG) {
1994 error = 11; /* bad format */
1996 else if (code == CM_ERROR_INVAL) {
1997 class = 2; /* server non-specific error code */
2000 else if (code == CM_ERROR_BADFD) {
2002 error = 6; /* invalid file handle */
2004 else if (code == CM_ERROR_BADFDOP) {
2005 class = 1; /* invalid op on FD */
2008 else if (code == CM_ERROR_EXISTS) {
2010 error = 80; /* file already exists */
2012 else if (code == CM_ERROR_NOTEMPTY) {
2014 error = 5; /* delete directory not empty */
2016 else if (code == CM_ERROR_CROSSDEVLINK) {
2018 error = 17; /* EXDEV */
2020 else if (code == CM_ERROR_NOTDIR) {
2021 class = 1; /* bad path */
2024 else if (code == CM_ERROR_ISDIR) {
2025 class = 1; /* access denied; DOS doesn't have a good match */
2028 else if (code == CM_ERROR_BADOP) {
2032 else if (code == CM_ERROR_BADSHARENAME) {
2036 else if (code == CM_ERROR_NOIPC) {
2038 error = 4; /* bad access */
2040 else if (code == CM_ERROR_CLOCKSKEW) {
2041 class = 1; /* invalid function */
2044 else if (code == CM_ERROR_BADTID) {
2048 else if (code == CM_ERROR_USESTD) {
2052 else if (code == CM_ERROR_REMOTECONN) {
2056 else if (code == CM_ERROR_QUOTA) {
2057 if (vcp->flags & SMB_VCFLAG_USEV3) {
2059 error = 39; /* disk full */
2063 error = 5; /* access denied */
2066 else if (code == CM_ERROR_SPACE) {
2067 if (vcp->flags & SMB_VCFLAG_USEV3) {
2069 error = 39; /* disk full */
2073 error = 5; /* access denied */
2076 else if (code == CM_ERROR_PARTIALWRITE) {
2078 error = 39; /* disk full */
2080 else if (code == CM_ERROR_ATSYS) {
2082 error = 2; /* ENOENT */
2084 else if (code == CM_ERROR_WOULDBLOCK) {
2086 error = 33; /* lock conflict */
2088 else if (code == CM_ERROR_NOFILES) {
2090 error = 18; /* no files in search */
2092 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2094 error = 183; /* Samba uses this */
2103 osi_Log3(afsd_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2106 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2108 return CM_ERROR_BADOP;
2111 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2113 unsigned short EchoCount, i;
2114 char *data, *outdata;
2117 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2119 for (i=1; i<=EchoCount; i++) {
2120 data = smb_GetSMBData(inp, &dataSize);
2121 smb_SetSMBParm(outp, 0, i);
2122 smb_SetSMBDataLength(outp, dataSize);
2123 outdata = smb_GetSMBData(outp, NULL);
2124 memcpy(outdata, data, dataSize);
2125 smb_SendPacket(vcp, outp);
2131 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2134 long count, minCount, finalCount;
2138 cm_user_t *userp = NULL;
2142 char *rawBuf = NULL;
2144 dos_ptr rawBuf = NULL;
2151 fd = smb_GetSMBParm(inp, 0);
2152 count = smb_GetSMBParm(inp, 3);
2153 minCount = smb_GetSMBParm(inp, 4);
2154 offset.HighPart = 0; /* too bad */
2155 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2157 osi_Log3(afsd_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2158 fd, offset.LowPart, count);
2160 fidp = smb_FindFID(vcp, fd, 0);
2164 lock_ObtainMutex(&smb_RawBufLock);
2166 /* Get a raw buf, from head of list */
2167 rawBuf = smb_RawBufs;
2169 smb_RawBufs = *(char **)smb_RawBufs;
2171 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2174 lock_ReleaseMutex(&smb_RawBufLock);
2178 if (fidp->flags & SMB_FID_IOCTL)
2181 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2183 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2186 /* Give back raw buffer */
2187 lock_ObtainMutex(&smb_RawBufLock);
2189 *((char **) rawBuf) = smb_RawBufs;
2191 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2194 smb_RawBufs = rawBuf;
2195 lock_ReleaseMutex(&smb_RawBufLock);
2200 userp = smb_GetUser(vcp, inp);
2203 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2205 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2206 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2207 userp, &finalCount, TRUE /* rawFlag */);
2214 cm_ReleaseUser(userp);
2216 smb_ReleaseFID(fidp);
2221 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2223 memset((char *)ncbp, 0, sizeof(NCB));
2225 ncbp->ncb_length = (unsigned short) finalCount;
2226 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2227 ncbp->ncb_lana_num = vcp->lana;
2228 ncbp->ncb_command = NCBSEND;
2229 ncbp->ncb_buffer = rawBuf;
2232 code = Netbios(ncbp);
2234 code = Netbios(ncbp, dos_ncb);
2237 osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
2240 /* Give back raw buffer */
2241 lock_ObtainMutex(&smb_RawBufLock);
2243 *((char **) rawBuf) = smb_RawBufs;
2245 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2248 smb_RawBufs = rawBuf;
2249 lock_ReleaseMutex(&smb_RawBufLock);
2255 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2260 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2265 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2271 int protoIndex; /* index we're using */
2276 char protocol_array[10][1024]; /* protocol signature of the client */
2279 osi_Log1(afsd_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2283 DWORD now = GetCurrentTime();
2284 if (now - last_msg_time >= 30000
2285 && now - last_msg_time <= 90000) {
2287 "Setting dead_vcp %x", active_vcp);
2288 dead_vcp = active_vcp;
2289 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2294 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2296 namep = smb_GetSMBData(inp, &dbytes);
2299 coreProtoIndex = -1; /* not found */
2302 while(namex < dbytes) {
2303 osi_Log1(afsd_logp, "Protocol %s",
2304 osi_LogSaveString(afsd_logp, namep+1));
2305 strcpy(protocol_array[tcounter], namep+1);
2307 /* namep points at the first protocol, or really, a 0x02
2308 * byte preceding the null-terminated ASCII name.
2310 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2311 coreProtoIndex = tcounter;
2313 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2314 v3ProtoIndex = tcounter;
2316 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2317 NTProtoIndex = tcounter;
2320 /* compute size of protocol entry */
2321 entryLength = strlen(namep+1);
2322 entryLength += 2; /* 0x02 bytes and null termination */
2324 /* advance over this protocol entry */
2325 namex += entryLength;
2326 namep += entryLength;
2327 tcounter++; /* which proto entry we're looking at */
2329 #ifndef NOMOREFILESFIX
2331 * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
2332 * the client is running by reading the protocol signature.
2333 * ie. the order in which it sends us the protocol list.
2335 * Special handling for Windows 2000 clients (defect 11765 )
2336 * <asanka:11Jun03> Proto signature is the same for Win XP. </>
2338 if (tcounter == 6) {
2340 smb_t *ip = (smb_t *) inp;
2341 smb_t *op = (smb_t *) outp;
2343 if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
2344 (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
2345 (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
2346 (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
2347 (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
2348 (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
2349 isWindows2000 = TRUE;
2350 osi_Log0(afsd_logp, "Looks like a Windows 2000 client");
2352 * HACK: for now - just negotiate a lower protocol till we
2353 * figure out which flag/flag2 or some other field
2354 * (capabilities maybe?) to set in order for this to work
2355 * correctly with Windows 2000 clients (defect 11765)
2358 /* Things to try (after looking at tcpdump output could be
2359 * setting flags and flags2 to 0x98 and 0xc853 like this
2360 * op->reb = 0x98; op->flg2 = 0xc853;
2361 * osi_Log2(afsd_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
2365 #endif /* NOMOREFILESFIX */
2367 if (NTProtoIndex != -1) {
2368 protoIndex = NTProtoIndex;
2369 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2371 else if (v3ProtoIndex != -1) {
2372 protoIndex = v3ProtoIndex;
2373 vcp->flags |= SMB_VCFLAG_USEV3;
2375 else if (coreProtoIndex != -1) {
2376 protoIndex = coreProtoIndex;
2377 vcp->flags |= SMB_VCFLAG_USECORE;
2379 else protoIndex = -1;
2381 if (protoIndex == -1)
2382 return CM_ERROR_INVAL;
2383 else if (NTProtoIndex != -1) {
2384 smb_SetSMBParm(outp, 0, protoIndex);
2385 smb_SetSMBParmByte(outp, 1, 0); /* share level security, no passwd encrypt */
2386 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2387 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2388 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2389 smb_SetSMBParmLong(outp, 5, 65536); /* raw buffer size */
2390 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2391 smb_SetSMBParm(outp, 8, 1);
2393 * Tried changing the capabilities to support for W2K - defect 117695
2394 * Maybe something else needs to be changed here?
2398 smb_SetSMBParmLong(outp, 9, 0x43fd);
2400 smb_SetSMBParmLong(outp, 9, 0x251);
2402 smb_SetSMBParmLong(outp, 9, 0x251); /* Capabilities: *
2403 * 32-bit error codes *
2407 smb_SetSMBParmLong(outp, 11, 0);/* XXX server time: do we need? */
2408 smb_SetSMBParmLong(outp, 13, 0);/* XXX server date: do we need? */
2409 smb_SetSMBParm(outp, 15, 0); /* XXX server tzone: do we need? */
2410 smb_SetSMBParmByte(outp, 16, 0);/* Encryption key length */
2411 smb_SetSMBDataLength(outp, 0); /* perhaps should specify 8 bytes anyway */
2413 else if (v3ProtoIndex != -1) {
2414 smb_SetSMBParm(outp, 0, protoIndex);
2415 smb_SetSMBParm(outp, 1, 0); /* share level security, no passwd encrypt */
2416 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2417 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2418 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2419 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2420 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2421 smb_SetSMBParm(outp, 7, 1);
2422 smb_SetSMBParm(outp, 8, 0); /* XXX server time: do we need? */
2423 smb_SetSMBParm(outp, 9, 0); /* XXX server date: do we need? */
2424 smb_SetSMBParm(outp, 10, 0); /* XXX server tzone: do we need? */
2425 smb_SetSMBParm(outp, 11, 0); /* resvd */
2426 smb_SetSMBParm(outp, 12, 0); /* resvd */
2427 smb_SetSMBDataLength(outp, 0); /* perhaps should specify 8 bytes anyway */
2429 else if (coreProtoIndex != -1) {
2430 smb_SetSMBParm(outp, 0, protoIndex);
2431 smb_SetSMBDataLength(outp, 0);
2436 void smb_Daemon(void *parmp)
2443 if ((count % 360) == 0) /* every hour */
2444 smb_CalculateNowTZ();
2445 /* XXX GC dir search entries */
2449 void smb_WaitingLocksDaemon()
2451 smb_waitingLock_t *wL, *nwL;
2454 smb_packet_t *inp, *outp;
2459 lock_ObtainWrite(&smb_globalLock);
2460 nwL = smb_allWaitingLocks;
2462 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2471 lock_ObtainWrite(&smb_globalLock);
2473 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2474 lock_ReleaseWrite(&smb_globalLock);
2475 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2476 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2477 if (code == CM_ERROR_WOULDBLOCK) {
2479 if (wL->timeRemaining != 0xffffffff
2480 && (wL->timeRemaining -= 1000) < 0)
2489 ncbp->ncb_length = inp->ncb_length;
2490 inp->spacep = cm_GetSpace();
2492 /* Remove waitingLock from list */
2493 lock_ObtainWrite(&smb_globalLock);
2494 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2496 lock_ReleaseWrite(&smb_globalLock);
2498 /* Resume packet processing */
2500 smb_SetSMBDataLength(outp, 0);
2501 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2502 outp->resumeCode = code;
2504 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2507 cm_FreeSpace(inp->spacep);
2508 smb_FreePacket(inp);
2509 smb_FreePacket(outp);
2517 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2519 osi_Log0(afsd_logp, "SMB receive get disk attributes");
2521 smb_SetSMBParm(outp, 0, 32000);
2522 smb_SetSMBParm(outp, 1, 64);
2523 smb_SetSMBParm(outp, 2, 1024);
2524 smb_SetSMBParm(outp, 3, 30000);
2525 smb_SetSMBParm(outp, 4, 0);
2526 smb_SetSMBDataLength(outp, 0);
2530 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2533 unsigned short newTid;
2534 char shareName[256];
2542 osi_Log0(afsd_logp, "SMB receive tree connect");
2544 /* parse input parameters */
2545 tp = smb_GetSMBData(inp, NULL);
2546 pathp = smb_ParseASCIIBlock(tp, &tp);
2547 passwordp = smb_ParseASCIIBlock(tp, &tp);
2548 tp = strrchr(pathp, '\\');
2550 return CM_ERROR_BADSMB;
2551 strcpy(shareName, tp+1);
2553 userp = smb_GetUser(vcp, inp);
2555 lock_ObtainMutex(&vcp->mx);
2556 newTid = vcp->tidCounter++;
2557 lock_ReleaseMutex(&vcp->mx);
2559 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2560 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
2562 smb_ReleaseTID(tidp);
2563 return CM_ERROR_BADSHARENAME;
2565 lock_ObtainMutex(&tidp->mx);
2566 tidp->userp = userp;
2567 tidp->pathname = sharePath;
2568 lock_ReleaseMutex(&tidp->mx);
2569 smb_ReleaseTID(tidp);
2571 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2572 smb_SetSMBParm(rsp, 1, newTid);
2573 smb_SetSMBDataLength(rsp, 0);
2575 osi_Log1(afsd_logp, "SMB tree connect created ID %d", newTid);
2579 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2583 if (*inp++ != 0x1) return NULL;
2584 tlen = inp[0] + (inp[1]<<8);
2585 inp += 2; /* skip length field */
2588 *chainpp = inp + tlen;
2591 if (lengthp) *lengthp = tlen;
2596 /* set maskp to the mask part of the incoming path.
2597 * Mask is 11 bytes long (8.3 with the dot elided).
2598 * Returns true if succeeds with a valid name, otherwise it does
2599 * its best, but returns false.
2601 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2609 /* starts off valid */
2612 /* mask starts out all blanks */
2613 memset(maskp, ' ', 11);
2615 /* find last backslash, or use whole thing if there is none */
2616 tp = strrchr(pathp, '\\');
2617 if (!tp) tp = pathp;
2618 else tp++; /* skip slash */
2622 /* names starting with a dot are illegal */
2623 if (*tp == '.') valid8Dot3 = 0;
2627 if (tc == 0) return valid8Dot3;
2628 if (tc == '.' || tc == '"') break;
2629 if (i < 8) *up++ = tc;
2630 else valid8Dot3 = 0;
2633 /* if we get here, tp point after the dot */
2634 up = maskp+8; /* ext goes here */
2637 if (tc == 0) return valid8Dot3;
2640 if (tc == '.' || tc == '"') valid8Dot3 = 0;
2642 /* copy extension if not too long */
2643 if (i < 3) *up++ = tc;
2644 else valid8Dot3 = 0;
2650 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2660 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2662 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2663 if (!valid) return 0;
2665 /* otherwise, we have a valid 8.3 name; see if we have a match,
2666 * treating '?' as a wildcard in maskp (but not in the file name).
2668 tp1 = umask; /* real name, in mask format */
2669 tp2 = maskp; /* mask, in mask format */
2670 for(i=0; i<11; i++) {
2671 tc1 = *tp1++; /* char from real name */
2672 tc2 = *tp2++; /* char from mask */
2673 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
2674 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
2675 if (tc1 == tc2) continue;
2676 if (tc2 == '?' && tc1 != ' ') continue;
2677 if (tc2 == '>') continue;
2681 /* we got a match */
2685 char *smb_FindMask(char *pathp)
2689 tp = strrchr(pathp, '\\'); /* find last slash */
2691 if (tp) return tp+1; /* skip the slash */
2692 else return pathp; /* no slash, return the entire path */
2695 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2697 unsigned char *pathp;
2699 unsigned char mask[11];
2700 unsigned char *statBlockp;
2701 unsigned char initStatBlock[21];
2704 osi_Log0(afsd_logp, "SMB receive search volume");
2706 /* pull pathname and stat block out of request */
2707 tp = smb_GetSMBData(inp, NULL);
2708 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
2709 osi_assert(pathp != NULL);
2710 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
2711 osi_assert(statBlockp != NULL);
2713 statBlockp = initStatBlock;
2717 /* for returning to caller */
2718 smb_Get8Dot3MaskFromPath(mask, pathp);
2720 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
2721 tp = smb_GetSMBData(outp, NULL);
2723 *tp++ = 43; /* bytes in a dir entry */
2724 *tp++ = 0; /* high byte in counter */
2726 /* now marshall the dir entry, starting with the search status */
2727 *tp++ = statBlockp[0]; /* Reserved */
2728 memcpy(tp, mask, 11); tp += 11; /* FileName */
2730 /* now pass back server use info, with 1st byte non-zero */
2732 memset(tp, 0, 4); tp += 4; /* reserved for server use */
2734 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
2736 *tp++ = 0x8; /* attribute: volume */
2746 /* 4 byte file size */
2752 /* finally, null-terminated 8.3 pathname, which we set to AFS */
2753 memset(tp, ' ', 13);
2756 /* set the length of the data part of the packet to 43 + 3, for the dir
2757 * entry plus the 5 and the length fields.
2759 smb_SetSMBDataLength(outp, 46);
2763 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
2764 cm_user_t *userp, cm_req_t *reqp)
2772 smb_dirListPatch_t *patchp;
2773 smb_dirListPatch_t *npatchp;
2775 for(patchp = *dirPatchespp; patchp; patchp =
2776 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2777 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2779 lock_ObtainMutex(&scp->mx);
2780 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2781 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2783 lock_ReleaseMutex(&scp->mx);
2784 cm_ReleaseSCache(scp);
2787 dptr = patchp->dptr;
2789 attr = smb_Attributes(scp);
2792 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
2793 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2794 attr |= SMB_ATTR_HIDDEN;
2797 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2800 shortTemp = dosTime & 0xffff;
2801 *((u_short *)dptr) = shortTemp;
2804 /* and copy out date */
2805 shortTemp = (dosTime>>16) & 0xffff;
2806 *((u_short *)dptr) = shortTemp;
2809 /* copy out file length */
2810 *((u_long *)dptr) = scp->length.LowPart;
2812 lock_ReleaseMutex(&scp->mx);
2813 cm_ReleaseSCache(scp);
2816 /* now free the patches */
2817 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2818 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
2822 /* and mark the list as empty */
2823 *dirPatchespp = NULL;
2828 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2837 smb_dirListPatch_t *dirListPatchesp;
2838 smb_dirListPatch_t *curPatchp;
2842 osi_hyper_t dirLength;
2843 osi_hyper_t bufferOffset;
2844 osi_hyper_t curOffset;
2846 unsigned char *inCookiep;
2847 smb_dirSearch_t *dsp;
2851 unsigned long clientCookie;
2852 cm_pageHeader_t *pageHeaderp;
2853 cm_user_t *userp = NULL;
2860 long nextEntryCookie;
2861 int numDirChunks; /* # of 32 byte dir chunks in this entry */
2862 char resByte; /* reserved byte from the cookie */
2863 char *op; /* output data ptr */
2864 char *origOp; /* original value of op */
2865 cm_space_t *spacep; /* for pathname buffer */
2876 maxCount = smb_GetSMBParm(inp, 0);
2878 dirListPatchesp = NULL;
2880 caseFold = CM_FLAG_CASEFOLD;
2882 tp = smb_GetSMBData(inp, NULL);
2883 pathp = smb_ParseASCIIBlock(tp, &tp);
2884 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
2886 /* bail out if request looks bad */
2887 if (!tp || !pathp) {
2888 return CM_ERROR_BADSMB;
2891 /* We can handle long names */
2892 if (vcp->flags & SMB_VCFLAG_USENT)
2893 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
2895 /* make sure we got a whole search status */
2896 if (dataLength < 21) {
2897 nextCookie = 0; /* start at the beginning of the dir */
2900 attribute = smb_GetSMBParm(inp, 1);
2902 /* handle volume info in another function */
2903 if (attribute & 0x8)
2904 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
2906 osi_Log2(afsd_logp, "SMB receive search dir count %d [%s]",
2907 maxCount, osi_LogSaveString(afsd_logp, pathp));
2909 if (*pathp == 0) { /* null pathp, treat as root dir */
2910 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
2911 return CM_ERROR_NOFILES;
2915 dsp = smb_NewDirSearch(0);
2916 dsp->attribute = attribute;
2917 smb_Get8Dot3MaskFromPath(mask, pathp);
2918 memcpy(dsp->mask, mask, 11);
2920 /* track if this is likely to match a lot of entries */
2921 if (smb_IsStarMask(mask)) starPattern = 1;
2922 else starPattern = 0;
2925 /* pull the next cookie value out of the search status block */
2926 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
2927 + (inCookiep[16]<<24);
2928 dsp = smb_FindDirSearch(inCookiep[12]);
2930 /* can't find dir search status; fatal error */
2931 return CM_ERROR_BADFD;
2933 attribute = dsp->attribute;
2934 resByte = inCookiep[0];
2936 /* copy out client cookie, in host byte order. Don't bother
2937 * interpreting it, since we're just passing it through, anyway.
2939 memcpy(&clientCookie, &inCookiep[17], 4);
2941 memcpy(mask, dsp->mask, 11);
2943 /* assume we're doing a star match if it has continued for more
2949 osi_Log3(afsd_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
2950 nextCookie, dsp->cookie, attribute);
2952 userp = smb_GetUser(vcp, inp);
2954 /* try to get the vnode for the path name next */
2955 lock_ObtainMutex(&dsp->mx);
2962 spacep = inp->spacep;
2963 smb_StripLastComponent(spacep->data, NULL, pathp);
2964 lock_ReleaseMutex(&dsp->mx);
2965 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2966 code = cm_NameI(cm_rootSCachep, spacep->data,
2967 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
2968 lock_ObtainMutex(&dsp->mx);
2970 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2972 /* we need one hold for the entry we just stored into,
2973 * and one for our own processing. When we're done with this
2974 * function, we'll drop the one for our own processing.
2975 * We held it once from the namei call, and so we do another hold
2979 lock_ObtainMutex(&scp->mx);
2980 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2981 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2982 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2983 dsp->flags |= SMB_DIRSEARCH_BULKST;
2985 lock_ReleaseMutex(&scp->mx);
2988 lock_ReleaseMutex(&dsp->mx);
2990 cm_ReleaseUser(userp);
2991 smb_DeleteDirSearch(dsp);
2992 smb_ReleaseDirSearch(dsp);
2996 /* reserves space for parameter; we'll adjust it again later to the
2997 * real count of the # of entries we returned once we've actually
2998 * assembled the directory listing.
3000 smb_SetSMBParm(outp, 0, 0);
3002 /* get the directory size */
3003 lock_ObtainMutex(&scp->mx);
3004 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3005 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3007 lock_ReleaseMutex(&scp->mx);
3008 cm_ReleaseSCache(scp);
3009 cm_ReleaseUser(userp);
3010 smb_DeleteDirSearch(dsp);
3011 smb_ReleaseDirSearch(dsp);
3015 dirLength = scp->length;
3017 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3018 curOffset.HighPart = 0;
3019 curOffset.LowPart = nextCookie;
3020 origOp = op = smb_GetSMBData(outp, NULL);
3021 /* and write out the basic header */
3022 *op++ = 5; /* variable block */
3023 op += 2; /* skip vbl block length; we'll fill it in later */
3027 /* make sure that curOffset.LowPart doesn't point to the first
3028 * 32 bytes in the 2nd through last dir page, and that it doesn't
3029 * point at the first 13 32-byte chunks in the first dir page,
3030 * since those are dir and page headers, and don't contain useful
3033 temp = curOffset.LowPart & (2048-1);
3034 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3035 /* we're in the first page */
3036 if (temp < 13*32) temp = 13*32;
3039 /* we're in a later dir page */
3040 if (temp < 32) temp = 32;
3043 /* make sure the low order 5 bits are zero */
3046 /* now put temp bits back ito curOffset.LowPart */
3047 curOffset.LowPart &= ~(2048-1);
3048 curOffset.LowPart |= temp;
3050 /* check if we've returned all the names that will fit in the
3053 if (returnedNames >= maxCount) break;
3055 /* check if we've passed the dir's EOF */
3056 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3058 /* see if we can use the bufferp we have now; compute in which page
3059 * the current offset would be, and check whether that's the offset
3060 * of the buffer we have. If not, get the buffer.
3062 thyper.HighPart = curOffset.HighPart;
3063 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3064 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3067 buf_Release(bufferp);
3070 lock_ReleaseMutex(&scp->mx);
3071 lock_ObtainRead(&scp->bufCreateLock);
3072 code = buf_Get(scp, &thyper, &bufferp);
3073 lock_ReleaseRead(&scp->bufCreateLock);
3075 /* now, if we're doing a star match, do bulk fetching of all of
3076 * the status info for files in the dir.
3079 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3081 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3082 && LargeIntegerGreaterThanOrEqualTo(thyper,
3083 scp->bulkStatProgress)) {
3084 /* Don't bulk stat if risking timeout */
3085 int now = GetCurrentTime();
3086 if (now - req.startTime > 5000) {
3087 scp->bulkStatProgress = thyper;
3088 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3089 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3091 cm_TryBulkStat(scp, &thyper,
3096 lock_ObtainMutex(&scp->mx);
3098 bufferOffset = thyper;
3100 /* now get the data in the cache */
3102 code = cm_SyncOp(scp, bufferp, userp, &req,
3104 CM_SCACHESYNC_NEEDCALLBACK
3105 | CM_SCACHESYNC_READ);
3108 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3110 /* otherwise, load the buffer and try again */
3111 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3116 buf_Release(bufferp);
3120 } /* if (wrong buffer) ... */
3122 /* now we have the buffer containing the entry we're interested in; copy
3123 * it out if it represents a non-deleted entry.
3125 entryInDir = curOffset.LowPart & (2048-1);
3126 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3128 /* page header will help tell us which entries are free. Page header
3129 * can change more often than once per buffer, since AFS 3 dir page size
3130 * may be less than (but not more than a buffer package buffer.
3132 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3133 temp &= ~(2048 - 1); /* turn off intra-page bits */
3134 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3136 /* now determine which entry we're looking at in the page. If it is
3137 * free (there's a free bitmap at the start of the dir), we should
3138 * skip these 32 bytes.
3140 slotInPage = (entryInDir & 0x7e0) >> 5;
3141 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3142 /* this entry is free */
3143 numDirChunks = 1; /* only skip this guy */
3147 tp = bufferp->datap + entryInBuffer;
3148 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3150 /* while we're here, compute the next entry's location, too,
3151 * since we'll need it when writing out the cookie into the dir
3154 * XXXX Probably should do more sanity checking.
3156 numDirChunks = cm_NameEntries(dep->name, NULL);
3158 /* compute the offset of the cookie representing the next entry */
3159 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3161 /* Compute 8.3 name if necessary */
3162 actualName = dep->name;
3163 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3164 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3165 actualName = shortName;
3168 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3169 /* this is one of the entries to use: it is not deleted
3170 * and it matches the star pattern we're looking for.
3173 /* Eliminate entries that don't match requested
3176 /* no hidden files */
3177 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3180 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3182 /* We have already done the cm_TryBulkStat above */
3183 fid.cell = scp->fid.cell;
3184 fid.volume = scp->fid.volume;
3185 fid.vnode = ntohl(dep->fid.vnode);
3186 fid.unique = ntohl(dep->fid.unique);
3187 fileType = cm_FindFileType(&fid);
3188 osi_Log2(afsd_logp, "smb_ReceiveCoreSearchDir: file %s "
3189 "has filetype %d", dep->name,
3191 if (fileType == CM_SCACHETYPE_DIRECTORY)
3196 memcpy(op, mask, 11); op += 11;
3197 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3198 *op++ = nextEntryCookie & 0xff;
3199 *op++ = (nextEntryCookie>>8) & 0xff;
3200 *op++ = (nextEntryCookie>>16) & 0xff;
3201 *op++ = (nextEntryCookie>>24) & 0xff;
3202 memcpy(op, &clientCookie, 4); op += 4;
3204 /* now we emit the attribute. This is sort of tricky,
3205 * since we need to really stat the file to find out
3206 * what type of entry we've got. Right now, we're
3207 * copying out data from a buffer, while holding the
3208 * scp locked, so it isn't really convenient to stat
3209 * something now. We'll put in a place holder now,
3210 * and make a second pass before returning this to get
3211 * the real attributes. So, we just skip the data for
3212 * now, and adjust it later. We allocate a patch
3213 * record to make it easy to find this point later.
3214 * The replay will happen at a time when it is safe to
3215 * unlock the directory.
3217 curPatchp = malloc(sizeof(*curPatchp));
3218 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3219 curPatchp->dptr = op;
3220 curPatchp->fid.cell = scp->fid.cell;
3221 curPatchp->fid.volume = scp->fid.volume;
3222 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3223 curPatchp->fid.unique = ntohl(dep->fid.unique);
3225 /* do hidden attribute here since name won't be around when applying
3229 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3230 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3232 curPatchp->flags = 0;
3234 op += 9; /* skip attr, time, date and size */
3236 /* zero out name area. The spec says to pad with
3237 * spaces, but Samba doesn't, and neither do we.
3241 /* finally, we get to copy out the name; we know that
3242 * it fits in 8.3 or the pattern wouldn't match, but it
3243 * never hurts to be sure.
3245 strncpy(op, actualName, 13);
3247 /* Uppercase if requested by client */
3248 if ((((smb_t *)inp)->flg2 & 1) == 0)
3253 /* now, adjust the # of entries copied */
3255 } /* if we're including this name */
3258 /* and adjust curOffset to be where the new cookie is */
3259 thyper.HighPart = 0;
3260 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3261 curOffset = LargeIntegerAdd(thyper, curOffset);
3262 } /* while copying data for dir listing */
3264 /* release the mutex */
3265 lock_ReleaseMutex(&scp->mx);
3266 if (bufferp) buf_Release(bufferp);
3268 /* apply and free last set of patches; if not doing a star match, this
3269 * will be empty, but better safe (and freeing everything) than sorry.
3271 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3273 /* special return code for unsuccessful search */
3274 if (code == 0 && dataLength < 21 && returnedNames == 0)
3275 code = CM_ERROR_NOFILES;
3277 osi_Log2(afsd_logp, "SMB search dir done, %d names, code %d",
3278 returnedNames, code);
3281 smb_DeleteDirSearch(dsp);
3282 smb_ReleaseDirSearch(dsp);
3283 cm_ReleaseSCache(scp);
3284 cm_ReleaseUser(userp);
3288 /* finalize the output buffer */
3289 smb_SetSMBParm(outp, 0, returnedNames);
3290 temp = (long) (op - origOp);
3291 smb_SetSMBDataLength(outp, temp);
3293 /* the data area is a variable block, which has a 5 (already there)
3294 * followed by the length of the # of data bytes. We now know this to
3295 * be "temp," although that includes the 3 bytes of vbl block header.
3296 * Deduct for them and fill in the length field.
3298 temp -= 3; /* deduct vbl block info */
3299 osi_assert(temp == (43 * returnedNames));
3300 origOp[1] = temp & 0xff;
3301 origOp[2] = (temp>>8) & 0xff;
3302 if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3303 smb_ReleaseDirSearch(dsp);
3304 cm_ReleaseSCache(scp);
3305 cm_ReleaseUser(userp);
3309 /* verify that this is a valid path to a directory. I don't know why they
3310 * don't use the get file attributes call.
3312 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3316 cm_scache_t *rootScp;
3317 cm_scache_t *newScp;
3326 pathp = smb_GetSMBData(inp, NULL);
3327 pathp = smb_ParseASCIIBlock(pathp, NULL);
3328 osi_Log1(afsd_logp, "SMB receive check path %s",
3329 osi_LogSaveString(afsd_logp, pathp));
3332 return CM_ERROR_BADFD;
3335 rootScp = cm_rootSCachep;
3337 userp = smb_GetUser(vcp, inp);
3339 caseFold = CM_FLAG_CASEFOLD;
3341 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3342 code = cm_NameI(rootScp, pathp,
3343 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3344 userp, tidPathp, &req, &newScp);
3347 cm_ReleaseUser(userp);
3351 /* now lock the vnode with a callback; returns with newScp locked */
3352 lock_ObtainMutex(&newScp->mx);
3353 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3354 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3355 if (code && code != CM_ERROR_NOACCESS) {
3356 lock_ReleaseMutex(&newScp->mx);
3357 cm_ReleaseSCache(newScp);
3358 cm_ReleaseUser(userp);
3362 attrs = smb_Attributes(newScp);
3364 if (!(attrs & 0x10))
3365 code = CM_ERROR_NOTDIR;
3367 lock_ReleaseMutex(&newScp->mx);
3369 cm_ReleaseSCache(newScp);
3370 cm_ReleaseUser(userp);
3374 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3378 cm_scache_t *rootScp;
3379 unsigned short attribute;
3381 cm_scache_t *newScp;
3390 /* decode basic attributes we're passed */
3391 attribute = smb_GetSMBParm(inp, 0);
3392 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3394 pathp = smb_GetSMBData(inp, NULL);
3395 pathp = smb_ParseASCIIBlock(pathp, NULL);
3398 return CM_ERROR_BADSMB;
3401 osi_Log2(afsd_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3402 dosTime, attribute);
3404 rootScp = cm_rootSCachep;
3406 userp = smb_GetUser(vcp, inp);
3408 caseFold = CM_FLAG_CASEFOLD;
3410 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3411 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3412 tidPathp, &req, &newScp);
3415 cm_ReleaseUser(userp);
3419 /* now lock the vnode with a callback; returns with newScp locked; we
3420 * need the current status to determine what the new status is, in some
3423 lock_ObtainMutex(&newScp->mx);
3424 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3425 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3427 lock_ReleaseMutex(&newScp->mx);
3428 cm_ReleaseSCache(newScp);
3429 cm_ReleaseUser(userp);
3433 /* Check for RO volume */
3434 if (newScp->flags & CM_SCACHEFLAG_RO) {
3435 lock_ReleaseMutex(&newScp->mx);
3436 cm_ReleaseSCache(newScp);