2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
12 #define NOMOREFILESFIX 1
14 #include <afs/param.h>
20 #include <sys/timeb.h>
35 #include "lanahelper.h"
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
41 smb_vc_t *dead_vcp = NULL;
42 smb_vc_t *active_vcp = NULL;
44 /* TODO; logout mechanism needs to be thread-safe */
45 char *loggedOutName = NULL;
46 smb_user_t *loggedOutUserp = NULL;
47 unsigned long loggedOutTime;
49 int smbShutdownFlag = 0;
51 int smb_LogoffTokenTransfer;
52 unsigned long smb_LogoffTransferTimeout;
54 DWORD last_msg_time = 0;
58 unsigned int sessionGen = 0;
60 extern void afsi_log(char *pattern, ...);
61 extern HANDLE afsi_file;
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t smb_ListenerLock;
72 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
75 long smb_maxObsConcurrentCalls=0;
76 long smb_concurrentCalls=0;
78 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
80 smb_packet_t *smb_packetFreeListp;
81 smb_ncb_t *smb_ncbFreeListp;
83 int smb_NumServerThreads;
85 int numNCBs, numSessions;
87 int smb_maxVCPerServer;
88 int smb_maxMpxRequests;
90 #define NCBmax MAXIMUM_WAIT_OBJECTS
91 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
92 EVENT_HANDLE **NCBreturns;
93 DWORD NCBsessions[NCBmax];
95 struct smb_packet *bufs[NCBmax];
97 #define Sessionmax MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE SessionEvents[Sessionmax];
99 unsigned short LSNs[Sessionmax];
100 int lanas[Sessionmax];
101 BOOL dead_sessions[Sessionmax];
105 osi_mutex_t smb_RawBufLock;
107 #define SMB_RAW_BUFS 4
109 int smb_RawBufSel[SMB_RAW_BUFS];
114 #define SMB_MASKFLAG_TILDE 1
115 #define SMB_MASKFLAG_CASEFOLD 2
117 #define RAWTIMEOUT INFINITE
120 typedef struct raw_write_cont {
133 /* dir search stuff */
134 long smb_dirSearchCounter = 1;
135 smb_dirSearch_t *smb_firstDirSearchp;
136 smb_dirSearch_t *smb_lastDirSearchp;
138 /* hide dot files? */
139 int smb_hideDotFiles;
141 /* global state about V3 protocols */
142 int smb_useV3; /* try to negotiate V3 */
145 static showErrors = 1;
146 /* MessageBox or something like it */
147 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
148 extern HANDLE WaitToTerminate;
152 * Time in Unix format of midnight, 1/1/1970 local time.
153 * When added to dosUTime, gives Unix (AFS) time.
157 /* Time difference for converting to kludge-GMT */
160 char *smb_localNamep = NULL;
162 smb_vc_t *smb_allVCsp;
164 smb_username_t *usernamesp = NULL;
166 smb_waitingLock_t *smb_allWaitingLocks;
169 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
170 NCB *ncbp, raw_write_cont_t *rwcp);
171 void smb_NetbiosInit();
173 #ifndef AFS_WIN95_ENV
174 DWORD smb_ServerExceptionFilter(void);
177 extern char cm_HostName[];
178 extern char cm_confDir[];
182 #define LPTSTR char *
183 #define GetComputerName(str, sizep) \
184 strcpy((str), cm_HostName); \
185 *(sizep) = strlen(cm_HostName)
188 extern char AFSConfigKeyName[];
193 * To build an expiring version, comment out the definition of NOEXPIRE,
194 * and set the definition of EXPIREDATE to the desired value.
197 #define EXPIREDATE 834000000 /* Wed Jun 5 1996 */
200 char * myCrt_Dispatch(int i)
205 return "unknown SMB op";
207 return "(00)ReceiveCoreMakeDir";
209 return "(01)ReceiveCoreRemoveDir";
211 return "(02)ReceiveCoreOpen";
213 return "(03)ReceiveCoreCreate";
215 return "(04)ReceiveCoreClose";
217 return "(05)ReceiveCoreFlush";
219 return "(06)ReceiveCoreUnlink";
221 return "(07)ReceiveCoreRename";
223 return "(08)ReceiveCoreGetFileAttributes";
225 return "(09)ReceiveCoreSetFileAttributes";
227 return "(0a)ReceiveCoreRead";
229 return "(0b)ReceiveCoreWrite";
231 return "(0c)ReceiveCoreLockRecord";
233 return "(0d)ReceiveCoreUnlockRecord";
235 return "(0e)SendCoreBadOp";
237 return "(0f)ReceiveCoreCreate";
239 return "(10)ReceiveCoreCheckPath";
241 return "(11)SendCoreBadOp";
243 return "(12)ReceiveCoreSeek";
245 return "(1a)ReceiveCoreReadRaw";
247 return "(1d)ReceiveCoreWriteRawDummy";
249 return "(22)ReceiveV3SetAttributes";
251 return "(23)ReceiveV3GetAttributes";
253 return "(24)ReceiveV3LockingX";
255 return "(29)SendCoreBadOp";
257 return "(2b)ReceiveCoreEcho";
259 return "(2d)ReceiveV3OpenX";
261 return "(2e)ReceiveV3ReadX";
263 return "(32)ReceiveV3Tran2A";
265 return "(33)ReceiveV3Tran2A";
267 return "(34)ReceiveV3FindClose";
269 return "(35)ReceiveV3FindNotifyClose";
271 return "(70)ReceiveCoreTreeConnect";
273 return "(71)ReceiveCoreTreeDisconnect";
275 return "(72)ReceiveNegotiate";
277 return "(73)ReceiveV3SessionSetupX";
279 return "(74)ReceiveV3UserLogoffX";
281 return "(75)ReceiveV3TreeConnectX";
283 return "(80)ReceiveCoreGetDiskAttributes";
285 return "(81)ReceiveCoreSearchDir";
287 return "(A0)ReceiveNTTransact";
289 return "(A2)ReceiveNTCreateX";
291 return "(A4)ReceiveNTCancel";
293 return "(c0)SendCoreBadOp";
295 return "(c1)SendCoreBadOp";
297 return "(c2)SendCoreBadOp";
299 return "(c3)SendCoreBadOp";
303 char * myCrt_2Dispatch(int i)
308 return "unknown SMB op-2";
310 return "S(00)CreateFile";
312 return "S(01)FindFirst";
314 return "S(02)FindNext"; /* FindNext */
316 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
320 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
322 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
324 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
326 return "S(08)??_ReceiveTran2SetFileInfo";
328 return "S(09)??_ReceiveTran2FSCTL";
330 return "S(0a)_ReceiveTran2IOCTL";
332 return "S(0b)_ReceiveTran2FindNotifyFirst";
334 return "S(0c)_ReceiveTran2FindNotifyNext";
336 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
340 /* scache must be locked */
341 unsigned int smb_Attributes(cm_scache_t *scp)
345 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
346 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
347 attrs = SMB_ATTR_DIRECTORY;
352 * We used to mark a file RO if it was in an RO volume, but that
353 * turns out to be impolitic in NT. See defect 10007.
356 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
358 if ((scp->unixModeBits & 0222) == 0)
359 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
364 /* Check if the named file/dir is a dotfile/dotdir */
365 /* String pointed to by lastComp can have leading slashes, but otherwise should have
366 no other patch components */
367 unsigned int smb_IsDotFile(char *lastComp) {
370 /* skip over slashes */
371 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
376 /* nulls, curdir and parent dir doesn't count */
379 if(!*(s + 1)) return 0;
380 if(*(s+1) == '.' && !*(s + 2)) return 0;
386 static int ExtractBits(WORD bits, short start, short len)
393 num = bits << (16 - end);
394 num = num >> ((16 - end) + start);
400 void ShowUnixTime(char *FuncName, long unixTime)
405 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
407 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
408 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
410 int day, month, year, sec, min, hour;
413 day = ExtractBits(wDate, 0, 5);
414 month = ExtractBits(wDate, 5, 4);
415 year = ExtractBits(wDate, 9, 7) + 1980;
417 sec = ExtractBits(wTime, 0, 5);
418 min = ExtractBits(wTime, 5, 6);
419 hour = ExtractBits(wTime, 11, 5);
421 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
422 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
428 /* Determine if we are observing daylight savings time */
429 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
431 TIME_ZONE_INFORMATION timeZoneInformation;
432 SYSTEMTIME utc, local, localDST;
434 /* Get the time zone info. NT uses this to calc if we are in DST. */
435 GetTimeZoneInformation(&timeZoneInformation);
437 /* Return the daylight bias */
438 *pDstBias = timeZoneInformation.DaylightBias;
440 /* Return the bias */
441 *pBias = timeZoneInformation.Bias;
443 /* Now determine if DST is being observed */
445 /* Get the UTC (GMT) time */
448 /* Convert UTC time to local time using the time zone info. If we are
449 observing DST, the calculated local time will include this.
451 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
453 /* Set the daylight bias to 0. The daylight bias is the amount of change
454 in time that we use for daylight savings time. By setting this to 0
455 we cause there to be no change in time during daylight savings time.
457 timeZoneInformation.DaylightBias = 0;
459 /* Convert the utc time to local time again, but this time without any
460 adjustment for daylight savings time.
462 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
464 /* If the two times are different, then it means that the localDST that
465 we calculated includes the daylight bias, and therefore we are
466 observing daylight savings time.
468 *pDST = localDST.wHour != local.wHour;
471 /* Determine if we are observing daylight savings time */
472 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
478 *pDstBias = -60; /* where can this be different? */
484 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
486 BOOL dst; /* Will be TRUE if observing DST */
487 LONG dstBias; /* Offset from local time if observing DST */
488 LONG bias; /* Offset from GMT for local time */
491 * This function will adjust the last write time to compensate
492 * for two bugs in the smb client:
494 * 1) During Daylight Savings Time, the LastWriteTime is ahead
495 * in time by the DaylightBias (ignoring the sign - the
496 * DaylightBias is always stored as a negative number). If
497 * the DaylightBias is -60, then the LastWriteTime will be
498 * ahead by 60 minutes.
500 * 2) If the local time zone is a positive offset from GMT, then
501 * the LastWriteTime will be the correct local time plus the
502 * Bias (ignoring the sign - a positive offset from GMT is
503 * always stored as a negative Bias). If the Bias is -120,
504 * then the LastWriteTime will be ahead by 120 minutes.
506 * These bugs can occur at the same time.
509 GetTimeZoneInfo(&dst, &dstBias, &bias);
511 /* First adjust for DST */
513 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
515 /* Now adjust for a positive offset from GMT (a negative bias). */
517 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
521 * Calculate the difference (in seconds) between local time and GMT.
522 * This enables us to convert file times to kludge-GMT.
528 struct tm gmt_tm, local_tm;
529 int days, hours, minutes, seconds;
532 gmt_tm = *(gmtime(&t));
533 local_tm = *(localtime(&t));
535 days = local_tm.tm_yday - gmt_tm.tm_yday;
536 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
538 /* There is a problem with DST immediately after the time change
539 * which may continue to exist until the machine is rebooted
541 - (local_tm.tm_isdst ? 1 : 0)
544 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
545 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
551 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
556 long ersatz_unixTime;
559 * Must use kludge-GMT instead of real GMT.
560 * kludge-GMT is computed by adding time zone difference to localtime.
563 * ltp = gmtime(&unixTime);
565 ersatz_unixTime = unixTime - smb_NowTZ;
566 ltp = localtime(&ersatz_unixTime);
568 /* if we fail, make up something */
571 localJunk.tm_year = 89 - 20;
572 localJunk.tm_mon = 4;
573 localJunk.tm_mday = 12;
574 localJunk.tm_hour = 0;
575 localJunk.tm_min = 0;
576 localJunk.tm_sec = 0;
579 stm.wYear = ltp->tm_year + 1900;
580 stm.wMonth = ltp->tm_mon + 1;
581 stm.wDayOfWeek = ltp->tm_wday;
582 stm.wDay = ltp->tm_mday;
583 stm.wHour = ltp->tm_hour;
584 stm.wMinute = ltp->tm_min;
585 stm.wSecond = ltp->tm_sec;
586 stm.wMilliseconds = 0;
588 SystemTimeToFileTime(&stm, largeTimep);
591 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
593 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
594 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
595 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
597 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
599 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
600 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
602 *ft = LargeIntegerMultiplyByLong(*ft, 60);
603 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
606 ut = ConvertLongToLargeInteger(unixTime);
607 ut = LargeIntegerMultiplyByLong(ut, 10000000);
608 *ft = LargeIntegerAdd(*ft, ut);
613 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
619 FileTimeToSystemTime(largeTimep, &stm);
621 lt.tm_year = stm.wYear - 1900;
622 lt.tm_mon = stm.wMonth - 1;
623 lt.tm_wday = stm.wDayOfWeek;
624 lt.tm_mday = stm.wDay;
625 lt.tm_hour = stm.wHour;
626 lt.tm_min = stm.wMinute;
627 lt.tm_sec = stm.wSecond;
630 save_timezone = _timezone;
631 _timezone += smb_NowTZ;
632 *unixTimep = mktime(<);
633 _timezone = save_timezone;
636 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
638 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
639 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
640 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
644 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
645 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
646 a = LargeIntegerMultiplyByLong(a, 60);
647 a = LargeIntegerMultiplyByLong(a, 10000000);
649 /* subtract it from ft */
650 a = LargeIntegerSubtract(*ft, a);
652 /* divide down to seconds */
653 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
657 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
664 ltp = localtime((time_t*) &unixTime);
666 /* if we fail, make up something */
669 localJunk.tm_year = 89 - 20;
670 localJunk.tm_mon = 4;
671 localJunk.tm_mday = 12;
672 localJunk.tm_hour = 0;
673 localJunk.tm_min = 0;
674 localJunk.tm_sec = 0;
677 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
678 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
679 *dosTimep = (dosDate<<16) | dosTime;
682 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
684 unsigned short dosDate;
685 unsigned short dosTime;
688 dosDate = searchTime & 0xffff;
689 dosTime = (searchTime >> 16) & 0xffff;
691 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
692 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
693 localTm.tm_mday = (dosDate) & 0x1f;
694 localTm.tm_hour = (dosTime>>11) & 0x1f;
695 localTm.tm_min = (dosTime >> 5) & 0x3f;
696 localTm.tm_sec = (dosTime & 0x1f) * 2;
697 localTm.tm_isdst = -1; /* compute whether DST in effect */
699 *unixTimep = mktime(&localTm);
702 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
704 *dosUTimep = unixTime - smb_localZero;
707 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
710 *unixTimep = dosTime + smb_localZero;
712 /* dosTime seems to be already adjusted for GMT */
713 *unixTimep = dosTime;
717 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
721 lock_ObtainWrite(&smb_rctLock);
722 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
723 if (lsn == vcp->lsn && lana == vcp->lana) {
728 if (!vcp && (flags & SMB_FLAG_CREATE)) {
729 vcp = malloc(sizeof(*vcp));
730 memset(vcp, 0, sizeof(*vcp));
734 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
735 vcp->nextp = smb_allVCsp;
737 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
741 lock_ReleaseWrite(&smb_rctLock);
745 int smb_IsStarMask(char *maskp)
750 for(i=0; i<11; i++) {
752 if (tc == '?' || tc == '*' || tc == '>') return 1;
757 void smb_ReleaseVC(smb_vc_t *vcp)
759 lock_ObtainWrite(&smb_rctLock);
760 osi_assert(vcp->refCount-- > 0);
761 lock_ReleaseWrite(&smb_rctLock);
764 void smb_HoldVC(smb_vc_t *vcp)
766 lock_ObtainWrite(&smb_rctLock);
768 lock_ReleaseWrite(&smb_rctLock);
771 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
775 lock_ObtainWrite(&smb_rctLock);
776 for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
777 if (tid == tidp->tid) {
782 if (!tidp && (flags & SMB_FLAG_CREATE)) {
783 tidp = malloc(sizeof(*tidp));
784 memset(tidp, 0, sizeof(*tidp));
785 tidp->nextp = vcp->tidsp;
790 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
793 lock_ReleaseWrite(&smb_rctLock);
797 void smb_ReleaseTID(smb_tid_t *tidp)
806 lock_ObtainWrite(&smb_rctLock);
807 osi_assert(tidp->refCount-- > 0);
808 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
809 ltpp = &tidp->vcp->tidsp;
810 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
811 if (tp == tidp) break;
813 osi_assert(tp != NULL);
815 lock_FinalizeMutex(&tidp->mx);
816 userp = tidp->userp; /* remember to drop ref later */
819 lock_ReleaseWrite(&smb_rctLock);
821 cm_ReleaseUser(userp);
828 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
830 smb_user_t *uidp = NULL;
832 lock_ObtainWrite(&smb_rctLock);
833 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
834 if (uid == uidp->userID) {
836 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 : "");
840 if (!uidp && (flags & SMB_FLAG_CREATE)) {
841 uidp = malloc(sizeof(*uidp));
842 memset(uidp, 0, sizeof(*uidp));
843 uidp->nextp = vcp->usersp;
848 lock_InitializeMutex(&uidp->mx, "uid_t mutex");
850 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 : ""));
852 lock_ReleaseWrite(&smb_rctLock);
856 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
858 smb_username_t *unp= NULL;
860 lock_ObtainWrite(&smb_rctLock);
861 for(unp = usernamesp; unp; unp = unp->nextp) {
862 if (stricmp(unp->name, usern) == 0 &&
863 stricmp(unp->machine, machine) == 0) {
868 if (!unp && (flags & SMB_FLAG_CREATE)) {
869 unp = malloc(sizeof(*unp));
870 memset(unp, 0, sizeof(*unp));
872 unp->nextp = usernamesp;
873 unp->name = strdup(usern);
874 unp->machine = strdup(machine);
876 lock_InitializeMutex(&unp->mx, "username_t mutex");
878 lock_ReleaseWrite(&smb_rctLock);
882 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
884 smb_user_t *uidp= NULL;
886 lock_ObtainWrite(&smb_rctLock);
887 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
890 if (stricmp(uidp->unp->name, usern) == 0) {
892 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
897 lock_ReleaseWrite(&smb_rctLock);
900 void smb_ReleaseUID(smb_user_t *uidp)
909 lock_ObtainWrite(&smb_rctLock);
910 osi_assert(uidp->refCount-- > 0);
911 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
912 lupp = &uidp->vcp->usersp;
913 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
914 if (up == uidp) break;
916 osi_assert(up != NULL);
918 lock_FinalizeMutex(&uidp->mx);
920 userp = uidp->unp->userp; /* remember to drop ref later */
921 uidp->unp->userp = NULL;
926 lock_ReleaseWrite(&smb_rctLock);
928 cm_ReleaseUserVCRef(userp);
929 cm_ReleaseUser(userp);
936 /* retrieve a held reference to a user structure corresponding to an incoming
938 * corresponding release function is cm_ReleaseUser.
940 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
946 smbp = (smb_t *) inp;
947 uidp = smb_FindUID(vcp, smbp->uid, 0);
948 if ((!uidp) || (!uidp->unp))
951 lock_ObtainMutex(&uidp->mx);
952 up = uidp->unp->userp;
954 lock_ReleaseMutex(&uidp->mx);
956 smb_ReleaseUID(uidp);
962 * Return a pointer to a pathname extracted from a TID structure. The
963 * TID structure is not held; assume it won't go away.
965 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
970 tidp = smb_FindTID(vcp, tid, 0);
973 tpath = tidp->pathname;
974 smb_ReleaseTID(tidp);
978 /* check to see if we have a chained fid, that is, a fid that comes from an
979 * OpenAndX message that ran earlier in this packet. In this case, the fid
980 * field in a read, for example, request, isn't set, since the value is
981 * supposed to be inherited from the openAndX call.
983 int smb_ChainFID(int fid, smb_packet_t *inp)
985 if (inp->fid == 0 || inp->inCount == 0)
991 /* are we a priv'd user? What does this mean on NT? */
992 int smb_SUser(cm_user_t *userp)
997 /* find a file ID. If we pass in 0 we select an used File ID.
998 * If the SMB_FLAG_CREATE flag is set, we allocate a new
999 * smb_fid_t data structure if desired File ID cannot be found.
1001 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1006 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1009 lock_ObtainWrite(&smb_rctLock);
1010 /* figure out if we need to allocate a new file ID */
1013 fid = vcp->fidCounter;
1017 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1018 if (fid == fidp->fid) {
1029 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1030 char eventName[MAX_PATH];
1032 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1033 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1034 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1035 afsi_log("Event Object Already Exists: %s", eventName);
1036 thrd_CloseHandle(event);
1043 fidp = malloc(sizeof(*fidp));
1044 memset(fidp, 0, sizeof(*fidp));
1045 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1049 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1051 fidp->curr_chunk = fidp->prev_chunk = -2;
1052 fidp->raw_write_event = event;
1054 vcp->fidCounter = fid+1;
1055 if (vcp->fidCounter == 0)
1056 vcp->fidCounter = 1;
1059 lock_ReleaseWrite(&smb_rctLock);
1063 void smb_ReleaseFID(smb_fid_t *fidp)
1066 smb_vc_t *vcp = NULL;
1067 smb_ioctl_t *ioctlp;
1073 lock_ObtainWrite(&smb_rctLock);
1074 osi_assert(fidp->refCount-- > 0);
1075 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1077 if (!(fidp->flags & SMB_FID_IOCTL))
1079 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1080 thrd_CloseHandle(fidp->raw_write_event);
1082 /* and see if there is ioctl stuff to free */
1083 ioctlp = fidp->ioctlp;
1085 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1086 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1087 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1093 /* do not call smb_ReleaseVC() because we already have the lock */
1096 lock_ReleaseWrite(&smb_rctLock);
1098 /* now release the scache structure */
1100 cm_ReleaseSCache(scp);
1104 * Case-insensitive search for one string in another;
1105 * used to find variable names in submount pathnames.
1107 static char *smb_stristr(char *str1, char *str2)
1111 for (cursor = str1; *cursor; cursor++)
1112 if (stricmp(cursor, str2) == 0)
1119 * Substitute a variable value for its name in a submount pathname. Variable
1120 * name has been identified by smb_stristr() and is in substr. Variable name
1121 * length (plus one) is in substr_size. Variable value is in newstr.
1123 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1128 strcpy(temp, substr + substr_size - 1);
1129 strcpy(substr, newstr);
1133 char VNUserName[] = "%USERNAME%";
1134 char VNLCUserName[] = "%LCUSERNAME%";
1135 char VNComputerName[] = "%COMPUTERNAME%";
1136 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1138 /* List available shares */
1139 int smb_ListShares()
1143 char shareBuf[4096];
1151 /*strcpy(shareNameList[num_shares], "all");
1152 strcpy(pathNameList[num_shares++], "/afs");*/
1153 fprintf(stderr, "The following shares are available:\n");
1154 fprintf(stderr, "Share Name (AFS Path)\n");
1155 fprintf(stderr, "---------------------\n");
1156 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1159 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1160 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1162 strcpy(sbmtpath, cm_confDir);
1164 strcat(sbmtpath, "/afsdsbmt.ini");
1165 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1166 shareBuf, sizeof(shareBuf),
1172 this_share = shareBuf;
1176 /*strcpy(shareNameList[num_shares], this_share);*/
1177 len = GetPrivateProfileString("AFS Submounts", this_share,
1184 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1187 if (*p == '\\') *p = '/'; /* change to / */
1191 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1192 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1195 while (*this_share != 0) this_share++; /* find next NUL */
1196 this_share++; /* skip past the NUL */
1197 } while (*this_share != 0); /* stop at final NUL */
1202 /* find a shareName in the table of submounts */
1203 int smb_FindShare(smb_vc_t *vcp, smb_packet_t *inp, char *shareName,
1207 char pathName[1024];
1212 char sbmtpath[MAX_PATH];
1216 DWORD allSubmount = 1;
1218 if (strcmp(shareName, "IPC$") == 0) {
1223 /* if allSubmounts == 0, only return the //mountRoot/all share
1224 * if in fact it has been been created in the subMounts table.
1225 * This is to allow sites that want to restrict access to the
1228 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1229 0, KEY_QUERY_VALUE, &parmKey);
1230 if (code == ERROR_SUCCESS) {
1231 len = sizeof(allSubmount);
1232 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1233 (BYTE *) &allSubmount, &len);
1234 if (code != ERROR_SUCCESS) {
1237 RegCloseKey (parmKey);
1240 if (allSubmount && _stricmp(shareName, "all") == 0) {
1245 /* In case, the all share is disabled we need to still be able
1246 * to handle ioctl requests
1248 if (_stricmp(shareName, "ioctl$") == 0) {
1249 *pathNamep = strdup("/.__ioctl__");
1254 strcpy(sbmtpath, "afsdsbmt.ini");
1256 strcpy(sbmtpath, cm_confDir);
1257 strcat(sbmtpath, "/afsdsbmt.ini");
1259 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1260 pathName, sizeof(pathName), sbmtpath);
1261 if (len != 0 && len != sizeof(pathName) - 1) {
1262 /* We can accept either unix or PC style AFS pathnames. Convert
1263 * Unix-style to PC style here for internal use.
1266 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1267 p += strlen(cm_mountRoot); /* skip mount path */
1270 if (*q == '/') *q = '\\'; /* change to \ */
1276 if (var = smb_stristr(p, VNUserName)) {
1277 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1278 if (uidp && uidp->unp)
1279 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1281 smb_subst(p, var, sizeof(VNUserName)," ");
1283 smb_ReleaseUID(uidp);
1285 else if (var = smb_stristr(p, VNLCUserName))
1287 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1288 if (uidp && uidp->unp)
1289 strcpy(temp, uidp->unp->name);
1293 smb_subst(p, var, sizeof(VNLCUserName), temp);
1295 smb_ReleaseUID(uidp);
1297 else if (var = smb_stristr(p, VNComputerName))
1299 sizeTemp = sizeof(temp);
1300 GetComputerName((LPTSTR)temp, &sizeTemp);
1301 smb_subst(p, var, sizeof(VNComputerName), temp);
1303 else if (var = smb_stristr(p, VNLCComputerName))
1305 sizeTemp = sizeof(temp);
1306 GetComputerName((LPTSTR)temp, &sizeTemp);
1308 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1313 *pathNamep = strdup(p);
1316 else /* create \\<netbiosName>\<cellname> */
1318 char * p = shareName;
1325 /* Get the full name for this cell */
1326 code = cm_SearchCellFile(p, temp, 0, 0);
1327 #ifdef AFS_AFSDB_ENV
1328 if (code && cm_dnsEnabled) {
1330 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1333 /* construct the path */
1335 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1336 *pathNamep = strdup(strlwr(pathName));
1345 /* Client-side offline caching policy types */
1346 #define CSC_POLICY_MANUAL 0
1347 #define CSC_POLICY_DOCUMENTS 1
1348 #define CSC_POLICY_PROGRAMS 2
1349 #define CSC_POLICY_DISABLE 3
1351 int smb_FindShareCSCPolicy(char *shareName)
1358 strcpy(sbmtpath, "afsdsbmt.ini");
1360 strcpy(sbmtpath, cm_confDir);
1361 strcat(sbmtpath, "/afsdsbmt.ini");
1363 len = GetPrivateProfileString("CSC Policy", shareName, "",
1364 policy, sizeof(policy), sbmtpath);
1365 if (len == 0 || len == sizeof(policy) - 1) {
1366 return CSC_POLICY_MANUAL;
1369 if (stricmp(policy, "documents") == 0)
1371 return CSC_POLICY_DOCUMENTS;
1374 if (stricmp(policy, "programs") == 0)
1376 return CSC_POLICY_PROGRAMS;
1379 if (stricmp(policy, "disable") == 0)
1381 return CSC_POLICY_DISABLE;
1384 return CSC_POLICY_MANUAL;
1387 /* find a dir search structure by cookie value, and return it held.
1388 * Must be called with smb_globalLock held.
1390 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1392 smb_dirSearch_t *dsp;
1394 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1395 if (dsp->cookie == cookie) {
1396 if (dsp != smb_firstDirSearchp) {
1397 /* move to head of LRU queue, too, if we're not already there */
1398 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1399 smb_lastDirSearchp = (smb_dirSearch_t *)
1401 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1402 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1403 if (!smb_lastDirSearchp)
1404 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1413 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1415 lock_ObtainWrite(&smb_globalLock);
1416 dsp->flags |= SMB_DIRSEARCH_DELETE;
1417 lock_ReleaseWrite(&smb_globalLock);
1418 lock_ObtainMutex(&dsp->mx);
1419 if(dsp->scp != NULL) {
1420 lock_ObtainMutex(&dsp->scp->mx);
1421 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1422 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1423 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1424 dsp->scp->bulkStatProgress = hones;
1426 lock_ReleaseMutex(&dsp->scp->mx);
1428 lock_ReleaseMutex(&dsp->mx);
1431 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1437 lock_ObtainWrite(&smb_globalLock);
1438 osi_assert(dsp->refCount-- > 0);
1439 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1440 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1441 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1442 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1443 lock_FinalizeMutex(&dsp->mx);
1447 lock_ReleaseWrite(&smb_globalLock);
1449 /* do this now to avoid spurious locking hierarchy creation */
1450 if (scp) cm_ReleaseSCache(scp);
1453 /* find a dir search structure by cookie value, and return it held */
1454 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1456 smb_dirSearch_t *dsp;
1458 lock_ObtainWrite(&smb_globalLock);
1459 dsp = smb_FindDirSearchNL(cookie);
1460 lock_ReleaseWrite(&smb_globalLock);
1464 /* GC some dir search entries, in the address space expected by the specific protocol.
1465 * Must be called with smb_globalLock held; release the lock temporarily.
1467 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1468 void smb_GCDirSearches(int isV3)
1470 smb_dirSearch_t *prevp;
1471 smb_dirSearch_t *tp;
1472 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1476 victimCount = 0; /* how many have we got so far */
1477 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1478 /* we'll move tp from queue, so
1481 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1482 /* if no one is using this guy, and we're either in the new protocol,
1483 * or we're in the old one and this is a small enough ID to be useful
1484 * to the old protocol, GC this guy.
1486 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1487 /* hold and delete */
1488 tp->flags |= SMB_DIRSEARCH_DELETE;
1489 victimsp[victimCount++] = tp;
1493 /* don't do more than this */
1494 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1497 /* now release them */
1498 lock_ReleaseWrite(&smb_globalLock);
1499 for(i = 0; i < victimCount; i++) {
1500 smb_ReleaseDirSearch(victimsp[i]);
1502 lock_ObtainWrite(&smb_globalLock);
1505 /* function for allocating a dir search entry. We need these to remember enough context
1506 * since we don't get passed the path from call to call during a directory search.
1508 * Returns a held dir search structure, and bumps the reference count on the vnode,
1509 * since it saves a pointer to the vnode.
1511 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1513 smb_dirSearch_t *dsp;
1517 lock_ObtainWrite(&smb_globalLock);
1520 /* what's the biggest ID allowed in this version of the protocol */
1521 if (isV3) maxAllowed = 65535;
1522 else maxAllowed = 255;
1525 /* twice so we have enough tries to find guys we GC after one pass;
1526 * 10 extra is just in case I mis-counted.
1528 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1529 __FILE__, __LINE__);
1530 if (smb_dirSearchCounter > maxAllowed) {
1531 smb_dirSearchCounter = 1;
1532 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1534 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1536 /* don't need to watch for refcount zero and deleted, since
1537 * we haven't dropped the global lock.
1540 ++smb_dirSearchCounter;
1544 dsp = malloc(sizeof(*dsp));
1545 memset(dsp, 0, sizeof(*dsp));
1546 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1547 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1548 dsp->cookie = smb_dirSearchCounter;
1549 ++smb_dirSearchCounter;
1551 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1552 dsp->lastTime = osi_Time();
1555 lock_ReleaseWrite(&smb_globalLock);
1559 static smb_packet_t *GetPacket(void)
1563 unsigned int npar, seg, tb_sel;
1566 lock_ObtainWrite(&smb_globalLock);
1567 tbp = smb_packetFreeListp;
1569 smb_packetFreeListp = tbp->nextp;
1570 lock_ReleaseWrite(&smb_globalLock);
1573 tbp = calloc(65540,1);
1575 tbp = malloc(sizeof(smb_packet_t));
1577 tbp->magic = SMB_PACKETMAGIC;
1580 tbp->resumeCode = 0;
1586 tbp->ncb_length = 0;
1591 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1594 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1596 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1598 osi_panic("",__FILE__,__LINE__);
1601 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1606 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1607 tbp->dos_pkt_sel = tb_sel;
1610 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1615 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1619 memcpy(tbp, pkt, sizeof(smb_packet_t));
1620 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1624 static NCB *GetNCB(void)
1629 unsigned int npar, seg, tb_sel;
1632 lock_ObtainWrite(&smb_globalLock);
1633 tbp = smb_ncbFreeListp;
1635 smb_ncbFreeListp = tbp->nextp;
1636 lock_ReleaseWrite(&smb_globalLock);
1639 tbp = calloc(sizeof(*tbp),1);
1641 tbp = malloc(sizeof(*tbp));
1642 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1645 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1647 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1649 osi_panic("",__FILE__,__LINE__);
1651 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1656 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1657 tbp->dos_ncb_sel = tb_sel;
1659 tbp->magic = SMB_NCBMAGIC;
1662 osi_assert(tbp->magic == SMB_NCBMAGIC);
1664 memset(&tbp->ncb, 0, sizeof(NCB));
1667 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1672 void smb_FreePacket(smb_packet_t *tbp)
1674 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1676 lock_ObtainWrite(&smb_globalLock);
1677 tbp->nextp = smb_packetFreeListp;
1678 smb_packetFreeListp = tbp;
1679 tbp->magic = SMB_PACKETMAGIC;
1682 tbp->resumeCode = 0;
1688 tbp->ncb_length = 0;
1690 lock_ReleaseWrite(&smb_globalLock);
1693 static void FreeNCB(NCB *bufferp)
1697 tbp = (smb_ncb_t *) bufferp;
1698 osi_assert(tbp->magic == SMB_NCBMAGIC);
1700 lock_ObtainWrite(&smb_globalLock);
1701 tbp->nextp = smb_ncbFreeListp;
1702 smb_ncbFreeListp = tbp;
1703 lock_ReleaseWrite(&smb_globalLock);
1706 /* get a ptr to the data part of a packet, and its count */
1707 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1711 unsigned char *afterParmsp;
1713 parmBytes = *smbp->wctp << 1;
1714 afterParmsp = smbp->wctp + parmBytes + 1;
1716 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1717 if (nbytesp) *nbytesp = dataBytes;
1719 /* don't forget to skip the data byte count, since it follows
1720 * the parameters; that's where the "2" comes from below.
1722 return (unsigned char *) (afterParmsp + 2);
1725 /* must set all the returned parameters before playing around with the
1726 * data region, since the data region is located past the end of the
1727 * variable number of parameters.
1729 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1731 unsigned char *afterParmsp;
1733 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1735 *afterParmsp++ = dsize & 0xff;
1736 *afterParmsp = (dsize>>8) & 0xff;
1739 /* return the parm'th parameter in the smbp packet */
1740 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1743 unsigned char *parmDatap;
1745 parmCount = *smbp->wctp;
1747 if (parm >= parmCount) {
1752 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1753 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1754 parm, parmCount, smbp->ncb_length);
1756 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1757 1, smbp->ncb_length, ptbuf, smbp);
1758 DeregisterEventSource(h);
1762 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1763 parm, parmCount, smbp->ncb_length);
1764 osi_Log0(smb_logp, s);
1766 osi_panic(s, __FILE__, __LINE__);
1768 parmDatap = smbp->wctp + (2*parm) + 1;
1770 return parmDatap[0] + (parmDatap[1] << 8);
1773 /* return the parm'th parameter in the smbp packet */
1774 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1777 unsigned char *parmDatap;
1779 parmCount = *smbp->wctp;
1781 if (parm * 2 + offset >= parmCount * 2) {
1786 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1787 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1788 parm, offset, parmCount, smbp->ncb_length);
1790 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1791 1, smbp->ncb_length, ptbuf, smbp);
1792 DeregisterEventSource(h);
1796 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1798 parm, offset, parmCount, smbp->ncb_length);
1799 osi_Log0(smb_logp, s);
1802 osi_panic(s, __FILE__, __LINE__);
1804 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1806 return parmDatap[0] + (parmDatap[1] << 8);
1809 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1813 /* make sure we have enough slots */
1814 if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1816 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1817 *parmDatap++ = parmValue & 0xff;
1818 *parmDatap = (parmValue>>8) & 0xff;
1821 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1825 /* make sure we have enough slots */
1826 if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1828 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1829 *parmDatap++ = parmValue & 0xff;
1830 *parmDatap++ = (parmValue>>8) & 0xff;
1831 *parmDatap++ = (parmValue>>16) & 0xff;
1832 *parmDatap++ = (parmValue>>24) & 0xff;
1835 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1840 /* make sure we have enough slots */
1841 if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1843 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1845 *parmDatap++ = *parmValuep++;
1848 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1852 /* make sure we have enough slots */
1853 if (*smbp->wctp <= slot) {
1854 if (smbp->oddByte) {
1856 *smbp->wctp = slot+1;
1861 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1862 *parmDatap++ = parmValue & 0xff;
1865 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1869 lastSlashp = strrchr(inPathp, '\\');
1871 *lastComponentp = lastSlashp;
1874 if (inPathp == lastSlashp)
1876 *outPathp++ = *inPathp++;
1885 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1890 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
1895 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1901 tlen = inp[0] + (inp[1]<<8);
1902 inp += 2; /* skip length field */
1905 *chainpp = inp + tlen;
1914 /* format a packet as a response */
1915 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1920 outp = (smb_t *) op;
1922 /* zero the basic structure through the smb_wct field, and zero the data
1923 * size field, assuming that wct stays zero; otherwise, you have to
1924 * explicitly set the data size field, too.
1926 inSmbp = (smb_t *) inp;
1927 memset(outp, 0, sizeof(smb_t)+2);
1933 outp->com = inSmbp->com;
1934 outp->tid = inSmbp->tid;
1935 outp->pid = inSmbp->pid;
1936 outp->uid = inSmbp->uid;
1937 outp->mid = inSmbp->mid;
1938 outp->res[0] = inSmbp->res[0];
1939 outp->res[1] = inSmbp->res[1];
1940 op->inCom = inSmbp->com;
1942 outp->reb = 0x80; /* SERVER_RESP */
1943 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
1945 /* copy fields in generic packet area */
1946 op->wctp = &outp->wct;
1949 /* send a (probably response) packet; vcp tells us to whom to send it.
1950 * we compute the length by looking at wct and bcc fields.
1952 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1969 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
1972 memset((char *)ncbp, 0, sizeof(NCB));
1974 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
1975 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
1976 extra += tp[0] + (tp[1]<<8);
1977 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
1978 extra += 3; /* wct and length fields */
1980 ncbp->ncb_length = extra; /* bytes to send */
1981 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
1982 ncbp->ncb_lana_num = vcp->lana;
1983 ncbp->ncb_command = NCBSEND; /* op means send data */
1985 ncbp->ncb_buffer = (char *) inp;/* packet */
1986 code = Netbios(ncbp);
1988 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
1989 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
1991 /* copy header information from virtual to DOS address space */
1992 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
1993 code = Netbios(ncbp, dos_ncb);
1997 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2003 void smb_MapNTError(long code, unsigned long *NTStatusp)
2005 unsigned long NTStatus;
2007 /* map CM_ERROR_* errors to NT 32-bit status codes */
2008 /* NT Status codes are listed in ntstatus.h not winerror.h */
2009 if (code == CM_ERROR_NOSUCHCELL) {
2010 NTStatus = 0xC000000FL; /* No such file */
2012 else if (code == CM_ERROR_NOSUCHVOLUME) {
2013 NTStatus = 0xC000000FL; /* No such file */
2015 else if (code == CM_ERROR_TIMEDOUT) {
2016 NTStatus = 0xC00000CFL; /* Sharing Paused */
2018 else if (code == CM_ERROR_RETRY) {
2019 NTStatus = 0xC000022DL; /* Retry */
2021 else if (code == CM_ERROR_NOACCESS) {
2022 NTStatus = 0xC0000022L; /* Access denied */
2024 else if (code == CM_ERROR_READONLY) {
2025 NTStatus = 0xC00000A2L; /* Write protected */
2027 else if (code == CM_ERROR_NOSUCHFILE) {
2028 NTStatus = 0xC000000FL; /* No such file */
2030 else if (code == CM_ERROR_NOSUCHPATH) {
2031 NTStatus = 0xC000003AL; /* Object path not found */
2033 else if (code == CM_ERROR_TOOBIG) {
2034 NTStatus = 0xC000007BL; /* Invalid image format */
2036 else if (code == CM_ERROR_INVAL) {
2037 NTStatus = 0xC000000DL; /* Invalid parameter */
2039 else if (code == CM_ERROR_BADFD) {
2040 NTStatus = 0xC0000008L; /* Invalid handle */
2042 else if (code == CM_ERROR_BADFDOP) {
2043 NTStatus = 0xC0000022L; /* Access denied */
2045 else if (code == CM_ERROR_EXISTS) {
2046 NTStatus = 0xC0000035L; /* Object name collision */
2048 else if (code == CM_ERROR_NOTEMPTY) {
2049 NTStatus = 0xC0000101L; /* Directory not empty */
2051 else if (code == CM_ERROR_CROSSDEVLINK) {
2052 NTStatus = 0xC00000D4L; /* Not same device */
2054 else if (code == CM_ERROR_NOTDIR) {
2055 NTStatus = 0xC0000103L; /* Not a directory */
2057 else if (code == CM_ERROR_ISDIR) {
2058 NTStatus = 0xC00000BAL; /* File is a directory */
2060 else if (code == CM_ERROR_BADOP) {
2061 NTStatus = 0xC09820FFL; /* SMB no support */
2063 else if (code == CM_ERROR_BADSHARENAME) {
2064 NTStatus = 0xC00000CCL; /* Bad network name */
2066 else if (code == CM_ERROR_NOIPC) {
2068 NTStatus = 0xC0000022L; /* Access Denied */
2070 NTStatus = 0xC000013DL; /* Remote Resources */
2073 else if (code == CM_ERROR_CLOCKSKEW) {
2074 NTStatus = 0xC0000133L; /* Time difference at DC */
2076 else if (code == CM_ERROR_BADTID) {
2077 NTStatus = 0xC0982005L; /* SMB bad TID */
2079 else if (code == CM_ERROR_USESTD) {
2080 NTStatus = 0xC09820FBL; /* SMB use standard */
2082 else if (code == CM_ERROR_QUOTA) {
2083 NTStatus = 0xC0000044L; /* Quota exceeded */
2085 else if (code == CM_ERROR_SPACE) {
2086 NTStatus = 0xC000007FL; /* Disk full */
2088 else if (code == CM_ERROR_ATSYS) {
2089 NTStatus = 0xC0000033L; /* Object name invalid */
2091 else if (code == CM_ERROR_BADNTFILENAME) {
2092 NTStatus = 0xC0000033L; /* Object name invalid */
2094 else if (code == CM_ERROR_WOULDBLOCK) {
2095 NTStatus = 0xC0000055L; /* Lock not granted */
2097 else if (code == CM_ERROR_PARTIALWRITE) {
2098 NTStatus = 0xC000007FL; /* Disk full */
2100 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2101 NTStatus = 0xC0000023L; /* Buffer too small */
2103 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2104 NTStatus = 0xC0000035L; /* Object name collision */
2107 NTStatus = 0xC0982001L; /* SMB non-specific error */
2110 *NTStatusp = NTStatus;
2111 osi_Log2(smb_logp, "SMB SEND code %x as NT %x", code, NTStatus);
2114 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2115 unsigned char *classp)
2117 unsigned char class;
2118 unsigned short error;
2120 /* map CM_ERROR_* errors to SMB errors */
2121 if (code == CM_ERROR_NOSUCHCELL) {
2123 error = 3; /* bad path */
2125 else if (code == CM_ERROR_NOSUCHVOLUME) {
2127 error = 3; /* bad path */
2129 else if (code == CM_ERROR_TIMEDOUT) {
2131 error = 81; /* server is paused */
2133 else if (code == CM_ERROR_RETRY) {
2134 class = 2; /* shouldn't happen */
2137 else if (code == CM_ERROR_NOACCESS) {
2139 error = 4; /* bad access */
2141 else if (code == CM_ERROR_READONLY) {
2143 error = 19; /* read only */
2145 else if (code == CM_ERROR_NOSUCHFILE) {
2147 error = 2; /* ENOENT! */
2149 else if (code == CM_ERROR_NOSUCHPATH) {
2151 error = 3; /* Bad path */
2153 else if (code == CM_ERROR_TOOBIG) {
2155 error = 11; /* bad format */
2157 else if (code == CM_ERROR_INVAL) {
2158 class = 2; /* server non-specific error code */
2161 else if (code == CM_ERROR_BADFD) {
2163 error = 6; /* invalid file handle */
2165 else if (code == CM_ERROR_BADFDOP) {
2166 class = 1; /* invalid op on FD */
2169 else if (code == CM_ERROR_EXISTS) {
2171 error = 80; /* file already exists */
2173 else if (code == CM_ERROR_NOTEMPTY) {
2175 error = 5; /* delete directory not empty */
2177 else if (code == CM_ERROR_CROSSDEVLINK) {
2179 error = 17; /* EXDEV */
2181 else if (code == CM_ERROR_NOTDIR) {
2182 class = 1; /* bad path */
2185 else if (code == CM_ERROR_ISDIR) {
2186 class = 1; /* access denied; DOS doesn't have a good match */
2189 else if (code == CM_ERROR_BADOP) {
2193 else if (code == CM_ERROR_BADSHARENAME) {
2197 else if (code == CM_ERROR_NOIPC) {
2199 error = 4; /* bad access */
2201 else if (code == CM_ERROR_CLOCKSKEW) {
2202 class = 1; /* invalid function */
2205 else if (code == CM_ERROR_BADTID) {
2209 else if (code == CM_ERROR_USESTD) {
2213 else if (code == CM_ERROR_REMOTECONN) {
2217 else if (code == CM_ERROR_QUOTA) {
2218 if (vcp->flags & SMB_VCFLAG_USEV3) {
2220 error = 39; /* disk full */
2224 error = 5; /* access denied */
2227 else if (code == CM_ERROR_SPACE) {
2228 if (vcp->flags & SMB_VCFLAG_USEV3) {
2230 error = 39; /* disk full */
2234 error = 5; /* access denied */
2237 else if (code == CM_ERROR_PARTIALWRITE) {
2239 error = 39; /* disk full */
2241 else if (code == CM_ERROR_ATSYS) {
2243 error = 2; /* ENOENT */
2245 else if (code == CM_ERROR_WOULDBLOCK) {
2247 error = 33; /* lock conflict */
2249 else if (code == CM_ERROR_NOFILES) {
2251 error = 18; /* no files in search */
2253 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2255 error = 183; /* Samba uses this */
2264 osi_Log3(smb_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2267 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2269 return CM_ERROR_BADOP;
2272 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2274 unsigned short EchoCount, i;
2275 char *data, *outdata;
2278 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2280 for (i=1; i<=EchoCount; i++) {
2281 data = smb_GetSMBData(inp, &dataSize);
2282 smb_SetSMBParm(outp, 0, i);
2283 smb_SetSMBDataLength(outp, dataSize);
2284 outdata = smb_GetSMBData(outp, NULL);
2285 memcpy(outdata, data, dataSize);
2286 smb_SendPacket(vcp, outp);
2292 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2295 long count, minCount, finalCount;
2299 cm_user_t *userp = NULL;
2303 char *rawBuf = NULL;
2305 dos_ptr rawBuf = NULL;
2312 fd = smb_GetSMBParm(inp, 0);
2313 count = smb_GetSMBParm(inp, 3);
2314 minCount = smb_GetSMBParm(inp, 4);
2315 offset.HighPart = 0; /* too bad */
2316 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2318 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2319 fd, offset.LowPart, count);
2321 fidp = smb_FindFID(vcp, fd, 0);
2325 lock_ObtainMutex(&smb_RawBufLock);
2327 /* Get a raw buf, from head of list */
2328 rawBuf = smb_RawBufs;
2330 smb_RawBufs = *(char **)smb_RawBufs;
2332 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2335 lock_ReleaseMutex(&smb_RawBufLock);
2339 if (fidp->flags & SMB_FID_IOCTL)
2342 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2344 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2347 /* Give back raw buffer */
2348 lock_ObtainMutex(&smb_RawBufLock);
2350 *((char **) rawBuf) = smb_RawBufs;
2352 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2355 smb_RawBufs = rawBuf;
2356 lock_ReleaseMutex(&smb_RawBufLock);
2359 smb_ReleaseFID(fidp);
2363 userp = smb_GetUser(vcp, inp);
2366 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2368 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2369 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2370 userp, &finalCount, TRUE /* rawFlag */);
2377 cm_ReleaseUser(userp);
2380 smb_ReleaseFID(fidp);
2385 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2387 memset((char *)ncbp, 0, sizeof(NCB));
2389 ncbp->ncb_length = (unsigned short) finalCount;
2390 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2391 ncbp->ncb_lana_num = vcp->lana;
2392 ncbp->ncb_command = NCBSEND;
2393 ncbp->ncb_buffer = rawBuf;
2396 code = Netbios(ncbp);
2398 code = Netbios(ncbp, dos_ncb);
2401 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2404 /* Give back raw buffer */
2405 lock_ObtainMutex(&smb_RawBufLock);
2407 *((char **) rawBuf) = smb_RawBufs;
2409 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2412 smb_RawBufs = rawBuf;
2413 lock_ReleaseMutex(&smb_RawBufLock);
2419 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2424 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2429 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2435 int protoIndex; /* index we're using */
2440 char protocol_array[10][1024]; /* protocol signature of the client */
2443 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2447 DWORD now = GetCurrentTime();
2448 if (now - last_msg_time >= 30000
2449 && now - last_msg_time <= 90000) {
2451 "Setting dead_vcp %x", active_vcp);
2453 smb_ReleaseVC(dead_vcp);
2455 "Previous dead_vcp %x", dead_vcp);
2457 smb_HoldVC(active_vcp);
2458 dead_vcp = active_vcp;
2459 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2464 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2466 namep = smb_GetSMBData(inp, &dbytes);
2469 coreProtoIndex = -1; /* not found */
2472 while(namex < dbytes) {
2473 osi_Log1(smb_logp, "Protocol %s",
2474 osi_LogSaveString(smb_logp, namep+1));
2475 strcpy(protocol_array[tcounter], namep+1);
2477 /* namep points at the first protocol, or really, a 0x02
2478 * byte preceding the null-terminated ASCII name.
2480 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2481 coreProtoIndex = tcounter;
2483 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2484 v3ProtoIndex = tcounter;
2486 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2487 NTProtoIndex = tcounter;
2490 /* compute size of protocol entry */
2491 entryLength = strlen(namep+1);
2492 entryLength += 2; /* 0x02 bytes and null termination */
2494 /* advance over this protocol entry */
2495 namex += entryLength;
2496 namep += entryLength;
2497 tcounter++; /* which proto entry we're looking at */
2499 #ifndef NOMOREFILESFIX
2501 * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
2502 * the client is running by reading the protocol signature.
2503 * ie. the order in which it sends us the protocol list.
2505 * Special handling for Windows 2000 clients (defect 11765 )
2506 * <asanka:11Jun03> Proto signature is the same for Win XP. </>
2508 if (tcounter == 6) {
2510 smb_t *ip = (smb_t *) inp;
2511 smb_t *op = (smb_t *) outp;
2513 if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
2514 (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
2515 (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
2516 (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
2517 (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
2518 (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
2519 isWindows2000 = TRUE;
2520 osi_Log0(smb_logp, "Looks like a Windows 2000 client");
2522 * HACK: for now - just negotiate a lower protocol till we
2523 * figure out which flag/flag2 or some other field
2524 * (capabilities maybe?) to set in order for this to work
2525 * correctly with Windows 2000 clients (defect 11765)
2528 /* Things to try (after looking at tcpdump output could be
2529 * setting flags and flags2 to 0x98 and 0xc853 like this
2530 * op->reb = 0x98; op->flg2 = 0xc853;
2531 * osi_Log2(smb_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
2535 #endif /* NOMOREFILESFIX */
2537 if (NTProtoIndex != -1) {
2538 protoIndex = NTProtoIndex;
2539 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2541 else if (v3ProtoIndex != -1) {
2542 protoIndex = v3ProtoIndex;
2543 vcp->flags |= SMB_VCFLAG_USEV3;
2545 else if (coreProtoIndex != -1) {
2546 protoIndex = coreProtoIndex;
2547 vcp->flags |= SMB_VCFLAG_USECORE;
2549 else protoIndex = -1;
2551 if (protoIndex == -1)
2552 return CM_ERROR_INVAL;
2553 else if (NTProtoIndex != -1) {
2554 smb_SetSMBParm(outp, 0, protoIndex);
2555 smb_SetSMBParmByte(outp, 1, 0); /* share level security, no passwd encrypt */
2556 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2557 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2558 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2559 smb_SetSMBParmLong(outp, 5, 65536); /* raw buffer size */
2560 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2561 smb_SetSMBParm(outp, 8, 1);
2563 * Tried changing the capabilities to support for W2K - defect 117695
2564 * Maybe something else needs to be changed here?
2568 smb_SetSMBParmLong(outp, 9, 0x43fd);
2570 smb_SetSMBParmLong(outp, 9, 0x251);
2573 * 32-bit error codes *
2577 smb_SetSMBParmLong(outp, 9, 0x251);
2578 smb_SetSMBParmLong(outp, 11, 0);/* XXX server time: do we need? */
2579 smb_SetSMBParmLong(outp, 13, 0);/* XXX server date: do we need? */
2580 smb_SetSMBParm(outp, 15, 0); /* XXX server tzone: do we need? */
2581 smb_SetSMBParmByte(outp, 16, 0);/* Encryption key length */
2582 smb_SetSMBDataLength(outp, 0); /* perhaps should specify 8 bytes anyway */
2584 else if (v3ProtoIndex != -1) {
2585 smb_SetSMBParm(outp, 0, protoIndex);
2586 smb_SetSMBParm(outp, 1, 0); /* share level security, no passwd encrypt */
2587 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2588 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2589 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2590 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2591 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2592 smb_SetSMBParm(outp, 7, 1);
2593 smb_SetSMBParm(outp, 8, 0); /* XXX server time: do we need? */
2594 smb_SetSMBParm(outp, 9, 0); /* XXX server date: do we need? */
2595 smb_SetSMBParm(outp, 10, 0); /* XXX server tzone: do we need? */
2596 smb_SetSMBParm(outp, 11, 0); /* resvd */
2597 smb_SetSMBParm(outp, 12, 0); /* resvd */
2598 smb_SetSMBDataLength(outp, 0); /* perhaps should specify 8 bytes anyway */
2600 else if (coreProtoIndex != -1) {
2601 smb_SetSMBParm(outp, 0, protoIndex);
2602 smb_SetSMBDataLength(outp, 0);
2607 void smb_Daemon(void *parmp)
2614 if ((count % 360) == 0) /* every hour */
2615 smb_CalculateNowTZ();
2616 /* XXX GC dir search entries */
2620 void smb_WaitingLocksDaemon()
2622 smb_waitingLock_t *wL, *nwL;
2625 smb_packet_t *inp, *outp;
2630 lock_ObtainWrite(&smb_globalLock);
2631 nwL = smb_allWaitingLocks;
2633 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2642 lock_ObtainWrite(&smb_globalLock);
2644 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2645 lock_ReleaseWrite(&smb_globalLock);
2646 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2647 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2648 if (code == CM_ERROR_WOULDBLOCK) {
2650 if (wL->timeRemaining != 0xffffffff
2651 && (wL->timeRemaining -= 1000) < 0)
2660 ncbp->ncb_length = inp->ncb_length;
2661 inp->spacep = cm_GetSpace();
2663 /* Remove waitingLock from list */
2664 lock_ObtainWrite(&smb_globalLock);
2665 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2667 lock_ReleaseWrite(&smb_globalLock);
2669 /* Resume packet processing */
2671 smb_SetSMBDataLength(outp, 0);
2672 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2673 outp->resumeCode = code;
2675 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2678 cm_FreeSpace(inp->spacep);
2679 smb_FreePacket(inp);
2680 smb_FreePacket(outp);
2688 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2690 osi_Log0(smb_logp, "SMB receive get disk attributes");
2692 smb_SetSMBParm(outp, 0, 32000);
2693 smb_SetSMBParm(outp, 1, 64);
2694 smb_SetSMBParm(outp, 2, 1024);
2695 smb_SetSMBParm(outp, 3, 30000);
2696 smb_SetSMBParm(outp, 4, 0);
2697 smb_SetSMBDataLength(outp, 0);
2701 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2704 unsigned short newTid;
2705 char shareName[256];
2713 osi_Log0(smb_logp, "SMB receive tree connect");
2715 /* parse input parameters */
2716 tp = smb_GetSMBData(inp, NULL);
2717 pathp = smb_ParseASCIIBlock(tp, &tp);
2718 passwordp = smb_ParseASCIIBlock(tp, &tp);
2719 tp = strrchr(pathp, '\\');
2721 return CM_ERROR_BADSMB;
2722 strcpy(shareName, tp+1);
2724 userp = smb_GetUser(vcp, inp);
2726 lock_ObtainMutex(&vcp->mx);
2727 newTid = vcp->tidCounter++;
2728 lock_ReleaseMutex(&vcp->mx);
2730 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2731 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
2733 smb_ReleaseTID(tidp);
2734 return CM_ERROR_BADSHARENAME;
2736 lock_ObtainMutex(&tidp->mx);
2737 tidp->userp = userp;
2738 tidp->pathname = sharePath;
2739 lock_ReleaseMutex(&tidp->mx);
2740 smb_ReleaseTID(tidp);
2742 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2743 smb_SetSMBParm(rsp, 1, newTid);
2744 smb_SetSMBDataLength(rsp, 0);
2746 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2750 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2754 if (*inp++ != 0x1) return NULL;
2755 tlen = inp[0] + (inp[1]<<8);
2756 inp += 2; /* skip length field */
2759 *chainpp = inp + tlen;
2762 if (lengthp) *lengthp = tlen;
2767 /* set maskp to the mask part of the incoming path.
2768 * Mask is 11 bytes long (8.3 with the dot elided).
2769 * Returns true if succeeds with a valid name, otherwise it does
2770 * its best, but returns false.
2772 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2780 /* starts off valid */
2783 /* mask starts out all blanks */
2784 memset(maskp, ' ', 11);
2786 /* find last backslash, or use whole thing if there is none */
2787 tp = strrchr(pathp, '\\');
2788 if (!tp) tp = pathp;
2789 else tp++; /* skip slash */
2793 /* names starting with a dot are illegal */
2794 if (*tp == '.') valid8Dot3 = 0;
2798 if (tc == 0) return valid8Dot3;
2799 if (tc == '.' || tc == '"') break;
2800 if (i < 8) *up++ = tc;
2801 else valid8Dot3 = 0;
2804 /* if we get here, tp point after the dot */
2805 up = maskp+8; /* ext goes here */
2812 if (tc == '.' || tc == '"')
2815 /* copy extension if not too long */
2825 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2835 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2837 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2841 /* otherwise, we have a valid 8.3 name; see if we have a match,
2842 * treating '?' as a wildcard in maskp (but not in the file name).
2844 tp1 = umask; /* real name, in mask format */
2845 tp2 = maskp; /* mask, in mask format */
2846 for(i=0; i<11; i++) {
2847 tc1 = *tp1++; /* char from real name */
2848 tc2 = *tp2++; /* char from mask */
2849 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
2850 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
2853 if (tc2 == '?' && tc1 != ' ')
2860 /* we got a match */
2864 char *smb_FindMask(char *pathp)
2868 tp = strrchr(pathp, '\\'); /* find last slash */
2871 return tp+1; /* skip the slash */
2873 return pathp; /* no slash, return the entire path */
2876 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2878 unsigned char *pathp;
2880 unsigned char mask[11];
2881 unsigned char *statBlockp;
2882 unsigned char initStatBlock[21];
2885 osi_Log0(smb_logp, "SMB receive search volume");
2887 /* pull pathname and stat block out of request */
2888 tp = smb_GetSMBData(inp, NULL);
2889 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
2890 osi_assert(pathp != NULL);
2891 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
2892 osi_assert(statBlockp != NULL);
2894 statBlockp = initStatBlock;
2898 /* for returning to caller */
2899 smb_Get8Dot3MaskFromPath(mask, pathp);
2901 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
2902 tp = smb_GetSMBData(outp, NULL);
2904 *tp++ = 43; /* bytes in a dir entry */
2905 *tp++ = 0; /* high byte in counter */
2907 /* now marshall the dir entry, starting with the search status */
2908 *tp++ = statBlockp[0]; /* Reserved */
2909 memcpy(tp, mask, 11); tp += 11; /* FileName */
2911 /* now pass back server use info, with 1st byte non-zero */
2913 memset(tp, 0, 4); tp += 4; /* reserved for server use */
2915 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
2917 *tp++ = 0x8; /* attribute: volume */
2927 /* 4 byte file size */
2933 /* finally, null-terminated 8.3 pathname, which we set to AFS */
2934 memset(tp, ' ', 13);
2937 /* set the length of the data part of the packet to 43 + 3, for the dir
2938 * entry plus the 5 and the length fields.
2940 smb_SetSMBDataLength(outp, 46);
2944 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
2945 cm_user_t *userp, cm_req_t *reqp)
2953 smb_dirListPatch_t *patchp;
2954 smb_dirListPatch_t *npatchp;
2956 for(patchp = *dirPatchespp; patchp; patchp =
2957 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2958 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2960 lock_ObtainMutex(&scp->mx);
2961 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2962 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2964 lock_ReleaseMutex(&scp->mx);
2965 cm_ReleaseSCache(scp);
2968 dptr = patchp->dptr;
2970 attr = smb_Attributes(scp);
2971 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
2972 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2973 attr |= SMB_ATTR_HIDDEN;
2977 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2980 shortTemp = dosTime & 0xffff;
2981 *((u_short *)dptr) = shortTemp;
2984 /* and copy out date */
2985 shortTemp = (dosTime>>16) & 0xffff;
2986 *((u_short *)dptr) = shortTemp;
2989 /* copy out file length */
2990 *((u_long *)dptr) = scp->length.LowPart;
2992 lock_ReleaseMutex(&scp->mx);
2993 cm_ReleaseSCache(scp);
2996 /* now free the patches */
2997 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2998 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3002 /* and mark the list as empty */
3003 *dirPatchespp = NULL;
3008 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3017 smb_dirListPatch_t *dirListPatchesp;
3018 smb_dirListPatch_t *curPatchp;
3022 osi_hyper_t dirLength;
3023 osi_hyper_t bufferOffset;
3024 osi_hyper_t curOffset;
3026 unsigned char *inCookiep;
3027 smb_dirSearch_t *dsp;
3031 unsigned long clientCookie;
3032 cm_pageHeader_t *pageHeaderp;
3033 cm_user_t *userp = NULL;
3040 long nextEntryCookie;
3041 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3042 char resByte; /* reserved byte from the cookie */
3043 char *op; /* output data ptr */
3044 char *origOp; /* original value of op */
3045 cm_space_t *spacep; /* for pathname buffer */
3056 maxCount = smb_GetSMBParm(inp, 0);
3058 dirListPatchesp = NULL;
3060 caseFold = CM_FLAG_CASEFOLD;
3062 tp = smb_GetSMBData(inp, NULL);
3063 pathp = smb_ParseASCIIBlock(tp, &tp);
3064 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3066 /* bail out if request looks bad */
3067 if (!tp || !pathp) {
3068 return CM_ERROR_BADSMB;
3071 /* We can handle long names */
3072 if (vcp->flags & SMB_VCFLAG_USENT)
3073 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3075 /* make sure we got a whole search status */
3076 if (dataLength < 21) {
3077 nextCookie = 0; /* start at the beginning of the dir */
3080 attribute = smb_GetSMBParm(inp, 1);
3082 /* handle volume info in another function */
3083 if (attribute & 0x8)
3084 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3086 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3087 maxCount, osi_LogSaveString(smb_logp, pathp));
3089 if (*pathp == 0) { /* null pathp, treat as root dir */
3090 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3091 return CM_ERROR_NOFILES;
3095 dsp = smb_NewDirSearch(0);
3096 dsp->attribute = attribute;
3097 smb_Get8Dot3MaskFromPath(mask, pathp);
3098 memcpy(dsp->mask, mask, 11);
3100 /* track if this is likely to match a lot of entries */
3101 if (smb_IsStarMask(mask)) starPattern = 1;
3102 else starPattern = 0;
3105 /* pull the next cookie value out of the search status block */
3106 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3107 + (inCookiep[16]<<24);
3108 dsp = smb_FindDirSearch(inCookiep[12]);
3110 /* can't find dir search status; fatal error */
3111 return CM_ERROR_BADFD;
3113 attribute = dsp->attribute;
3114 resByte = inCookiep[0];
3116 /* copy out client cookie, in host byte order. Don't bother
3117 * interpreting it, since we're just passing it through, anyway.
3119 memcpy(&clientCookie, &inCookiep[17], 4);
3121 memcpy(mask, dsp->mask, 11);
3123 /* assume we're doing a star match if it has continued for more
3129 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3130 nextCookie, dsp->cookie, attribute);
3132 userp = smb_GetUser(vcp, inp);
3134 /* try to get the vnode for the path name next */
3135 lock_ObtainMutex(&dsp->mx);
3142 spacep = inp->spacep;
3143 smb_StripLastComponent(spacep->data, NULL, pathp);
3144 lock_ReleaseMutex(&dsp->mx);
3145 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3146 code = cm_NameI(cm_rootSCachep, spacep->data,
3147 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3148 lock_ObtainMutex(&dsp->mx);
3150 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3152 /* we need one hold for the entry we just stored into,
3153 * and one for our own processing. When we're done with this
3154 * function, we'll drop the one for our own processing.
3155 * We held it once from the namei call, and so we do another hold
3159 lock_ObtainMutex(&scp->mx);
3160 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3161 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3162 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3163 dsp->flags |= SMB_DIRSEARCH_BULKST;
3165 lock_ReleaseMutex(&scp->mx);
3168 lock_ReleaseMutex(&dsp->mx);
3170 cm_ReleaseUser(userp);
3171 smb_DeleteDirSearch(dsp);
3172 smb_ReleaseDirSearch(dsp);
3176 /* reserves space for parameter; we'll adjust it again later to the
3177 * real count of the # of entries we returned once we've actually
3178 * assembled the directory listing.
3180 smb_SetSMBParm(outp, 0, 0);
3182 /* get the directory size */
3183 lock_ObtainMutex(&scp->mx);
3184 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3185 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3187 lock_ReleaseMutex(&scp->mx);
3188 cm_ReleaseSCache(scp);
3189 cm_ReleaseUser(userp);
3190 smb_DeleteDirSearch(dsp);
3191 smb_ReleaseDirSearch(dsp);
3195 dirLength = scp->length;
3197 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3198 curOffset.HighPart = 0;
3199 curOffset.LowPart = nextCookie;
3200 origOp = op = smb_GetSMBData(outp, NULL);
3201 /* and write out the basic header */
3202 *op++ = 5; /* variable block */
3203 op += 2; /* skip vbl block length; we'll fill it in later */
3207 /* make sure that curOffset.LowPart doesn't point to the first
3208 * 32 bytes in the 2nd through last dir page, and that it doesn't
3209 * point at the first 13 32-byte chunks in the first dir page,
3210 * since those are dir and page headers, and don't contain useful
3213 temp = curOffset.LowPart & (2048-1);
3214 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3215 /* we're in the first page */
3216 if (temp < 13*32) temp = 13*32;
3219 /* we're in a later dir page */
3220 if (temp < 32) temp = 32;
3223 /* make sure the low order 5 bits are zero */
3226 /* now put temp bits back ito curOffset.LowPart */
3227 curOffset.LowPart &= ~(2048-1);
3228 curOffset.LowPart |= temp;
3230 /* check if we've returned all the names that will fit in the
3233 if (returnedNames >= maxCount)
3236 /* check if we've passed the dir's EOF */
3237 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3239 /* see if we can use the bufferp we have now; compute in which page
3240 * the current offset would be, and check whether that's the offset
3241 * of the buffer we have. If not, get the buffer.
3243 thyper.HighPart = curOffset.HighPart;
3244 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3245 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3248 buf_Release(bufferp);
3251 lock_ReleaseMutex(&scp->mx);
3252 lock_ObtainRead(&scp->bufCreateLock);
3253 code = buf_Get(scp, &thyper, &bufferp);
3254 lock_ReleaseRead(&scp->bufCreateLock);
3256 /* now, if we're doing a star match, do bulk fetching of all of
3257 * the status info for files in the dir.
3260 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3262 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3263 && LargeIntegerGreaterThanOrEqualTo(thyper,
3264 scp->bulkStatProgress)) {
3265 /* Don't bulk stat if risking timeout */
3266 int now = GetCurrentTime();
3267 if (now - req.startTime > 5000) {
3268 scp->bulkStatProgress = thyper;
3269 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3270 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3272 cm_TryBulkStat(scp, &thyper, userp, &req);
3276 lock_ObtainMutex(&scp->mx);
3279 bufferOffset = thyper;
3281 /* now get the data in the cache */
3283 code = cm_SyncOp(scp, bufferp, userp, &req,
3285 CM_SCACHESYNC_NEEDCALLBACK
3286 | CM_SCACHESYNC_READ);
3289 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3291 /* otherwise, load the buffer and try again */
3292 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3297 buf_Release(bufferp);
3301 } /* if (wrong buffer) ... */
3303 /* now we have the buffer containing the entry we're interested in; copy
3304 * it out if it represents a non-deleted entry.
3306 entryInDir = curOffset.LowPart & (2048-1);
3307 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3309 /* page header will help tell us which entries are free. Page header
3310 * can change more often than once per buffer, since AFS 3 dir page size
3311 * may be less than (but not more than a buffer package buffer.
3313 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3314 temp &= ~(2048 - 1); /* turn off intra-page bits */
3315 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3317 /* now determine which entry we're looking at in the page. If it is
3318 * free (there's a free bitmap at the start of the dir), we should
3319 * skip these 32 bytes.
3321 slotInPage = (entryInDir & 0x7e0) >> 5;
3322 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3323 /* this entry is free */
3324 numDirChunks = 1; /* only skip this guy */
3328 tp = bufferp->datap + entryInBuffer;
3329 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3331 /* while we're here, compute the next entry's location, too,
3332 * since we'll need it when writing out the cookie into the dir
3335 * XXXX Probably should do more sanity checking.
3337 numDirChunks = cm_NameEntries(dep->name, NULL);
3339 /* compute the offset of the cookie representing the next entry */
3340 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3342 /* Compute 8.3 name if necessary */
3343 actualName = dep->name;
3344 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3345 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3346 actualName = shortName;
3349 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3350 /* this is one of the entries to use: it is not deleted
3351 * and it matches the star pattern we're looking for.
3354 /* Eliminate entries that don't match requested
3357 /* no hidden files */
3358 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3361 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3363 /* We have already done the cm_TryBulkStat above */
3364 fid.cell = scp->fid.cell;
3365 fid.volume = scp->fid.volume;
3366 fid.vnode = ntohl(dep->fid.vnode);
3367 fid.unique = ntohl(dep->fid.unique);
3368 fileType = cm_FindFileType(&fid);
3369 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3370 "has filetype %d", dep->name,
3372 if (fileType == CM_SCACHETYPE_DIRECTORY)
3377 memcpy(op, mask, 11); op += 11;
3378 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3379 *op++ = nextEntryCookie & 0xff;
3380 *op++ = (nextEntryCookie>>8) & 0xff;
3381 *op++ = (nextEntryCookie>>16) & 0xff;
3382 *op++ = (nextEntryCookie>>24) & 0xff;
3383 memcpy(op, &clientCookie, 4); op += 4;
3385 /* now we emit the attribute. This is sort of tricky,
3386 * since we need to really stat the file to find out
3387 * what type of entry we've got. Right now, we're
3388 * copying out data from a buffer, while holding the
3389 * scp locked, so it isn't really convenient to stat
3390 * something now. We'll put in a place holder now,
3391 * and make a second pass before returning this to get
3392 * the real attributes. So, we just skip the data for
3393 * now, and adjust it later. We allocate a patch
3394 * record to make it easy to find this point later.
3395 * The replay will happen at a time when it is safe to
3396 * unlock the directory.
3398 curPatchp = malloc(sizeof(*curPatchp));
3399 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3400 curPatchp->dptr = op;
3401 curPatchp->fid.cell = scp->fid.cell;
3402 curPatchp->fid.volume = scp->fid.volume;
3403 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3404 curPatchp->fid.unique = ntohl(dep->fid.unique);
3406 /* do hidden attribute here since name won't be around when applying
3410 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3411 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3413 curPatchp->flags = 0;
3415 op += 9; /* skip attr, time, date and size */
3417 /* zero out name area. The spec says to pad with
3418 * spaces, but Samba doesn't, and neither do we.
3422 /* finally, we get to copy out the name; we know that
3423 * it fits in 8.3 or the pattern wouldn't match, but it
3424 * never hurts to be sure.
3426 strncpy(op, actualName, 13);
3428 /* Uppercase if requested by client */
3429 if ((((smb_t *)inp)->flg2 & 1) == 0)
3434 /* now, adjust the # of entries copied */
3436 } /* if we're including this name */
3439 /* and adjust curOffset to be where the new cookie is */
3440 thyper.HighPart = 0;
3441 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3442 curOffset = LargeIntegerAdd(thyper, curOffset);
3443 } /* while copying data for dir listing */
3445 /* release the mutex */
3446 lock_ReleaseMutex(&scp->mx);
3447 if (bufferp) buf_Release(bufferp);
3449 /* apply and free last set of patches; if not doing a star match, this
3450 * will be empty, but better safe (and freeing everything) than sorry.
3452 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3454 /* special return code for unsuccessful search */
3455 if (code == 0 && dataLength < 21 && returnedNames == 0)
3456 code = CM_ERROR_NOFILES;
3458 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3459 returnedNames, code);
3462 smb_DeleteDirSearch(dsp);
3463 smb_ReleaseDirSearch(dsp);
3464 cm_ReleaseSCache(scp);
3465 cm_ReleaseUser(userp);
3469 /* finalize the output buffer */
3470 smb_SetSMBParm(outp, 0, returnedNames);
3471 temp = (long) (op - origOp);
3472 smb_SetSMBDataLength(outp, temp);
3474 /* the data area is a variable block, which has a 5 (already there)
3475 * followed by the length of the # of data bytes. We now know this to
3476 * be "temp," although that includes the 3 bytes of vbl block header.
3477 * Deduct for them and fill in the length field.
3479 temp -= 3; /* deduct vbl block info */
3480 osi_assert(temp == (43 * returnedNames));
3481 origOp[1] = temp & 0xff;
3482 origOp[2] = (temp>>8) & 0xff;
3483 if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3484 smb_ReleaseDirSearch(dsp);
3485 cm_ReleaseSCache(scp);
3486 cm_ReleaseUser(userp);
3490 /* verify that this is a valid path to a directory. I don't know why they
3491 * don't use the get file attributes call.
3493 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3497 cm_scache_t *rootScp;
3498 cm_scache_t *newScp;
3507 pathp = smb_GetSMBData(inp, NULL);
3508 pathp = smb_ParseASCIIBlock(pathp, NULL);
3509 osi_Log1(smb_logp, "SMB receive check path %s",
3510 osi_LogSaveString(smb_logp, pathp));
3513 return CM_ERROR_BADFD;
3516 rootScp = cm_rootSCachep;
3518 userp = smb_GetUser(vcp, inp);
3520 caseFold = CM_FLAG_CASEFOLD;
3522 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3523 code = cm_NameI(rootScp, pathp,
3524 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3525 userp, tidPathp, &req, &newScp);
3528 cm_ReleaseUser(userp);
3532 /* now lock the vnode with a callback; returns with newScp locked */
3533 lock_ObtainMutex(&newScp->mx);
3534 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3535 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3536 if (code && code != CM_ERROR_NOACCESS) {
3537 lock_ReleaseMutex(&newScp->mx);
3538 cm_ReleaseSCache(newScp);
3539 cm_ReleaseUser(userp);
3543 attrs = smb_Attributes(newScp);
3545 if (!(attrs & 0x10))
3546 code = CM_ERROR_NOTDIR;
3548 lock_ReleaseMutex(&newScp->mx);
3550 cm_ReleaseSCache(newScp);
3551 cm_ReleaseUser(userp);
3555 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3559 cm_scache_t *rootScp;
3560 unsigned short attribute;
3562 cm_scache_t *newScp;
3571 /* decode basic attributes we're passed */
3572 attribute = smb_GetSMBParm(inp, 0);
3573 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3575 pathp = smb_GetSMBData(inp, NULL);
3576 pathp = smb_ParseASCIIBlock(pathp, NULL);
3579 return CM_ERROR_BADSMB;
3582 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3583 dosTime, attribute);
3585 rootScp = cm_rootSCachep;
3587 userp = smb_GetUser(vcp, inp);
3589 caseFold = CM_FLAG_CASEFOLD;
3591 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3592 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3593 tidPathp, &req, &newScp);
3596 cm_ReleaseUser(userp);
3600 /* now lock the vnode with a callback; returns with newScp locked; we
3601 * need the current status to determine what the new status is, in some
3604 lock_ObtainMutex(&newScp->mx);
3605 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3606 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3608 lock_ReleaseMutex(&newScp->mx);
3609 cm_ReleaseSCache(newScp);
3610 cm_ReleaseUser(userp);
3614 /* Check for RO volume */
3615 if (newScp->flags & CM_SCACHEFLAG_RO) {
3616 lock_ReleaseMutex(&newScp->mx);
3617 cm_ReleaseSCache(newScp);
3618 cm_ReleaseUser(userp);
3619 return CM_ERROR_READONLY;
3622 /* prepare for setattr call */
3625 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3626 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3628 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3629 /* we're told to make a writable file read-only */
3630 attr.unixModeBits = newScp->unixModeBits & ~0222;
3631 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3633 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3634 /* we're told to make a read-only file writable */
3635 attr.unixModeBits = newScp->unixModeBits | 0222;
3636 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3638 lock_ReleaseMutex(&newScp->mx);
3640 /* now call setattr */
3642 code = cm_SetAttr(newScp, &attr, userp, &req);
3646 cm_ReleaseSCache(newScp);
3647 cm_ReleaseUser(userp);
3652 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3656 cm_scache_t *rootScp;
3657 cm_scache_t *newScp, *dscp;
3669 pathp = smb_GetSMBData(inp, NULL);
3670 pathp = smb_ParseASCIIBlock(pathp, NULL);
3673 return CM_ERROR_BADSMB;
3676 if (*pathp == 0) /* null path */
3679 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3680 osi_LogSaveString(smb_logp, pathp));
3682 rootScp = cm_rootSCachep;
3684 userp = smb_GetUser(vcp, inp);
3686 /* we shouldn't need this for V3 requests, but we seem to */
3687 caseFold = CM_FLAG_CASEFOLD;
3689 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3692 * XXX Strange hack XXX
3694 * As of Patch 5 (16 July 97), we are having the following problem:
3695 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3696 * requests to look up "desktop.ini" in all the subdirectories.
3697 * This can cause zillions of timeouts looking up non-existent cells
3698 * and volumes, especially in the top-level directory.
3700 * We have not found any way to avoid this or work around it except
3701 * to explicitly ignore the requests for mount points that haven't
3702 * yet been evaluated and for directories that haven't yet been
3705 * We should modify this hack to provide a fake desktop.ini file
3706 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3708 spacep = inp->spacep;
3709 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3710 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3711 code = cm_NameI(rootScp, spacep->data,
3712 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3713 userp, tidPathp, &req, &dscp);
3715 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3716 && !dscp->mountRootFidp)
3717 code = CM_ERROR_NOSUCHFILE;
3718 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3719 cm_buf_t *bp = buf_Find(dscp, &hzero);
3723 code = CM_ERROR_NOSUCHFILE;
3725 cm_ReleaseSCache(dscp);
3727 cm_ReleaseUser(userp);
3733 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3734 tidPathp, &req, &newScp);
3737 cm_ReleaseUser(userp);
3741 /* now lock the vnode with a callback; returns with newScp locked */
3742 lock_ObtainMutex(&newScp->mx);
3743 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3744 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3746 lock_ReleaseMutex(&newScp->mx);
3747 cm_ReleaseSCache(newScp);
3748 cm_ReleaseUser(userp);
3753 /* use smb_Attributes instead. Also the fact that a file is
3754 * in a readonly volume doesn't mean it shojuld be marked as RO
3756 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
3757 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
3758 attrs = SMB_ATTR_DIRECTORY;
3761 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
3762 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
3764 attrs = smb_Attributes(newScp);
3767 smb_SetSMBParm(outp, 0, attrs);
3769 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
3770 smb_SetSMBParm(outp, 1, dosTime & 0xffff);
3771 smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
3772 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
3773 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
3774 smb_SetSMBParm(outp, 5, 0);
3775 smb_SetSMBParm(outp, 6, 0);
3776 smb_SetSMBParm(outp, 7, 0);
3777 smb_SetSMBParm(outp, 8, 0);
3778 smb_SetSMBParm(outp, 9, 0);
3779 smb_SetSMBDataLength(outp, 0);
3780 lock_ReleaseMutex(&newScp->mx);
3782 cm_ReleaseSCache(newScp);
3783 cm_ReleaseUser(userp);
3788 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3792 osi_Log0(smb_logp, "SMB receive tree disconnect");
3794 /* find the tree and free it */
3795 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
3797 lock_ObtainMutex(&tidp->mx);
3798 tidp->flags |= SMB_TIDFLAG_DELETE;
3799 lock_ReleaseMutex(&tidp->mx);
3800 smb_ReleaseTID(tidp);
3806 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3824 pathp = smb_GetSMBData(inp, NULL);
3825 pathp = smb_ParseASCIIBlock(pathp, NULL);
3827 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
3829 #ifdef DEBUG_VERBOSE
3833 hexpath = osi_HexifyString( pathp );
3834 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
3839 share = smb_GetSMBParm(inp, 0);
3840 attribute = smb_GetSMBParm(inp, 1);
3842 spacep = inp->spacep;
3843 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3844 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3845 /* special case magic file name for receiving IOCTL requests
3846 * (since IOCTL calls themselves aren't getting through).
3848 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3849 smb_SetupIoctlFid(fidp, spacep);
3850 smb_SetSMBParm(outp, 0, fidp->fid);
3851 smb_SetSMBParm(outp, 1, 0); /* attrs */
3852 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
3853 smb_SetSMBParm(outp, 3, 0);
3854 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
3855 smb_SetSMBParm(outp, 5, 0x7fff);
3856 /* pass the open mode back */
3857 smb_SetSMBParm(outp, 6, (share & 0xf));
3858 smb_SetSMBDataLength(outp, 0);
3859 smb_ReleaseFID(fidp);
3863 userp = smb_GetUser(vcp, inp);
3865 caseFold = CM_FLAG_CASEFOLD;
3867 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3868 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3869 tidPathp, &req, &scp);
3872 cm_ReleaseUser(userp);
3876 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
3878 cm_ReleaseSCache(scp);
3879 cm_ReleaseUser(userp);
3883 /* don't need callback to check file type, since file types never
3884 * change, and namei and cm_Lookup all stat the object at least once on
3885 * a successful return.
3887 if (scp->fileType != CM_SCACHETYPE_FILE) {
3888 cm_ReleaseSCache(scp);
3889 cm_ReleaseUser(userp);
3890 return CM_ERROR_ISDIR;
3893 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3896 /* save a pointer to the vnode */
3899 if ((share & 0xf) == 0)
3900 fidp->flags |= SMB_FID_OPENREAD;
3901 else if ((share & 0xf) == 1)
3902 fidp->flags |= SMB_FID_OPENWRITE;
3904 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
3906 lock_ObtainMutex(&scp->mx);
3907 smb_SetSMBParm(outp, 0, fidp->fid);
3908 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
3909 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
3910 smb_SetSMBParm(outp, 2, dosTime & 0xffff);
3911 smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
3912 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
3913 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
3914 /* pass the open mode back; XXXX add access checks */
3915 smb_SetSMBParm(outp, 6, (share & 0xf));
3916 smb_SetSMBDataLength(outp, 0);
3917 lock_ReleaseMutex(&scp->mx);
3920 cm_Open(scp, 0, userp);
3922 /* send and free packet */
3923 smb_ReleaseFID(fidp);
3924 cm_ReleaseUser(userp);
3925 /* don't release scp, since we've squirreled away the pointer in the fid struct */
3929 typedef struct smb_unlinkRock {
3934 char *maskp; /* pointer to the star pattern */
3939 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3942 smb_unlinkRock_t *rockp;
3950 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
3951 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
3952 caseFold |= CM_FLAG_8DOT3;
3954 matchName = dep->name;
3955 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3957 && (rockp->flags & SMB_MASKFLAG_TILDE)
3958 && !cm_Is8Dot3(dep->name)) {
3959 cm_Gen8Dot3Name(dep, shortName, NULL);
3960 matchName = shortName;
3961 /* 8.3 matches are always case insensitive */
3962 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
3965 osi_Log1(smb_logp, "Unlinking %s",
3966 osi_LogSaveString(smb_logp, matchName));
3967 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
3968 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3969 smb_NotifyChange(FILE_ACTION_REMOVED,
3970 FILE_NOTIFY_CHANGE_FILE_NAME,
3971 dscp, dep->name, NULL, TRUE);
3974 /* If we made a case sensitive exact match, we might as well quit now. */
3975 if(!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
3976 code = CM_ERROR_STOPNOW;
3984 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3993 smb_unlinkRock_t rock;
4002 attribute = smb_GetSMBParm(inp, 0);
4004 tp = smb_GetSMBData(inp, NULL);
4005 pathp = smb_ParseASCIIBlock(tp, &tp);
4007 osi_Log1(smb_logp, "SMB receive unlink %s",
4008 osi_LogSaveString(smb_logp, pathp));
4010 spacep = inp->spacep;
4011 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4013 userp = smb_GetUser(vcp, inp);
4015 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4017 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4018 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4022 cm_ReleaseUser(userp);
4026 /* otherwise, scp points to the parent directory. */
4033 rock.maskp = smb_FindMask(pathp);
4034 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4037 thyper.HighPart = 0;
4043 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4044 * match. If that fails, we do a case insensitve match.
4046 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4047 !smb_IsStarMask(rock.maskp)) {
4048 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4051 thyper.HighPart = 0;
4052 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4057 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4059 if (code == CM_ERROR_STOPNOW)
4062 cm_ReleaseUser(userp);
4064 cm_ReleaseSCache(dscp);
4066 if (code == 0 && !rock.any)
4067 code = CM_ERROR_NOSUCHFILE;
4071 typedef struct smb_renameRock {
4072 cm_scache_t *odscp; /* old dir */
4073 cm_scache_t *ndscp; /* new dir */
4074 cm_user_t *userp; /* user */
4075 cm_req_t *reqp; /* request struct */
4076 smb_vc_t *vcp; /* virtual circuit */
4077 char *maskp; /* pointer to star pattern of old file name */
4078 int flags; /* tilde, casefold, etc */
4079 char *newNamep; /* ptr to the new file's name */
4082 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4085 smb_renameRock_t *rockp;
4090 rockp = (smb_renameRock_t *) vrockp;
4092 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4093 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4094 caseFold |= CM_FLAG_8DOT3;
4096 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4098 && (rockp->flags & SMB_MASKFLAG_TILDE)
4099 && !cm_Is8Dot3(dep->name)) {
4100 cm_Gen8Dot3Name(dep, shortName, NULL);
4101 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4104 code = cm_Rename(rockp->odscp, dep->name,
4105 rockp->ndscp, rockp->newNamep, rockp->userp,
4107 /* if the call worked, stop doing the search now, since we
4108 * really only want to rename one file.
4111 code = CM_ERROR_STOPNOW;
4118 long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4124 cm_space_t *spacep = NULL;
4125 smb_renameRock_t rock;
4126 cm_scache_t *oldDscp = NULL;
4127 cm_scache_t *newDscp = NULL;
4128 cm_scache_t *tmpscp= NULL;
4129 cm_scache_t *tmpscp2 = NULL;
4141 tp = smb_GetSMBData(inp, NULL);
4142 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4143 newPathp = smb_ParseASCIIBlock(tp, &tp);
4145 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4146 osi_LogSaveString(smb_logp, oldPathp),
4147 osi_LogSaveString(smb_logp, newPathp));
4149 spacep = inp->spacep;
4150 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4152 userp = smb_GetUser(vcp, inp);
4155 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4156 * what actually exists is foo/baz. I don't know why the code used to be
4157 * the way it was. 1/29/96
4159 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4161 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4163 * caseFold = CM_FLAG_CASEFOLD;
4165 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4167 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4168 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4169 userp, tidPathp, &req, &oldDscp);
4172 cm_ReleaseUser(userp);
4176 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4177 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4178 userp, tidPathp, &req, &newDscp);
4181 cm_ReleaseSCache(oldDscp);
4182 cm_ReleaseUser(userp);
4186 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4187 * next, get the component names, and lower case them.
4190 /* handle the old name first */
4192 oldLastNamep = oldPathp;
4196 /* and handle the new name, too */
4198 newLastNamep = newPathp;
4202 /* TODO: The old name could be a wildcard. The new name must not be */
4204 /* do the vnode call */
4205 rock.odscp = oldDscp;
4206 rock.ndscp = newDscp;
4210 rock.maskp = oldLastNamep;
4211 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4212 rock.newNamep = newLastNamep;
4214 /* Check if the file already exists; if so return error */
4215 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4216 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4217 osi_Log2(afsd_logp, " lookup returns %ld for [%s]", code,
4218 osi_LogSaveString(afsd_logp, newLastNamep));
4220 /* Check if the old and the new names differ only in case. If so return
4221 * success, else return CM_ERROR_EXISTS
4223 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4225 /* This would be a success only if the old file is *as same as* the new file */
4226 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4228 if (tmpscp == tmpscp2)
4231 code = CM_ERROR_EXISTS;
4232 cm_ReleaseSCache(tmpscp2);
4235 code = CM_ERROR_NOSUCHFILE;
4238 /* file exist, do not rename, also fixes move */
4239 osi_Log0(afsd_logp, "Can't rename. Target already exists");
4240 code = CM_ERROR_EXISTS;
4244 cm_ReleaseSCache(tmpscp);
4245 cm_ReleaseSCache(newDscp);
4246 cm_ReleaseSCache(oldDscp);
4247 cm_ReleaseUser(userp);
4251 /* Now search the directory for the pattern, and do the appropriate rename when found */
4252 thyper.LowPart = 0; /* search dir from here */
4253 thyper.HighPart = 0;
4255 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4257 if (code == CM_ERROR_STOPNOW)
4260 code = CM_ERROR_NOSUCHFILE;
4262 /* Handle Change Notification */
4264 * Being lazy, not distinguishing between files and dirs in this
4265 * filter, since we'd have to do a lookup.
4267 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4268 if (oldDscp == newDscp) {
4269 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4270 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4271 filter, oldDscp, oldLastNamep,
4272 newLastNamep, TRUE);
4274 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4275 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4276 filter, oldDscp, oldLastNamep,
4278 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4279 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4280 filter, newDscp, newLastNamep,
4285 cm_ReleaseSCache(tmpscp);
4286 cm_ReleaseUser(userp);
4287 cm_ReleaseSCache(oldDscp);
4288 cm_ReleaseSCache(newDscp);
4292 typedef struct smb_rmdirRock {
4296 char *maskp; /* pointer to the star pattern */
4301 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4304 smb_rmdirRock_t *rockp;
4309 rockp = (smb_rmdirRock_t *) vrockp;
4311 matchName = dep->name;
4312 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4313 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4315 match = (strcmp(matchName, rockp->maskp) == 0);
4317 && (rockp->flags & SMB_MASKFLAG_TILDE)
4318 && !cm_Is8Dot3(dep->name)) {
4319 cm_Gen8Dot3Name(dep, shortName, NULL);
4320 matchName = shortName;
4321 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4324 osi_Log1(smb_logp, "Removing directory %s",
4325 osi_LogSaveString(smb_logp, matchName));
4326 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4327 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4328 smb_NotifyChange(FILE_ACTION_REMOVED,
4329 FILE_NOTIFY_CHANGE_DIR_NAME,
4330 dscp, dep->name, NULL, TRUE);
4339 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4347 smb_rmdirRock_t rock;
4356 tp = smb_GetSMBData(inp, NULL);
4357 pathp = smb_ParseASCIIBlock(tp, &tp);
4359 spacep = inp->spacep;
4360 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4362 userp = smb_GetUser(vcp, inp);
4364 caseFold = CM_FLAG_CASEFOLD;
4366 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4367 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4368 userp, tidPathp, &req, &dscp);
4371 cm_ReleaseUser(userp);
4375 /* otherwise, scp points to the parent directory. */
4382 rock.maskp = lastNamep;
4383 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4386 thyper.HighPart = 0;
4390 /* First do a case sensitive match, and if that fails, do a case insensitive match */
4391 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4392 if (code == 0 && !rock.any) {
4394 thyper.HighPart = 0;
4395 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4396 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4399 cm_ReleaseUser(userp);
4401 cm_ReleaseSCache(dscp);
4403 if (code == 0 && !rock.any)
4404 code = CM_ERROR_NOSUCHFILE;
4408 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4418 fid = smb_GetSMBParm(inp, 0);
4420 osi_Log1(smb_logp, "SMB flush fid %d", fid);
4422 fid = smb_ChainFID(fid, inp);
4423 fidp = smb_FindFID(vcp, fid, 0);
4424 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4426 smb_ReleaseFID(fidp);
4427 return CM_ERROR_BADFD;
4430 userp = smb_GetUser(vcp, inp);
4432 lock_ObtainMutex(&fidp->mx);
4433 if (fidp->flags & SMB_FID_OPENWRITE)
4434 code = cm_FSync(fidp->scp, userp, &req);
4437 lock_ReleaseMutex(&fidp->mx);
4439 smb_ReleaseFID(fidp);
4441 cm_ReleaseUser(userp);
4446 struct smb_FullNameRock {
4452 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4456 struct smb_FullNameRock *vrockp;
4458 vrockp = (struct smb_FullNameRock *)rockp;
4460 if (!cm_Is8Dot3(dep->name)) {
4461 cm_Gen8Dot3Name(dep, shortName, NULL);
4463 if (cm_stricmp(shortName, vrockp->name) == 0) {
4464 vrockp->fullName = strdup(dep->name);
4465 return CM_ERROR_STOPNOW;
4468 if (cm_stricmp(dep->name, vrockp->name) == 0
4469 && ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode
4470 && ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4471 vrockp->fullName = strdup(dep->name);
4472 return CM_ERROR_STOPNOW;
4477 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4478 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4480 struct smb_FullNameRock rock;
4486 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL,
4488 if (code == CM_ERROR_STOPNOW)
4489 *newPathp = rock.fullName;
4491 *newPathp = strdup(pathp);
4494 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4505 fid = smb_GetSMBParm(inp, 0);
4506 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4508 osi_Log1(smb_logp, "SMB close fid %d", fid);
4510 fid = smb_ChainFID(fid, inp);
4511 fidp = smb_FindFID(vcp, fid, 0);
4513 return CM_ERROR_BADFD;
4516 userp = smb_GetUser(vcp, inp);
4518 lock_ObtainMutex(&fidp->mx);
4520 /* Don't jump the gun on an async raw write */
4521 while (fidp->raw_writers) {
4522 lock_ReleaseMutex(&fidp->mx);
4523 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4524 lock_ObtainMutex(&fidp->mx);
4527 fidp->flags |= SMB_FID_DELETE;
4529 /* watch for ioctl closes, and read-only opens */
4530 if (fidp->scp != NULL
4531 && (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4532 == SMB_FID_OPENWRITE) {
4533 if (dosTime != 0 && dosTime != -1) {
4534 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4535 /* This fixes defect 10958 */
4536 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
4537 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
4539 code = cm_FSync(fidp->scp, userp, &req);
4544 if (fidp->flags & SMB_FID_DELONCLOSE) {
4545 cm_scache_t *dscp = fidp->NTopen_dscp;
4546 char *pathp = fidp->NTopen_pathp;
4549 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
4550 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
4551 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
4552 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4553 smb_NotifyChange(FILE_ACTION_REMOVED,
4554 FILE_NOTIFY_CHANGE_DIR_NAME,
4555 dscp, fullPathp, NULL, TRUE);
4559 code = cm_Unlink(dscp, fullPathp, userp, &req);
4560 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4561 smb_NotifyChange(FILE_ACTION_REMOVED,
4562 FILE_NOTIFY_CHANGE_FILE_NAME,
4563 dscp, fullPathp, NULL, TRUE);
4567 lock_ReleaseMutex(&fidp->mx);
4569 if (fidp->flags & SMB_FID_NTOPEN) {
4570 cm_ReleaseSCache(fidp->NTopen_dscp);
4571 free(fidp->NTopen_pathp);
4573 if (fidp->NTopen_wholepathp)
4574 free(fidp->NTopen_wholepathp);
4576 smb_ReleaseFID(fidp);
4577 cm_ReleaseUser(userp);
4582 * smb_ReadData -- common code for Read, Read And X, and Raw Read
4585 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4586 cm_user_t *userp, long *readp)
4588 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4589 cm_user_t *userp, long *readp, int dosflag)
4596 osi_hyper_t fileLength;
4598 osi_hyper_t lastByte;
4599 osi_hyper_t bufferOffset;
4600 long bufIndex, nbytes;
4610 lock_ObtainMutex(&fidp->mx);
4612 lock_ObtainMutex(&scp->mx);
4614 if (offset.HighPart == 0) {
4615 chunk = offset.LowPart >> cm_logChunkSize;
4616 if (chunk != fidp->curr_chunk) {
4617 fidp->prev_chunk = fidp->curr_chunk;
4618 fidp->curr_chunk = chunk;
4620 if (fidp->curr_chunk == fidp->prev_chunk + 1)
4624 /* start by looking up the file's end */
4625 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4626 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4627 if (code) goto done;
4629 /* now we have the entry locked, look up the length */
4630 fileLength = scp->length;
4632 /* adjust count down so that it won't go past EOF */
4633 thyper.LowPart = count;
4634 thyper.HighPart = 0;
4635 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
4637 if (LargeIntegerGreaterThan(thyper, fileLength)) {
4638 /* we'd read past EOF, so just stop at fileLength bytes.
4639 * Start by computing how many bytes remain in the file.
4641 thyper = LargeIntegerSubtract(fileLength, offset);
4643 /* if we are past EOF, read 0 bytes */
4644 if (LargeIntegerLessThanZero(thyper))
4647 count = thyper.LowPart;
4652 /* now, copy the data one buffer at a time,
4653 * until we've filled the request packet
4656 /* if we've copied all the data requested, we're done */
4657 if (count <= 0) break;
4659 /* otherwise, load up a buffer of data */
4660 thyper.HighPart = offset.HighPart;
4661 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4662 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4665 buf_Release(bufferp);
4668 lock_ReleaseMutex(&scp->mx);
4670 lock_ObtainRead(&scp->bufCreateLock);
4671 code = buf_Get(scp, &thyper, &bufferp);
4672 lock_ReleaseRead(&scp->bufCreateLock);
4674 lock_ObtainMutex(&scp->mx);
4675 if (code) goto done;
4676 bufferOffset = thyper;
4678 /* now get the data in the cache */
4680 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4681 CM_SCACHESYNC_NEEDCALLBACK
4682 | CM_SCACHESYNC_READ);
4683 if (code) goto done;
4685 if (cm_HaveBuffer(scp, bufferp, 0)) break;
4687 /* otherwise, load the buffer and try again */
4688 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4692 buf_Release(bufferp);
4696 } /* if (wrong buffer) ... */
4698 /* now we have the right buffer loaded. Copy out the
4699 * data from here to the user's buffer.
4701 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4703 /* and figure out how many bytes we want from this buffer */
4704 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
4705 if (nbytes > count) nbytes = count; /* don't go past EOF */
4707 /* now copy the data */
4710 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
4713 memcpy(op, bufferp->datap + bufIndex, nbytes);
4715 /* adjust counters, pointers, etc. */
4718 thyper.LowPart = nbytes;
4719 thyper.HighPart = 0;
4720 offset = LargeIntegerAdd(thyper, offset);
4724 lock_ReleaseMutex(&scp->mx);
4725 lock_ReleaseMutex(&fidp->mx);
4727 buf_Release(bufferp);
4729 if (code == 0 && sequential)
4730 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
4736 * smb_WriteData -- common code for Write and Raw Write
4739 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4740 cm_user_t *userp, long *writtenp)
4742 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4743 cm_user_t *userp, long *writtenp, int dosflag)
4750 osi_hyper_t fileLength; /* file's length at start of write */
4751 osi_hyper_t minLength; /* don't read past this */
4752 long nbytes; /* # of bytes to transfer this iteration */
4754 osi_hyper_t thyper; /* hyper tmp variable */
4755 osi_hyper_t bufferOffset;
4756 long bufIndex; /* index in buffer where our data is */
4758 osi_hyper_t writeBackOffset; /* offset of region to write back when
4769 lock_ObtainMutex(&fidp->mx);
4771 lock_ObtainMutex(&scp->mx);
4773 /* start by looking up the file's end */
4774 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4775 CM_SCACHESYNC_NEEDCALLBACK
4776 | CM_SCACHESYNC_SETSTATUS
4777 | CM_SCACHESYNC_GETSTATUS);
4781 /* make sure we have a writable FD */
4782 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
4783 code = CM_ERROR_BADFDOP;
4787 /* now we have the entry locked, look up the length */
4788 fileLength = scp->length;
4789 minLength = fileLength;
4790 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
4791 minLength = scp->serverLength;
4793 /* adjust file length if we extend past EOF */
4794 thyper.LowPart = count;
4795 thyper.HighPart = 0;
4796 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
4797 if (LargeIntegerGreaterThan(thyper, fileLength)) {
4798 /* we'd write past EOF, so extend the file */
4799 scp->mask |= CM_SCACHEMASK_LENGTH;
4800 scp->length = thyper;
4801 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
4803 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
4805 /* now, if the new position (thyper) and the old (offset) are in
4806 * different storeback windows, remember to store back the previous
4807 * storeback window when we're done with the write.
4809 if ((thyper.LowPart & (-cm_chunkSize)) !=
4810 (offset.LowPart & (-cm_chunkSize))) {
4811 /* they're different */
4813 writeBackOffset.HighPart = offset.HighPart;
4814 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
4819 /* now, copy the data one buffer at a time, until we've filled the
4822 /* if we've copied all the data requested, we're done */
4823 if (count <= 0) break;
4825 /* handle over quota or out of space */
4826 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
4827 *writtenp = written;
4831 /* otherwise, load up a buffer of data */
4832 thyper.HighPart = offset.HighPart;
4833 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4834 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4837 lock_ReleaseMutex(&bufferp->mx);
4838 buf_Release(bufferp);
4841 lock_ReleaseMutex(&scp->mx);
4843 lock_ObtainRead(&scp->bufCreateLock);
4844 code = buf_Get(scp, &thyper, &bufferp);
4845 lock_ReleaseRead(&scp->bufCreateLock);
4847 lock_ObtainMutex(&bufferp->mx);
4848 lock_ObtainMutex(&scp->mx);
4849 if (code) goto done;
4851 bufferOffset = thyper;
4853 /* now get the data in the cache */
4855 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4856 CM_SCACHESYNC_NEEDCALLBACK
4857 | CM_SCACHESYNC_WRITE
4858 | CM_SCACHESYNC_BUFLOCKED);
4862 /* If we're overwriting the entire buffer, or
4863 * if we're writing at or past EOF, mark the
4864 * buffer as current so we don't call
4865 * cm_GetBuffer. This skips the fetch from the
4866 * server in those cases where we're going to
4867 * obliterate all the data in the buffer anyway,
4868 * or in those cases where there is no useful
4869 * data at the server to start with.
4871 * Use minLength instead of scp->length, since
4872 * the latter has already been updated by this
4875 if (LargeIntegerGreaterThanOrEqualTo(
4876 bufferp->offset, minLength)
4877 || LargeIntegerEqualTo(offset, bufferp->offset)
4878 && (count >= buf_bufferSize
4879 || LargeIntegerGreaterThanOrEqualTo(
4880 LargeIntegerAdd(offset,
4881 ConvertLongToLargeInteger(count)),
4883 if (count < buf_bufferSize
4884 && bufferp->dataVersion == -1)
4885 memset(bufferp->datap, 0,
4887 bufferp->dataVersion = scp->dataVersion;
4890 if (cm_HaveBuffer(scp, bufferp, 1)) break;
4892 /* otherwise, load the buffer and try again */
4893 lock_ReleaseMutex(&bufferp->mx);
4894 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4896 lock_ReleaseMutex(&scp->mx);
4897 lock_ObtainMutex(&bufferp->mx);
4898 lock_ObtainMutex(&scp->mx);
4902 lock_ReleaseMutex(&bufferp->mx);
4903 buf_Release(bufferp);
4907 } /* if (wrong buffer) ... */
4909 /* now we have the right buffer loaded. Copy out the
4910 * data from here to the user's buffer.
4912 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4914 /* and figure out how many bytes we want from this buffer */
4915 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
4917 nbytes = count; /* don't go past end of request */
4919 /* now copy the data */
4922 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
4925 memcpy(bufferp->datap + bufIndex, op, nbytes);
4926 buf_SetDirty(bufferp);
4928 /* and record the last writer */
4929 if (bufferp->userp != userp) {
4932 cm_ReleaseUser(bufferp->userp);
4933 bufferp->userp = userp;
4936 /* adjust counters, pointers, etc. */
4940 thyper.LowPart = nbytes;
4941 thyper.HighPart = 0;
4942 offset = LargeIntegerAdd(thyper, offset);
4946 lock_ReleaseMutex(&scp->mx);
4947 lock_ReleaseMutex(&fidp->mx);
4949 lock_ReleaseMutex(&bufferp->mx);
4950 buf_Release(bufferp);
4953 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
4954 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
4955 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
4956 fidp->NTopen_dscp, fidp->NTopen_pathp,
4960 if (code == 0 && doWriteBack) {
4961 lock_ObtainMutex(&scp->mx);
4962 cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
4963 lock_ReleaseMutex(&scp->mx);
4964 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
4965 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
4971 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4974 long count, written = 0;
4979 cm_attr_t truncAttr; /* attribute struct used for truncating file */
4981 int inDataBlockCount;
4983 fd = smb_GetSMBParm(inp, 0);
4984 count = smb_GetSMBParm(inp, 1);
4985 offset.HighPart = 0; /* too bad */
4986 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
4988 op = smb_GetSMBData(inp, NULL);
4989 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
4991 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fd %d, off 0x%x, size 0x%x",
4992 fd, offset.LowPart, count);
4994 fd = smb_ChainFID(fd, inp);
4995 fidp = smb_FindFID(vcp, fd, 0);
4997 return CM_ERROR_BADFD;
5000 if (fidp->flags & SMB_FID_IOCTL)
5001 return smb_IoctlWrite(fidp, vcp, inp, outp);
5003 userp = smb_GetUser(vcp, inp);
5005 /* special case: 0 bytes transferred means truncate to this position */
5011 truncAttr.mask = CM_ATTRMASK_LENGTH;
5012 truncAttr.length.LowPart = offset.LowPart;
5013 truncAttr.length.HighPart = 0;
5014 lock_ObtainMutex(&fidp->mx);
5015 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5016 lock_ReleaseMutex(&fidp->mx);
5017 smb_SetSMBParm(outp, 0, /* count */ 0);
5018 smb_SetSMBDataLength(outp, 0);
5019 fidp->flags |= SMB_FID_LENGTHSETDONE;
5024 * Work around bug in NT client
5026 * When copying a file, the NT client should first copy the data,
5027 * then copy the last write time. But sometimes the NT client does
5028 * these in the wrong order, so the data copies would inadvertently
5029 * cause the last write time to be overwritten. We try to detect this,
5030 * and don't set client mod time if we think that would go against the
5033 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5034 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5035 fidp->scp->clientModTime = time(NULL);
5039 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5041 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5043 if (code == 0 && written < count)
5044 code = CM_ERROR_PARTIALWRITE;
5046 /* set the packet data length to 3 bytes for the data block header,
5047 * plus the size of the data.
5049 smb_SetSMBParm(outp, 0, written);
5050 smb_SetSMBDataLength(outp, 0);
5053 smb_ReleaseFID(fidp);
5054 cm_ReleaseUser(userp);
5059 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5060 NCB *ncbp, raw_write_cont_t *rwcp)
5073 fd = smb_GetSMBParm(inp, 0);
5074 fidp = smb_FindFID(vcp, fd, 0);
5076 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5077 rwcp->offset.LowPart, rwcp->count);
5079 userp = smb_GetUser(vcp, inp);
5083 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5086 rawBuf = (dos_ptr) rwcp->buf;
5087 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5088 (unsigned char *) rawBuf, userp,
5092 if (rwcp->writeMode & 0x1) { /* synchronous */
5095 smb_FormatResponsePacket(vcp, inp, outp);
5096 op = (smb_t *) outp;
5097 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5098 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5099 smb_SetSMBDataLength(outp, 0);
5100 smb_SendPacket(vcp, outp);
5101 smb_FreePacket(outp);
5103 else { /* asynchronous */
5104 lock_ObtainMutex(&fidp->mx);
5105 fidp->raw_writers--;
5106 if (fidp->raw_writers == 0)
5107 thrd_SetEvent(fidp->raw_write_event);
5108 lock_ReleaseMutex(&fidp->mx);
5111 /* Give back raw buffer */
5112 lock_ObtainMutex(&smb_RawBufLock);
5114 *((char **)rawBuf) = smb_RawBufs;
5116 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5118 smb_RawBufs = rawBuf;
5119 lock_ReleaseMutex(&smb_RawBufLock);
5121 smb_ReleaseFID(fidp);
5122 cm_ReleaseUser(userp);
5125 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5130 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5133 long count, written = 0;
5140 unsigned short writeMode;
5147 fd = smb_GetSMBParm(inp, 0);
5148 totalCount = smb_GetSMBParm(inp, 1);
5149 count = smb_GetSMBParm(inp, 10);
5150 offset.HighPart = 0; /* too bad */
5151 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5152 writeMode = smb_GetSMBParm(inp, 7);
5154 op = (char *) inp->data;
5155 op += smb_GetSMBParm(inp, 11);
5158 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5159 fd, offset.LowPart, count, writeMode);
5161 fd = smb_ChainFID(fd, inp);
5162 fidp = smb_FindFID(vcp, fd, 0);
5164 return CM_ERROR_BADFD;
5167 userp = smb_GetUser(vcp, inp);
5170 * Work around bug in NT client
5172 * When copying a file, the NT client should first copy the data,
5173 * then copy the last write time. But sometimes the NT client does
5174 * these in the wrong order, so the data copies would inadvertently
5175 * cause the last write time to be overwritten. We try to detect this,
5176 * and don't set client mod time if we think that would go against the
5179 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5180 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5181 fidp->scp->clientModTime = time(NULL);
5185 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5187 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5189 if (code == 0 && written < count)
5190 code = CM_ERROR_PARTIALWRITE;
5192 /* Get a raw buffer */
5195 lock_ObtainMutex(&smb_RawBufLock);
5197 /* Get a raw buf, from head of list */
5198 rawBuf = smb_RawBufs;
5200 smb_RawBufs = *(char **)smb_RawBufs;
5202 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5206 code = CM_ERROR_USESTD;
5208 lock_ReleaseMutex(&smb_RawBufLock);
5211 /* Don't allow a premature Close */
5212 if (code == 0 && (writeMode & 1) == 0) {
5213 lock_ObtainMutex(&fidp->mx);
5214 fidp->raw_writers++;
5215 thrd_ResetEvent(fidp->raw_write_event);
5216 lock_ReleaseMutex(&fidp->mx);
5219 smb_ReleaseFID(fidp);
5220 cm_ReleaseUser(userp);
5223 smb_SetSMBParm(outp, 0, written);
5224 smb_SetSMBDataLength(outp, 0);
5225 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5232 rwcp->offset.HighPart = 0;
5233 rwcp->offset.LowPart = offset.LowPart + count;
5234 rwcp->count = totalCount - count;
5235 rwcp->writeMode = writeMode;
5236 rwcp->alreadyWritten = written;
5238 /* set the packet data length to 3 bytes for the data block header,
5239 * plus the size of the data.
5241 smb_SetSMBParm(outp, 0, 0xffff);
5242 smb_SetSMBDataLength(outp, 0);
5247 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5250 long count, finalCount;
5257 fd = smb_GetSMBParm(inp, 0);
5258 count = smb_GetSMBParm(inp, 1);
5259 offset.HighPart = 0; /* too bad */
5260 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5262 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5263 fd, offset.LowPart, count);
5265 fd = smb_ChainFID(fd, inp);
5266 fidp = smb_FindFID(vcp, fd, 0);
5268 return CM_ERROR_BADFD;
5271 if (fidp->flags & SMB_FID_IOCTL) {
5272 return smb_IoctlRead(fidp, vcp, inp, outp);
5275 userp = smb_GetUser(vcp, inp);
5277 /* remember this for final results */
5278 smb_SetSMBParm(outp, 0, count);
5279 smb_SetSMBParm(outp, 1, 0);
5280 smb_SetSMBParm(outp, 2, 0);
5281 smb_SetSMBParm(outp, 3, 0);
5282 smb_SetSMBParm(outp, 4, 0);
5284 /* set the packet data length to 3 bytes for the data block header,
5285 * plus the size of the data.
5287 smb_SetSMBDataLength(outp, count+3);
5289 /* get op ptr after putting in the parms, since otherwise we don't
5290 * know where the data really is.
5292 op = smb_GetSMBData(outp, NULL);
5294 /* now emit the data block header: 1 byte of type and 2 bytes of length */
5295 *op++ = 1; /* data block marker */
5296 *op++ = (unsigned char) (count & 0xff);
5297 *op++ = (unsigned char) ((count >> 8) & 0xff);
5300 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5302 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5305 /* fix some things up */
5306 smb_SetSMBParm(outp, 0, finalCount);
5307 smb_SetSMBDataLength(outp, finalCount+3);
5309 smb_ReleaseFID(fidp);
5311 cm_ReleaseUser(userp);
5315 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5322 cm_scache_t *dscp; /* dir we're dealing with */
5323 cm_scache_t *scp; /* file we're creating */
5325 int initialModeBits;
5335 /* compute initial mode bits based on read-only flag in attributes */
5336 initialModeBits = 0777;
5338 tp = smb_GetSMBData(inp, NULL);
5339 pathp = smb_ParseASCIIBlock(tp, &tp);
5341 if (strcmp(pathp, "\\") == 0)
5342 return CM_ERROR_EXISTS;
5344 spacep = inp->spacep;
5345 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5347 userp = smb_GetUser(vcp, inp);
5349 caseFold = CM_FLAG_CASEFOLD;
5351 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5353 code = cm_NameI(cm_rootSCachep, spacep->data,
5354 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5355 userp, tidPathp, &req, &dscp);
5358 cm_ReleaseUser(userp);
5362 /* otherwise, scp points to the parent directory. Do a lookup, and
5363 * fail if we find it. Otherwise, we do the create.
5369 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5370 if (scp) cm_ReleaseSCache(scp);
5371 if (code != CM_ERROR_NOSUCHFILE) {
5372 if (code == 0) code = CM_ERROR_EXISTS;
5373 cm_ReleaseSCache(dscp);
5374 cm_ReleaseUser(userp);
5378 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5379 setAttr.clientModTime = time(NULL);
5380 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5381 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5382 smb_NotifyChange(FILE_ACTION_ADDED,
5383 FILE_NOTIFY_CHANGE_DIR_NAME,
5384 dscp, lastNamep, NULL, TRUE);
5386 /* we don't need this any longer */
5387 cm_ReleaseSCache(dscp);
5390 /* something went wrong creating or truncating the file */
5391 cm_ReleaseUser(userp);
5395 /* otherwise we succeeded */
5396 smb_SetSMBDataLength(outp, 0);
5397 cm_ReleaseUser(userp);
5402 BOOL smb_IsLegalFilename(char *filename)
5405 * Find the longest substring of filename that does not contain
5406 * any of the chars in illegalChars. If that substring is less
5407 * than the length of the whole string, then one or more of the
5408 * illegal chars is in filename.
5410 if (strcspn(filename, illegalChars) < strlen(filename))
5416 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5424 cm_scache_t *dscp; /* dir we're dealing with */
5425 cm_scache_t *scp; /* file we're creating */
5427 int initialModeBits;
5439 excl = (inp->inCom == 0x03)? 0 : 1;
5441 attributes = smb_GetSMBParm(inp, 0);
5442 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5444 /* compute initial mode bits based on read-only flag in attributes */
5445 initialModeBits = 0666;
5446 if (attributes & 1) initialModeBits &= ~0222;
5448 tp = smb_GetSMBData(inp, NULL);
5449 pathp = smb_ParseASCIIBlock(tp, &tp);
5451 spacep = inp->spacep;
5452 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5454 userp = smb_GetUser(vcp, inp);
5456 caseFold = CM_FLAG_CASEFOLD;
5458 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5459 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5460 userp, tidPathp, &req, &dscp);
5463 cm_ReleaseUser(userp);
5467 /* otherwise, scp points to the parent directory. Do a lookup, and
5468 * truncate the file if we find it, otherwise we create the file.
5470 if (!lastNamep) lastNamep = pathp;
5473 if (!smb_IsLegalFilename(lastNamep))
5474 return CM_ERROR_BADNTFILENAME;
5476 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
5477 #ifdef DEBUG_VERBOSE
5480 hexp = osi_HexifyString( lastNamep );
5481 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5486 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5487 if (code && code != CM_ERROR_NOSUCHFILE) {
5488 cm_ReleaseSCache(dscp);
5489 cm_ReleaseUser(userp);
5493 /* if we get here, if code is 0, the file exists and is represented by
5494 * scp. Otherwise, we have to create it.
5498 /* oops, file shouldn't be there */
5499 cm_ReleaseSCache(dscp);
5500 cm_ReleaseSCache(scp);
5501 cm_ReleaseUser(userp);
5502 return CM_ERROR_EXISTS;
5505 setAttr.mask = CM_ATTRMASK_LENGTH;
5506 setAttr.length.LowPart = 0;
5507 setAttr.length.HighPart = 0;
5508 code = cm_SetAttr(scp, &setAttr, userp, &req);
5511 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5512 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5513 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5515 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5516 smb_NotifyChange(FILE_ACTION_ADDED,
5517 FILE_NOTIFY_CHANGE_FILE_NAME,
5518 dscp, lastNamep, NULL, TRUE);
5519 if (!excl && code == CM_ERROR_EXISTS) {
5520 /* not an exclusive create, and someone else tried
5521 * creating it already, then we open it anyway. We
5522 * don't bother retrying after this, since if this next
5523 * fails, that means that the file was deleted after
5524 * we started this call.
5526 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
5529 setAttr.mask = CM_ATTRMASK_LENGTH;
5530 setAttr.length.LowPart = 0;
5531 setAttr.length.HighPart = 0;
5532 code = cm_SetAttr(scp, &setAttr, userp, &req);
5537 /* we don't need this any longer */
5538 cm_ReleaseSCache(dscp);
5541 /* something went wrong creating or truncating the file */
5542 if (scp) cm_ReleaseSCache(scp);
5543 cm_ReleaseUser(userp);
5547 /* make sure we only open files */
5548 if (scp->fileType != CM_SCACHETYPE_FILE) {
5549 cm_ReleaseSCache(scp);
5550 cm_ReleaseUser(userp);
5551 return CM_ERROR_ISDIR;
5554 /* now all we have to do is open the file itself */
5555 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5558 /* save a pointer to the vnode */
5561 /* always create it open for read/write */
5562 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
5564 smb_ReleaseFID(fidp);
5566 smb_SetSMBParm(outp, 0, fidp->fid);
5567 smb_SetSMBDataLength(outp, 0);
5569 cm_Open(scp, 0, userp);
5571 cm_ReleaseUser(userp);
5572 /* leave scp held since we put it in fidp->scp */
5576 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5589 fd = smb_GetSMBParm(inp, 0);
5590 whence = smb_GetSMBParm(inp, 1);
5591 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5593 /* try to find the file descriptor */
5594 fd = smb_ChainFID(fd, inp);
5595 fidp = smb_FindFID(vcp, fd, 0);
5596 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5597 return CM_ERROR_BADFD;
5600 userp = smb_GetUser(vcp, inp);
5602 lock_ObtainMutex(&fidp->mx);
5604 lock_ObtainMutex(&scp->mx);
5605 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5606 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5609 /* offset from current offset */
5610 offset += fidp->offset;
5612 else if (whence == 2) {
5613 /* offset from current EOF */
5614 offset += scp->length.LowPart;
5616 fidp->offset = offset;
5617 smb_SetSMBParm(outp, 0, offset & 0xffff);
5618 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
5619 smb_SetSMBDataLength(outp, 0);
5621 lock_ReleaseMutex(&scp->mx);
5622 lock_ReleaseMutex(&fidp->mx);
5623 smb_ReleaseFID(fidp);
5624 cm_ReleaseUser(userp);
5628 /* dispatch all of the requests received in a packet. Due to chaining, this may
5629 * be more than one request.
5631 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5632 NCB *ncbp, raw_write_cont_t *rwcp)
5636 unsigned long code = 0;
5637 unsigned char *outWctp;
5638 int nparms; /* # of bytes of parameters */
5640 int nbytes; /* bytes of data, excluding count */
5643 unsigned short errCode;
5644 unsigned long NTStatus;
5646 unsigned char errClass;
5647 unsigned int oldGen;
5648 DWORD oldTime, newTime;
5650 /* get easy pointer to the data */
5651 smbp = (smb_t *) inp->data;
5653 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
5654 /* setup the basic parms for the initial request in the packet */
5655 inp->inCom = smbp->com;
5656 inp->wctp = &smbp->wct;
5658 inp->ncb_length = ncbp->ncb_length;
5663 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
5664 /* log it and discard it */
5669 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5670 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
5672 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
5673 1, ncbp->ncb_length, ptbuf, inp);
5674 DeregisterEventSource(h);
5676 osi_Log1(smb_logp, "SMB message too short, len %d",
5683 /* We are an ongoing op */
5684 thrd_Increment(&ongoingOps);
5686 /* set up response packet for receiving output */
5687 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
5688 smb_FormatResponsePacket(vcp, inp, outp);
5689 outWctp = outp->wctp;
5691 /* Remember session generation number and time */
5692 oldGen = sessionGen;
5693 oldTime = GetCurrentTime();
5695 while(inp->inCom != 0xff) {
5696 dp = &smb_dispatchTable[inp->inCom];
5698 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
5699 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
5700 code = outp->resumeCode;
5704 /* process each request in the packet; inCom, wctp and inCount
5705 * are already set up.
5707 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
5710 /* now do the dispatch */
5711 /* start by formatting the response record a little, as a default */
5712 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
5714 outWctp[1] = 0xff; /* no operation */
5715 outWctp[2] = 0; /* padding */
5720 /* not a chained request, this is a more reasonable default */
5721 outWctp[0] = 0; /* wct of zero */
5722 outWctp[1] = 0; /* and bcc (word) of zero */
5726 /* once set, stays set. Doesn't matter, since we never chain
5727 * "no response" calls.
5729 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
5733 /* we have a recognized operation */
5735 if (inp->inCom == 0x1d)
5737 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
5740 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
5741 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
5742 code = (*(dp->procp)) (vcp, inp, outp);
5743 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5744 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5747 if (oldGen != sessionGen) {
5752 newTime = GetCurrentTime();
5753 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5754 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
5755 newTime - oldTime, ncbp->ncb_length);
5757 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
5758 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
5759 DeregisterEventSource(h);
5761 osi_Log1(smb_logp, "Pkt straddled session startup, "
5762 "ncb length %d", ncbp->ncb_length);
5767 /* bad opcode, fail the request, after displaying it */
5770 #endif /* NOTSERVICE */
5774 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
5775 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
5776 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
5777 if (code == IDCANCEL) showErrors = 0;
5780 code = CM_ERROR_BADOP;
5783 /* catastrophic failure: log as much as possible */
5784 if (code == CM_ERROR_BADSMB) {
5791 "Invalid SMB, ncb_length %d",
5794 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5795 sprintf(s, "Invalid SMB message, length %d",
5798 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
5799 1, ncbp->ncb_length, ptbuf, smbp);
5800 DeregisterEventSource(h);
5803 #endif /* NOTSERVICE */
5805 osi_Log1(smb_logp, "Invalid SMB message, length %d",
5809 code = CM_ERROR_INVAL;
5812 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
5813 thrd_Decrement(&ongoingOps);
5818 /* now, if we failed, turn the current response into an empty
5819 * one, and fill in the response packet's error code.
5822 if (vcp->flags & SMB_VCFLAG_STATUS32) {
5823 smb_MapNTError(code, &NTStatus);
5824 outWctp = outp->wctp;
5825 smbp = (smb_t *) &outp->data;
5826 if (code != CM_ERROR_PARTIALWRITE
5827 && code != CM_ERROR_BUFFERTOOSMALL) {
5828 /* nuke wct and bcc. For a partial
5829 * write, assume they're OK.
5835 smbp->rcls = (unsigned char) (NTStatus & 0xff);
5836 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
5837 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
5838 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
5839 smbp->flg2 |= 0x4000;
5843 smb_MapCoreError(code, vcp, &errCode, &errClass);
5844 outWctp = outp->wctp;
5845 smbp = (smb_t *) &outp->data;
5846 if (code != CM_ERROR_PARTIALWRITE) {
5847 /* nuke wct and bcc. For a partial
5848 * write, assume they're OK.
5854 smbp->errLow = (unsigned char) (errCode & 0xff);
5855 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
5856 smbp->rcls = errClass;
5859 } /* error occurred */
5861 /* if we're here, we've finished one request. Look to see if
5862 * this is a chained opcode. If it is, setup things to process
5863 * the chained request, and setup the output buffer to hold the
5864 * chained response. Start by finding the next input record.
5866 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
5867 break; /* not a chained req */
5868 tp = inp->wctp; /* points to start of last request */
5869 /* in a chained request, the first two
5870 * parm fields are required, and are
5871 * AndXCommand/AndXReserved and
5873 if (tp[0] < 2) break;
5874 if (tp[1] == 0xff) break; /* no more chained opcodes */
5876 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
5879 /* and now append the next output request to the end of this
5880 * last request. Begin by finding out where the last response
5881 * ends, since that's where we'll put our new response.
5883 outWctp = outp->wctp; /* ptr to out parameters */
5884 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
5885 nparms = outWctp[0] << 1;
5886 tp = outWctp + nparms + 1; /* now points to bcc field */
5887 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
5888 tp += 2 /* for the count itself */ + nbytes;
5889 /* tp now points to the new output record; go back and patch the
5890 * second parameter (off2) to point to the new record.
5892 temp = (unsigned int)tp - ((unsigned int) outp->data);
5893 outWctp[3] = (unsigned char) (temp & 0xff);
5894 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
5895 outWctp[2] = 0; /* padding */
5896 outWctp[1] = inp->inCom; /* next opcode */
5898 /* finally, setup for the next iteration */
5901 } /* while loop over all requests in the packet */
5903 /* done logging out, turn off logging-out flag */
5904 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
5905 vcp->justLoggedOut = NULL;
5908 free(loggedOutName);
5909 loggedOutName = NULL;
5910 smb_ReleaseUID(loggedOutUserp);
5911 loggedOutUserp = NULL;
5915 /* now send the output packet, and return */
5917 smb_SendPacket(vcp, outp);
5918 thrd_Decrement(&ongoingOps);
5920 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
5922 smb_ReleaseVC(active_vcp);
5924 "Replacing active_vcp %x with %x", active_vcp, vcp);
5928 last_msg_time = GetCurrentTime();
5930 else if (active_vcp == vcp) {
5931 smb_ReleaseVC(active_vcp);
5939 /* Wait for Netbios() calls to return, and make the results available to server
5940 * threads. Note that server threads can't wait on the NCBevents array
5941 * themselves, because NCB events are manual-reset, and the servers would race
5942 * each other to reset them.
5944 void smb_ClientWaiter(void *parmp)
5950 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
5952 if (code == WAIT_OBJECT_0)
5955 /* error checking */
5956 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
5958 int abandonIdx = code - WAIT_ABANDONED_0;
5959 afsi_log("Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
5962 if (code == WAIT_IO_COMPLETION)
5964 afsi_log("Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
5968 if (code == WAIT_TIMEOUT)
5970 afsi_log("Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
5973 if (code == WAIT_FAILED)
5975 afsi_log("Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
5978 idx = code - WAIT_OBJECT_0;
5980 /* check idx range! */
5981 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
5983 /* this is fatal - log as much as possible */
5984 afsi_log("Fatal: NCBevents idx [ %d ] out of range.\n", idx);
5988 thrd_ResetEvent(NCBevents[idx]);
5989 thrd_SetEvent(NCBreturns[0][idx]);
5995 * Try to have one NCBRECV request waiting for every live session. Not more
5996 * than one, because if there is more than one, it's hard to handle Write Raw.
5998 void smb_ServerWaiter(void *parmp)
6001 int idx_session, idx_NCB;
6009 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6011 if (code == WAIT_OBJECT_0)
6014 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6016 int abandonIdx = code - WAIT_ABANDONED_0;
6017 afsi_log("Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6020 if (code == WAIT_IO_COMPLETION)
6022 afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6026 if (code == WAIT_TIMEOUT)
6028 afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6031 if (code == WAIT_FAILED)
6033 afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6036 idx_session = code - WAIT_OBJECT_0;
6038 /* check idx range! */
6039 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6041 /* this is fatal - log as much as possible */
6042 afsi_log("Fatal: session idx [ %d ] out of range.\n", idx_session);
6048 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6050 if (code == WAIT_OBJECT_0)
6053 /* error checking */
6054 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6056 int abandonIdx = code - WAIT_ABANDONED_0;
6057 afsi_log("Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6060 if (code == WAIT_IO_COMPLETION)
6062 afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6066 if (code == WAIT_TIMEOUT)
6068 afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6071 if (code == WAIT_FAILED)
6073 afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6076 idx_NCB = code - WAIT_OBJECT_0;
6078 /* check idx range! */
6079 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6081 /* this is fatal - log as much as possible */
6082 afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6086 /* Link them together */
6087 NCBsessions[idx_NCB] = idx_session;
6090 ncbp = NCBs[idx_NCB];
6092 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6094 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6095 ncbp->ncb_command = NCBRECV | ASYNCH;
6096 ncbp->ncb_lana_num = lanas[idx_session];
6098 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6099 ncbp->ncb_event = NCBevents[idx_NCB];
6100 ncbp->ncb_length = SMB_PACKETSIZE;
6103 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6104 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6105 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6106 ncbp->ncb_length = SMB_PACKETSIZE;
6107 Netbios(ncbp, dos_ncb);
6113 * The top level loop for handling SMB request messages. Each server thread
6114 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6115 * NCB and buffer for the incoming request are loaned to us.
6117 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6118 * to immediately send a request for the rest of the data. This must come
6119 * before any other traffic for that session, so we delay setting the session
6120 * event until that data has come in.
6122 void smb_Server(VOID *parmp)
6124 int myIdx = (int) parmp;
6128 smb_packet_t *outbufp;
6130 int idx_NCB, idx_session;
6132 smb_vc_t *vcp = NULL;
6139 outbufp = GetPacket();
6140 outbufp->ncbp = outncbp;
6144 /* check for demo expiration */
6146 unsigned long tod = time((void *) 0);
6147 if (tod > EXPIREDATE) {
6148 (*smb_MBfunc)(NULL, "AFS demo expiration",
6150 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6154 #endif /* !NOEXPIRE */
6156 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6158 if (code == WAIT_OBJECT_0) {
6162 /* error checking */
6163 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6165 int abandonIdx = code - WAIT_ABANDONED_0;
6166 afsi_log("Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6169 if (code == WAIT_IO_COMPLETION)
6171 afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6175 if (code == WAIT_TIMEOUT)
6177 afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6180 if (code == WAIT_FAILED)
6182 afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6185 idx_NCB = code - WAIT_OBJECT_0;
6187 /* check idx range! */
6188 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6190 /* this is fatal - log as much as possible */
6191 afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6195 ncbp = NCBs[idx_NCB];
6197 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6199 idx_session = NCBsessions[idx_NCB];
6200 rc = ncbp->ncb_retcode;
6202 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6203 osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6206 case NRC_GOODRET: break;
6209 /* Can this happen? Or is it just my
6216 /* Client closed session */
6217 if (reportSessionStartups)
6219 afsi_log("session [ %d ] closed", idx_session);
6221 dead_sessions[idx_session] = TRUE;
6224 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6225 /* Should also release vcp. [done] 2004-05-11 jaltman
6227 * sanity check that all TID's are gone.
6229 * TODO: check if we could use LSNs[idx_session] instead,
6230 * also cleanup after dead vcp
6235 "dead_vcp already set, %x",
6237 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6239 "setting dead_vcp %x, user struct %x",
6243 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6245 if (vcp->justLoggedOut) {
6247 loggedOutTime = vcp->logoffTime;
6249 strdup(vcp->justLoggedOut->unp->name);
6250 loggedOutUserp = vcp->justLoggedOut;
6251 lock_ObtainWrite(&smb_rctLock);
6252 loggedOutUserp->refCount++;
6253 lock_ReleaseWrite(&smb_rctLock);
6259 /* Treat as transient error */
6266 osi_Log1(smb_logp, "dispatch smb recv failed, message incomplete, ncb_length %d",
6268 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6269 sprintf(s, "SMB message incomplete, length %d",
6272 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6274 ncbp->ncb_length, ptbuf,
6276 DeregisterEventSource(h);
6279 "dispatch smb recv failed, message incomplete, ncb_length %d",
6282 "SMB message incomplete, "
6283 "length %d", ncbp->ncb_length);
6287 * We used to discard the packet.
6288 * Instead, try handling it normally.
6296 /* A weird error code. Log it, sleep, and
6298 if (vcp && vcp->errorCount++ > 3) {
6299 afsi_log("session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6300 dead_sessions[idx_session] = TRUE;
6304 thrd_SetEvent(SessionEvents[idx_session]);
6309 /* Success, so now dispatch on all the data in the packet */
6311 smb_concurrentCalls++;
6312 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6313 smb_maxObsConcurrentCalls = smb_concurrentCalls;
6317 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6319 * If at this point vcp is NULL (implies that packet was invalid)
6320 * then we are in big trouble. This means either :
6321 * a) we have the wrong NCB.
6322 * b) Netbios screwed up the call.
6323 * Obviously this implies that
6324 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
6325 * lanas[idx_session] != ncbp->ncb_lana_num )
6326 * Either way, we can't do anything with this packet.
6327 * Log, sleep and resume.
6336 "LSNs[idx_session]=[%d],"
6337 "lanas[idx_session]=[%d],"
6338 "ncbp->ncb_lsn=[%d],"
6339 "ncbp->ncb_lana_num=[%d]",
6343 ncbp->ncb_lana_num);
6347 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6349 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6350 DeregisterEventSource(h);
6353 /* Also log in the trace log. */
6354 osi_Log4(smb_logp, "Server: BAD VCP!"
6355 "LSNs[idx_session]=[%d],"
6356 "lanas[idx_session]=[%d],"
6357 "ncbp->ncb_lsn=[%d],"
6358 "ncbp->ncb_lana_num=[%d]",
6362 ncbp->ncb_lana_num);
6364 /* thrd_Sleep(1000); Don't bother sleeping */
6365 thrd_SetEvent(SessionEvents[idx_session]);
6366 smb_concurrentCalls--;
6371 vcp->errorCount = 0;
6372 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6374 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6375 /* copy whole packet to virtual memory */
6376 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6378 bufp->dos_pkt / 16, bufp);*/
6380 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6382 smbp = (smb_t *)bufp->data;
6385 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6389 if (smbp->com == 0x1d) {
6390 /* Special handling for Write Raw */
6391 raw_write_cont_t rwc;
6392 EVENT_HANDLE rwevent;
6393 char eventName[MAX_PATH];
6395 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6396 if (rwc.code == 0) {
6397 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6398 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6399 afsi_log("Event Object Already Exists: %s", eventName);
6400 ncbp->ncb_command = NCBRECV | ASYNCH;
6401 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6402 ncbp->ncb_lana_num = vcp->lana;
6403 ncbp->ncb_buffer = rwc.buf;
6404 ncbp->ncb_length = 65535;
6405 ncbp->ncb_event = rwevent;
6409 Netbios(ncbp, dos_ncb);
6411 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6412 thrd_CloseHandle(rwevent);
6414 thrd_SetEvent(SessionEvents[idx_session]);
6416 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6417 } else if (smbp->com == 0xa0) {
6419 * Serialize the handling for NT Transact
6422 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6423 thrd_SetEvent(SessionEvents[idx_session]);
6425 thrd_SetEvent(SessionEvents[idx_session]);
6426 /* TODO: what else needs to be serialized? */
6427 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6429 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6431 __except( smb_ServerExceptionFilter() ) {
6435 smb_concurrentCalls--;
6438 thrd_SetEvent(NCBavails[idx_NCB]);
6445 * Exception filter for the server threads. If an exception occurs in the
6446 * dispatch routines, which is where exceptions are most common, then do a
6447 * force trace and give control to upstream exception handlers. Useful for
6450 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6451 DWORD smb_ServerExceptionFilter(void) {
6452 /* While this is not the best time to do a trace, if it succeeds, then
6453 * we have a trace (assuming tracing was enabled). Otherwise, this should
6454 * throw a second exception.
6459 ptbuf[0] = "Unhandled exception forcing trace";
6461 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6463 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6464 DeregisterEventSource(h);
6467 afsd_ForceTrace(TRUE);
6468 return EXCEPTION_CONTINUE_SEARCH;
6473 * Create a new NCB and associated events, packet buffer, and "space" buffer.
6474 * If the number of server threads is M, and the number of live sessions is
6475 * N, then the number of NCB's in use at any time either waiting for, or
6476 * holding, received messages is M + N, so that is how many NCB's get created.
6478 void InitNCBslot(int idx)
6480 struct smb_packet *bufp;
6481 EVENT_HANDLE retHandle;
6483 char eventName[MAX_PATH];
6485 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
6487 NCBs[idx] = GetNCB();
6488 sprintf(eventName,"NCBavails[%d]", idx);
6489 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6490 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6491 afsi_log("Event Object Already Exists: %s", eventName);
6493 sprintf(eventName,"NCBevents[%d]", idx);
6494 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
6495 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6496 afsi_log("Event Object Already Exists: %s", eventName);
6498 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
6499 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6500 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6501 afsi_log("Event Object Already Exists: %s", eventName);
6502 for (i=0; i<smb_NumServerThreads; i++)
6503 NCBreturns[i][idx] = retHandle;
6505 bufp->spacep = cm_GetSpace();
6509 /* listen for new connections */
6510 void smb_Listener(void *parmp)
6518 char rname[NCBNAMSZ+1];
6519 char cname[MAX_COMPUTERNAME_LENGTH+1];
6520 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
6525 int lana = (int) parmp;
6529 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6532 /* retrieve computer name */
6533 GetComputerName(cname, &cnamelen);
6537 memset(ncbp, 0, sizeof(NCB));
6541 /* check for demo expiration */
6543 unsigned long tod = time((void *) 0);
6544 if (tod > EXPIREDATE) {
6545 (*smb_MBfunc)(NULL, "AFS demo expiration",
6547 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6555 #endif /* !NOEXPIRE */
6557 ncbp->ncb_command = NCBLISTEN;
6558 ncbp->ncb_rto = 0; /* No receive timeout */
6559 ncbp->ncb_sto = 0; /* No send timeout */
6561 /* pad out with spaces instead of null termination */
6562 len = strlen(smb_localNamep);
6563 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
6564 for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
6566 strcpy(ncbp->ncb_callname, "*");
6567 for(i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
6569 ncbp->ncb_lana_num = lana;
6572 code = Netbios(ncbp);
6574 code = Netbios(ncbp, dos_ncb);
6583 /* terminate silently if shutdown flag is set */
6584 if (smbShutdownFlag == 1) {
6593 "NCBLISTEN lana=%d failed with code %d",
6594 ncbp->ncb_lana_num, code);
6596 "Client exiting due to network failure. Please restart client.\n");
6600 "Client exiting due to network failure. Please restart client.\n"
6601 "NCBLISTEN lana=%d failed with code %d",
6602 ncbp->ncb_lana_num, code);
6604 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
6605 MB_OK|MB_SERVICE_NOTIFICATION);
6606 osi_assert(tbuffer);
6609 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
6610 ncbp->ncb_lana_num, code);
6611 fprintf(stderr, "\nClient exiting due to network failure "
6612 "(possibly due to power-saving mode)\n");
6613 fprintf(stderr, "Please restart client.\n");
6614 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
6618 /* check for remote conns */
6619 /* first get remote name and insert null terminator */
6620 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
6621 for (i=NCBNAMSZ; i>0; i--) {
6622 if (rname[i-1] != ' ' && rname[i-1] != 0) {
6628 /* compare with local name */
6630 if (strncmp(rname, cname, NCBNAMSZ) != 0)
6631 flags |= SMB_VCFLAG_REMOTECONN;
6633 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
6635 lock_ObtainMutex(&smb_ListenerLock);
6637 /* New generation */
6640 /* Log session startup */
6642 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
6644 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
6646 afsi_log("New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
6647 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname, ongoingOps);
6649 if (reportSessionStartups) {
6655 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6656 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
6658 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
6660 DeregisterEventSource(h);
6662 afsi_log("NCBLISTEN completed, call from %s",rname);
6663 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
6666 fprintf(stderr, "%s: New session %d starting from host %s\n",
6667 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
6672 /* now ncbp->ncb_lsn is the connection ID */
6673 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
6674 vcp->flags |= flags;
6675 strcpy(vcp->rname, rname);
6677 /* Allocate slot in session arrays */
6678 /* Re-use dead session if possible, otherwise add one more */
6679 /* But don't look at session[0], it is reserved */
6680 for (i = 1; i < numSessions; i++) {
6681 if (dead_sessions[i]) {
6682 afsi_log("connecting to dead session [ %d ]", i);
6683 dead_sessions[i] = FALSE;
6688 /* assert that we do not exceed the maximum number of sessions or NCBs.
6689 * we should probably want to wait for a session to be freed in case
6693 osi_assert(i < Sessionmax);
6694 osi_assert(numNCBs < NCBmax);
6696 LSNs[i] = ncbp->ncb_lsn;
6697 lanas[i] = ncbp->ncb_lana_num;
6699 if (i == numSessions) {
6700 /* Add new NCB for new session */
6701 char eventName[MAX_PATH];
6703 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
6705 InitNCBslot(numNCBs);
6707 thrd_SetEvent(NCBavails[0]);
6708 thrd_SetEvent(NCBevents[0]);
6709 for (j = 0; j < smb_NumServerThreads; j++)
6710 thrd_SetEvent(NCBreturns[j][0]);
6711 /* Also add new session event */
6712 sprintf(eventName, "SessionEvents[%d]", i);
6713 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6714 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6715 afsi_log("Event Object Already Exists: %s", eventName);
6717 afsi_log("increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
6718 thrd_SetEvent(SessionEvents[0]);
6720 thrd_SetEvent(SessionEvents[i]);
6723 lock_ReleaseMutex(&smb_ListenerLock);
6725 } /* dispatch while loop */
6728 /* initialize Netbios */
6729 void smb_NetbiosInit()
6735 int i, lana, code, l;
6737 int delname_tried=0;
6740 OSVERSIONINFO Version;
6742 /* AFAIK, this is the default for the ms loopback adapter.*/
6743 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
6744 /*******************************************************************/
6746 /* Get the version of Windows */
6747 memset(&Version, 0x00, sizeof(Version));
6748 Version.dwOSVersionInfoSize = sizeof(Version);
6749 GetVersionEx(&Version);
6751 /* setup the NCB system */
6754 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6758 if (smb_LANadapter == -1) {
6759 ncbp->ncb_command = NCBENUM;
6760 ncbp->ncb_buffer = (PUCHAR)&lana_list;
6761 ncbp->ncb_length = sizeof(lana_list);
6762 code = Netbios(ncbp);
6764 sprintf(s, "Netbios NCBENUM error code %d", code);
6766 osi_panic(s, __FILE__, __LINE__);
6770 lana_list.length = 1;
6771 lana_list.lana[0] = smb_LANadapter;
6774 for (i = 0; i < lana_list.length; i++) {
6775 /* reset the adaptor: in Win32, this is required for every process, and
6776 * acts as an init call, not as a real hardware reset.
6778 ncbp->ncb_command = NCBRESET;
6779 ncbp->ncb_callname[0] = 100;
6780 ncbp->ncb_callname[2] = 100;
6781 ncbp->ncb_lana_num = lana_list.lana[i];
6782 code = Netbios(ncbp);
6784 code = ncbp->ncb_retcode;
6786 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
6788 lana_list.lana[i] = 255; /* invalid lana */
6790 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
6795 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
6796 we will just fake the LANA list */
6797 if (smb_LANadapter == -1) {
6798 for (i = 0; i < 8; i++)
6799 lana_list.lana[i] = i;
6800 lana_list.length = 8;
6803 lana_list.length = 1;
6804 lana_list.lana[0] = smb_LANadapter;
6808 /* and declare our name so we can receive connections */
6809 memset(ncbp, 0, sizeof(*ncbp));
6810 len=lstrlen(smb_localNamep);
6811 memset(smb_sharename,' ',NCBNAMSZ);
6812 memcpy(smb_sharename,smb_localNamep,len);
6813 sprintf(s, "lana_list.length %d", lana_list.length);
6816 /* Keep the name so we can unregister it later */
6817 for (l = 0; l < lana_list.length; l++) {
6818 lana = lana_list.lana[l];
6820 ncbp->ncb_command = NCBADDNAME;
6821 ncbp->ncb_lana_num = lana;
6822 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
6824 code = Netbios(ncbp);
6826 code = Netbios(ncbp, dos_ncb);
6829 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
6830 lana, code, ncbp->ncb_retcode,ncbp->ncb_cmd_cplt);
6832 char name[NCBNAMSZ+1];
6834 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
6835 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
6838 if (code == 0) code = ncbp->ncb_retcode;
6840 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
6842 /* we only use one LANA with djgpp */
6843 lana_list.lana[0] = lana;
6844 lana_list.length = 1;
6848 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
6850 if (code == NRC_BRIDGE) { /* invalid LANA num */
6851 lana_list.lana[l] = 255;
6854 else if (code == NRC_DUPNAME) {
6855 afsi_log("Name already exists; try to delete it");
6856 memset(ncbp, 0, sizeof(*ncbp));
6857 ncbp->ncb_command = NCBDELNAME;
6858 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
6859 ncbp->ncb_lana_num = lana;
6861 code = Netbios(ncbp);
6863 code = Netbios(ncbp, dos_ncb);
6865 if (code == 0) code = ncbp->ncb_retcode;
6867 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
6870 if (code != 0 || delname_tried) {
6871 lana_list.lana[l] = 255;
6873 else if (code == 0) {
6874 if (!delname_tried) {
6882 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
6884 lana_list.lana[l] = 255; /* invalid lana */
6885 osi_panic(s, __FILE__, __LINE__);
6889 lana_found = 1; /* at least one worked */
6896 osi_assert(lana_list.length >= 0);
6898 sprintf(s, "No valid LANA numbers found!");
6899 osi_panic(s, __FILE__, __LINE__);
6902 /* we're done with the NCB now */
6906 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
6923 EVENT_HANDLE retHandle;
6924 char eventName[MAX_PATH];
6927 smb_MBfunc = aMBfunc;
6931 /* check for demo expiration */
6933 unsigned long tod = time((void *) 0);
6934 if (tod > EXPIREDATE) {
6936 (*smb_MBfunc)(NULL, "AFS demo expiration", "afsd",
6937 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6940 fprintf(stderr, "AFS demo expiration\n");
6945 #endif /* !NOEXPIRE */
6948 smb_LANadapter = LANadapt;
6950 /* Initialize smb_localZero */
6951 myTime.tm_isdst = -1; /* compute whether on DST or not */
6952 myTime.tm_year = 70;
6958 smb_localZero = mktime(&myTime);
6960 /* Initialize kludge-GMT */
6961 smb_CalculateNowTZ();
6963 /* initialize the remote debugging log */
6966 /* remember the name */
6967 len = strlen(snamep);
6968 smb_localNamep = malloc(len+1);
6969 strcpy(smb_localNamep, snamep);
6970 afsi_log("smb_localNamep is >%s<", smb_localNamep);
6972 /* and the global lock */
6973 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
6974 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
6976 /* Raw I/O data structures */
6977 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
6979 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
6981 /* 4 Raw I/O buffers */
6983 smb_RawBufs = calloc(65536,1);
6984 *((char **)smb_RawBufs) = NULL;
6985 for (i=0; i<3; i++) {
6986 char *rawBuf = calloc(65536,1);
6987 *((char **)rawBuf) = smb_RawBufs;
6988 smb_RawBufs = rawBuf;
6991 npar = 65536 >> 4; /* number of paragraphs */
6992 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
6994 afsi_log("Cannot allocate %d paragraphs of DOS memory",
6996 osi_panic("",__FILE__,__LINE__);
6999 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7002 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7004 _farpokel(_dos_ds, smb_RawBufs, NULL);
7005 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7006 npar = 65536 >> 4; /* number of paragraphs */
7007 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7009 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7011 osi_panic("",__FILE__,__LINE__);
7014 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7017 rawBuf = (seg * 16) + 0; /* DOS physical address */
7018 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7019 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7020 smb_RawBufs = rawBuf;
7024 /* global free lists */
7025 smb_ncbFreeListp = NULL;
7026 smb_packetFreeListp = NULL;
7030 /* Initialize listener and server structures */
7031 memset(dead_sessions, 0, sizeof(dead_sessions));
7032 sprintf(eventName, "SessionEvents[0]");
7033 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7034 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7035 afsi_log("Event Object Already Exists: %s", eventName);
7037 smb_NumServerThreads = nThreads;
7038 sprintf(eventName, "NCBavails[0]");
7039 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7040 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7041 afsi_log("Event Object Already Exists: %s", eventName);
7042 sprintf(eventName, "NCBevents[0]");
7043 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7044 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7045 afsi_log("Event Object Already Exists: %s", eventName);
7046 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7047 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7048 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7049 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7050 afsi_log("Event Object Already Exists: %s", eventName);
7051 for (i = 0; i < smb_NumServerThreads; i++) {
7052 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7053 NCBreturns[i][0] = retHandle;
7055 for (i = 1; i <= nThreads; i++)
7057 numNCBs = nThreads + 1;
7059 /* Initialize dispatch table */
7060 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7061 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7062 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7063 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7064 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7065 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7066 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7067 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7068 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7069 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7070 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7071 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7072 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7073 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7074 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7075 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7076 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7077 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7078 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7079 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7080 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7081 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7082 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7083 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7084 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7085 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7086 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7087 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7088 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7089 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7090 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7091 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7092 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7093 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7094 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7095 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7096 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7097 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7098 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7099 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7100 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7101 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7102 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7103 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7104 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7105 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7106 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7107 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7108 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7109 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7110 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7111 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7112 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7113 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7114 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7115 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7116 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7117 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7118 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;
7119 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;
7120 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;
7121 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;
7122 for(i=0xd0; i<= 0xd7; i++) {
7123 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7126 /* setup tran 2 dispatch table */
7127 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7128 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7129 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7130 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7131 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7132 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7133 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7134 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7135 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7136 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7137 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7138 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7139 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7140 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2MKDir;
7144 /* Start listeners, waiters, servers, and daemons */
7146 for (i = 0; i < lana_list.length; i++) {
7147 if (lana_list.lana[i] == 255) continue;
7148 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7149 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7150 osi_assert(phandle != NULL);
7151 thrd_CloseHandle(phandle);
7155 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7156 NULL, 0, &lpid, "smb_ClientWaiter");
7157 osi_assert(phandle != NULL);
7158 thrd_CloseHandle(phandle);
7161 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7162 NULL, 0, &lpid, "smb_ServerWaiter");
7163 osi_assert(phandle != NULL);
7164 thrd_CloseHandle(phandle);
7166 for (i=0; i<nThreads; i++) {
7167 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7168 (void *) i, 0, &lpid, "smb_Server");
7169 osi_assert(phandle != NULL);
7170 thrd_CloseHandle(phandle);
7173 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7174 NULL, 0, &lpid, "smb_Daemon");
7175 osi_assert(phandle != NULL);
7176 thrd_CloseHandle(phandle);
7178 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7179 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7180 osi_assert(phandle != NULL);
7181 thrd_CloseHandle(phandle);
7190 void smb_Shutdown(void)
7199 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7201 /* setup the NCB system */
7204 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7207 /* Block new sessions by setting shutdown flag */
7208 smbShutdownFlag = 1;
7210 /* Hang up all sessions */
7211 memset((char *)ncbp, 0, sizeof(NCB));
7212 for (i = 1; i < numSessions; i++)
7214 if (dead_sessions[i])
7217 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7218 ncbp->ncb_command = NCBHANGUP;
7219 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
7220 ncbp->ncb_lsn = LSNs[i];
7222 code = Netbios(ncbp);
7224 code = Netbios(ncbp, dos_ncb);
7226 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7227 if (code == 0) code = ncbp->ncb_retcode;
7229 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7230 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7234 /* Delete Netbios name */
7235 memset((char *)ncbp, 0, sizeof(NCB));
7236 for (i = 0; i < lana_list.length; i++) {
7237 if (lana_list.lana[i] == 255) continue;
7238 ncbp->ncb_command = NCBDELNAME;
7239 ncbp->ncb_lana_num = lana_list.lana[i];
7240 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7242 code = Netbios(ncbp);
7244 code = Netbios(ncbp, dos_ncb);
7246 if (code == 0) code = ncbp->ncb_retcode;
7248 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7249 ncbp->ncb_lana_num, code);
7255 /* Get the UNC \\<servername>\<sharename> prefix. */
7256 char *smb_GetSharename()
7260 /* Make sure we have been properly initialized. */
7261 if (smb_localNamep == NULL)
7264 /* Allocate space for \\<servername>\<sharename>, plus the
7267 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7268 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7274 void smb_LogPacket(smb_packet_t *packet)
7277 unsigned length, paramlen, datalen, i, j;
7279 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7283 osi_Log0(smb_logp, "*** SMB packet dump ***");
7285 vp = (BYTE *) packet->data;
7287 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7288 length = paramlen + 2 + datalen;
7291 for(i=0;i < length; i+=16)
7293 memset( buf, ' ', 80 );
7298 buf[strlen(buf)] = ' ';
7300 cp = (BYTE*) buf + 7;
7302 for(j=0;j < 16 && (i+j)<length; j++)
7304 *(cp++) = hex[vp[i+j] >> 4];
7305 *(cp++) = hex[vp[i+j] & 0xf];
7315 for(j=0;j < 16 && (i+j)<length;j++)
7317 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7328 osi_Log0( smb_logp, buf );
7331 osi_Log0(smb_logp, "*** End SMB packet dump ***");
7335 #endif /* NOTSERVICE */
7337 int smb_DumpVCP(FILE *outputFile, char *cookie)
7344 lock_ObtainRead(&smb_rctLock);
7346 sprintf(output, "begin dumping vcpsp\n");
7347 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7349 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
7353 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7354 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7355 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7357 sprintf(output, "begin dumping fidsp\n");
7358 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7360 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
7362 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",
7363 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
7364 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
7365 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7366 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7369 sprintf(output, "done dumping fidsp\n");
7370 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7373 sprintf(output, "done dumping vcpsp\n");
7374 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7376 lock_ReleaseRead(&smb_rctLock);