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 #include <afs/param.h>
18 #include <sys/timeb.h>
34 #include "lanahelper.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 /* TODO; logout mechanism needs to be thread-safe */
44 char *loggedOutName = NULL;
45 smb_user_t *loggedOutUserp = NULL;
46 unsigned long loggedOutTime;
48 int smbShutdownFlag = 0;
50 int smb_LogoffTokenTransfer;
51 unsigned long smb_LogoffTransferTimeout;
53 DWORD last_msg_time = 0;
57 unsigned int sessionGen = 0;
59 extern void afsi_log(char *pattern, ...);
60 extern HANDLE afsi_file;
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, numVCs;
86 int smb_maxVCPerServer;
87 int smb_maxMpxRequests;
89 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
91 ULONG smb_lsaSecPackage;
92 LSA_STRING smb_lsaLogonOrigin;
94 #define NCBmax MAXIMUM_WAIT_OBJECTS
95 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
96 EVENT_HANDLE **NCBreturns;
97 DWORD NCBsessions[NCBmax];
99 struct smb_packet *bufs[NCBmax];
101 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
102 EVENT_HANDLE SessionEvents[Sessionmax];
103 unsigned short LSNs[Sessionmax];
104 int lanas[Sessionmax];
105 BOOL dead_sessions[Sessionmax];
109 osi_mutex_t smb_RawBufLock;
111 #define SMB_RAW_BUFS 4
113 int smb_RawBufSel[SMB_RAW_BUFS];
118 #define SMB_MASKFLAG_TILDE 1
119 #define SMB_MASKFLAG_CASEFOLD 2
121 #define RAWTIMEOUT INFINITE
124 typedef struct raw_write_cont {
137 /* dir search stuff */
138 long smb_dirSearchCounter = 1;
139 smb_dirSearch_t *smb_firstDirSearchp;
140 smb_dirSearch_t *smb_lastDirSearchp;
142 /* hide dot files? */
143 int smb_hideDotFiles;
145 /* global state about V3 protocols */
146 int smb_useV3; /* try to negotiate V3 */
149 static showErrors = 1;
150 /* MessageBox or something like it */
151 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
152 extern HANDLE WaitToTerminate;
156 * Time in Unix format of midnight, 1/1/1970 local time.
157 * When added to dosUTime, gives Unix (AFS) time.
159 long smb_localZero = 0;
161 /* Time difference for converting to kludge-GMT */
164 char *smb_localNamep = NULL;
166 smb_vc_t *smb_allVCsp;
168 smb_username_t *usernamesp = NULL;
170 smb_waitingLock_t *smb_allWaitingLocks;
173 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
174 NCB *ncbp, raw_write_cont_t *rwcp);
175 void smb_NetbiosInit();
177 #ifndef AFS_WIN95_ENV
178 DWORD smb_ServerExceptionFilter(void);
181 extern char cm_HostName[];
182 extern char cm_confDir[];
186 #define LPTSTR char *
187 #define GetComputerName(str, sizep) \
188 strcpy((str), cm_HostName); \
189 *(sizep) = strlen(cm_HostName)
192 extern char AFSConfigKeyName[];
194 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
195 int smb_ServerDomainNameLength = 0;
196 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
197 int smb_ServerOSLength = sizeof(smb_ServerOS);
198 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
199 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
201 /* Faux server GUID. This is never checked. */
202 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
207 * To build an expiring version, comment out the definition of NOEXPIRE,
208 * and set the definition of EXPIREDATE to the desired value.
211 #define EXPIREDATE 834000000 /* Wed Jun 5 1996 */
214 char * myCrt_Dispatch(int i)
219 return "unknown SMB op";
221 return "(00)ReceiveCoreMakeDir";
223 return "(01)ReceiveCoreRemoveDir";
225 return "(02)ReceiveCoreOpen";
227 return "(03)ReceiveCoreCreate";
229 return "(04)ReceiveCoreClose";
231 return "(05)ReceiveCoreFlush";
233 return "(06)ReceiveCoreUnlink";
235 return "(07)ReceiveCoreRename";
237 return "(08)ReceiveCoreGetFileAttributes";
239 return "(09)ReceiveCoreSetFileAttributes";
241 return "(0a)ReceiveCoreRead";
243 return "(0b)ReceiveCoreWrite";
245 return "(0c)ReceiveCoreLockRecord";
247 return "(0d)ReceiveCoreUnlockRecord";
249 return "(0e)SendCoreBadOp";
251 return "(0f)ReceiveCoreCreate";
253 return "(10)ReceiveCoreCheckPath";
255 return "(11)SendCoreBadOp";
257 return "(12)ReceiveCoreSeek";
259 return "(1a)ReceiveCoreReadRaw";
261 return "(1d)ReceiveCoreWriteRawDummy";
263 return "(22)ReceiveV3SetAttributes";
265 return "(23)ReceiveV3GetAttributes";
267 return "(24)ReceiveV3LockingX";
269 return "(25)ReceiveV3Trans";
271 return "(26)ReceiveV3Trans[aux]";
273 return "(29)SendCoreBadOp";
275 return "(2b)ReceiveCoreEcho";
277 return "(2d)ReceiveV3OpenX";
279 return "(2e)ReceiveV3ReadX";
281 return "(32)ReceiveV3Tran2A";
283 return "(33)ReceiveV3Tran2A[aux]";
285 return "(34)ReceiveV3FindClose";
287 return "(35)ReceiveV3FindNotifyClose";
289 return "(70)ReceiveCoreTreeConnect";
291 return "(71)ReceiveCoreTreeDisconnect";
293 return "(72)ReceiveNegotiate";
295 return "(73)ReceiveV3SessionSetupX";
297 return "(74)ReceiveV3UserLogoffX";
299 return "(75)ReceiveV3TreeConnectX";
301 return "(80)ReceiveCoreGetDiskAttributes";
303 return "(81)ReceiveCoreSearchDir";
305 return "(A0)ReceiveNTTransact";
307 return "(A2)ReceiveNTCreateX";
309 return "(A4)ReceiveNTCancel";
311 return "(c0)SendCoreBadOp";
313 return "(c1)SendCoreBadOp";
315 return "(c2)SendCoreBadOp";
317 return "(c3)SendCoreBadOp";
321 char * myCrt_2Dispatch(int i)
326 return "unknown SMB op-2";
328 return "S(00)CreateFile";
330 return "S(01)FindFirst";
332 return "S(02)FindNext"; /* FindNext */
334 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
338 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
340 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
342 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
344 return "S(08)??_ReceiveTran2SetFileInfo";
346 return "S(09)??_ReceiveTran2FSCTL";
348 return "S(0a)_ReceiveTran2IOCTL";
350 return "S(0b)_ReceiveTran2FindNotifyFirst";
352 return "S(0c)_ReceiveTran2FindNotifyNext";
354 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
358 char * myCrt_RapDispatch(int i)
363 return "unknown RAP OP";
365 return "RAP(0)NetShareEnum";
367 return "RAP(1)NetShareGetInfo";
369 return "RAP(13)NetServerGetInfo";
371 return "RAP(63)NetWkStaGetInfo";
375 /* scache must be locked */
376 unsigned int smb_Attributes(cm_scache_t *scp)
380 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
381 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
382 attrs = SMB_ATTR_DIRECTORY;
387 * We used to mark a file RO if it was in an RO volume, but that
388 * turns out to be impolitic in NT. See defect 10007.
391 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
393 if ((scp->unixModeBits & 0222) == 0)
394 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
399 /* Check if the named file/dir is a dotfile/dotdir */
400 /* String pointed to by lastComp can have leading slashes, but otherwise should have
401 no other patch components */
402 unsigned int smb_IsDotFile(char *lastComp) {
405 /* skip over slashes */
406 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
411 /* nulls, curdir and parent dir doesn't count */
414 if(!*(s + 1)) return 0;
415 if(*(s+1) == '.' && !*(s + 2)) return 0;
421 static int ExtractBits(WORD bits, short start, short len)
428 num = bits << (16 - end);
429 num = num >> ((16 - end) + start);
435 void ShowUnixTime(char *FuncName, afs_uint32 unixTime)
440 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
442 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
443 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
445 int day, month, year, sec, min, hour;
448 day = ExtractBits(wDate, 0, 5);
449 month = ExtractBits(wDate, 5, 4);
450 year = ExtractBits(wDate, 9, 7) + 1980;
452 sec = ExtractBits(wTime, 0, 5);
453 min = ExtractBits(wTime, 5, 6);
454 hour = ExtractBits(wTime, 11, 5);
456 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
457 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
463 /* Determine if we are observing daylight savings time */
464 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
466 TIME_ZONE_INFORMATION timeZoneInformation;
467 SYSTEMTIME utc, local, localDST;
469 /* Get the time zone info. NT uses this to calc if we are in DST. */
470 GetTimeZoneInformation(&timeZoneInformation);
472 /* Return the daylight bias */
473 *pDstBias = timeZoneInformation.DaylightBias;
475 /* Return the bias */
476 *pBias = timeZoneInformation.Bias;
478 /* Now determine if DST is being observed */
480 /* Get the UTC (GMT) time */
483 /* Convert UTC time to local time using the time zone info. If we are
484 observing DST, the calculated local time will include this.
486 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
488 /* Set the daylight bias to 0. The daylight bias is the amount of change
489 in time that we use for daylight savings time. By setting this to 0
490 we cause there to be no change in time during daylight savings time.
492 timeZoneInformation.DaylightBias = 0;
494 /* Convert the utc time to local time again, but this time without any
495 adjustment for daylight savings time.
497 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
499 /* If the two times are different, then it means that the localDST that
500 we calculated includes the daylight bias, and therefore we are
501 observing daylight savings time.
503 *pDST = localDST.wHour != local.wHour;
506 /* Determine if we are observing daylight savings time */
507 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
513 *pDstBias = -60; /* where can this be different? */
519 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
521 BOOL dst; /* Will be TRUE if observing DST */
522 LONG dstBias; /* Offset from local time if observing DST */
523 LONG bias; /* Offset from GMT for local time */
526 * This function will adjust the last write time to compensate
527 * for two bugs in the smb client:
529 * 1) During Daylight Savings Time, the LastWriteTime is ahead
530 * in time by the DaylightBias (ignoring the sign - the
531 * DaylightBias is always stored as a negative number). If
532 * the DaylightBias is -60, then the LastWriteTime will be
533 * ahead by 60 minutes.
535 * 2) If the local time zone is a positive offset from GMT, then
536 * the LastWriteTime will be the correct local time plus the
537 * Bias (ignoring the sign - a positive offset from GMT is
538 * always stored as a negative Bias). If the Bias is -120,
539 * then the LastWriteTime will be ahead by 120 minutes.
541 * These bugs can occur at the same time.
544 GetTimeZoneInfo(&dst, &dstBias, &bias);
546 /* First adjust for DST */
548 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
550 /* Now adjust for a positive offset from GMT (a negative bias). */
552 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
556 * Calculate the difference (in seconds) between local time and GMT.
557 * This enables us to convert file times to kludge-GMT.
563 struct tm gmt_tm, local_tm;
564 int days, hours, minutes, seconds;
567 gmt_tm = *(gmtime(&t));
568 local_tm = *(localtime(&t));
570 days = local_tm.tm_yday - gmt_tm.tm_yday;
571 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
573 /* There is a problem with DST immediately after the time change
574 * which may continue to exist until the machine is rebooted
576 - (local_tm.tm_isdst ? 1 : 0)
579 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
580 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
586 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, afs_uint32 unixTime)
591 long ersatz_unixTime;
594 * Must use kludge-GMT instead of real GMT.
595 * kludge-GMT is computed by adding time zone difference to localtime.
598 * ltp = gmtime(&unixTime);
600 ersatz_unixTime = unixTime - smb_NowTZ;
601 ltp = localtime(&ersatz_unixTime);
603 /* if we fail, make up something */
606 localJunk.tm_year = 89 - 20;
607 localJunk.tm_mon = 4;
608 localJunk.tm_mday = 12;
609 localJunk.tm_hour = 0;
610 localJunk.tm_min = 0;
611 localJunk.tm_sec = 0;
614 stm.wYear = ltp->tm_year + 1900;
615 stm.wMonth = ltp->tm_mon + 1;
616 stm.wDayOfWeek = ltp->tm_wday;
617 stm.wDay = ltp->tm_mday;
618 stm.wHour = ltp->tm_hour;
619 stm.wMinute = ltp->tm_min;
620 stm.wSecond = ltp->tm_sec;
621 stm.wMilliseconds = 0;
623 SystemTimeToFileTime(&stm, largeTimep);
626 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, afs_uint32 unixTime)
628 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
629 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
630 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
632 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
634 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
635 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
637 *ft = LargeIntegerMultiplyByLong(*ft, 60);
638 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
641 ut = ConvertLongToLargeInteger(unixTime);
642 ut = LargeIntegerMultiplyByLong(ut, 10000000);
643 *ft = LargeIntegerAdd(*ft, ut);
648 void smb_UnixTimeFromLargeSearchTime(afs_uint32 *unixTimep, FILETIME *largeTimep)
654 FileTimeToSystemTime(largeTimep, &stm);
656 lt.tm_year = stm.wYear - 1900;
657 lt.tm_mon = stm.wMonth - 1;
658 lt.tm_wday = stm.wDayOfWeek;
659 lt.tm_mday = stm.wDay;
660 lt.tm_hour = stm.wHour;
661 lt.tm_min = stm.wMinute;
662 lt.tm_sec = stm.wSecond;
665 save_timezone = _timezone;
666 _timezone += smb_NowTZ;
667 *unixTimep = mktime(<);
668 _timezone = save_timezone;
671 void smb_UnixTimeFromLargeSearchTime(afs_uint32 *unixTimep, FILETIME *largeTimep)
673 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
674 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
675 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
679 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
680 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
681 a = LargeIntegerMultiplyByLong(a, 60);
682 a = LargeIntegerMultiplyByLong(a, 10000000);
684 /* subtract it from ft */
685 a = LargeIntegerSubtract(*ft, a);
687 /* divide down to seconds */
688 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
692 void smb_SearchTimeFromUnixTime(long *dosTimep, afs_uint32 unixTime)
699 ltp = localtime((time_t*) &unixTime);
701 /* if we fail, make up something */
704 localJunk.tm_year = 89 - 20;
705 localJunk.tm_mon = 4;
706 localJunk.tm_mday = 12;
707 localJunk.tm_hour = 0;
708 localJunk.tm_min = 0;
709 localJunk.tm_sec = 0;
712 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
713 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
714 *dosTimep = (dosDate<<16) | dosTime;
717 void smb_UnixTimeFromSearchTime(afs_uint32 *unixTimep, long searchTime)
719 unsigned short dosDate;
720 unsigned short dosTime;
723 dosDate = searchTime & 0xffff;
724 dosTime = (searchTime >> 16) & 0xffff;
726 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
727 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
728 localTm.tm_mday = (dosDate) & 0x1f;
729 localTm.tm_hour = (dosTime>>11) & 0x1f;
730 localTm.tm_min = (dosTime >> 5) & 0x3f;
731 localTm.tm_sec = (dosTime & 0x1f) * 2;
732 localTm.tm_isdst = -1; /* compute whether DST in effect */
734 *unixTimep = mktime(&localTm);
737 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, afs_uint32 unixTime)
739 *dosUTimep = unixTime - smb_localZero;
742 void smb_UnixTimeFromDosUTime(afs_uint32 *unixTimep, afs_uint32 dosTime)
745 *unixTimep = dosTime + smb_localZero;
747 /* dosTime seems to be already adjusted for GMT */
748 *unixTimep = dosTime;
752 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
756 lock_ObtainWrite(&smb_rctLock);
757 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
758 if (lsn == vcp->lsn && lana == vcp->lana) {
763 if (!vcp && (flags & SMB_FLAG_CREATE)) {
764 vcp = malloc(sizeof(*vcp));
765 memset(vcp, 0, sizeof(*vcp));
766 vcp->vcID = numVCs++;
770 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
771 vcp->nextp = smb_allVCsp;
773 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
778 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
779 /* We must obtain a challenge for extended auth
780 * in case the client negotiates smb v3
783 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
784 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
787 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
789 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
796 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
798 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
799 LsaFreeReturnBuffer(lsaResp);
802 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
804 lock_ReleaseWrite(&smb_rctLock);
808 int smb_IsStarMask(char *maskp)
813 for(i=0; i<11; i++) {
815 if (tc == '?' || tc == '*' || tc == '>') return 1;
820 void smb_ReleaseVC(smb_vc_t *vcp)
822 lock_ObtainWrite(&smb_rctLock);
823 osi_assert(vcp->refCount-- > 0);
824 lock_ReleaseWrite(&smb_rctLock);
827 void smb_HoldVC(smb_vc_t *vcp)
829 lock_ObtainWrite(&smb_rctLock);
831 lock_ReleaseWrite(&smb_rctLock);
834 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
838 lock_ObtainWrite(&smb_rctLock);
839 for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
840 if (tid == tidp->tid) {
845 if (!tidp && (flags & SMB_FLAG_CREATE)) {
846 tidp = malloc(sizeof(*tidp));
847 memset(tidp, 0, sizeof(*tidp));
848 tidp->nextp = vcp->tidsp;
853 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
856 lock_ReleaseWrite(&smb_rctLock);
860 void smb_ReleaseTID(smb_tid_t *tidp)
869 lock_ObtainWrite(&smb_rctLock);
870 osi_assert(tidp->refCount-- > 0);
871 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
872 ltpp = &tidp->vcp->tidsp;
873 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
874 if (tp == tidp) break;
876 osi_assert(tp != NULL);
878 lock_FinalizeMutex(&tidp->mx);
879 userp = tidp->userp; /* remember to drop ref later */
882 lock_ReleaseWrite(&smb_rctLock);
884 cm_ReleaseUser(userp);
891 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
893 smb_user_t *uidp = NULL;
895 lock_ObtainWrite(&smb_rctLock);
896 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
897 if (uid == uidp->userID) {
899 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
900 (int)vcp, uidp->userID,
901 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
905 if (!uidp && (flags & SMB_FLAG_CREATE)) {
906 uidp = malloc(sizeof(*uidp));
907 memset(uidp, 0, sizeof(*uidp));
908 uidp->nextp = vcp->usersp;
913 lock_InitializeMutex(&uidp->mx, "user_t mutex");
915 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 : ""));
917 lock_ReleaseWrite(&smb_rctLock);
921 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
923 smb_username_t *unp= NULL;
925 lock_ObtainWrite(&smb_rctLock);
926 for(unp = usernamesp; unp; unp = unp->nextp) {
927 if (stricmp(unp->name, usern) == 0 &&
928 stricmp(unp->machine, machine) == 0) {
933 if (!unp && (flags & SMB_FLAG_CREATE)) {
934 unp = malloc(sizeof(*unp));
935 memset(unp, 0, sizeof(*unp));
937 unp->nextp = usernamesp;
938 unp->name = strdup(usern);
939 unp->machine = strdup(machine);
941 lock_InitializeMutex(&unp->mx, "username_t mutex");
943 lock_ReleaseWrite(&smb_rctLock);
947 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
949 smb_user_t *uidp= NULL;
951 lock_ObtainWrite(&smb_rctLock);
952 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
955 if (stricmp(uidp->unp->name, usern) == 0) {
957 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
962 lock_ReleaseWrite(&smb_rctLock);
965 void smb_ReleaseUID(smb_user_t *uidp)
974 lock_ObtainWrite(&smb_rctLock);
975 osi_assert(uidp->refCount-- > 0);
976 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
977 lupp = &uidp->vcp->usersp;
978 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
979 if (up == uidp) break;
981 osi_assert(up != NULL);
983 lock_FinalizeMutex(&uidp->mx);
985 userp = uidp->unp->userp; /* remember to drop ref later */
986 uidp->unp->userp = NULL;
991 lock_ReleaseWrite(&smb_rctLock);
993 cm_ReleaseUserVCRef(userp);
994 cm_ReleaseUser(userp);
1001 /* retrieve a held reference to a user structure corresponding to an incoming
1003 * corresponding release function is cm_ReleaseUser.
1005 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1011 smbp = (smb_t *) inp;
1012 uidp = smb_FindUID(vcp, smbp->uid, 0);
1013 if ((!uidp) || (!uidp->unp))
1016 lock_ObtainMutex(&uidp->mx);
1017 up = uidp->unp->userp;
1019 lock_ReleaseMutex(&uidp->mx);
1021 smb_ReleaseUID(uidp);
1027 * Return a pointer to a pathname extracted from a TID structure. The
1028 * TID structure is not held; assume it won't go away.
1030 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1035 tidp = smb_FindTID(vcp, tid, 0);
1039 if(tidp->flags & SMB_TIDFLAG_IPC) {
1040 code = CM_ERROR_TIDIPC;
1041 /* tidp->pathname would be NULL, but that's fine */
1043 *treepath = tidp->pathname;
1044 smb_ReleaseTID(tidp);
1049 /* check to see if we have a chained fid, that is, a fid that comes from an
1050 * OpenAndX message that ran earlier in this packet. In this case, the fid
1051 * field in a read, for example, request, isn't set, since the value is
1052 * supposed to be inherited from the openAndX call.
1054 int smb_ChainFID(int fid, smb_packet_t *inp)
1056 if (inp->fid == 0 || inp->inCount == 0)
1062 /* are we a priv'd user? What does this mean on NT? */
1063 int smb_SUser(cm_user_t *userp)
1068 /* find a file ID. If we pass in 0 we select an used File ID.
1069 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1070 * smb_fid_t data structure if desired File ID cannot be found.
1072 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1077 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1080 lock_ObtainWrite(&smb_rctLock);
1081 /* figure out if we need to allocate a new file ID */
1084 fid = vcp->fidCounter;
1088 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1089 if (fid == fidp->fid) {
1100 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1101 char eventName[MAX_PATH];
1103 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1104 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1105 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1106 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1107 thrd_CloseHandle(event);
1114 fidp = malloc(sizeof(*fidp));
1115 memset(fidp, 0, sizeof(*fidp));
1116 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1120 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1122 fidp->curr_chunk = fidp->prev_chunk = -2;
1123 fidp->raw_write_event = event;
1125 vcp->fidCounter = fid+1;
1126 if (vcp->fidCounter == 0)
1127 vcp->fidCounter = 1;
1130 lock_ReleaseWrite(&smb_rctLock);
1134 void smb_ReleaseFID(smb_fid_t *fidp)
1137 smb_vc_t *vcp = NULL;
1138 smb_ioctl_t *ioctlp;
1144 lock_ObtainWrite(&smb_rctLock);
1145 osi_assert(fidp->refCount-- > 0);
1146 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1148 if (!(fidp->flags & SMB_FID_IOCTL))
1150 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1151 thrd_CloseHandle(fidp->raw_write_event);
1153 /* and see if there is ioctl stuff to free */
1154 ioctlp = fidp->ioctlp;
1156 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1157 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1158 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1164 /* do not call smb_ReleaseVC() because we already have the lock */
1167 lock_ReleaseWrite(&smb_rctLock);
1169 /* now release the scache structure */
1171 cm_ReleaseSCache(scp);
1175 * Case-insensitive search for one string in another;
1176 * used to find variable names in submount pathnames.
1178 static char *smb_stristr(char *str1, char *str2)
1182 for (cursor = str1; *cursor; cursor++)
1183 if (stricmp(cursor, str2) == 0)
1190 * Substitute a variable value for its name in a submount pathname. Variable
1191 * name has been identified by smb_stristr() and is in substr. Variable name
1192 * length (plus one) is in substr_size. Variable value is in newstr.
1194 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1199 strcpy(temp, substr + substr_size - 1);
1200 strcpy(substr, newstr);
1204 char VNUserName[] = "%USERNAME%";
1205 char VNLCUserName[] = "%LCUSERNAME%";
1206 char VNComputerName[] = "%COMPUTERNAME%";
1207 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1210 /* List available shares */
1211 int smb_ListShares()
1215 char shareBuf[4096];
1223 /*strcpy(shareNameList[num_shares], "all");
1224 strcpy(pathNameList[num_shares++], "/afs");*/
1225 fprintf(stderr, "The following shares are available:\n");
1226 fprintf(stderr, "Share Name (AFS Path)\n");
1227 fprintf(stderr, "---------------------\n");
1228 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1231 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1232 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1234 strcpy(sbmtpath, cm_confDir);
1236 strcat(sbmtpath, "/afsdsbmt.ini");
1237 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1238 shareBuf, sizeof(shareBuf),
1244 this_share = shareBuf;
1248 /*strcpy(shareNameList[num_shares], this_share);*/
1249 len = GetPrivateProfileString("AFS Submounts", this_share,
1256 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1259 if (*p == '\\') *p = '/'; /* change to / */
1263 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1264 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1267 while (*this_share != 0) this_share++; /* find next NUL */
1268 this_share++; /* skip past the NUL */
1269 } while (*this_share != 0); /* stop at final NUL */
1275 typedef struct smb_findShare_rock {
1279 } smb_findShare_rock_t;
1281 #define SMB_FINDSHARE_EXACT_MATCH 1
1282 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1284 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1288 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1289 if(!strnicmp(dep->name, vrock->shareName, 12)) {
1290 if(!stricmp(dep->name, vrock->shareName))
1291 matchType = SMB_FINDSHARE_EXACT_MATCH;
1293 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1294 if(vrock->match) free(vrock->match);
1295 vrock->match = strdup(dep->name);
1296 vrock->matchType = matchType;
1298 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1299 return CM_ERROR_STOPNOW;
1305 /* find a shareName in the table of submounts */
1306 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1310 char pathName[1024];
1315 char sbmtpath[MAX_PATH];
1320 DWORD allSubmount = 1;
1322 /* if allSubmounts == 0, only return the //mountRoot/all share
1323 * if in fact it has been been created in the subMounts table.
1324 * This is to allow sites that want to restrict access to the
1327 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1328 0, KEY_QUERY_VALUE, &parmKey);
1329 if (code == ERROR_SUCCESS) {
1330 len = sizeof(allSubmount);
1331 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1332 (BYTE *) &allSubmount, &len);
1333 if (code != ERROR_SUCCESS) {
1336 RegCloseKey (parmKey);
1339 if (allSubmount && _stricmp(shareName, "all") == 0) {
1344 /* In case, the all share is disabled we need to still be able
1345 * to handle ioctl requests
1347 if (_stricmp(shareName, "ioctl$") == 0) {
1348 *pathNamep = strdup("/.__ioctl__");
1352 if (_stricmp(shareName, "IPC$") == 0 ||
1353 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1354 _stricmp(shareName, "DESKTOP.INI") == 0
1361 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1362 0, KEY_QUERY_VALUE, &parmKey);
1363 if (code == ERROR_SUCCESS) {
1364 len = sizeof(pathName);
1365 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1366 (BYTE *) pathName, &len);
1367 if (code != ERROR_SUCCESS)
1369 RegCloseKey (parmKey);
1374 strcpy(sbmtpath, cm_confDir);
1375 strcat(sbmtpath, "/afsdsbmt.ini");
1376 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1377 pathName, sizeof(pathName), sbmtpath);
1379 if (len != 0 && len != sizeof(pathName) - 1) {
1380 /* We can accept either unix or PC style AFS pathnames. Convert
1381 * Unix-style to PC style here for internal use.
1384 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1385 p += strlen(cm_mountRoot); /* skip mount path */
1388 if (*q == '/') *q = '\\'; /* change to \ */
1394 if (var = smb_stristr(p, VNUserName)) {
1395 if (uidp && uidp->unp)
1396 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1398 smb_subst(p, var, sizeof(VNUserName)," ");
1400 else if (var = smb_stristr(p, VNLCUserName))
1402 if (uidp && uidp->unp)
1403 strcpy(temp, uidp->unp->name);
1407 smb_subst(p, var, sizeof(VNLCUserName), temp);
1409 else if (var = smb_stristr(p, VNComputerName))
1411 sizeTemp = sizeof(temp);
1412 GetComputerName((LPTSTR)temp, &sizeTemp);
1413 smb_subst(p, var, sizeof(VNComputerName), temp);
1415 else if (var = smb_stristr(p, VNLCComputerName))
1417 sizeTemp = sizeof(temp);
1418 GetComputerName((LPTSTR)temp, &sizeTemp);
1420 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1425 *pathNamep = strdup(p);
1430 /* First lookup shareName in root.afs */
1432 smb_findShare_rock_t vrock;
1434 char * p = shareName;
1437 /* attempt to locate a partial match in root.afs. This is because
1438 when using the ANSI RAP calls, the share name is limited to 13 chars
1439 and hence is truncated. Of course we prefer exact matches. */
1441 thyper.HighPart = 0;
1444 vrock.shareName = shareName;
1446 vrock.matchType = 0;
1448 cm_HoldSCache(cm_rootSCachep);
1449 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1450 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1451 cm_ReleaseSCache(cm_rootSCachep);
1453 if(vrock.matchType) {
1454 sprintf(pathName,"/%s/",vrock.match);
1455 *pathNamep = strdup(strlwr(pathName));
1460 /* if we get here, there was no match for the share in root.afs */
1461 /* so try to create \\<netbiosName>\<cellname> */
1466 /* Get the full name for this cell */
1467 code = cm_SearchCellFile(p, temp, 0, 0);
1468 #ifdef AFS_AFSDB_ENV
1469 if (code && cm_dnsEnabled) {
1471 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1474 /* construct the path */
1476 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1477 *pathNamep = strdup(strlwr(pathName));
1486 /* Client-side offline caching policy types */
1487 #define CSC_POLICY_MANUAL 0
1488 #define CSC_POLICY_DOCUMENTS 1
1489 #define CSC_POLICY_PROGRAMS 2
1490 #define CSC_POLICY_DISABLE 3
1492 int smb_FindShareCSCPolicy(char *shareName)
1498 int retval = CSC_POLICY_MANUAL;
1500 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1501 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1504 REG_OPTION_NON_VOLATILE,
1510 len = sizeof(policy);
1511 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1513 retval = CSC_POLICY_MANUAL;
1515 else if (stricmp(policy, "documents") == 0)
1517 retval = CSC_POLICY_DOCUMENTS;
1519 else if (stricmp(policy, "programs") == 0)
1521 retval = CSC_POLICY_PROGRAMS;
1523 else if (stricmp(policy, "disable") == 0)
1525 retval = CSC_POLICY_DISABLE;
1528 RegCloseKey(hkCSCPolicy);
1532 /* find a dir search structure by cookie value, and return it held.
1533 * Must be called with smb_globalLock held.
1535 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1537 smb_dirSearch_t *dsp;
1539 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1540 if (dsp->cookie == cookie) {
1541 if (dsp != smb_firstDirSearchp) {
1542 /* move to head of LRU queue, too, if we're not already there */
1543 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1544 smb_lastDirSearchp = (smb_dirSearch_t *)
1546 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1547 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1548 if (!smb_lastDirSearchp)
1549 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1558 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1560 lock_ObtainWrite(&smb_globalLock);
1561 dsp->flags |= SMB_DIRSEARCH_DELETE;
1562 lock_ReleaseWrite(&smb_globalLock);
1563 lock_ObtainMutex(&dsp->mx);
1564 if(dsp->scp != NULL) {
1565 lock_ObtainMutex(&dsp->scp->mx);
1566 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1567 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1568 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1569 dsp->scp->bulkStatProgress = hones;
1571 lock_ReleaseMutex(&dsp->scp->mx);
1573 lock_ReleaseMutex(&dsp->mx);
1576 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1582 lock_ObtainWrite(&smb_globalLock);
1583 osi_assert(dsp->refCount-- > 0);
1584 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1585 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1586 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1587 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1588 lock_FinalizeMutex(&dsp->mx);
1592 lock_ReleaseWrite(&smb_globalLock);
1594 /* do this now to avoid spurious locking hierarchy creation */
1595 if (scp) cm_ReleaseSCache(scp);
1598 /* find a dir search structure by cookie value, and return it held */
1599 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1601 smb_dirSearch_t *dsp;
1603 lock_ObtainWrite(&smb_globalLock);
1604 dsp = smb_FindDirSearchNL(cookie);
1605 lock_ReleaseWrite(&smb_globalLock);
1609 /* GC some dir search entries, in the address space expected by the specific protocol.
1610 * Must be called with smb_globalLock held; release the lock temporarily.
1612 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1613 void smb_GCDirSearches(int isV3)
1615 smb_dirSearch_t *prevp;
1616 smb_dirSearch_t *tp;
1617 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1621 victimCount = 0; /* how many have we got so far */
1622 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1623 /* we'll move tp from queue, so
1626 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1627 /* if no one is using this guy, and we're either in the new protocol,
1628 * or we're in the old one and this is a small enough ID to be useful
1629 * to the old protocol, GC this guy.
1631 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1632 /* hold and delete */
1633 tp->flags |= SMB_DIRSEARCH_DELETE;
1634 victimsp[victimCount++] = tp;
1638 /* don't do more than this */
1639 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1642 /* now release them */
1643 lock_ReleaseWrite(&smb_globalLock);
1644 for(i = 0; i < victimCount; i++) {
1645 smb_ReleaseDirSearch(victimsp[i]);
1647 lock_ObtainWrite(&smb_globalLock);
1650 /* function for allocating a dir search entry. We need these to remember enough context
1651 * since we don't get passed the path from call to call during a directory search.
1653 * Returns a held dir search structure, and bumps the reference count on the vnode,
1654 * since it saves a pointer to the vnode.
1656 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1658 smb_dirSearch_t *dsp;
1662 lock_ObtainWrite(&smb_globalLock);
1665 /* what's the biggest ID allowed in this version of the protocol */
1666 if (isV3) maxAllowed = 65535;
1667 else maxAllowed = 255;
1670 /* twice so we have enough tries to find guys we GC after one pass;
1671 * 10 extra is just in case I mis-counted.
1673 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1674 __FILE__, __LINE__);
1675 if (smb_dirSearchCounter > maxAllowed) {
1676 smb_dirSearchCounter = 1;
1677 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1679 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1681 /* don't need to watch for refcount zero and deleted, since
1682 * we haven't dropped the global lock.
1685 ++smb_dirSearchCounter;
1689 dsp = malloc(sizeof(*dsp));
1690 memset(dsp, 0, sizeof(*dsp));
1691 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1692 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1693 dsp->cookie = smb_dirSearchCounter;
1694 ++smb_dirSearchCounter;
1696 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1697 dsp->lastTime = osi_Time();
1700 lock_ReleaseWrite(&smb_globalLock);
1704 static smb_packet_t *GetPacket(void)
1708 unsigned int npar, seg, tb_sel;
1711 lock_ObtainWrite(&smb_globalLock);
1712 tbp = smb_packetFreeListp;
1714 smb_packetFreeListp = tbp->nextp;
1715 lock_ReleaseWrite(&smb_globalLock);
1718 tbp = calloc(65540,1);
1720 tbp = malloc(sizeof(smb_packet_t));
1722 tbp->magic = SMB_PACKETMAGIC;
1725 tbp->resumeCode = 0;
1731 tbp->ncb_length = 0;
1736 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1739 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1741 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1743 osi_panic("",__FILE__,__LINE__);
1746 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1751 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1752 tbp->dos_pkt_sel = tb_sel;
1755 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1760 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1764 memcpy(tbp, pkt, sizeof(smb_packet_t));
1765 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1769 static NCB *GetNCB(void)
1774 unsigned int npar, seg, tb_sel;
1777 lock_ObtainWrite(&smb_globalLock);
1778 tbp = smb_ncbFreeListp;
1780 smb_ncbFreeListp = tbp->nextp;
1781 lock_ReleaseWrite(&smb_globalLock);
1784 tbp = calloc(sizeof(*tbp),1);
1786 tbp = malloc(sizeof(*tbp));
1787 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1790 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1792 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1794 osi_panic("",__FILE__,__LINE__);
1796 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1801 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1802 tbp->dos_ncb_sel = tb_sel;
1804 tbp->magic = SMB_NCBMAGIC;
1807 osi_assert(tbp->magic == SMB_NCBMAGIC);
1809 memset(&tbp->ncb, 0, sizeof(NCB));
1812 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1817 void smb_FreePacket(smb_packet_t *tbp)
1819 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1821 lock_ObtainWrite(&smb_globalLock);
1822 tbp->nextp = smb_packetFreeListp;
1823 smb_packetFreeListp = tbp;
1824 tbp->magic = SMB_PACKETMAGIC;
1827 tbp->resumeCode = 0;
1833 tbp->ncb_length = 0;
1835 lock_ReleaseWrite(&smb_globalLock);
1838 static void FreeNCB(NCB *bufferp)
1842 tbp = (smb_ncb_t *) bufferp;
1843 osi_assert(tbp->magic == SMB_NCBMAGIC);
1845 lock_ObtainWrite(&smb_globalLock);
1846 tbp->nextp = smb_ncbFreeListp;
1847 smb_ncbFreeListp = tbp;
1848 lock_ReleaseWrite(&smb_globalLock);
1851 /* get a ptr to the data part of a packet, and its count */
1852 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1856 unsigned char *afterParmsp;
1858 parmBytes = *smbp->wctp << 1;
1859 afterParmsp = smbp->wctp + parmBytes + 1;
1861 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1862 if (nbytesp) *nbytesp = dataBytes;
1864 /* don't forget to skip the data byte count, since it follows
1865 * the parameters; that's where the "2" comes from below.
1867 return (unsigned char *) (afterParmsp + 2);
1870 /* must set all the returned parameters before playing around with the
1871 * data region, since the data region is located past the end of the
1872 * variable number of parameters.
1874 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1876 unsigned char *afterParmsp;
1878 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1880 *afterParmsp++ = dsize & 0xff;
1881 *afterParmsp = (dsize>>8) & 0xff;
1884 /* return the parm'th parameter in the smbp packet */
1885 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1888 unsigned char *parmDatap;
1890 parmCount = *smbp->wctp;
1892 if (parm >= parmCount) {
1897 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1899 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1900 parm, parmCount, smbp->ncb_length);
1903 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1904 1, smbp->ncb_length, ptbuf, smbp);
1905 DeregisterEventSource(h);
1907 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1908 osi_panic(s, __FILE__, __LINE__);
1910 parmDatap = smbp->wctp + (2*parm) + 1;
1912 return parmDatap[0] + (parmDatap[1] << 8);
1915 /* return the parm'th parameter in the smbp packet */
1916 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1919 unsigned char *parmDatap;
1921 parmCount = *smbp->wctp;
1923 if (parm * 2 + offset >= parmCount * 2) {
1928 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1930 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1931 parm, offset, parmCount, smbp->ncb_length);
1934 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1935 1, smbp->ncb_length, ptbuf, smbp);
1936 DeregisterEventSource(h);
1938 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1939 osi_panic(s, __FILE__, __LINE__);
1941 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1943 return parmDatap[0] + (parmDatap[1] << 8);
1946 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1950 /* make sure we have enough slots */
1951 if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1953 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1954 *parmDatap++ = parmValue & 0xff;
1955 *parmDatap = (parmValue>>8) & 0xff;
1958 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1962 /* make sure we have enough slots */
1963 if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1965 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1966 *parmDatap++ = parmValue & 0xff;
1967 *parmDatap++ = (parmValue>>8) & 0xff;
1968 *parmDatap++ = (parmValue>>16) & 0xff;
1969 *parmDatap++ = (parmValue>>24) & 0xff;
1972 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1977 /* make sure we have enough slots */
1978 if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1980 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1982 *parmDatap++ = *parmValuep++;
1985 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1989 /* make sure we have enough slots */
1990 if (*smbp->wctp <= slot) {
1991 if (smbp->oddByte) {
1993 *smbp->wctp = slot+1;
1998 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1999 *parmDatap++ = parmValue & 0xff;
2002 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2006 lastSlashp = strrchr(inPathp, '\\');
2008 *lastComponentp = lastSlashp;
2011 if (inPathp == lastSlashp)
2013 *outPathp++ = *inPathp++;
2022 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2027 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2032 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2038 tlen = inp[0] + (inp[1]<<8);
2039 inp += 2; /* skip length field */
2042 *chainpp = inp + tlen;
2051 /* format a packet as a response */
2052 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2057 outp = (smb_t *) op;
2059 /* zero the basic structure through the smb_wct field, and zero the data
2060 * size field, assuming that wct stays zero; otherwise, you have to
2061 * explicitly set the data size field, too.
2063 inSmbp = (smb_t *) inp;
2064 memset(outp, 0, sizeof(smb_t)+2);
2070 outp->com = inSmbp->com;
2071 outp->tid = inSmbp->tid;
2072 outp->pid = inSmbp->pid;
2073 outp->uid = inSmbp->uid;
2074 outp->mid = inSmbp->mid;
2075 outp->res[0] = inSmbp->res[0];
2076 outp->res[1] = inSmbp->res[1];
2077 op->inCom = inSmbp->com;
2079 outp->reb = 0x80; /* SERVER_RESP */
2080 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2082 /* copy fields in generic packet area */
2083 op->wctp = &outp->wct;
2086 /* send a (probably response) packet; vcp tells us to whom to send it.
2087 * we compute the length by looking at wct and bcc fields.
2089 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2106 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2109 memset((char *)ncbp, 0, sizeof(NCB));
2111 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2112 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2113 extra += tp[0] + (tp[1]<<8);
2114 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2115 extra += 3; /* wct and length fields */
2117 ncbp->ncb_length = extra; /* bytes to send */
2118 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2119 ncbp->ncb_lana_num = vcp->lana;
2120 ncbp->ncb_command = NCBSEND; /* op means send data */
2122 ncbp->ncb_buffer = (char *) inp;/* packet */
2123 code = Netbios(ncbp);
2125 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2126 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2128 /* copy header information from virtual to DOS address space */
2129 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2130 code = Netbios(ncbp, dos_ncb);
2134 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2140 void smb_MapNTError(long code, unsigned long *NTStatusp)
2142 unsigned long NTStatus;
2144 /* map CM_ERROR_* errors to NT 32-bit status codes */
2145 /* NT Status codes are listed in ntstatus.h not winerror.h */
2146 if (code == CM_ERROR_NOSUCHCELL) {
2147 NTStatus = 0xC000000FL; /* No such file */
2149 else if (code == CM_ERROR_NOSUCHVOLUME) {
2150 NTStatus = 0xC000000FL; /* No such file */
2152 else if (code == CM_ERROR_TIMEDOUT) {
2153 NTStatus = 0xC00000CFL; /* Sharing Paused */
2155 else if (code == CM_ERROR_RETRY) {
2156 NTStatus = 0xC000022DL; /* Retry */
2158 else if (code == CM_ERROR_NOACCESS) {
2159 NTStatus = 0xC0000022L; /* Access denied */
2161 else if (code == CM_ERROR_READONLY) {
2162 NTStatus = 0xC00000A2L; /* Write protected */
2164 else if (code == CM_ERROR_NOSUCHFILE) {
2165 NTStatus = 0xC000000FL; /* No such file */
2167 else if (code == CM_ERROR_NOSUCHPATH) {
2168 NTStatus = 0xC000003AL; /* Object path not found */
2170 else if (code == CM_ERROR_TOOBIG) {
2171 NTStatus = 0xC000007BL; /* Invalid image format */
2173 else if (code == CM_ERROR_INVAL) {
2174 NTStatus = 0xC000000DL; /* Invalid parameter */
2176 else if (code == CM_ERROR_BADFD) {
2177 NTStatus = 0xC0000008L; /* Invalid handle */
2179 else if (code == CM_ERROR_BADFDOP) {
2180 NTStatus = 0xC0000022L; /* Access denied */
2182 else if (code == CM_ERROR_EXISTS) {
2183 NTStatus = 0xC0000035L; /* Object name collision */
2185 else if (code == CM_ERROR_NOTEMPTY) {
2186 NTStatus = 0xC0000101L; /* Directory not empty */
2188 else if (code == CM_ERROR_CROSSDEVLINK) {
2189 NTStatus = 0xC00000D4L; /* Not same device */
2191 else if (code == CM_ERROR_NOTDIR) {
2192 NTStatus = 0xC0000103L; /* Not a directory */
2194 else if (code == CM_ERROR_ISDIR) {
2195 NTStatus = 0xC00000BAL; /* File is a directory */
2197 else if (code == CM_ERROR_BADOP) {
2198 NTStatus = 0xC09820FFL; /* SMB no support */
2200 else if (code == CM_ERROR_BADSHARENAME) {
2201 NTStatus = 0xC00000CCL; /* Bad network name */
2203 else if (code == CM_ERROR_NOIPC) {
2205 NTStatus = 0xC0000022L; /* Access Denied */
2207 NTStatus = 0xC000013DL; /* Remote Resources */
2210 else if (code == CM_ERROR_CLOCKSKEW) {
2211 NTStatus = 0xC0000133L; /* Time difference at DC */
2213 else if (code == CM_ERROR_BADTID) {
2214 NTStatus = 0xC0982005L; /* SMB bad TID */
2216 else if (code == CM_ERROR_USESTD) {
2217 NTStatus = 0xC09820FBL; /* SMB use standard */
2219 else if (code == CM_ERROR_QUOTA) {
2220 NTStatus = 0xC0000044L; /* Quota exceeded */
2222 else if (code == CM_ERROR_SPACE) {
2223 NTStatus = 0xC000007FL; /* Disk full */
2225 else if (code == CM_ERROR_ATSYS) {
2226 NTStatus = 0xC0000033L; /* Object name invalid */
2228 else if (code == CM_ERROR_BADNTFILENAME) {
2229 NTStatus = 0xC0000033L; /* Object name invalid */
2231 else if (code == CM_ERROR_WOULDBLOCK) {
2232 NTStatus = 0xC0000055L; /* Lock not granted */
2234 else if (code == CM_ERROR_PARTIALWRITE) {
2235 NTStatus = 0xC000007FL; /* Disk full */
2237 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2238 NTStatus = 0xC0000023L; /* Buffer too small */
2240 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2241 NTStatus = 0xC0000035L; /* Object name collision */
2243 else if (code == CM_ERROR_BADPASSWORD) {
2244 NTStatus = 0xC000006DL; /* unknown username or bad password */
2246 else if (code == CM_ERROR_BADLOGONTYPE) {
2247 NTStatus = 0xC000015BL; /* logon type not granted */
2249 else if (code == CM_ERROR_GSSCONTINUE) {
2250 NTStatus = 0xC0000016L; /* more processing required */
2253 NTStatus = 0xC0982001L; /* SMB non-specific error */
2256 *NTStatusp = NTStatus;
2257 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2260 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2261 unsigned char *classp)
2263 unsigned char class;
2264 unsigned short error;
2266 /* map CM_ERROR_* errors to SMB errors */
2267 if (code == CM_ERROR_NOSUCHCELL) {
2269 error = 3; /* bad path */
2271 else if (code == CM_ERROR_NOSUCHVOLUME) {
2273 error = 3; /* bad path */
2275 else if (code == CM_ERROR_TIMEDOUT) {
2277 error = 81; /* server is paused */
2279 else if (code == CM_ERROR_RETRY) {
2280 class = 2; /* shouldn't happen */
2283 else if (code == CM_ERROR_NOACCESS) {
2285 error = 4; /* bad access */
2287 else if (code == CM_ERROR_READONLY) {
2289 error = 19; /* read only */
2291 else if (code == CM_ERROR_NOSUCHFILE) {
2293 error = 2; /* ENOENT! */
2295 else if (code == CM_ERROR_NOSUCHPATH) {
2297 error = 3; /* Bad path */
2299 else if (code == CM_ERROR_TOOBIG) {
2301 error = 11; /* bad format */
2303 else if (code == CM_ERROR_INVAL) {
2304 class = 2; /* server non-specific error code */
2307 else if (code == CM_ERROR_BADFD) {
2309 error = 6; /* invalid file handle */
2311 else if (code == CM_ERROR_BADFDOP) {
2312 class = 1; /* invalid op on FD */
2315 else if (code == CM_ERROR_EXISTS) {
2317 error = 80; /* file already exists */
2319 else if (code == CM_ERROR_NOTEMPTY) {
2321 error = 5; /* delete directory not empty */
2323 else if (code == CM_ERROR_CROSSDEVLINK) {
2325 error = 17; /* EXDEV */
2327 else if (code == CM_ERROR_NOTDIR) {
2328 class = 1; /* bad path */
2331 else if (code == CM_ERROR_ISDIR) {
2332 class = 1; /* access denied; DOS doesn't have a good match */
2335 else if (code == CM_ERROR_BADOP) {
2339 else if (code == CM_ERROR_BADSHARENAME) {
2343 else if (code == CM_ERROR_NOIPC) {
2345 error = 4; /* bad access */
2347 else if (code == CM_ERROR_CLOCKSKEW) {
2348 class = 1; /* invalid function */
2351 else if (code == CM_ERROR_BADTID) {
2355 else if (code == CM_ERROR_USESTD) {
2359 else if (code == CM_ERROR_REMOTECONN) {
2363 else if (code == CM_ERROR_QUOTA) {
2364 if (vcp->flags & SMB_VCFLAG_USEV3) {
2366 error = 39; /* disk full */
2370 error = 5; /* access denied */
2373 else if (code == CM_ERROR_SPACE) {
2374 if (vcp->flags & SMB_VCFLAG_USEV3) {
2376 error = 39; /* disk full */
2380 error = 5; /* access denied */
2383 else if (code == CM_ERROR_PARTIALWRITE) {
2385 error = 39; /* disk full */
2387 else if (code == CM_ERROR_ATSYS) {
2389 error = 2; /* ENOENT */
2391 else if (code == CM_ERROR_WOULDBLOCK) {
2393 error = 33; /* lock conflict */
2395 else if (code == CM_ERROR_NOFILES) {
2397 error = 18; /* no files in search */
2399 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2401 error = 183; /* Samba uses this */
2403 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2404 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2406 error = 2; /* bad password */
2415 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2418 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2420 return CM_ERROR_BADOP;
2423 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2425 unsigned short EchoCount, i;
2426 char *data, *outdata;
2429 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2431 for (i=1; i<=EchoCount; i++) {
2432 data = smb_GetSMBData(inp, &dataSize);
2433 smb_SetSMBParm(outp, 0, i);
2434 smb_SetSMBDataLength(outp, dataSize);
2435 outdata = smb_GetSMBData(outp, NULL);
2436 memcpy(outdata, data, dataSize);
2437 smb_SendPacket(vcp, outp);
2443 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2446 long count, minCount, finalCount;
2450 cm_user_t *userp = NULL;
2454 char *rawBuf = NULL;
2456 dos_ptr rawBuf = NULL;
2463 fd = smb_GetSMBParm(inp, 0);
2464 count = smb_GetSMBParm(inp, 3);
2465 minCount = smb_GetSMBParm(inp, 4);
2466 offset.HighPart = 0; /* too bad */
2467 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2469 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2470 fd, offset.LowPart, count);
2472 fidp = smb_FindFID(vcp, fd, 0);
2476 lock_ObtainMutex(&smb_RawBufLock);
2478 /* Get a raw buf, from head of list */
2479 rawBuf = smb_RawBufs;
2481 smb_RawBufs = *(char **)smb_RawBufs;
2483 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2486 lock_ReleaseMutex(&smb_RawBufLock);
2490 if (fidp->flags & SMB_FID_IOCTL)
2493 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2495 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2498 /* Give back raw buffer */
2499 lock_ObtainMutex(&smb_RawBufLock);
2501 *((char **) rawBuf) = smb_RawBufs;
2503 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2506 smb_RawBufs = rawBuf;
2507 lock_ReleaseMutex(&smb_RawBufLock);
2510 smb_ReleaseFID(fidp);
2514 userp = smb_GetUser(vcp, inp);
2517 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2519 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2520 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2521 userp, &finalCount, TRUE /* rawFlag */);
2528 cm_ReleaseUser(userp);
2531 smb_ReleaseFID(fidp);
2536 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2538 memset((char *)ncbp, 0, sizeof(NCB));
2540 ncbp->ncb_length = (unsigned short) finalCount;
2541 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2542 ncbp->ncb_lana_num = vcp->lana;
2543 ncbp->ncb_command = NCBSEND;
2544 ncbp->ncb_buffer = rawBuf;
2547 code = Netbios(ncbp);
2549 code = Netbios(ncbp, dos_ncb);
2552 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2555 /* Give back raw buffer */
2556 lock_ObtainMutex(&smb_RawBufLock);
2558 *((char **) rawBuf) = smb_RawBufs;
2560 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2563 smb_RawBufs = rawBuf;
2564 lock_ReleaseMutex(&smb_RawBufLock);
2570 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2575 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2580 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2587 int protoIndex; /* index we're using */
2592 char protocol_array[10][1024]; /* protocol signature of the client */
2593 int caps; /* capabilities */
2596 TIME_ZONE_INFORMATION tzi;
2598 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2602 DWORD now = GetCurrentTime();
2603 if (now - last_msg_time >= 30000
2604 && now - last_msg_time <= 90000) {
2606 "Setting dead_vcp %x", active_vcp);
2608 smb_ReleaseVC(dead_vcp);
2610 "Previous dead_vcp %x", dead_vcp);
2612 smb_HoldVC(active_vcp);
2613 dead_vcp = active_vcp;
2614 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2619 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2621 namep = smb_GetSMBData(inp, &dbytes);
2624 coreProtoIndex = -1; /* not found */
2627 while(namex < dbytes) {
2628 osi_Log1(smb_logp, "Protocol %s",
2629 osi_LogSaveString(smb_logp, namep+1));
2630 strcpy(protocol_array[tcounter], namep+1);
2632 /* namep points at the first protocol, or really, a 0x02
2633 * byte preceding the null-terminated ASCII name.
2635 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2636 coreProtoIndex = tcounter;
2638 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2639 v3ProtoIndex = tcounter;
2641 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2642 NTProtoIndex = tcounter;
2645 /* compute size of protocol entry */
2646 entryLength = strlen(namep+1);
2647 entryLength += 2; /* 0x02 bytes and null termination */
2649 /* advance over this protocol entry */
2650 namex += entryLength;
2651 namep += entryLength;
2652 tcounter++; /* which proto entry we're looking at */
2655 if (NTProtoIndex != -1) {
2656 protoIndex = NTProtoIndex;
2657 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2659 else if (v3ProtoIndex != -1) {
2660 protoIndex = v3ProtoIndex;
2661 vcp->flags |= SMB_VCFLAG_USEV3;
2663 else if (coreProtoIndex != -1) {
2664 protoIndex = coreProtoIndex;
2665 vcp->flags |= SMB_VCFLAG_USECORE;
2667 else protoIndex = -1;
2669 if (protoIndex == -1)
2670 return CM_ERROR_INVAL;
2671 else if (NTProtoIndex != -1) {
2672 smb_SetSMBParm(outp, 0, protoIndex);
2673 if (smb_authType != SMB_AUTH_NONE) {
2674 smb_SetSMBParmByte(outp, 1,
2675 NEGOTIATE_SECURITY_USER_LEVEL |
2676 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2678 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2680 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2681 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2682 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2683 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2684 /* The session key is not a well documented field however most clients
2685 * will echo back the session key to the server. Currently we are using
2686 * the same value for all sessions. We should generate a random value
2687 * and store it into the vcp
2689 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2690 smb_SetSMBParm(outp, 8, 1);
2692 * Tried changing the capabilities to support for W2K - defect 117695
2693 * Maybe something else needs to be changed here?
2697 smb_SetSMBParmLong(outp, 9, 0x43fd);
2699 smb_SetSMBParmLong(outp, 9, 0x251);
2702 * 32-bit error codes *
2706 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2707 NTNEGOTIATE_CAPABILITY_NTFIND |
2708 NTNEGOTIATE_CAPABILITY_RAWMODE |
2709 NTNEGOTIATE_CAPABILITY_NTSMB;
2711 if ( smb_authType == SMB_AUTH_EXTENDED )
2712 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2714 smb_SetSMBParmLong(outp, 9, caps);
2716 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2717 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2718 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2720 GetTimeZoneInformation(&tzi);
2721 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2723 if (smb_authType == SMB_AUTH_NTLM) {
2724 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2725 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2726 /* paste in encryption key */
2727 datap = smb_GetSMBData(outp, NULL);
2728 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2729 /* and the faux domain name */
2730 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2731 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2735 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2737 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2739 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2741 datap = smb_GetSMBData(outp, NULL);
2742 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2745 datap += sizeof(smb_ServerGUID);
2746 memcpy(datap, secBlob, secBlobLength);
2750 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2751 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2754 else if (v3ProtoIndex != -1) {
2755 smb_SetSMBParm(outp, 0, protoIndex);
2757 /* NOTE: Extended authentication cannot be negotiated with v3
2758 * therefore we fail over to NTLM
2760 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2761 smb_SetSMBParm(outp, 1,
2762 NEGOTIATE_SECURITY_USER_LEVEL |
2763 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2765 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2767 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2768 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2769 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2770 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2771 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2772 smb_SetSMBParm(outp, 7, 1);
2774 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2775 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2776 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2778 GetTimeZoneInformation(&tzi);
2779 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2781 /* NOTE: Extended authentication cannot be negotiated with v3
2782 * therefore we fail over to NTLM
2784 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2785 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2786 smb_SetSMBParm(outp, 12, 0); /* resvd */
2787 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2788 datap = smb_GetSMBData(outp, NULL);
2789 /* paste in a new encryption key */
2790 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2791 /* and the faux domain name */
2792 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2794 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2795 smb_SetSMBParm(outp, 12, 0); /* resvd */
2796 smb_SetSMBDataLength(outp, 0);
2799 else if (coreProtoIndex != -1) { /* not really supported anymore */
2800 smb_SetSMBParm(outp, 0, protoIndex);
2801 smb_SetSMBDataLength(outp, 0);
2806 void smb_Daemon(void *parmp)
2808 afs_uint32 count = 0;
2813 if ((count % 72) == 0) { /* every five minutes */
2815 long old_localZero = smb_localZero;
2817 /* Initialize smb_localZero */
2818 myTime.tm_isdst = -1; /* compute whether on DST or not */
2819 myTime.tm_year = 70;
2825 smb_localZero = mktime(&myTime);
2827 smb_CalculateNowTZ();
2829 #ifdef AFS_FREELANCE
2830 if ( smb_localZero != old_localZero )
2831 cm_noteLocalMountPointChange();
2834 /* XXX GC dir search entries */
2838 void smb_WaitingLocksDaemon()
2840 smb_waitingLock_t *wL, *nwL;
2843 smb_packet_t *inp, *outp;
2848 lock_ObtainWrite(&smb_globalLock);
2849 nwL = smb_allWaitingLocks;
2851 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2860 lock_ObtainWrite(&smb_globalLock);
2862 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2863 lock_ReleaseWrite(&smb_globalLock);
2864 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2865 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2866 if (code == CM_ERROR_WOULDBLOCK) {
2868 if (wL->timeRemaining != 0xffffffff
2869 && (wL->timeRemaining -= 1000) < 0)
2878 ncbp->ncb_length = inp->ncb_length;
2879 inp->spacep = cm_GetSpace();
2881 /* Remove waitingLock from list */
2882 lock_ObtainWrite(&smb_globalLock);
2883 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2885 lock_ReleaseWrite(&smb_globalLock);
2887 /* Resume packet processing */
2889 smb_SetSMBDataLength(outp, 0);
2890 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2891 outp->resumeCode = code;
2893 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2896 cm_FreeSpace(inp->spacep);
2897 smb_FreePacket(inp);
2898 smb_FreePacket(outp);
2906 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2908 osi_Log0(smb_logp, "SMB receive get disk attributes");
2910 smb_SetSMBParm(outp, 0, 32000);
2911 smb_SetSMBParm(outp, 1, 64);
2912 smb_SetSMBParm(outp, 2, 1024);
2913 smb_SetSMBParm(outp, 3, 30000);
2914 smb_SetSMBParm(outp, 4, 0);
2915 smb_SetSMBDataLength(outp, 0);
2919 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2923 unsigned short newTid;
2924 char shareName[256];
2932 osi_Log0(smb_logp, "SMB receive tree connect");
2934 /* parse input parameters */
2935 tp = smb_GetSMBData(inp, NULL);
2936 pathp = smb_ParseASCIIBlock(tp, &tp);
2937 passwordp = smb_ParseASCIIBlock(tp, &tp);
2938 tp = strrchr(pathp, '\\');
2940 return CM_ERROR_BADSMB;
2941 strcpy(shareName, tp+1);
2943 userp = smb_GetUser(vcp, inp);
2945 lock_ObtainMutex(&vcp->mx);
2946 newTid = vcp->tidCounter++;
2947 lock_ReleaseMutex(&vcp->mx);
2949 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2950 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2951 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2953 smb_ReleaseUID(uidp);
2955 smb_ReleaseTID(tidp);
2956 return CM_ERROR_BADSHARENAME;
2958 lock_ObtainMutex(&tidp->mx);
2959 tidp->userp = userp;
2960 tidp->pathname = sharePath;
2961 lock_ReleaseMutex(&tidp->mx);
2962 smb_ReleaseTID(tidp);
2964 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2965 smb_SetSMBParm(rsp, 1, newTid);
2966 smb_SetSMBDataLength(rsp, 0);
2968 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2972 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2976 if (*inp++ != 0x1) return NULL;
2977 tlen = inp[0] + (inp[1]<<8);
2978 inp += 2; /* skip length field */
2981 *chainpp = inp + tlen;
2984 if (lengthp) *lengthp = tlen;
2989 /* set maskp to the mask part of the incoming path.
2990 * Mask is 11 bytes long (8.3 with the dot elided).
2991 * Returns true if succeeds with a valid name, otherwise it does
2992 * its best, but returns false.
2994 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3002 /* starts off valid */
3005 /* mask starts out all blanks */
3006 memset(maskp, ' ', 11);
3008 /* find last backslash, or use whole thing if there is none */
3009 tp = strrchr(pathp, '\\');
3010 if (!tp) tp = pathp;
3011 else tp++; /* skip slash */
3015 /* names starting with a dot are illegal */
3016 if (*tp == '.') valid8Dot3 = 0;
3020 if (tc == 0) return valid8Dot3;
3021 if (tc == '.' || tc == '"') break;
3022 if (i < 8) *up++ = tc;
3023 else valid8Dot3 = 0;
3026 /* if we get here, tp point after the dot */
3027 up = maskp+8; /* ext goes here */
3034 if (tc == '.' || tc == '"')
3037 /* copy extension if not too long */
3047 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3057 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3059 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3063 /* otherwise, we have a valid 8.3 name; see if we have a match,
3064 * treating '?' as a wildcard in maskp (but not in the file name).
3066 tp1 = umask; /* real name, in mask format */
3067 tp2 = maskp; /* mask, in mask format */
3068 for(i=0; i<11; i++) {
3069 tc1 = *tp1++; /* char from real name */
3070 tc2 = *tp2++; /* char from mask */
3071 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3072 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3075 if (tc2 == '?' && tc1 != ' ')
3082 /* we got a match */
3086 char *smb_FindMask(char *pathp)
3090 tp = strrchr(pathp, '\\'); /* find last slash */
3093 return tp+1; /* skip the slash */
3095 return pathp; /* no slash, return the entire path */
3098 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3100 unsigned char *pathp;
3102 unsigned char mask[11];
3103 unsigned char *statBlockp;
3104 unsigned char initStatBlock[21];
3107 osi_Log0(smb_logp, "SMB receive search volume");
3109 /* pull pathname and stat block out of request */
3110 tp = smb_GetSMBData(inp, NULL);
3111 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3112 osi_assert(pathp != NULL);
3113 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3114 osi_assert(statBlockp != NULL);
3116 statBlockp = initStatBlock;
3120 /* for returning to caller */
3121 smb_Get8Dot3MaskFromPath(mask, pathp);
3123 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3124 tp = smb_GetSMBData(outp, NULL);
3126 *tp++ = 43; /* bytes in a dir entry */
3127 *tp++ = 0; /* high byte in counter */
3129 /* now marshall the dir entry, starting with the search status */
3130 *tp++ = statBlockp[0]; /* Reserved */
3131 memcpy(tp, mask, 11); tp += 11; /* FileName */
3133 /* now pass back server use info, with 1st byte non-zero */
3135 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3137 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3139 *tp++ = 0x8; /* attribute: volume */
3149 /* 4 byte file size */
3155 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3156 memset(tp, ' ', 13);
3159 /* set the length of the data part of the packet to 43 + 3, for the dir
3160 * entry plus the 5 and the length fields.
3162 smb_SetSMBDataLength(outp, 46);
3166 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3167 cm_user_t *userp, cm_req_t *reqp)
3175 smb_dirListPatch_t *patchp;
3176 smb_dirListPatch_t *npatchp;
3178 for(patchp = *dirPatchespp; patchp; patchp =
3179 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3181 dptr = patchp->dptr;
3183 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3185 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3186 *dptr++ = SMB_ATTR_HIDDEN;
3189 lock_ObtainMutex(&scp->mx);
3190 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3191 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3193 lock_ReleaseMutex(&scp->mx);
3194 cm_ReleaseSCache(scp);
3195 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3196 *dptr++ = SMB_ATTR_HIDDEN;
3200 attr = smb_Attributes(scp);
3201 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3202 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3203 attr |= SMB_ATTR_HIDDEN;
3207 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3210 shortTemp = dosTime & 0xffff;
3211 *((u_short *)dptr) = shortTemp;
3214 /* and copy out date */
3215 shortTemp = (dosTime>>16) & 0xffff;
3216 *((u_short *)dptr) = shortTemp;
3219 /* copy out file length */
3220 *((u_long *)dptr) = scp->length.LowPart;
3222 lock_ReleaseMutex(&scp->mx);
3223 cm_ReleaseSCache(scp);
3226 /* now free the patches */
3227 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3228 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3232 /* and mark the list as empty */
3233 *dirPatchespp = NULL;
3238 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3247 smb_dirListPatch_t *dirListPatchesp;
3248 smb_dirListPatch_t *curPatchp;
3252 osi_hyper_t dirLength;
3253 osi_hyper_t bufferOffset;
3254 osi_hyper_t curOffset;
3256 unsigned char *inCookiep;
3257 smb_dirSearch_t *dsp;
3261 unsigned long clientCookie;
3262 cm_pageHeader_t *pageHeaderp;
3263 cm_user_t *userp = NULL;
3270 long nextEntryCookie;
3271 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3272 char resByte; /* reserved byte from the cookie */
3273 char *op; /* output data ptr */
3274 char *origOp; /* original value of op */
3275 cm_space_t *spacep; /* for pathname buffer */
3286 maxCount = smb_GetSMBParm(inp, 0);
3288 dirListPatchesp = NULL;
3290 caseFold = CM_FLAG_CASEFOLD;
3292 tp = smb_GetSMBData(inp, NULL);
3293 pathp = smb_ParseASCIIBlock(tp, &tp);
3294 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3296 /* bail out if request looks bad */
3297 if (!tp || !pathp) {
3298 return CM_ERROR_BADSMB;
3301 /* We can handle long names */
3302 if (vcp->flags & SMB_VCFLAG_USENT)
3303 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3305 /* make sure we got a whole search status */
3306 if (dataLength < 21) {
3307 nextCookie = 0; /* start at the beginning of the dir */
3310 attribute = smb_GetSMBParm(inp, 1);
3312 /* handle volume info in another function */
3313 if (attribute & 0x8)
3314 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3316 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3317 maxCount, osi_LogSaveString(smb_logp, pathp));
3319 if (*pathp == 0) { /* null pathp, treat as root dir */
3320 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3321 return CM_ERROR_NOFILES;
3325 dsp = smb_NewDirSearch(0);
3326 dsp->attribute = attribute;
3327 smb_Get8Dot3MaskFromPath(mask, pathp);
3328 memcpy(dsp->mask, mask, 11);
3330 /* track if this is likely to match a lot of entries */
3331 if (smb_IsStarMask(mask)) starPattern = 1;
3332 else starPattern = 0;
3335 /* pull the next cookie value out of the search status block */
3336 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3337 + (inCookiep[16]<<24);
3338 dsp = smb_FindDirSearch(inCookiep[12]);
3340 /* can't find dir search status; fatal error */
3341 return CM_ERROR_BADFD;
3343 attribute = dsp->attribute;
3344 resByte = inCookiep[0];
3346 /* copy out client cookie, in host byte order. Don't bother
3347 * interpreting it, since we're just passing it through, anyway.
3349 memcpy(&clientCookie, &inCookiep[17], 4);
3351 memcpy(mask, dsp->mask, 11);
3353 /* assume we're doing a star match if it has continued for more
3359 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3360 nextCookie, dsp->cookie, attribute);
3362 userp = smb_GetUser(vcp, inp);
3364 /* try to get the vnode for the path name next */
3365 lock_ObtainMutex(&dsp->mx);
3372 spacep = inp->spacep;
3373 smb_StripLastComponent(spacep->data, NULL, pathp);
3374 lock_ReleaseMutex(&dsp->mx);
3375 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3377 lock_ReleaseMutex(&dsp->mx);
3378 cm_ReleaseUser(userp);
3379 smb_DeleteDirSearch(dsp);
3380 smb_ReleaseDirSearch(dsp);
3381 return CM_ERROR_NOFILES;
3383 code = cm_NameI(cm_rootSCachep, spacep->data,
3384 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3385 lock_ObtainMutex(&dsp->mx);
3387 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3389 /* we need one hold for the entry we just stored into,
3390 * and one for our own processing. When we're done with this
3391 * function, we'll drop the one for our own processing.
3392 * We held it once from the namei call, and so we do another hold
3396 lock_ObtainMutex(&scp->mx);
3397 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3398 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3399 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3400 dsp->flags |= SMB_DIRSEARCH_BULKST;
3402 lock_ReleaseMutex(&scp->mx);
3405 lock_ReleaseMutex(&dsp->mx);
3407 cm_ReleaseUser(userp);
3408 smb_DeleteDirSearch(dsp);
3409 smb_ReleaseDirSearch(dsp);
3413 /* reserves space for parameter; we'll adjust it again later to the
3414 * real count of the # of entries we returned once we've actually
3415 * assembled the directory listing.
3417 smb_SetSMBParm(outp, 0, 0);
3419 /* get the directory size */
3420 lock_ObtainMutex(&scp->mx);
3421 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3422 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3424 lock_ReleaseMutex(&scp->mx);
3425 cm_ReleaseSCache(scp);
3426 cm_ReleaseUser(userp);
3427 smb_DeleteDirSearch(dsp);
3428 smb_ReleaseDirSearch(dsp);
3432 dirLength = scp->length;
3434 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3435 curOffset.HighPart = 0;
3436 curOffset.LowPart = nextCookie;
3437 origOp = op = smb_GetSMBData(outp, NULL);
3438 /* and write out the basic header */
3439 *op++ = 5; /* variable block */
3440 op += 2; /* skip vbl block length; we'll fill it in later */
3444 /* make sure that curOffset.LowPart doesn't point to the first
3445 * 32 bytes in the 2nd through last dir page, and that it doesn't
3446 * point at the first 13 32-byte chunks in the first dir page,
3447 * since those are dir and page headers, and don't contain useful
3450 temp = curOffset.LowPart & (2048-1);
3451 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3452 /* we're in the first page */
3453 if (temp < 13*32) temp = 13*32;
3456 /* we're in a later dir page */
3457 if (temp < 32) temp = 32;
3460 /* make sure the low order 5 bits are zero */
3463 /* now put temp bits back ito curOffset.LowPart */
3464 curOffset.LowPart &= ~(2048-1);
3465 curOffset.LowPart |= temp;
3467 /* check if we've returned all the names that will fit in the
3470 if (returnedNames >= maxCount)
3473 /* check if we've passed the dir's EOF */
3474 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3476 /* see if we can use the bufferp we have now; compute in which page
3477 * the current offset would be, and check whether that's the offset
3478 * of the buffer we have. If not, get the buffer.
3480 thyper.HighPart = curOffset.HighPart;
3481 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3482 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3485 buf_Release(bufferp);
3488 lock_ReleaseMutex(&scp->mx);
3489 lock_ObtainRead(&scp->bufCreateLock);
3490 code = buf_Get(scp, &thyper, &bufferp);
3491 lock_ReleaseRead(&scp->bufCreateLock);
3493 /* now, if we're doing a star match, do bulk fetching of all of
3494 * the status info for files in the dir.
3497 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3499 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3500 && LargeIntegerGreaterThanOrEqualTo(thyper,
3501 scp->bulkStatProgress)) {
3502 /* Don't bulk stat if risking timeout */
3503 int now = GetCurrentTime();
3504 if (now - req.startTime > 5000) {
3505 scp->bulkStatProgress = thyper;
3506 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3507 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3509 cm_TryBulkStat(scp, &thyper, userp, &req);
3513 lock_ObtainMutex(&scp->mx);
3516 bufferOffset = thyper;
3518 /* now get the data in the cache */
3520 code = cm_SyncOp(scp, bufferp, userp, &req,
3522 CM_SCACHESYNC_NEEDCALLBACK
3523 | CM_SCACHESYNC_READ);
3526 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3528 /* otherwise, load the buffer and try again */
3529 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3534 buf_Release(bufferp);
3538 } /* if (wrong buffer) ... */
3540 /* now we have the buffer containing the entry we're interested in; copy
3541 * it out if it represents a non-deleted entry.
3543 entryInDir = curOffset.LowPart & (2048-1);
3544 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3546 /* page header will help tell us which entries are free. Page header
3547 * can change more often than once per buffer, since AFS 3 dir page size
3548 * may be less than (but not more than a buffer package buffer.
3550 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3551 temp &= ~(2048 - 1); /* turn off intra-page bits */
3552 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3554 /* now determine which entry we're looking at in the page. If it is
3555 * free (there's a free bitmap at the start of the dir), we should
3556 * skip these 32 bytes.
3558 slotInPage = (entryInDir & 0x7e0) >> 5;
3559 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3560 /* this entry is free */
3561 numDirChunks = 1; /* only skip this guy */
3565 tp = bufferp->datap + entryInBuffer;
3566 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3568 /* while we're here, compute the next entry's location, too,
3569 * since we'll need it when writing out the cookie into the dir
3572 * XXXX Probably should do more sanity checking.
3574 numDirChunks = cm_NameEntries(dep->name, NULL);
3576 /* compute the offset of the cookie representing the next entry */
3577 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3579 /* Compute 8.3 name if necessary */
3580 actualName = dep->name;
3581 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3582 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3583 actualName = shortName;
3586 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3587 /* this is one of the entries to use: it is not deleted
3588 * and it matches the star pattern we're looking for.
3591 /* Eliminate entries that don't match requested
3594 /* no hidden files */
3595 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3598 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3600 /* We have already done the cm_TryBulkStat above */
3601 fid.cell = scp->fid.cell;
3602 fid.volume = scp->fid.volume;
3603 fid.vnode = ntohl(dep->fid.vnode);
3604 fid.unique = ntohl(dep->fid.unique);
3605 fileType = cm_FindFileType(&fid);
3606 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3607 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3609 if (fileType == CM_SCACHETYPE_DIRECTORY)
3614 memcpy(op, mask, 11); op += 11;
3615 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3616 *op++ = nextEntryCookie & 0xff;
3617 *op++ = (nextEntryCookie>>8) & 0xff;
3618 *op++ = (nextEntryCookie>>16) & 0xff;
3619 *op++ = (nextEntryCookie>>24) & 0xff;
3620 memcpy(op, &clientCookie, 4); op += 4;
3622 /* now we emit the attribute. This is sort of tricky,
3623 * since we need to really stat the file to find out
3624 * what type of entry we've got. Right now, we're
3625 * copying out data from a buffer, while holding the
3626 * scp locked, so it isn't really convenient to stat
3627 * something now. We'll put in a place holder now,
3628 * and make a second pass before returning this to get
3629 * the real attributes. So, we just skip the data for
3630 * now, and adjust it later. We allocate a patch
3631 * record to make it easy to find this point later.
3632 * The replay will happen at a time when it is safe to
3633 * unlock the directory.
3635 curPatchp = malloc(sizeof(*curPatchp));
3636 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3637 curPatchp->dptr = op;
3638 curPatchp->fid.cell = scp->fid.cell;
3639 curPatchp->fid.volume = scp->fid.volume;
3640 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3641 curPatchp->fid.unique = ntohl(dep->fid.unique);
3643 /* do hidden attribute here since name won't be around when applying
3647 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3648 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3650 curPatchp->flags = 0;
3652 op += 9; /* skip attr, time, date and size */
3654 /* zero out name area. The spec says to pad with
3655 * spaces, but Samba doesn't, and neither do we.
3659 /* finally, we get to copy out the name; we know that
3660 * it fits in 8.3 or the pattern wouldn't match, but it
3661 * never hurts to be sure.
3663 strncpy(op, actualName, 13);
3665 /* Uppercase if requested by client */
3666 if ((((smb_t *)inp)->flg2 & 1) == 0)
3671 /* now, adjust the # of entries copied */
3673 } /* if we're including this name */
3676 /* and adjust curOffset to be where the new cookie is */
3677 thyper.HighPart = 0;
3678 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3679 curOffset = LargeIntegerAdd(thyper, curOffset);
3680 } /* while copying data for dir listing */
3682 /* release the mutex */
3683 lock_ReleaseMutex(&scp->mx);
3684 if (bufferp) buf_Release(bufferp);
3686 /* apply and free last set of patches; if not doing a star match, this
3687 * will be empty, but better safe (and freeing everything) than sorry.
3689 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3691 /* special return code for unsuccessful search */
3692 if (code == 0 && dataLength < 21 && returnedNames == 0)
3693 code = CM_ERROR_NOFILES;
3695 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3696 returnedNames, code);
3699 smb_DeleteDirSearch(dsp);
3700 smb_ReleaseDirSearch(dsp);
3701 cm_ReleaseSCache(scp);
3702 cm_ReleaseUser(userp);
3706 /* finalize the output buffer */
3707 smb_SetSMBParm(outp, 0, returnedNames);
3708 temp = (long) (op - origOp);
3709 smb_SetSMBDataLength(outp, temp);
3711 /* the data area is a variable block, which has a 5 (already there)
3712 * followed by the length of the # of data bytes. We now know this to
3713 * be "temp," although that includes the 3 bytes of vbl block header.
3714 * Deduct for them and fill in the length field.
3716 temp -= 3; /* deduct vbl block info */
3717 osi_assert(temp == (43 * returnedNames));
3718 origOp[1] = temp & 0xff;
3719 origOp[2] = (temp>>8) & 0xff;
3720 if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3721 smb_ReleaseDirSearch(dsp);
3722 cm_ReleaseSCache(scp);
3723 cm_ReleaseUser(userp);
3727 /* verify that this is a valid path to a directory. I don't know why they
3728 * don't use the get file attributes call.
3730 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3734 cm_scache_t *rootScp;
3735 cm_scache_t *newScp;
3744 pathp = smb_GetSMBData(inp, NULL);
3745 pathp = smb_ParseASCIIBlock(pathp, NULL);
3746 osi_Log1(smb_logp, "SMB receive check path %s",
3747 osi_LogSaveString(smb_logp, pathp));
3750 return CM_ERROR_BADFD;
3753 rootScp = cm_rootSCachep;
3755 userp = smb_GetUser(vcp, inp);
3757 caseFold = CM_FLAG_CASEFOLD;
3759 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3761 cm_ReleaseUser(userp);
3762 return CM_ERROR_NOSUCHPATH;
3764 code = cm_NameI(rootScp, pathp,
3765 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3766 userp, tidPathp, &req, &newScp);
3769 cm_ReleaseUser(userp);
3773 /* now lock the vnode with a callback; returns with newScp locked */
3774 lock_ObtainMutex(&newScp->mx);
3775 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3776 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3777 if (code && code != CM_ERROR_NOACCESS) {
3778 lock_ReleaseMutex(&newScp->mx);
3779 cm_ReleaseSCache(newScp);
3780 cm_ReleaseUser(userp);
3784 attrs = smb_Attributes(newScp);
3786 if (!(attrs & 0x10))
3787 code = CM_ERROR_NOTDIR;
3789 lock_ReleaseMutex(&newScp->mx);
3791 cm_ReleaseSCache(newScp);
3792 cm_ReleaseUser(userp);
3796 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3800 cm_scache_t *rootScp;
3801 unsigned short attribute;
3803 cm_scache_t *newScp;
3812 /* decode basic attributes we're passed */
3813 attribute = smb_GetSMBParm(inp, 0);
3814 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3816 pathp = smb_GetSMBData(inp, NULL);
3817 pathp = smb_ParseASCIIBlock(pathp, NULL);
3820 return CM_ERROR_BADSMB;
3823 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3824 dosTime, attribute);
3826 rootScp = cm_rootSCachep;
3828 userp = smb_GetUser(vcp, inp);
3830 caseFold = CM_FLAG_CASEFOLD;
3832 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3834 cm_ReleaseUser(userp);
3835 return CM_ERROR_NOSUCHFILE;
3837 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3838 tidPathp, &req, &newScp);
3841 cm_ReleaseUser(userp);
3845 /* now lock the vnode with a callback; returns with newScp locked; we
3846 * need the current status to determine what the new status is, in some
3849 lock_ObtainMutex(&newScp->mx);
3850 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3851 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3853 lock_ReleaseMutex(&newScp->mx);
3854 cm_ReleaseSCache(newScp);
3855 cm_ReleaseUser(userp);
3859 /* Check for RO volume */
3860 if (newScp->flags & CM_SCACHEFLAG_RO) {
3861 lock_ReleaseMutex(&newScp->mx);
3862 cm_ReleaseSCache(newScp);
3863 cm_ReleaseUser(userp);
3864 return CM_ERROR_READONLY;
3867 /* prepare for setattr call */
3870 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3871 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3873 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3874 /* we're told to make a writable file read-only */
3875 attr.unixModeBits = newScp->unixModeBits & ~0222;
3876 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3878 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3879 /* we're told to make a read-only file writable */
3880 attr.unixModeBits = newScp->unixModeBits | 0222;
3881 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3883 lock_ReleaseMutex(&newScp->mx);
3885 /* now call setattr */
3887 code = cm_SetAttr(newScp, &attr, userp, &req);
3891 cm_ReleaseSCache(newScp);
3892 cm_ReleaseUser(userp);
3897 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3901 cm_scache_t *rootScp;
3902 cm_scache_t *newScp, *dscp;
3914 pathp = smb_GetSMBData(inp, NULL);
3915 pathp = smb_ParseASCIIBlock(pathp, NULL);
3918 return CM_ERROR_BADSMB;
3921 if (*pathp == 0) /* null path */
3924 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3925 osi_LogSaveString(smb_logp, pathp));
3927 rootScp = cm_rootSCachep;
3929 userp = smb_GetUser(vcp, inp);
3931 /* we shouldn't need this for V3 requests, but we seem to */
3932 caseFold = CM_FLAG_CASEFOLD;
3934 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3936 cm_ReleaseUser(userp);
3937 return CM_ERROR_NOSUCHFILE;
3941 * XXX Strange hack XXX
3943 * As of Patch 5 (16 July 97), we are having the following problem:
3944 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3945 * requests to look up "desktop.ini" in all the subdirectories.
3946 * This can cause zillions of timeouts looking up non-existent cells
3947 * and volumes, especially in the top-level directory.
3949 * We have not found any way to avoid this or work around it except
3950 * to explicitly ignore the requests for mount points that haven't
3951 * yet been evaluated and for directories that haven't yet been
3954 * We should modify this hack to provide a fake desktop.ini file
3955 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3957 spacep = inp->spacep;
3958 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3959 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3960 code = cm_NameI(rootScp, spacep->data,
3961 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3962 userp, tidPathp, &req, &dscp);
3964 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3965 && !dscp->mountRootFidp)
3966 code = CM_ERROR_NOSUCHFILE;
3967 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3968 cm_buf_t *bp = buf_Find(dscp, &hzero);
3972 code = CM_ERROR_NOSUCHFILE;
3974 cm_ReleaseSCache(dscp);
3976 cm_ReleaseUser(userp);
3982 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3983 tidPathp, &req, &newScp);
3986 cm_ReleaseUser(userp);
3990 /* now lock the vnode with a callback; returns with newScp locked */
3991 lock_ObtainMutex(&newScp->mx);
3992 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3993 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3995 lock_ReleaseMutex(&newScp->mx);
3996 cm_ReleaseSCache(newScp);
3997 cm_ReleaseUser(userp);
4002 /* use smb_Attributes instead. Also the fact that a file is
4003 * in a readonly volume doesn't mean it shojuld be marked as RO
4005 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
4006 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4007 attrs = SMB_ATTR_DIRECTORY;
4010 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4011 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4013 attrs = smb_Attributes(newScp);
4016 smb_SetSMBParm(outp, 0, attrs);
4018 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4019 smb_SetSMBParm(outp, 1, dosTime & 0xffff);
4020 smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
4021 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4022 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4023 smb_SetSMBParm(outp, 5, 0);
4024 smb_SetSMBParm(outp, 6, 0);
4025 smb_SetSMBParm(outp, 7, 0);
4026 smb_SetSMBParm(outp, 8, 0);
4027 smb_SetSMBParm(outp, 9, 0);
4028 smb_SetSMBDataLength(outp, 0);
4029 lock_ReleaseMutex(&newScp->mx);
4031 cm_ReleaseSCache(newScp);
4032 cm_ReleaseUser(userp);
4037 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4041 osi_Log0(smb_logp, "SMB receive tree disconnect");
4043 /* find the tree and free it */
4044 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4046 lock_ObtainMutex(&tidp->mx);
4047 tidp->flags |= SMB_TIDFLAG_DELETE;
4048 lock_ReleaseMutex(&tidp->mx);
4049 smb_ReleaseTID(tidp);
4055 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4073 pathp = smb_GetSMBData(inp, NULL);
4074 pathp = smb_ParseASCIIBlock(pathp, NULL);
4076 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4078 #ifdef DEBUG_VERBOSE
4082 hexpath = osi_HexifyString( pathp );
4083 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4088 share = smb_GetSMBParm(inp, 0);
4089 attribute = smb_GetSMBParm(inp, 1);
4091 spacep = inp->spacep;
4092 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4093 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4094 /* special case magic file name for receiving IOCTL requests
4095 * (since IOCTL calls themselves aren't getting through).
4097 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4098 smb_SetupIoctlFid(fidp, spacep);
4099 smb_SetSMBParm(outp, 0, fidp->fid);
4100 smb_SetSMBParm(outp, 1, 0); /* attrs */
4101 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4102 smb_SetSMBParm(outp, 3, 0);
4103 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4104 smb_SetSMBParm(outp, 5, 0x7fff);
4105 /* pass the open mode back */
4106 smb_SetSMBParm(outp, 6, (share & 0xf));
4107 smb_SetSMBDataLength(outp, 0);
4108 smb_ReleaseFID(fidp);
4112 userp = smb_GetUser(vcp, inp);
4114 caseFold = CM_FLAG_CASEFOLD;
4116 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4118 cm_ReleaseUser(userp);
4119 return CM_ERROR_NOSUCHPATH;
4121 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4122 tidPathp, &req, &scp);
4125 cm_ReleaseUser(userp);
4129 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4131 cm_ReleaseSCache(scp);
4132 cm_ReleaseUser(userp);
4136 /* don't need callback to check file type, since file types never
4137 * change, and namei and cm_Lookup all stat the object at least once on
4138 * a successful return.
4140 if (scp->fileType != CM_SCACHETYPE_FILE) {
4141 cm_ReleaseSCache(scp);
4142 cm_ReleaseUser(userp);
4143 return CM_ERROR_ISDIR;
4146 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4149 /* save a pointer to the vnode */
4152 if ((share & 0xf) == 0)
4153 fidp->flags |= SMB_FID_OPENREAD;
4154 else if ((share & 0xf) == 1)
4155 fidp->flags |= SMB_FID_OPENWRITE;
4157 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4159 lock_ObtainMutex(&scp->mx);
4160 smb_SetSMBParm(outp, 0, fidp->fid);
4161 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4162 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4163 smb_SetSMBParm(outp, 2, dosTime & 0xffff);
4164 smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
4165 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4166 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4167 /* pass the open mode back; XXXX add access checks */
4168 smb_SetSMBParm(outp, 6, (share & 0xf));
4169 smb_SetSMBDataLength(outp, 0);
4170 lock_ReleaseMutex(&scp->mx);
4173 cm_Open(scp, 0, userp);
4175 /* send and free packet */
4176 smb_ReleaseFID(fidp);
4177 cm_ReleaseUser(userp);
4178 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4182 typedef struct smb_unlinkRock {
4187 char *maskp; /* pointer to the star pattern */
4192 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4195 smb_unlinkRock_t *rockp;
4203 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4204 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4205 caseFold |= CM_FLAG_8DOT3;
4207 matchName = dep->name;
4208 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4210 && (rockp->flags & SMB_MASKFLAG_TILDE)
4211 && !cm_Is8Dot3(dep->name)) {
4212 cm_Gen8Dot3Name(dep, shortName, NULL);
4213 matchName = shortName;
4214 /* 8.3 matches are always case insensitive */
4215 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4218 osi_Log1(smb_logp, "Unlinking %s",
4219 osi_LogSaveString(smb_logp, matchName));
4220 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4221 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4222 smb_NotifyChange(FILE_ACTION_REMOVED,
4223 FILE_NOTIFY_CHANGE_FILE_NAME,
4224 dscp, dep->name, NULL, TRUE);
4227 /* If we made a case sensitive exact match, we might as well quit now. */
4228 if(!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4229 code = CM_ERROR_STOPNOW;
4237 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4246 smb_unlinkRock_t rock;
4255 attribute = smb_GetSMBParm(inp, 0);
4257 tp = smb_GetSMBData(inp, NULL);
4258 pathp = smb_ParseASCIIBlock(tp, &tp);
4260 osi_Log1(smb_logp, "SMB receive unlink %s",
4261 osi_LogSaveString(smb_logp, pathp));
4263 spacep = inp->spacep;
4264 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4266 userp = smb_GetUser(vcp, inp);
4268 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4270 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4272 cm_ReleaseUser(userp);
4273 return CM_ERROR_NOSUCHPATH;
4275 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4279 cm_ReleaseUser(userp);
4283 /* otherwise, scp points to the parent directory. */
4290 rock.maskp = smb_FindMask(pathp);
4291 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4294 thyper.HighPart = 0;
4300 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4301 * match. If that fails, we do a case insensitve match.
4303 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4304 !smb_IsStarMask(rock.maskp)) {
4305 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4308 thyper.HighPart = 0;
4309 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4314 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4316 if (code == CM_ERROR_STOPNOW)
4319 cm_ReleaseUser(userp);
4321 cm_ReleaseSCache(dscp);
4323 if (code == 0 && !rock.any)
4324 code = CM_ERROR_NOSUCHFILE;
4328 typedef struct smb_renameRock {
4329 cm_scache_t *odscp; /* old dir */
4330 cm_scache_t *ndscp; /* new dir */
4331 cm_user_t *userp; /* user */
4332 cm_req_t *reqp; /* request struct */
4333 smb_vc_t *vcp; /* virtual circuit */
4334 char *maskp; /* pointer to star pattern of old file name */
4335 int flags; /* tilde, casefold, etc */
4336 char *newNamep; /* ptr to the new file's name */
4339 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4342 smb_renameRock_t *rockp;
4347 rockp = (smb_renameRock_t *) vrockp;
4349 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4350 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4351 caseFold |= CM_FLAG_8DOT3;
4353 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4355 && (rockp->flags & SMB_MASKFLAG_TILDE)
4356 && !cm_Is8Dot3(dep->name)) {
4357 cm_Gen8Dot3Name(dep, shortName, NULL);
4358 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4361 code = cm_Rename(rockp->odscp, dep->name,
4362 rockp->ndscp, rockp->newNamep, rockp->userp,
4364 /* if the call worked, stop doing the search now, since we
4365 * really only want to rename one file.
4368 code = CM_ERROR_STOPNOW;
4375 long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4381 cm_space_t *spacep = NULL;
4382 smb_renameRock_t rock;
4383 cm_scache_t *oldDscp = NULL;
4384 cm_scache_t *newDscp = NULL;
4385 cm_scache_t *tmpscp= NULL;
4386 cm_scache_t *tmpscp2 = NULL;
4398 tp = smb_GetSMBData(inp, NULL);
4399 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4400 newPathp = smb_ParseASCIIBlock(tp, &tp);
4402 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4403 osi_LogSaveString(smb_logp, oldPathp),
4404 osi_LogSaveString(smb_logp, newPathp));
4406 spacep = inp->spacep;
4407 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4409 userp = smb_GetUser(vcp, inp);
4412 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4413 * what actually exists is foo/baz. I don't know why the code used to be
4414 * the way it was. 1/29/96
4416 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4418 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4420 * caseFold = CM_FLAG_CASEFOLD;
4422 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4424 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4426 cm_ReleaseUser(userp);
4427 return CM_ERROR_NOSUCHPATH;
4429 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4430 userp, tidPathp, &req, &oldDscp);
4433 cm_ReleaseUser(userp);
4437 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4438 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4439 userp, tidPathp, &req, &newDscp);
4442 cm_ReleaseSCache(oldDscp);
4443 cm_ReleaseUser(userp);
4447 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4448 * next, get the component names, and lower case them.
4451 /* handle the old name first */
4453 oldLastNamep = oldPathp;
4457 /* and handle the new name, too */
4459 newLastNamep = newPathp;
4463 /* TODO: The old name could be a wildcard. The new name must not be */
4465 /* do the vnode call */
4466 rock.odscp = oldDscp;
4467 rock.ndscp = newDscp;
4471 rock.maskp = oldLastNamep;
4472 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4473 rock.newNamep = newLastNamep;
4475 /* Check if the file already exists; if so return error */
4476 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4477 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4478 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4479 osi_LogSaveString(afsd_logp, newLastNamep));
4481 /* Check if the old and the new names differ only in case. If so return
4482 * success, else return CM_ERROR_EXISTS
4484 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4486 /* This would be a success only if the old file is *as same as* the new file */
4487 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4489 if (tmpscp == tmpscp2)
4492 code = CM_ERROR_EXISTS;
4493 cm_ReleaseSCache(tmpscp2);
4496 code = CM_ERROR_NOSUCHFILE;
4499 /* file exist, do not rename, also fixes move */
4500 osi_Log0(smb_logp, "Can't rename. Target already exists");
4501 code = CM_ERROR_EXISTS;
4505 cm_ReleaseSCache(tmpscp);
4506 cm_ReleaseSCache(newDscp);
4507 cm_ReleaseSCache(oldDscp);
4508 cm_ReleaseUser(userp);
4512 /* Now search the directory for the pattern, and do the appropriate rename when found */
4513 thyper.LowPart = 0; /* search dir from here */
4514 thyper.HighPart = 0;
4516 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4518 if (code == CM_ERROR_STOPNOW)
4521 code = CM_ERROR_NOSUCHFILE;
4523 /* Handle Change Notification */
4525 * Being lazy, not distinguishing between files and dirs in this
4526 * filter, since we'd have to do a lookup.
4528 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4529 if (oldDscp == newDscp) {
4530 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4531 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4532 filter, oldDscp, oldLastNamep,
4533 newLastNamep, TRUE);
4535 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4536 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4537 filter, oldDscp, oldLastNamep,
4539 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4540 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4541 filter, newDscp, newLastNamep,
4546 cm_ReleaseSCache(tmpscp);
4547 cm_ReleaseUser(userp);
4548 cm_ReleaseSCache(oldDscp);
4549 cm_ReleaseSCache(newDscp);
4553 typedef struct smb_rmdirRock {
4557 char *maskp; /* pointer to the star pattern */
4562 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4565 smb_rmdirRock_t *rockp;
4570 rockp = (smb_rmdirRock_t *) vrockp;
4572 matchName = dep->name;
4573 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4574 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4576 match = (strcmp(matchName, rockp->maskp) == 0);
4578 && (rockp->flags & SMB_MASKFLAG_TILDE)
4579 && !cm_Is8Dot3(dep->name)) {
4580 cm_Gen8Dot3Name(dep, shortName, NULL);
4581 matchName = shortName;
4582 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4585 osi_Log1(smb_logp, "Removing directory %s",
4586 osi_LogSaveString(smb_logp, matchName));
4587 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4588 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4589 smb_NotifyChange(FILE_ACTION_REMOVED,
4590 FILE_NOTIFY_CHANGE_DIR_NAME,
4591 dscp, dep->name, NULL, TRUE);
4600 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4608 smb_rmdirRock_t rock;
4617 tp = smb_GetSMBData(inp, NULL);
4618 pathp = smb_ParseASCIIBlock(tp, &tp);
4620 spacep = inp->spacep;
4621 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4623 userp = smb_GetUser(vcp, inp);
4625 caseFold = CM_FLAG_CASEFOLD;
4627 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4629 cm_ReleaseUser(userp);
4630 return CM_ERROR_NOSUCHPATH;
4632 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4633 userp, tidPathp, &req, &dscp);
4636 cm_ReleaseUser(userp);
4640 /* otherwise, scp points to the parent directory. */
4647 rock.maskp = lastNamep;
4648 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4651 thyper.HighPart = 0;
4655 /* First do a case sensitive match, and if that fails, do a case insensitive match */
4656 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4657 if (code == 0 && !rock.any) {
4659 thyper.HighPart = 0;
4660 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4661 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4664 cm_ReleaseUser(userp);
4666 cm_ReleaseSCache(dscp);
4668 if (code == 0 && !rock.any)
4669 code = CM_ERROR_NOSUCHFILE;
4673 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4683 fid = smb_GetSMBParm(inp, 0);
4685 osi_Log1(smb_logp, "SMB flush fid %d", fid);
4687 fid = smb_ChainFID(fid, inp);
4688 fidp = smb_FindFID(vcp, fid, 0);
4689 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4691 smb_ReleaseFID(fidp);
4692 return CM_ERROR_BADFD;
4695 userp = smb_GetUser(vcp, inp);
4697 lock_ObtainMutex(&fidp->mx);
4698 if (fidp->flags & SMB_FID_OPENWRITE)
4699 code = cm_FSync(fidp->scp, userp, &req);
4702 lock_ReleaseMutex(&fidp->mx);
4704 smb_ReleaseFID(fidp);
4706 cm_ReleaseUser(userp);
4711 struct smb_FullNameRock {
4717 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4721 struct smb_FullNameRock *vrockp;
4723 vrockp = (struct smb_FullNameRock *)rockp;
4725 if (!cm_Is8Dot3(dep->name)) {
4726 cm_Gen8Dot3Name(dep, shortName, NULL);
4728 if (cm_stricmp(shortName, vrockp->name) == 0) {
4729 vrockp->fullName = strdup(dep->name);
4730 return CM_ERROR_STOPNOW;
4733 if (cm_stricmp(dep->name, vrockp->name) == 0
4734 && ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode
4735 && ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4736 vrockp->fullName = strdup(dep->name);
4737 return CM_ERROR_STOPNOW;
4742 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4743 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4745 struct smb_FullNameRock rock;
4751 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL,
4753 if (code == CM_ERROR_STOPNOW)
4754 *newPathp = rock.fullName;
4756 *newPathp = strdup(pathp);
4759 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4770 fid = smb_GetSMBParm(inp, 0);
4771 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4773 osi_Log1(smb_logp, "SMB close fid %d", fid);
4775 fid = smb_ChainFID(fid, inp);
4776 fidp = smb_FindFID(vcp, fid, 0);
4778 return CM_ERROR_BADFD;
4781 userp = smb_GetUser(vcp, inp);
4783 lock_ObtainMutex(&fidp->mx);
4785 /* Don't jump the gun on an async raw write */
4786 while (fidp->raw_writers) {
4787 lock_ReleaseMutex(&fidp->mx);
4788 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4789 lock_ObtainMutex(&fidp->mx);
4792 fidp->flags |= SMB_FID_DELETE;
4794 /* watch for ioctl closes, and read-only opens */
4795 if (fidp->scp != NULL
4796 && (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4797 == SMB_FID_OPENWRITE) {
4798 if (dosTime != 0 && dosTime != -1) {
4799 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4800 /* This fixes defect 10958 */
4801 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
4802 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
4804 code = cm_FSync(fidp->scp, userp, &req);
4809 if (fidp->flags & SMB_FID_DELONCLOSE) {
4810 cm_scache_t *dscp = fidp->NTopen_dscp;
4811 char *pathp = fidp->NTopen_pathp;
4814 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
4815 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
4816 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
4817 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4818 smb_NotifyChange(FILE_ACTION_REMOVED,
4819 FILE_NOTIFY_CHANGE_DIR_NAME,
4820 dscp, fullPathp, NULL, TRUE);
4824 code = cm_Unlink(dscp, fullPathp, userp, &req);
4825 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4826 smb_NotifyChange(FILE_ACTION_REMOVED,
4827 FILE_NOTIFY_CHANGE_FILE_NAME,
4828 dscp, fullPathp, NULL, TRUE);
4832 lock_ReleaseMutex(&fidp->mx);
4834 if (fidp->flags & SMB_FID_NTOPEN) {
4835 cm_ReleaseSCache(fidp->NTopen_dscp);
4836 free(fidp->NTopen_pathp);
4838 if (fidp->NTopen_wholepathp)
4839 free(fidp->NTopen_wholepathp);
4841 smb_ReleaseFID(fidp);
4842 cm_ReleaseUser(userp);
4847 * smb_ReadData -- common code for Read, Read And X, and Raw Read
4850 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4851 cm_user_t *userp, long *readp)
4853 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4854 cm_user_t *userp, long *readp, int dosflag)
4861 osi_hyper_t fileLength;
4863 osi_hyper_t lastByte;
4864 osi_hyper_t bufferOffset;
4865 long bufIndex, nbytes;
4875 lock_ObtainMutex(&fidp->mx);
4877 lock_ObtainMutex(&scp->mx);
4879 if (offset.HighPart == 0) {
4880 chunk = offset.LowPart >> cm_logChunkSize;
4881 if (chunk != fidp->curr_chunk) {
4882 fidp->prev_chunk = fidp->curr_chunk;
4883 fidp->curr_chunk = chunk;
4885 if (fidp->curr_chunk == fidp->prev_chunk + 1)
4889 /* start by looking up the file's end */
4890 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4891 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4892 if (code) goto done;
4894 /* now we have the entry locked, look up the length */
4895 fileLength = scp->length;
4897 /* adjust count down so that it won't go past EOF */
4898 thyper.LowPart = count;
4899 thyper.HighPart = 0;
4900 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
4902 if (LargeIntegerGreaterThan(thyper, fileLength)) {
4903 /* we'd read past EOF, so just stop at fileLength bytes.
4904 * Start by computing how many bytes remain in the file.
4906 thyper = LargeIntegerSubtract(fileLength, offset);
4908 /* if we are past EOF, read 0 bytes */
4909 if (LargeIntegerLessThanZero(thyper))
4912 count = thyper.LowPart;
4917 /* now, copy the data one buffer at a time,
4918 * until we've filled the request packet
4921 /* if we've copied all the data requested, we're done */
4922 if (count <= 0) break;
4924 /* otherwise, load up a buffer of data */
4925 thyper.HighPart = offset.HighPart;
4926 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4927 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4930 buf_Release(bufferp);
4933 lock_ReleaseMutex(&scp->mx);
4935 lock_ObtainRead(&scp->bufCreateLock);
4936 code = buf_Get(scp, &thyper, &bufferp);
4937 lock_ReleaseRead(&scp->bufCreateLock);
4939 lock_ObtainMutex(&scp->mx);
4940 if (code) goto done;
4941 bufferOffset = thyper;
4943 /* now get the data in the cache */
4945 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4946 CM_SCACHESYNC_NEEDCALLBACK
4947 | CM_SCACHESYNC_READ);
4948 if (code) goto done;
4950 if (cm_HaveBuffer(scp, bufferp, 0)) break;
4952 /* otherwise, load the buffer and try again */
4953 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4957 buf_Release(bufferp);
4961 } /* if (wrong buffer) ... */
4963 /* now we have the right buffer loaded. Copy out the
4964 * data from here to the user's buffer.
4966 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4968 /* and figure out how many bytes we want from this buffer */
4969 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
4970 if (nbytes > count) nbytes = count; /* don't go past EOF */
4972 /* now copy the data */
4975 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
4978 memcpy(op, bufferp->datap + bufIndex, nbytes);
4980 /* adjust counters, pointers, etc. */
4983 thyper.LowPart = nbytes;
4984 thyper.HighPart = 0;
4985 offset = LargeIntegerAdd(thyper, offset);
4989 lock_ReleaseMutex(&scp->mx);
4990 lock_ReleaseMutex(&fidp->mx);
4992 buf_Release(bufferp);
4994 if (code == 0 && sequential)
4995 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5001 * smb_WriteData -- common code for Write and Raw Write
5004 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5005 cm_user_t *userp, long *writtenp)
5007 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5008 cm_user_t *userp, long *writtenp, int dosflag)
5015 osi_hyper_t fileLength; /* file's length at start of write */
5016 osi_hyper_t minLength; /* don't read past this */
5017 long nbytes; /* # of bytes to transfer this iteration */
5019 osi_hyper_t thyper; /* hyper tmp variable */
5020 osi_hyper_t bufferOffset;
5021 long bufIndex; /* index in buffer where our data is */
5023 osi_hyper_t writeBackOffset; /* offset of region to write back when
5028 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5029 fidp->fid, offsetp->LowPart, count);
5037 lock_ObtainMutex(&fidp->mx);
5039 lock_ObtainMutex(&scp->mx);
5041 /* start by looking up the file's end */
5042 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5044 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5045 CM_SCACHESYNC_NEEDCALLBACK
5046 | CM_SCACHESYNC_SETSTATUS
5047 | CM_SCACHESYNC_GETSTATUS);
5048 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5053 /* make sure we have a writable FD */
5054 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5055 code = CM_ERROR_BADFDOP;
5059 /* now we have the entry locked, look up the length */
5060 fileLength = scp->length;
5061 minLength = fileLength;
5062 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5063 minLength = scp->serverLength;
5065 /* adjust file length if we extend past EOF */
5066 thyper.LowPart = count;
5067 thyper.HighPart = 0;
5068 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5069 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5070 /* we'd write past EOF, so extend the file */
5071 scp->mask |= CM_SCACHEMASK_LENGTH;
5072 scp->length = thyper;
5073 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5075 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5077 /* now, if the new position (thyper) and the old (offset) are in
5078 * different storeback windows, remember to store back the previous
5079 * storeback window when we're done with the write.
5081 if ((thyper.LowPart & (-cm_chunkSize)) !=
5082 (offset.LowPart & (-cm_chunkSize))) {
5083 /* they're different */
5085 writeBackOffset.HighPart = offset.HighPart;
5086 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5091 /* now, copy the data one buffer at a time, until we've filled the
5094 /* if we've copied all the data requested, we're done */
5095 if (count <= 0) break;
5097 /* handle over quota or out of space */
5098 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5099 *writtenp = written;
5103 /* otherwise, load up a buffer of data */
5104 thyper.HighPart = offset.HighPart;
5105 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5106 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5109 lock_ReleaseMutex(&bufferp->mx);
5110 buf_Release(bufferp);
5113 lock_ReleaseMutex(&scp->mx);
5115 lock_ObtainRead(&scp->bufCreateLock);
5116 code = buf_Get(scp, &thyper, &bufferp);
5117 lock_ReleaseRead(&scp->bufCreateLock);
5119 lock_ObtainMutex(&bufferp->mx);
5120 lock_ObtainMutex(&scp->mx);
5121 if (code) goto done;
5123 bufferOffset = thyper;
5125 /* now get the data in the cache */
5127 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5129 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5130 CM_SCACHESYNC_NEEDCALLBACK
5131 | CM_SCACHESYNC_WRITE
5132 | CM_SCACHESYNC_BUFLOCKED);
5133 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5138 /* If we're overwriting the entire buffer, or
5139 * if we're writing at or past EOF, mark the
5140 * buffer as current so we don't call
5141 * cm_GetBuffer. This skips the fetch from the
5142 * server in those cases where we're going to
5143 * obliterate all the data in the buffer anyway,
5144 * or in those cases where there is no useful
5145 * data at the server to start with.
5147 * Use minLength instead of scp->length, since
5148 * the latter has already been updated by this
5151 if (LargeIntegerGreaterThanOrEqualTo(
5152 bufferp->offset, minLength)
5153 || LargeIntegerEqualTo(offset, bufferp->offset)
5154 && (count >= buf_bufferSize
5155 || LargeIntegerGreaterThanOrEqualTo(
5156 LargeIntegerAdd(offset,
5157 ConvertLongToLargeInteger(count)),
5159 if (count < buf_bufferSize
5160 && bufferp->dataVersion == -1)
5161 memset(bufferp->datap, 0,
5163 bufferp->dataVersion = scp->dataVersion;
5166 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5168 /* otherwise, load the buffer and try again */
5169 lock_ReleaseMutex(&bufferp->mx);
5170 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5172 lock_ReleaseMutex(&scp->mx);
5173 lock_ObtainMutex(&bufferp->mx);
5174 lock_ObtainMutex(&scp->mx);
5178 lock_ReleaseMutex(&bufferp->mx);
5179 buf_Release(bufferp);
5183 } /* if (wrong buffer) ... */
5185 /* now we have the right buffer loaded. Copy out the
5186 * data from here to the user's buffer.
5188 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5190 /* and figure out how many bytes we want from this buffer */
5191 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5193 nbytes = count; /* don't go past end of request */
5195 /* now copy the data */
5198 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5201 memcpy(bufferp->datap + bufIndex, op, nbytes);
5202 buf_SetDirty(bufferp);
5204 /* and record the last writer */
5205 if (bufferp->userp != userp) {
5208 cm_ReleaseUser(bufferp->userp);
5209 bufferp->userp = userp;
5212 /* adjust counters, pointers, etc. */
5216 thyper.LowPart = nbytes;
5217 thyper.HighPart = 0;
5218 offset = LargeIntegerAdd(thyper, offset);
5222 lock_ReleaseMutex(&scp->mx);
5223 lock_ReleaseMutex(&fidp->mx);
5225 lock_ReleaseMutex(&bufferp->mx);
5226 buf_Release(bufferp);
5229 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5230 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5231 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5232 fidp->NTopen_dscp, fidp->NTopen_pathp,
5236 if (code == 0 && doWriteBack) {
5238 lock_ObtainMutex(&scp->mx);
5239 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5241 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5242 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5244 lock_ReleaseMutex(&scp->mx);
5245 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5246 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5249 osi_Log2(smb_logp, "smb_WriteData fid %d returns %d",
5254 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5257 long count, written = 0;
5262 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5264 int inDataBlockCount;
5266 fd = smb_GetSMBParm(inp, 0);
5267 count = smb_GetSMBParm(inp, 1);
5268 offset.HighPart = 0; /* too bad */
5269 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5271 op = smb_GetSMBData(inp, NULL);
5272 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5274 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5275 fd, offset.LowPart, count);
5277 fd = smb_ChainFID(fd, inp);
5278 fidp = smb_FindFID(vcp, fd, 0);
5280 return CM_ERROR_BADFD;
5283 if (fidp->flags & SMB_FID_IOCTL)
5284 return smb_IoctlWrite(fidp, vcp, inp, outp);
5286 userp = smb_GetUser(vcp, inp);
5288 /* special case: 0 bytes transferred means truncate to this position */
5294 truncAttr.mask = CM_ATTRMASK_LENGTH;
5295 truncAttr.length.LowPart = offset.LowPart;
5296 truncAttr.length.HighPart = 0;
5297 lock_ObtainMutex(&fidp->mx);
5298 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5299 lock_ReleaseMutex(&fidp->mx);
5300 smb_SetSMBParm(outp, 0, /* count */ 0);
5301 smb_SetSMBDataLength(outp, 0);
5302 fidp->flags |= SMB_FID_LENGTHSETDONE;
5307 * Work around bug in NT client
5309 * When copying a file, the NT client should first copy the data,
5310 * then copy the last write time. But sometimes the NT client does
5311 * these in the wrong order, so the data copies would inadvertently
5312 * cause the last write time to be overwritten. We try to detect this,
5313 * and don't set client mod time if we think that would go against the
5316 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5317 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5318 fidp->scp->clientModTime = time(NULL);
5322 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5324 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5326 if (code == 0 && written < count)
5327 code = CM_ERROR_PARTIALWRITE;
5329 /* set the packet data length to 3 bytes for the data block header,
5330 * plus the size of the data.
5332 smb_SetSMBParm(outp, 0, written);
5333 smb_SetSMBDataLength(outp, 0);
5336 smb_ReleaseFID(fidp);
5337 cm_ReleaseUser(userp);
5342 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5343 NCB *ncbp, raw_write_cont_t *rwcp)
5356 fd = smb_GetSMBParm(inp, 0);
5357 fidp = smb_FindFID(vcp, fd, 0);
5359 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5360 rwcp->offset.LowPart, rwcp->count);
5362 userp = smb_GetUser(vcp, inp);
5366 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5369 rawBuf = (dos_ptr) rwcp->buf;
5370 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5371 (unsigned char *) rawBuf, userp,
5375 if (rwcp->writeMode & 0x1) { /* synchronous */
5378 smb_FormatResponsePacket(vcp, inp, outp);
5379 op = (smb_t *) outp;
5380 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5381 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5382 smb_SetSMBDataLength(outp, 0);
5383 smb_SendPacket(vcp, outp);
5384 smb_FreePacket(outp);
5386 else { /* asynchronous */
5387 lock_ObtainMutex(&fidp->mx);
5388 fidp->raw_writers--;
5389 if (fidp->raw_writers == 0)
5390 thrd_SetEvent(fidp->raw_write_event);
5391 lock_ReleaseMutex(&fidp->mx);
5394 /* Give back raw buffer */
5395 lock_ObtainMutex(&smb_RawBufLock);
5397 *((char **)rawBuf) = smb_RawBufs;
5399 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5401 smb_RawBufs = rawBuf;
5402 lock_ReleaseMutex(&smb_RawBufLock);
5404 smb_ReleaseFID(fidp);
5405 cm_ReleaseUser(userp);
5408 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5413 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5416 long count, written = 0;
5423 unsigned short writeMode;
5430 fd = smb_GetSMBParm(inp, 0);
5431 totalCount = smb_GetSMBParm(inp, 1);
5432 count = smb_GetSMBParm(inp, 10);
5433 offset.HighPart = 0; /* too bad */
5434 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5435 writeMode = smb_GetSMBParm(inp, 7);
5437 op = (char *) inp->data;
5438 op += smb_GetSMBParm(inp, 11);
5441 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5442 fd, offset.LowPart, count, writeMode);
5444 fd = smb_ChainFID(fd, inp);
5445 fidp = smb_FindFID(vcp, fd, 0);
5447 return CM_ERROR_BADFD;
5450 userp = smb_GetUser(vcp, inp);
5453 * Work around bug in NT client
5455 * When copying a file, the NT client should first copy the data,
5456 * then copy the last write time. But sometimes the NT client does
5457 * these in the wrong order, so the data copies would inadvertently
5458 * cause the last write time to be overwritten. We try to detect this,
5459 * and don't set client mod time if we think that would go against the
5462 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5463 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5464 fidp->scp->clientModTime = time(NULL);
5468 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5470 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5472 if (code == 0 && written < count)
5473 code = CM_ERROR_PARTIALWRITE;
5475 /* Get a raw buffer */
5478 lock_ObtainMutex(&smb_RawBufLock);
5480 /* Get a raw buf, from head of list */
5481 rawBuf = smb_RawBufs;
5483 smb_RawBufs = *(char **)smb_RawBufs;
5485 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5489 code = CM_ERROR_USESTD;
5491 lock_ReleaseMutex(&smb_RawBufLock);
5494 /* Don't allow a premature Close */
5495 if (code == 0 && (writeMode & 1) == 0) {
5496 lock_ObtainMutex(&fidp->mx);
5497 fidp->raw_writers++;
5498 thrd_ResetEvent(fidp->raw_write_event);
5499 lock_ReleaseMutex(&fidp->mx);
5502 smb_ReleaseFID(fidp);
5503 cm_ReleaseUser(userp);
5506 smb_SetSMBParm(outp, 0, written);
5507 smb_SetSMBDataLength(outp, 0);
5508 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5515 rwcp->offset.HighPart = 0;
5516 rwcp->offset.LowPart = offset.LowPart + count;
5517 rwcp->count = totalCount - count;
5518 rwcp->writeMode = writeMode;
5519 rwcp->alreadyWritten = written;
5521 /* set the packet data length to 3 bytes for the data block header,
5522 * plus the size of the data.
5524 smb_SetSMBParm(outp, 0, 0xffff);
5525 smb_SetSMBDataLength(outp, 0);
5530 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5533 long count, finalCount;
5540 fd = smb_GetSMBParm(inp, 0);
5541 count = smb_GetSMBParm(inp, 1);
5542 offset.HighPart = 0; /* too bad */
5543 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5545 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5546 fd, offset.LowPart, count);
5548 fd = smb_ChainFID(fd, inp);
5549 fidp = smb_FindFID(vcp, fd, 0);
5551 return CM_ERROR_BADFD;
5554 if (fidp->flags & SMB_FID_IOCTL) {
5555 return smb_IoctlRead(fidp, vcp, inp, outp);
5558 userp = smb_GetUser(vcp, inp);
5560 /* remember this for final results */
5561 smb_SetSMBParm(outp, 0, count);
5562 smb_SetSMBParm(outp, 1, 0);
5563 smb_SetSMBParm(outp, 2, 0);
5564 smb_SetSMBParm(outp, 3, 0);
5565 smb_SetSMBParm(outp, 4, 0);
5567 /* set the packet data length to 3 bytes for the data block header,
5568 * plus the size of the data.
5570 smb_SetSMBDataLength(outp, count+3);
5572 /* get op ptr after putting in the parms, since otherwise we don't
5573 * know where the data really is.
5575 op = smb_GetSMBData(outp, NULL);
5577 /* now emit the data block header: 1 byte of type and 2 bytes of length */
5578 *op++ = 1; /* data block marker */
5579 *op++ = (unsigned char) (count & 0xff);
5580 *op++ = (unsigned char) ((count >> 8) & 0xff);
5583 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5585 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5588 /* fix some things up */
5589 smb_SetSMBParm(outp, 0, finalCount);
5590 smb_SetSMBDataLength(outp, finalCount+3);
5592 smb_ReleaseFID(fidp);
5594 cm_ReleaseUser(userp);
5598 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5605 cm_scache_t *dscp; /* dir we're dealing with */
5606 cm_scache_t *scp; /* file we're creating */
5608 int initialModeBits;
5618 /* compute initial mode bits based on read-only flag in attributes */
5619 initialModeBits = 0777;
5621 tp = smb_GetSMBData(inp, NULL);
5622 pathp = smb_ParseASCIIBlock(tp, &tp);
5624 if (strcmp(pathp, "\\") == 0)
5625 return CM_ERROR_EXISTS;
5627 spacep = inp->spacep;
5628 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5630 userp = smb_GetUser(vcp, inp);
5632 caseFold = CM_FLAG_CASEFOLD;
5634 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5636 cm_ReleaseUser(userp);
5637 return CM_ERROR_NOSUCHPATH;
5640 code = cm_NameI(cm_rootSCachep, spacep->data,
5641 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5642 userp, tidPathp, &req, &dscp);
5645 cm_ReleaseUser(userp);
5649 /* otherwise, scp points to the parent directory. Do a lookup, and
5650 * fail if we find it. Otherwise, we do the create.
5656 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5657 if (scp) cm_ReleaseSCache(scp);
5658 if (code != CM_ERROR_NOSUCHFILE) {
5659 if (code == 0) code = CM_ERROR_EXISTS;
5660 cm_ReleaseSCache(dscp);
5661 cm_ReleaseUser(userp);
5665 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5666 setAttr.clientModTime = time(NULL);
5667 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5668 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5669 smb_NotifyChange(FILE_ACTION_ADDED,
5670 FILE_NOTIFY_CHANGE_DIR_NAME,
5671 dscp, lastNamep, NULL, TRUE);
5673 /* we don't need this any longer */
5674 cm_ReleaseSCache(dscp);
5677 /* something went wrong creating or truncating the file */
5678 cm_ReleaseUser(userp);
5682 /* otherwise we succeeded */
5683 smb_SetSMBDataLength(outp, 0);
5684 cm_ReleaseUser(userp);
5689 BOOL smb_IsLegalFilename(char *filename)
5692 * Find the longest substring of filename that does not contain
5693 * any of the chars in illegalChars. If that substring is less
5694 * than the length of the whole string, then one or more of the
5695 * illegal chars is in filename.
5697 if (strcspn(filename, illegalChars) < strlen(filename))
5703 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5711 cm_scache_t *dscp; /* dir we're dealing with */
5712 cm_scache_t *scp; /* file we're creating */
5714 int initialModeBits;
5726 excl = (inp->inCom == 0x03)? 0 : 1;
5728 attributes = smb_GetSMBParm(inp, 0);
5729 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5731 /* compute initial mode bits based on read-only flag in attributes */
5732 initialModeBits = 0666;
5733 if (attributes & 1) initialModeBits &= ~0222;
5735 tp = smb_GetSMBData(inp, NULL);
5736 pathp = smb_ParseASCIIBlock(tp, &tp);
5738 spacep = inp->spacep;
5739 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5741 userp = smb_GetUser(vcp, inp);
5743 caseFold = CM_FLAG_CASEFOLD;
5745 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5747 cm_ReleaseUser(userp);
5748 return CM_ERROR_NOSUCHPATH;
5750 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5751 userp, tidPathp, &req, &dscp);
5754 cm_ReleaseUser(userp);
5758 /* otherwise, scp points to the parent directory. Do a lookup, and
5759 * truncate the file if we find it, otherwise we create the file.
5761 if (!lastNamep) lastNamep = pathp;
5764 if (!smb_IsLegalFilename(lastNamep))
5765 return CM_ERROR_BADNTFILENAME;
5767 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
5768 #ifdef DEBUG_VERBOSE
5771 hexp = osi_HexifyString( lastNamep );
5772 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5777 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5778 if (code && code != CM_ERROR_NOSUCHFILE) {
5779 cm_ReleaseSCache(dscp);
5780 cm_ReleaseUser(userp);
5784 /* if we get here, if code is 0, the file exists and is represented by
5785 * scp. Otherwise, we have to create it.
5789 /* oops, file shouldn't be there */
5790 cm_ReleaseSCache(dscp);
5791 cm_ReleaseSCache(scp);
5792 cm_ReleaseUser(userp);
5793 return CM_ERROR_EXISTS;
5796 setAttr.mask = CM_ATTRMASK_LENGTH;
5797 setAttr.length.LowPart = 0;
5798 setAttr.length.HighPart = 0;
5799 code = cm_SetAttr(scp, &setAttr, userp, &req);
5802 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5803 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5804 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5806 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5807 smb_NotifyChange(FILE_ACTION_ADDED,
5808 FILE_NOTIFY_CHANGE_FILE_NAME,
5809 dscp, lastNamep, NULL, TRUE);
5810 if (!excl && code == CM_ERROR_EXISTS) {
5811 /* not an exclusive create, and someone else tried
5812 * creating it already, then we open it anyway. We
5813 * don't bother retrying after this, since if this next
5814 * fails, that means that the file was deleted after
5815 * we started this call.
5817 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
5820 setAttr.mask = CM_ATTRMASK_LENGTH;
5821 setAttr.length.LowPart = 0;
5822 setAttr.length.HighPart = 0;
5823 code = cm_SetAttr(scp, &setAttr, userp, &req);
5828 /* we don't need this any longer */
5829 cm_ReleaseSCache(dscp);
5832 /* something went wrong creating or truncating the file */
5833 if (scp) cm_ReleaseSCache(scp);
5834 cm_ReleaseUser(userp);
5838 /* make sure we only open files */
5839 if (scp->fileType != CM_SCACHETYPE_FILE) {
5840 cm_ReleaseSCache(scp);
5841 cm_ReleaseUser(userp);
5842 return CM_ERROR_ISDIR;
5845 /* now all we have to do is open the file itself */
5846 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5849 /* save a pointer to the vnode */
5852 /* always create it open for read/write */
5853 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
5855 smb_ReleaseFID(fidp);
5857 smb_SetSMBParm(outp, 0, fidp->fid);
5858 smb_SetSMBDataLength(outp, 0);
5860 cm_Open(scp, 0, userp);
5862 cm_ReleaseUser(userp);
5863 /* leave scp held since we put it in fidp->scp */
5867 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5880 fd = smb_GetSMBParm(inp, 0);
5881 whence = smb_GetSMBParm(inp, 1);
5882 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5884 /* try to find the file descriptor */
5885 fd = smb_ChainFID(fd, inp);
5886 fidp = smb_FindFID(vcp, fd, 0);
5887 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5888 return CM_ERROR_BADFD;
5891 userp = smb_GetUser(vcp, inp);
5893 lock_ObtainMutex(&fidp->mx);
5895 lock_ObtainMutex(&scp->mx);
5896 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5897 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5900 /* offset from current offset */
5901 offset += fidp->offset;
5903 else if (whence == 2) {
5904 /* offset from current EOF */
5905 offset += scp->length.LowPart;
5907 fidp->offset = offset;
5908 smb_SetSMBParm(outp, 0, offset & 0xffff);
5909 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
5910 smb_SetSMBDataLength(outp, 0);
5912 lock_ReleaseMutex(&scp->mx);
5913 lock_ReleaseMutex(&fidp->mx);
5914 smb_ReleaseFID(fidp);
5915 cm_ReleaseUser(userp);
5919 /* dispatch all of the requests received in a packet. Due to chaining, this may
5920 * be more than one request.
5922 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5923 NCB *ncbp, raw_write_cont_t *rwcp)
5927 unsigned long code = 0;
5928 unsigned char *outWctp;
5929 int nparms; /* # of bytes of parameters */
5931 int nbytes; /* bytes of data, excluding count */
5934 unsigned short errCode;
5935 unsigned long NTStatus;
5937 unsigned char errClass;
5938 unsigned int oldGen;
5939 DWORD oldTime, newTime;
5941 /* get easy pointer to the data */
5942 smbp = (smb_t *) inp->data;
5944 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
5945 /* setup the basic parms for the initial request in the packet */
5946 inp->inCom = smbp->com;
5947 inp->wctp = &smbp->wct;
5949 inp->ncb_length = ncbp->ncb_length;
5954 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
5955 /* log it and discard it */
5960 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5961 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
5963 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
5964 1, ncbp->ncb_length, ptbuf, inp);
5965 DeregisterEventSource(h);
5967 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
5972 /* We are an ongoing op */
5973 thrd_Increment(&ongoingOps);
5975 /* set up response packet for receiving output */
5976 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
5977 smb_FormatResponsePacket(vcp, inp, outp);
5978 outWctp = outp->wctp;
5980 /* Remember session generation number and time */
5981 oldGen = sessionGen;
5982 oldTime = GetCurrentTime();
5984 while(inp->inCom != 0xff) {
5985 dp = &smb_dispatchTable[inp->inCom];
5987 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
5988 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
5989 code = outp->resumeCode;
5993 /* process each request in the packet; inCom, wctp and inCount
5994 * are already set up.
5996 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
5999 /* now do the dispatch */
6000 /* start by formatting the response record a little, as a default */
6001 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6003 outWctp[1] = 0xff; /* no operation */
6004 outWctp[2] = 0; /* padding */
6009 /* not a chained request, this is a more reasonable default */
6010 outWctp[0] = 0; /* wct of zero */
6011 outWctp[1] = 0; /* and bcc (word) of zero */
6015 /* once set, stays set. Doesn't matter, since we never chain
6016 * "no response" calls.
6018 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6022 /* we have a recognized operation */
6024 if (inp->inCom == 0x1d)
6026 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6029 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
6030 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
6031 code = (*(dp->procp)) (vcp, inp, outp);
6032 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6033 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6036 if (oldGen != sessionGen) {
6041 newTime = GetCurrentTime();
6042 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6043 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6044 newTime - oldTime, ncbp->ncb_length);
6046 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6047 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6048 DeregisterEventSource(h);
6050 osi_Log1(smb_logp, "Pkt straddled session startup, "
6051 "ncb length %d", ncbp->ncb_length);
6055 /* bad opcode, fail the request, after displaying it */
6058 #endif /* NOTSERVICE */
6062 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6063 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6064 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6065 if (code == IDCANCEL) showErrors = 0;
6068 code = CM_ERROR_BADOP;
6071 /* catastrophic failure: log as much as possible */
6072 if (code == CM_ERROR_BADSMB) {
6079 "Invalid SMB, ncb_length %d",
6082 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6083 sprintf(s, "Invalid SMB message, length %d",
6086 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6087 1, ncbp->ncb_length, ptbuf, smbp);
6088 DeregisterEventSource(h);
6091 #endif /* NOTSERVICE */
6093 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6096 code = CM_ERROR_INVAL;
6099 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6100 thrd_Decrement(&ongoingOps);
6105 /* now, if we failed, turn the current response into an empty
6106 * one, and fill in the response packet's error code.
6109 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6110 smb_MapNTError(code, &NTStatus);
6111 outWctp = outp->wctp;
6112 smbp = (smb_t *) &outp->data;
6113 if (code != CM_ERROR_PARTIALWRITE
6114 && code != CM_ERROR_BUFFERTOOSMALL
6115 && code != CM_ERROR_GSSCONTINUE) {
6116 /* nuke wct and bcc. For a partial
6117 * write or an in-process authentication handshake,
6118 * assume they're OK.
6124 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6125 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6126 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6127 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6128 smbp->flg2 |= 0x4000;
6132 smb_MapCoreError(code, vcp, &errCode, &errClass);
6133 outWctp = outp->wctp;
6134 smbp = (smb_t *) &outp->data;
6135 if (code != CM_ERROR_PARTIALWRITE) {
6136 /* nuke wct and bcc. For a partial
6137 * write, assume they're OK.
6143 smbp->errLow = (unsigned char) (errCode & 0xff);
6144 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6145 smbp->rcls = errClass;
6148 } /* error occurred */
6150 /* if we're here, we've finished one request. Look to see if
6151 * this is a chained opcode. If it is, setup things to process
6152 * the chained request, and setup the output buffer to hold the
6153 * chained response. Start by finding the next input record.
6155 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6156 break; /* not a chained req */
6157 tp = inp->wctp; /* points to start of last request */
6158 /* in a chained request, the first two
6159 * parm fields are required, and are
6160 * AndXCommand/AndXReserved and
6162 if (tp[0] < 2) break;
6163 if (tp[1] == 0xff) break; /* no more chained opcodes */
6165 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6168 /* and now append the next output request to the end of this
6169 * last request. Begin by finding out where the last response
6170 * ends, since that's where we'll put our new response.
6172 outWctp = outp->wctp; /* ptr to out parameters */
6173 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6174 nparms = outWctp[0] << 1;
6175 tp = outWctp + nparms + 1; /* now points to bcc field */
6176 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6177 tp += 2 /* for the count itself */ + nbytes;
6178 /* tp now points to the new output record; go back and patch the
6179 * second parameter (off2) to point to the new record.
6181 temp = (unsigned int)tp - ((unsigned int) outp->data);
6182 outWctp[3] = (unsigned char) (temp & 0xff);
6183 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6184 outWctp[2] = 0; /* padding */
6185 outWctp[1] = inp->inCom; /* next opcode */
6187 /* finally, setup for the next iteration */
6190 } /* while loop over all requests in the packet */
6192 /* done logging out, turn off logging-out flag */
6193 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6194 vcp->justLoggedOut = NULL;
6197 free(loggedOutName);
6198 loggedOutName = NULL;
6199 smb_ReleaseUID(loggedOutUserp);
6200 loggedOutUserp = NULL;
6204 /* now send the output packet, and return */
6206 smb_SendPacket(vcp, outp);
6207 thrd_Decrement(&ongoingOps);
6209 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6211 smb_ReleaseVC(active_vcp);
6213 "Replacing active_vcp %x with %x", active_vcp, vcp);
6217 last_msg_time = GetCurrentTime();
6219 else if (active_vcp == vcp) {
6220 smb_ReleaseVC(active_vcp);
6228 /* Wait for Netbios() calls to return, and make the results available to server
6229 * threads. Note that server threads can't wait on the NCBevents array
6230 * themselves, because NCB events are manual-reset, and the servers would race
6231 * each other to reset them.
6233 void smb_ClientWaiter(void *parmp)
6239 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6241 if (code == WAIT_OBJECT_0)
6244 /* error checking */
6245 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6247 int abandonIdx = code - WAIT_ABANDONED_0;
6248 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6251 if (code == WAIT_IO_COMPLETION)
6253 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6257 if (code == WAIT_TIMEOUT)
6259 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6262 if (code == WAIT_FAILED)
6264 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6267 idx = code - WAIT_OBJECT_0;
6269 /* check idx range! */
6270 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6272 /* this is fatal - log as much as possible */
6273 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6277 thrd_ResetEvent(NCBevents[idx]);
6278 thrd_SetEvent(NCBreturns[0][idx]);
6284 * Try to have one NCBRECV request waiting for every live session. Not more
6285 * than one, because if there is more than one, it's hard to handle Write Raw.
6287 void smb_ServerWaiter(void *parmp)
6290 int idx_session, idx_NCB;
6298 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6300 if (code == WAIT_OBJECT_0)
6303 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6305 int abandonIdx = code - WAIT_ABANDONED_0;
6306 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6309 if (code == WAIT_IO_COMPLETION)
6311 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6315 if (code == WAIT_TIMEOUT)
6317 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6320 if (code == WAIT_FAILED)
6322 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6325 idx_session = code - WAIT_OBJECT_0;
6327 /* check idx range! */
6328 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6330 /* this is fatal - log as much as possible */
6331 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6337 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6339 if (code == WAIT_OBJECT_0)
6342 /* error checking */
6343 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6345 int abandonIdx = code - WAIT_ABANDONED_0;
6346 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6349 if (code == WAIT_IO_COMPLETION)
6351 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6355 if (code == WAIT_TIMEOUT)
6357 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6360 if (code == WAIT_FAILED)
6362 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6365 idx_NCB = code - WAIT_OBJECT_0;
6367 /* check idx range! */
6368 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6370 /* this is fatal - log as much as possible */
6371 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6375 /* Link them together */
6376 NCBsessions[idx_NCB] = idx_session;
6379 ncbp = NCBs[idx_NCB];
6381 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6383 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6384 ncbp->ncb_command = NCBRECV | ASYNCH;
6385 ncbp->ncb_lana_num = lanas[idx_session];
6387 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6388 ncbp->ncb_event = NCBevents[idx_NCB];
6389 ncbp->ncb_length = SMB_PACKETSIZE;
6392 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6393 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6394 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6395 ncbp->ncb_length = SMB_PACKETSIZE;
6396 Netbios(ncbp, dos_ncb);
6402 * The top level loop for handling SMB request messages. Each server thread
6403 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6404 * NCB and buffer for the incoming request are loaned to us.
6406 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6407 * to immediately send a request for the rest of the data. This must come
6408 * before any other traffic for that session, so we delay setting the session
6409 * event until that data has come in.
6411 void smb_Server(VOID *parmp)
6413 int myIdx = (int) parmp;
6417 smb_packet_t *outbufp;
6419 int idx_NCB, idx_session;
6421 smb_vc_t *vcp = NULL;
6428 outbufp = GetPacket();
6429 outbufp->ncbp = outncbp;
6433 /* check for demo expiration */
6435 unsigned long tod = time((void *) 0);
6436 if (tod > EXPIREDATE) {
6437 (*smb_MBfunc)(NULL, "AFS demo expiration",
6439 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6443 #endif /* !NOEXPIRE */
6445 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6447 if (code == WAIT_OBJECT_0) {
6451 /* error checking */
6452 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6454 int abandonIdx = code - WAIT_ABANDONED_0;
6455 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6458 if (code == WAIT_IO_COMPLETION)
6460 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6464 if (code == WAIT_TIMEOUT)
6466 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6469 if (code == WAIT_FAILED)
6471 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6474 idx_NCB = code - WAIT_OBJECT_0;
6476 /* check idx range! */
6477 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6479 /* this is fatal - log as much as possible */
6480 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6484 ncbp = NCBs[idx_NCB];
6486 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6488 idx_session = NCBsessions[idx_NCB];
6489 rc = ncbp->ncb_retcode;
6491 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6492 osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6495 case NRC_GOODRET: break;
6498 /* Can this happen? Or is it just my
6505 /* Client closed session */
6506 if (reportSessionStartups)
6508 osi_Log1(smb_logp, "session [ %d ] closed", idx_session);
6510 dead_sessions[idx_session] = TRUE;
6513 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6514 /* Should also release vcp. [done] 2004-05-11 jaltman
6516 * sanity check that all TID's are gone.
6518 * TODO: check if we could use LSNs[idx_session] instead,
6519 * also cleanup after dead vcp
6524 "dead_vcp already set, %x",
6526 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6528 "setting dead_vcp %x, user struct %x",
6532 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6534 if (vcp->justLoggedOut) {
6536 loggedOutTime = vcp->logoffTime;
6538 strdup(vcp->justLoggedOut->unp->name);
6539 loggedOutUserp = vcp->justLoggedOut;
6540 lock_ObtainWrite(&smb_rctLock);
6541 loggedOutUserp->refCount++;
6542 lock_ReleaseWrite(&smb_rctLock);
6548 /* Treat as transient error */
6555 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6556 sprintf(s, "SMB message incomplete, length %d",
6559 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6561 ncbp->ncb_length, ptbuf,
6563 DeregisterEventSource(h);
6566 "dispatch smb recv failed, message incomplete, ncb_length %d",
6569 "SMB message incomplete, "
6570 "length %d", ncbp->ncb_length);
6573 * We used to discard the packet.
6574 * Instead, try handling it normally.
6582 /* A weird error code. Log it, sleep, and
6584 if (vcp && vcp->errorCount++ > 3) {
6585 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6586 dead_sessions[idx_session] = TRUE;
6590 thrd_SetEvent(SessionEvents[idx_session]);
6595 /* Success, so now dispatch on all the data in the packet */
6597 smb_concurrentCalls++;
6598 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6599 smb_maxObsConcurrentCalls = smb_concurrentCalls;
6603 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6605 * If at this point vcp is NULL (implies that packet was invalid)
6606 * then we are in big trouble. This means either :
6607 * a) we have the wrong NCB.
6608 * b) Netbios screwed up the call.
6609 * Obviously this implies that
6610 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
6611 * lanas[idx_session] != ncbp->ncb_lana_num )
6612 * Either way, we can't do anything with this packet.
6613 * Log, sleep and resume.
6622 "LSNs[idx_session]=[%d],"
6623 "lanas[idx_session]=[%d],"
6624 "ncbp->ncb_lsn=[%d],"
6625 "ncbp->ncb_lana_num=[%d]",
6629 ncbp->ncb_lana_num);
6633 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6635 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6636 DeregisterEventSource(h);
6639 /* Also log in the trace log. */
6640 osi_Log4(smb_logp, "Server: BAD VCP!"
6641 "LSNs[idx_session]=[%d],"
6642 "lanas[idx_session]=[%d],"
6643 "ncbp->ncb_lsn=[%d],"
6644 "ncbp->ncb_lana_num=[%d]",
6648 ncbp->ncb_lana_num);
6650 /* thrd_Sleep(1000); Don't bother sleeping */
6651 thrd_SetEvent(SessionEvents[idx_session]);
6652 smb_concurrentCalls--;
6657 vcp->errorCount = 0;
6658 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6660 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6661 /* copy whole packet to virtual memory */
6662 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6664 bufp->dos_pkt / 16, bufp);*/
6666 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6668 smbp = (smb_t *)bufp->data;
6671 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6675 if (smbp->com == 0x1d) {
6676 /* Special handling for Write Raw */
6677 raw_write_cont_t rwc;
6678 EVENT_HANDLE rwevent;
6679 char eventName[MAX_PATH];
6681 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6682 if (rwc.code == 0) {
6683 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6684 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6685 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6686 ncbp->ncb_command = NCBRECV | ASYNCH;
6687 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6688 ncbp->ncb_lana_num = vcp->lana;
6689 ncbp->ncb_buffer = rwc.buf;
6690 ncbp->ncb_length = 65535;
6691 ncbp->ncb_event = rwevent;
6695 Netbios(ncbp, dos_ncb);
6697 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6698 thrd_CloseHandle(rwevent);
6700 thrd_SetEvent(SessionEvents[idx_session]);
6702 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6703 } else if (smbp->com == 0xa0) {
6705 * Serialize the handling for NT Transact
6708 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6709 thrd_SetEvent(SessionEvents[idx_session]);
6711 thrd_SetEvent(SessionEvents[idx_session]);
6712 /* TODO: what else needs to be serialized? */
6713 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6715 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6717 __except( smb_ServerExceptionFilter() ) {
6721 smb_concurrentCalls--;
6724 thrd_SetEvent(NCBavails[idx_NCB]);
6731 * Exception filter for the server threads. If an exception occurs in the
6732 * dispatch routines, which is where exceptions are most common, then do a
6733 * force trace and give control to upstream exception handlers. Useful for
6736 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6737 DWORD smb_ServerExceptionFilter(void) {
6738 /* While this is not the best time to do a trace, if it succeeds, then
6739 * we have a trace (assuming tracing was enabled). Otherwise, this should
6740 * throw a second exception.
6745 ptbuf[0] = "Unhandled exception forcing trace";
6747 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6749 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6750 DeregisterEventSource(h);
6753 afsd_ForceTrace(TRUE);
6754 return EXCEPTION_CONTINUE_SEARCH;
6759 * Create a new NCB and associated events, packet buffer, and "space" buffer.
6760 * If the number of server threads is M, and the number of live sessions is
6761 * N, then the number of NCB's in use at any time either waiting for, or
6762 * holding, received messages is M + N, so that is how many NCB's get created.
6764 void InitNCBslot(int idx)
6766 struct smb_packet *bufp;
6767 EVENT_HANDLE retHandle;
6769 char eventName[MAX_PATH];
6771 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
6773 NCBs[idx] = GetNCB();
6774 sprintf(eventName,"NCBavails[%d]", idx);
6775 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6776 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6777 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6779 sprintf(eventName,"NCBevents[%d]", idx);
6780 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
6781 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6782 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6784 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
6785 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6786 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6787 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6788 for (i=0; i<smb_NumServerThreads; i++)
6789 NCBreturns[i][idx] = retHandle;
6791 bufp->spacep = cm_GetSpace();
6795 /* listen for new connections */
6796 void smb_Listener(void *parmp)
6804 char rname[NCBNAMSZ+1];
6805 char cname[MAX_COMPUTERNAME_LENGTH+1];
6806 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
6811 int lana = (int) parmp;
6815 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6818 /* retrieve computer name */
6819 GetComputerName(cname, &cnamelen);
6823 memset(ncbp, 0, sizeof(NCB));
6827 /* check for demo expiration */
6829 unsigned long tod = time((void *) 0);
6830 if (tod > EXPIREDATE) {
6831 (*smb_MBfunc)(NULL, "AFS demo expiration",
6833 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6841 #endif /* !NOEXPIRE */
6843 ncbp->ncb_command = NCBLISTEN;
6844 ncbp->ncb_rto = 0; /* No receive timeout */
6845 ncbp->ncb_sto = 0; /* No send timeout */
6847 /* pad out with spaces instead of null termination */
6848 len = strlen(smb_localNamep);
6849 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
6850 for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
6852 strcpy(ncbp->ncb_callname, "*");
6853 for(i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
6855 ncbp->ncb_lana_num = lana;
6858 code = Netbios(ncbp);
6860 code = Netbios(ncbp, dos_ncb);
6869 /* terminate silently if shutdown flag is set */
6870 if (smbShutdownFlag == 1) {
6879 "NCBLISTEN lana=%d failed with code %d",
6880 ncbp->ncb_lana_num, code);
6882 "Client exiting due to network failure. Please restart client.\n");
6886 "Client exiting due to network failure. Please restart client.\n"
6887 "NCBLISTEN lana=%d failed with code %d",
6888 ncbp->ncb_lana_num, code);
6890 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
6891 MB_OK|MB_SERVICE_NOTIFICATION);
6892 osi_assert(tbuffer);
6895 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
6896 ncbp->ncb_lana_num, code);
6897 fprintf(stderr, "\nClient exiting due to network failure "
6898 "(possibly due to power-saving mode)\n");
6899 fprintf(stderr, "Please restart client.\n");
6900 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
6904 /* check for remote conns */
6905 /* first get remote name and insert null terminator */
6906 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
6907 for (i=NCBNAMSZ; i>0; i--) {
6908 if (rname[i-1] != ' ' && rname[i-1] != 0) {
6914 /* compare with local name */
6916 if (strncmp(rname, cname, NCBNAMSZ) != 0)
6917 flags |= SMB_VCFLAG_REMOTECONN;
6919 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
6921 lock_ObtainMutex(&smb_ListenerLock);
6923 /* New generation */
6926 /* Log session startup */
6928 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
6930 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
6932 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
6933 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
6935 if (reportSessionStartups) {
6941 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6942 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
6944 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
6946 DeregisterEventSource(h);
6949 fprintf(stderr, "%s: New session %d starting from host %s\n",
6950 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
6954 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
6955 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
6958 /* now ncbp->ncb_lsn is the connection ID */
6959 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
6960 vcp->flags |= flags;
6961 strcpy(vcp->rname, rname);
6963 /* Allocate slot in session arrays */
6964 /* Re-use dead session if possible, otherwise add one more */
6965 /* But don't look at session[0], it is reserved */
6966 for (i = 1; i < numSessions; i++) {
6967 if (dead_sessions[i]) {
6968 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
6969 dead_sessions[i] = FALSE;
6974 /* assert that we do not exceed the maximum number of sessions or NCBs.
6975 * we should probably want to wait for a session to be freed in case
6979 osi_assert(i < Sessionmax - 1);
6980 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
6982 LSNs[i] = ncbp->ncb_lsn;
6983 lanas[i] = ncbp->ncb_lana_num;
6985 if (i == numSessions) {
6986 /* Add new NCB for new session */
6987 char eventName[MAX_PATH];
6989 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
6991 InitNCBslot(numNCBs);
6993 thrd_SetEvent(NCBavails[0]);
6994 thrd_SetEvent(NCBevents[0]);
6995 for (j = 0; j < smb_NumServerThreads; j++)
6996 thrd_SetEvent(NCBreturns[j][0]);
6997 /* Also add new session event */
6998 sprintf(eventName, "SessionEvents[%d]", i);
6999 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7000 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7001 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7003 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7004 thrd_SetEvent(SessionEvents[0]);
7006 thrd_SetEvent(SessionEvents[i]);
7009 lock_ReleaseMutex(&smb_ListenerLock);
7011 } /* dispatch while loop */
7014 /* initialize Netbios */
7015 void smb_NetbiosInit()
7021 int i, lana, code, l;
7023 int delname_tried=0;
7026 OSVERSIONINFO Version;
7028 /* AFAIK, this is the default for the ms loopback adapter.*/
7029 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
7030 /*******************************************************************/
7032 /* Get the version of Windows */
7033 memset(&Version, 0x00, sizeof(Version));
7034 Version.dwOSVersionInfoSize = sizeof(Version);
7035 GetVersionEx(&Version);
7037 /* setup the NCB system */
7040 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7044 if (smb_LANadapter == -1) {
7045 ncbp->ncb_command = NCBENUM;
7046 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7047 ncbp->ncb_length = sizeof(lana_list);
7048 code = Netbios(ncbp);
7050 sprintf(s, "Netbios NCBENUM error code %d", code);
7051 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7052 osi_panic(s, __FILE__, __LINE__);
7056 lana_list.length = 1;
7057 lana_list.lana[0] = smb_LANadapter;
7060 for (i = 0; i < lana_list.length; i++) {
7061 /* reset the adaptor: in Win32, this is required for every process, and
7062 * acts as an init call, not as a real hardware reset.
7064 ncbp->ncb_command = NCBRESET;
7065 ncbp->ncb_callname[0] = 100;
7066 ncbp->ncb_callname[2] = 100;
7067 ncbp->ncb_lana_num = lana_list.lana[i];
7068 code = Netbios(ncbp);
7070 code = ncbp->ncb_retcode;
7072 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7073 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7074 lana_list.lana[i] = 255; /* invalid lana */
7076 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7077 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7081 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7082 we will just fake the LANA list */
7083 if (smb_LANadapter == -1) {
7084 for (i = 0; i < 8; i++)
7085 lana_list.lana[i] = i;
7086 lana_list.length = 8;
7089 lana_list.length = 1;
7090 lana_list.lana[0] = smb_LANadapter;
7094 /* and declare our name so we can receive connections */
7095 memset(ncbp, 0, sizeof(*ncbp));
7096 len=lstrlen(smb_localNamep);
7097 memset(smb_sharename,' ',NCBNAMSZ);
7098 memcpy(smb_sharename,smb_localNamep,len);
7099 sprintf(s, "lana_list.length %d", lana_list.length);
7100 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7102 /* Keep the name so we can unregister it later */
7103 for (l = 0; l < lana_list.length; l++) {
7104 lana = lana_list.lana[l];
7106 ncbp->ncb_command = NCBADDNAME;
7107 ncbp->ncb_lana_num = lana;
7108 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7110 code = Netbios(ncbp);
7112 code = Netbios(ncbp, dos_ncb);
7115 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7116 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7118 char name[NCBNAMSZ+1];
7120 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7121 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7124 if (code == 0) code = ncbp->ncb_retcode;
7126 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7128 /* we only use one LANA with djgpp */
7129 lana_list.lana[0] = lana;
7130 lana_list.length = 1;
7134 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7135 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7136 if (code == NRC_BRIDGE) { /* invalid LANA num */
7137 lana_list.lana[l] = 255;
7140 else if (code == NRC_DUPNAME) {
7141 osi_Log0(smb_logp, "Name already exists; try to delete it");
7142 memset(ncbp, 0, sizeof(*ncbp));
7143 ncbp->ncb_command = NCBDELNAME;
7144 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7145 ncbp->ncb_lana_num = lana;
7147 code = Netbios(ncbp);
7149 code = Netbios(ncbp, dos_ncb);
7151 if (code == 0) code = ncbp->ncb_retcode;
7153 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7154 osi_Log0(smb_logp, s);
7156 if (code != 0 || delname_tried) {
7157 lana_list.lana[l] = 255;
7159 else if (code == 0) {
7160 if (!delname_tried) {
7168 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7169 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7170 lana_list.lana[l] = 255; /* invalid lana */
7171 osi_panic(s, __FILE__, __LINE__);
7175 lana_found = 1; /* at least one worked */
7182 osi_assert(lana_list.length >= 0);
7184 sprintf(s, "No valid LANA numbers found!");
7185 osi_panic(s, __FILE__, __LINE__);
7188 /* we're done with the NCB now */
7192 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7209 EVENT_HANDLE retHandle;
7210 char eventName[MAX_PATH];
7213 smb_MBfunc = aMBfunc;
7217 /* check for demo expiration */
7219 unsigned long tod = time((void *) 0);
7220 if (tod > EXPIREDATE) {
7222 (*smb_MBfunc)(NULL, "AFS demo expiration", "afsd",
7223 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
7226 fprintf(stderr, "AFS demo expiration\n");
7231 #endif /* !NOEXPIRE */
7234 smb_LANadapter = LANadapt;
7236 /* Initialize smb_localZero */
7237 myTime.tm_isdst = -1; /* compute whether on DST or not */
7238 myTime.tm_year = 70;
7244 smb_localZero = mktime(&myTime);
7246 /* Initialize kludge-GMT */
7247 smb_CalculateNowTZ();
7249 #ifdef AFS_FREELANCE_CLIENT
7250 /* Make sure the root.afs volume has the correct time */
7251 cm_noteLocalMountPointChange();
7254 /* initialize the remote debugging log */
7257 /* remember the name */
7258 len = strlen(snamep);
7259 smb_localNamep = malloc(len+1);
7260 strcpy(smb_localNamep, snamep);
7261 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7263 /* and the global lock */
7264 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7265 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7267 /* Raw I/O data structures */
7268 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7270 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7272 /* 4 Raw I/O buffers */
7274 smb_RawBufs = calloc(65536,1);
7275 *((char **)smb_RawBufs) = NULL;
7276 for (i=0; i<3; i++) {
7277 char *rawBuf = calloc(65536,1);
7278 *((char **)rawBuf) = smb_RawBufs;
7279 smb_RawBufs = rawBuf;
7282 npar = 65536 >> 4; /* number of paragraphs */
7283 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7285 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7287 osi_panic("",__FILE__,__LINE__);
7290 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7293 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7295 _farpokel(_dos_ds, smb_RawBufs, NULL);
7296 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7297 npar = 65536 >> 4; /* number of paragraphs */
7298 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7300 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7302 osi_panic("",__FILE__,__LINE__);
7305 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7308 rawBuf = (seg * 16) + 0; /* DOS physical address */
7309 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7310 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7311 smb_RawBufs = rawBuf;
7315 /* global free lists */
7316 smb_ncbFreeListp = NULL;
7317 smb_packetFreeListp = NULL;
7321 /* Initialize listener and server structures */
7323 memset(dead_sessions, 0, sizeof(dead_sessions));
7324 sprintf(eventName, "SessionEvents[0]");
7325 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7326 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7327 afsi_log("Event Object Already Exists: %s", eventName);
7329 smb_NumServerThreads = nThreads;
7330 sprintf(eventName, "NCBavails[0]");
7331 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7332 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7333 afsi_log("Event Object Already Exists: %s", eventName);
7334 sprintf(eventName, "NCBevents[0]");
7335 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7336 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7337 afsi_log("Event Object Already Exists: %s", eventName);
7338 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7339 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7340 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7341 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7342 afsi_log("Event Object Already Exists: %s", eventName);
7343 for (i = 0; i < smb_NumServerThreads; i++) {
7344 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7345 NCBreturns[i][0] = retHandle;
7347 for (i = 1; i <= nThreads; i++)
7349 numNCBs = nThreads + 1;
7351 /* Initialize dispatch table */
7352 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7353 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7354 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7355 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7356 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7357 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7358 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7359 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7360 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7361 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7362 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7363 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7364 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7365 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7366 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7367 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7368 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7369 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7370 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7371 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7372 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7373 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7374 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7375 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7376 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7377 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7378 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7379 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7380 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7381 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7382 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7383 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7384 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7385 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7386 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7387 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7388 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7389 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7390 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7391 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7392 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7393 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7394 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7395 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7396 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7397 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7398 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7399 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7400 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7401 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7402 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7403 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7404 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7405 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7406 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7407 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7408 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7409 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7410 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7411 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7412 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7413 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7414 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;
7415 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;
7416 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;
7417 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;
7418 for(i=0xd0; i<= 0xd7; i++) {
7419 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7422 /* setup tran 2 dispatch table */
7423 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7424 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7425 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7426 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7427 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7428 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7429 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7430 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7431 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7432 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7433 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7434 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7435 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7436 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2MKDir;
7438 /* setup the rap dispatch table */
7439 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
7440 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
7441 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
7442 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
7443 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
7447 /* if we are doing SMB authentication we have register outselves as a logon process */
7448 if (smb_authType != SMB_AUTH_NONE) {
7450 LSA_STRING afsProcessName;
7451 LSA_OPERATIONAL_MODE dummy; /*junk*/
7453 afsProcessName.Buffer = "OpenAFSClientDaemon";
7454 afsProcessName.Length = strlen(afsProcessName.Buffer);
7455 afsProcessName.MaximumLength = afsProcessName.Length + 1;
7457 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
7459 if (nts == STATUS_SUCCESS) {
7460 LSA_STRING packageName;
7461 /* we are registered. Find out the security package id */
7462 packageName.Buffer = MSV1_0_PACKAGE_NAME;
7463 packageName.Length = strlen(packageName.Buffer);
7464 packageName.MaximumLength = packageName.Length + 1;
7465 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
7466 if (nts == STATUS_SUCCESS) {
7467 smb_lsaLogonOrigin.Buffer = "OpenAFS";
7468 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
7469 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
7471 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
7474 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
7477 if (nts != STATUS_SUCCESS) {
7478 /* something went wrong. We report the error and revert back to no authentication
7479 because we can't perform any auth requests without a successful lsa handle
7480 or sec package id. */
7481 afsi_log("Reverting to NO SMB AUTH");
7482 smb_authType = SMB_AUTH_NONE;
7485 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
7486 * time prevents the failure of authentication when logged into Windows with an
7487 * external Kerberos principal mapped to a local account.
7489 else if ( smb_authType == SMB_AUTH_EXTENDED) {
7490 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
7491 * then the only option is NTLMSSP anyway; so just fallback.
7496 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
7497 if (secBlobLength == 0) {
7498 smb_authType = SMB_AUTH_NTLM;
7499 afsi_log("Reverting to SMB AUTH NTLM");
7508 /* Now get ourselves a domain name. */
7509 /* For now we are using the local computer name as the domain name.
7510 * It is actually the domain for local logins, and we are acting as
7511 * a local SMB server.
7513 bufsize = sizeof(smb_ServerDomainName) - 1;
7514 GetComputerName(smb_ServerDomainName, &bufsize);
7515 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
7516 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
7519 /* Start listeners, waiters, servers, and daemons */
7521 for (i = 0; i < lana_list.length; i++) {
7522 if (lana_list.lana[i] == 255) continue;
7523 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7524 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7525 osi_assert(phandle != NULL);
7526 thrd_CloseHandle(phandle);
7530 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7531 NULL, 0, &lpid, "smb_ClientWaiter");
7532 osi_assert(phandle != NULL);
7533 thrd_CloseHandle(phandle);
7536 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7537 NULL, 0, &lpid, "smb_ServerWaiter");
7538 osi_assert(phandle != NULL);
7539 thrd_CloseHandle(phandle);
7541 for (i=0; i<nThreads; i++) {
7542 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7543 (void *) i, 0, &lpid, "smb_Server");
7544 osi_assert(phandle != NULL);
7545 thrd_CloseHandle(phandle);
7548 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7549 NULL, 0, &lpid, "smb_Daemon");
7550 osi_assert(phandle != NULL);
7551 thrd_CloseHandle(phandle);
7553 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7554 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7555 osi_assert(phandle != NULL);
7556 thrd_CloseHandle(phandle);
7565 void smb_Shutdown(void)
7574 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7576 /* setup the NCB system */
7579 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7582 /* Block new sessions by setting shutdown flag */
7583 smbShutdownFlag = 1;
7585 /* Hang up all sessions */
7586 memset((char *)ncbp, 0, sizeof(NCB));
7587 for (i = 1; i < numSessions; i++)
7589 if (dead_sessions[i])
7592 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7593 ncbp->ncb_command = NCBHANGUP;
7594 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
7595 ncbp->ncb_lsn = LSNs[i];
7597 code = Netbios(ncbp);
7599 code = Netbios(ncbp, dos_ncb);
7601 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7602 if (code == 0) code = ncbp->ncb_retcode;
7604 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7605 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7609 /* Delete Netbios name */
7610 memset((char *)ncbp, 0, sizeof(NCB));
7611 for (i = 0; i < lana_list.length; i++) {
7612 if (lana_list.lana[i] == 255) continue;
7613 ncbp->ncb_command = NCBDELNAME;
7614 ncbp->ncb_lana_num = lana_list.lana[i];
7615 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7617 code = Netbios(ncbp);
7619 code = Netbios(ncbp, dos_ncb);
7621 if (code == 0) code = ncbp->ncb_retcode;
7623 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7624 ncbp->ncb_lana_num, code);
7630 /* Get the UNC \\<servername>\<sharename> prefix. */
7631 char *smb_GetSharename()
7635 /* Make sure we have been properly initialized. */
7636 if (smb_localNamep == NULL)
7639 /* Allocate space for \\<servername>\<sharename>, plus the
7642 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7643 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7649 void smb_LogPacket(smb_packet_t *packet)
7652 unsigned length, paramlen, datalen, i, j;
7654 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7658 osi_Log0(smb_logp, "*** SMB packet dump ***");
7660 vp = (BYTE *) packet->data;
7662 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7663 length = paramlen + 2 + datalen;
7666 for(i=0;i < length; i+=16)
7668 memset( buf, ' ', 80 );
7673 buf[strlen(buf)] = ' ';
7675 cp = (BYTE*) buf + 7;
7677 for(j=0;j < 16 && (i+j)<length; j++)
7679 *(cp++) = hex[vp[i+j] >> 4];
7680 *(cp++) = hex[vp[i+j] & 0xf];
7690 for(j=0;j < 16 && (i+j)<length;j++)
7692 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7703 osi_Log0( smb_logp, buf );
7706 osi_Log0(smb_logp, "*** End SMB packet dump ***");
7710 #endif /* NOTSERVICE */
7712 int smb_DumpVCP(FILE *outputFile, char *cookie)
7719 lock_ObtainRead(&smb_rctLock);
7721 sprintf(output, "begin dumping vcpsp\n");
7722 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7724 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
7728 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7729 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7730 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7732 sprintf(output, "begin dumping fidsp\n");
7733 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7735 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
7737 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",
7738 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
7739 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
7740 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7741 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7744 sprintf(output, "done dumping fidsp\n");
7745 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7748 sprintf(output, "done dumping vcpsp\n");
7749 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7751 lock_ReleaseRead(&smb_rctLock);