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, ...);
63 extern HANDLE afsi_file;
65 osi_hyper_t hzero = {0, 0};
66 osi_hyper_t hones = {0xFFFFFFFF, -1};
69 osi_rwlock_t smb_globalLock;
70 osi_rwlock_t smb_rctLock;
71 osi_mutex_t smb_ListenerLock;
74 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
85 int smb_NumServerThreads;
87 int numNCBs, numSessions;
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
92 #define NCBmax MAXIMUM_WAIT_OBJECTS
93 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
94 EVENT_HANDLE **NCBreturns;
95 DWORD NCBsessions[NCBmax];
97 struct smb_packet *bufs[NCBmax];
99 #define Sessionmax MAXIMUM_WAIT_OBJECTS
100 EVENT_HANDLE SessionEvents[Sessionmax];
101 unsigned short LSNs[Sessionmax];
102 int lanas[Sessionmax];
103 BOOL dead_sessions[Sessionmax];
107 osi_mutex_t smb_RawBufLock;
109 #define SMB_RAW_BUFS 4
111 int smb_RawBufSel[SMB_RAW_BUFS];
116 #define RAWTIMEOUT INFINITE
119 typedef struct raw_write_cont {
132 /* dir search stuff */
133 long smb_dirSearchCounter = 1;
134 smb_dirSearch_t *smb_firstDirSearchp;
135 smb_dirSearch_t *smb_lastDirSearchp;
137 /* hide dot files? */
138 int smb_hideDotFiles;
140 /* global state about V3 protocols */
141 int smb_useV3; /* try to negotiate V3 */
144 /* MessageBox or something like it */
145 int (WINAPI *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
149 * Time in Unix format of midnight, 1/1/1970 local time.
150 * When added to dosUTime, gives Unix (AFS) time.
154 /* Time difference for converting to kludge-GMT */
157 char *smb_localNamep = NULL;
159 smb_vc_t *smb_allVCsp;
161 smb_username_t *usernamesp = NULL;
163 smb_waitingLock_t *smb_allWaitingLocks;
166 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
167 NCB *ncbp, raw_write_cont_t *rwcp);
168 void smb_NetbiosInit();
170 #ifndef AFS_WIN95_ENV
171 DWORD smb_ServerExceptionFilter(void);
174 extern char cm_HostName[];
175 extern char cm_confDir[];
179 #define LPTSTR char *
180 #define GetComputerName(str, sizep) \
181 strcpy((str), cm_HostName); \
182 *(sizep) = strlen(cm_HostName)
185 extern char AFSConfigKeyName[];
190 * To build an expiring version, comment out the definition of NOEXPIRE,
191 * and set the definition of EXPIREDATE to the desired value.
194 #define EXPIREDATE 834000000 /* Wed Jun 5 1996 */
197 char * myCrt_Dispatch(int i)
202 return "unknown SMB op";
204 return "(00)ReceiveCoreMakeDir";
206 return "(01)ReceiveCoreRemoveDir";
208 return "(02)ReceiveCoreOpen";
210 return "(03)ReceiveCoreCreate";
212 return "(04)ReceiveCoreClose";
214 return "(05)ReceiveCoreFlush";
216 return "(06)ReceiveCoreUnlink";
218 return "(07)ReceiveCoreRename";
220 return "(08)ReceiveCoreGetFileAttributes";
222 return "(09)ReceiveCoreSetFileAttributes";
224 return "(0a)ReceiveCoreRead";
226 return "(0b)ReceiveCoreWrite";
228 return "(0c)ReceiveCoreLockRecord";
230 return "(0d)ReceiveCoreUnlockRecord";
232 return "(0e)SendCoreBadOp";
234 return "(0f)ReceiveCoreCreate";
236 return "(10)ReceiveCoreCheckPath";
238 return "(11)SendCoreBadOp";
240 return "(12)ReceiveCoreSeek";
242 return "(1a)ReceiveCoreReadRaw";
244 return "(1d)ReceiveCoreWriteRawDummy";
246 return "(22)ReceiveV3SetAttributes";
248 return "(23)ReceiveV3GetAttributes";
250 return "(24)ReceiveV3LockingX";
252 return "(29)SendCoreBadOp";
254 return "(2b)ReceiveCoreEcho";
256 return "(2d)ReceiveV3OpenX";
258 return "(2e)ReceiveV3ReadX";
260 return "(32)ReceiveV3Tran2A";
262 return "(33)ReceiveV3Tran2A";
264 return "(34)ReceiveV3FindClose";
266 return "(35)ReceiveV3FindNotifyClose";
268 return "(70)ReceiveCoreTreeConnect";
270 return "(71)ReceiveCoreTreeDisconnect";
272 return "(72)ReceiveNegotiate";
274 return "(73)ReceiveV3SessionSetupX";
276 return "(74)ReceiveV3UserLogoffX";
278 return "(75)ReceiveV3TreeConnectX";
280 return "(80)ReceiveCoreGetDiskAttributes";
282 return "(81)ReceiveCoreSearchDir";
284 return "(A0)ReceiveNTTransact";
286 return "(A2)ReceiveNTCreateX";
288 return "(A4)ReceiveNTCancel";
290 return "(c0)SendCoreBadOp";
292 return "(c1)SendCoreBadOp";
294 return "(c2)SendCoreBadOp";
296 return "(c3)SendCoreBadOp";
300 char * myCrt_2Dispatch(int i)
305 return "unknown SMB op-2";
307 return "S(00)CreateFile";
309 return "S(01)FindFirst";
311 return "S(02)FindNext"; /* FindNext */
313 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
317 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
319 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
321 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
323 return "S(08)??_ReceiveTran2SetFileInfo";
325 return "S(09)??_ReceiveTran2FSCTL";
327 return "S(0a)_ReceiveTran2IOCTL";
329 return "S(0b)_ReceiveTran2FindNotifyFirst";
331 return "S(0c)_ReceiveTran2FindNotifyNext";
333 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
337 /* scache must be locked */
338 unsigned int smb_Attributes(cm_scache_t *scp)
342 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
343 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
344 attrs = SMB_ATTR_DIRECTORY;
349 * We used to mark a file RO if it was in an RO volume, but that
350 * turns out to be impolitic in NT. See defect 10007.
353 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
355 if ((scp->unixModeBits & 0222) == 0)
356 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
361 /* Check if the named file/dir is a dotfile/dotdir */
362 /* String pointed to by lastComp can have leading slashes, but otherwise should have
363 no other patch components */
364 unsigned int smb_IsDotFile(char *lastComp) {
367 /* skip over slashes */
368 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
373 /* nulls, curdir and parent dir doesn't count */
376 if(!*(s + 1)) return 0;
377 if(*(s+1) == '.' && !*(s + 2)) return 0;
383 static int ExtractBits(WORD bits, short start, short len)
390 num = bits << (16 - end);
391 num = num >> ((16 - end) + start);
397 void ShowUnixTime(char *FuncName, long unixTime)
402 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
404 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
405 osi_Log1(afsd_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
407 int day, month, year, sec, min, hour;
410 day = ExtractBits(wDate, 0, 5);
411 month = ExtractBits(wDate, 5, 4);
412 year = ExtractBits(wDate, 9, 7) + 1980;
414 sec = ExtractBits(wTime, 0, 5);
415 min = ExtractBits(wTime, 5, 6);
416 hour = ExtractBits(wTime, 11, 5);
418 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
419 osi_Log1(afsd_logp, "%s", osi_LogSaveString(afsd_logp, msg));
425 /* Determine if we are observing daylight savings time */
426 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
428 TIME_ZONE_INFORMATION timeZoneInformation;
429 SYSTEMTIME utc, local, localDST;
431 /* Get the time zone info. NT uses this to calc if we are in DST. */
432 GetTimeZoneInformation(&timeZoneInformation);
434 /* Return the daylight bias */
435 *pDstBias = timeZoneInformation.DaylightBias;
437 /* Return the bias */
438 *pBias = timeZoneInformation.Bias;
440 /* Now determine if DST is being observed */
442 /* Get the UTC (GMT) time */
445 /* Convert UTC time to local time using the time zone info. If we are
446 observing DST, the calculated local time will include this.
448 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
450 /* Set the daylight bias to 0. The daylight bias is the amount of change
451 in time that we use for daylight savings time. By setting this to 0
452 we cause there to be no change in time during daylight savings time.
454 timeZoneInformation.DaylightBias = 0;
456 /* Convert the utc time to local time again, but this time without any
457 adjustment for daylight savings time.
459 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
461 /* If the two times are different, then it means that the localDST that
462 we calculated includes the daylight bias, and therefore we are
463 observing daylight savings time.
465 *pDST = localDST.wHour != local.wHour;
468 /* Determine if we are observing daylight savings time */
469 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
475 *pDstBias = -60; /* where can this be different? */
481 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
483 BOOL dst; /* Will be TRUE if observing DST */
484 LONG dstBias; /* Offset from local time if observing DST */
485 LONG bias; /* Offset from GMT for local time */
488 * This function will adjust the last write time to compensate
489 * for two bugs in the smb client:
491 * 1) During Daylight Savings Time, the LastWriteTime is ahead
492 * in time by the DaylightBias (ignoring the sign - the
493 * DaylightBias is always stored as a negative number). If
494 * the DaylightBias is -60, then the LastWriteTime will be
495 * ahead by 60 minutes.
497 * 2) If the local time zone is a positive offset from GMT, then
498 * the LastWriteTime will be the correct local time plus the
499 * Bias (ignoring the sign - a positive offset from GMT is
500 * always stored as a negative Bias). If the Bias is -120,
501 * then the LastWriteTime will be ahead by 120 minutes.
503 * These bugs can occur at the same time.
506 GetTimeZoneInfo(&dst, &dstBias, &bias);
508 /* First adjust for DST */
510 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
512 /* Now adjust for a positive offset from GMT (a negative bias). */
514 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
518 * Calculate the difference (in seconds) between local time and GMT.
519 * This enables us to convert file times to kludge-GMT.
525 struct tm gmt_tm, local_tm;
526 int days, hours, minutes, seconds;
529 gmt_tm = *(gmtime(&t));
530 local_tm = *(localtime(&t));
532 days = local_tm.tm_yday - gmt_tm.tm_yday;
533 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
534 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
535 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
541 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
546 long ersatz_unixTime;
549 * Must use kludge-GMT instead of real GMT.
550 * kludge-GMT is computed by adding time zone difference to localtime.
553 * ltp = gmtime(&unixTime);
555 ersatz_unixTime = unixTime - smb_NowTZ;
556 ltp = localtime(&ersatz_unixTime);
558 /* if we fail, make up something */
561 localJunk.tm_year = 89 - 20;
562 localJunk.tm_mon = 4;
563 localJunk.tm_mday = 12;
564 localJunk.tm_hour = 0;
565 localJunk.tm_min = 0;
566 localJunk.tm_sec = 0;
569 stm.wYear = ltp->tm_year + 1900;
570 stm.wMonth = ltp->tm_mon + 1;
571 stm.wDayOfWeek = ltp->tm_wday;
572 stm.wDay = ltp->tm_mday;
573 stm.wHour = ltp->tm_hour;
574 stm.wMinute = ltp->tm_min;
575 stm.wSecond = ltp->tm_sec;
576 stm.wMilliseconds = 0;
578 SystemTimeToFileTime(&stm, largeTimep);
581 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
583 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
584 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
585 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
587 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
589 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
590 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
592 *ft = LargeIntegerMultiplyByLong(*ft, 60);
593 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
596 ut = ConvertLongToLargeInteger(unixTime);
597 ut = LargeIntegerMultiplyByLong(ut, 10000000);
598 *ft = LargeIntegerAdd(*ft, ut);
603 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
609 FileTimeToSystemTime(largeTimep, &stm);
611 lt.tm_year = stm.wYear - 1900;
612 lt.tm_mon = stm.wMonth - 1;
613 lt.tm_wday = stm.wDayOfWeek;
614 lt.tm_mday = stm.wDay;
615 lt.tm_hour = stm.wHour;
616 lt.tm_min = stm.wMinute;
617 lt.tm_sec = stm.wSecond;
620 save_timezone = _timezone;
621 _timezone += smb_NowTZ;
622 *unixTimep = mktime(<);
623 _timezone = save_timezone;
626 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
628 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
629 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
630 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
634 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
635 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60
637 a = LargeIntegerMultiplyByLong(a, 60);
638 a = LargeIntegerMultiplyByLong(a, 10000000);
640 /* subtract it from ft */
641 a = LargeIntegerSubtract(*ft, a);
643 /* divide down to seconds */
644 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
648 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
655 ltp = localtime((time_t*) &unixTime);
657 /* if we fail, make up something */
660 localJunk.tm_year = 89 - 20;
661 localJunk.tm_mon = 4;
662 localJunk.tm_mday = 12;
663 localJunk.tm_hour = 0;
664 localJunk.tm_min = 0;
665 localJunk.tm_sec = 0;
668 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
669 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
670 *dosTimep = (dosDate<<16) | dosTime;
673 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
675 unsigned short dosDate;
676 unsigned short dosTime;
679 dosDate = searchTime & 0xffff;
680 dosTime = (searchTime >> 16) & 0xffff;
682 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
683 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
684 localTm.tm_mday = (dosDate) & 0x1f;
685 localTm.tm_hour = (dosTime>>11) & 0x1f;
686 localTm.tm_min = (dosTime >> 5) & 0x3f;
687 localTm.tm_sec = (dosTime & 0x1f) * 2;
688 localTm.tm_isdst = -1; /* compute whether DST in effect */
690 *unixTimep = mktime(&localTm);
693 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
695 *dosUTimep = unixTime - smb_localZero;
698 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
701 *unixTimep = dosTime + smb_localZero;
703 /* dosTime seems to be already adjusted for GMT */
704 *unixTimep = dosTime;
708 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
712 lock_ObtainWrite(&smb_rctLock);
713 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
714 if (lsn == vcp->lsn && lana == vcp->lana) {
719 if (!vcp && (flags & SMB_FLAG_CREATE)) {
720 vcp = malloc(sizeof(*vcp));
721 memset(vcp, 0, sizeof(*vcp));
725 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
726 vcp->nextp = smb_allVCsp;
728 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
732 lock_ReleaseWrite(&smb_rctLock);
736 int smb_IsStarMask(char *maskp)
741 for(i=0; i<11; i++) {
743 if (tc == '?' || tc == '*' || tc == '>') return 1;
748 void smb_ReleaseVC(smb_vc_t *vcp)
750 lock_ObtainWrite(&smb_rctLock);
751 osi_assert(vcp->refCount-- > 0);
752 lock_ReleaseWrite(&smb_rctLock);
755 void smb_HoldVC(smb_vc_t *vcp)
757 lock_ObtainWrite(&smb_rctLock);
759 lock_ReleaseWrite(&smb_rctLock);
762 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
766 lock_ObtainWrite(&smb_rctLock);
767 for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
768 if (tid == tidp->tid) {
773 if (!tidp && (flags & SMB_FLAG_CREATE)) {
774 tidp = malloc(sizeof(*tidp));
775 memset(tidp, 0, sizeof(*tidp));
776 tidp->nextp = vcp->tidsp;
780 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
783 lock_ReleaseWrite(&smb_rctLock);
787 void smb_ReleaseTID(smb_tid_t *tidp)
794 lock_ObtainWrite(&smb_rctLock);
795 osi_assert(tidp->refCount-- > 0);
796 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
797 ltpp = &tidp->vcp->tidsp;
798 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
799 if (tp == tidp) break;
801 osi_assert(tp != NULL);
803 lock_FinalizeMutex(&tidp->mx);
804 userp = tidp->userp; /* remember to drop ref later */
806 lock_ReleaseWrite(&smb_rctLock);
808 cm_ReleaseUser(userp);
812 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
814 smb_user_t *uidp = NULL;
816 lock_ObtainWrite(&smb_rctLock);
817 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
818 if (uid == uidp->userID) {
820 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 : "");
824 if (!uidp && (flags & SMB_FLAG_CREATE)) {
825 uidp = malloc(sizeof(*uidp));
826 memset(uidp, 0, sizeof(*uidp));
827 uidp->nextp = vcp->usersp;
831 lock_InitializeMutex(&uidp->mx, "uid_t mutex");
833 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 : ""));
835 lock_ReleaseWrite(&smb_rctLock);
839 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
841 smb_username_t *unp= NULL;
843 lock_ObtainWrite(&smb_rctLock);
844 for(unp = usernamesp; unp; unp = unp->nextp) {
845 if (stricmp(unp->name, usern) == 0 &&
846 stricmp(unp->machine, machine) == 0) {
851 if (!unp && (flags & SMB_FLAG_CREATE)) {
852 unp = malloc(sizeof(*unp));
853 memset(unp, 0, sizeof(*unp));
855 unp->nextp = usernamesp;
856 unp->name = strdup(usern);
857 unp->machine = strdup(machine);
859 lock_InitializeMutex(&unp->mx, "username_t mutex");
861 lock_ReleaseWrite(&smb_rctLock);
865 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
867 smb_user_t *uidp= NULL;
869 lock_ObtainWrite(&smb_rctLock);
870 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
873 if (stricmp(uidp->unp->name, usern) == 0) {
875 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
880 lock_ReleaseWrite(&smb_rctLock);
883 void smb_ReleaseUID(smb_user_t *uidp)
890 lock_ObtainWrite(&smb_rctLock);
891 osi_assert(uidp->refCount-- > 0);
892 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
893 lupp = &uidp->vcp->usersp;
894 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
895 if (up == uidp) break;
897 osi_assert(up != NULL);
899 lock_FinalizeMutex(&uidp->mx);
901 userp = uidp->unp->userp; /* remember to drop ref later */
903 lock_ReleaseWrite(&smb_rctLock);
905 cm_ReleaseUserVCRef(userp);
906 cm_ReleaseUser(userp);
910 /* retrieve a held reference to a user structure corresponding to an incoming
912 * corresponding release function is cm_ReleaseUser.
914 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
920 smbp = (smb_t *) inp;
921 uidp = smb_FindUID(vcp, smbp->uid, 0);
922 if ((!uidp) || (!uidp->unp))
925 lock_ObtainMutex(&uidp->mx);
926 up = uidp->unp->userp;
928 lock_ReleaseMutex(&uidp->mx);
930 smb_ReleaseUID(uidp);
936 * Return a pointer to a pathname extracted from a TID structure. The
937 * TID structure is not held; assume it won't go away.
939 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
944 tidp = smb_FindTID(vcp, tid, 0);
947 tpath = tidp->pathname;
948 smb_ReleaseTID(tidp);
952 /* check to see if we have a chained fid, that is, a fid that comes from an
953 * OpenAndX message that ran earlier in this packet. In this case, the fid
954 * field in a read, for example, request, isn't set, since the value is
955 * supposed to be inherited from the openAndX call.
957 int smb_ChainFID(int fid, smb_packet_t *inp)
959 if (inp->fid == 0 || inp->inCount == 0) return fid;
960 else return inp->fid;
963 /* are we a priv'd user? What does this mean on NT? */
964 int smb_SUser(cm_user_t *userp)
969 /* find a file ID. If pass in 0, we'll allocate on on a create operation. */
970 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
975 /* figure out if we need to allocate a new file ID */
978 fid = vcp->fidCounter;
982 lock_ObtainWrite(&smb_rctLock);
984 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
985 if (fid == fidp->fid) {
988 if (fid == 0) fid = 1;
995 if (!fidp && (flags & SMB_FLAG_CREATE)) {
996 char eventName[MAX_PATH];
997 sprintf(eventName,"fid_t event fid=%d", fid);
998 fidp = malloc(sizeof(*fidp));
999 memset(fidp, 0, sizeof(*fidp));
1000 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1003 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1005 fidp->curr_chunk = fidp->prev_chunk = -2;
1006 fidp->raw_write_event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1007 if ( GetLastError() == ERROR_ALREADY_EXISTS )
1008 afsi_log("Event Object Already Exists: %s", eventName);
1010 vcp->fidCounter = fid+1;
1011 if (vcp->fidCounter == 0) vcp->fidCounter = 1;
1014 lock_ReleaseWrite(&smb_rctLock);
1018 void smb_ReleaseFID(smb_fid_t *fidp)
1022 smb_ioctl_t *ioctlp;
1028 lock_ObtainWrite(&smb_rctLock);
1029 osi_assert(fidp->refCount-- > 0);
1030 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1032 if (!(fidp->flags & SMB_FID_IOCTL))
1034 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1035 thrd_CloseHandle(fidp->raw_write_event);
1037 /* and see if there is ioctl stuff to free */
1038 ioctlp = fidp->ioctlp;
1040 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1041 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1042 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1048 lock_ReleaseWrite(&smb_rctLock);
1050 /* now release the scache structure */
1051 if (scp) cm_ReleaseSCache(scp);
1055 * Case-insensitive search for one string in another;
1056 * used to find variable names in submount pathnames.
1058 static char *smb_stristr(char *str1, char *str2)
1062 for (cursor = str1; *cursor; cursor++)
1063 if (stricmp(cursor, str2) == 0)
1070 * Substitute a variable value for its name in a submount pathname. Variable
1071 * name has been identified by smb_stristr() and is in substr. Variable name
1072 * length (plus one) is in substr_size. Variable value is in newstr.
1074 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1079 strcpy(temp, substr + substr_size - 1);
1080 strcpy(substr, newstr);
1084 char VNUserName[] = "%USERNAME%";
1085 char VNLCUserName[] = "%LCUSERNAME%";
1086 char VNComputerName[] = "%COMPUTERNAME%";
1087 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1089 /* List available shares */
1090 int smb_ListShares()
1094 char shareBuf[4096];
1102 /*strcpy(shareNameList[num_shares], "all");
1103 strcpy(pathNameList[num_shares++], "/afs");*/
1104 fprintf(stderr, "The following shares are available:\n");
1105 fprintf(stderr, "Share Name (AFS Path)\n");
1106 fprintf(stderr, "---------------------\n");
1107 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1110 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1111 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1113 strcpy(sbmtpath, cm_confDir);
1115 strcat(sbmtpath, "/afsdsbmt.ini");
1116 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1117 shareBuf, sizeof(shareBuf),
1123 this_share = shareBuf;
1127 /*strcpy(shareNameList[num_shares], this_share);*/
1128 len = GetPrivateProfileString("AFS Submounts", this_share,
1132 if (!len) return num_shares;
1134 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1137 if (*p == '\\') *p = '/'; /* change to / */
1141 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1142 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1145 while (*this_share != 0) this_share++; /* find next NUL */
1146 this_share++; /* skip past the NUL */
1147 } while (*this_share != 0); /* stop at final NUL */
1152 /* find a shareName in the table of submounts */
1153 int smb_FindShare(smb_vc_t *vcp, smb_packet_t *inp, char *shareName,
1157 char pathName[1024];
1162 char sbmtpath[MAX_PATH];
1166 DWORD allSubmount = 1;
1168 if (strcmp(shareName, "IPC$") == 0) {
1173 /* if allSubmounts == 0, only return the //mountRoot/all share
1174 * if in fact it has been been created in the subMounts table.
1175 * This is to allow sites that want to restrict access to the
1178 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1179 0, KEY_QUERY_VALUE, &parmKey);
1180 if (code == ERROR_SUCCESS) {
1181 len = sizeof(allSubmount);
1182 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1183 (BYTE *) &allSubmount, &len);
1184 if (code != ERROR_SUCCESS) {
1187 RegCloseKey (parmKey);
1190 if (allSubmount && _stricmp(shareName, "all") == 0) {
1195 /* In case, the all share is disabled we need to still be able
1196 * to handle ioctl requests
1198 if (_stricmp(shareName, "ioctl$") == 0) {
1199 *pathNamep = strdup("/.__ioctl__");
1204 strcpy(sbmtpath, "afsdsbmt.ini");
1206 strcpy(sbmtpath, cm_confDir);
1207 strcat(sbmtpath, "/afsdsbmt.ini");
1209 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1210 pathName, sizeof(pathName), sbmtpath);
1211 if (len != 0 && len != sizeof(pathName) - 1) {
1212 /* We can accept either unix or PC style AFS pathnames. Convert
1213 * Unix-style to PC style here for internal use.
1216 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1217 p += strlen(cm_mountRoot); /* skip mount path */
1220 if (*q == '/') *q = '\\'; /* change to \ */
1226 if (var = smb_stristr(p, VNUserName)) {
1227 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1228 if (uidp && uidp->unp)
1229 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1231 smb_subst(p, var, sizeof(VNUserName)," ");
1233 smb_ReleaseUID(uidp);
1235 else if (var = smb_stristr(p, VNLCUserName))
1237 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1238 if (uidp && uidp->unp)
1239 strcpy(temp, uidp->unp->name);
1243 smb_subst(p, var, sizeof(VNLCUserName), temp);
1245 smb_ReleaseUID(uidp);
1247 else if (var = smb_stristr(p, VNComputerName))
1249 sizeTemp = sizeof(temp);
1250 GetComputerName((LPTSTR)temp, &sizeTemp);
1251 smb_subst(p, var, sizeof(VNComputerName), temp);
1253 else if (var = smb_stristr(p, VNLCComputerName))
1255 sizeTemp = sizeof(temp);
1256 GetComputerName((LPTSTR)temp, &sizeTemp);
1258 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1263 *pathNamep = strdup(p);
1266 else /* create \\<netbiosName>\<cellname> */
1268 if (cm_GetCell_Gen(shareName, temp, CM_FLAG_CREATE))
1270 if (!stricmp(shareName, temp)) { /* no partial matches allowed */
1271 sprintf(pathName,"/%s/",shareName);
1272 *pathNamep = strdup(strlwr(pathName));
1282 /* find a dir search structure by cookie value, and return it held.
1283 * Must be called with smb_globalLock held.
1285 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1287 smb_dirSearch_t *dsp;
1289 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1290 if (dsp->cookie == cookie) {
1291 if (dsp != smb_firstDirSearchp) {
1292 /* move to head of LRU queue, too, if we're not already there */
1293 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1294 smb_lastDirSearchp = (smb_dirSearch_t *)
1296 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1297 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1298 if (!smb_lastDirSearchp)
1299 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1308 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1310 lock_ObtainWrite(&smb_globalLock);
1311 dsp->flags |= SMB_DIRSEARCH_DELETE;
1312 lock_ReleaseWrite(&smb_globalLock);
1313 lock_ObtainMutex(&dsp->mx);
1314 if(dsp->scp != NULL) {
1315 lock_ObtainMutex(&dsp->scp->mx);
1316 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1317 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1318 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1319 dsp->scp->bulkStatProgress = hones;
1321 lock_ReleaseMutex(&dsp->scp->mx);
1323 lock_ReleaseMutex(&dsp->mx);
1326 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1332 lock_ObtainWrite(&smb_globalLock);
1333 osi_assert(dsp->refCount-- > 0);
1334 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1335 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1336 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1337 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1338 lock_FinalizeMutex(&dsp->mx);
1342 lock_ReleaseWrite(&smb_globalLock);
1344 /* do this now to avoid spurious locking hierarchy creation */
1345 if (scp) cm_ReleaseSCache(scp);
1348 /* find a dir search structure by cookie value, and return it held */
1349 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1351 smb_dirSearch_t *dsp;
1353 lock_ObtainWrite(&smb_globalLock);
1354 dsp = smb_FindDirSearchNL(cookie);
1355 lock_ReleaseWrite(&smb_globalLock);
1359 /* GC some dir search entries, in the address space expected by the specific protocol.
1360 * Must be called with smb_globalLock held; release the lock temporarily.
1362 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1363 void smb_GCDirSearches(int isV3)
1365 smb_dirSearch_t *prevp;
1366 smb_dirSearch_t *tp;
1367 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1371 victimCount = 0; /* how many have we got so far */
1372 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1373 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q); /* we'll move tp from queue, so
1376 /* if no one is using this guy, and we're either in the new protocol,
1377 * or we're in the old one and this is a small enough ID to be useful
1378 * to the old protocol, GC this guy.
1380 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1381 /* hold and delete */
1382 tp->flags |= SMB_DIRSEARCH_DELETE;
1383 victimsp[victimCount++] = tp;
1387 /* don't do more than this */
1388 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1391 /* now release them */
1392 lock_ReleaseWrite(&smb_globalLock);
1393 for(i = 0; i < victimCount; i++) {
1394 smb_ReleaseDirSearch(victimsp[i]);
1396 lock_ObtainWrite(&smb_globalLock);
1399 /* function for allocating a dir search entry. We need these to remember enough context
1400 * since we don't get passed the path from call to call during a directory search.
1402 * Returns a held dir search structure, and bumps the reference count on the vnode,
1403 * since it saves a pointer to the vnode.
1405 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1407 smb_dirSearch_t *dsp;
1411 lock_ObtainWrite(&smb_globalLock);
1414 /* what's the biggest ID allowed in this version of the protocol */
1415 if (isV3) maxAllowed = 65535;
1416 else maxAllowed = 255;
1419 /* twice so we have enough tries to find guys we GC after one pass;
1420 * 10 extra is just in case I mis-counted.
1422 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1423 __FILE__, __LINE__);
1424 if (smb_dirSearchCounter > maxAllowed) {
1425 smb_dirSearchCounter = 1;
1426 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1428 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1430 /* don't need to watch for refcount zero and deleted, since
1431 * we haven't dropped the global lock.
1434 ++smb_dirSearchCounter;
1438 dsp = malloc(sizeof(*dsp));
1439 memset(dsp, 0, sizeof(*dsp));
1440 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1441 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1442 dsp->cookie = smb_dirSearchCounter;
1443 ++smb_dirSearchCounter;
1445 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1446 dsp->lastTime = osi_Time();
1449 lock_ReleaseWrite(&smb_globalLock);
1453 static smb_packet_t *GetPacket(void)
1457 unsigned int npar, seg, tb_sel;
1460 lock_ObtainWrite(&smb_globalLock);
1461 tbp = smb_packetFreeListp;
1463 smb_packetFreeListp = tbp->nextp;
1464 lock_ReleaseWrite(&smb_globalLock);
1467 tbp = calloc(65540,1);
1469 tbp = malloc(sizeof(smb_packet_t));
1471 tbp->magic = SMB_PACKETMAGIC;
1474 tbp->resumeCode = 0;
1480 tbp->ncb_length = 0;
1485 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1488 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1490 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1492 osi_panic("",__FILE__,__LINE__);
1495 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1500 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1501 tbp->dos_pkt_sel = tb_sel;
1504 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1509 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1513 memcpy(tbp, pkt, sizeof(smb_packet_t));
1514 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1518 static NCB *GetNCB(void)
1523 unsigned int npar, seg, tb_sel;
1526 lock_ObtainWrite(&smb_globalLock);
1527 tbp = smb_ncbFreeListp;
1529 smb_ncbFreeListp = tbp->nextp;
1530 lock_ReleaseWrite(&smb_globalLock);
1533 tbp = calloc(sizeof(*tbp),1);
1535 tbp = malloc(sizeof(*tbp));
1536 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1539 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1541 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1543 osi_panic("",__FILE__,__LINE__);
1545 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1550 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1551 tbp->dos_ncb_sel = tb_sel;
1553 tbp->magic = SMB_NCBMAGIC;
1556 osi_assert(tbp->magic == SMB_NCBMAGIC);
1558 memset(&tbp->ncb, 0, sizeof(NCB));
1561 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1566 void smb_FreePacket(smb_packet_t *tbp)
1568 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1570 lock_ObtainWrite(&smb_globalLock);
1571 tbp->nextp = smb_packetFreeListp;
1572 smb_packetFreeListp = tbp;
1573 tbp->magic = SMB_PACKETMAGIC;
1576 tbp->resumeCode = 0;
1582 tbp->ncb_length = 0;
1584 lock_ReleaseWrite(&smb_globalLock);
1587 static void FreeNCB(NCB *bufferp)
1591 tbp = (smb_ncb_t *) bufferp;
1592 osi_assert(tbp->magic == SMB_NCBMAGIC);
1594 lock_ObtainWrite(&smb_globalLock);
1595 tbp->nextp = smb_ncbFreeListp;
1596 smb_ncbFreeListp = tbp;
1597 lock_ReleaseWrite(&smb_globalLock);
1600 /* get a ptr to the data part of a packet, and its count */
1601 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1605 unsigned char *afterParmsp;
1607 parmBytes = *smbp->wctp << 1;
1608 afterParmsp = smbp->wctp + parmBytes + 1;
1610 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1611 if (nbytesp) *nbytesp = dataBytes;
1613 /* don't forget to skip the data byte count, since it follows
1614 * the parameters; that's where the "2" comes from below.
1616 return (unsigned char *) (afterParmsp + 2);
1619 /* must set all the returned parameters before playing around with the
1620 * data region, since the data region is located past the end of the
1621 * variable number of parameters.
1623 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1625 unsigned char *afterParmsp;
1627 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1629 *afterParmsp++ = dsize & 0xff;
1630 *afterParmsp = (dsize>>8) & 0xff;
1633 /* return the parm'th parameter in the smbp packet */
1634 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1637 unsigned char *parmDatap;
1639 parmCount = *smbp->wctp;
1641 if (parm >= parmCount) {
1646 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1647 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1648 parm, parmCount, smbp->ncb_length);
1650 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1651 1, smbp->ncb_length, ptbuf, smbp);
1652 DeregisterEventSource(h);
1656 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1657 parm, parmCount, smbp->ncb_length);
1658 osi_Log0(afsd_logp, s);
1660 osi_panic(s, __FILE__, __LINE__);
1662 parmDatap = smbp->wctp + (2*parm) + 1;
1664 return parmDatap[0] + (parmDatap[1] << 8);
1667 /* return the parm'th parameter in the smbp packet */
1668 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1671 unsigned char *parmDatap;
1673 parmCount = *smbp->wctp;
1675 if (parm * 2 + offset >= parmCount * 2) {
1680 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1681 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1682 parm, offset, parmCount, smbp->ncb_length);
1684 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1685 1, smbp->ncb_length, ptbuf, smbp);
1686 DeregisterEventSource(h);
1690 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1692 parm, offset, parmCount, smbp->ncb_length);
1693 osi_Log0(afsd_logp, s);
1696 osi_panic(s, __FILE__, __LINE__);
1698 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1700 return parmDatap[0] + (parmDatap[1] << 8);
1703 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1707 /* make sure we have enough slots */
1708 if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1710 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1711 *parmDatap++ = parmValue & 0xff;
1712 *parmDatap = (parmValue>>8) & 0xff;
1715 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1719 /* make sure we have enough slots */
1720 if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1722 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1723 *parmDatap++ = parmValue & 0xff;
1724 *parmDatap++ = (parmValue>>8) & 0xff;
1725 *parmDatap++ = (parmValue>>16) & 0xff;
1726 *parmDatap++ = (parmValue>>24) & 0xff;
1729 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1734 /* make sure we have enough slots */
1735 if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1737 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1739 *parmDatap++ = *parmValuep++;
1742 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1746 /* make sure we have enough slots */
1747 if (*smbp->wctp <= slot) {
1748 if (smbp->oddByte) {
1750 *smbp->wctp = slot+1;
1755 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1756 *parmDatap++ = parmValue & 0xff;
1759 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1763 lastSlashp = strrchr(inPathp, '\\');
1765 *lastComponentp = lastSlashp;
1768 if (inPathp == lastSlashp) break;
1769 *outPathp++ = *inPathp++;
1778 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1780 if (*inp++ != 0x4) return NULL;
1782 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
1787 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1791 if (*inp++ != 0x5) return NULL;
1792 tlen = inp[0] + (inp[1]<<8);
1793 inp += 2; /* skip length field */
1796 *chainpp = inp + tlen;
1799 if (lengthp) *lengthp = tlen;
1804 /* format a packet as a response */
1805 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1810 outp = (smb_t *) op;
1812 /* zero the basic structure through the smb_wct field, and zero the data
1813 * size field, assuming that wct stays zero; otherwise, you have to
1814 * explicitly set the data size field, too.
1816 inSmbp = (smb_t *) inp;
1817 memset(outp, 0, sizeof(smb_t)+2);
1823 outp->com = inSmbp->com;
1824 outp->tid = inSmbp->tid;
1825 outp->pid = inSmbp->pid;
1826 outp->uid = inSmbp->uid;
1827 outp->mid = inSmbp->mid;
1828 outp->res[0] = inSmbp->res[0];
1829 outp->res[1] = inSmbp->res[1];
1830 op->inCom = inSmbp->com;
1832 outp->reb = 0x80; /* SERVER_RESP */
1833 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
1835 /* copy fields in generic packet area */
1836 op->wctp = &outp->wct;
1839 /* send a (probably response) packet; vcp tells us to whom to send it.
1840 * we compute the length by looking at wct and bcc fields.
1842 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1859 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
1862 memset((char *)ncbp, 0, sizeof(NCB));
1864 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
1865 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
1866 extra += tp[0] + (tp[1]<<8);
1867 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
1868 extra += 3; /* wct and length fields */
1870 ncbp->ncb_length = extra; /* bytes to send */
1871 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
1872 ncbp->ncb_lana_num = vcp->lana;
1873 ncbp->ncb_command = NCBSEND; /* op means send data */
1875 ncbp->ncb_buffer = (char *) inp;/* packet */
1876 code = Netbios(ncbp);
1878 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
1879 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
1881 /* copy header information from virtual to DOS address space */
1882 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
1883 code = Netbios(ncbp, dos_ncb);
1887 osi_Log1(afsd_logp, "SendPacket failure code %d", code);
1893 void smb_MapNTError(long code, unsigned long *NTStatusp)
1895 unsigned long NTStatus;
1897 /* map CM_ERROR_* errors to NT 32-bit status codes */
1898 if (code == CM_ERROR_NOSUCHCELL) {
1899 NTStatus = 0xC000000FL; /* No such file */
1901 else if (code == CM_ERROR_NOSUCHVOLUME) {
1902 NTStatus = 0xC000000FL; /* No such file */
1904 else if (code == CM_ERROR_TIMEDOUT) {
1905 NTStatus = 0xC00000CFL; /* Sharing Paused */
1907 else if (code == CM_ERROR_RETRY) {
1908 NTStatus = 0xC000022DL; /* Retry */
1910 else if (code == CM_ERROR_NOACCESS) {
1911 NTStatus = 0xC0000022L; /* Access denied */
1913 else if (code == CM_ERROR_READONLY) {
1914 NTStatus = 0xC00000A2L; /* Write protected */
1916 else if (code == CM_ERROR_NOSUCHFILE) {
1917 NTStatus = 0xC000000FL; /* No such file */
1919 else if (code == CM_ERROR_NOSUCHPATH) {
1920 NTStatus = 0xC000003AL; /* Object path not found */
1922 else if (code == CM_ERROR_TOOBIG) {
1923 NTStatus = 0xC000007BL; /* Invalid image format */
1925 else if (code == CM_ERROR_INVAL) {
1926 NTStatus = 0xC000000DL; /* Invalid parameter */
1928 else if (code == CM_ERROR_BADFD) {
1929 NTStatus = 0xC0000008L; /* Invalid handle */
1931 else if (code == CM_ERROR_BADFDOP) {
1932 NTStatus = 0xC0000022L; /* Access denied */
1934 else if (code == CM_ERROR_EXISTS) {
1935 NTStatus = 0xC0000035L; /* Object name collision */
1937 else if (code == CM_ERROR_NOTEMPTY) {
1938 NTStatus = 0xC0000101L; /* Directory not empty */
1940 else if (code == CM_ERROR_CROSSDEVLINK) {
1941 NTStatus = 0xC00000D4L; /* Not same device */
1943 else if (code == CM_ERROR_NOTDIR) {
1944 NTStatus = 0xC0000103L; /* Not a directory */
1946 else if (code == CM_ERROR_ISDIR) {
1947 NTStatus = 0xC00000BAL; /* File is a directory */
1949 else if (code == CM_ERROR_BADOP) {
1950 NTStatus = 0xC09820FFL; /* SMB no support */
1952 else if (code == CM_ERROR_BADSHARENAME) {
1953 NTStatus = 0xC00000CCL; /* Bad network name */
1955 else if (code == CM_ERROR_NOIPC) {
1957 NTStatus = 0xC0000022L; /* Access Denied */
1959 NTStatus = 0xC000013DL; /* Remote Resources */
1962 else if (code == CM_ERROR_CLOCKSKEW) {
1963 NTStatus = 0xC0000133L; /* Time difference at DC */
1965 else if (code == CM_ERROR_BADTID) {
1966 NTStatus = 0xC0982005L; /* SMB bad TID */
1968 else if (code == CM_ERROR_USESTD) {
1969 NTStatus = 0xC09820FBL; /* SMB use standard */
1971 else if (code == CM_ERROR_QUOTA) {
1972 NTStatus = 0xC0000044L; /* Quota exceeded */
1974 else if (code == CM_ERROR_SPACE) {
1975 NTStatus = 0xC000007FL; /* Disk full */
1977 else if (code == CM_ERROR_ATSYS) {
1978 NTStatus = 0xC0000033L; /* Object name invalid */
1980 else if (code == CM_ERROR_BADNTFILENAME) {
1981 NTStatus = 0xC0000033L; /* Object name invalid */
1983 else if (code == CM_ERROR_WOULDBLOCK) {
1984 NTStatus = 0xC0000055L; /* Lock not granted */
1986 else if (code == CM_ERROR_PARTIALWRITE) {
1987 NTStatus = 0xC000007FL; /* Disk full */
1989 else if (code == CM_ERROR_BUFFERTOOSMALL) {
1990 NTStatus = 0xC0000023L; /* Buffer too small */
1993 NTStatus = 0xC0982001L; /* SMB non-specific error */
1996 *NTStatusp = NTStatus;
1997 osi_Log2(afsd_logp, "SMB SEND code %x as NT %x", code, NTStatus);
2000 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2001 unsigned char *classp)
2003 unsigned char class;
2004 unsigned short error;
2006 /* map CM_ERROR_* errors to SMB errors */
2007 if (code == CM_ERROR_NOSUCHCELL) {
2009 error = 3; /* bad path */
2011 else if (code == CM_ERROR_NOSUCHVOLUME) {
2013 error = 3; /* bad path */
2015 else if (code == CM_ERROR_TIMEDOUT) {
2017 error = 81; /* server is paused */
2019 else if (code == CM_ERROR_RETRY) {
2020 class = 2; /* shouldn't happen */
2023 else if (code == CM_ERROR_NOACCESS) {
2025 error = 4; /* bad access */
2027 else if (code == CM_ERROR_READONLY) {
2029 error = 19; /* read only */
2031 else if (code == CM_ERROR_NOSUCHFILE) {
2033 error = 2; /* ENOENT! */
2035 else if (code == CM_ERROR_NOSUCHPATH) {
2037 error = 3; /* Bad path */
2039 else if (code == CM_ERROR_TOOBIG) {
2041 error = 11; /* bad format */
2043 else if (code == CM_ERROR_INVAL) {
2044 class = 2; /* server non-specific error code */
2047 else if (code == CM_ERROR_BADFD) {
2049 error = 6; /* invalid file handle */
2051 else if (code == CM_ERROR_BADFDOP) {
2052 class = 1; /* invalid op on FD */
2055 else if (code == CM_ERROR_EXISTS) {
2057 error = 80; /* file already exists */
2059 else if (code == CM_ERROR_NOTEMPTY) {
2061 error = 5; /* delete directory not empty */
2063 else if (code == CM_ERROR_CROSSDEVLINK) {
2065 error = 17; /* EXDEV */
2067 else if (code == CM_ERROR_NOTDIR) {
2068 class = 1; /* bad path */
2071 else if (code == CM_ERROR_ISDIR) {
2072 class = 1; /* access denied; DOS doesn't have a good match */
2075 else if (code == CM_ERROR_BADOP) {
2079 else if (code == CM_ERROR_BADSHARENAME) {
2083 else if (code == CM_ERROR_NOIPC) {
2085 error = 4; /* bad access */
2087 else if (code == CM_ERROR_CLOCKSKEW) {
2088 class = 1; /* invalid function */
2091 else if (code == CM_ERROR_BADTID) {
2095 else if (code == CM_ERROR_USESTD) {
2099 else if (code == CM_ERROR_REMOTECONN) {
2103 else if (code == CM_ERROR_QUOTA) {
2104 if (vcp->flags & SMB_VCFLAG_USEV3) {
2106 error = 39; /* disk full */
2110 error = 5; /* access denied */
2113 else if (code == CM_ERROR_SPACE) {
2114 if (vcp->flags & SMB_VCFLAG_USEV3) {
2116 error = 39; /* disk full */
2120 error = 5; /* access denied */
2123 else if (code == CM_ERROR_PARTIALWRITE) {
2125 error = 39; /* disk full */
2127 else if (code == CM_ERROR_ATSYS) {
2129 error = 2; /* ENOENT */
2131 else if (code == CM_ERROR_WOULDBLOCK) {
2133 error = 33; /* lock conflict */
2135 else if (code == CM_ERROR_NOFILES) {
2137 error = 18; /* no files in search */
2139 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2141 error = 183; /* Samba uses this */
2150 osi_Log3(afsd_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2153 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2155 return CM_ERROR_BADOP;
2158 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2160 unsigned short EchoCount, i;
2161 char *data, *outdata;
2164 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2166 for (i=1; i<=EchoCount; i++) {
2167 data = smb_GetSMBData(inp, &dataSize);
2168 smb_SetSMBParm(outp, 0, i);
2169 smb_SetSMBDataLength(outp, dataSize);
2170 outdata = smb_GetSMBData(outp, NULL);
2171 memcpy(outdata, data, dataSize);
2172 smb_SendPacket(vcp, outp);
2178 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2181 long count, minCount, finalCount;
2185 cm_user_t *userp = NULL;
2189 char *rawBuf = NULL;
2191 dos_ptr rawBuf = NULL;
2198 fd = smb_GetSMBParm(inp, 0);
2199 count = smb_GetSMBParm(inp, 3);
2200 minCount = smb_GetSMBParm(inp, 4);
2201 offset.HighPart = 0; /* too bad */
2202 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2204 osi_Log3(afsd_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2205 fd, offset.LowPart, count);
2207 fidp = smb_FindFID(vcp, fd, 0);
2211 lock_ObtainMutex(&smb_RawBufLock);
2213 /* Get a raw buf, from head of list */
2214 rawBuf = smb_RawBufs;
2216 smb_RawBufs = *(char **)smb_RawBufs;
2218 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2221 lock_ReleaseMutex(&smb_RawBufLock);
2225 if (fidp->flags & SMB_FID_IOCTL)
2228 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2230 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2233 /* Give back raw buffer */
2234 lock_ObtainMutex(&smb_RawBufLock);
2236 *((char **) rawBuf) = smb_RawBufs;
2238 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2241 smb_RawBufs = rawBuf;
2242 lock_ReleaseMutex(&smb_RawBufLock);
2245 smb_ReleaseFID(fidp);
2249 userp = smb_GetUser(vcp, inp);
2252 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2254 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2255 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2256 userp, &finalCount, TRUE /* rawFlag */);
2263 cm_ReleaseUser(userp);
2266 smb_ReleaseFID(fidp);
2271 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2273 memset((char *)ncbp, 0, sizeof(NCB));
2275 ncbp->ncb_length = (unsigned short) finalCount;
2276 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2277 ncbp->ncb_lana_num = vcp->lana;
2278 ncbp->ncb_command = NCBSEND;
2279 ncbp->ncb_buffer = rawBuf;
2282 code = Netbios(ncbp);
2284 code = Netbios(ncbp, dos_ncb);
2287 osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
2290 /* Give back raw buffer */
2291 lock_ObtainMutex(&smb_RawBufLock);
2293 *((char **) rawBuf) = smb_RawBufs;
2295 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2298 smb_RawBufs = rawBuf;
2299 lock_ReleaseMutex(&smb_RawBufLock);
2305 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2310 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2315 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2321 int protoIndex; /* index we're using */
2326 char protocol_array[10][1024]; /* protocol signature of the client */
2329 osi_Log1(afsd_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2333 DWORD now = GetCurrentTime();
2334 if (now - last_msg_time >= 30000
2335 && now - last_msg_time <= 90000) {
2337 "Setting dead_vcp %x", active_vcp);
2338 dead_vcp = active_vcp;
2339 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2344 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2346 namep = smb_GetSMBData(inp, &dbytes);
2349 coreProtoIndex = -1; /* not found */
2352 while(namex < dbytes) {
2353 osi_Log1(afsd_logp, "Protocol %s",
2354 osi_LogSaveString(afsd_logp, namep+1));
2355 strcpy(protocol_array[tcounter], namep+1);
2357 /* namep points at the first protocol, or really, a 0x02
2358 * byte preceding the null-terminated ASCII name.
2360 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2361 coreProtoIndex = tcounter;
2363 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2364 v3ProtoIndex = tcounter;
2366 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2367 NTProtoIndex = tcounter;
2370 /* compute size of protocol entry */
2371 entryLength = strlen(namep+1);
2372 entryLength += 2; /* 0x02 bytes and null termination */
2374 /* advance over this protocol entry */
2375 namex += entryLength;
2376 namep += entryLength;
2377 tcounter++; /* which proto entry we're looking at */
2379 #ifndef NOMOREFILESFIX
2381 * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
2382 * the client is running by reading the protocol signature.
2383 * ie. the order in which it sends us the protocol list.
2385 * Special handling for Windows 2000 clients (defect 11765 )
2386 * <asanka:11Jun03> Proto signature is the same for Win XP. </>
2388 if (tcounter == 6) {
2390 smb_t *ip = (smb_t *) inp;
2391 smb_t *op = (smb_t *) outp;
2393 if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
2394 (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
2395 (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
2396 (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
2397 (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
2398 (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
2399 isWindows2000 = TRUE;
2400 osi_Log0(afsd_logp, "Looks like a Windows 2000 client");
2402 * HACK: for now - just negotiate a lower protocol till we
2403 * figure out which flag/flag2 or some other field
2404 * (capabilities maybe?) to set in order for this to work
2405 * correctly with Windows 2000 clients (defect 11765)
2408 /* Things to try (after looking at tcpdump output could be
2409 * setting flags and flags2 to 0x98 and 0xc853 like this
2410 * op->reb = 0x98; op->flg2 = 0xc853;
2411 * osi_Log2(afsd_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
2415 #endif /* NOMOREFILESFIX */
2417 if (NTProtoIndex != -1) {
2418 protoIndex = NTProtoIndex;
2419 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2421 else if (v3ProtoIndex != -1) {
2422 protoIndex = v3ProtoIndex;
2423 vcp->flags |= SMB_VCFLAG_USEV3;
2425 else if (coreProtoIndex != -1) {
2426 protoIndex = coreProtoIndex;
2427 vcp->flags |= SMB_VCFLAG_USECORE;
2429 else protoIndex = -1;
2431 if (protoIndex == -1)
2432 return CM_ERROR_INVAL;
2433 else if (NTProtoIndex != -1) {
2434 smb_SetSMBParm(outp, 0, protoIndex);
2435 smb_SetSMBParmByte(outp, 1, 0); /* share level security, no passwd encrypt */
2436 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2437 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2438 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2439 smb_SetSMBParmLong(outp, 5, 65536); /* raw buffer size */
2440 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2441 smb_SetSMBParm(outp, 8, 1);
2443 * Tried changing the capabilities to support for W2K - defect 117695
2444 * Maybe something else needs to be changed here?
2448 smb_SetSMBParmLong(outp, 9, 0x43fd);
2450 smb_SetSMBParmLong(outp, 9, 0x251);
2452 smb_SetSMBParmLong(outp, 9, 0x251); /* Capabilities: *
2453 * 32-bit error codes *
2457 smb_SetSMBParmLong(outp, 11, 0);/* XXX server time: do we need? */
2458 smb_SetSMBParmLong(outp, 13, 0);/* XXX server date: do we need? */
2459 smb_SetSMBParm(outp, 15, 0); /* XXX server tzone: do we need? */
2460 smb_SetSMBParmByte(outp, 16, 0);/* Encryption key length */
2461 smb_SetSMBDataLength(outp, 0); /* perhaps should specify 8 bytes anyway */
2463 else if (v3ProtoIndex != -1) {
2464 smb_SetSMBParm(outp, 0, protoIndex);
2465 smb_SetSMBParm(outp, 1, 0); /* share level security, no passwd encrypt */
2466 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2467 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2468 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2469 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2470 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2471 smb_SetSMBParm(outp, 7, 1);
2472 smb_SetSMBParm(outp, 8, 0); /* XXX server time: do we need? */
2473 smb_SetSMBParm(outp, 9, 0); /* XXX server date: do we need? */
2474 smb_SetSMBParm(outp, 10, 0); /* XXX server tzone: do we need? */
2475 smb_SetSMBParm(outp, 11, 0); /* resvd */
2476 smb_SetSMBParm(outp, 12, 0); /* resvd */
2477 smb_SetSMBDataLength(outp, 0); /* perhaps should specify 8 bytes anyway */
2479 else if (coreProtoIndex != -1) {
2480 smb_SetSMBParm(outp, 0, protoIndex);
2481 smb_SetSMBDataLength(outp, 0);
2486 void smb_Daemon(void *parmp)
2493 if ((count % 360) == 0) /* every hour */
2494 smb_CalculateNowTZ();
2495 /* XXX GC dir search entries */
2499 void smb_WaitingLocksDaemon()
2501 smb_waitingLock_t *wL, *nwL;
2504 smb_packet_t *inp, *outp;
2509 lock_ObtainWrite(&smb_globalLock);
2510 nwL = smb_allWaitingLocks;
2512 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2521 lock_ObtainWrite(&smb_globalLock);
2523 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2524 lock_ReleaseWrite(&smb_globalLock);
2525 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2526 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2527 if (code == CM_ERROR_WOULDBLOCK) {
2529 if (wL->timeRemaining != 0xffffffff
2530 && (wL->timeRemaining -= 1000) < 0)
2539 ncbp->ncb_length = inp->ncb_length;
2540 inp->spacep = cm_GetSpace();
2542 /* Remove waitingLock from list */
2543 lock_ObtainWrite(&smb_globalLock);
2544 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2546 lock_ReleaseWrite(&smb_globalLock);
2548 /* Resume packet processing */
2550 smb_SetSMBDataLength(outp, 0);
2551 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2552 outp->resumeCode = code;
2554 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2557 cm_FreeSpace(inp->spacep);
2558 smb_FreePacket(inp);
2559 smb_FreePacket(outp);
2567 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2569 osi_Log0(afsd_logp, "SMB receive get disk attributes");
2571 smb_SetSMBParm(outp, 0, 32000);
2572 smb_SetSMBParm(outp, 1, 64);
2573 smb_SetSMBParm(outp, 2, 1024);
2574 smb_SetSMBParm(outp, 3, 30000);
2575 smb_SetSMBParm(outp, 4, 0);
2576 smb_SetSMBDataLength(outp, 0);
2580 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2583 unsigned short newTid;
2584 char shareName[256];
2592 osi_Log0(afsd_logp, "SMB receive tree connect");
2594 /* parse input parameters */
2595 tp = smb_GetSMBData(inp, NULL);
2596 pathp = smb_ParseASCIIBlock(tp, &tp);
2597 passwordp = smb_ParseASCIIBlock(tp, &tp);
2598 tp = strrchr(pathp, '\\');
2600 return CM_ERROR_BADSMB;
2601 strcpy(shareName, tp+1);
2603 userp = smb_GetUser(vcp, inp);
2605 lock_ObtainMutex(&vcp->mx);
2606 newTid = vcp->tidCounter++;
2607 lock_ReleaseMutex(&vcp->mx);
2609 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2610 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
2612 smb_ReleaseTID(tidp);
2613 return CM_ERROR_BADSHARENAME;
2615 lock_ObtainMutex(&tidp->mx);
2616 tidp->userp = userp;
2617 tidp->pathname = sharePath;
2618 lock_ReleaseMutex(&tidp->mx);
2619 smb_ReleaseTID(tidp);
2621 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2622 smb_SetSMBParm(rsp, 1, newTid);
2623 smb_SetSMBDataLength(rsp, 0);
2625 osi_Log1(afsd_logp, "SMB tree connect created ID %d", newTid);
2629 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2633 if (*inp++ != 0x1) return NULL;
2634 tlen = inp[0] + (inp[1]<<8);
2635 inp += 2; /* skip length field */
2638 *chainpp = inp + tlen;
2641 if (lengthp) *lengthp = tlen;
2646 /* set maskp to the mask part of the incoming path.
2647 * Mask is 11 bytes long (8.3 with the dot elided).
2648 * Returns true if succeeds with a valid name, otherwise it does
2649 * its best, but returns false.
2651 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2659 /* starts off valid */
2662 /* mask starts out all blanks */
2663 memset(maskp, ' ', 11);
2665 /* find last backslash, or use whole thing if there is none */
2666 tp = strrchr(pathp, '\\');
2667 if (!tp) tp = pathp;
2668 else tp++; /* skip slash */
2672 /* names starting with a dot are illegal */
2673 if (*tp == '.') valid8Dot3 = 0;
2677 if (tc == 0) return valid8Dot3;
2678 if (tc == '.' || tc == '"') break;
2679 if (i < 8) *up++ = tc;
2680 else valid8Dot3 = 0;
2683 /* if we get here, tp point after the dot */
2684 up = maskp+8; /* ext goes here */
2687 if (tc == 0) return valid8Dot3;
2690 if (tc == '.' || tc == '"') valid8Dot3 = 0;
2692 /* copy extension if not too long */
2693 if (i < 3) *up++ = tc;
2694 else valid8Dot3 = 0;
2700 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2710 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2712 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2713 if (!valid) return 0;
2715 /* otherwise, we have a valid 8.3 name; see if we have a match,
2716 * treating '?' as a wildcard in maskp (but not in the file name).
2718 tp1 = umask; /* real name, in mask format */
2719 tp2 = maskp; /* mask, in mask format */
2720 for(i=0; i<11; i++) {
2721 tc1 = *tp1++; /* char from real name */
2722 tc2 = *tp2++; /* char from mask */
2723 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
2724 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
2725 if (tc1 == tc2) continue;
2726 if (tc2 == '?' && tc1 != ' ') continue;
2727 if (tc2 == '>') continue;
2731 /* we got a match */
2735 char *smb_FindMask(char *pathp)
2739 tp = strrchr(pathp, '\\'); /* find last slash */
2741 if (tp) return tp+1; /* skip the slash */
2742 else return pathp; /* no slash, return the entire path */
2745 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2747 unsigned char *pathp;
2749 unsigned char mask[11];
2750 unsigned char *statBlockp;
2751 unsigned char initStatBlock[21];
2754 osi_Log0(afsd_logp, "SMB receive search volume");
2756 /* pull pathname and stat block out of request */
2757 tp = smb_GetSMBData(inp, NULL);
2758 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
2759 osi_assert(pathp != NULL);
2760 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
2761 osi_assert(statBlockp != NULL);
2763 statBlockp = initStatBlock;
2767 /* for returning to caller */
2768 smb_Get8Dot3MaskFromPath(mask, pathp);
2770 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
2771 tp = smb_GetSMBData(outp, NULL);
2773 *tp++ = 43; /* bytes in a dir entry */
2774 *tp++ = 0; /* high byte in counter */
2776 /* now marshall the dir entry, starting with the search status */
2777 *tp++ = statBlockp[0]; /* Reserved */
2778 memcpy(tp, mask, 11); tp += 11; /* FileName */
2780 /* now pass back server use info, with 1st byte non-zero */
2782 memset(tp, 0, 4); tp += 4; /* reserved for server use */
2784 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
2786 *tp++ = 0x8; /* attribute: volume */
2796 /* 4 byte file size */
2802 /* finally, null-terminated 8.3 pathname, which we set to AFS */
2803 memset(tp, ' ', 13);
2806 /* set the length of the data part of the packet to 43 + 3, for the dir
2807 * entry plus the 5 and the length fields.
2809 smb_SetSMBDataLength(outp, 46);
2813 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
2814 cm_user_t *userp, cm_req_t *reqp)
2822 smb_dirListPatch_t *patchp;
2823 smb_dirListPatch_t *npatchp;
2825 for(patchp = *dirPatchespp; patchp; patchp =
2826 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2827 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2829 lock_ObtainMutex(&scp->mx);
2830 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2831 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2833 lock_ReleaseMutex(&scp->mx);
2834 cm_ReleaseSCache(scp);
2837 dptr = patchp->dptr;
2839 attr = smb_Attributes(scp);
2840 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
2841 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2842 attr |= SMB_ATTR_HIDDEN;
2846 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2849 shortTemp = dosTime & 0xffff;
2850 *((u_short *)dptr) = shortTemp;
2853 /* and copy out date */
2854 shortTemp = (dosTime>>16) & 0xffff;
2855 *((u_short *)dptr) = shortTemp;
2858 /* copy out file length */
2859 *((u_long *)dptr) = scp->length.LowPart;
2861 lock_ReleaseMutex(&scp->mx);
2862 cm_ReleaseSCache(scp);
2865 /* now free the patches */
2866 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2867 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
2871 /* and mark the list as empty */
2872 *dirPatchespp = NULL;
2877 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2886 smb_dirListPatch_t *dirListPatchesp;
2887 smb_dirListPatch_t *curPatchp;
2891 osi_hyper_t dirLength;
2892 osi_hyper_t bufferOffset;
2893 osi_hyper_t curOffset;
2895 unsigned char *inCookiep;
2896 smb_dirSearch_t *dsp;
2900 unsigned long clientCookie;
2901 cm_pageHeader_t *pageHeaderp;
2902 cm_user_t *userp = NULL;
2909 long nextEntryCookie;
2910 int numDirChunks; /* # of 32 byte dir chunks in this entry */
2911 char resByte; /* reserved byte from the cookie */
2912 char *op; /* output data ptr */
2913 char *origOp; /* original value of op */
2914 cm_space_t *spacep; /* for pathname buffer */
2925 maxCount = smb_GetSMBParm(inp, 0);
2927 dirListPatchesp = NULL;
2929 caseFold = CM_FLAG_CASEFOLD;
2931 tp = smb_GetSMBData(inp, NULL);
2932 pathp = smb_ParseASCIIBlock(tp, &tp);
2933 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
2935 /* bail out if request looks bad */
2936 if (!tp || !pathp) {
2937 return CM_ERROR_BADSMB;
2940 /* We can handle long names */
2941 if (vcp->flags & SMB_VCFLAG_USENT)
2942 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
2944 /* make sure we got a whole search status */
2945 if (dataLength < 21) {
2946 nextCookie = 0; /* start at the beginning of the dir */
2949 attribute = smb_GetSMBParm(inp, 1);
2951 /* handle volume info in another function */
2952 if (attribute & 0x8)
2953 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
2955 osi_Log2(afsd_logp, "SMB receive search dir count %d [%s]",
2956 maxCount, osi_LogSaveString(afsd_logp, pathp));
2958 if (*pathp == 0) { /* null pathp, treat as root dir */
2959 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
2960 return CM_ERROR_NOFILES;
2964 dsp = smb_NewDirSearch(0);
2965 dsp->attribute = attribute;
2966 smb_Get8Dot3MaskFromPath(mask, pathp);
2967 memcpy(dsp->mask, mask, 11);
2969 /* track if this is likely to match a lot of entries */
2970 if (smb_IsStarMask(mask)) starPattern = 1;
2971 else starPattern = 0;
2974 /* pull the next cookie value out of the search status block */
2975 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
2976 + (inCookiep[16]<<24);
2977 dsp = smb_FindDirSearch(inCookiep[12]);
2979 /* can't find dir search status; fatal error */
2980 return CM_ERROR_BADFD;
2982 attribute = dsp->attribute;
2983 resByte = inCookiep[0];
2985 /* copy out client cookie, in host byte order. Don't bother
2986 * interpreting it, since we're just passing it through, anyway.
2988 memcpy(&clientCookie, &inCookiep[17], 4);
2990 memcpy(mask, dsp->mask, 11);
2992 /* assume we're doing a star match if it has continued for more
2998 osi_Log3(afsd_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
2999 nextCookie, dsp->cookie, attribute);
3001 userp = smb_GetUser(vcp, inp);
3003 /* try to get the vnode for the path name next */
3004 lock_ObtainMutex(&dsp->mx);
3011 spacep = inp->spacep;
3012 smb_StripLastComponent(spacep->data, NULL, pathp);
3013 lock_ReleaseMutex(&dsp->mx);
3014 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3015 code = cm_NameI(cm_rootSCachep, spacep->data,
3016 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3017 lock_ObtainMutex(&dsp->mx);
3019 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3021 /* we need one hold for the entry we just stored into,
3022 * and one for our own processing. When we're done with this
3023 * function, we'll drop the one for our own processing.
3024 * We held it once from the namei call, and so we do another hold
3028 lock_ObtainMutex(&scp->mx);
3029 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3030 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3031 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3032 dsp->flags |= SMB_DIRSEARCH_BULKST;
3034 lock_ReleaseMutex(&scp->mx);
3037 lock_ReleaseMutex(&dsp->mx);
3039 cm_ReleaseUser(userp);
3040 smb_DeleteDirSearch(dsp);
3041 smb_ReleaseDirSearch(dsp);
3045 /* reserves space for parameter; we'll adjust it again later to the
3046 * real count of the # of entries we returned once we've actually
3047 * assembled the directory listing.
3049 smb_SetSMBParm(outp, 0, 0);
3051 /* get the directory size */
3052 lock_ObtainMutex(&scp->mx);
3053 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3054 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3056 lock_ReleaseMutex(&scp->mx);
3057 cm_ReleaseSCache(scp);
3058 cm_ReleaseUser(userp);
3059 smb_DeleteDirSearch(dsp);
3060 smb_ReleaseDirSearch(dsp);
3064 dirLength = scp->length;
3066 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3067 curOffset.HighPart = 0;
3068 curOffset.LowPart = nextCookie;
3069 origOp = op = smb_GetSMBData(outp, NULL);
3070 /* and write out the basic header */
3071 *op++ = 5; /* variable block */
3072 op += 2; /* skip vbl block length; we'll fill it in later */
3076 /* make sure that curOffset.LowPart doesn't point to the first
3077 * 32 bytes in the 2nd through last dir page, and that it doesn't
3078 * point at the first 13 32-byte chunks in the first dir page,
3079 * since those are dir and page headers, and don't contain useful
3082 temp = curOffset.LowPart & (2048-1);
3083 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3084 /* we're in the first page */
3085 if (temp < 13*32) temp = 13*32;
3088 /* we're in a later dir page */
3089 if (temp < 32) temp = 32;
3092 /* make sure the low order 5 bits are zero */
3095 /* now put temp bits back ito curOffset.LowPart */
3096 curOffset.LowPart &= ~(2048-1);
3097 curOffset.LowPart |= temp;
3099 /* check if we've returned all the names that will fit in the
3102 if (returnedNames >= maxCount) break;
3104 /* check if we've passed the dir's EOF */
3105 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3107 /* see if we can use the bufferp we have now; compute in which page
3108 * the current offset would be, and check whether that's the offset
3109 * of the buffer we have. If not, get the buffer.
3111 thyper.HighPart = curOffset.HighPart;
3112 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3113 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3116 buf_Release(bufferp);
3119 lock_ReleaseMutex(&scp->mx);
3120 lock_ObtainRead(&scp->bufCreateLock);
3121 code = buf_Get(scp, &thyper, &bufferp);
3122 lock_ReleaseRead(&scp->bufCreateLock);
3124 /* now, if we're doing a star match, do bulk fetching of all of
3125 * the status info for files in the dir.
3128 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3130 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3131 && LargeIntegerGreaterThanOrEqualTo(thyper,
3132 scp->bulkStatProgress)) {
3133 /* Don't bulk stat if risking timeout */
3134 int now = GetCurrentTime();
3135 if (now - req.startTime > 5000) {
3136 scp->bulkStatProgress = thyper;
3137 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3138 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3140 cm_TryBulkStat(scp, &thyper,
3145 lock_ObtainMutex(&scp->mx);
3147 bufferOffset = thyper;
3149 /* now get the data in the cache */
3151 code = cm_SyncOp(scp, bufferp, userp, &req,
3153 CM_SCACHESYNC_NEEDCALLBACK
3154 | CM_SCACHESYNC_READ);
3157 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3159 /* otherwise, load the buffer and try again */
3160 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3165 buf_Release(bufferp);
3169 } /* if (wrong buffer) ... */
3171 /* now we have the buffer containing the entry we're interested in; copy
3172 * it out if it represents a non-deleted entry.
3174 entryInDir = curOffset.LowPart & (2048-1);
3175 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3177 /* page header will help tell us which entries are free. Page header
3178 * can change more often than once per buffer, since AFS 3 dir page size
3179 * may be less than (but not more than a buffer package buffer.
3181 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3182 temp &= ~(2048 - 1); /* turn off intra-page bits */
3183 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3185 /* now determine which entry we're looking at in the page. If it is
3186 * free (there's a free bitmap at the start of the dir), we should
3187 * skip these 32 bytes.
3189 slotInPage = (entryInDir & 0x7e0) >> 5;
3190 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3191 /* this entry is free */
3192 numDirChunks = 1; /* only skip this guy */
3196 tp = bufferp->datap + entryInBuffer;
3197 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3199 /* while we're here, compute the next entry's location, too,
3200 * since we'll need it when writing out the cookie into the dir
3203 * XXXX Probably should do more sanity checking.
3205 numDirChunks = cm_NameEntries(dep->name, NULL);
3207 /* compute the offset of the cookie representing the next entry */
3208 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3210 /* Compute 8.3 name if necessary */
3211 actualName = dep->name;
3212 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3213 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3214 actualName = shortName;
3217 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3218 /* this is one of the entries to use: it is not deleted
3219 * and it matches the star pattern we're looking for.
3222 /* Eliminate entries that don't match requested
3225 /* no hidden files */
3226 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3229 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3231 /* We have already done the cm_TryBulkStat above */
3232 fid.cell = scp->fid.cell;
3233 fid.volume = scp->fid.volume;
3234 fid.vnode = ntohl(dep->fid.vnode);
3235 fid.unique = ntohl(dep->fid.unique);
3236 fileType = cm_FindFileType(&fid);
3237 osi_Log2(afsd_logp, "smb_ReceiveCoreSearchDir: file %s "
3238 "has filetype %d", dep->name,
3240 if (fileType == CM_SCACHETYPE_DIRECTORY)
3245 memcpy(op, mask, 11); op += 11;
3246 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3247 *op++ = nextEntryCookie & 0xff;
3248 *op++ = (nextEntryCookie>>8) & 0xff;
3249 *op++ = (nextEntryCookie>>16) & 0xff;
3250 *op++ = (nextEntryCookie>>24) & 0xff;
3251 memcpy(op, &clientCookie, 4); op += 4;
3253 /* now we emit the attribute. This is sort of tricky,
3254 * since we need to really stat the file to find out
3255 * what type of entry we've got. Right now, we're
3256 * copying out data from a buffer, while holding the
3257 * scp locked, so it isn't really convenient to stat
3258 * something now. We'll put in a place holder now,
3259 * and make a second pass before returning this to get
3260 * the real attributes. So, we just skip the data for
3261 * now, and adjust it later. We allocate a patch
3262 * record to make it easy to find this point later.
3263 * The replay will happen at a time when it is safe to
3264 * unlock the directory.
3266 curPatchp = malloc(sizeof(*curPatchp));
3267 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3268 curPatchp->dptr = op;
3269 curPatchp->fid.cell = scp->fid.cell;
3270 curPatchp->fid.volume = scp->fid.volume;
3271 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3272 curPatchp->fid.unique = ntohl(dep->fid.unique);
3274 /* do hidden attribute here since name won't be around when applying
3278 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3279 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3281 curPatchp->flags = 0;
3283 op += 9; /* skip attr, time, date and size */
3285 /* zero out name area. The spec says to pad with
3286 * spaces, but Samba doesn't, and neither do we.
3290 /* finally, we get to copy out the name; we know that
3291 * it fits in 8.3 or the pattern wouldn't match, but it
3292 * never hurts to be sure.
3294 strncpy(op, actualName, 13);
3296 /* Uppercase if requested by client */
3297 if ((((smb_t *)inp)->flg2 & 1) == 0)
3302 /* now, adjust the # of entries copied */
3304 } /* if we're including this name */
3307 /* and adjust curOffset to be where the new cookie is */
3308 thyper.HighPart = 0;
3309 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3310 curOffset = LargeIntegerAdd(thyper, curOffset);
3311 } /* while copying data for dir listing */
3313 /* release the mutex */
3314 lock_ReleaseMutex(&scp->mx);
3315 if (bufferp) buf_Release(bufferp);
3317 /* apply and free last set of patches; if not doing a star match, this
3318 * will be empty, but better safe (and freeing everything) than sorry.
3320 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3322 /* special return code for unsuccessful search */
3323 if (code == 0 && dataLength < 21 && returnedNames == 0)
3324 code = CM_ERROR_NOFILES;
3326 osi_Log2(afsd_logp, "SMB search dir done, %d names, code %d",
3327 returnedNames, code);
3330 smb_DeleteDirSearch(dsp);
3331 smb_ReleaseDirSearch(dsp);
3332 cm_ReleaseSCache(scp);
3333 cm_ReleaseUser(userp);
3337 /* finalize the output buffer */
3338 smb_SetSMBParm(outp, 0, returnedNames);
3339 temp = (long) (op - origOp);
3340 smb_SetSMBDataLength(outp, temp);
3342 /* the data area is a variable block, which has a 5 (already there)
3343 * followed by the length of the # of data bytes. We now know this to
3344 * be "temp," although that includes the 3 bytes of vbl block header.
3345 * Deduct for them and fill in the length field.
3347 temp -= 3; /* deduct vbl block info */
3348 osi_assert(temp == (43 * returnedNames));
3349 origOp[1] = temp & 0xff;
3350 origOp[2] = (temp>>8) & 0xff;
3351 if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3352 smb_ReleaseDirSearch(dsp);
3353 cm_ReleaseSCache(scp);
3354 cm_ReleaseUser(userp);
3358 /* verify that this is a valid path to a directory. I don't know why they
3359 * don't use the get file attributes call.
3361 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3365 cm_scache_t *rootScp;
3366 cm_scache_t *newScp;
3375 pathp = smb_GetSMBData(inp, NULL);
3376 pathp = smb_ParseASCIIBlock(pathp, NULL);
3377 osi_Log1(afsd_logp, "SMB receive check path %s",
3378 osi_LogSaveString(afsd_logp, pathp));
3381 return CM_ERROR_BADFD;
3384 rootScp = cm_rootSCachep;
3386 userp = smb_GetUser(vcp, inp);
3388 caseFold = CM_FLAG_CASEFOLD;
3390 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3391 code = cm_NameI(rootScp, pathp,
3392 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3393 userp, tidPathp, &req, &newScp);
3396 cm_ReleaseUser(userp);
3400 /* now lock the vnode with a callback; returns with newScp locked */
3401 lock_ObtainMutex(&newScp->mx);
3402 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3403 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3404 if (code && code != CM_ERROR_NOACCESS) {
3405 lock_ReleaseMutex(&newScp->mx);
3406 cm_ReleaseSCache(newScp);
3407 cm_ReleaseUser(userp);
3411 attrs = smb_Attributes(newScp);
3413 if (!(attrs & 0x10))
3414 code = CM_ERROR_NOTDIR;
3416 lock_ReleaseMutex(&newScp->mx);
3418 cm_ReleaseSCache(newScp);
3419 cm_ReleaseUser(userp);
3423 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3427 cm_scache_t *rootScp;
3428 unsigned short attribute;
3430 cm_scache_t *newScp;
3439 /* decode basic attributes we're passed */
3440 attribute = smb_GetSMBParm(inp, 0);
3441 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3443 pathp = smb_GetSMBData(inp, NULL);
3444 pathp = smb_ParseASCIIBlock(pathp, NULL);
3447 return CM_ERROR_BADSMB;
3450 osi_Log2(afsd_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3451 dosTime, attribute);
3453 rootScp = cm_rootSCachep;
3455 userp = smb_GetUser(vcp, inp);
3457 caseFold = CM_FLAG_CASEFOLD;
3459 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3460 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3461 tidPathp, &req, &newScp);
3464 cm_ReleaseUser(userp);
3468 /* now lock the vnode with a callback; returns with newScp locked; we
3469 * need the current status to determine what the new status is, in some
3472 lock_ObtainMutex(&newScp->mx);
3473 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3474 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3476 lock_ReleaseMutex(&newScp->mx);
3477 cm_ReleaseSCache(newScp);
3478 cm_ReleaseUser(userp);
3482 /* Check for RO volume */
3483 if (newScp->flags & CM_SCACHEFLAG_RO) {
3484 lock_ReleaseMutex(&newScp->mx);
3485 cm_ReleaseSCache(newScp);
3486 cm_ReleaseUser(userp);
3487 return CM_ERROR_READONLY;
3490 /* prepare for setattr call */
3493 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3494 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3496 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3497 /* we're told to make a writable file read-only */
3498 attr.unixModeBits = newScp->unixModeBits & ~0222;
3499 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3501 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3502 /* we're told to make a read-only file writable */
3503 attr.unixModeBits = newScp->unixModeBits | 0222;
3504 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3506 lock_ReleaseMutex(&newScp->mx);
3508 /* now call setattr */
3510 code = cm_SetAttr(newScp, &attr, userp, &req);
3514 cm_ReleaseSCache(newScp);
3515 cm_ReleaseUser(userp);
3520 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3524 cm_scache_t *rootScp;
3525 cm_scache_t *newScp, *dscp;
3537 pathp = smb_GetSMBData(inp, NULL);
3538 pathp = smb_ParseASCIIBlock(pathp, NULL);
3541 return CM_ERROR_BADSMB;
3544 if (*pathp == 0) /* null path */
3547 osi_Log1(afsd_logp, "SMB receive getfile attributes path %s",
3548 osi_LogSaveString(afsd_logp, pathp));
3550 rootScp = cm_rootSCachep;
3552 userp = smb_GetUser(vcp, inp);
3554 /* we shouldn't need this for V3 requests, but we seem to */
3555 caseFold = CM_FLAG_CASEFOLD;
3557 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3560 * XXX Strange hack XXX
3562 * As of Patch 5 (16 July 97), we are having the following problem:
3563 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3564 * requests to look up "desktop.ini" in all the subdirectories.
3565 * This can cause zillions of timeouts looking up non-existent cells
3566 * and volumes, especially in the top-level directory.
3568 * We have not found any way to avoid this or work around it except
3569 * to explicitly ignore the requests for mount points that haven't
3570 * yet been evaluated and for directories that haven't yet been
3573 spacep = inp->spacep;
3574 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3575 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3576 code = cm_NameI(rootScp, spacep->data,
3577 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3578 userp, tidPathp, &req, &dscp);
3580 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3581 && !dscp->mountRootFidp)
3582 code = CM_ERROR_NOSUCHFILE;
3583 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3584 cm_buf_t *bp = buf_Find(dscp, &hzero);
3588 code = CM_ERROR_NOSUCHFILE;
3590 cm_ReleaseSCache(dscp);
3592 cm_ReleaseUser(userp);
3598 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3599 tidPathp, &req, &newScp);
3602 cm_ReleaseUser(userp);
3606 /* now lock the vnode with a callback; returns with newScp locked */
3607 lock_ObtainMutex(&newScp->mx);
3608 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3609 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3611 lock_ReleaseMutex(&newScp->mx);
3612 cm_ReleaseSCache(newScp);
3613 cm_ReleaseUser(userp);
3618 /* use smb_Attributes instead. Also the fact that a file is in a readonly volume
3619 doesn't mean it shojuld be marked as RO */
3621 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
3622 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
3623 attrs = SMB_ATTR_DIRECTORY;
3626 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
3627 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
3629 attrs = smb_Attributes(newScp);
3632 smb_SetSMBParm(outp, 0, attrs);
3634 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
3635 smb_SetSMBParm(outp, 1, dosTime & 0xffff);
3636 smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
3637 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
3638 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
3639 smb_SetSMBParm(outp, 5, 0);
3640 smb_SetSMBParm(outp, 6, 0);
3641 smb_SetSMBParm(outp, 7, 0);
3642 smb_SetSMBParm(outp, 8, 0);
3643 smb_SetSMBParm(outp, 9, 0);
3644 smb_SetSMBDataLength(outp, 0);
3645 lock_ReleaseMutex(&newScp->mx);
3647 cm_ReleaseSCache(newScp);
3648 cm_ReleaseUser(userp);
3653 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3657 osi_Log0(afsd_logp, "SMB receive tree disconnect");
3659 /* find the tree and free it */
3660 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
3662 lock_ObtainMutex(&tidp->mx);
3663 tidp->flags |= SMB_TIDFLAG_DELETE;
3664 lock_ReleaseMutex(&tidp->mx);
3665 smb_ReleaseTID(tidp);
3671 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3689 pathp = smb_GetSMBData(inp, NULL);
3690 pathp = smb_ParseASCIIBlock(pathp, NULL);
3692 osi_Log1(afsd_logp, "SMB receive open file [%s]", osi_LogSaveString(afsd_logp, pathp));
3694 #ifdef DEBUG_VERBOSE
3698 hexpath = osi_HexifyString( pathp );
3699 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
3704 share = smb_GetSMBParm(inp, 0);
3705 attribute = smb_GetSMBParm(inp, 1);
3707 spacep = inp->spacep;
3708 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3709 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3710 /* special case magic file name for receiving IOCTL requests
3711 * (since IOCTL calls themselves aren't getting through).
3713 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3714 smb_SetupIoctlFid(fidp, spacep);
3715 smb_SetSMBParm(outp, 0, fidp->fid);
3716 smb_SetSMBParm(outp, 1, 0); /* attrs */
3717 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
3718 smb_SetSMBParm(outp, 3, 0);
3719 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
3720 smb_SetSMBParm(outp, 5, 0x7fff);
3721 /* pass the open mode back */
3722 smb_SetSMBParm(outp, 6, (share & 0xf));
3723 smb_SetSMBDataLength(outp, 0);
3724 smb_ReleaseFID(fidp);
3728 userp = smb_GetUser(vcp, inp);
3730 caseFold = CM_FLAG_CASEFOLD;
3732 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3733 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3734 tidPathp, &req, &scp);
3737 cm_ReleaseUser(userp);
3741 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
3743 cm_ReleaseSCache(scp);
3744 cm_ReleaseUser(userp);
3748 /* don't need callback to check file type, since file types never
3749 * change, and namei and cm_Lookup all stat the object at least once on
3750 * a successful return.
3752 if (scp->fileType != CM_SCACHETYPE_FILE) {
3753 cm_ReleaseSCache(scp);
3754 cm_ReleaseUser(userp);
3755 return CM_ERROR_ISDIR;
3758 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3761 /* save a pointer to the vnode */
3764 if ((share & 0xf) == 0)
3765 fidp->flags |= SMB_FID_OPENREAD;
3766 else if ((share & 0xf) == 1)
3767 fidp->flags |= SMB_FID_OPENWRITE;
3769 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
3771 lock_ObtainMutex(&scp->mx);
3772 smb_SetSMBParm(outp, 0, fidp->fid);
3773 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
3774 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
3775 smb_SetSMBParm(outp, 2, dosTime & 0xffff);
3776 smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
3777 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
3778 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
3779 /* pass the open mode back; XXXX add access checks */
3780 smb_SetSMBParm(outp, 6, (share & 0xf));
3781 smb_SetSMBDataLength(outp, 0);
3782 lock_ReleaseMutex(&scp->mx);
3785 cm_Open(scp, 0, userp);
3787 /* send and free packet */
3788 smb_ReleaseFID(fidp);
3789 cm_ReleaseUser(userp);
3790 /* don't release scp, since we've squirreled away the pointer in the fid struct */
3794 typedef struct smb_unlinkRock {
3799 char *maskp; /* pointer to the star pattern */
3804 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3807 smb_unlinkRock_t *rockp;
3815 if (rockp->vcp->flags & SMB_VCFLAG_USEV3)
3816 caseFold = CM_FLAG_CASEFOLD;
3818 caseFold = CM_FLAG_CASEFOLD | CM_FLAG_8DOT3;
3820 matchName = dep->name;
3821 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3824 && !cm_Is8Dot3(dep->name)) {
3825 cm_Gen8Dot3Name(dep, shortName, NULL);
3826 matchName = shortName;
3827 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3830 osi_Log1(smb_logp, "Unlinking %s",
3831 osi_LogSaveString(smb_logp, matchName));
3832 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
3833 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3834 smb_NotifyChange(FILE_ACTION_REMOVED,
3835 FILE_NOTIFY_CHANGE_FILE_NAME,
3836 dscp, dep->name, NULL, TRUE);
3845 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3854 smb_unlinkRock_t rock;
3863 attribute = smb_GetSMBParm(inp, 0);
3865 tp = smb_GetSMBData(inp, NULL);
3866 pathp = smb_ParseASCIIBlock(tp, &tp);
3868 osi_Log1(smb_logp, "SMB receive unlink %s",
3869 osi_LogSaveString(smb_logp, pathp));
3871 spacep = inp->spacep;
3872 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3874 userp = smb_GetUser(vcp, inp);
3876 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3878 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3879 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
3883 cm_ReleaseUser(userp);
3887 /* otherwise, scp points to the parent directory.
3889 if (!lastNamep) lastNamep = pathp;
3893 rock.maskp = smb_FindMask(pathp);
3894 rock.hasTilde = ((strchr(rock.maskp, '~') != NULL) ? 1 : 0);
3897 thyper.HighPart = 0;
3902 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
3904 cm_ReleaseUser(userp);
3906 cm_ReleaseSCache(dscp);
3908 if (code == 0 && !rock.any)
3909 code = CM_ERROR_NOSUCHFILE;
3913 typedef struct smb_renameRock {
3914 cm_scache_t *odscp; /* old dir */
3915 cm_scache_t *ndscp; /* new dir */
3916 cm_user_t *userp; /* user */
3917 cm_req_t *reqp; /* request struct */
3918 smb_vc_t *vcp; /* virtual circuit */
3919 char *maskp; /* pointer to star pattern of old file name */
3920 int hasTilde; /* star pattern might be shortname? */
3921 char *newNamep; /* ptr to the new file's name */
3924 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3927 smb_renameRock_t *rockp;
3934 if (rockp->vcp->flags & SMB_VCFLAG_USEV3)
3935 caseFold = CM_FLAG_CASEFOLD;
3937 caseFold = CM_FLAG_CASEFOLD | CM_FLAG_8DOT3;
3939 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
3942 && !cm_Is8Dot3(dep->name)) {
3943 cm_Gen8Dot3Name(dep, shortName, NULL);
3944 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
3947 code = cm_Rename(rockp->odscp, dep->name,
3948 rockp->ndscp, rockp->newNamep, rockp->userp,
3950 /* if the call worked, stop doing the search now, since we
3951 * really only want to rename one file.
3953 if (code == 0) code = CM_ERROR_STOPNOW;
3960 long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3967 smb_renameRock_t rock;
3968 cm_scache_t *oldDscp;
3969 cm_scache_t *newDscp;
3970 cm_scache_t *tmpscp;
3982 tp = smb_GetSMBData(inp, NULL);
3983 oldPathp = smb_ParseASCIIBlock(tp, &tp);
3984 newPathp = smb_ParseASCIIBlock(tp, &tp);
3986 osi_Log2(afsd_logp, "smb rename %s to %s",
3987 osi_LogSaveString(afsd_logp, oldPathp),
3988 osi_LogSaveString(afsd_logp, newPathp));
3990 spacep = inp->spacep;
3991 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
3993 userp = smb_GetUser(vcp, inp);
3996 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
3997 * what actually exists is foo/baz. I don't know why the code used to be
3998 * the way it was. 1/29/96
4000 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4002 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4004 * caseFold = CM_FLAG_CASEFOLD;
4006 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4008 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4009 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4010 userp, tidPathp, &req, &oldDscp);
4013 cm_ReleaseUser(userp);
4017 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4018 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4019 userp, tidPathp, &req, &newDscp);
4022 cm_ReleaseSCache(oldDscp);
4023 cm_ReleaseUser(userp);
4027 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4028 * next, get the component names, and lower case them.
4031 /* handle the old name first */
4032 if (!oldLastNamep) oldLastNamep = oldPathp;
4033 else oldLastNamep++;
4035 /* and handle the new name, too */
4036 if (!newLastNamep) newLastNamep = newPathp;
4037 else newLastNamep++;
4039 /* do the vnode call */
4040 rock.odscp = oldDscp;
4041 rock.ndscp = newDscp;
4045 rock.maskp = oldLastNamep;
4046 rock.hasTilde = ((strchr(oldLastNamep, '~') != NULL) ? 1 : 0);
4047 rock.newNamep = newLastNamep;
4049 /* Check if the file already exists; if so return error */
4050 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4051 if((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4052 cm_ReleaseSCache(tmpscp);
4053 return CM_ERROR_EXISTS; /* file exist, do not rename, also
4057 /* Now search the directory for the pattern, and do the appropriate rename when found */
4058 thyper.LowPart = 0; /* search dir from here */
4059 thyper.HighPart = 0;
4061 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4063 if (code == CM_ERROR_STOPNOW)
4066 code = CM_ERROR_NOSUCHFILE;
4068 /* Handle Change Notification */
4070 * Being lazy, not distinguishing between files and dirs in this
4071 * filter, since we'd have to do a lookup.
4073 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4074 if (oldDscp == newDscp) {
4075 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4076 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4077 filter, oldDscp, oldLastNamep,
4078 newLastNamep, TRUE);
4080 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4081 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4082 filter, oldDscp, oldLastNamep,
4084 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4085 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4086 filter, newDscp, newLastNamep,
4090 cm_ReleaseUser(userp);
4092 cm_ReleaseSCache(oldDscp);
4093 cm_ReleaseSCache(newDscp);
4098 typedef struct smb_rmdirRock {
4102 char *maskp; /* pointer to the star pattern */
4107 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4110 smb_rmdirRock_t *rockp;
4117 matchName = dep->name;
4118 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4121 && !cm_Is8Dot3(dep->name)) {
4122 cm_Gen8Dot3Name(dep, shortName, NULL);
4123 matchName = shortName;
4124 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4127 osi_Log1(smb_logp, "Removing directory %s",
4128 osi_LogSaveString(smb_logp, matchName));
4129 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4130 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4131 smb_NotifyChange(FILE_ACTION_REMOVED,
4132 FILE_NOTIFY_CHANGE_DIR_NAME,
4133 dscp, dep->name, NULL, TRUE);
4142 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4150 smb_rmdirRock_t rock;
4159 tp = smb_GetSMBData(inp, NULL);
4160 pathp = smb_ParseASCIIBlock(tp, &tp);
4162 spacep = inp->spacep;
4163 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4165 userp = smb_GetUser(vcp, inp);
4167 caseFold = CM_FLAG_CASEFOLD;
4169 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4170 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4171 userp, tidPathp, &req, &dscp);
4174 cm_ReleaseUser(userp);
4178 /* otherwise, scp points to the parent directory. */
4179 if (!lastNamep) lastNamep = pathp;
4183 rock.maskp = lastNamep;
4184 rock.hasTilde = ((strchr(rock.maskp, '~') != NULL) ? 1 : 0);
4187 thyper.HighPart = 0;
4191 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4193 cm_ReleaseUser(userp);
4195 cm_ReleaseSCache(dscp);
4197 if (code == 0 && !rock.any)
4198 code = CM_ERROR_NOSUCHFILE;
4202 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4212 fid = smb_GetSMBParm(inp, 0);
4214 osi_Log1(afsd_logp, "SMB flush fid %d", fid);
4216 fid = smb_ChainFID(fid, inp);
4217 fidp = smb_FindFID(vcp, fid, 0);
4218 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4220 smb_ReleaseFID(fidp);
4221 return CM_ERROR_BADFD;
4224 userp = smb_GetUser(vcp, inp);
4226 lock_ObtainMutex(&fidp->mx);
4227 if (fidp->flags & SMB_FID_OPENWRITE)
4228 code = cm_FSync(fidp->scp, userp, &req);
4230 lock_ReleaseMutex(&fidp->mx);
4232 smb_ReleaseFID(fidp);
4234 cm_ReleaseUser(userp);
4239 struct smb_FullNameRock {
4245 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4249 struct smb_FullNameRock *vrockp;
4253 if (!cm_Is8Dot3(dep->name)) {
4254 cm_Gen8Dot3Name(dep, shortName, NULL);
4256 if (strcmp(shortName, vrockp->name) == 0) {
4257 vrockp->fullName = strdup(dep->name);
4258 return CM_ERROR_STOPNOW;
4261 if (stricmp(dep->name, vrockp->name) == 0
4262 && ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode
4263 && ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4264 vrockp->fullName = strdup(dep->name);
4265 return CM_ERROR_STOPNOW;
4270 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4271 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4273 struct smb_FullNameRock rock;
4279 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL,
4281 if (code == CM_ERROR_STOPNOW)
4282 *newPathp = rock.fullName;
4284 *newPathp = strdup(pathp);
4287 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4298 fid = smb_GetSMBParm(inp, 0);
4299 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4301 osi_Log1(afsd_logp, "SMB close fid %d", fid);
4303 fid = smb_ChainFID(fid, inp);
4304 fidp = smb_FindFID(vcp, fid, 0);
4306 return CM_ERROR_BADFD;
4309 userp = smb_GetUser(vcp, inp);
4311 lock_ObtainMutex(&fidp->mx);
4313 /* Don't jump the gun on an async raw write */
4314 while (fidp->raw_writers) {
4315 lock_ReleaseMutex(&fidp->mx);
4316 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4317 lock_ObtainMutex(&fidp->mx);
4320 fidp->flags |= SMB_FID_DELETE;
4322 /* watch for ioctl closes, and read-only opens */
4323 if (fidp->scp != NULL
4324 && (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4325 == SMB_FID_OPENWRITE) {
4326 if (dosTime != 0 && dosTime != -1) {
4327 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4328 /* This fixes defect 10958 */
4329 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
4330 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
4332 code = cm_FSync(fidp->scp, userp, &req);
4337 if (fidp->flags & SMB_FID_DELONCLOSE) {
4338 cm_scache_t *dscp = fidp->NTopen_dscp;
4339 char *pathp = fidp->NTopen_pathp;
4342 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
4343 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
4344 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
4345 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4346 smb_NotifyChange(FILE_ACTION_REMOVED,
4347 FILE_NOTIFY_CHANGE_DIR_NAME,
4348 dscp, fullPathp, NULL, TRUE);
4352 code = cm_Unlink(dscp, fullPathp, userp, &req);
4353 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4354 smb_NotifyChange(FILE_ACTION_REMOVED,
4355 FILE_NOTIFY_CHANGE_FILE_NAME,
4356 dscp, fullPathp, NULL, TRUE);
4360 lock_ReleaseMutex(&fidp->mx);
4362 if (fidp->flags & SMB_FID_NTOPEN) {
4363 cm_ReleaseSCache(fidp->NTopen_dscp);
4364 free(fidp->NTopen_pathp);
4366 if (fidp->NTopen_wholepathp)
4367 free(fidp->NTopen_wholepathp);
4369 smb_ReleaseFID(fidp);
4370 cm_ReleaseUser(userp);
4375 * smb_ReadData -- common code for Read, Read And X, and Raw Read
4378 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4379 cm_user_t *userp, long *readp)
4381 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4382 cm_user_t *userp, long *readp, int dosflag)
4389 osi_hyper_t fileLength;
4391 osi_hyper_t lastByte;
4392 osi_hyper_t bufferOffset;
4393 long bufIndex, nbytes;
4403 lock_ObtainMutex(&fidp->mx);
4405 lock_ObtainMutex(&scp->mx);
4407 if (offset.HighPart == 0) {
4408 chunk = offset.LowPart >> cm_logChunkSize;
4409 if (chunk != fidp->curr_chunk) {
4410 fidp->prev_chunk = fidp->curr_chunk;
4411 fidp->curr_chunk = chunk;
4413 if (fidp->curr_chunk == fidp->prev_chunk + 1)
4417 /* start by looking up the file's end */
4418 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4419 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4420 if (code) goto done;
4422 /* now we have the entry locked, look up the length */
4423 fileLength = scp->length;
4425 /* adjust count down so that it won't go past EOF */
4426 thyper.LowPart = count;
4427 thyper.HighPart = 0;
4428 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
4430 if (LargeIntegerGreaterThan(thyper, fileLength)) {
4431 /* we'd read past EOF, so just stop at fileLength bytes.
4432 * Start by computing how many bytes remain in the file.
4434 thyper = LargeIntegerSubtract(fileLength, offset);
4436 /* if we are past EOF, read 0 bytes */
4437 if (LargeIntegerLessThanZero(thyper))
4440 count = thyper.LowPart;
4445 /* now, copy the data one buffer at a time,
4446 * until we've filled the request packet
4449 /* if we've copied all the data requested, we're done */
4450 if (count <= 0) break;
4452 /* otherwise, load up a buffer of data */
4453 thyper.HighPart = offset.HighPart;
4454 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4455 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4458 buf_Release(bufferp);
4461 lock_ReleaseMutex(&scp->mx);
4463 lock_ObtainRead(&scp->bufCreateLock);
4464 code = buf_Get(scp, &thyper, &bufferp);
4465 lock_ReleaseRead(&scp->bufCreateLock);
4467 lock_ObtainMutex(&scp->mx);
4468 if (code) goto done;
4469 bufferOffset = thyper;
4471 /* now get the data in the cache */
4473 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4474 CM_SCACHESYNC_NEEDCALLBACK
4475 | CM_SCACHESYNC_READ);
4476 if (code) goto done;
4478 if (cm_HaveBuffer(scp, bufferp, 0)) break;
4480 /* otherwise, load the buffer and try again */
4481 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4485 buf_Release(bufferp);
4489 } /* if (wrong buffer) ... */
4491 /* now we have the right buffer loaded. Copy out the
4492 * data from here to the user's buffer.
4494 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4496 /* and figure out how many bytes we want from this buffer */
4497 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
4498 if (nbytes > count) nbytes = count; /* don't go past EOF */
4500 /* now copy the data */
4503 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
4506 memcpy(op, bufferp->datap + bufIndex, nbytes);
4508 /* adjust counters, pointers, etc. */
4511 thyper.LowPart = nbytes;
4512 thyper.HighPart = 0;
4513 offset = LargeIntegerAdd(thyper, offset);
4517 lock_ReleaseMutex(&scp->mx);
4518 lock_ReleaseMutex(&fidp->mx);
4519 if (bufferp) buf_Release(bufferp);
4521 if (code == 0 && sequential)
4522 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
4528 * smb_WriteData -- common code for Write and Raw Write
4531 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4532 cm_user_t *userp, long *writtenp)
4534 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4535 cm_user_t *userp, long *writtenp, int dosflag)
4542 osi_hyper_t fileLength; /* file's length at start of write */
4543 osi_hyper_t minLength; /* don't read past this */
4544 long nbytes; /* # of bytes to transfer this iteration */
4546 osi_hyper_t thyper; /* hyper tmp variable */
4547 osi_hyper_t bufferOffset;
4548 long bufIndex; /* index in buffer where our data is */
4550 osi_hyper_t writeBackOffset; /* offset of region to write back when
4561 lock_ObtainMutex(&fidp->mx);
4563 lock_ObtainMutex(&scp->mx);
4565 /* start by looking up the file's end */
4566 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4567 CM_SCACHESYNC_NEEDCALLBACK
4568 | CM_SCACHESYNC_SETSTATUS
4569 | CM_SCACHESYNC_GETSTATUS);
4570 if (code) goto done;
4572 /* make sure we have a writable FD */
4573 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
4574 code = CM_ERROR_BADFDOP;
4578 /* now we have the entry locked, look up the length */
4579 fileLength = scp->length;
4580 minLength = fileLength;
4581 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
4582 minLength = scp->serverLength;
4584 /* adjust file length if we extend past EOF */
4585 thyper.LowPart = count;
4586 thyper.HighPart = 0;
4587 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
4588 if (LargeIntegerGreaterThan(thyper, fileLength)) {
4589 /* we'd write past EOF, so extend the file */
4590 scp->mask |= CM_SCACHEMASK_LENGTH;
4591 scp->length = thyper;
4593 (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
4595 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
4597 /* now, if the new position (thyper) and the old (offset) are in
4598 * different storeback windows, remember to store back the previous
4599 * storeback window when we're done with the write.
4601 if ((thyper.LowPart & (-cm_chunkSize)) !=
4602 (offset.LowPart & (-cm_chunkSize))) {
4603 /* they're different */
4605 writeBackOffset.HighPart = offset.HighPart;
4606 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
4611 /* now, copy the data one buffer at a time, until we've filled the
4614 /* if we've copied all the data requested, we're done */
4615 if (count <= 0) break;
4617 /* handle over quota or out of space */
4618 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA
4619 | CM_SCACHEFLAG_OUTOFSPACE)) {
4620 *writtenp = written;
4624 /* otherwise, load up a buffer of data */
4625 thyper.HighPart = offset.HighPart;
4626 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4627 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4630 lock_ReleaseMutex(&bufferp->mx);
4631 buf_Release(bufferp);
4634 lock_ReleaseMutex(&scp->mx);
4636 lock_ObtainRead(&scp->bufCreateLock);
4637 code = buf_Get(scp, &thyper, &bufferp);
4638 lock_ReleaseRead(&scp->bufCreateLock);
4640 lock_ObtainMutex(&bufferp->mx);
4641 lock_ObtainMutex(&scp->mx);
4642 if (code) goto done;
4644 bufferOffset = thyper;
4646 /* now get the data in the cache */
4648 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4649 CM_SCACHESYNC_NEEDCALLBACK
4650 | CM_SCACHESYNC_WRITE
4651 | CM_SCACHESYNC_BUFLOCKED);
4652 if (code) goto done;
4654 /* If we're overwriting the entire buffer, or
4655 * if we're writing at or past EOF, mark the
4656 * buffer as current so we don't call
4657 * cm_GetBuffer. This skips the fetch from the
4658 * server in those cases where we're going to
4659 * obliterate all the data in the buffer anyway,
4660 * or in those cases where there is no useful
4661 * data at the server to start with.
4663 * Use minLength instead of scp->length, since
4664 * the latter has already been updated by this
4667 if (LargeIntegerGreaterThanOrEqualTo(
4668 bufferp->offset, minLength)
4669 || LargeIntegerEqualTo(offset, bufferp->offset)
4670 && (count >= buf_bufferSize
4671 || LargeIntegerGreaterThanOrEqualTo(
4672 LargeIntegerAdd(offset,
4673 ConvertLongToLargeInteger(count)),
4675 if (count < buf_bufferSize
4676 && bufferp->dataVersion == -1)
4677 memset(bufferp->datap, 0,
4679 bufferp->dataVersion = scp->dataVersion;
4682 if (cm_HaveBuffer(scp, bufferp, 1)) break;
4684 /* otherwise, load the buffer and try again */
4685 lock_ReleaseMutex(&bufferp->mx);
4686 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4688 lock_ReleaseMutex(&scp->mx);
4689 lock_ObtainMutex(&bufferp->mx);
4690 lock_ObtainMutex(&scp->mx);
4694 lock_ReleaseMutex(&bufferp->mx);
4695 buf_Release(bufferp);
4699 } /* if (wrong buffer) ... */
4701 /* now we have the right buffer loaded. Copy out the
4702 * data from here to the user's buffer.
4704 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4706 /* and figure out how many bytes we want from this buffer */
4707 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
4708 if (nbytes > count) nbytes = count; /* don't go past end of request */
4710 /* now copy the data */
4713 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
4716 memcpy(bufferp->datap + bufIndex, op, nbytes);
4717 buf_SetDirty(bufferp);
4719 /* and record the last writer */
4720 if (bufferp->userp != userp) {
4721 if (bufferp->userp) cm_ReleaseUser(bufferp->userp);
4722 bufferp->userp = userp;
4726 /* adjust counters, pointers, etc. */
4730 thyper.LowPart = nbytes;
4731 thyper.HighPart = 0;
4732 offset = LargeIntegerAdd(thyper, offset);
4736 lock_ReleaseMutex(&scp->mx);
4737 lock_ReleaseMutex(&fidp->mx);
4739 lock_ReleaseMutex(&bufferp->mx);
4740 buf_Release(bufferp);
4743 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
4744 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
4745 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
4746 fidp->NTopen_dscp, fidp->NTopen_pathp,
4750 if (code == 0 && doWriteBack) {
4751 lock_ObtainMutex(&scp->mx);
4752 cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
4753 lock_ReleaseMutex(&scp->mx);
4754 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
4755 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
4761 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4764 long count, written = 0;
4769 cm_attr_t truncAttr; /* attribute struct used for truncating file */
4771 int inDataBlockCount;
4773 fd = smb_GetSMBParm(inp, 0);
4774 count = smb_GetSMBParm(inp, 1);
4775 offset.HighPart = 0; /* too bad */
4776 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
4778 op = smb_GetSMBData(inp, NULL);
4779 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
4781 osi_Log3(afsd_logp, "smb_ReceiveCoreWrite fd %d, off 0x%x, size 0x%x",
4782 fd, offset.LowPart, count);
4784 fd = smb_ChainFID(fd, inp);
4785 fidp = smb_FindFID(vcp, fd, 0);
4787 return CM_ERROR_BADFD;
4790 if (fidp->flags & SMB_FID_IOCTL)
4791 return smb_IoctlWrite(fidp, vcp, inp, outp);
4793 userp = smb_GetUser(vcp, inp);
4795 /* special case: 0 bytes transferred means truncate to this position */
4801 truncAttr.mask = CM_ATTRMASK_LENGTH;
4802 truncAttr.length.LowPart = offset.LowPart;
4803 truncAttr.length.HighPart = 0;
4804 lock_ObtainMutex(&fidp->mx);
4805 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
4806 lock_ReleaseMutex(&fidp->mx);
4807 smb_SetSMBParm(outp, 0, /* count */ 0);
4808 smb_SetSMBDataLength(outp, 0);
4809 fidp->flags |= SMB_FID_LENGTHSETDONE;
4814 * Work around bug in NT client
4816 * When copying a file, the NT client should first copy the data,
4817 * then copy the last write time. But sometimes the NT client does
4818 * these in the wrong order, so the data copies would inadvertently
4819 * cause the last write time to be overwritten. We try to detect this,
4820 * and don't set client mod time if we think that would go against the
4823 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
4824 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4825 fidp->scp->clientModTime = time(NULL);
4829 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
4831 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
4833 if (code == 0 && written < count)
4834 code = CM_ERROR_PARTIALWRITE;
4836 /* set the packet data length to 3 bytes for the data block header,
4837 * plus the size of the data.
4839 smb_SetSMBParm(outp, 0, written);
4840 smb_SetSMBDataLength(outp, 0);
4843 smb_ReleaseFID(fidp);
4844 cm_ReleaseUser(userp);
4849 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
4850 NCB *ncbp, raw_write_cont_t *rwcp)
4863 fd = smb_GetSMBParm(inp, 0);
4864 fidp = smb_FindFID(vcp, fd, 0);
4866 osi_Log2(afsd_logp, "Completing Raw Write offset %x count %x",
4867 rwcp->offset.LowPart, rwcp->count);
4869 userp = smb_GetUser(vcp, inp);
4873 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
4876 rawBuf = (dos_ptr) rwcp->buf;
4877 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
4878 (unsigned char *) rawBuf, userp,
4882 if (rwcp->writeMode & 0x1) { /* synchronous */
4885 smb_FormatResponsePacket(vcp, inp, outp);
4886 op = (smb_t *) outp;
4887 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
4888 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
4889 smb_SetSMBDataLength(outp, 0);
4890 smb_SendPacket(vcp, outp);
4891 smb_FreePacket(outp);
4893 else { /* asynchronous */
4894 lock_ObtainMutex(&fidp->mx);
4895 fidp->raw_writers--;
4896 if (fidp->raw_writers == 0)
4897 thrd_SetEvent(fidp->raw_write_event);
4898 lock_ReleaseMutex(&fidp->mx);
4901 /* Give back raw buffer */
4902 lock_ObtainMutex(&smb_RawBufLock);
4904 *((char **)rawBuf) = smb_RawBufs;
4906 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
4908 smb_RawBufs = rawBuf;
4909 lock_ReleaseMutex(&smb_RawBufLock);
4911 smb_ReleaseFID(fidp);
4912 cm_ReleaseUser(userp);
4915 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4920 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
4923 long count, written = 0;
4930 unsigned short writeMode;
4937 fd = smb_GetSMBParm(inp, 0);
4938 totalCount = smb_GetSMBParm(inp, 1);
4939 count = smb_GetSMBParm(inp, 10);
4940 offset.HighPart = 0; /* too bad */
4941 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4942 writeMode = smb_GetSMBParm(inp, 7);
4944 op = (char *) inp->data;
4945 op += smb_GetSMBParm(inp, 11);
4948 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
4949 fd, offset.LowPart, count, writeMode);
4951 fd = smb_ChainFID(fd, inp);
4952 fidp = smb_FindFID(vcp, fd, 0);
4954 return CM_ERROR_BADFD;
4957 userp = smb_GetUser(vcp, inp);
4960 * Work around bug in NT client
4962 * When copying a file, the NT client should first copy the data,
4963 * then copy the last write time. But sometimes the NT client does
4964 * these in the wrong order, so the data copies would inadvertently
4965 * cause the last write time to be overwritten. We try to detect this,
4966 * and don't set client mod time if we think that would go against the
4969 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
4970 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4971 fidp->scp->clientModTime = time(NULL);
4975 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
4977 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
4979 if (code == 0 && written < count)
4980 code = CM_ERROR_PARTIALWRITE;
4982 /* Get a raw buffer */
4985 lock_ObtainMutex(&smb_RawBufLock);
4987 /* Get a raw buf, from head of list */
4988 rawBuf = smb_RawBufs;
4990 smb_RawBufs = *(char **)smb_RawBufs;
4992 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
4996 code = CM_ERROR_USESTD;
4998 lock_ReleaseMutex(&smb_RawBufLock);
5001 /* Don't allow a premature Close */
5002 if (code == 0 && (writeMode & 1) == 0) {
5003 lock_ObtainMutex(&fidp->mx);
5004 fidp->raw_writers++;
5005 thrd_ResetEvent(fidp->raw_write_event);
5006 lock_ReleaseMutex(&fidp->mx);
5009 smb_ReleaseFID(fidp);
5010 cm_ReleaseUser(userp);
5013 smb_SetSMBParm(outp, 0, written);
5014 smb_SetSMBDataLength(outp, 0);
5015 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5022 rwcp->offset.HighPart = 0;
5023 rwcp->offset.LowPart = offset.LowPart + count;
5024 rwcp->count = totalCount - count;
5025 rwcp->writeMode = writeMode;
5026 rwcp->alreadyWritten = written;
5028 /* set the packet data length to 3 bytes for the data block header,
5029 * plus the size of the data.
5031 smb_SetSMBParm(outp, 0, 0xffff);
5032 smb_SetSMBDataLength(outp, 0);
5037 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5040 long count, finalCount;
5047 fd = smb_GetSMBParm(inp, 0);
5048 count = smb_GetSMBParm(inp, 1);
5049 offset.HighPart = 0; /* too bad */
5050 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5052 osi_Log3(afsd_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5053 fd, offset.LowPart, count);
5055 fd = smb_ChainFID(fd, inp);
5056 fidp = smb_FindFID(vcp, fd, 0);
5058 return CM_ERROR_BADFD;
5061 if (fidp->flags & SMB_FID_IOCTL) {
5062 return smb_IoctlRead(fidp, vcp, inp, outp);
5065 userp = smb_GetUser(vcp, inp);
5067 /* remember this for final results */
5068 smb_SetSMBParm(outp, 0, count);
5069 smb_SetSMBParm(outp, 1, 0);
5070 smb_SetSMBParm(outp, 2, 0);
5071 smb_SetSMBParm(outp, 3, 0);
5072 smb_SetSMBParm(outp, 4, 0);
5074 /* set the packet data length to 3 bytes for the data block header,
5075 * plus the size of the data.
5077 smb_SetSMBDataLength(outp, count+3);
5079 /* get op ptr after putting in the parms, since otherwise we don't
5080 * know where the data really is.
5082 op = smb_GetSMBData(outp, NULL);
5084 /* now emit the data block header: 1 byte of type and 2 bytes of length */
5085 *op++ = 1; /* data block marker */
5086 *op++ = (unsigned char) (count & 0xff);
5087 *op++ = (unsigned char) ((count >> 8) & 0xff);
5090 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5092 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5095 /* fix some things up */
5096 smb_SetSMBParm(outp, 0, finalCount);
5097 smb_SetSMBDataLength(outp, finalCount+3);
5099 smb_ReleaseFID(fidp);
5101 cm_ReleaseUser(userp);
5105 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5112 cm_scache_t *dscp; /* dir we're dealing with */
5113 cm_scache_t *scp; /* file we're creating */
5115 int initialModeBits;
5125 /* compute initial mode bits based on read-only flag in attributes */
5126 initialModeBits = 0777;
5128 tp = smb_GetSMBData(inp, NULL);
5129 pathp = smb_ParseASCIIBlock(tp, &tp);
5131 if (strcmp(pathp, "\\") == 0)
5132 return CM_ERROR_EXISTS;
5134 spacep = inp->spacep;
5135 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5137 userp = smb_GetUser(vcp, inp);
5139 caseFold = CM_FLAG_CASEFOLD;
5141 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5143 code = cm_NameI(cm_rootSCachep, spacep->data,
5144 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5145 userp, tidPathp, &req, &dscp);
5148 cm_ReleaseUser(userp);
5152 /* otherwise, scp points to the parent directory. Do a lookup, and
5153 * fail if we find it. Otherwise, we do the create.
5155 if (!lastNamep) lastNamep = pathp;
5157 code = cm_Lookup(dscp, lastNamep, caseFold, userp, &req, &scp);
5158 if (scp) cm_ReleaseSCache(scp);
5159 if (code != CM_ERROR_NOSUCHFILE) {
5160 if (code == 0) code = CM_ERROR_EXISTS;
5161 cm_ReleaseSCache(dscp);
5162 cm_ReleaseUser(userp);
5166 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5167 setAttr.clientModTime = time(NULL);
5168 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5169 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5170 smb_NotifyChange(FILE_ACTION_ADDED,
5171 FILE_NOTIFY_CHANGE_DIR_NAME,
5172 dscp, lastNamep, NULL, TRUE);
5174 /* we don't need this any longer */
5175 cm_ReleaseSCache(dscp);
5178 /* something went wrong creating or truncating the file */
5179 cm_ReleaseUser(userp);
5183 /* otherwise we succeeded */
5184 smb_SetSMBDataLength(outp, 0);
5185 cm_ReleaseUser(userp);
5190 BOOL smb_IsLegalFilename(char *filename)
5193 * Find the longest substring of filename that does not contain
5194 * any of the chars in illegalChars. If that substring is less
5195 * than the length of the whole string, then one or more of the
5196 * illegal chars is in filename.
5198 if (strcspn(filename, illegalChars) < strlen(filename))
5204 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5212 cm_scache_t *dscp; /* dir we're dealing with */
5213 cm_scache_t *scp; /* file we're creating */
5215 int initialModeBits;
5227 excl = (inp->inCom == 0x03)? 0 : 1;
5229 attributes = smb_GetSMBParm(inp, 0);
5230 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5232 /* compute initial mode bits based on read-only flag in attributes */
5233 initialModeBits = 0666;
5234 if (attributes & 1) initialModeBits &= ~0222;
5236 tp = smb_GetSMBData(inp, NULL);
5237 pathp = smb_ParseASCIIBlock(tp, &tp);
5239 spacep = inp->spacep;
5240 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5242 userp = smb_GetUser(vcp, inp);
5244 caseFold = CM_FLAG_CASEFOLD;
5246 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5247 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5248 userp, tidPathp, &req, &dscp);
5251 cm_ReleaseUser(userp);
5255 /* otherwise, scp points to the parent directory. Do a lookup, and
5256 * truncate the file if we find it, otherwise we create the file.
5258 if (!lastNamep) lastNamep = pathp;
5261 if (!smb_IsLegalFilename(lastNamep))
5262 return CM_ERROR_BADNTFILENAME;
5264 osi_Log1(afsd_logp, "SMB receive create [%s]", osi_LogSaveString( afsd_logp, pathp ));
5265 #ifdef DEBUG_VERBOSE
5268 hexp = osi_HexifyString( lastNamep );
5269 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5274 code = cm_Lookup(dscp, lastNamep, caseFold, userp, &req, &scp);
5275 if (code && code != CM_ERROR_NOSUCHFILE) {
5276 cm_ReleaseSCache(dscp);
5277 cm_ReleaseUser(userp);
5281 /* if we get here, if code is 0, the file exists and is represented by
5282 * scp. Otherwise, we have to create it.
5286 /* oops, file shouldn't be there */
5287 cm_ReleaseSCache(dscp);
5288 cm_ReleaseSCache(scp);
5289 cm_ReleaseUser(userp);
5290 return CM_ERROR_EXISTS;
5293 setAttr.mask = CM_ATTRMASK_LENGTH;
5294 setAttr.length.LowPart = 0;
5295 setAttr.length.HighPart = 0;
5296 code = cm_SetAttr(scp, &setAttr, userp, &req);
5299 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5300 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5301 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5303 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5304 smb_NotifyChange(FILE_ACTION_ADDED,
5305 FILE_NOTIFY_CHANGE_FILE_NAME,
5306 dscp, lastNamep, NULL, TRUE);
5307 if (!excl && code == CM_ERROR_EXISTS) {
5308 /* not an exclusive create, and someone else tried
5309 * creating it already, then we open it anyway. We
5310 * don't bother retrying after this, since if this next
5311 * fails, that means that the file was deleted after
5312 * we started this call.
5314 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
5317 setAttr.mask = CM_ATTRMASK_LENGTH;
5318 setAttr.length.LowPart = 0;
5319 setAttr.length.HighPart = 0;
5320 code = cm_SetAttr(scp, &setAttr, userp, &req);
5325 /* we don't need this any longer */
5326 cm_ReleaseSCache(dscp);
5329 /* something went wrong creating or truncating the file */
5330 if (scp) cm_ReleaseSCache(scp);
5331 cm_ReleaseUser(userp);
5335 /* make sure we only open files */
5336 if (scp->fileType != CM_SCACHETYPE_FILE) {
5337 cm_ReleaseSCache(scp);
5338 cm_ReleaseUser(userp);
5339 return CM_ERROR_ISDIR;
5342 /* now all we have to do is open the file itself */
5343 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5346 /* save a pointer to the vnode */
5349 /* always create it open for read/write */
5350 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
5352 smb_ReleaseFID(fidp);
5354 smb_SetSMBParm(outp, 0, fidp->fid);
5355 smb_SetSMBDataLength(outp, 0);
5357 cm_Open(scp, 0, userp);
5359 cm_ReleaseUser(userp);
5360 /* leave scp held since we put it in fidp->scp */
5364 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5377 fd = smb_GetSMBParm(inp, 0);
5378 whence = smb_GetSMBParm(inp, 1);
5379 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5381 /* try to find the file descriptor */
5382 fd = smb_ChainFID(fd, inp);
5383 fidp = smb_FindFID(vcp, fd, 0);
5384 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5385 return CM_ERROR_BADFD;
5388 userp = smb_GetUser(vcp, inp);
5390 lock_ObtainMutex(&fidp->mx);
5392 lock_ObtainMutex(&scp->mx);
5393 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5394 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5397 /* offset from current offset */
5398 offset += fidp->offset;
5400 else if (whence == 2) {
5401 /* offset from current EOF */
5402 offset += scp->length.LowPart;
5404 fidp->offset = offset;
5405 smb_SetSMBParm(outp, 0, offset & 0xffff);
5406 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
5407 smb_SetSMBDataLength(outp, 0);
5409 lock_ReleaseMutex(&scp->mx);
5410 lock_ReleaseMutex(&fidp->mx);
5411 smb_ReleaseFID(fidp);
5412 cm_ReleaseUser(userp);
5416 /* dispatch all of the requests received in a packet. Due to chaining, this may
5417 * be more than one request.
5419 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5420 NCB *ncbp, raw_write_cont_t *rwcp)
5422 static showErrors = 0;
5426 unsigned char *outWctp;
5427 int nparms; /* # of bytes of parameters */
5429 int nbytes; /* bytes of data, excluding count */
5432 unsigned short errCode;
5433 unsigned long NTStatus;
5435 unsigned char errClass;
5436 unsigned int oldGen;
5437 DWORD oldTime, newTime;
5439 /* get easy pointer to the data */
5440 smbp = (smb_t *) inp->data;
5442 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
5443 /* setup the basic parms for the initial request in the packet */
5444 inp->inCom = smbp->com;
5445 inp->wctp = &smbp->wct;
5447 inp->ncb_length = ncbp->ncb_length;
5452 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
5453 /* log it and discard it */
5458 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5459 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
5461 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
5462 1, ncbp->ncb_length, ptbuf, inp);
5463 DeregisterEventSource(h);
5465 osi_Log1(smb_logp, "SMB message too short, len %d",
5472 /* We are an ongoing op */
5473 thrd_Increment(&ongoingOps);
5475 /* set up response packet for receiving output */
5476 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
5477 smb_FormatResponsePacket(vcp, inp, outp);
5478 outWctp = outp->wctp;
5480 /* Remember session generation number and time */
5481 oldGen = sessionGen;
5482 oldTime = GetCurrentTime();
5484 while(inp->inCom != 0xff) {
5485 dp = &smb_dispatchTable[inp->inCom];
5487 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
5488 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
5489 code = outp->resumeCode;
5493 /* process each request in the packet; inCom, wctp and inCount
5494 * are already set up.
5496 osi_Log2(afsd_logp, "SMB received op 0x%x lsn %d", inp->inCom,
5499 /* now do the dispatch */
5500 /* start by formatting the response record a little, as a default */
5501 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
5503 outWctp[1] = 0xff; /* no operation */
5504 outWctp[2] = 0; /* padding */
5509 /* not a chained request, this is a more reasonable default */
5510 outWctp[0] = 0; /* wct of zero */
5511 outWctp[1] = 0; /* and bcc (word) of zero */
5515 /* once set, stays set. Doesn't matter, since we never chain
5516 * "no response" calls.
5518 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
5522 /* we have a recognized operation */
5524 if (inp->inCom == 0x1d)
5526 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
5529 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
5530 osi_Log4(afsd_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
5531 code = (*(dp->procp)) (vcp, inp, outp);
5532 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5533 osi_Log1(afsd_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5536 if (oldGen != sessionGen) {
5541 newTime = GetCurrentTime();
5542 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5543 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
5544 newTime - oldTime, ncbp->ncb_length);
5546 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
5547 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
5548 DeregisterEventSource(h);
5550 osi_Log1(afsd_logp, "Pkt straddled session startup, "
5551 "ncb length %d", ncbp->ncb_length);
5556 /* bad opcode, fail the request, after displaying it */
5559 #endif /* NOTSERVICE */
5563 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
5564 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
5566 if (code == IDCANCEL) showErrors = 0;
5569 code = CM_ERROR_BADOP;
5572 /* catastrophic failure: log as much as possible */
5573 if (code == CM_ERROR_BADSMB) {
5580 "Invalid SMB, ncb_length %d",
5583 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5584 sprintf(s, "Invalid SMB message, length %d",
5587 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
5588 1, ncbp->ncb_length, ptbuf, smbp);
5589 DeregisterEventSource(h);
5592 #endif /* NOTSERVICE */
5594 osi_Log1(afsd_logp, "Invalid SMB message, length %d",
5598 code = CM_ERROR_INVAL;
5601 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
5602 thrd_Decrement(&ongoingOps);
5607 /* now, if we failed, turn the current response into an empty
5608 * one, and fill in the response packet's error code.
5611 if (vcp->flags & SMB_VCFLAG_STATUS32) {
5612 smb_MapNTError(code, &NTStatus);
5613 outWctp = outp->wctp;
5614 smbp = (smb_t *) &outp->data;
5615 if (code != CM_ERROR_PARTIALWRITE
5616 && code != CM_ERROR_BUFFERTOOSMALL) {
5617 /* nuke wct and bcc. For a partial
5618 * write, assume they're OK.
5624 smbp->rcls = (unsigned char) (NTStatus & 0xff);
5625 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
5626 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
5627 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
5628 smbp->flg2 |= 0x4000;
5632 smb_MapCoreError(code, vcp, &errCode, &errClass);
5633 outWctp = outp->wctp;
5634 smbp = (smb_t *) &outp->data;
5635 if (code != CM_ERROR_PARTIALWRITE) {
5636 /* nuke wct and bcc. For a partial
5637 * write, assume they're OK.
5643 smbp->errLow = (unsigned char) (errCode & 0xff);
5644 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
5645 smbp->rcls = errClass;
5648 } /* error occurred */
5650 /* if we're here, we've finished one request. Look to see if
5651 * this is a chained opcode. If it is, setup things to process
5652 * the chained request, and setup the output buffer to hold the
5653 * chained response. Start by finding the next input record.
5655 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
5656 break; /* not a chained req */
5657 tp = inp->wctp; /* points to start of last request */
5658 if (tp[0] < 2) break; /* in a chained request, the first two
5659 * parm fields are required, and are
5660 * AndXCommand/AndXReserved and
5662 if (tp[1] == 0xff) break; /* no more chained opcodes */
5664 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
5667 /* and now append the next output request to the end of this
5668 * last request. Begin by finding out where the last response
5669 * ends, since that's where we'll put our new response.
5671 outWctp = outp->wctp; /* ptr to out parameters */
5672 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
5673 nparms = outWctp[0] << 1;
5674 tp = outWctp + nparms + 1; /* now points to bcc field */
5675 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
5676 tp += 2 /* for the count itself */ + nbytes;
5677 /* tp now points to the new output record; go back and patch the
5678 * second parameter (off2) to point to the new record.
5680 temp = (unsigned int)tp - ((unsigned int) outp->data);
5681 outWctp[3] = (unsigned char) (temp & 0xff);
5682 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
5683 outWctp[2] = 0; /* padding */
5684 outWctp[1] = inp->inCom; /* next opcode */
5686 /* finally, setup for the next iteration */
5689 } /* while loop over all requests in the packet */
5691 /* done logging out, turn off logging-out flag */
5692 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
5693 vcp->justLoggedOut = NULL;
5696 free(loggedOutName);
5697 loggedOutName = NULL;
5698 smb_ReleaseUID(loggedOutUserp);
5699 loggedOutUserp = NULL;
5703 /* now send the output packet, and return */
5705 smb_SendPacket(vcp, outp);
5706 thrd_Decrement(&ongoingOps);
5708 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
5710 last_msg_time = GetCurrentTime();
5712 else if (active_vcp == vcp)
5719 /* Wait for Netbios() calls to return, and make the results available to server
5720 * threads. Note that server threads can't wait on the NCBevents array
5721 * themselves, because NCB events are manual-reset, and the servers would race
5722 * each other to reset them.
5724 void smb_ClientWaiter(void *parmp)
5730 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
5732 if (code == WAIT_OBJECT_0)
5735 /* error checking */
5736 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
5738 int abandonIdx = code - WAIT_ABANDONED_0;
5739 afsi_log("Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
5742 if (code == WAIT_IO_COMPLETION)
5744 afsi_log("Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
5748 if (code == WAIT_TIMEOUT)
5750 afsi_log("Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
5753 if (code == WAIT_FAILED)
5755 afsi_log("Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
5758 idx = code - WAIT_OBJECT_0;
5760 /* check idx range! */
5761 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
5763 /* this is fatal - log as much as possible */
5764 afsi_log("Fatal: NCBevents idx [ %d ] out of range.\n", idx);
5768 thrd_ResetEvent(NCBevents[idx]);
5769 thrd_SetEvent(NCBreturns[0][idx]);
5775 * Try to have one NCBRECV request waiting for every live session. Not more
5776 * than one, because if there is more than one, it's hard to handle Write Raw.
5778 void smb_ServerWaiter(void *parmp)
5781 int idx_session, idx_NCB;
5789 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
5791 if (code == WAIT_OBJECT_0)
5794 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
5796 int abandonIdx = code - WAIT_ABANDONED_0;
5797 afsi_log("Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
5800 if (code == WAIT_IO_COMPLETION)
5802 afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
5806 if (code == WAIT_TIMEOUT)
5808 afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
5811 if (code == WAIT_FAILED)
5813 afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
5816 idx_session = code - WAIT_OBJECT_0;
5818 /* check idx range! */
5819 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
5821 /* this is fatal - log as much as possible */
5822 afsi_log("Fatal: session idx [ %d ] out of range.\n", idx_session);
5828 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
5830 if (code == WAIT_OBJECT_0)
5833 /* error checking */
5834 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
5836 int abandonIdx = code - WAIT_ABANDONED_0;
5837 afsi_log("Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
5840 if (code == WAIT_IO_COMPLETION)
5842 afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
5846 if (code == WAIT_TIMEOUT)
5848 afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
5851 if (code == WAIT_FAILED)
5853 afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
5856 idx_NCB = code - WAIT_OBJECT_0;
5858 /* check idx range! */
5859 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
5861 /* this is fatal - log as much as possible */
5862 afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
5866 /* Link them together */
5867 NCBsessions[idx_NCB] = idx_session;
5870 ncbp = NCBs[idx_NCB];
5872 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
5874 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
5875 ncbp->ncb_command = NCBRECV | ASYNCH;
5876 ncbp->ncb_lana_num = lanas[idx_session];
5878 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
5879 ncbp->ncb_event = NCBevents[idx_NCB];
5880 ncbp->ncb_length = SMB_PACKETSIZE;
5883 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
5884 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
5885 ncbp->ncb_event = NCBreturns[0][idx_NCB];
5886 ncbp->ncb_length = SMB_PACKETSIZE;
5887 Netbios(ncbp, dos_ncb);
5893 * The top level loop for handling SMB request messages. Each server thread
5894 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
5895 * NCB and buffer for the incoming request are loaned to us.
5897 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
5898 * to immediately send a request for the rest of the data. This must come
5899 * before any other traffic for that session, so we delay setting the session
5900 * event until that data has come in.
5902 void smb_Server(VOID *parmp)
5904 int myIdx = (int) parmp;
5908 smb_packet_t *outbufp;
5910 int idx_NCB, idx_session;
5919 outbufp = GetPacket();
5920 outbufp->ncbp = outncbp;
5924 /* check for demo expiration */
5926 unsigned long tod = time((void *) 0);
5927 if (tod > EXPIREDATE) {
5928 (*smb_MBfunc)(NULL, "AFS demo expiration",
5930 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
5934 #endif /* !NOEXPIRE */
5936 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
5938 if (code == WAIT_OBJECT_0) {
5942 /* error checking */
5943 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
5945 int abandonIdx = code - WAIT_ABANDONED_0;
5946 afsi_log("Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
5949 if (code == WAIT_IO_COMPLETION)
5951 afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
5955 if (code == WAIT_TIMEOUT)
5957 afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
5960 if (code == WAIT_FAILED)
5962 afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
5965 idx_NCB = code - WAIT_OBJECT_0;
5967 /* check idx range! */
5968 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
5970 /* this is fatal - log as much as possible */
5971 afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
5975 ncbp = NCBs[idx_NCB];
5977 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
5979 idx_session = NCBsessions[idx_NCB];
5980 rc = ncbp->ncb_retcode;
5982 if (rc != NRC_PENDING && rc != NRC_GOODRET)
5983 osi_Log1(afsd_logp, "NCBRECV failure code %d", rc);
5986 case NRC_GOODRET: break;
5989 /* Can this happen? Or is it just my
5996 /* Client closed session */
5997 if (reportSessionStartups)
5999 afsi_log("session [ %d ] closed", idx_session);
6001 dead_sessions[idx_session] = TRUE;
6002 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6003 /* Should also release vcp. Also, would do
6004 * sanity check that all TID's are gone.
6006 * TODO: check if we could use LSNs[idx_session] instead,
6007 * also cleanup after dead vcp
6012 "dead_vcp already set, %x",
6014 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6016 "setting dead_vcp %x, user struct %x",
6019 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6021 if (vcp->justLoggedOut) {
6023 loggedOutTime = vcp->logoffTime;
6025 strdup(vcp->justLoggedOut->unp->name);
6026 loggedOutUserp = vcp->justLoggedOut;
6027 lock_ObtainWrite(&smb_rctLock);
6028 loggedOutUserp->refCount++;
6029 lock_ReleaseWrite(&smb_rctLock);
6035 /* Treat as transient error */
6043 "dispatch smb recv failed, message incomplete, ncb_length %d",
6045 h = RegisterEventSource(NULL,
6046 AFS_DAEMON_EVENT_NAME);
6047 sprintf(s, "SMB message incomplete, length %d",
6050 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6052 ncbp->ncb_length, ptbuf,
6054 DeregisterEventSource(h);
6057 "dispatch smb recv failed, message incomplete, ncb_length %d",
6060 "SMB message incomplete, "
6061 "length %d", ncbp->ncb_length);
6065 * We used to discard the packet.
6066 * Instead, try handling it normally.
6074 /* A weird error code. Log it, sleep, and
6076 if (vcp->errorCount++ > 3) {
6077 afsi_log("session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6078 dead_sessions[idx_session] = TRUE;
6082 thrd_SetEvent(SessionEvents[idx_session]);
6087 /* Success, so now dispatch on all the data in the packet */
6089 smb_concurrentCalls++;
6090 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6091 smb_maxObsConcurrentCalls = smb_concurrentCalls;
6093 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6095 * If at this point vcp is NULL (implies that packet was invalid)
6096 * then we are in big trouble. This means either :
6097 * a) we have the wrong NCB.
6098 * b) Netbios screwed up the call.
6099 * Obviously this implies that
6100 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
6101 * lanas[idx_session] != ncbp->ncb_lana_num )
6102 * Either way, we can't do anything with this packet.
6103 * Log, sleep and resume.
6112 "LSNs[idx_session]=[%d],"
6113 "lanas[idx_session]=[%d],"
6114 "ncbp->ncb_lsn=[%d],"
6115 "ncbp->ncb_lana_num=[%d]",
6119 ncbp->ncb_lana_num);
6123 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6125 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6126 DeregisterEventSource(h);
6129 /* Also log in the trace log. */
6130 osi_Log4(afsd_logp, "Server: BAD VCP!"
6131 "LSNs[idx_session]=[%d],"
6132 "lanas[idx_session]=[%d],"
6133 "ncbp->ncb_lsn=[%d],"
6134 "ncbp->ncb_lana_num=[%d]",
6138 ncbp->ncb_lana_num);
6140 /* thrd_Sleep(1000); Don't bother sleeping */
6141 thrd_SetEvent(SessionEvents[idx_session]);
6142 smb_concurrentCalls--;
6147 vcp->errorCount = 0;
6148 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6150 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6151 /* copy whole packet to virtual memory */
6152 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6154 bufp->dos_pkt / 16, bufp);*/
6156 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6158 smbp = (smb_t *)bufp->data;
6161 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6165 if (smbp->com == 0x1d) {
6166 /* Special handling for Write Raw */
6167 raw_write_cont_t rwc;
6168 EVENT_HANDLE rwevent;
6169 char eventName[MAX_PATH];
6171 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6172 if (rwc.code == 0) {
6173 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6174 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6175 afsi_log("Event Object Already Exists: %s", eventName);
6176 ncbp->ncb_command = NCBRECV | ASYNCH;
6177 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6178 ncbp->ncb_lana_num = vcp->lana;
6179 ncbp->ncb_buffer = rwc.buf;
6180 ncbp->ncb_length = 65535;
6181 ncbp->ncb_event = rwevent;
6185 Netbios(ncbp, dos_ncb);
6187 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6188 thrd_CloseHandle(rwevent);
6190 thrd_SetEvent(SessionEvents[idx_session]);
6192 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6193 } else if (smbp->com == 0xa0) {
6195 * Serialize the handling for NT Transact
6198 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6199 thrd_SetEvent(SessionEvents[idx_session]);
6201 thrd_SetEvent(SessionEvents[idx_session]);
6202 /* TODO: what else needs to be serialized? */
6203 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6205 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6207 __except( smb_ServerExceptionFilter() ) {
6211 smb_concurrentCalls--;
6214 thrd_SetEvent(NCBavails[idx_NCB]);
6219 * Exception filter for the server threads. If an exception occurs in the
6220 * dispatch routines, which is where exceptions are most common, then do a
6221 * force trace and give control to upstream exception handlers. Useful for
6224 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6225 DWORD smb_ServerExceptionFilter(void) {
6226 /* While this is not the best time to do a trace, if it succeeds, then
6227 * we have a trace (assuming tracing was enabled). Otherwise, this should
6228 * throw a second exception.
6233 ptbuf[0] = "Unhandled exception forcing trace";
6235 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6237 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6238 DeregisterEventSource(h);
6241 afsd_ForceTrace(TRUE);
6242 return EXCEPTION_CONTINUE_SEARCH;
6247 * Create a new NCB and associated events, packet buffer, and "space" buffer.
6248 * If the number of server threads is M, and the number of live sessions is
6249 * N, then the number of NCB's in use at any time either waiting for, or
6250 * holding, received messages is M + N, so that is how many NCB's get created.
6252 void InitNCBslot(int idx)
6254 struct smb_packet *bufp;
6255 EVENT_HANDLE retHandle;
6257 char eventName[MAX_PATH];
6259 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
6261 NCBs[idx] = GetNCB();
6262 sprintf(eventName,"NCBavails[%d]", idx);
6263 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6264 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6265 afsi_log("Event Object Already Exists: %s", eventName);
6267 sprintf(eventName,"NCBevents[%d]", idx);
6268 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
6269 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6270 afsi_log("Event Object Already Exists: %s", eventName);
6272 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
6273 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6274 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6275 afsi_log("Event Object Already Exists: %s", eventName);
6276 for (i=0; i<smb_NumServerThreads; i++)
6277 NCBreturns[i][idx] = retHandle;
6279 bufp->spacep = cm_GetSpace();
6283 /* listen for new connections */
6284 void smb_Listener(void *parmp)
6292 char rname[NCBNAMSZ+1];
6293 char cname[MAX_COMPUTERNAME_LENGTH+1];
6294 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
6299 int lana = (int) parmp;
6303 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6306 /* retrieve computer name */
6307 GetComputerName(cname, &cnamelen);
6311 memset(ncbp, 0, sizeof(NCB));
6314 /* terminate if shutdown flag is set */
6315 if (smbShutdownFlag == 1)
6320 /* check for demo expiration */
6322 unsigned long tod = time((void *) 0);
6323 if (tod > EXPIREDATE) {
6324 (*smb_MBfunc)(NULL, "AFS demo expiration",
6326 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
6330 #endif /* !NOEXPIRE */
6332 ncbp->ncb_command = NCBLISTEN;
6333 ncbp->ncb_rto = 0; /* No receive timeout */
6334 ncbp->ncb_sto = 0; /* No send timeout */
6336 /* pad out with spaces instead of null termination */
6337 len = strlen(smb_localNamep);
6338 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
6339 for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
6341 strcpy(ncbp->ncb_callname, "*");
6342 for(i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
6344 ncbp->ncb_lana_num = lana;
6347 code = Netbios(ncbp);
6349 code = Netbios(ncbp, dos_ncb);
6353 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
6354 ncbp->ncb_lana_num, code);
6355 osi_Log2(0, "NCBLISTEN lana=%d failed with code %d",
6356 ncbp->ncb_lana_num, code);
6357 fprintf(stderr, "\nClient exiting due to network failure "
6358 "(possibly due to power-saving mode)\n");
6359 fprintf(stderr, "Please restart client.\n");
6360 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
6364 osi_assert(code == 0);
6366 /* check for remote conns */
6367 /* first get remote name and insert null terminator */
6368 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
6369 for (i=NCBNAMSZ; i>0; i--) {
6370 if (rname[i-1] != ' ' && rname[i-1] != 0) {
6376 /* compare with local name */
6378 if (strncmp(rname, cname, NCBNAMSZ) != 0)
6379 flags |= SMB_VCFLAG_REMOTECONN;
6381 osi_Log1(afsd_logp, "New session lsn %d", ncbp->ncb_lsn);
6383 lock_ObtainMutex(&smb_ListenerLock);
6385 /* New generation */
6388 /* Log session startup */
6390 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
6392 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
6394 afsi_log("New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
6395 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname, ongoingOps);
6397 if (reportSessionStartups) {
6403 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6404 sprintf(s, "SMB session startup, %d ongoing ops",
6407 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
6409 DeregisterEventSource(h);
6411 afsi_log("NCBLISTEN completed, call from %s",rname);
6412 osi_Log1(afsd_logp, "SMB session startup, %d ongoing ops",
6415 fprintf(stderr, "%s: New session %d starting from host "
6417 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
6422 /* now ncbp->ncb_lsn is the connection ID */
6423 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
6424 vcp->flags |= flags;
6425 strcpy(vcp->rname, rname);
6427 /* Allocate slot in session arrays */
6428 /* Re-use dead session if possible, otherwise add one more */
6429 /* But don't look at session[0], it is reserved */
6430 for (i = 1; i < numSessions; i++) {
6431 if (dead_sessions[i]) {
6432 afsi_log("connecting to dead session [ %d ]", i);
6433 dead_sessions[i] = FALSE;
6438 /* assert that we do not exceed the maximum number of sessions or NCBs.
6439 * we should probably want to wait for a session to be freed in case
6443 osi_assert(i < Sessionmax && numNCBs < NCBmax - 1);
6445 LSNs[i] = ncbp->ncb_lsn;
6446 lanas[i] = ncbp->ncb_lana_num;
6448 if (i == numSessions) {
6449 /* Add new NCB for new session */
6450 char eventName[MAX_PATH];
6452 osi_Log1(afsd_logp, "smb_Listener creating new session %d", i);
6454 InitNCBslot(numNCBs);
6456 thrd_SetEvent(NCBavails[0]);
6457 thrd_SetEvent(NCBevents[0]);
6458 for (j = 0; j < smb_NumServerThreads; j++)
6459 thrd_SetEvent(NCBreturns[j][0]);
6460 /* Also add new session event */
6461 sprintf(eventName, "SessionEvents[%d]", i);
6462 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6463 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6464 afsi_log("Event Object Already Exists: %s", eventName);
6466 afsi_log("increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
6467 thrd_SetEvent(SessionEvents[0]);
6469 thrd_SetEvent(SessionEvents[i]);
6472 lock_ReleaseMutex(&smb_ListenerLock);
6474 } /* dispatch while loop */
6477 /* initialize Netbios */
6478 void smb_NetbiosInit()
6484 int i, lana, code, l;
6486 int delname_tried=0;
6489 OSVERSIONINFO Version;
6491 /*******************************************************************/
6492 /* ms loopback adapter scan */
6493 /*******************************************************************/
6496 ADAPTER_STATUS status;
6497 NAME_BUFFER NameBuff [30];
6503 /* AFAIK, this is the default for the ms loopback adapter.*/
6504 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
6505 /*******************************************************************/
6507 /* Get the version of Windows */
6508 memset(&Version, 0x00, sizeof(Version));
6509 Version.dwOSVersionInfoSize = sizeof(Version);
6510 GetVersionEx(&Version);
6512 /* setup the NCB system */
6515 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6519 if (smb_LANadapter == -1) {
6520 ncbp->ncb_command = NCBENUM;
6521 ncbp->ncb_buffer = (PUCHAR)&lana_list;
6522 ncbp->ncb_length = sizeof(lana_list);
6523 code = Netbios(ncbp);
6525 sprintf(s, "Netbios NCBENUM error code %d", code);
6527 osi_panic(s, __FILE__, __LINE__);
6531 lana_list.length = 1;
6532 lana_list.lana[0] = smb_LANadapter;
6535 for (i = 0; i < lana_list.length; i++) {
6536 /* reset the adaptor: in Win32, this is required for every process, and
6537 * acts as an init call, not as a real hardware reset.
6539 ncbp->ncb_command = NCBRESET;
6540 ncbp->ncb_callname[0] = 100;
6541 ncbp->ncb_callname[2] = 100;
6542 ncbp->ncb_lana_num = lana_list.lana[i];
6543 code = Netbios(ncbp);
6545 code = ncbp->ncb_retcode;
6547 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
6549 lana_list.lana[i] = 255; /* invalid lana */
6551 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
6555 /* This code searches for the loopback adapter but
6556 * we already did this during afsd_init
6558 memset( ncbp, 0, sizeof (*ncbp) );
6559 ncbp->ncb_command = NCBASTAT;
6560 ncbp->ncb_lana_num = lana_list.lana[i];
6561 strcpy( ncbp->ncb_callname, "* " );
6562 ncbp->ncb_buffer = (char *) &Adapter;
6563 ncbp->ncb_length = sizeof(Adapter);
6564 code = Netbios( ncbp );
6568 for (j=0; wla_found && (j<6); j++)
6569 wla_found = ( Adapter.status.adapter_address[j] == kWLA_MAC[j] );
6573 * check to see if this is the Microsoft Loopback Adapter"
6574 * if we are running on Windows XP or higher
6575 * or if we only have the loopback adapter because it was
6576 * selected during afsd_init
6578 if ( Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
6579 ( lana_list.length == 1 ||
6580 ( Version.dwMajorVersion > 5 ||
6581 Version.dwMajorVersion == 5 &&
6582 Version.dwMinorVersion >= 1 )
6586 sprintf(s, "Windows Loopback Adapter detected lana %d", lana_list.lana[i]);
6589 /* select this lana; no need to continue */
6590 lana_list.length = 1;
6591 lana_list.lana[0] = lana_list.lana[i];
6594 sprintf(s, "Windows Loopback Adapter disabled lana %d", lana_list.lana[i]);
6596 lana_list.lana[i] = 255; /* invalid lana */
6600 #endif /* COMMENT */
6604 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
6605 we will just fake the LANA list */
6606 if (smb_LANadapter == -1) {
6607 for (i = 0; i < 8; i++)
6608 lana_list.lana[i] = i;
6609 lana_list.length = 8;
6612 lana_list.length = 1;
6613 lana_list.lana[0] = smb_LANadapter;
6617 /* and declare our name so we can receive connections */
6618 memset(ncbp, 0, sizeof(*ncbp));
6619 len=lstrlen(smb_localNamep);
6620 memset(smb_sharename,' ',NCBNAMSZ);
6621 memcpy(smb_sharename,smb_localNamep,len);
6623 /*ncbp->ncb_lana_num = smb_LANadapter;*/
6624 strcpy(ncbp->ncb_name, smb_localNamep);
6625 len = strlen(smb_localNamep);
6626 for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
6628 sprintf(s, "lana_list.length %d", lana_list.length);
6631 /* Keep the name so we can unregister it later */
6632 for (l = 0; l < lana_list.length; l++) {
6633 lana = lana_list.lana[l];
6635 ncbp->ncb_command = NCBADDNAME;
6636 ncbp->ncb_lana_num = lana;
6637 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
6639 code = Netbios(ncbp);
6641 code = Netbios(ncbp, dos_ncb);
6644 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
6645 lana, code, ncbp->ncb_retcode,ncbp->ncb_cmd_cplt);
6647 char name[NCBNAMSZ+1];
6649 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
6650 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
6653 if (code == 0) code = ncbp->ncb_retcode;
6655 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
6657 /* we only use one LANA with djgpp */
6658 lana_list.lana[0] = lana;
6659 lana_list.length = 1;
6663 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
6665 if (code == NRC_BRIDGE) { /* invalid LANA num */
6666 lana_list.lana[l] = 255;
6669 else if (code == NRC_DUPNAME) {
6670 afsi_log("Name already exists; try to delete it");
6671 memset(ncbp, 0, sizeof(*ncbp));
6672 ncbp->ncb_command = NCBDELNAME;
6673 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
6674 ncbp->ncb_lana_num = lana;
6676 code = Netbios(ncbp);
6678 code = Netbios(ncbp, dos_ncb);
6680 if (code == 0) code = ncbp->ncb_retcode;
6682 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
6685 if (code != 0 || delname_tried) {
6686 lana_list.lana[l] = 255;
6688 else if (code == 0) {
6689 if (!delname_tried) {
6697 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
6699 lana_list.lana[l] = 255; /* invalid lana */
6700 osi_panic(s, __FILE__, __LINE__);
6704 lana_found = 1; /* at least one worked */
6711 osi_assert(lana_list.length >= 0);
6713 sprintf(s, "No valid LANA numbers found!");
6714 osi_panic(s, __FILE__, __LINE__);
6717 /* we're done with the NCB now */
6721 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
6738 EVENT_HANDLE retHandle;
6739 char eventName[MAX_PATH];
6742 smb_MBfunc = aMBfunc;
6746 /* check for demo expiration */
6748 unsigned long tod = time((void *) 0);
6749 if (tod > EXPIREDATE) {
6751 (*smb_MBfunc)(NULL, "AFS demo expiration",
6753 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
6756 fprintf(stderr, "AFS demo expiration\n");
6761 #endif /* !NOEXPIRE */
6764 smb_LANadapter = LANadapt;
6766 /* Initialize smb_localZero */
6767 myTime.tm_isdst = -1; /* compute whether on DST or not */
6768 myTime.tm_year = 70;
6774 smb_localZero = mktime(&myTime);
6776 /* Initialize kludge-GMT */
6777 smb_CalculateNowTZ();
6779 /* initialize the remote debugging log */
6782 /* remember the name */
6783 len = strlen(snamep);
6784 smb_localNamep = malloc(len+1);
6785 strcpy(smb_localNamep, snamep);
6786 afsi_log("smb_localNamep is >%s<", smb_localNamep);
6788 /* and the global lock */
6789 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
6790 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
6792 /* Raw I/O data structures */
6793 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
6795 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
6797 /* 4 Raw I/O buffers */
6799 smb_RawBufs = calloc(65536,1);
6800 *((char **)smb_RawBufs) = NULL;
6801 for (i=0; i<3; i++) {
6802 char *rawBuf = calloc(65536,1);
6803 *((char **)rawBuf) = smb_RawBufs;
6804 smb_RawBufs = rawBuf;
6807 npar = 65536 >> 4; /* number of paragraphs */
6808 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
6810 afsi_log("Cannot allocate %d paragraphs of DOS memory",
6812 osi_panic("",__FILE__,__LINE__);
6815 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
6818 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
6820 _farpokel(_dos_ds, smb_RawBufs, NULL);
6821 for (i=0; i<SMB_RAW_BUFS-1; i++) {
6822 npar = 65536 >> 4; /* number of paragraphs */
6823 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
6825 afsi_log("Cannot allocate %d paragraphs of DOS memory",
6827 osi_panic("",__FILE__,__LINE__);
6830 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
6833 rawBuf = (seg * 16) + 0; /* DOS physical address */
6834 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
6835 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6836 smb_RawBufs = rawBuf;
6840 /* global free lists */
6841 smb_ncbFreeListp = NULL;
6842 smb_packetFreeListp = NULL;
6846 /* Initialize listener and server structures */
6847 memset(dead_sessions, 0, sizeof(dead_sessions));
6848 sprintf(eventName, "SessionEvents[0]");
6849 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6850 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6851 afsi_log("Event Object Already Exists: %s", eventName);
6853 smb_NumServerThreads = nThreads;
6854 sprintf(eventName, "NCBavails[0]");
6855 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6856 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6857 afsi_log("Event Object Already Exists: %s", eventName);
6858 sprintf(eventName, "NCBevents[0]");
6859 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6860 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6861 afsi_log("Event Object Already Exists: %s", eventName);
6862 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
6863 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
6864 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6865 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6866 afsi_log("Event Object Already Exists: %s", eventName);
6867 for (i = 0; i < smb_NumServerThreads; i++) {
6868 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
6869 NCBreturns[i][0] = retHandle;
6871 for (i = 1; i <= nThreads; i++)
6873 numNCBs = nThreads + 1;
6875 /* Initialize dispatch table */
6876 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
6877 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
6878 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
6879 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
6880 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
6881 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
6882 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
6883 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
6884 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
6885 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
6886 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
6887 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
6888 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
6889 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
6890 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
6891 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
6892 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
6893 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
6894 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
6895 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
6896 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
6897 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
6898 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6899 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
6900 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
6901 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
6902 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
6903 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
6904 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
6905 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
6906 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
6907 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6908 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
6909 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
6910 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
6911 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
6912 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
6913 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6914 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
6915 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6916 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
6917 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
6918 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
6919 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
6920 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
6921 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
6922 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
6923 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
6924 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
6925 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
6926 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
6927 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
6928 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
6929 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
6930 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
6931 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
6932 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
6933 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6934 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;
6935 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;
6936 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;
6937 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;
6938 for(i=0xd0; i<= 0xd7; i++) {
6939 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
6942 /* setup tran 2 dispatch table */
6943 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
6944 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
6945 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
6946 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
6947 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
6948 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
6949 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
6950 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
6951 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
6952 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
6953 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
6954 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
6955 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
6956 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2MKDir;
6960 /* Start listeners, waiters, servers, and daemons */
6962 for (i = 0; i < lana_list.length; i++) {
6963 if (lana_list.lana[i] == 255) continue;
6964 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
6965 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
6966 osi_assert(phandle != NULL);
6967 thrd_CloseHandle(phandle);
6971 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
6972 NULL, 0, &lpid, "smb_ClientWaiter");
6973 osi_assert(phandle != NULL);
6974 thrd_CloseHandle(phandle);
6977 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
6978 NULL, 0, &lpid, "smb_ServerWaiter");
6979 osi_assert(phandle != NULL);
6980 thrd_CloseHandle(phandle);
6982 for (i=0; i<nThreads; i++) {
6983 phandle = thrd_Create(NULL, 65536,
6984 (ThreadFunc) smb_Server,
6985 (void *) i, 0, &lpid, "smb_Server");
6986 osi_assert(phandle != NULL);
6987 thrd_CloseHandle(phandle);
6990 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
6991 NULL, 0, &lpid, "smb_Daemon");
6992 osi_assert(phandle != NULL);
6993 thrd_CloseHandle(phandle);
6995 phandle = thrd_Create(NULL, 65536,
6996 (ThreadFunc) smb_WaitingLocksDaemon,
6997 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
6998 osi_assert(phandle != NULL);
6999 thrd_CloseHandle(phandle);
7009 void smb_Shutdown(void)
7016 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7018 /* setup the NCB system */
7020 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7022 /* Block new sessions by setting shutdown flag */
7023 /*smbShutdownFlag = 1;*/
7025 /* Hang up all sessions */
7026 for (i = 1; i < numSessions; i++)
7028 if (dead_sessions[i])
7031 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7032 ncbp->ncb_command = NCBHANGUP;
7033 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
7034 ncbp->ncb_lsn = LSNs[i];
7035 code = Netbios(ncbp, dos_ncb);
7036 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LS
7038 if (code == 0) code = ncbp->ncb_retcode;
7040 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7045 /* Delete Netbios name */
7046 for (i = 0; i < lana_list.length; i++) {
7047 if (lana_list.lana[i] == 255) continue;
7048 ncbp->ncb_command = NCBDELNAME;
7049 ncbp->ncb_lana_num = lana_list.lana[i];
7050 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7051 code = Netbios(ncbp, dos_ncb);
7052 if (code == 0) code = ncbp->ncb_retcode;
7054 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7055 ncbp->ncb_lana_num, code);
7063 /* Get the UNC \\<servername>\<sharename> prefix. */
7064 char *smb_GetSharename()
7068 /* Make sure we have been properly initialized. */
7069 if (smb_localNamep == NULL)
7072 /* Allocate space for \\<servername>\<sharename>, plus the
7075 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7076 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7082 void smb_LogPacket(smb_packet_t *packet)
7085 unsigned length, paramlen, datalen, i, j;
7087 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7091 osi_Log0(afsd_logp, "*** SMB packet dump ***");
7093 vp = (BYTE *) packet->data;
7095 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7096 length = paramlen + 2 + datalen;
7099 for(i=0;i < length; i+=16)
7101 memset( buf, ' ', 80 );
7106 buf[strlen(buf)] = ' ';
7108 cp = (BYTE*) buf + 7;
7110 for(j=0;j < 16 && (i+j)<length; j++)
7112 *(cp++) = hex[vp[i+j] >> 4];
7113 *(cp++) = hex[vp[i+j] & 0xf];
7123 for(j=0;j < 16 && (i+j)<length;j++)
7125 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7136 osi_Log0( afsd_logp, buf );
7139 osi_Log0(afsd_logp, "*** End SMB packet dump ***");
7143 #endif /* NOTSERVICE */
7145 int smb_DumpVCP(FILE *outputFile, char *cookie)
7152 lock_ObtainRead(&smb_rctLock);
7154 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
7158 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7159 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7160 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7162 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
7164 sprintf(output, "%s -- fidp=0x%08X, refCount=%d, fid=%d, vcp=0x%08X, scp=0x%08X, ioctlp=0x%08X, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
7165 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
7166 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
7167 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7168 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7171 sprintf(output, "done dumping fidsp\n");
7172 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7175 lock_ReleaseRead(&smb_rctLock);