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>
36 /* These characters are illegal in Windows filenames */
37 static char *illegalChars = "\\/:*?\"<>|";
38 BOOL isWindows2000 = FALSE;
40 smb_vc_t *dead_vcp = NULL;
41 smb_vc_t *active_vcp = NULL;
43 char *loggedOutName = NULL;
44 smb_user_t *loggedOutUserp = NULL;
45 unsigned long loggedOutTime;
48 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, ...);
62 osi_hyper_t hzero = {0, 0};
63 osi_hyper_t hones = {0xFFFFFFFF, -1};
66 osi_rwlock_t smb_globalLock;
67 osi_rwlock_t smb_rctLock;
68 osi_mutex_t smb_ListenerLock;
71 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
74 long smb_maxObsConcurrentCalls=0;
75 long smb_concurrentCalls=0;
77 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
79 smb_packet_t *smb_packetFreeListp;
80 smb_ncb_t *smb_ncbFreeListp;
82 int smb_NumServerThreads;
84 int numNCBs, numSessions;
87 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
88 EVENT_HANDLE **NCBreturns;
89 DWORD NCBsessions[NCBmax];
91 struct smb_packet *bufs[NCBmax];
93 #define Sessionmax 100
94 EVENT_HANDLE SessionEvents[Sessionmax];
95 unsigned short LSNs[Sessionmax];
96 int lanas[Sessionmax];
97 BOOL dead_sessions[Sessionmax];
101 osi_mutex_t smb_RawBufLock;
103 #define SMB_RAW_BUFS 4
105 int smb_RawBufSel[SMB_RAW_BUFS];
110 #define RAWTIMEOUT INFINITE
113 typedef struct raw_write_cont {
126 /* dir search stuff */
127 long smb_dirSearchCounter = 1;
128 smb_dirSearch_t *smb_firstDirSearchp;
129 smb_dirSearch_t *smb_lastDirSearchp;
131 /* global state about V3 protocols */
132 int smb_useV3; /* try to negotiate V3 */
135 /* MessageBox or something like it */
136 int (WINAPI *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
140 * Time in Unix format of midnight, 1/1/1970 local time.
141 * When added to dosUTime, gives Unix (AFS) time.
145 /* Time difference for converting to kludge-GMT */
148 char *smb_localNamep;
150 smb_vc_t *smb_allVCsp;
152 smb_username_t *usernamesp = NULL;
154 smb_waitingLock_t *smb_allWaitingLocks;
157 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
158 NCB *ncbp, raw_write_cont_t *rwcp);
159 void smb_NetbiosInit();
161 extern char cm_HostName[];
162 extern char cm_confDir[];
166 #define LPTSTR char *
167 #define GetComputerName(str, sizep) \
168 strcpy((str), cm_HostName); \
169 *(sizep) = strlen(cm_HostName)
175 * To build an expiring version, comment out the definition of NOEXPIRE,
176 * and set the definition of EXPIREDATE to the desired value.
179 #define EXPIREDATE 834000000 /* Wed Jun 5 1996 */
182 char * myCrt_Dispatch(int i)
187 return "unknown SMB op";
189 return "(00)ReceiveCoreMakeDir";
191 return "(01)ReceiveCoreRemoveDir";
193 return "(02)ReceiveCoreOpen";
195 return "(03)ReceiveCoreCreate";
197 return "(04)ReceiveCoreClose";
199 return "(05)ReceiveCoreFlush";
201 return "(06)ReceiveCoreUnlink";
203 return "(07)ReceiveCoreRename";
205 return "(08)ReceiveCoreGetFileAttributes";
207 return "(09)ReceiveCoreSetFileAttributes";
209 return "(0a)ReceiveCoreRead";
211 return "(0b)ReceiveCoreWrite";
213 return "(0c)ReceiveCoreLockRecord";
215 return "(0d)ReceiveCoreUnlockRecord";
217 return "(0e)SendCoreBadOp";
219 return "(0f)ReceiveCoreCreate";
221 return "(10)ReceiveCoreCheckPath";
223 return "(11)SendCoreBadOp";
225 return "(12)ReceiveCoreSeek";
227 return "(1a)ReceiveCoreReadRaw";
229 return "(1d)ReceiveCoreWriteRawDummy";
231 return "(22)ReceiveV3SetAttributes";
233 return "(23)ReceiveV3GetAttributes";
235 return "(24)ReceiveV3LockingX";
237 return "(29)SendCoreBadOp";
239 return "(2b)ReceiveCoreEcho";
241 return "(2d)ReceiveV3OpenX";
243 return "(2e)ReceiveV3ReadX";
245 return "(32)ReceiveV3Tran2A";
247 return "(33)ReceiveV3Tran2A";
249 return "(34)ReceiveV3FindClose";
251 return "(35)ReceiveV3FindNotifyClose";
253 return "(70)ReceiveCoreTreeConnect";
255 return "(71)ReceiveCoreTreeDisconnect";
257 return "(72)ReceiveNegotiate";
259 return "(73)ReceiveV3SessionSetupX";
261 return "(74)ReceiveV3UserLogoffX";
263 return "(75)ReceiveV3TreeConnectX";
265 return "(80)ReceiveCoreGetDiskAttributes";
267 return "(81)ReceiveCoreSearchDir";
269 return "(A0)ReceiveNTTransact";
271 return "(A2)ReceiveNTCreateX";
273 return "(A4)ReceiveNTCancel";
275 return "(c0)SendCoreBadOp";
277 return "(c1)SendCoreBadOp";
279 return "(c2)SendCoreBadOp";
281 return "(c3)SendCoreBadOp";
285 char * myCrt_2Dispatch(int i)
290 return "unknown SMB op-2";
292 return "S(00)CreateFile";
294 return "S(01)FindFirst";
296 return "S(02)FindNext"; /* FindNext */
298 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
302 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
304 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
306 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
308 return "S(08)??_ReceiveTran2SetFileInfo";
310 return "S(09)??_ReceiveTran2FSCTL";
312 return "S(0a)_ReceiveTran2IOCTL";
314 return "S(0b)_ReceiveTran2FindNotifyFirst";
316 return "S(0c)_ReceiveTran2FindNotifyNext";
318 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
322 /* scache must be locked */
323 unsigned int smb_Attributes(cm_scache_t *scp)
327 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
328 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
334 * We used to mark a file RO if it was in an RO volume, but that
335 * turns out to be impolitic in NT. See defect 10007.
338 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
340 if ((scp->unixModeBits & 0222) == 0)
341 attrs |= 1; /* turn on read-only flag */
346 static int ExtractBits(WORD bits, short start, short len)
353 num = bits << (16 - end);
354 num = num >> ((16 - end) + start);
360 void ShowUnixTime(char *FuncName, long unixTime)
365 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
367 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
368 osi_Log1(afsd_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
370 int day, month, year, sec, min, hour;
373 day = ExtractBits(wDate, 0, 5);
374 month = ExtractBits(wDate, 5, 4);
375 year = ExtractBits(wDate, 9, 7) + 1980;
377 sec = ExtractBits(wTime, 0, 5);
378 min = ExtractBits(wTime, 5, 6);
379 hour = ExtractBits(wTime, 11, 5);
381 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
382 osi_Log1(afsd_logp, "%s", osi_LogSaveString(afsd_logp, msg));
388 /* Determine if we are observing daylight savings time */
389 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
391 TIME_ZONE_INFORMATION timeZoneInformation;
392 SYSTEMTIME utc, local, localDST;
394 /* Get the time zone info. NT uses this to calc if we are in DST. */
395 GetTimeZoneInformation(&timeZoneInformation);
397 /* Return the daylight bias */
398 *pDstBias = timeZoneInformation.DaylightBias;
400 /* Return the bias */
401 *pBias = timeZoneInformation.Bias;
403 /* Now determine if DST is being observed */
405 /* Get the UTC (GMT) time */
408 /* Convert UTC time to local time using the time zone info. If we are
409 observing DST, the calculated local time will include this.
411 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
413 /* Set the daylight bias to 0. The daylight bias is the amount of change
414 in time that we use for daylight savings time. By setting this to 0
415 we cause there to be no change in time during daylight savings time.
417 timeZoneInformation.DaylightBias = 0;
419 /* Convert the utc time to local time again, but this time without any
420 adjustment for daylight savings time.
422 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
424 /* If the two times are different, then it means that the localDST that
425 we calculated includes the daylight bias, and therefore we are
426 observing daylight savings time.
428 *pDST = localDST.wHour != local.wHour;
431 /* Determine if we are observing daylight savings time */
432 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
438 *pDstBias = -60; /* where can this be different? */
444 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
446 BOOL dst; /* Will be TRUE if observing DST */
447 LONG dstBias; /* Offset from local time if observing DST */
448 LONG bias; /* Offset from GMT for local time */
451 * This function will adjust the last write time to compensate
452 * for two bugs in the smb client:
454 * 1) During Daylight Savings Time, the LastWriteTime is ahead
455 * in time by the DaylightBias (ignoring the sign - the
456 * DaylightBias is always stored as a negative number). If
457 * the DaylightBias is -60, then the LastWriteTime will be
458 * ahead by 60 minutes.
460 * 2) If the local time zone is a positive offset from GMT, then
461 * the LastWriteTime will be the correct local time plus the
462 * Bias (ignoring the sign - a positive offset from GMT is
463 * always stored as a negative Bias). If the Bias is -120,
464 * then the LastWriteTime will be ahead by 120 minutes.
466 * These bugs can occur at the same time.
469 GetTimeZoneInfo(&dst, &dstBias, &bias);
471 /* First adjust for DST */
473 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
475 /* Now adjust for a positive offset from GMT (a negative bias). */
477 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
481 * Calculate the difference (in seconds) between local time and GMT.
482 * This enables us to convert file times to kludge-GMT.
488 struct tm gmt_tm, local_tm;
489 int days, hours, minutes, seconds;
492 gmt_tm = *(gmtime(&t));
493 local_tm = *(localtime(&t));
495 days = local_tm.tm_yday - gmt_tm.tm_yday;
496 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
497 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
498 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
504 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
509 long ersatz_unixTime;
512 * Must use kludge-GMT instead of real GMT.
513 * kludge-GMT is computed by adding time zone difference to localtime.
516 * ltp = gmtime(&unixTime);
518 ersatz_unixTime = unixTime - smb_NowTZ;
519 ltp = localtime(&ersatz_unixTime);
521 /* if we fail, make up something */
524 localJunk.tm_year = 89 - 20;
525 localJunk.tm_mon = 4;
526 localJunk.tm_mday = 12;
527 localJunk.tm_hour = 0;
528 localJunk.tm_min = 0;
529 localJunk.tm_sec = 0;
532 stm.wYear = ltp->tm_year + 1900;
533 stm.wMonth = ltp->tm_mon + 1;
534 stm.wDayOfWeek = ltp->tm_wday;
535 stm.wDay = ltp->tm_mday;
536 stm.wHour = ltp->tm_hour;
537 stm.wMinute = ltp->tm_min;
538 stm.wSecond = ltp->tm_sec;
539 stm.wMilliseconds = 0;
541 SystemTimeToFileTime(&stm, largeTimep);
544 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
546 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
547 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
548 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
550 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
552 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
553 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
555 *ft = LargeIntegerMultiplyByLong(*ft, 60);
556 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
559 ut = ConvertLongToLargeInteger(unixTime);
560 ut = LargeIntegerMultiplyByLong(ut, 10000000);
561 *ft = LargeIntegerAdd(*ft, ut);
566 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
572 FileTimeToSystemTime(largeTimep, &stm);
574 lt.tm_year = stm.wYear - 1900;
575 lt.tm_mon = stm.wMonth - 1;
576 lt.tm_wday = stm.wDayOfWeek;
577 lt.tm_mday = stm.wDay;
578 lt.tm_hour = stm.wHour;
579 lt.tm_min = stm.wMinute;
580 lt.tm_sec = stm.wSecond;
583 save_timezone = _timezone;
584 _timezone += smb_NowTZ;
585 *unixTimep = mktime(<);
586 _timezone = save_timezone;
589 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
591 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
592 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
593 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
597 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
598 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60
600 a = LargeIntegerMultiplyByLong(a, 60);
601 a = LargeIntegerMultiplyByLong(a, 10000000);
603 /* subtract it from ft */
604 a = LargeIntegerSubtract(*ft, a);
606 /* divide down to seconds */
607 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
611 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
618 ltp = localtime((time_t*) &unixTime);
620 /* if we fail, make up something */
623 localJunk.tm_year = 89 - 20;
624 localJunk.tm_mon = 4;
625 localJunk.tm_mday = 12;
626 localJunk.tm_hour = 0;
627 localJunk.tm_min = 0;
628 localJunk.tm_sec = 0;
631 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
632 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
633 *dosTimep = (dosDate<<16) | dosTime;
636 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
638 unsigned short dosDate;
639 unsigned short dosTime;
642 dosDate = searchTime & 0xffff;
643 dosTime = (searchTime >> 16) & 0xffff;
645 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
646 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
647 localTm.tm_mday = (dosDate) & 0x1f;
648 localTm.tm_hour = (dosTime>>11) & 0x1f;
649 localTm.tm_min = (dosTime >> 5) & 0x3f;
650 localTm.tm_sec = (dosTime & 0x1f) * 2;
651 localTm.tm_isdst = -1; /* compute whether DST in effect */
653 *unixTimep = mktime(&localTm);
656 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
658 *dosUTimep = unixTime - smb_localZero;
661 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
664 *unixTimep = dosTime + smb_localZero;
666 /* dosTime seems to be already adjusted for GMT */
667 *unixTimep = dosTime;
671 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
675 lock_ObtainWrite(&smb_rctLock);
676 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
677 if (lsn == vcp->lsn && lana == vcp->lana) {
682 if (!vcp && (flags & SMB_FLAG_CREATE)) {
683 vcp = malloc(sizeof(*vcp));
684 memset(vcp, 0, sizeof(*vcp));
688 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
689 vcp->nextp = smb_allVCsp;
691 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
695 lock_ReleaseWrite(&smb_rctLock);
699 int smb_IsStarMask(char *maskp)
704 for(i=0; i<11; i++) {
706 if (tc == '?' || tc == '*' || tc == '>') return 1;
711 void smb_ReleaseVC(smb_vc_t *vcp)
713 lock_ObtainWrite(&smb_rctLock);
714 osi_assert(vcp->refCount-- > 0);
715 lock_ReleaseWrite(&smb_rctLock);
718 void smb_HoldVC(smb_vc_t *vcp)
720 lock_ObtainWrite(&smb_rctLock);
722 lock_ReleaseWrite(&smb_rctLock);
725 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
729 lock_ObtainWrite(&smb_rctLock);
730 for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
731 if (tid == tidp->tid) {
736 if (!tidp && (flags & SMB_FLAG_CREATE)) {
737 tidp = malloc(sizeof(*tidp));
738 memset(tidp, 0, sizeof(*tidp));
739 tidp->nextp = vcp->tidsp;
743 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
746 lock_ReleaseWrite(&smb_rctLock);
750 void smb_ReleaseTID(smb_tid_t *tidp)
757 lock_ObtainWrite(&smb_rctLock);
758 osi_assert(tidp->refCount-- > 0);
759 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
760 ltpp = &tidp->vcp->tidsp;
761 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
762 if (tp == tidp) break;
764 osi_assert(tp != NULL);
766 lock_FinalizeMutex(&tidp->mx);
767 userp = tidp->userp; /* remember to drop ref later */
769 lock_ReleaseWrite(&smb_rctLock);
771 cm_ReleaseUser(userp);
775 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
777 smb_user_t *uidp = NULL;
779 lock_ObtainWrite(&smb_rctLock);
780 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
781 if (uid == uidp->userID) {
783 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 : "");
787 if (!uidp && (flags & SMB_FLAG_CREATE)) {
788 uidp = malloc(sizeof(*uidp));
789 memset(uidp, 0, sizeof(*uidp));
790 uidp->nextp = vcp->usersp;
794 lock_InitializeMutex(&uidp->mx, "uid_t mutex");
796 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 : ""));
798 lock_ReleaseWrite(&smb_rctLock);
802 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
804 smb_username_t *unp= NULL;
806 lock_ObtainWrite(&smb_rctLock);
807 for(unp = usernamesp; unp; unp = unp->nextp) {
808 if (stricmp(unp->name, usern) == 0 &&
809 stricmp(unp->machine, machine) == 0) {
814 if (!unp && (flags & SMB_FLAG_CREATE)) {
815 unp = malloc(sizeof(*unp));
816 memset(unp, 0, sizeof(*unp));
817 unp->nextp = usernamesp;
818 unp->name = strdup(usern);
819 unp->machine = strdup(machine);
821 lock_InitializeMutex(&unp->mx, "username_t mutex");
823 lock_ReleaseWrite(&smb_rctLock);
827 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
829 smb_user_t *uidp= NULL;
831 lock_ObtainWrite(&smb_rctLock);
832 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
835 if (stricmp(uidp->unp->name, usern) == 0) {
837 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
842 lock_ReleaseWrite(&smb_rctLock);
845 void smb_ReleaseUID(smb_user_t *uidp)
852 lock_ObtainWrite(&smb_rctLock);
853 osi_assert(uidp->refCount-- > 0);
854 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
855 lupp = &uidp->vcp->usersp;
856 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
857 if (up == uidp) break;
859 osi_assert(up != NULL);
861 lock_FinalizeMutex(&uidp->mx);
863 userp = uidp->unp->userp; /* remember to drop ref later */
865 lock_ReleaseWrite(&smb_rctLock);
867 cm_ReleaseUserVCRef(userp);
868 cm_ReleaseUser(userp);
872 /* retrieve a held reference to a user structure corresponding to an incoming
874 * corresponding release function is cm_ReleaseUser.
876 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
882 smbp = (smb_t *) inp;
883 uidp = smb_FindUID(vcp, smbp->uid, 0);
884 if ((!uidp) || (!uidp->unp))
887 lock_ObtainMutex(&uidp->mx);
888 up = uidp->unp->userp;
890 lock_ReleaseMutex(&uidp->mx);
892 smb_ReleaseUID(uidp);
898 * Return a pointer to a pathname extracted from a TID structure. The
899 * TID structure is not held; assume it won't go away.
901 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
906 tidp = smb_FindTID(vcp, tid, 0);
907 tpath = tidp->pathname;
908 smb_ReleaseTID(tidp);
912 /* check to see if we have a chained fid, that is, a fid that comes from an
913 * OpenAndX message that ran earlier in this packet. In this case, the fid
914 * field in a read, for example, request, isn't set, since the value is
915 * supposed to be inherited from the openAndX call.
917 int smb_ChainFID(int fid, smb_packet_t *inp)
919 if (inp->fid == 0 || inp->inCount == 0) return fid;
920 else return inp->fid;
923 /* are we a priv'd user? What does this mean on NT? */
924 int smb_SUser(cm_user_t *userp)
929 /* find a file ID. If pass in 0, we'll allocate on on a create operation. */
930 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
935 /* figure out if we need to allocate a new file ID */
938 fid = vcp->fidCounter;
942 lock_ObtainWrite(&smb_rctLock);
944 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
945 if (fid == fidp->fid) {
948 if (fid == 0) fid = 1;
955 if (!fidp && (flags & SMB_FLAG_CREATE)) {
956 fidp = malloc(sizeof(*fidp));
957 memset(fidp, 0, sizeof(*fidp));
958 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
961 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
963 fidp->curr_chunk = fidp->prev_chunk = -2;
964 fidp->raw_write_event = thrd_CreateEvent(NULL, FALSE, TRUE, NULL);
966 vcp->fidCounter = fid+1;
967 if (vcp->fidCounter == 0) vcp->fidCounter = 1;
970 lock_ReleaseWrite(&smb_rctLock);
974 void smb_ReleaseFID(smb_fid_t *fidp)
981 lock_ObtainWrite(&smb_rctLock);
982 osi_assert(fidp->refCount-- > 0);
983 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
985 if (!(fidp->flags & SMB_FID_IOCTL))
987 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
988 thrd_CloseHandle(fidp->raw_write_event);
990 /* and see if there is ioctl stuff to free */
991 ioctlp = fidp->ioctlp;
993 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
994 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
995 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1001 lock_ReleaseWrite(&smb_rctLock);
1003 /* now release the scache structure */
1004 if (scp) cm_ReleaseSCache(scp);
1008 * Case-insensitive search for one string in another;
1009 * used to find variable names in submount pathnames.
1011 static char *smb_stristr(char *str1, char *str2)
1015 for (cursor = str1; *cursor; cursor++)
1016 if (stricmp(cursor, str2) == 0)
1023 * Substitute a variable value for its name in a submount pathname. Variable
1024 * name has been identified by smb_stristr() and is in substr. Variable name
1025 * length (plus one) is in substr_size. Variable value is in newstr.
1027 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1032 strcpy(temp, substr + substr_size - 1);
1033 strcpy(substr, newstr);
1037 char VNUserName[] = "%USERNAME%";
1038 char VNLCUserName[] = "%LCUSERNAME%";
1039 char VNComputerName[] = "%COMPUTERNAME%";
1040 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1042 /* List available shares */
1043 int smb_ListShares()
1047 char shareBuf[4096];
1055 /*strcpy(shareNameList[num_shares], "all");
1056 strcpy(pathNameList[num_shares++], "/afs");*/
1057 fprintf(stderr, "The following shares are available:\n");
1058 fprintf(stderr, "Share Name (AFS Path)\n");
1059 fprintf(stderr, "---------------------\n");
1060 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1063 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1064 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1066 strcpy(sbmtpath, cm_confDir);
1068 strcat(sbmtpath, "/afsdsbmt.ini");
1069 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1070 shareBuf, sizeof(shareBuf),
1076 this_share = shareBuf;
1080 /*strcpy(shareNameList[num_shares], this_share);*/
1081 len = GetPrivateProfileString("AFS Submounts", this_share,
1085 if (!len) return num_shares;
1087 if (strncmp(p, cm_mountRoot, 4) != 0)
1090 if (*p == '\\') *p = '/'; /* change to / */
1094 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1095 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1098 while (*this_share != 0) this_share++; /* find next NUL */
1099 this_share++; /* skip past the NUL */
1100 } while (*this_share != 0); /* stop at final NUL */
1105 /* find a shareName in the table of submounts */
1106 int smb_FindShare(smb_vc_t *vcp, smb_packet_t *inp, char *shareName,
1110 char pathName[1024];
1118 if (strcmp(shareName, "IPC$") == 0) {
1123 if (_stricmp(shareName, "all") == 0) {
1129 strcpy(sbmtpath, "afsdsbmt.ini");
1131 strcpy(sbmtpath, cm_confDir);
1132 strcat(sbmtpath, "/afsdsbmt.ini");
1134 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1135 pathName, sizeof(pathName), sbmtpath);
1136 if (len == 0 || len == sizeof(pathName) - 1) {
1141 /* We can accept either unix or PC style AFS pathnames. Convert
1142 Unix-style to PC style here for internal use. */
1144 if (strncmp(p, cm_mountRoot, 4) == 0)
1145 p += strlen(cm_mountRoot); /* skip mount path */
1148 if (*q == '/') *q = '\\'; /* change to \ */
1154 if (var = smb_stristr(p, VNUserName)) {
1155 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1156 if (uidp && uidp->unp)
1157 smb_subst(p, var, sizeof(VNUserName),
1160 smb_subst(p, var, sizeof(VNUserName),
1162 smb_ReleaseUID(uidp);
1164 else if (var = smb_stristr(p, VNLCUserName)) {
1165 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1166 if (uidp && uidp->unp)
1167 strcpy(temp, uidp->unp->name);
1168 else strcpy(temp, " ");
1170 smb_subst(p, var, sizeof(VNLCUserName), temp);
1171 smb_ReleaseUID(uidp);
1173 else if (var = smb_stristr(p, VNComputerName)) {
1174 sizeTemp = sizeof(temp);
1175 GetComputerName((LPTSTR)temp, &sizeTemp);
1176 smb_subst(p, var, sizeof(VNComputerName),
1179 else if (var = smb_stristr(p, VNLCComputerName)) {
1180 sizeTemp = sizeof(temp);
1181 GetComputerName((LPTSTR)temp, &sizeTemp);
1183 smb_subst(p, var, sizeof(VNLCComputerName),
1189 *pathNamep = strdup(p);
1193 /* find a dir search structure by cookie value, and return it held.
1194 * Must be called with smb_globalLock held.
1196 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1198 smb_dirSearch_t *dsp;
1200 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1201 if (dsp->cookie == cookie) {
1202 if (dsp != smb_firstDirSearchp) {
1203 /* move to head of LRU queue, too, if we're not already there */
1204 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1205 smb_lastDirSearchp = (smb_dirSearch_t *)
1207 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1208 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1209 if (!smb_lastDirSearchp)
1210 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1219 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1221 lock_ObtainWrite(&smb_globalLock);
1222 dsp->flags |= SMB_DIRSEARCH_DELETE;
1223 lock_ReleaseWrite(&smb_globalLock);
1224 lock_ObtainMutex(&dsp->mx);
1225 if(dsp->scp != NULL) {
1226 lock_ObtainMutex(&dsp->scp->mx);
1227 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1228 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1229 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1230 dsp->scp->bulkStatProgress = hones;
1232 lock_ReleaseMutex(&dsp->scp->mx);
1234 lock_ReleaseMutex(&dsp->mx);
1237 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1243 lock_ObtainWrite(&smb_globalLock);
1244 osi_assert(dsp->refCount-- > 0);
1245 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1246 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1247 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1248 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1249 lock_FinalizeMutex(&dsp->mx);
1253 lock_ReleaseWrite(&smb_globalLock);
1255 /* do this now to avoid spurious locking hierarchy creation */
1256 if (scp) cm_ReleaseSCache(scp);
1259 /* find a dir search structure by cookie value, and return it held */
1260 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1262 smb_dirSearch_t *dsp;
1264 lock_ObtainWrite(&smb_globalLock);
1265 dsp = smb_FindDirSearchNL(cookie);
1266 lock_ReleaseWrite(&smb_globalLock);
1270 /* GC some dir search entries, in the address space expected by the specific protocol.
1271 * Must be called with smb_globalLock held; release the lock temporarily.
1273 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1274 void smb_GCDirSearches(int isV3)
1276 smb_dirSearch_t *prevp;
1277 smb_dirSearch_t *tp;
1278 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1282 victimCount = 0; /* how many have we got so far */
1283 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1284 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q); /* we'll move tp from queue, so
1287 /* if no one is using this guy, and we're either in the new protocol,
1288 * or we're in the old one and this is a small enough ID to be useful
1289 * to the old protocol, GC this guy.
1291 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1292 /* hold and delete */
1293 tp->flags |= SMB_DIRSEARCH_DELETE;
1294 victimsp[victimCount++] = tp;
1298 /* don't do more than this */
1299 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1302 /* now release them */
1303 lock_ReleaseWrite(&smb_globalLock);
1304 for(i = 0; i < victimCount; i++) {
1305 smb_ReleaseDirSearch(victimsp[i]);
1307 lock_ObtainWrite(&smb_globalLock);
1310 /* function for allocating a dir search entry. We need these to remember enough context
1311 * since we don't get passed the path from call to call during a directory search.
1313 * Returns a held dir search structure, and bumps the reference count on the vnode,
1314 * since it saves a pointer to the vnode.
1316 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1318 smb_dirSearch_t *dsp;
1322 lock_ObtainWrite(&smb_globalLock);
1325 /* what's the biggest ID allowed in this version of the protocol */
1326 if (isV3) maxAllowed = 65535;
1327 else maxAllowed = 255;
1330 /* twice so we have enough tries to find guys we GC after one pass;
1331 * 10 extra is just in case I mis-counted.
1333 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1334 __FILE__, __LINE__);
1335 if (smb_dirSearchCounter > maxAllowed) {
1336 smb_dirSearchCounter = 1;
1337 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1339 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1341 /* don't need to watch for refcount zero and deleted, since
1342 * we haven't dropped the global lock.
1345 ++smb_dirSearchCounter;
1349 dsp = malloc(sizeof(*dsp));
1350 memset(dsp, 0, sizeof(*dsp));
1351 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1352 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1353 dsp->cookie = smb_dirSearchCounter;
1354 ++smb_dirSearchCounter;
1356 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1357 dsp->lastTime = osi_Time();
1360 lock_ReleaseWrite(&smb_globalLock);
1364 static smb_packet_t *GetPacket(void)
1368 unsigned int npar, seg, tb_sel;
1371 lock_ObtainWrite(&smb_globalLock);
1372 tbp = smb_packetFreeListp;
1373 if (tbp) smb_packetFreeListp = tbp->nextp;
1374 lock_ReleaseWrite(&smb_globalLock);
1377 tbp = calloc(65540,1);
1379 tbp = malloc(sizeof(smb_packet_t));
1381 tbp->magic = SMB_PACKETMAGIC;
1384 tbp->resumeCode = 0;
1390 tbp->ncb_length = 0;
1394 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1397 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1399 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1401 osi_panic("",__FILE__,__LINE__);
1404 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1409 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1410 tbp->dos_pkt_sel = tb_sel;
1413 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1418 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1422 memcpy(tbp, pkt, sizeof(smb_packet_t));
1423 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1427 static NCB *GetNCB(void)
1432 unsigned int npar, seg, tb_sel;
1435 lock_ObtainWrite(&smb_globalLock);
1436 tbp = smb_ncbFreeListp;
1438 smb_ncbFreeListp = tbp->nextp;
1439 lock_ReleaseWrite(&smb_globalLock);
1442 tbp = calloc(sizeof(*tbp),1);
1444 tbp = malloc(sizeof(*tbp));
1445 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1448 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1450 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1452 osi_panic("",__FILE__,__LINE__);
1454 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1459 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1460 tbp->dos_ncb_sel = tb_sel;
1462 tbp->magic = SMB_NCBMAGIC;
1465 osi_assert(tbp->magic == SMB_NCBMAGIC);
1467 memset(&tbp->ncb, 0, sizeof(NCB));
1470 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1475 void smb_FreePacket(smb_packet_t *tbp)
1477 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1479 lock_ObtainWrite(&smb_globalLock);
1480 tbp->nextp = smb_packetFreeListp;
1481 smb_packetFreeListp = tbp;
1482 tbp->magic = SMB_PACKETMAGIC;
1485 tbp->resumeCode = 0;
1491 tbp->ncb_length = 0;
1493 lock_ReleaseWrite(&smb_globalLock);
1496 static void FreeNCB(NCB *bufferp)
1500 tbp = (smb_ncb_t *) bufferp;
1501 osi_assert(tbp->magic == SMB_NCBMAGIC);
1503 lock_ObtainWrite(&smb_globalLock);
1504 tbp->nextp = smb_ncbFreeListp;
1505 smb_ncbFreeListp = tbp;
1506 lock_ReleaseWrite(&smb_globalLock);
1509 /* get a ptr to the data part of a packet, and its count */
1510 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1514 unsigned char *afterParmsp;
1516 parmBytes = *smbp->wctp << 1;
1517 afterParmsp = smbp->wctp + parmBytes + 1;
1519 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1520 if (nbytesp) *nbytesp = dataBytes;
1522 /* don't forget to skip the data byte count, since it follows
1523 * the parameters; that's where the "2" comes from below.
1525 return (unsigned char *) (afterParmsp + 2);
1528 /* must set all the returned parameters before playing around with the
1529 * data region, since the data region is located past the end of the
1530 * variable number of parameters.
1532 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1534 unsigned char *afterParmsp;
1536 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1538 *afterParmsp++ = dsize & 0xff;
1539 *afterParmsp = (dsize>>8) & 0xff;
1542 /* return the parm'th parameter in the smbp packet */
1543 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1546 unsigned char *parmDatap;
1548 parmCount = *smbp->wctp;
1550 if (parm >= parmCount) {
1555 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1556 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1557 parm, parmCount, smbp->ncb_length);
1559 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1560 1, smbp->ncb_length, ptbuf, smbp);
1561 DeregisterEventSource(h);
1565 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1566 parm, parmCount, smbp->ncb_length);
1567 osi_Log0(afsd_logp, s);
1569 osi_panic(s, __FILE__, __LINE__);
1571 parmDatap = smbp->wctp + (2*parm) + 1;
1573 return parmDatap[0] + (parmDatap[1] << 8);
1576 /* return the parm'th parameter in the smbp packet */
1577 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1580 unsigned char *parmDatap;
1582 parmCount = *smbp->wctp;
1584 if (parm * 2 + offset >= parmCount * 2) {
1589 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1590 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1591 parm, offset, parmCount, smbp->ncb_length);
1593 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1594 1, smbp->ncb_length, ptbuf, smbp);
1595 DeregisterEventSource(h);
1599 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1601 parm, offset, parmCount, smbp->ncb_length);
1602 osi_Log0(afsd_logp, s);
1605 osi_panic(s, __FILE__, __LINE__);
1607 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1609 return parmDatap[0] + (parmDatap[1] << 8);
1612 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1616 /* make sure we have enough slots */
1617 if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1619 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1620 *parmDatap++ = parmValue & 0xff;
1621 *parmDatap = (parmValue>>8) & 0xff;
1624 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1628 /* make sure we have enough slots */
1629 if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1631 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1632 *parmDatap++ = parmValue & 0xff;
1633 *parmDatap++ = (parmValue>>8) & 0xff;
1634 *parmDatap++ = (parmValue>>16) & 0xff;
1635 *parmDatap++ = (parmValue>>24) & 0xff;
1638 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1643 /* make sure we have enough slots */
1644 if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1646 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1648 *parmDatap++ = *parmValuep++;
1651 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1655 /* make sure we have enough slots */
1656 if (*smbp->wctp <= slot) {
1657 if (smbp->oddByte) {
1659 *smbp->wctp = slot+1;
1664 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1665 *parmDatap++ = parmValue & 0xff;
1668 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1672 lastSlashp = strrchr(inPathp, '\\');
1674 *lastComponentp = lastSlashp;
1677 if (inPathp == lastSlashp) break;
1678 *outPathp++ = *inPathp++;
1687 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1689 if (*inp++ != 0x4) return NULL;
1691 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
1696 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1700 if (*inp++ != 0x5) return NULL;
1701 tlen = inp[0] + (inp[1]<<8);
1702 inp += 2; /* skip length field */
1705 *chainpp = inp + tlen;
1708 if (lengthp) *lengthp = tlen;
1713 /* format a packet as a response */
1714 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1719 outp = (smb_t *) op;
1721 /* zero the basic structure through the smb_wct field, and zero the data
1722 * size field, assuming that wct stays zero; otherwise, you have to
1723 * explicitly set the data size field, too.
1725 inSmbp = (smb_t *) inp;
1726 memset(outp, 0, sizeof(smb_t)+2);
1732 outp->com = inSmbp->com;
1733 outp->tid = inSmbp->tid;
1734 outp->pid = inSmbp->pid;
1735 outp->uid = inSmbp->uid;
1736 outp->mid = inSmbp->mid;
1737 outp->res[0] = inSmbp->res[0];
1738 outp->res[1] = inSmbp->res[1];
1739 op->inCom = inSmbp->com;
1741 outp->reb = 0x80; /* SERVER_RESP */
1742 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
1744 /* copy fields in generic packet area */
1745 op->wctp = &outp->wct;
1748 /* send a (probably response) packet; vcp tells us to whom to send it.
1749 * we compute the length by looking at wct and bcc fields.
1751 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1768 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
1771 memset((char *)ncbp, 0, sizeof(NCB));
1773 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
1774 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
1775 extra += tp[0] + (tp[1]<<8);
1776 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
1777 extra += 3; /* wct and length fields */
1779 ncbp->ncb_length = extra; /* bytes to send */
1780 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
1781 ncbp->ncb_lana_num = vcp->lana;
1782 ncbp->ncb_command = NCBSEND; /* op means send data */
1784 ncbp->ncb_buffer = (char *) inp;/* packet */
1785 code = Netbios(ncbp);
1787 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
1788 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
1790 /* copy header information from virtual to DOS address space */
1791 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
1792 code = Netbios(ncbp, dos_ncb);
1796 osi_Log1(afsd_logp, "SendPacket failure code %d", code);
1802 void smb_MapNTError(long code, unsigned long *NTStatusp)
1804 unsigned long NTStatus;
1806 /* map CM_ERROR_* errors to NT 32-bit status codes */
1807 if (code == CM_ERROR_NOSUCHCELL) {
1808 NTStatus = 0xC000000FL; /* No such file */
1810 else if (code == CM_ERROR_NOSUCHVOLUME) {
1811 NTStatus = 0xC000000FL; /* No such file */
1813 else if (code == CM_ERROR_TIMEDOUT) {
1814 NTStatus = 0xC00000CFL; /* Sharing Paused */
1816 else if (code == CM_ERROR_RETRY) {
1817 NTStatus = 0xC000022DL; /* Retry */
1819 else if (code == CM_ERROR_NOACCESS) {
1820 NTStatus = 0xC0000022L; /* Access denied */
1822 else if (code == CM_ERROR_READONLY) {
1823 NTStatus = 0xC00000A2L; /* Write protected */
1825 else if (code == CM_ERROR_NOSUCHFILE) {
1826 NTStatus = 0xC000000FL; /* No such file */
1828 else if (code == CM_ERROR_NOSUCHPATH) {
1829 NTStatus = 0xC000003AL; /* Object path not found */
1831 else if (code == CM_ERROR_TOOBIG) {
1832 NTStatus = 0xC000007BL; /* Invalid image format */
1834 else if (code == CM_ERROR_INVAL) {
1835 NTStatus = 0xC000000DL; /* Invalid parameter */
1837 else if (code == CM_ERROR_BADFD) {
1838 NTStatus = 0xC0000008L; /* Invalid handle */
1840 else if (code == CM_ERROR_BADFDOP) {
1841 NTStatus = 0xC0000022L; /* Access denied */
1843 else if (code == CM_ERROR_EXISTS) {
1844 NTStatus = 0xC0000035L; /* Object name collision */
1846 else if (code == CM_ERROR_NOTEMPTY) {
1847 NTStatus = 0xC0000101L; /* Directory not empty */
1849 else if (code == CM_ERROR_CROSSDEVLINK) {
1850 NTStatus = 0xC00000D4L; /* Not same device */
1852 else if (code == CM_ERROR_NOTDIR) {
1853 NTStatus = 0xC0000103L; /* Not a directory */
1855 else if (code == CM_ERROR_ISDIR) {
1856 NTStatus = 0xC00000BAL; /* File is a directory */
1858 else if (code == CM_ERROR_BADOP) {
1859 NTStatus = 0xC09820FFL; /* SMB no support */
1861 else if (code == CM_ERROR_BADSHARENAME) {
1862 NTStatus = 0xC00000CCL; /* Bad network name */
1864 else if (code == CM_ERROR_NOIPC) {
1866 NTStatus = 0xC0000022L; /* Access Denied */
1868 NTStatus = 0xC000013DL; /* Remote Resources */
1871 else if (code == CM_ERROR_CLOCKSKEW) {
1872 NTStatus = 0xC0000133L; /* Time difference at DC */
1874 else if (code == CM_ERROR_BADTID) {
1875 NTStatus = 0xC0982005L; /* SMB bad TID */
1877 else if (code == CM_ERROR_USESTD) {
1878 NTStatus = 0xC09820FBL; /* SMB use standard */
1880 else if (code == CM_ERROR_QUOTA) {
1881 NTStatus = 0xC0000044L; /* Quota exceeded */
1883 else if (code == CM_ERROR_SPACE) {
1884 NTStatus = 0xC000007FL; /* Disk full */
1886 else if (code == CM_ERROR_ATSYS) {
1887 NTStatus = 0xC0000033L; /* Object name invalid */
1889 else if (code == CM_ERROR_BADNTFILENAME) {
1890 NTStatus = 0xC0000033L; /* Object name invalid */
1892 else if (code == CM_ERROR_WOULDBLOCK) {
1893 NTStatus = 0xC0000055L; /* Lock not granted */
1895 else if (code == CM_ERROR_PARTIALWRITE) {
1896 NTStatus = 0xC000007FL; /* Disk full */
1898 else if (code == CM_ERROR_BUFFERTOOSMALL) {
1899 NTStatus = 0xC0000023L; /* Buffer too small */
1902 NTStatus = 0xC0982001L; /* SMB non-specific error */
1905 *NTStatusp = NTStatus;
1906 osi_Log2(afsd_logp, "SMB SEND code %x as NT %x", code, NTStatus);
1909 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
1910 unsigned char *classp)
1912 unsigned char class;
1913 unsigned short error;
1915 /* map CM_ERROR_* errors to SMB errors */
1916 if (code == CM_ERROR_NOSUCHCELL) {
1918 error = 3; /* bad path */
1920 else if (code == CM_ERROR_NOSUCHVOLUME) {
1922 error = 3; /* bad path */
1924 else if (code == CM_ERROR_TIMEDOUT) {
1926 error = 81; /* server is paused */
1928 else if (code == CM_ERROR_RETRY) {
1929 class = 2; /* shouldn't happen */
1932 else if (code == CM_ERROR_NOACCESS) {
1934 error = 4; /* bad access */
1936 else if (code == CM_ERROR_READONLY) {
1938 error = 19; /* read only */
1940 else if (code == CM_ERROR_NOSUCHFILE) {
1942 error = 2; /* ENOENT! */
1944 else if (code == CM_ERROR_NOSUCHPATH) {
1946 error = 3; /* Bad path */
1948 else if (code == CM_ERROR_TOOBIG) {
1950 error = 11; /* bad format */
1952 else if (code == CM_ERROR_INVAL) {
1953 class = 2; /* server non-specific error code */
1956 else if (code == CM_ERROR_BADFD) {
1958 error = 6; /* invalid file handle */
1960 else if (code == CM_ERROR_BADFDOP) {
1961 class = 1; /* invalid op on FD */
1964 else if (code == CM_ERROR_EXISTS) {
1966 error = 80; /* file already exists */
1968 else if (code == CM_ERROR_NOTEMPTY) {
1970 error = 5; /* delete directory not empty */
1972 else if (code == CM_ERROR_CROSSDEVLINK) {
1974 error = 17; /* EXDEV */
1976 else if (code == CM_ERROR_NOTDIR) {
1977 class = 1; /* bad path */
1980 else if (code == CM_ERROR_ISDIR) {
1981 class = 1; /* access denied; DOS doesn't have a good match */
1984 else if (code == CM_ERROR_BADOP) {
1988 else if (code == CM_ERROR_BADSHARENAME) {
1992 else if (code == CM_ERROR_NOIPC) {
1994 error = 4; /* bad access */
1996 else if (code == CM_ERROR_CLOCKSKEW) {
1997 class = 1; /* invalid function */
2000 else if (code == CM_ERROR_BADTID) {
2004 else if (code == CM_ERROR_USESTD) {
2008 else if (code == CM_ERROR_REMOTECONN) {
2012 else if (code == CM_ERROR_QUOTA) {
2013 if (vcp->flags & SMB_VCFLAG_USEV3) {
2015 error = 39; /* disk full */
2019 error = 5; /* access denied */
2022 else if (code == CM_ERROR_SPACE) {
2023 if (vcp->flags & SMB_VCFLAG_USEV3) {
2025 error = 39; /* disk full */
2029 error = 5; /* access denied */
2032 else if (code == CM_ERROR_PARTIALWRITE) {
2034 error = 39; /* disk full */
2036 else if (code == CM_ERROR_ATSYS) {
2038 error = 2; /* ENOENT */
2040 else if (code == CM_ERROR_WOULDBLOCK) {
2042 error = 33; /* lock conflict */
2044 else if (code == CM_ERROR_NOFILES) {
2046 error = 18; /* no files in search */
2048 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2050 error = 183; /* Samba uses this */
2059 osi_Log3(afsd_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2062 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2064 return CM_ERROR_BADOP;
2067 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2069 unsigned short EchoCount, i;
2070 char *data, *outdata;
2073 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2075 for (i=1; i<=EchoCount; i++) {
2076 data = smb_GetSMBData(inp, &dataSize);
2077 smb_SetSMBParm(outp, 0, i);
2078 smb_SetSMBDataLength(outp, dataSize);
2079 outdata = smb_GetSMBData(outp, NULL);
2080 memcpy(outdata, data, dataSize);
2081 smb_SendPacket(vcp, outp);
2087 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2090 long count, minCount, finalCount;
2094 cm_user_t *userp = NULL;
2098 char *rawBuf = NULL;
2100 dos_ptr rawBuf = NULL;
2107 fd = smb_GetSMBParm(inp, 0);
2108 count = smb_GetSMBParm(inp, 3);
2109 minCount = smb_GetSMBParm(inp, 4);
2110 offset.HighPart = 0; /* too bad */
2111 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2113 osi_Log3(afsd_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2114 fd, offset.LowPart, count);
2116 fidp = smb_FindFID(vcp, fd, 0);
2120 lock_ObtainMutex(&smb_RawBufLock);
2122 /* Get a raw buf, from head of list */
2123 rawBuf = smb_RawBufs;
2125 smb_RawBufs = *(char **)smb_RawBufs;
2127 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2130 lock_ReleaseMutex(&smb_RawBufLock);
2134 if (fidp->flags & SMB_FID_IOCTL)
2137 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2139 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2142 /* Give back raw buffer */
2143 lock_ObtainMutex(&smb_RawBufLock);
2145 *((char **) rawBuf) = smb_RawBufs;
2147 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2150 smb_RawBufs = rawBuf;
2151 lock_ReleaseMutex(&smb_RawBufLock);
2156 userp = smb_GetUser(vcp, inp);
2159 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2161 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2162 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2163 userp, &finalCount, TRUE /* rawFlag */);
2170 cm_ReleaseUser(userp);
2172 smb_ReleaseFID(fidp);
2177 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2179 memset((char *)ncbp, 0, sizeof(NCB));
2181 ncbp->ncb_length = (unsigned short) finalCount;
2182 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2183 ncbp->ncb_lana_num = vcp->lana;
2184 ncbp->ncb_command = NCBSEND;
2185 ncbp->ncb_buffer = rawBuf;
2188 code = Netbios(ncbp);
2190 code = Netbios(ncbp, dos_ncb);
2193 osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
2196 /* Give back raw buffer */
2197 lock_ObtainMutex(&smb_RawBufLock);
2199 *((char **) rawBuf) = smb_RawBufs;
2201 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2204 smb_RawBufs = rawBuf;
2205 lock_ReleaseMutex(&smb_RawBufLock);
2211 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2216 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2221 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2227 int protoIndex; /* index we're using */
2232 char protocol_array[10][1024]; /* protocol signature of the client */
2235 osi_Log1(afsd_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2239 DWORD now = GetCurrentTime();
2240 if (now - last_msg_time >= 30000
2241 && now - last_msg_time <= 90000) {
2243 "Setting dead_vcp %x", active_vcp);
2244 dead_vcp = active_vcp;
2245 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2250 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2252 namep = smb_GetSMBData(inp, &dbytes);
2255 coreProtoIndex = -1; /* not found */
2258 while(namex < dbytes) {
2259 osi_Log1(afsd_logp, "Protocol %s",
2260 osi_LogSaveString(afsd_logp, namep+1));
2261 strcpy(protocol_array[tcounter], namep+1);
2263 /* namep points at the first protocol, or really, a 0x02
2264 * byte preceding the null-terminated ASCII name.
2266 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2267 coreProtoIndex = tcounter;
2269 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2270 v3ProtoIndex = tcounter;
2272 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2273 NTProtoIndex = tcounter;
2276 /* compute size of protocol entry */
2277 entryLength = strlen(namep+1);
2278 entryLength += 2; /* 0x02 bytes and null termination */
2280 /* advance over this protocol entry */
2281 namex += entryLength;
2282 namep += entryLength;
2283 tcounter++; /* which proto entry we're looking at */
2285 #ifndef NOMOREFILESFIX
2287 * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
2288 * the client is running by reading the protocol signature.
2289 * ie. the order in which it sends us the protocol list.
2291 * Special handling for Windows 2000 clients (defect 11765 )
2293 if (tcounter == 6) {
2295 smb_t *ip = (smb_t *) inp;
2296 smb_t *op = (smb_t *) outp;
2298 if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
2299 (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
2300 (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
2301 (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
2302 (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
2303 (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
2304 isWindows2000 = TRUE;
2305 osi_Log0(afsd_logp, "Looks like a Windows 2000 client");
2307 * HACK: for now - just negotiate a lower protocol till we
2308 * figure out which flag/flag2 or some other field
2309 * (capabilities maybe?) to set in order for this to work
2310 * correctly with Windows 2000 clients (defect 11765)
2313 /* Things to try (after looking at tcpdump output could be
2314 * setting flags and flags2 to 0x98 and 0xc853 like this
2315 * op->reb = 0x98; op->flg2 = 0xc853;
2316 * osi_Log2(afsd_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
2323 if (NTProtoIndex != -1) {
2324 protoIndex = NTProtoIndex;
2325 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2327 else if (v3ProtoIndex != -1) {
2328 protoIndex = v3ProtoIndex;
2329 vcp->flags |= SMB_VCFLAG_USEV3;
2331 else if (coreProtoIndex != -1) {
2332 protoIndex = coreProtoIndex;
2333 vcp->flags |= SMB_VCFLAG_USECORE;
2335 else protoIndex = -1;
2337 if (protoIndex == -1)
2338 return CM_ERROR_INVAL;
2339 else if (NTProtoIndex != -1) {
2340 smb_SetSMBParm(outp, 0, protoIndex);
2341 smb_SetSMBParmByte(outp, 1, 0); /* share level security, no passwd encrypt */
2342 smb_SetSMBParm(outp, 1, 8); /* max multiplexed requests */
2343 smb_SetSMBParm(outp, 2, 100); /* max VCs per consumer/server connection */
2344 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2345 smb_SetSMBParmLong(outp, 5, 65536); /* raw buffer size */
2346 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2347 smb_SetSMBParm(outp, 8, 1);
2349 * Tried changing the capabilities to support for W2K - defect 117695
2350 * Maybe something else needs to be changed here?
2354 smb_SetSMBParmLong(outp, 9, 0x43fd);
2356 smb_SetSMBParmLong(outp, 9, 0x251);
2358 smb_SetSMBParmLong(outp, 9, 0x251); /* Capabilities: *
2359 * 32-bit error codes *
2363 smb_SetSMBParmLong(outp, 11, 0);/* XXX server time: do we need? */
2364 smb_SetSMBParmLong(outp, 13, 0);/* XXX server date: do we need? */
2365 smb_SetSMBParm(outp, 15, 0); /* XXX server tzone: do we need? */
2366 smb_SetSMBParmByte(outp, 16, 0);/* Encryption key length */
2367 smb_SetSMBDataLength(outp, 0); /* perhaps should specify 8 bytes anyway */
2369 else if (v3ProtoIndex != -1) {
2370 smb_SetSMBParm(outp, 0, protoIndex);
2371 smb_SetSMBParm(outp, 1, 0); /* share level security, no passwd encrypt */
2372 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2373 smb_SetSMBParm(outp, 3, 8); /* max multiplexed requests */
2374 smb_SetSMBParm(outp, 4, 100); /* max VCs per consumer/server connection */
2375 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2376 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2377 smb_SetSMBParm(outp, 7, 1);
2378 smb_SetSMBParm(outp, 8, 0); /* XXX server time: do we need? */
2379 smb_SetSMBParm(outp, 9, 0); /* XXX server date: do we need? */
2380 smb_SetSMBParm(outp, 10, 0); /* XXX server tzone: do we need? */
2381 smb_SetSMBParm(outp, 11, 0); /* resvd */
2382 smb_SetSMBParm(outp, 12, 0); /* resvd */
2383 smb_SetSMBDataLength(outp, 0); /* perhaps should specify 8 bytes anyway */
2385 else if (coreProtoIndex != -1) {
2386 smb_SetSMBParm(outp, 0, protoIndex);
2387 smb_SetSMBDataLength(outp, 0);
2392 void smb_Daemon(void *parmp)
2399 if ((count % 360) == 0) /* every hour */
2400 smb_CalculateNowTZ();
2401 /* XXX GC dir search entries */
2405 void smb_WaitingLocksDaemon()
2407 smb_waitingLock_t *wL, *nwL;
2410 smb_packet_t *inp, *outp;
2415 lock_ObtainWrite(&smb_globalLock);
2416 nwL = smb_allWaitingLocks;
2418 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2427 lock_ObtainWrite(&smb_globalLock);
2429 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2430 lock_ReleaseWrite(&smb_globalLock);
2431 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2432 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2433 if (code == CM_ERROR_WOULDBLOCK) {
2435 if (wL->timeRemaining != 0xffffffff
2436 && (wL->timeRemaining -= 1000) < 0)
2445 ncbp->ncb_length = inp->ncb_length;
2446 inp->spacep = cm_GetSpace();
2448 /* Remove waitingLock from list */
2449 lock_ObtainWrite(&smb_globalLock);
2450 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2452 lock_ReleaseWrite(&smb_globalLock);
2454 /* Resume packet processing */
2456 smb_SetSMBDataLength(outp, 0);
2457 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2458 outp->resumeCode = code;
2460 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2463 cm_FreeSpace(inp->spacep);
2464 smb_FreePacket(inp);
2465 smb_FreePacket(outp);
2473 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2475 osi_Log0(afsd_logp, "SMB receive get disk attributes");
2477 smb_SetSMBParm(outp, 0, 32000);
2478 smb_SetSMBParm(outp, 1, 64);
2479 smb_SetSMBParm(outp, 2, 1024);
2480 smb_SetSMBParm(outp, 3, 30000);
2481 smb_SetSMBParm(outp, 4, 0);
2482 smb_SetSMBDataLength(outp, 0);
2486 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2489 unsigned short newTid;
2490 char shareName[256];
2498 osi_Log0(afsd_logp, "SMB receive tree connect");
2500 /* parse input parameters */
2501 tp = smb_GetSMBData(inp, NULL);
2502 pathp = smb_ParseASCIIBlock(tp, &tp);
2503 passwordp = smb_ParseASCIIBlock(tp, &tp);
2504 tp = strrchr(pathp, '\\');
2506 return CM_ERROR_BADSMB;
2507 strcpy(shareName, tp+1);
2509 userp = smb_GetUser(vcp, inp);
2511 lock_ObtainMutex(&vcp->mx);
2512 newTid = vcp->tidCounter++;
2513 lock_ReleaseMutex(&vcp->mx);
2515 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2516 shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
2518 smb_ReleaseTID(tidp);
2519 return CM_ERROR_BADSHARENAME;
2521 lock_ObtainMutex(&tidp->mx);
2522 tidp->userp = userp;
2523 tidp->pathname = sharePath;
2524 lock_ReleaseMutex(&tidp->mx);
2525 smb_ReleaseTID(tidp);
2527 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2528 smb_SetSMBParm(rsp, 1, newTid);
2529 smb_SetSMBDataLength(rsp, 0);
2531 osi_Log1(afsd_logp, "SMB tree connect created ID %d", newTid);
2535 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2539 if (*inp++ != 0x1) return NULL;
2540 tlen = inp[0] + (inp[1]<<8);
2541 inp += 2; /* skip length field */
2544 *chainpp = inp + tlen;
2547 if (lengthp) *lengthp = tlen;
2552 /* set maskp to the mask part of the incoming path.
2553 * Mask is 11 bytes long (8.3 with the dot elided).
2554 * Returns true if succeeds with a valid name, otherwise it does
2555 * its best, but returns false.
2557 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2565 /* starts off valid */
2568 /* mask starts out all blanks */
2569 memset(maskp, ' ', 11);
2571 /* find last backslash, or use whole thing if there is none */
2572 tp = strrchr(pathp, '\\');
2573 if (!tp) tp = pathp;
2574 else tp++; /* skip slash */
2578 /* names starting with a dot are illegal */
2579 if (*tp == '.') valid8Dot3 = 0;
2583 if (tc == 0) return valid8Dot3;
2584 if (tc == '.' || tc == '"') break;
2585 if (i < 8) *up++ = tc;
2586 else valid8Dot3 = 0;
2589 /* if we get here, tp point after the dot */
2590 up = maskp+8; /* ext goes here */
2593 if (tc == 0) return valid8Dot3;
2596 if (tc == '.' || tc == '"') valid8Dot3 = 0;
2598 /* copy extension if not too long */
2599 if (i < 3) *up++ = tc;
2600 else valid8Dot3 = 0;
2604 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2614 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2616 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2617 if (!valid) return 0;
2619 /* otherwise, we have a valid 8.3 name; see if we have a match,
2620 * treating '?' as a wildcard in maskp (but not in the file name).
2622 tp1 = umask; /* real name, in mask format */
2623 tp2 = maskp; /* mask, in mask format */
2624 for(i=0; i<11; i++) {
2625 tc1 = *tp1++; /* char from real name */
2626 tc2 = *tp2++; /* char from mask */
2627 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
2628 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
2629 if (tc1 == tc2) continue;
2630 if (tc2 == '?' && tc1 != ' ') continue;
2631 if (tc2 == '>') continue;
2635 /* we got a match */
2639 char *smb_FindMask(char *pathp)
2643 tp = strrchr(pathp, '\\'); /* find last slash */
2645 if (tp) return tp+1; /* skip the slash */
2646 else return pathp; /* no slash, return the entire path */
2649 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2651 unsigned char *pathp;
2653 unsigned char mask[11];
2654 unsigned char *statBlockp;
2655 unsigned char initStatBlock[21];
2658 osi_Log0(afsd_logp, "SMB receive search volume");
2660 /* pull pathname and stat block out of request */
2661 tp = smb_GetSMBData(inp, NULL);
2662 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
2663 osi_assert(pathp != NULL);
2664 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
2665 osi_assert(statBlockp != NULL);
2667 statBlockp = initStatBlock;
2671 /* for returning to caller */
2672 smb_Get8Dot3MaskFromPath(mask, pathp);
2674 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
2675 tp = smb_GetSMBData(outp, NULL);
2677 *tp++ = 43; /* bytes in a dir entry */
2678 *tp++ = 0; /* high byte in counter */
2680 /* now marshall the dir entry, starting with the search status */
2681 *tp++ = statBlockp[0]; /* Reserved */
2682 memcpy(tp, mask, 11); tp += 11; /* FileName */
2684 /* now pass back server use info, with 1st byte non-zero */
2686 memset(tp, 0, 4); tp += 4; /* reserved for server use */
2688 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
2690 *tp++ = 0x8; /* attribute: volume */
2700 /* 4 byte file size */
2706 /* finally, null-terminated 8.3 pathname, which we set to AFS */
2707 memset(tp, ' ', 13);
2710 /* set the length of the data part of the packet to 43 + 3, for the dir
2711 * entry plus the 5 and the length fields.
2713 smb_SetSMBDataLength(outp, 46);
2717 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
2718 cm_user_t *userp, cm_req_t *reqp)
2726 smb_dirListPatch_t *patchp;
2727 smb_dirListPatch_t *npatchp;
2729 for(patchp = *dirPatchespp; patchp; patchp =
2730 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2731 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2733 lock_ObtainMutex(&scp->mx);
2734 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2735 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2737 lock_ReleaseMutex(&scp->mx);
2738 cm_ReleaseSCache(scp);
2741 dptr = patchp->dptr;
2743 attr = smb_Attributes(scp);
2747 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2750 shortTemp = dosTime & 0xffff;
2751 *((u_short *)dptr) = shortTemp;
2754 /* and copy out date */
2755 shortTemp = (dosTime>>16) & 0xffff;
2756 *((u_short *)dptr) = shortTemp;
2759 /* copy out file length */
2760 *((u_long *)dptr) = scp->length.LowPart;
2762 lock_ReleaseMutex(&scp->mx);
2763 cm_ReleaseSCache(scp);
2766 /* now free the patches */
2767 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2768 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
2772 /* and mark the list as empty */
2773 *dirPatchespp = NULL;
2778 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2787 smb_dirListPatch_t *dirListPatchesp;
2788 smb_dirListPatch_t *curPatchp;
2792 osi_hyper_t dirLength;
2793 osi_hyper_t bufferOffset;
2794 osi_hyper_t curOffset;
2796 unsigned char *inCookiep;
2797 smb_dirSearch_t *dsp;
2801 unsigned long clientCookie;
2802 cm_pageHeader_t *pageHeaderp;
2803 cm_user_t *userp = NULL;
2810 long nextEntryCookie;
2811 int numDirChunks; /* # of 32 byte dir chunks in this entry */
2812 char resByte; /* reserved byte from the cookie */
2813 char *op; /* output data ptr */
2814 char *origOp; /* original value of op */
2815 cm_space_t *spacep; /* for pathname buffer */
2826 maxCount = smb_GetSMBParm(inp, 0);
2828 dirListPatchesp = NULL;
2830 caseFold = CM_FLAG_CASEFOLD;
2832 tp = smb_GetSMBData(inp, NULL);
2833 pathp = smb_ParseASCIIBlock(tp, &tp);
2834 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
2836 /* bail out if request looks bad */
2837 if (!tp || !pathp) {
2838 return CM_ERROR_BADSMB;
2841 /* We can handle long names */
2842 if (vcp->flags & SMB_VCFLAG_USENT)
2843 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
2845 /* make sure we got a whole search status */
2846 if (dataLength < 21) {
2847 nextCookie = 0; /* start at the beginning of the dir */
2850 attribute = smb_GetSMBParm(inp, 1);
2852 /* handle volume info in another function */
2853 if (attribute & 0x8)
2854 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
2856 osi_Log2(afsd_logp, "SMB receive search dir count %d |%s|",
2857 maxCount, osi_LogSaveString(afsd_logp, pathp));
2859 if (*pathp == 0) { /* null pathp, treat as root dir */
2860 if (!(attribute & 0x10)) /* exclude dirs */
2861 return CM_ERROR_NOFILES;
2865 dsp = smb_NewDirSearch(0);
2866 dsp->attribute = attribute;
2867 smb_Get8Dot3MaskFromPath(mask, pathp);
2868 memcpy(dsp->mask, mask, 11);
2870 /* track if this is likely to match a lot of entries */
2871 if (smb_IsStarMask(mask)) starPattern = 1;
2872 else starPattern = 0;
2875 /* pull the next cookie value out of the search status block */
2876 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
2877 + (inCookiep[16]<<24);
2878 dsp = smb_FindDirSearch(inCookiep[12]);
2880 /* can't find dir search status; fatal error */
2881 return CM_ERROR_BADFD;
2883 attribute = dsp->attribute;
2884 resByte = inCookiep[0];
2886 /* copy out client cookie, in host byte order. Don't bother
2887 * interpreting it, since we're just passing it through, anyway.
2889 memcpy(&clientCookie, &inCookiep[17], 4);
2891 memcpy(mask, dsp->mask, 11);
2893 /* assume we're doing a star match if it has continued for more
2899 osi_Log3(afsd_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
2900 nextCookie, dsp->cookie, attribute);
2902 userp = smb_GetUser(vcp, inp);
2904 /* try to get the vnode for the path name next */
2905 lock_ObtainMutex(&dsp->mx);
2912 spacep = inp->spacep;
2913 smb_StripLastComponent(spacep->data, NULL, pathp);
2914 lock_ReleaseMutex(&dsp->mx);
2915 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2916 code = cm_NameI(cm_rootSCachep, spacep->data,
2917 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
2918 lock_ObtainMutex(&dsp->mx);
2920 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2922 /* we need one hold for the entry we just stored into,
2923 * and one for our own processing. When we're done with this
2924 * function, we'll drop the one for our own processing.
2925 * We held it once from the namei call, and so we do another hold
2929 lock_ObtainMutex(&scp->mx);
2930 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2931 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2932 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2933 dsp->flags |= SMB_DIRSEARCH_BULKST;
2935 lock_ReleaseMutex(&scp->mx);
2938 lock_ReleaseMutex(&dsp->mx);
2940 cm_ReleaseUser(userp);
2941 smb_DeleteDirSearch(dsp);
2942 smb_ReleaseDirSearch(dsp);
2946 /* reserves space for parameter; we'll adjust it again later to the
2947 * real count of the # of entries we returned once we've actually
2948 * assembled the directory listing.
2950 smb_SetSMBParm(outp, 0, 0);
2952 /* get the directory size */
2953 lock_ObtainMutex(&scp->mx);
2954 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2955 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2957 lock_ReleaseMutex(&scp->mx);
2958 cm_ReleaseSCache(scp);
2959 cm_ReleaseUser(userp);
2960 smb_DeleteDirSearch(dsp);
2961 smb_ReleaseDirSearch(dsp);
2965 dirLength = scp->length;
2967 bufferOffset.LowPart = bufferOffset.HighPart = 0;
2968 curOffset.HighPart = 0;
2969 curOffset.LowPart = nextCookie;
2970 origOp = op = smb_GetSMBData(outp, NULL);
2971 /* and write out the basic header */
2972 *op++ = 5; /* variable block */
2973 op += 2; /* skip vbl block length; we'll fill it in later */
2977 /* make sure that curOffset.LowPart doesn't point to the first
2978 * 32 bytes in the 2nd through last dir page, and that it doesn't
2979 * point at the first 13 32-byte chunks in the first dir page,
2980 * since those are dir and page headers, and don't contain useful
2983 temp = curOffset.LowPart & (2048-1);
2984 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2985 /* we're in the first page */
2986 if (temp < 13*32) temp = 13*32;
2989 /* we're in a later dir page */
2990 if (temp < 32) temp = 32;
2993 /* make sure the low order 5 bits are zero */
2996 /* now put temp bits back ito curOffset.LowPart */
2997 curOffset.LowPart &= ~(2048-1);
2998 curOffset.LowPart |= temp;
3000 /* check if we've returned all the names that will fit in the
3003 if (returnedNames >= maxCount) break;
3005 /* check if we've passed the dir's EOF */
3006 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3008 /* see if we can use the bufferp we have now; compute in which page
3009 * the current offset would be, and check whether that's the offset
3010 * of the buffer we have. If not, get the buffer.
3012 thyper.HighPart = curOffset.HighPart;
3013 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3014 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3017 buf_Release(bufferp);
3020 lock_ReleaseMutex(&scp->mx);
3021 lock_ObtainRead(&scp->bufCreateLock);
3022 code = buf_Get(scp, &thyper, &bufferp);
3023 lock_ReleaseRead(&scp->bufCreateLock);
3025 /* now, if we're doing a star match, do bulk fetching of all of
3026 * the status info for files in the dir.
3029 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3031 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3032 && LargeIntegerGreaterThanOrEqualTo(thyper,
3033 scp->bulkStatProgress)) {
3034 /* Don't bulk stat if risking timeout */
3035 int now = GetCurrentTime();
3036 if (now - req.startTime > 5000) {
3037 scp->bulkStatProgress = thyper;
3038 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3039 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3041 cm_TryBulkStat(scp, &thyper,
3046 lock_ObtainMutex(&scp->mx);
3048 bufferOffset = thyper;
3050 /* now get the data in the cache */
3052 code = cm_SyncOp(scp, bufferp, userp, &req,
3054 CM_SCACHESYNC_NEEDCALLBACK
3055 | CM_SCACHESYNC_READ);
3058 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3060 /* otherwise, load the buffer and try again */
3061 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3066 buf_Release(bufferp);
3070 } /* if (wrong buffer) ... */
3072 /* now we have the buffer containing the entry we're interested in; copy
3073 * it out if it represents a non-deleted entry.
3075 entryInDir = curOffset.LowPart & (2048-1);
3076 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3078 /* page header will help tell us which entries are free. Page header
3079 * can change more often than once per buffer, since AFS 3 dir page size
3080 * may be less than (but not more than a buffer package buffer.
3082 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3083 temp &= ~(2048 - 1); /* turn off intra-page bits */
3084 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3086 /* now determine which entry we're looking at in the page. If it is
3087 * free (there's a free bitmap at the start of the dir), we should
3088 * skip these 32 bytes.
3090 slotInPage = (entryInDir & 0x7e0) >> 5;
3091 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3092 /* this entry is free */
3093 numDirChunks = 1; /* only skip this guy */
3097 tp = bufferp->datap + entryInBuffer;
3098 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3100 /* while we're here, compute the next entry's location, too,
3101 * since we'll need it when writing out the cookie into the dir
3104 * XXXX Probably should do more sanity checking.
3106 numDirChunks = cm_NameEntries(dep->name, NULL);
3108 /* compute the offset of the cookie representing the next entry */
3109 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3111 /* Compute 8.3 name if necessary */
3112 actualName = dep->name;
3113 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3114 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3115 actualName = shortName;
3118 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3119 /* this is one of the entries to use: it is not deleted
3120 * and it matches the star pattern we're looking for.
3123 /* Eliminate entries that don't match requested
3125 if (!(dsp->attribute & 0x10)) /* no directories */
3127 /* We have already done the cm_TryBulkStat above */
3128 fid.cell = scp->fid.cell;
3129 fid.volume = scp->fid.volume;
3130 fid.vnode = ntohl(dep->fid.vnode);
3131 fid.unique = ntohl(dep->fid.unique);
3132 fileType = cm_FindFileType(&fid);
3133 osi_Log2(afsd_logp, "smb_ReceiveCoreSearchDir: file %s "
3134 "has filetype %d", dep->name,
3136 if (fileType == CM_SCACHETYPE_DIRECTORY)
3141 memcpy(op, mask, 11); op += 11;
3142 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3143 *op++ = nextEntryCookie & 0xff;
3144 *op++ = (nextEntryCookie>>8) & 0xff;
3145 *op++ = (nextEntryCookie>>16) & 0xff;
3146 *op++ = (nextEntryCookie>>24) & 0xff;
3147 memcpy(op, &clientCookie, 4); op += 4;
3149 /* now we emit the attribute. This is sort of tricky,
3150 * since we need to really stat the file to find out
3151 * what type of entry we've got. Right now, we're
3152 * copying out data from a buffer, while holding the
3153 * scp locked, so it isn't really convenient to stat
3154 * something now. We'll put in a place holder now,
3155 * and make a second pass before returning this to get
3156 * the real attributes. So, we just skip the data for
3157 * now, and adjust it later. We allocate a patch
3158 * record to make it easy to find this point later.
3159 * The replay will happen at a time when it is safe to
3160 * unlock the directory.
3162 curPatchp = malloc(sizeof(*curPatchp));
3163 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3164 curPatchp->dptr = op;
3165 curPatchp->fid.cell = scp->fid.cell;
3166 curPatchp->fid.volume = scp->fid.volume;
3167 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3168 curPatchp->fid.unique = ntohl(dep->fid.unique);
3169 op += 9; /* skip attr, time, date and size */
3171 /* zero out name area. The spec says to pad with
3172 * spaces, but Samba doesn't, and neither do we.
3176 /* finally, we get to copy out the name; we know that
3177 * it fits in 8.3 or the pattern wouldn't match, but it
3178 * never hurts to be sure.
3180 strncpy(op, actualName, 13);
3182 /* Uppercase if requested by client */
3183 if ((((smb_t *)inp)->flg2 & 1) == 0)
3188 /* now, adjust the # of entries copied */
3190 } /* if we're including this name */
3193 /* and adjust curOffset to be where the new cookie is */
3194 thyper.HighPart = 0;
3195 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3196 curOffset = LargeIntegerAdd(thyper, curOffset);
3197 } /* while copying data for dir listing */
3199 /* release the mutex */
3200 lock_ReleaseMutex(&scp->mx);
3201 if (bufferp) buf_Release(bufferp);
3203 /* apply and free last set of patches; if not doing a star match, this
3204 * will be empty, but better safe (and freeing everything) than sorry.
3206 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3208 /* special return code for unsuccessful search */
3209 if (code == 0 && dataLength < 21 && returnedNames == 0)
3210 code = CM_ERROR_NOFILES;
3212 osi_Log2(afsd_logp, "SMB search dir done, %d names, code %d",
3213 returnedNames, code);
3216 smb_DeleteDirSearch(dsp);
3217 smb_ReleaseDirSearch(dsp);
3218 cm_ReleaseSCache(scp);
3219 cm_ReleaseUser(userp);
3223 /* finalize the output buffer */
3224 smb_SetSMBParm(outp, 0, returnedNames);
3225 temp = (long) (op - origOp);
3226 smb_SetSMBDataLength(outp, temp);
3228 /* the data area is a variable block, which has a 5 (already there)
3229 * followed by the length of the # of data bytes. We now know this to
3230 * be "temp," although that includes the 3 bytes of vbl block header.
3231 * Deduct for them and fill in the length field.
3233 temp -= 3; /* deduct vbl block info */
3234 osi_assert(temp == (43 * returnedNames));
3235 origOp[1] = temp & 0xff;
3236 origOp[2] = (temp>>8) & 0xff;
3237 if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3238 smb_ReleaseDirSearch(dsp);
3239 cm_ReleaseSCache(scp);
3240 cm_ReleaseUser(userp);
3244 /* verify that this is a valid path to a directory. I don't know why they
3245 * don't use the get file attributes call.
3247 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3251 cm_scache_t *rootScp;
3252 cm_scache_t *newScp;
3261 pathp = smb_GetSMBData(inp, NULL);
3262 pathp = smb_ParseASCIIBlock(pathp, NULL);
3263 osi_Log1(afsd_logp, "SMB receive check path %s",
3264 osi_LogSaveString(afsd_logp, pathp));
3267 return CM_ERROR_BADFD;
3270 rootScp = cm_rootSCachep;
3272 userp = smb_GetUser(vcp, inp);
3274 caseFold = CM_FLAG_CASEFOLD;
3276 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3277 code = cm_NameI(rootScp, pathp,
3278 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3279 userp, tidPathp, &req, &newScp);
3282 cm_ReleaseUser(userp);
3286 /* now lock the vnode with a callback; returns with newScp locked */
3287 lock_ObtainMutex(&newScp->mx);
3288 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3289 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3290 if (code && code != CM_ERROR_NOACCESS) {
3291 lock_ReleaseMutex(&newScp->mx);
3292 cm_ReleaseSCache(newScp);
3293 cm_ReleaseUser(userp);
3297 attrs = smb_Attributes(newScp);
3299 if (!(attrs & 0x10))
3300 code = CM_ERROR_NOTDIR;
3302 lock_ReleaseMutex(&newScp->mx);
3304 cm_ReleaseSCache(newScp);
3305 cm_ReleaseUser(userp);
3309 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3313 cm_scache_t *rootScp;
3314 unsigned short attribute;
3316 cm_scache_t *newScp;
3325 /* decode basic attributes we're passed */
3326 attribute = smb_GetSMBParm(inp, 0);
3327 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3329 pathp = smb_GetSMBData(inp, NULL);
3330 pathp = smb_ParseASCIIBlock(pathp, NULL);
3333 return CM_ERROR_BADSMB;
3336 osi_Log2(afsd_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3337 dosTime, attribute);
3339 rootScp = cm_rootSCachep;
3341 userp = smb_GetUser(vcp, inp);
3343 caseFold = CM_FLAG_CASEFOLD;
3345 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3346 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3347 tidPathp, &req, &newScp);
3350 cm_ReleaseUser(userp);
3354 /* now lock the vnode with a callback; returns with newScp locked; we
3355 * need the current status to determine what the new status is, in some
3358 lock_ObtainMutex(&newScp->mx);
3359 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3360 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3362 lock_ReleaseMutex(&newScp->mx);
3363 cm_ReleaseSCache(newScp);
3364 cm_ReleaseUser(userp);
3368 /* Check for RO volume */
3369 if (newScp->flags & CM_SCACHEFLAG_RO) {
3370 lock_ReleaseMutex(&newScp->mx);
3371 cm_ReleaseSCache(newScp);
3372 cm_ReleaseUser(userp);
3373 return CM_ERROR_READONLY;
3376 /* prepare for setattr call */
3379 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3380 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3382 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3383 /* we're told to make a writable file read-only */
3384 attr.unixModeBits = newScp->unixModeBits & ~0222;
3385 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3387 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3388 /* we're told to make a read-only file writable */
3389 attr.unixModeBits = newScp->unixModeBits | 0222;
3390 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3392 lock_ReleaseMutex(&newScp->mx);
3394 /* now call setattr */
3396 code = cm_SetAttr(newScp, &attr, userp, &req);
3400 cm_ReleaseSCache(newScp);
3401 cm_ReleaseUser(userp);
3406 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3410 cm_scache_t *rootScp;
3411 cm_scache_t *newScp, *dscp;
3423 pathp = smb_GetSMBData(inp, NULL);
3424 pathp = smb_ParseASCIIBlock(pathp, NULL);
3427 return CM_ERROR_BADSMB;
3430 if (*pathp == 0) /* null path */
3433 osi_Log1(afsd_logp, "SMB receive getfile attributes path %s",
3434 osi_LogSaveString(afsd_logp, pathp));
3436 rootScp = cm_rootSCachep;
3438 userp = smb_GetUser(vcp, inp);
3440 /* we shouldn't need this for V3 requests, but we seem to */
3441 caseFold = CM_FLAG_CASEFOLD;
3443 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3446 * XXX Strange hack XXX
3448 * As of Patch 5 (16 July 97), we are having the following problem:
3449 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3450 * requests to look up "desktop.ini" in all the subdirectories.
3451 * This can cause zillions of timeouts looking up non-existent cells
3452 * and volumes, especially in the top-level directory.
3454 * We have not found any way to avoid this or work around it except
3455 * to explicitly ignore the requests for mount points that haven't
3456 * yet been evaluated and for directories that haven't yet been
3459 spacep = inp->spacep;
3460 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3461 if (strcmp(lastComp, "\\desktop.ini") == 0) {
3462 code = cm_NameI(rootScp, spacep->data,
3463 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3464 userp, tidPathp, &req, &dscp);
3466 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3467 && !dscp->mountRootFidp)
3468 code = CM_ERROR_NOSUCHFILE;
3469 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3470 cm_buf_t *bp = buf_Find(dscp, &hzero);
3474 code = CM_ERROR_NOSUCHFILE;
3476 cm_ReleaseSCache(dscp);
3478 cm_ReleaseUser(userp);
3484 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3485 tidPathp, &req, &newScp);
3488 cm_ReleaseUser(userp);
3492 /* now lock the vnode with a callback; returns with newScp locked */
3493 lock_ObtainMutex(&newScp->mx);
3494 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3495 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3497 lock_ReleaseMutex(&newScp->mx);
3498 cm_ReleaseSCache(newScp);
3499 cm_ReleaseUser(userp);
3503 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
3504 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
3508 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
3509 attrs |= 1; /* turn on read-only flag */
3510 smb_SetSMBParm(outp, 0, attrs);
3512 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
3513 smb_SetSMBParm(outp, 1, dosTime & 0xffff);
3514 smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
3515 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
3516 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
3517 smb_SetSMBParm(outp, 5, 0);
3518 smb_SetSMBParm(outp, 6, 0);
3519 smb_SetSMBParm(outp, 7, 0);
3520 smb_SetSMBParm(outp, 8, 0);
3521 smb_SetSMBParm(outp, 9, 0);
3522 smb_SetSMBDataLength(outp, 0);
3523 lock_ReleaseMutex(&newScp->mx);
3525 cm_ReleaseSCache(newScp);
3526 cm_ReleaseUser(userp);
3531 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3535 osi_Log0(afsd_logp, "SMB receive tree disconnect");
3537 /* find the tree and free it */
3538 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
3540 lock_ObtainMutex(&tidp->mx);
3541 tidp->flags |= SMB_TIDFLAG_DELETE;
3542 lock_ReleaseMutex(&tidp->mx);
3543 smb_ReleaseTID(tidp);
3549 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3567 osi_Log0(afsd_logp, "SMB receive open");
3569 pathp = smb_GetSMBData(inp, NULL);
3570 pathp = smb_ParseASCIIBlock(pathp, NULL);
3572 share = smb_GetSMBParm(inp, 0);
3573 attribute = smb_GetSMBParm(inp, 1);
3575 spacep = inp->spacep;
3576 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3577 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3578 /* special case magic file name for receiving IOCTL requests
3579 * (since IOCTL calls themselves aren't getting through).
3581 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3582 smb_SetupIoctlFid(fidp, spacep);
3583 smb_SetSMBParm(outp, 0, fidp->fid);
3584 smb_SetSMBParm(outp, 1, 0); /* attrs */
3585 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
3586 smb_SetSMBParm(outp, 3, 0);
3587 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
3588 smb_SetSMBParm(outp, 5, 0x7fff);
3589 /* pass the open mode back */
3590 smb_SetSMBParm(outp, 6, (share & 0xf));
3591 smb_SetSMBDataLength(outp, 0);
3592 smb_ReleaseFID(fidp);
3596 userp = smb_GetUser(vcp, inp);
3598 caseFold = CM_FLAG_CASEFOLD;
3600 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3601 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3602 tidPathp, &req, &scp);
3605 cm_ReleaseUser(userp);
3609 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
3611 cm_ReleaseSCache(scp);
3612 cm_ReleaseUser(userp);
3616 /* don't need callback to check file type, since file types never
3617 * change, and namei and cm_Lookup all stat the object at least once on
3618 * a successful return.
3620 if (scp->fileType != CM_SCACHETYPE_FILE) {
3621 cm_ReleaseSCache(scp);
3622 cm_ReleaseUser(userp);
3623 return CM_ERROR_ISDIR;
3626 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3629 /* save a pointer to the vnode */
3632 if ((share & 0xf) == 0)
3633 fidp->flags |= SMB_FID_OPENREAD;
3634 else if ((share & 0xf) == 1)
3635 fidp->flags |= SMB_FID_OPENWRITE;
3636 else fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
3638 lock_ObtainMutex(&scp->mx);
3639 smb_SetSMBParm(outp, 0, fidp->fid);
3640 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
3641 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
3642 smb_SetSMBParm(outp, 2, dosTime & 0xffff);
3643 smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
3644 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
3645 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
3646 /* pass the open mode back; XXXX add access checks */
3647 smb_SetSMBParm(outp, 6, (share & 0xf));
3648 smb_SetSMBDataLength(outp, 0);
3649 lock_ReleaseMutex(&scp->mx);
3652 cm_Open(scp, 0, userp);
3654 /* send and free packet */
3655 smb_ReleaseFID(fidp);
3656 cm_ReleaseUser(userp);
3657 /* don't release scp, since we've squirreled away the pointer in the fid struct */
3662 typedef struct smb_unlinkRock {
3667 char *maskp; /* pointer to the star pattern */
3672 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3675 smb_unlinkRock_t *rockp;
3683 if (rockp->vcp->flags & SMB_VCFLAG_USEV3)
3684 caseFold = CM_FLAG_CASEFOLD;
3686 caseFold = CM_FLAG_CASEFOLD | CM_FLAG_8DOT3;
3688 matchName = dep->name;
3689 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3692 && !cm_Is8Dot3(dep->name)) {
3693 cm_Gen8Dot3Name(dep, shortName, NULL);
3694 matchName = shortName;
3695 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3698 osi_Log1(smb_logp, "Unlinking %s",
3699 osi_LogSaveString(smb_logp, matchName));
3700 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
3701 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3702 smb_NotifyChange(FILE_ACTION_REMOVED,
3703 FILE_NOTIFY_CHANGE_FILE_NAME,
3704 dscp, dep->name, NULL, TRUE);
3713 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3722 smb_unlinkRock_t rock;
3731 attribute = smb_GetSMBParm(inp, 0);
3733 tp = smb_GetSMBData(inp, NULL);
3734 pathp = smb_ParseASCIIBlock(tp, &tp);
3736 osi_Log1(smb_logp, "SMB receive unlink %s",
3737 osi_LogSaveString(smb_logp, pathp));
3739 spacep = inp->spacep;
3740 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3742 userp = smb_GetUser(vcp, inp);
3744 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3746 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3747 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
3751 cm_ReleaseUser(userp);
3755 /* otherwise, scp points to the parent directory.
3757 if (!lastNamep) lastNamep = pathp;
3761 rock.maskp = smb_FindMask(pathp);
3762 rock.hasTilde = ((strchr(rock.maskp, '~') != NULL) ? 1 : 0);
3765 thyper.HighPart = 0;
3770 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
3772 cm_ReleaseUser(userp);
3774 cm_ReleaseSCache(dscp);
3776 if (code == 0 && !rock.any)
3777 code = CM_ERROR_NOSUCHFILE;
3781 typedef struct smb_renameRock {
3782 cm_scache_t *odscp; /* old dir */
3783 cm_scache_t *ndscp; /* new dir */
3784 cm_user_t *userp; /* user */
3785 cm_req_t *reqp; /* request struct */
3786 smb_vc_t *vcp; /* virtual circuit */
3787 char *maskp; /* pointer to star pattern of old file name */
3788 int hasTilde; /* star pattern might be shortname? */
3789 char *newNamep; /* ptr to the new file's name */
3792 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3795 smb_renameRock_t *rockp;
3802 if (rockp->vcp->flags & SMB_VCFLAG_USEV3)
3803 caseFold = CM_FLAG_CASEFOLD;
3805 caseFold = CM_FLAG_CASEFOLD | CM_FLAG_8DOT3;
3807 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
3810 && !cm_Is8Dot3(dep->name)) {
3811 cm_Gen8Dot3Name(dep, shortName, NULL);
3812 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
3815 code = cm_Rename(rockp->odscp, dep->name,
3816 rockp->ndscp, rockp->newNamep, rockp->userp,
3818 /* if the call worked, stop doing the search now, since we
3819 * really only want to rename one file.
3821 if (code == 0) code = CM_ERROR_STOPNOW;
3828 long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3835 smb_renameRock_t rock;
3836 cm_scache_t *oldDscp;
3837 cm_scache_t *newDscp;
3838 cm_scache_t *tmpscp;
3850 tp = smb_GetSMBData(inp, NULL);
3851 oldPathp = smb_ParseASCIIBlock(tp, &tp);
3852 newPathp = smb_ParseASCIIBlock(tp, &tp);
3854 osi_Log2(afsd_logp, "smb rename %s to %s",
3855 osi_LogSaveString(afsd_logp, oldPathp),
3856 osi_LogSaveString(afsd_logp, newPathp));
3858 spacep = inp->spacep;
3859 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
3861 userp = smb_GetUser(vcp, inp);
3864 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
3865 * what actually exists is foo/baz. I don't know why the code used to be
3866 * the way it was. 1/29/96
3868 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
3870 * Changed to use CM_FLAG_FOLLOW. 7/24/96
3872 * caseFold = CM_FLAG_CASEFOLD;
3874 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3876 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3877 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
3878 userp, tidPathp, &req, &oldDscp);
3881 cm_ReleaseUser(userp);
3885 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
3886 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
3887 userp, tidPathp, &req, &newDscp);
3890 cm_ReleaseSCache(oldDscp);
3891 cm_ReleaseUser(userp);
3895 /* otherwise, oldDscp and newDscp point to the corresponding directories.
3896 * next, get the component names, and lower case them.
3899 /* handle the old name first */
3900 if (!oldLastNamep) oldLastNamep = oldPathp;
3901 else oldLastNamep++;
3903 /* and handle the new name, too */
3904 if (!newLastNamep) newLastNamep = newPathp;
3905 else newLastNamep++;
3907 /* do the vnode call */
3908 rock.odscp = oldDscp;
3909 rock.ndscp = newDscp;
3913 rock.maskp = oldLastNamep;
3914 rock.hasTilde = ((strchr(oldLastNamep, '~') != NULL) ? 1 : 0);
3915 rock.newNamep = newLastNamep;
3917 /* now search the dir for the pattern, and do the appropriate rename when
3920 thyper.LowPart = 0; /* search dir from here */
3921 thyper.HighPart = 0;
3922 /* search for file to already exhist, if so return error*/
3924 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
3925 if((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
3926 cm_ReleaseSCache(tmpscp);
3927 return CM_ERROR_EXISTS; /* file exist, do not rename, also
3930 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
3932 if (code == CM_ERROR_STOPNOW)
3935 code = CM_ERROR_NOSUCHFILE;
3937 /* Handle Change Notification */
3939 * Being lazy, not distinguishing between files and dirs in this
3940 * filter, since we'd have to do a lookup.
3942 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
3943 if (oldDscp == newDscp) {
3944 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
3945 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
3946 filter, oldDscp, oldLastNamep,
3947 newLastNamep, TRUE);
3949 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
3950 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
3951 filter, oldDscp, oldLastNamep,
3953 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
3954 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
3955 filter, newDscp, newLastNamep,
3959 cm_ReleaseUser(userp);
3961 cm_ReleaseSCache(oldDscp);
3962 cm_ReleaseSCache(newDscp);
3967 typedef struct smb_rmdirRock {
3971 char *maskp; /* pointer to the star pattern */
3976 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3979 smb_rmdirRock_t *rockp;
3986 matchName = dep->name;
3987 match = (cm_stricmp(matchName, rockp->maskp) == 0);
3990 && !cm_Is8Dot3(dep->name)) {
3991 cm_Gen8Dot3Name(dep, shortName, NULL);
3992 matchName = shortName;
3993 match = (cm_stricmp(matchName, rockp->maskp) == 0);
3996 osi_Log1(smb_logp, "Removing directory %s",
3997 osi_LogSaveString(smb_logp, matchName));
3998 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
3999 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4000 smb_NotifyChange(FILE_ACTION_REMOVED,
4001 FILE_NOTIFY_CHANGE_DIR_NAME,
4002 dscp, dep->name, NULL, TRUE);
4011 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4019 smb_rmdirRock_t rock;
4028 tp = smb_GetSMBData(inp, NULL);
4029 pathp = smb_ParseASCIIBlock(tp, &tp);
4031 spacep = inp->spacep;
4032 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4034 userp = smb_GetUser(vcp, inp);
4036 caseFold = CM_FLAG_CASEFOLD;
4038 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4039 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4040 userp, tidPathp, &req, &dscp);
4043 cm_ReleaseUser(userp);
4047 /* otherwise, scp points to the parent directory. */
4048 if (!lastNamep) lastNamep = pathp;
4052 rock.maskp = lastNamep;
4053 rock.hasTilde = ((strchr(rock.maskp, '~') != NULL) ? 1 : 0);
4056 thyper.HighPart = 0;
4060 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4062 cm_ReleaseUser(userp);
4064 cm_ReleaseSCache(dscp);
4066 if (code == 0 && !rock.any)
4067 code = CM_ERROR_NOSUCHFILE;
4071 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4081 fid = smb_GetSMBParm(inp, 0);
4083 osi_Log1(afsd_logp, "SMB flush fid %d", fid);
4085 fid = smb_ChainFID(fid, inp);
4086 fidp = smb_FindFID(vcp, fid, 0);
4087 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4088 return CM_ERROR_BADFD;
4091 userp = smb_GetUser(vcp, inp);
4093 lock_ObtainMutex(&fidp->mx);
4094 if (fidp->flags & SMB_FID_OPENWRITE)
4095 code = cm_FSync(fidp->scp, userp, &req);
4097 lock_ReleaseMutex(&fidp->mx);
4099 smb_ReleaseFID(fidp);
4101 cm_ReleaseUser(userp);
4106 struct smb_FullNameRock {
4112 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4116 struct smb_FullNameRock *vrockp;
4120 if (!cm_Is8Dot3(dep->name)) {
4121 cm_Gen8Dot3Name(dep, shortName, NULL);
4123 if (strcmp(shortName, vrockp->name) == 0) {
4124 vrockp->fullName = strdup(dep->name);
4125 return CM_ERROR_STOPNOW;
4128 if (stricmp(dep->name, vrockp->name) == 0
4129 && ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode
4130 && ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4131 vrockp->fullName = strdup(dep->name);
4132 return CM_ERROR_STOPNOW;
4137 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4138 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4140 struct smb_FullNameRock rock;
4146 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL,
4148 if (code == CM_ERROR_STOPNOW)
4149 *newPathp = rock.fullName;
4151 *newPathp = strdup(pathp);
4154 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4165 fid = smb_GetSMBParm(inp, 0);
4166 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4168 osi_Log1(afsd_logp, "SMB close fid %d", fid);
4170 fid = smb_ChainFID(fid, inp);
4171 fidp = smb_FindFID(vcp, fid, 0);
4173 return CM_ERROR_BADFD;
4176 userp = smb_GetUser(vcp, inp);
4178 lock_ObtainMutex(&fidp->mx);
4180 /* Don't jump the gun on an async raw write */
4181 while (fidp->raw_writers) {
4182 lock_ReleaseMutex(&fidp->mx);
4183 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4184 lock_ObtainMutex(&fidp->mx);
4187 fidp->flags |= SMB_FID_DELETE;
4189 /* watch for ioctl closes, and read-only opens */
4190 if (fidp->scp != NULL
4191 && (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4192 == SMB_FID_OPENWRITE) {
4193 if (dosTime != 0 && dosTime != -1) {
4194 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4195 /* This fixes defect 10958 */
4196 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
4197 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime,
4200 code = cm_FSync(fidp->scp, userp, &req);
4204 if (fidp->flags & SMB_FID_DELONCLOSE) {
4205 cm_scache_t *dscp = fidp->NTopen_dscp;
4206 char *pathp = fidp->NTopen_pathp;
4209 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
4210 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
4211 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
4212 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4213 smb_NotifyChange(FILE_ACTION_REMOVED,
4214 FILE_NOTIFY_CHANGE_DIR_NAME,
4215 dscp, fullPathp, NULL, TRUE);
4218 code = cm_Unlink(dscp, fullPathp, userp, &req);
4219 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4220 smb_NotifyChange(FILE_ACTION_REMOVED,
4221 FILE_NOTIFY_CHANGE_FILE_NAME,
4222 dscp, fullPathp, NULL, TRUE);
4226 lock_ReleaseMutex(&fidp->mx);
4228 if (fidp->flags & SMB_FID_NTOPEN) {
4229 cm_ReleaseSCache(fidp->NTopen_dscp);
4230 free(fidp->NTopen_pathp);
4232 if (fidp->NTopen_wholepathp)
4233 free(fidp->NTopen_wholepathp);
4234 smb_ReleaseFID(fidp);
4236 cm_ReleaseUser(userp);
4242 * smb_ReadData -- common code for Read, Read And X, and Raw Read
4245 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4246 cm_user_t *userp, long *readp)
4248 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4249 cm_user_t *userp, long *readp, int dosflag)
4256 osi_hyper_t fileLength;
4258 osi_hyper_t lastByte;
4259 osi_hyper_t bufferOffset;
4260 long bufIndex, nbytes;
4270 lock_ObtainMutex(&fidp->mx);
4272 lock_ObtainMutex(&scp->mx);
4274 if (offset.HighPart == 0) {
4275 chunk = offset.LowPart >> cm_logChunkSize;
4276 if (chunk != fidp->curr_chunk) {
4277 fidp->prev_chunk = fidp->curr_chunk;
4278 fidp->curr_chunk = chunk;
4280 if (fidp->curr_chunk == fidp->prev_chunk + 1)
4284 /* start by looking up the file's end */
4285 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4286 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4287 if (code) goto done;
4289 /* now we have the entry locked, look up the length */
4290 fileLength = scp->length;
4292 /* adjust count down so that it won't go past EOF */
4293 thyper.LowPart = count;
4294 thyper.HighPart = 0;
4295 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
4297 if (LargeIntegerGreaterThan(thyper, fileLength)) {
4298 /* we'd read past EOF, so just stop at fileLength bytes.
4299 * Start by computing how many bytes remain in the file.
4301 thyper = LargeIntegerSubtract(fileLength, offset);
4303 /* if we are past EOF, read 0 bytes */
4304 if (LargeIntegerLessThanZero(thyper))
4307 count = thyper.LowPart;
4312 /* now, copy the data one buffer at a time,
4313 * until we've filled the request packet
4316 /* if we've copied all the data requested, we're done */
4317 if (count <= 0) break;
4319 /* otherwise, load up a buffer of data */
4320 thyper.HighPart = offset.HighPart;
4321 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4322 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4325 buf_Release(bufferp);
4328 lock_ReleaseMutex(&scp->mx);
4330 lock_ObtainRead(&scp->bufCreateLock);
4331 code = buf_Get(scp, &thyper, &bufferp);
4332 lock_ReleaseRead(&scp->bufCreateLock);
4334 lock_ObtainMutex(&scp->mx);
4335 if (code) goto done;
4336 bufferOffset = thyper;
4338 /* now get the data in the cache */
4340 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4341 CM_SCACHESYNC_NEEDCALLBACK
4342 | CM_SCACHESYNC_READ);
4343 if (code) goto done;
4345 if (cm_HaveBuffer(scp, bufferp, 0)) break;
4347 /* otherwise, load the buffer and try again */
4348 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4352 buf_Release(bufferp);
4356 } /* if (wrong buffer) ... */
4358 /* now we have the right buffer loaded. Copy out the
4359 * data from here to the user's buffer.
4361 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4363 /* and figure out how many bytes we want from this buffer */
4364 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
4365 if (nbytes > count) nbytes = count; /* don't go past EOF */
4367 /* now copy the data */
4370 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
4373 memcpy(op, bufferp->datap + bufIndex, nbytes);
4375 /* adjust counters, pointers, etc. */
4378 thyper.LowPart = nbytes;
4379 thyper.HighPart = 0;
4380 offset = LargeIntegerAdd(thyper, offset);
4384 lock_ReleaseMutex(&scp->mx);
4385 lock_ReleaseMutex(&fidp->mx);
4386 if (bufferp) buf_Release(bufferp);
4388 if (code == 0 && sequential)
4389 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
4395 * smb_WriteData -- common code for Write and Raw Write
4398 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4399 cm_user_t *userp, long *writtenp)
4401 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4402 cm_user_t *userp, long *writtenp, int dosflag)
4409 osi_hyper_t fileLength; /* file's length at start of write */
4410 osi_hyper_t minLength; /* don't read past this */
4411 long nbytes; /* # of bytes to transfer this iteration */
4413 osi_hyper_t thyper; /* hyper tmp variable */
4414 osi_hyper_t bufferOffset;
4415 long bufIndex; /* index in buffer where our data is */
4417 osi_hyper_t writeBackOffset; /* offset of region to write back when
4428 lock_ObtainMutex(&fidp->mx);
4430 lock_ObtainMutex(&scp->mx);
4432 /* start by looking up the file's end */
4433 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4434 CM_SCACHESYNC_NEEDCALLBACK
4435 | CM_SCACHESYNC_SETSTATUS
4436 | CM_SCACHESYNC_GETSTATUS);
4437 if (code) goto done;
4439 /* make sure we have a writable FD */
4440 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
4441 code = CM_ERROR_BADFDOP;
4445 /* now we have the entry locked, look up the length */
4446 fileLength = scp->length;
4447 minLength = fileLength;
4448 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
4449 minLength = scp->serverLength;
4451 /* adjust file length if we extend past EOF */
4452 thyper.LowPart = count;
4453 thyper.HighPart = 0;
4454 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
4455 if (LargeIntegerGreaterThan(thyper, fileLength)) {
4456 /* we'd write past EOF, so extend the file */
4457 scp->mask |= CM_SCACHEMASK_LENGTH;
4458 scp->length = thyper;
4460 (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
4462 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
4464 /* now, if the new position (thyper) and the old (offset) are in
4465 * different storeback windows, remember to store back the previous
4466 * storeback window when we're done with the write.
4468 if ((thyper.LowPart & (-cm_chunkSize)) !=
4469 (offset.LowPart & (-cm_chunkSize))) {
4470 /* they're different */
4472 writeBackOffset.HighPart = offset.HighPart;
4473 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
4478 /* now, copy the data one buffer at a time, until we've filled the
4481 /* if we've copied all the data requested, we're done */
4482 if (count <= 0) break;
4484 /* handle over quota or out of space */
4485 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA
4486 | CM_SCACHEFLAG_OUTOFSPACE)) {
4487 *writtenp = written;
4491 /* otherwise, load up a buffer of data */
4492 thyper.HighPart = offset.HighPart;
4493 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4494 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4497 lock_ReleaseMutex(&bufferp->mx);
4498 buf_Release(bufferp);
4501 lock_ReleaseMutex(&scp->mx);
4503 lock_ObtainRead(&scp->bufCreateLock);
4504 code = buf_Get(scp, &thyper, &bufferp);
4505 lock_ReleaseRead(&scp->bufCreateLock);
4507 lock_ObtainMutex(&bufferp->mx);
4508 lock_ObtainMutex(&scp->mx);
4509 if (code) goto done;
4511 bufferOffset = thyper;
4513 /* now get the data in the cache */
4515 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4516 CM_SCACHESYNC_NEEDCALLBACK
4517 | CM_SCACHESYNC_WRITE
4518 | CM_SCACHESYNC_BUFLOCKED);
4519 if (code) goto done;
4521 /* If we're overwriting the entire buffer, or
4522 * if we're writing at or past EOF, mark the
4523 * buffer as current so we don't call
4524 * cm_GetBuffer. This skips the fetch from the
4525 * server in those cases where we're going to
4526 * obliterate all the data in the buffer anyway,
4527 * or in those cases where there is no useful
4528 * data at the server to start with.
4530 * Use minLength instead of scp->length, since
4531 * the latter has already been updated by this
4534 if (LargeIntegerGreaterThanOrEqualTo(
4535 bufferp->offset, minLength)
4536 || LargeIntegerEqualTo(offset, bufferp->offset)
4537 && (count >= buf_bufferSize
4538 || LargeIntegerGreaterThanOrEqualTo(
4539 LargeIntegerAdd(offset,
4540 ConvertLongToLargeInteger(count)),
4542 if (count < buf_bufferSize
4543 && bufferp->dataVersion == -1)
4544 memset(bufferp->datap, 0,
4546 bufferp->dataVersion = scp->dataVersion;
4549 if (cm_HaveBuffer(scp, bufferp, 1)) break;
4551 /* otherwise, load the buffer and try again */
4552 lock_ReleaseMutex(&bufferp->mx);
4553 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4555 lock_ReleaseMutex(&scp->mx);
4556 lock_ObtainMutex(&bufferp->mx);
4557 lock_ObtainMutex(&scp->mx);
4561 lock_ReleaseMutex(&bufferp->mx);
4562 buf_Release(bufferp);
4566 } /* if (wrong buffer) ... */
4568 /* now we have the right buffer loaded. Copy out the
4569 * data from here to the user's buffer.
4571 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4573 /* and figure out how many bytes we want from this buffer */
4574 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
4575 if (nbytes > count) nbytes = count; /* don't go past end of request */
4577 /* now copy the data */
4580 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
4583 memcpy(bufferp->datap + bufIndex, op, nbytes);
4584 buf_SetDirty(bufferp);
4586 /* and record the last writer */
4587 if (bufferp->userp != userp) {
4588 if (bufferp->userp) cm_ReleaseUser(bufferp->userp);
4589 bufferp->userp = userp;
4593 /* adjust counters, pointers, etc. */
4597 thyper.LowPart = nbytes;
4598 thyper.HighPart = 0;
4599 offset = LargeIntegerAdd(thyper, offset);
4603 lock_ReleaseMutex(&scp->mx);
4604 lock_ReleaseMutex(&fidp->mx);
4606 lock_ReleaseMutex(&bufferp->mx);
4607 buf_Release(bufferp);
4610 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
4611 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
4612 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
4613 fidp->NTopen_dscp, fidp->NTopen_pathp,
4617 if (code == 0 && doWriteBack) {
4618 lock_ObtainMutex(&scp->mx);
4619 cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
4620 lock_ReleaseMutex(&scp->mx);
4621 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
4622 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
4628 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4631 long count, written = 0;
4636 cm_attr_t truncAttr; /* attribute struct used for truncating file */
4638 int inDataBlockCount;
4640 fd = smb_GetSMBParm(inp, 0);
4641 count = smb_GetSMBParm(inp, 1);
4642 offset.HighPart = 0; /* too bad */
4643 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
4645 op = smb_GetSMBData(inp, NULL);
4646 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
4648 osi_Log3(afsd_logp, "smb_ReceiveCoreWrite fd %d, off 0x%x, size 0x%x",
4649 fd, offset.LowPart, count);
4651 fd = smb_ChainFID(fd, inp);
4652 fidp = smb_FindFID(vcp, fd, 0);
4654 return CM_ERROR_BADFD;
4657 if (fidp->flags & SMB_FID_IOCTL)
4658 return smb_IoctlWrite(fidp, vcp, inp, outp);
4660 userp = smb_GetUser(vcp, inp);
4662 /* special case: 0 bytes transferred means truncate to this position */
4668 truncAttr.mask = CM_ATTRMASK_LENGTH;
4669 truncAttr.length.LowPart = offset.LowPart;
4670 truncAttr.length.HighPart = 0;
4671 lock_ObtainMutex(&fidp->mx);
4672 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
4673 lock_ReleaseMutex(&fidp->mx);
4674 smb_SetSMBParm(outp, 0, /* count */ 0);
4675 smb_SetSMBDataLength(outp, 0);
4676 fidp->flags |= SMB_FID_LENGTHSETDONE;
4681 * Work around bug in NT client
4683 * When copying a file, the NT client should first copy the data,
4684 * then copy the last write time. But sometimes the NT client does
4685 * these in the wrong order, so the data copies would inadvertently
4686 * cause the last write time to be overwritten. We try to detect this,
4687 * and don't set client mod time if we think that would go against the
4690 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
4691 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4692 fidp->scp->clientModTime = time(NULL);
4696 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
4698 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
4700 if (code == 0 && written < count)
4701 code = CM_ERROR_PARTIALWRITE;
4703 /* set the packet data length to 3 bytes for the data block header,
4704 * plus the size of the data.
4706 smb_SetSMBParm(outp, 0, written);
4707 smb_SetSMBDataLength(outp, 0);
4710 smb_ReleaseFID(fidp);
4711 cm_ReleaseUser(userp);
4716 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
4717 NCB *ncbp, raw_write_cont_t *rwcp)
4730 fd = smb_GetSMBParm(inp, 0);
4731 fidp = smb_FindFID(vcp, fd, 0);
4733 osi_Log2(afsd_logp, "Completing Raw Write offset %x count %x",
4734 rwcp->offset.LowPart, rwcp->count);
4736 userp = smb_GetUser(vcp, inp);
4740 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
4743 rawBuf = (dos_ptr) rwcp->buf;
4744 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
4745 (unsigned char *) rawBuf, userp,
4749 if (rwcp->writeMode & 0x1) { /* synchronous */
4752 smb_FormatResponsePacket(vcp, inp, outp);
4753 op = (smb_t *) outp;
4754 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
4755 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
4756 smb_SetSMBDataLength(outp, 0);
4757 smb_SendPacket(vcp, outp);
4758 smb_FreePacket(outp);
4760 else { /* asynchronous */
4761 lock_ObtainMutex(&fidp->mx);
4762 fidp->raw_writers--;
4763 if (fidp->raw_writers == 0)
4764 thrd_SetEvent(fidp->raw_write_event);
4765 lock_ReleaseMutex(&fidp->mx);
4768 /* Give back raw buffer */
4769 lock_ObtainMutex(&smb_RawBufLock);
4771 *((char **)rawBuf) = smb_RawBufs;
4773 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
4775 smb_RawBufs = rawBuf;
4776 lock_ReleaseMutex(&smb_RawBufLock);
4778 smb_ReleaseFID(fidp);
4779 cm_ReleaseUser(userp);
4782 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4787 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
4790 long count, written = 0;
4797 unsigned short writeMode;
4804 fd = smb_GetSMBParm(inp, 0);
4805 totalCount = smb_GetSMBParm(inp, 1);
4806 count = smb_GetSMBParm(inp, 10);
4807 offset.HighPart = 0; /* too bad */
4808 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
4809 writeMode = smb_GetSMBParm(inp, 7);
4811 op = (char *) inp->data;
4812 op += smb_GetSMBParm(inp, 11);
4815 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
4816 fd, offset.LowPart, count, writeMode);
4818 fd = smb_ChainFID(fd, inp);
4819 fidp = smb_FindFID(vcp, fd, 0);
4821 return CM_ERROR_BADFD;
4824 userp = smb_GetUser(vcp, inp);
4827 * Work around bug in NT client
4829 * When copying a file, the NT client should first copy the data,
4830 * then copy the last write time. But sometimes the NT client does
4831 * these in the wrong order, so the data copies would inadvertently
4832 * cause the last write time to be overwritten. We try to detect this,
4833 * and don't set client mod time if we think that would go against the
4836 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
4837 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4838 fidp->scp->clientModTime = time(NULL);
4842 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
4844 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
4846 if (code == 0 && written < count)
4847 code = CM_ERROR_PARTIALWRITE;
4849 /* Get a raw buffer */
4852 lock_ObtainMutex(&smb_RawBufLock);
4854 /* Get a raw buf, from head of list */
4855 rawBuf = smb_RawBufs;
4857 smb_RawBufs = *(char **)smb_RawBufs;
4859 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
4863 code = CM_ERROR_USESTD;
4864 lock_ReleaseMutex(&smb_RawBufLock);
4867 /* Don't allow a premature Close */
4868 if (code == 0 && (writeMode & 1) == 0) {
4869 lock_ObtainMutex(&fidp->mx);
4870 fidp->raw_writers++;
4871 thrd_ResetEvent(fidp->raw_write_event);
4872 lock_ReleaseMutex(&fidp->mx);
4875 smb_ReleaseFID(fidp);
4876 cm_ReleaseUser(userp);
4879 smb_SetSMBParm(outp, 0, written);
4880 smb_SetSMBDataLength(outp, 0);
4881 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
4888 rwcp->offset.HighPart = 0;
4889 rwcp->offset.LowPart = offset.LowPart + count;
4890 rwcp->count = totalCount - count;
4891 rwcp->writeMode = writeMode;
4892 rwcp->alreadyWritten = written;
4894 /* set the packet data length to 3 bytes for the data block header,
4895 * plus the size of the data.
4897 smb_SetSMBParm(outp, 0, 0xffff);
4898 smb_SetSMBDataLength(outp, 0);
4903 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4906 long count, finalCount;
4913 fd = smb_GetSMBParm(inp, 0);
4914 count = smb_GetSMBParm(inp, 1);
4915 offset.HighPart = 0; /* too bad */
4916 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
4918 osi_Log3(afsd_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
4919 fd, offset.LowPart, count);
4921 fd = smb_ChainFID(fd, inp);
4922 fidp = smb_FindFID(vcp, fd, 0);
4924 return CM_ERROR_BADFD;
4927 if (fidp->flags & SMB_FID_IOCTL) {
4928 return smb_IoctlRead(fidp, vcp, inp, outp);
4931 userp = smb_GetUser(vcp, inp);
4933 /* remember this for final results */
4934 smb_SetSMBParm(outp, 0, count);
4935 smb_SetSMBParm(outp, 1, 0);
4936 smb_SetSMBParm(outp, 2, 0);
4937 smb_SetSMBParm(outp, 3, 0);
4938 smb_SetSMBParm(outp, 4, 0);
4940 /* set the packet data length to 3 bytes for the data block header,
4941 * plus the size of the data.
4943 smb_SetSMBDataLength(outp, count+3);
4945 /* get op ptr after putting in the parms, since otherwise we don't
4946 * know where the data really is.
4948 op = smb_GetSMBData(outp, NULL);
4950 /* now emit the data block header: 1 byte of type and 2 bytes of length */
4951 *op++ = 1; /* data block marker */
4952 *op++ = (unsigned char) (count & 0xff);
4953 *op++ = (unsigned char) ((count >> 8) & 0xff);
4956 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
4958 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
4961 /* fix some things up */
4962 smb_SetSMBParm(outp, 0, finalCount);
4963 smb_SetSMBDataLength(outp, finalCount+3);
4965 smb_ReleaseFID(fidp);
4967 cm_ReleaseUser(userp);
4971 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4978 cm_scache_t *dscp; /* dir we're dealing with */
4979 cm_scache_t *scp; /* file we're creating */
4981 int initialModeBits;
4991 /* compute initial mode bits based on read-only flag in attributes */
4992 initialModeBits = 0777;
4994 tp = smb_GetSMBData(inp, NULL);
4995 pathp = smb_ParseASCIIBlock(tp, &tp);
4997 if (strcmp(pathp, "\\") == 0)
4998 return CM_ERROR_EXISTS;
5000 spacep = inp->spacep;
5001 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5003 userp = smb_GetUser(vcp, inp);
5005 caseFold = CM_FLAG_CASEFOLD;
5007 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5009 code = cm_NameI(cm_rootSCachep, spacep->data,
5010 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5011 userp, tidPathp, &req, &dscp);
5014 cm_ReleaseUser(userp);
5018 /* otherwise, scp points to the parent directory. Do a lookup, and
5019 * fail if we find it. Otherwise, we do the create.
5021 if (!lastNamep) lastNamep = pathp;
5023 code = cm_Lookup(dscp, lastNamep, caseFold, userp, &req, &scp);
5024 if (scp) cm_ReleaseSCache(scp);
5025 if (code != CM_ERROR_NOSUCHFILE) {
5026 if (code == 0) code = CM_ERROR_EXISTS;
5027 cm_ReleaseSCache(dscp);
5028 cm_ReleaseUser(userp);
5032 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5033 setAttr.clientModTime = time(NULL);
5034 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5035 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5036 smb_NotifyChange(FILE_ACTION_ADDED,
5037 FILE_NOTIFY_CHANGE_DIR_NAME,
5038 dscp, lastNamep, NULL, TRUE);
5040 /* we don't need this any longer */
5041 cm_ReleaseSCache(dscp);
5044 /* something went wrong creating or truncating the file */
5045 cm_ReleaseUser(userp);
5049 /* otherwise we succeeded */
5050 smb_SetSMBDataLength(outp, 0);
5051 cm_ReleaseUser(userp);
5056 BOOL smb_IsLegalFilename(char *filename)
5059 * Find the longest substring of filename that does not contain
5060 * any of the chars in illegalChars. If that substring is less
5061 * than the length of the whole string, then one or more of the
5062 * illegal chars is in filename.
5064 if (strcspn(filename, illegalChars) < strlen(filename))
5070 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5078 cm_scache_t *dscp; /* dir we're dealing with */
5079 cm_scache_t *scp; /* file we're creating */
5081 int initialModeBits;
5093 excl = (inp->inCom == 0x03)? 0 : 1;
5095 attributes = smb_GetSMBParm(inp, 0);
5096 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5098 /* compute initial mode bits based on read-only flag in attributes */
5099 initialModeBits = 0666;
5100 if (attributes & 1) initialModeBits &= ~0222;
5102 tp = smb_GetSMBData(inp, NULL);
5103 pathp = smb_ParseASCIIBlock(tp, &tp);
5105 spacep = inp->spacep;
5106 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5108 userp = smb_GetUser(vcp, inp);
5110 caseFold = CM_FLAG_CASEFOLD;
5112 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5113 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5114 userp, tidPathp, &req, &dscp);
5117 cm_ReleaseUser(userp);
5121 /* otherwise, scp points to the parent directory. Do a lookup, and
5122 * truncate the file if we find it, otherwise we create the file.
5124 if (!lastNamep) lastNamep = pathp;
5127 if (!smb_IsLegalFilename(lastNamep))
5128 return CM_ERROR_BADNTFILENAME;
5130 code = cm_Lookup(dscp, lastNamep, caseFold, userp, &req, &scp);
5131 if (code && code != CM_ERROR_NOSUCHFILE) {
5132 cm_ReleaseSCache(dscp);
5133 cm_ReleaseUser(userp);
5137 /* if we get here, if code is 0, the file exists and is represented by
5138 * scp. Otherwise, we have to create it.
5142 /* oops, file shouldn't be there */
5143 cm_ReleaseSCache(dscp);
5144 cm_ReleaseSCache(scp);
5145 cm_ReleaseUser(userp);
5146 return CM_ERROR_EXISTS;
5149 setAttr.mask = CM_ATTRMASK_LENGTH;
5150 setAttr.length.LowPart = 0;
5151 setAttr.length.HighPart = 0;
5152 code = cm_SetAttr(scp, &setAttr, userp, &req);
5155 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5156 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5157 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5159 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5160 smb_NotifyChange(FILE_ACTION_ADDED,
5161 FILE_NOTIFY_CHANGE_FILE_NAME,
5162 dscp, lastNamep, NULL, TRUE);
5163 if (!excl && code == CM_ERROR_EXISTS) {
5164 /* not an exclusive create, and someone else tried
5165 * creating it already, then we open it anyway. We
5166 * don't bother retrying after this, since if this next
5167 * fails, that means that the file was deleted after
5168 * we started this call.
5170 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
5173 setAttr.mask = CM_ATTRMASK_LENGTH;
5174 setAttr.length.LowPart = 0;
5175 setAttr.length.HighPart = 0;
5176 code = cm_SetAttr(scp, &setAttr, userp, &req);
5181 /* we don't need this any longer */
5182 cm_ReleaseSCache(dscp);
5185 /* something went wrong creating or truncating the file */
5186 if (scp) cm_ReleaseSCache(scp);
5187 cm_ReleaseUser(userp);
5191 /* make sure we only open files */
5192 if (scp->fileType != CM_SCACHETYPE_FILE) {
5193 cm_ReleaseSCache(scp);
5194 cm_ReleaseUser(userp);
5195 return CM_ERROR_ISDIR;
5198 /* now all we have to do is open the file itself */
5199 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5202 /* save a pointer to the vnode */
5205 /* always create it open for read/write */
5206 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
5208 smb_ReleaseFID(fidp);
5210 smb_SetSMBParm(outp, 0, fidp->fid);
5211 smb_SetSMBDataLength(outp, 0);
5213 cm_Open(scp, 0, userp);
5215 cm_ReleaseUser(userp);
5216 /* leave scp held since we put it in fidp->scp */
5220 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5233 fd = smb_GetSMBParm(inp, 0);
5234 whence = smb_GetSMBParm(inp, 1);
5235 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5237 /* try to find the file descriptor */
5238 fd = smb_ChainFID(fd, inp);
5239 fidp = smb_FindFID(vcp, fd, 0);
5240 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5241 return CM_ERROR_BADFD;
5244 userp = smb_GetUser(vcp, inp);
5246 lock_ObtainMutex(&fidp->mx);
5248 lock_ObtainMutex(&scp->mx);
5249 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5250 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5253 /* offset from current offset */
5254 offset += fidp->offset;
5256 else if (whence == 2) {
5257 /* offset from current EOF */
5258 offset += scp->length.LowPart;
5260 fidp->offset = offset;
5261 smb_SetSMBParm(outp, 0, offset & 0xffff);
5262 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
5263 smb_SetSMBDataLength(outp, 0);
5265 lock_ReleaseMutex(&scp->mx);
5266 lock_ReleaseMutex(&fidp->mx);
5267 smb_ReleaseFID(fidp);
5268 cm_ReleaseUser(userp);
5272 /* dispatch all of the requests received in a packet. Due to chaining, this may
5273 * be more than one request.
5275 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5276 NCB *ncbp, raw_write_cont_t *rwcp)
5278 static showErrors = 0;
5282 unsigned char *outWctp;
5283 int nparms; /* # of bytes of parameters */
5285 int nbytes; /* bytes of data, excluding count */
5288 unsigned short errCode;
5289 unsigned long NTStatus;
5291 unsigned char errClass;
5292 unsigned int oldGen;
5293 DWORD oldTime, newTime;
5295 /* get easy pointer to the data */
5296 smbp = (smb_t *) inp->data;
5298 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
5299 /* setup the basic parms for the initial request in the packet */
5300 inp->inCom = smbp->com;
5301 inp->wctp = &smbp->wct;
5303 inp->ncb_length = ncbp->ncb_length;
5308 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
5309 /* log it and discard it */
5314 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5315 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
5317 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
5318 1, ncbp->ncb_length, ptbuf, inp);
5319 DeregisterEventSource(h);
5321 osi_Log1(smb_logp, "SMB message too short, len %d",
5328 /* We are an ongoing op */
5329 thrd_Increment(&ongoingOps);
5331 /* set up response packet for receiving output */
5332 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
5333 smb_FormatResponsePacket(vcp, inp, outp);
5334 outWctp = outp->wctp;
5336 /* Remember session generation number and time */
5337 oldGen = sessionGen;
5338 oldTime = GetCurrentTime();
5340 while(inp->inCom != 0xff) {
5341 dp = &smb_dispatchTable[inp->inCom];
5343 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
5344 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
5345 code = outp->resumeCode;
5349 /* process each request in the packet; inCom, wctp and inCount
5350 * are already set up.
5352 osi_Log2(afsd_logp, "SMB received op 0x%x lsn %d", inp->inCom,
5355 /* now do the dispatch */
5356 /* start by formatting the response record a little, as a default */
5357 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
5359 outWctp[1] = 0xff; /* no operation */
5360 outWctp[2] = 0; /* padding */
5365 /* not a chained request, this is a more reasonable default */
5366 outWctp[0] = 0; /* wct of zero */
5367 outWctp[1] = 0; /* and bcc (word) of zero */
5371 /* once set, stays set. Doesn't matter, since we never chain
5372 * "no response" calls.
5374 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
5378 /* we have a recognized operation */
5380 if (inp->inCom == 0x1d)
5382 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
5385 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
5386 osi_Log4(afsd_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
5387 code = (*(dp->procp)) (vcp, inp, outp);
5388 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5389 osi_Log1(afsd_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5392 if (oldGen != sessionGen) {
5397 newTime = GetCurrentTime();
5398 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5399 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
5400 newTime - oldTime, ncbp->ncb_length);
5402 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
5403 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
5404 DeregisterEventSource(h);
5406 osi_Log1(afsd_logp, "Pkt straddled session startup, "
5407 "ncb length %d", ncbp->ncb_length);
5412 /* bad opcode, fail the request, after displaying it */
5415 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
5416 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
5418 if (code == IDCANCEL) showErrors = 0;
5421 code = CM_ERROR_BADOP;
5424 /* catastrophic failure: log as much as possible */
5425 if (code == CM_ERROR_BADSMB) {
5432 "Invalid SMB, ncb_length %d",
5435 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5436 sprintf(s, "Invalid SMB message, length %d",
5439 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
5440 1, ncbp->ncb_length, ptbuf, smbp);
5441 DeregisterEventSource(h);
5443 osi_Log1(afsd_logp, "Invalid SMB message, length %d",
5447 code = CM_ERROR_INVAL;
5450 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
5451 thrd_Decrement(&ongoingOps);
5456 /* now, if we failed, turn the current response into an empty
5457 * one, and fill in the response packet's error code.
5460 if (vcp->flags & SMB_VCFLAG_STATUS32) {
5461 smb_MapNTError(code, &NTStatus);
5462 outWctp = outp->wctp;
5463 smbp = (smb_t *) &outp->data;
5464 if (code != CM_ERROR_PARTIALWRITE
5465 && code != CM_ERROR_BUFFERTOOSMALL) {
5466 /* nuke wct and bcc. For a partial
5467 * write, assume they're OK.
5473 smbp->rcls = (unsigned char) (NTStatus & 0xff);
5474 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
5475 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
5476 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
5477 smbp->flg2 |= 0x4000;
5481 smb_MapCoreError(code, vcp, &errCode, &errClass);
5482 outWctp = outp->wctp;
5483 smbp = (smb_t *) &outp->data;
5484 if (code != CM_ERROR_PARTIALWRITE) {
5485 /* nuke wct and bcc. For a partial
5486 * write, assume they're OK.
5492 smbp->errLow = (unsigned char) (errCode & 0xff);
5493 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
5494 smbp->rcls = errClass;
5497 } /* error occurred */
5499 /* if we're here, we've finished one request. Look to see if
5500 * this is a chained opcode. If it is, setup things to process
5501 * the chained request, and setup the output buffer to hold the
5502 * chained response. Start by finding the next input record.
5504 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
5505 break; /* not a chained req */
5506 tp = inp->wctp; /* points to start of last request */
5507 if (tp[0] < 2) break; /* in a chained request, the first two
5508 * parm fields are required, and are
5509 * AndXCommand/AndXReserved and
5511 if (tp[1] == 0xff) break; /* no more chained opcodes */
5513 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
5516 /* and now append the next output request to the end of this
5517 * last request. Begin by finding out where the last response
5518 * ends, since that's where we'll put our new response.
5520 outWctp = outp->wctp; /* ptr to out parameters */
5521 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
5522 nparms = outWctp[0] << 1;
5523 tp = outWctp + nparms + 1; /* now points to bcc field */
5524 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
5525 tp += 2 /* for the count itself */ + nbytes;
5526 /* tp now points to the new output record; go back and patch the
5527 * second parameter (off2) to point to the new record.
5529 temp = (unsigned int)tp - ((unsigned int) outp->data);
5530 outWctp[3] = (unsigned char) (temp & 0xff);
5531 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
5532 outWctp[2] = 0; /* padding */
5533 outWctp[1] = inp->inCom; /* next opcode */
5535 /* finally, setup for the next iteration */
5538 } /* while loop over all requests in the packet */
5540 /* done logging out, turn off logging-out flag */
5541 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
5542 vcp->justLoggedOut = NULL;
5545 free(loggedOutName);
5546 loggedOutName = NULL;
5547 smb_ReleaseUID(loggedOutUserp);
5548 loggedOutUserp = NULL;
5552 /* now send the output packet, and return */
5554 smb_SendPacket(vcp, outp);
5555 thrd_Decrement(&ongoingOps);
5557 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
5559 last_msg_time = GetCurrentTime();
5561 else if (active_vcp == vcp)
5568 /* Wait for Netbios() calls to return, and make the results available to server
5569 * threads. Note that server threads can't wait on the NCBevents array
5570 * themselves, because NCB events are manual-reset, and the servers would race
5571 * each other to reset them.
5573 void smb_ClientWaiter(void *parmp)
5578 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
5580 if (code == WAIT_OBJECT_0)
5582 idx = code - WAIT_OBJECT_0;
5584 thrd_ResetEvent(NCBevents[idx]);
5585 thrd_SetEvent(NCBreturns[0][idx]);
5591 * Try to have one NCBRECV request waiting for every live session. Not more
5592 * than one, because if there is more than one, it's hard to handle Write Raw.
5594 void smb_ServerWaiter(void *parmp)
5596 DWORD code, idx_session, idx_NCB;
5604 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
5606 if (code == WAIT_OBJECT_0)
5608 idx_session = code - WAIT_OBJECT_0;
5612 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
5614 if (code == WAIT_OBJECT_0)
5616 idx_NCB = code - WAIT_OBJECT_0;
5618 /* Link them together */
5619 NCBsessions[idx_NCB] = idx_session;
5622 ncbp = NCBs[idx_NCB];
5624 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
5626 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
5627 ncbp->ncb_command = NCBRECV | ASYNCH;
5628 ncbp->ncb_lana_num = lanas[idx_session];
5630 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
5631 ncbp->ncb_event = NCBevents[idx_NCB];
5632 ncbp->ncb_length = SMB_PACKETSIZE;
5635 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
5636 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
5637 ncbp->ncb_event = NCBreturns[0][idx_NCB];
5638 ncbp->ncb_length = SMB_PACKETSIZE;
5639 Netbios(ncbp, dos_ncb);
5645 * The top level loop for handling SMB request messages. Each server thread
5646 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
5647 * NCB and buffer for the incoming request are loaned to us.
5649 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
5650 * to immediately send a request for the rest of the data. This must come
5651 * before any other traffic for that session, so we delay setting the session
5652 * event until that data has come in.
5654 void smb_Server(VOID *parmp)
5656 int myIdx = (int) parmp;
5660 smb_packet_t *outbufp;
5661 DWORD code, rcode, idx_NCB, idx_session;
5670 outbufp = GetPacket();
5671 outbufp->ncbp = outncbp;
5675 /* check for demo expiration */
5677 unsigned long tod = time((void *) 0);
5678 if (tod > EXPIREDATE) {
5679 (*smb_MBfunc)(NULL, "AFS demo expiration",
5681 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
5685 #endif /* !NOEXPIRE */
5687 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
5689 if (code == WAIT_OBJECT_0)
5691 idx_NCB = code - WAIT_OBJECT_0;
5693 ncbp = NCBs[idx_NCB];
5695 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
5697 idx_session = NCBsessions[idx_NCB];
5698 rc = ncbp->ncb_retcode;
5700 if (rc != NRC_PENDING && rc != NRC_GOODRET)
5701 osi_Log1(afsd_logp, "NCBRECV failure code %d", rc);
5704 case NRC_GOODRET: break;
5707 /* Can this happen? Or is it just my
5713 /* Client closed session */
5714 dead_sessions[idx_session] = TRUE;
5715 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
5716 /* Should also release vcp. Also, would do
5717 * sanity check that all TID's are gone. */
5720 "dead_vcp already set, %x",
5723 && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
5725 "setting dead_vcp %x, user struct %x",
5728 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
5730 if (vcp->justLoggedOut) {
5732 loggedOutTime = vcp->logoffTime;
5734 strdup(vcp->justLoggedOut->unp->name);
5735 loggedOutUserp = vcp->justLoggedOut;
5736 lock_ObtainWrite(&smb_rctLock);
5737 loggedOutUserp->refCount++;
5738 lock_ReleaseWrite(&smb_rctLock);
5743 /* Treat as transient error */
5751 "dispatch smb recv failed, message incomplete, ncb_length %d",
5753 h = RegisterEventSource(NULL,
5754 AFS_DAEMON_EVENT_NAME);
5755 sprintf(s, "SMB message incomplete, length %d",
5758 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
5760 ncbp->ncb_length, ptbuf,
5762 DeregisterEventSource(h);
5765 "dispatch smb recv failed, message incomplete, ncb_length %d",
5768 "SMB message incomplete, "
5769 "length %d", ncbp->ncb_length);
5773 * We used to discard the packet.
5774 * Instead, try handling it normally.
5782 /* A weird error code. Log it, sleep, and
5784 if (vcp->errorCount++ > 3)
5785 dead_sessions[idx_session] = TRUE;
5788 thrd_SetEvent(SessionEvents[idx_session]);
5793 /* Success, so now dispatch on all the data in the packet */
5795 smb_concurrentCalls++;
5796 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
5797 smb_maxObsConcurrentCalls = smb_concurrentCalls;
5799 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
5800 vcp->errorCount = 0;
5801 bufp = (struct smb_packet *) ncbp->ncb_buffer;
5803 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
5804 /* copy whole packet to virtual memory */
5805 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
5807 bufp->dos_pkt / 16, bufp);*/
5809 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
5811 smbp = (smb_t *)bufp->data;
5814 if (smbp->com == 0x1d) {
5815 /* Special handling for Write Raw */
5816 raw_write_cont_t rwc;
5817 EVENT_HANDLE rwevent;
5818 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
5819 if (rwc.code == 0) {
5820 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, NULL);
5821 ncbp->ncb_command = NCBRECV | ASYNCH;
5822 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
5823 ncbp->ncb_lana_num = vcp->lana;
5824 ncbp->ncb_buffer = rwc.buf;
5825 ncbp->ncb_length = 65535;
5826 ncbp->ncb_event = rwevent;
5830 Netbios(ncbp, dos_ncb);
5832 rcode = thrd_WaitForSingleObject_Event(rwevent,
5834 thrd_CloseHandle(rwevent);
5836 thrd_SetEvent(SessionEvents[idx_session]);
5838 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp,
5840 } else if (smbp->com == 0xa0) {
5842 * Serialize the handling for NT Transact
5845 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
5846 thrd_SetEvent(SessionEvents[idx_session]);
5848 thrd_SetEvent(SessionEvents[idx_session]);
5849 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
5852 smb_concurrentCalls--;
5855 thrd_SetEvent(NCBavails[idx_NCB]);
5860 * Create a new NCB and associated events, packet buffer, and "space" buffer.
5861 * If the number of server threads is M, and the number of live sessions is
5862 * N, then the number of NCB's in use at any time either waiting for, or
5863 * holding, received messages is M + N, so that is how many NCB's get created.
5865 void InitNCBslot(int idx)
5867 struct smb_packet *bufp;
5868 EVENT_HANDLE retHandle;
5871 NCBs[idx] = GetNCB();
5872 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, NULL);
5874 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, NULL);
5876 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, NULL);
5877 for (i=0; i<smb_NumServerThreads; i++)
5878 NCBreturns[i][idx] = retHandle;
5880 bufp->spacep = cm_GetSpace();
5884 /* listen for new connections */
5885 void smb_Listener(void *parmp)
5893 char rname[NCBNAMSZ+1];
5894 char cname[MAX_COMPUTERNAME_LENGTH+1];
5895 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
5900 int lana = (int) parmp;
5904 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
5908 memset(ncbp, 0, sizeof(NCB));
5911 /* terminate if shutdown flag is set */
5912 if (smbShutdownFlag == 1)
5917 /* check for demo expiration */
5919 unsigned long tod = time((void *) 0);
5920 if (tod > EXPIREDATE) {
5921 (*smb_MBfunc)(NULL, "AFS demo expiration",
5923 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
5927 #endif /* !NOEXPIRE */
5929 ncbp->ncb_command = NCBLISTEN;
5930 ncbp->ncb_rto = 0; /* No receive timeout */
5931 ncbp->ncb_sto = 0; /* No send timeout */
5933 /* pad out with spaces instead of null termination */
5934 len = strlen(smb_localNamep);
5935 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
5936 for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
5938 strcpy(ncbp->ncb_callname, "*");
5939 for(i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
5941 ncbp->ncb_lana_num = lana;
5944 code = Netbios(ncbp);
5946 code = Netbios(ncbp, dos_ncb);
5950 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
5951 ncbp->ncb_lana_num, code);
5952 osi_Log2(0, "NCBLISTEN lana=%d failed with code %d",
5953 ncbp->ncb_lana_num, code);
5954 fprintf(stderr, "\nClient exiting due to network failure "
5955 "(possibly due to power-saving mode)\n");
5956 fprintf(stderr, "Please restart client.\n");
5957 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
5961 osi_assert(code == 0);
5963 /* check for remote conns */
5964 /* first get remote name and insert null terminator */
5965 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
5966 for (i=NCBNAMSZ; i>0; i--) {
5967 if (rname[i-1] != ' ' && rname[i-1] != 0) {
5972 /* get local name and compare */
5973 GetComputerName(cname, &cnamelen);
5976 if (strncmp(rname, cname, NCBNAMSZ) != 0)
5977 flags |= SMB_VCFLAG_REMOTECONN;
5979 osi_Log1(afsd_logp, "New session lsn %d", ncbp->ncb_lsn);
5981 lock_ObtainMutex(&smb_ListenerLock);
5983 /* New generation */
5986 /* Log session startup */
5988 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
5990 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
5992 if (reportSessionStartups) {
5998 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5999 sprintf(s, "SMB session startup, %d ongoing ops",
6002 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
6004 DeregisterEventSource(h);
6006 afsi_log("NCBLISTEN completed, call from %s",rname);
6007 osi_Log1(afsd_logp, "SMB session startup, %d ongoing ops",
6010 fprintf(stderr, "%s: New session %d starting from host "
6012 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
6017 /* now ncbp->ncb_lsn is the connection ID */
6018 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
6019 vcp->flags |= flags;
6020 strcpy(vcp->rname, rname);
6022 /* Allocate slot in session arrays */
6023 /* Re-use dead session if possible, otherwise add one more */
6024 for (i = 0; i < numSessions; i++) {
6025 if (dead_sessions[i]) {
6026 dead_sessions[i] = FALSE;
6030 LSNs[i] = ncbp->ncb_lsn;
6031 lanas[i] = ncbp->ncb_lana_num;
6033 if (i == numSessions) {
6034 /* Add new NCB for new session */
6035 InitNCBslot(numNCBs);
6037 thrd_SetEvent(NCBavails[0]);
6038 thrd_SetEvent(NCBevents[0]);
6039 for (j = 0; j < smb_NumServerThreads; j++)
6040 thrd_SetEvent(NCBreturns[j][0]);
6041 /* Also add new session event */
6042 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, NULL);
6044 thrd_SetEvent(SessionEvents[0]);
6046 thrd_SetEvent(SessionEvents[i]);
6049 lock_ReleaseMutex(&smb_ListenerLock);
6051 } /* dispatch while loop */
6054 /* initialize Netbios */
6055 void smb_NetbiosInit()
6061 int i, lana, code, l;
6063 int delname_tried=0;
6066 OSVERSIONINFO Version;
6068 /*******************************************************************/
6069 /* ms loopback adapter scan */
6070 /*******************************************************************/
6073 ADAPTER_STATUS status;
6074 NAME_BUFFER NameBuff [30];
6080 /* AFAIK, this is the default for the ms loopback adapter.*/
6081 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
6082 /*******************************************************************/
6084 /* Get the version of Windows */
6085 memset(&Version, 0x00, sizeof(Version));
6086 Version.dwOSVersionInfoSize = sizeof(Version);
6087 GetVersionEx(&Version);
6089 /* setup the NCB system */
6092 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6096 if (smb_LANadapter == -1) {
6097 ncbp->ncb_command = NCBENUM;
6098 ncbp->ncb_buffer = &lana_list;
6099 ncbp->ncb_length = sizeof(lana_list);
6100 code = Netbios(ncbp);
6102 sprintf(s, "Netbios NCBENUM error code %d", code);
6104 osi_panic(s, __FILE__, __LINE__);
6108 lana_list.length = 1;
6109 lana_list.lana[0] = smb_LANadapter;
6112 for (i = 0; i < lana_list.length; i++) {
6113 /* reset the adaptor: in Win32, this is required for every process, and
6114 * acts as an init call, not as a real hardware reset.
6116 ncbp->ncb_command = NCBRESET;
6117 ncbp->ncb_callname[0] = 100;
6118 ncbp->ncb_callname[2] = 100;
6119 ncbp->ncb_lana_num = lana_list.lana[i];
6120 code = Netbios(ncbp);
6122 code = ncbp->ncb_retcode;
6124 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
6126 lana_list.lana[i] = 255; /* invalid lana */
6128 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
6130 memset( ncbp, 0, sizeof (*ncbp) );
6131 ncbp->ncb_command = NCBASTAT;
6132 ncbp->ncb_lana_num = lana_list.lana[i];
6133 strcpy( ncbp->ncb_callname, "* " );
6134 ncbp->ncb_buffer = (char *) &Adapter;
6135 ncbp->ncb_length = sizeof(Adapter);
6136 code = Netbios( ncbp );
6140 for (j=0; wla_found && (j<6); j++)
6141 wla_found = ( Adapter.status.adapter_address[j] == kWLA_MAC[j] );
6145 * check to see if this is the Microsoft Loopback Adapter"
6146 * if we are running on Windows XP or higher
6148 if ( Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
6149 ( Version.dwMajorVersion > 5 ||
6150 Version.dwMajorVersion == 5 &&
6151 Version.dwMinorVersion >= 1 )
6154 sprintf(s, "Windows Loopback Adapter detected lana %d", lana_list.lana[i]);
6157 /* select this lana; no need to continue */
6158 lana_list.length = 1;
6159 lana_list.lana[0] = lana_list.lana[i];
6162 sprintf(s, "Windows Loopback Adapter disabled lana %d", lana_list.lana[i]);
6164 lana_list.lana[i] = 255; /* invalid lana */
6171 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
6172 we will just fake the LANA list */
6173 if (smb_LANadapter == -1) {
6174 for (i = 0; i < 8; i++)
6175 lana_list.lana[i] = i;
6176 lana_list.length = 8;
6179 lana_list.length = 1;
6180 lana_list.lana[0] = smb_LANadapter;
6184 /* and declare our name so we can receive connections */
6185 memset(ncbp, 0, sizeof(*ncbp));
6186 len=lstrlen(smb_localNamep);
6187 memset(smb_sharename,' ',NCBNAMSZ);
6188 memcpy(smb_sharename,smb_localNamep,len);
6190 /*ncbp->ncb_lana_num = smb_LANadapter;*/
6191 strcpy(ncbp->ncb_name, smb_localNamep);
6192 len = strlen(smb_localNamep);
6193 for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
6195 sprintf(s, "lana_list.length %d", lana_list.length);
6198 /* Keep the name so we can unregister it later */
6199 for (l = 0; l < lana_list.length; l++) {
6200 lana = lana_list.lana[l];
6202 ncbp->ncb_command = NCBADDNAME;
6203 ncbp->ncb_lana_num = lana;
6204 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
6206 code = Netbios(ncbp);
6208 code = Netbios(ncbp, dos_ncb);
6211 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
6212 lana, code, ncbp->ncb_retcode,ncbp->ncb_cmd_cplt);
6214 char name[NCBNAMSZ+1];
6216 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
6217 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
6220 if (code == 0) code = ncbp->ncb_retcode;
6222 afsi_log("Netbios NCBADDNAME succeeded on lana %d", lana);
6224 /* we only use one LANA with djgpp */
6225 lana_list.lana[0] = lana;
6226 lana_list.length = 1;
6230 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
6232 if (code == NRC_BRIDGE) { /* invalid LANA num */
6233 lana_list.lana[l] = 255;
6236 else if (code == NRC_DUPNAME) {
6237 afsi_log("Name already exists; try to delete it");
6238 memset(ncbp, 0, sizeof(*ncbp));
6239 ncbp->ncb_command = NCBDELNAME;
6240 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
6241 ncbp->ncb_lana_num = lana;
6243 code = Netbios(ncbp);
6245 code = Netbios(ncbp, dos_ncb);
6247 if (code == 0) code = ncbp->ncb_retcode;
6249 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
6252 if (code != 0 || delname_tried) {
6253 lana_list.lana[l] = 255;
6255 else if (code == 0) {
6256 if (!delname_tried) {
6264 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
6266 lana_list.lana[l] = 255; /* invalid lana */
6267 osi_panic(s, __FILE__, __LINE__);
6271 lana_found = 1; /* at least one worked */
6278 osi_assert(lana_list.length >= 0);
6280 sprintf(s, "No valid LANA numbers found!");
6281 osi_panic(s, __FILE__, __LINE__);
6284 /* we're done with the NCB now */
6288 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
6307 smb_MBfunc = aMBfunc;
6311 /* check for demo expiration */
6313 unsigned long tod = time((void *) 0);
6314 if (tod > EXPIREDATE) {
6316 (*smb_MBfunc)(NULL, "AFS demo expiration",
6318 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
6321 fprintf(stderr, "AFS demo expiration\n");
6326 #endif /* !NOEXPIRE */
6329 smb_LANadapter = LANadapt;
6331 /* Initialize smb_localZero */
6332 myTime.tm_isdst = -1; /* compute whether on DST or not */
6333 myTime.tm_year = 70;
6339 smb_localZero = mktime(&myTime);
6341 /* Initialize kludge-GMT */
6342 smb_CalculateNowTZ();
6344 /* initialize the remote debugging log */
6347 /* remember the name */
6348 len = strlen(snamep);
6349 smb_localNamep = malloc(len+1);
6350 strcpy(smb_localNamep, snamep);
6352 /* and the global lock */
6353 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
6354 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
6356 /* Raw I/O data structures */
6357 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
6359 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
6361 /* 4 Raw I/O buffers */
6363 smb_RawBufs = calloc(65536,1);
6364 *((char **)smb_RawBufs) = NULL;
6365 for (i=0; i<3; i++) {
6366 char *rawBuf = calloc(65536,1);
6367 *((char **)rawBuf) = smb_RawBufs;
6368 smb_RawBufs = rawBuf;
6371 npar = 65536 >> 4; /* number of paragraphs */
6372 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
6374 afsi_log("Cannot allocate %d paragraphs of DOS memory",
6376 osi_panic("",__FILE__,__LINE__);
6379 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
6382 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
6384 _farpokel(_dos_ds, smb_RawBufs, NULL);
6385 for (i=0; i<SMB_RAW_BUFS-1; i++) {
6386 npar = 65536 >> 4; /* number of paragraphs */
6387 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
6389 afsi_log("Cannot allocate %d paragraphs of DOS memory",
6391 osi_panic("",__FILE__,__LINE__);
6394 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
6397 rawBuf = (seg * 16) + 0; /* DOS physical address */
6398 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
6399 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6400 smb_RawBufs = rawBuf;
6404 /* global free lists */
6405 smb_ncbFreeListp = NULL;
6406 smb_packetFreeListp = NULL;
6410 /* Initialize listener and server structures */
6411 memset(dead_sessions, 0, sizeof(dead_sessions));
6412 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, NULL);
6414 smb_NumServerThreads = nThreads;
6415 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, NULL);
6416 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, NULL);
6417 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
6418 for (i = 0; i < nThreads; i++) {
6419 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
6420 NCBreturns[i][0] = thrd_CreateEvent(NULL, FALSE, FALSE, NULL);
6422 for (i = 1; i <= nThreads; i++)
6424 numNCBs = nThreads + 1;
6426 /* Initialize dispatch table */
6427 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
6428 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
6429 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
6430 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
6431 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
6432 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
6433 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
6434 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
6435 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
6436 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
6437 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
6438 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
6439 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
6440 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
6441 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
6442 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp;
6443 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
6444 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
6445 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
6446 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
6447 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
6448 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
6449 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6450 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
6451 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
6452 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
6453 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
6454 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
6455 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
6456 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
6457 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
6458 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6459 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
6460 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
6461 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
6462 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
6463 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
6464 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6465 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
6466 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6467 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
6468 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
6469 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
6470 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
6471 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
6472 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
6473 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
6474 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
6475 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
6476 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
6477 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
6478 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
6479 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
6480 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
6481 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
6482 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
6483 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
6484 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6485 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;
6486 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;
6487 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;
6488 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;
6489 for(i=0xd0; i<= 0xd7; i++) {
6490 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
6493 /* setup tran 2 dispatch table */
6494 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
6495 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
6496 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
6497 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
6498 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
6499 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
6500 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
6501 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
6502 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
6503 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
6504 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
6505 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
6506 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
6507 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2MKDir;
6511 /* Start listeners, waiters, servers, and daemons */
6513 for (i = 0; i < lana_list.length; i++) {
6514 if (lana_list.lana[i] == 255) continue;
6515 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
6516 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
6517 osi_assert(phandle != NULL);
6518 thrd_CloseHandle(phandle);
6522 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
6523 NULL, 0, &lpid, "smb_ClientWaiter");
6524 osi_assert(phandle != NULL);
6525 thrd_CloseHandle(phandle);
6528 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
6529 NULL, 0, &lpid, "smb_ServerWaiter");
6530 osi_assert(phandle != NULL);
6531 thrd_CloseHandle(phandle);
6533 for (i=0; i<nThreads; i++) {
6534 phandle = thrd_Create(NULL, 65536,
6535 (ThreadFunc) smb_Server,
6536 (void *) i, 0, &lpid, "smb_Server");
6537 osi_assert(phandle != NULL);
6538 thrd_CloseHandle(phandle);
6541 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
6542 NULL, 0, &lpid, "smb_Daemon");
6543 osi_assert(phandle != NULL);
6544 thrd_CloseHandle(phandle);
6546 phandle = thrd_Create(NULL, 65536,
6547 (ThreadFunc) smb_WaitingLocksDaemon,
6548 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
6549 osi_assert(phandle != NULL);
6550 thrd_CloseHandle(phandle);
6560 void smb_Shutdown(void)
6567 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
6569 /* setup the NCB system */
6571 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6573 /* Block new sessions by setting shutdown flag */
6574 /*smbShutdownFlag = 1;*/
6576 /* Hang up all sessions */
6577 for (i = 1; i < numSessions; i++)
6579 if (dead_sessions[i])
6582 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
6583 ncbp->ncb_command = NCBHANGUP;
6584 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
6585 ncbp->ncb_lsn = LSNs[i];
6586 code = Netbios(ncbp, dos_ncb);
6587 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LS
6589 if (code == 0) code = ncbp->ncb_retcode;
6591 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
6596 /* Delete Netbios name */
6597 for (i = 0; i < lana_list.length; i++) {
6598 if (lana_list.lana[i] == 255) continue;
6599 ncbp->ncb_command = NCBDELNAME;
6600 ncbp->ncb_lana_num = lana_list.lana[i];
6601 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
6602 code = Netbios(ncbp, dos_ncb);
6603 if (code == 0) code = ncbp->ncb_retcode;
6605 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
6606 ncbp->ncb_lana_num, code);
6614 int smb_DumpVCP(FILE *outputFile, char *cookie)
6622 lock_ObtainRead(&smb_rctLock);
6624 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
6628 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
6629 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
6630 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
6632 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
6634 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",
6635 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
6636 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
6637 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
6638 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
6641 sprintf(output, "done dumping fidsp\n");
6642 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
6645 lock_ReleaseRead(&smb_rctLock);