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;
48 int smbShutdownFlag = 0;
50 int smb_LogoffTokenTransfer;
51 time_t 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, time_t 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, time_t unixTime)
591 time_t 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, time_t 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(time_t *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(time_t *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, time_t unixTime)
700 ltp = localtime((time_t*) &t);
702 /* if we fail, make up something */
705 localJunk.tm_year = 89 - 20;
706 localJunk.tm_mon = 4;
707 localJunk.tm_mday = 12;
708 localJunk.tm_hour = 0;
709 localJunk.tm_min = 0;
710 localJunk.tm_sec = 0;
713 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
714 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
715 *dosTimep = (dosDate<<16) | dosTime;
718 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
720 unsigned short dosDate;
721 unsigned short dosTime;
724 dosDate = searchTime & 0xffff;
725 dosTime = (searchTime >> 16) & 0xffff;
727 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
728 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
729 localTm.tm_mday = (dosDate) & 0x1f;
730 localTm.tm_hour = (dosTime>>11) & 0x1f;
731 localTm.tm_min = (dosTime >> 5) & 0x3f;
732 localTm.tm_sec = (dosTime & 0x1f) * 2;
733 localTm.tm_isdst = -1; /* compute whether DST in effect */
735 *unixTimep = mktime(&localTm);
738 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
740 *dosUTimep = unixTime - smb_localZero;
743 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
746 *unixTimep = dosTime + smb_localZero;
748 /* dosTime seems to be already adjusted for GMT */
749 *unixTimep = dosTime;
753 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
757 lock_ObtainWrite(&smb_rctLock);
758 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
759 if (lsn == vcp->lsn && lana == vcp->lana) {
764 if (!vcp && (flags & SMB_FLAG_CREATE)) {
765 vcp = malloc(sizeof(*vcp));
766 memset(vcp, 0, sizeof(*vcp));
767 vcp->vcID = numVCs++;
771 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
772 vcp->nextp = smb_allVCsp;
774 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
779 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
780 /* We must obtain a challenge for extended auth
781 * in case the client negotiates smb v3
784 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
785 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
788 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
790 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
797 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
799 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
800 LsaFreeReturnBuffer(lsaResp);
803 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
805 lock_ReleaseWrite(&smb_rctLock);
809 int smb_IsStarMask(char *maskp)
814 for(i=0; i<11; i++) {
816 if (tc == '?' || tc == '*' || tc == '>') return 1;
821 void smb_ReleaseVC(smb_vc_t *vcp)
823 lock_ObtainWrite(&smb_rctLock);
824 osi_assert(vcp->refCount-- > 0);
825 lock_ReleaseWrite(&smb_rctLock);
828 void smb_HoldVC(smb_vc_t *vcp)
830 lock_ObtainWrite(&smb_rctLock);
832 lock_ReleaseWrite(&smb_rctLock);
835 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
839 lock_ObtainWrite(&smb_rctLock);
840 for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
841 if (tid == tidp->tid) {
846 if (!tidp && (flags & SMB_FLAG_CREATE)) {
847 tidp = malloc(sizeof(*tidp));
848 memset(tidp, 0, sizeof(*tidp));
849 tidp->nextp = vcp->tidsp;
854 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
857 lock_ReleaseWrite(&smb_rctLock);
861 void smb_ReleaseTID(smb_tid_t *tidp)
870 lock_ObtainWrite(&smb_rctLock);
871 osi_assert(tidp->refCount-- > 0);
872 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
873 ltpp = &tidp->vcp->tidsp;
874 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
875 if (tp == tidp) break;
877 osi_assert(tp != NULL);
879 lock_FinalizeMutex(&tidp->mx);
880 userp = tidp->userp; /* remember to drop ref later */
883 lock_ReleaseWrite(&smb_rctLock);
885 cm_ReleaseUser(userp);
892 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
894 smb_user_t *uidp = NULL;
896 lock_ObtainWrite(&smb_rctLock);
897 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
898 if (uid == uidp->userID) {
900 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
901 (int)vcp, uidp->userID,
902 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
906 if (!uidp && (flags & SMB_FLAG_CREATE)) {
907 uidp = malloc(sizeof(*uidp));
908 memset(uidp, 0, sizeof(*uidp));
909 uidp->nextp = vcp->usersp;
914 lock_InitializeMutex(&uidp->mx, "user_t mutex");
916 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 : ""));
918 lock_ReleaseWrite(&smb_rctLock);
922 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
924 smb_username_t *unp= NULL;
926 lock_ObtainWrite(&smb_rctLock);
927 for(unp = usernamesp; unp; unp = unp->nextp) {
928 if (stricmp(unp->name, usern) == 0 &&
929 stricmp(unp->machine, machine) == 0) {
934 if (!unp && (flags & SMB_FLAG_CREATE)) {
935 unp = malloc(sizeof(*unp));
936 memset(unp, 0, sizeof(*unp));
938 unp->nextp = usernamesp;
939 unp->name = strdup(usern);
940 unp->machine = strdup(machine);
942 lock_InitializeMutex(&unp->mx, "username_t mutex");
944 lock_ReleaseWrite(&smb_rctLock);
948 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
950 smb_user_t *uidp= NULL;
952 lock_ObtainWrite(&smb_rctLock);
953 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
956 if (stricmp(uidp->unp->name, usern) == 0) {
958 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
963 lock_ReleaseWrite(&smb_rctLock);
966 void smb_ReleaseUID(smb_user_t *uidp)
975 lock_ObtainWrite(&smb_rctLock);
976 osi_assert(uidp->refCount-- > 0);
977 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
978 lupp = &uidp->vcp->usersp;
979 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
980 if (up == uidp) break;
982 osi_assert(up != NULL);
984 lock_FinalizeMutex(&uidp->mx);
986 userp = uidp->unp->userp; /* remember to drop ref later */
987 uidp->unp->userp = NULL;
992 lock_ReleaseWrite(&smb_rctLock);
994 cm_ReleaseUserVCRef(userp);
995 cm_ReleaseUser(userp);
1002 /* retrieve a held reference to a user structure corresponding to an incoming
1004 * corresponding release function is cm_ReleaseUser.
1006 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1012 smbp = (smb_t *) inp;
1013 uidp = smb_FindUID(vcp, smbp->uid, 0);
1014 if ((!uidp) || (!uidp->unp))
1017 lock_ObtainMutex(&uidp->mx);
1018 up = uidp->unp->userp;
1020 lock_ReleaseMutex(&uidp->mx);
1022 smb_ReleaseUID(uidp);
1028 * Return a pointer to a pathname extracted from a TID structure. The
1029 * TID structure is not held; assume it won't go away.
1031 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1036 tidp = smb_FindTID(vcp, tid, 0);
1040 if(tidp->flags & SMB_TIDFLAG_IPC) {
1041 code = CM_ERROR_TIDIPC;
1042 /* tidp->pathname would be NULL, but that's fine */
1044 *treepath = tidp->pathname;
1045 smb_ReleaseTID(tidp);
1050 /* check to see if we have a chained fid, that is, a fid that comes from an
1051 * OpenAndX message that ran earlier in this packet. In this case, the fid
1052 * field in a read, for example, request, isn't set, since the value is
1053 * supposed to be inherited from the openAndX call.
1055 int smb_ChainFID(int fid, smb_packet_t *inp)
1057 if (inp->fid == 0 || inp->inCount == 0)
1063 /* are we a priv'd user? What does this mean on NT? */
1064 int smb_SUser(cm_user_t *userp)
1069 /* find a file ID. If we pass in 0 we select an used File ID.
1070 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1071 * smb_fid_t data structure if desired File ID cannot be found.
1073 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1078 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1081 lock_ObtainWrite(&smb_rctLock);
1082 /* figure out if we need to allocate a new file ID */
1085 fid = vcp->fidCounter;
1089 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1090 if (fid == fidp->fid) {
1101 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1102 char eventName[MAX_PATH];
1104 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1105 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1106 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1107 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1108 thrd_CloseHandle(event);
1115 fidp = malloc(sizeof(*fidp));
1116 memset(fidp, 0, sizeof(*fidp));
1117 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1121 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1123 fidp->curr_chunk = fidp->prev_chunk = -2;
1124 fidp->raw_write_event = event;
1126 vcp->fidCounter = fid+1;
1127 if (vcp->fidCounter == 0)
1128 vcp->fidCounter = 1;
1131 lock_ReleaseWrite(&smb_rctLock);
1135 void smb_ReleaseFID(smb_fid_t *fidp)
1138 smb_vc_t *vcp = NULL;
1139 smb_ioctl_t *ioctlp;
1145 lock_ObtainWrite(&smb_rctLock);
1146 osi_assert(fidp->refCount-- > 0);
1147 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1149 if (!(fidp->flags & SMB_FID_IOCTL))
1151 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1152 thrd_CloseHandle(fidp->raw_write_event);
1154 /* and see if there is ioctl stuff to free */
1155 ioctlp = fidp->ioctlp;
1157 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1158 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1159 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1165 /* do not call smb_ReleaseVC() because we already have the lock */
1168 lock_ReleaseWrite(&smb_rctLock);
1170 /* now release the scache structure */
1172 cm_ReleaseSCache(scp);
1176 * Case-insensitive search for one string in another;
1177 * used to find variable names in submount pathnames.
1179 static char *smb_stristr(char *str1, char *str2)
1183 for (cursor = str1; *cursor; cursor++)
1184 if (stricmp(cursor, str2) == 0)
1191 * Substitute a variable value for its name in a submount pathname. Variable
1192 * name has been identified by smb_stristr() and is in substr. Variable name
1193 * length (plus one) is in substr_size. Variable value is in newstr.
1195 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1200 strcpy(temp, substr + substr_size - 1);
1201 strcpy(substr, newstr);
1205 char VNUserName[] = "%USERNAME%";
1206 char VNLCUserName[] = "%LCUSERNAME%";
1207 char VNComputerName[] = "%COMPUTERNAME%";
1208 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1211 /* List available shares */
1212 int smb_ListShares()
1216 char shareBuf[4096];
1224 /*strcpy(shareNameList[num_shares], "all");
1225 strcpy(pathNameList[num_shares++], "/afs");*/
1226 fprintf(stderr, "The following shares are available:\n");
1227 fprintf(stderr, "Share Name (AFS Path)\n");
1228 fprintf(stderr, "---------------------\n");
1229 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1232 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1233 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1235 strcpy(sbmtpath, cm_confDir);
1237 strcat(sbmtpath, "/afsdsbmt.ini");
1238 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1239 shareBuf, sizeof(shareBuf),
1245 this_share = shareBuf;
1249 /*strcpy(shareNameList[num_shares], this_share);*/
1250 len = GetPrivateProfileString("AFS Submounts", this_share,
1257 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1260 if (*p == '\\') *p = '/'; /* change to / */
1264 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1265 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1268 while (*this_share != 0) this_share++; /* find next NUL */
1269 this_share++; /* skip past the NUL */
1270 } while (*this_share != 0); /* stop at final NUL */
1276 typedef struct smb_findShare_rock {
1280 } smb_findShare_rock_t;
1282 #define SMB_FINDSHARE_EXACT_MATCH 1
1283 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1285 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1289 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1290 if(!strnicmp(dep->name, vrock->shareName, 12)) {
1291 if(!stricmp(dep->name, vrock->shareName))
1292 matchType = SMB_FINDSHARE_EXACT_MATCH;
1294 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1295 if(vrock->match) free(vrock->match);
1296 vrock->match = strdup(dep->name);
1297 vrock->matchType = matchType;
1299 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1300 return CM_ERROR_STOPNOW;
1306 /* find a shareName in the table of submounts */
1307 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1311 char pathName[1024];
1316 char sbmtpath[MAX_PATH];
1321 DWORD allSubmount = 1;
1323 /* if allSubmounts == 0, only return the //mountRoot/all share
1324 * if in fact it has been been created in the subMounts table.
1325 * This is to allow sites that want to restrict access to the
1328 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1329 0, KEY_QUERY_VALUE, &parmKey);
1330 if (code == ERROR_SUCCESS) {
1331 len = sizeof(allSubmount);
1332 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1333 (BYTE *) &allSubmount, &len);
1334 if (code != ERROR_SUCCESS) {
1337 RegCloseKey (parmKey);
1340 if (allSubmount && _stricmp(shareName, "all") == 0) {
1345 /* In case, the all share is disabled we need to still be able
1346 * to handle ioctl requests
1348 if (_stricmp(shareName, "ioctl$") == 0) {
1349 *pathNamep = strdup("/.__ioctl__");
1353 if (_stricmp(shareName, "IPC$") == 0 ||
1354 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1355 _stricmp(shareName, "DESKTOP.INI") == 0
1362 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1363 0, KEY_QUERY_VALUE, &parmKey);
1364 if (code == ERROR_SUCCESS) {
1365 len = sizeof(pathName);
1366 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1367 (BYTE *) pathName, &len);
1368 if (code != ERROR_SUCCESS)
1370 RegCloseKey (parmKey);
1375 strcpy(sbmtpath, cm_confDir);
1376 strcat(sbmtpath, "/afsdsbmt.ini");
1377 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1378 pathName, sizeof(pathName), sbmtpath);
1380 if (len != 0 && len != sizeof(pathName) - 1) {
1381 /* We can accept either unix or PC style AFS pathnames. Convert
1382 * Unix-style to PC style here for internal use.
1385 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1386 p += strlen(cm_mountRoot); /* skip mount path */
1389 if (*q == '/') *q = '\\'; /* change to \ */
1395 if (var = smb_stristr(p, VNUserName)) {
1396 if (uidp && uidp->unp)
1397 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1399 smb_subst(p, var, sizeof(VNUserName)," ");
1401 else if (var = smb_stristr(p, VNLCUserName))
1403 if (uidp && uidp->unp)
1404 strcpy(temp, uidp->unp->name);
1408 smb_subst(p, var, sizeof(VNLCUserName), temp);
1410 else if (var = smb_stristr(p, VNComputerName))
1412 sizeTemp = sizeof(temp);
1413 GetComputerName((LPTSTR)temp, &sizeTemp);
1414 smb_subst(p, var, sizeof(VNComputerName), temp);
1416 else if (var = smb_stristr(p, VNLCComputerName))
1418 sizeTemp = sizeof(temp);
1419 GetComputerName((LPTSTR)temp, &sizeTemp);
1421 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1426 *pathNamep = strdup(p);
1431 /* First lookup shareName in root.afs */
1433 smb_findShare_rock_t vrock;
1435 char * p = shareName;
1438 /* attempt to locate a partial match in root.afs. This is because
1439 when using the ANSI RAP calls, the share name is limited to 13 chars
1440 and hence is truncated. Of course we prefer exact matches. */
1442 thyper.HighPart = 0;
1445 vrock.shareName = shareName;
1447 vrock.matchType = 0;
1449 cm_HoldSCache(cm_rootSCachep);
1450 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1451 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1452 cm_ReleaseSCache(cm_rootSCachep);
1454 if(vrock.matchType) {
1455 sprintf(pathName,"/%s/",vrock.match);
1456 *pathNamep = strdup(strlwr(pathName));
1461 /* if we get here, there was no match for the share in root.afs */
1462 /* so try to create \\<netbiosName>\<cellname> */
1467 /* Get the full name for this cell */
1468 code = cm_SearchCellFile(p, temp, 0, 0);
1469 #ifdef AFS_AFSDB_ENV
1470 if (code && cm_dnsEnabled) {
1472 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1475 /* construct the path */
1477 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1478 *pathNamep = strdup(strlwr(pathName));
1487 /* Client-side offline caching policy types */
1488 #define CSC_POLICY_MANUAL 0
1489 #define CSC_POLICY_DOCUMENTS 1
1490 #define CSC_POLICY_PROGRAMS 2
1491 #define CSC_POLICY_DISABLE 3
1493 int smb_FindShareCSCPolicy(char *shareName)
1499 int retval = CSC_POLICY_MANUAL;
1501 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1502 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1505 REG_OPTION_NON_VOLATILE,
1511 len = sizeof(policy);
1512 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1514 retval = CSC_POLICY_MANUAL;
1516 else if (stricmp(policy, "documents") == 0)
1518 retval = CSC_POLICY_DOCUMENTS;
1520 else if (stricmp(policy, "programs") == 0)
1522 retval = CSC_POLICY_PROGRAMS;
1524 else if (stricmp(policy, "disable") == 0)
1526 retval = CSC_POLICY_DISABLE;
1529 RegCloseKey(hkCSCPolicy);
1533 /* find a dir search structure by cookie value, and return it held.
1534 * Must be called with smb_globalLock held.
1536 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1538 smb_dirSearch_t *dsp;
1540 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1541 if (dsp->cookie == cookie) {
1542 if (dsp != smb_firstDirSearchp) {
1543 /* move to head of LRU queue, too, if we're not already there */
1544 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1545 smb_lastDirSearchp = (smb_dirSearch_t *)
1547 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1548 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1549 if (!smb_lastDirSearchp)
1550 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1559 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1561 lock_ObtainWrite(&smb_globalLock);
1562 dsp->flags |= SMB_DIRSEARCH_DELETE;
1563 lock_ReleaseWrite(&smb_globalLock);
1564 lock_ObtainMutex(&dsp->mx);
1565 if(dsp->scp != NULL) {
1566 lock_ObtainMutex(&dsp->scp->mx);
1567 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1568 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1569 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1570 dsp->scp->bulkStatProgress = hones;
1572 lock_ReleaseMutex(&dsp->scp->mx);
1574 lock_ReleaseMutex(&dsp->mx);
1577 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1583 lock_ObtainWrite(&smb_globalLock);
1584 osi_assert(dsp->refCount-- > 0);
1585 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1586 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1587 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1588 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1589 lock_FinalizeMutex(&dsp->mx);
1593 lock_ReleaseWrite(&smb_globalLock);
1595 /* do this now to avoid spurious locking hierarchy creation */
1596 if (scp) cm_ReleaseSCache(scp);
1599 /* find a dir search structure by cookie value, and return it held */
1600 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1602 smb_dirSearch_t *dsp;
1604 lock_ObtainWrite(&smb_globalLock);
1605 dsp = smb_FindDirSearchNL(cookie);
1606 lock_ReleaseWrite(&smb_globalLock);
1610 /* GC some dir search entries, in the address space expected by the specific protocol.
1611 * Must be called with smb_globalLock held; release the lock temporarily.
1613 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1614 void smb_GCDirSearches(int isV3)
1616 smb_dirSearch_t *prevp;
1617 smb_dirSearch_t *tp;
1618 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1622 victimCount = 0; /* how many have we got so far */
1623 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1624 /* we'll move tp from queue, so
1627 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1628 /* if no one is using this guy, and we're either in the new protocol,
1629 * or we're in the old one and this is a small enough ID to be useful
1630 * to the old protocol, GC this guy.
1632 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1633 /* hold and delete */
1634 tp->flags |= SMB_DIRSEARCH_DELETE;
1635 victimsp[victimCount++] = tp;
1639 /* don't do more than this */
1640 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1643 /* now release them */
1644 lock_ReleaseWrite(&smb_globalLock);
1645 for(i = 0; i < victimCount; i++) {
1646 smb_ReleaseDirSearch(victimsp[i]);
1648 lock_ObtainWrite(&smb_globalLock);
1651 /* function for allocating a dir search entry. We need these to remember enough context
1652 * since we don't get passed the path from call to call during a directory search.
1654 * Returns a held dir search structure, and bumps the reference count on the vnode,
1655 * since it saves a pointer to the vnode.
1657 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1659 smb_dirSearch_t *dsp;
1663 lock_ObtainWrite(&smb_globalLock);
1666 /* what's the biggest ID allowed in this version of the protocol */
1667 if (isV3) maxAllowed = 65535;
1668 else maxAllowed = 255;
1671 /* twice so we have enough tries to find guys we GC after one pass;
1672 * 10 extra is just in case I mis-counted.
1674 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1675 __FILE__, __LINE__);
1676 if (smb_dirSearchCounter > maxAllowed) {
1677 smb_dirSearchCounter = 1;
1678 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1680 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1682 /* don't need to watch for refcount zero and deleted, since
1683 * we haven't dropped the global lock.
1686 ++smb_dirSearchCounter;
1690 dsp = malloc(sizeof(*dsp));
1691 memset(dsp, 0, sizeof(*dsp));
1692 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1693 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1694 dsp->cookie = smb_dirSearchCounter;
1695 ++smb_dirSearchCounter;
1697 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1698 dsp->lastTime = osi_Time();
1701 lock_ReleaseWrite(&smb_globalLock);
1705 static smb_packet_t *GetPacket(void)
1709 unsigned int npar, seg, tb_sel;
1712 lock_ObtainWrite(&smb_globalLock);
1713 tbp = smb_packetFreeListp;
1715 smb_packetFreeListp = tbp->nextp;
1716 lock_ReleaseWrite(&smb_globalLock);
1719 tbp = calloc(65540,1);
1721 tbp = malloc(sizeof(smb_packet_t));
1723 tbp->magic = SMB_PACKETMAGIC;
1726 tbp->resumeCode = 0;
1732 tbp->ncb_length = 0;
1737 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1740 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1742 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1744 osi_panic("",__FILE__,__LINE__);
1747 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1752 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1753 tbp->dos_pkt_sel = tb_sel;
1756 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1761 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1765 memcpy(tbp, pkt, sizeof(smb_packet_t));
1766 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1770 static NCB *GetNCB(void)
1775 unsigned int npar, seg, tb_sel;
1778 lock_ObtainWrite(&smb_globalLock);
1779 tbp = smb_ncbFreeListp;
1781 smb_ncbFreeListp = tbp->nextp;
1782 lock_ReleaseWrite(&smb_globalLock);
1785 tbp = calloc(sizeof(*tbp),1);
1787 tbp = malloc(sizeof(*tbp));
1788 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1791 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1793 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1795 osi_panic("",__FILE__,__LINE__);
1797 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1802 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1803 tbp->dos_ncb_sel = tb_sel;
1805 tbp->magic = SMB_NCBMAGIC;
1808 osi_assert(tbp->magic == SMB_NCBMAGIC);
1810 memset(&tbp->ncb, 0, sizeof(NCB));
1813 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1818 void smb_FreePacket(smb_packet_t *tbp)
1820 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1822 lock_ObtainWrite(&smb_globalLock);
1823 tbp->nextp = smb_packetFreeListp;
1824 smb_packetFreeListp = tbp;
1825 tbp->magic = SMB_PACKETMAGIC;
1828 tbp->resumeCode = 0;
1834 tbp->ncb_length = 0;
1836 lock_ReleaseWrite(&smb_globalLock);
1839 static void FreeNCB(NCB *bufferp)
1843 tbp = (smb_ncb_t *) bufferp;
1844 osi_assert(tbp->magic == SMB_NCBMAGIC);
1846 lock_ObtainWrite(&smb_globalLock);
1847 tbp->nextp = smb_ncbFreeListp;
1848 smb_ncbFreeListp = tbp;
1849 lock_ReleaseWrite(&smb_globalLock);
1852 /* get a ptr to the data part of a packet, and its count */
1853 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1857 unsigned char *afterParmsp;
1859 parmBytes = *smbp->wctp << 1;
1860 afterParmsp = smbp->wctp + parmBytes + 1;
1862 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1863 if (nbytesp) *nbytesp = dataBytes;
1865 /* don't forget to skip the data byte count, since it follows
1866 * the parameters; that's where the "2" comes from below.
1868 return (unsigned char *) (afterParmsp + 2);
1871 /* must set all the returned parameters before playing around with the
1872 * data region, since the data region is located past the end of the
1873 * variable number of parameters.
1875 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1877 unsigned char *afterParmsp;
1879 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1881 *afterParmsp++ = dsize & 0xff;
1882 *afterParmsp = (dsize>>8) & 0xff;
1885 /* return the parm'th parameter in the smbp packet */
1886 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1889 unsigned char *parmDatap;
1891 parmCount = *smbp->wctp;
1893 if (parm >= parmCount) {
1898 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1900 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1901 parm, parmCount, smbp->ncb_length);
1904 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1905 1, smbp->ncb_length, ptbuf, smbp);
1906 DeregisterEventSource(h);
1908 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1909 osi_panic(s, __FILE__, __LINE__);
1911 parmDatap = smbp->wctp + (2*parm) + 1;
1913 return parmDatap[0] + (parmDatap[1] << 8);
1916 /* return the parm'th parameter in the smbp packet */
1917 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1920 unsigned char *parmDatap;
1922 parmCount = *smbp->wctp;
1924 if (parm * 2 + offset >= parmCount * 2) {
1929 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1931 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1932 parm, offset, parmCount, smbp->ncb_length);
1935 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1936 1, smbp->ncb_length, ptbuf, smbp);
1937 DeregisterEventSource(h);
1939 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1940 osi_panic(s, __FILE__, __LINE__);
1942 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1944 return parmDatap[0] + (parmDatap[1] << 8);
1947 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1951 /* make sure we have enough slots */
1952 if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1954 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1955 *parmDatap++ = parmValue & 0xff;
1956 *parmDatap = (parmValue>>8) & 0xff;
1959 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1963 /* make sure we have enough slots */
1964 if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1966 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1967 *parmDatap++ = parmValue & 0xff;
1968 *parmDatap++ = (parmValue>>8) & 0xff;
1969 *parmDatap++ = (parmValue>>16) & 0xff;
1970 *parmDatap++ = (parmValue>>24) & 0xff;
1973 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1978 /* make sure we have enough slots */
1979 if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1981 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1983 *parmDatap++ = *parmValuep++;
1986 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1990 /* make sure we have enough slots */
1991 if (*smbp->wctp <= slot) {
1992 if (smbp->oddByte) {
1994 *smbp->wctp = slot+1;
1999 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2000 *parmDatap++ = parmValue & 0xff;
2003 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2007 lastSlashp = strrchr(inPathp, '\\');
2009 *lastComponentp = lastSlashp;
2012 if (inPathp == lastSlashp)
2014 *outPathp++ = *inPathp++;
2023 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2028 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2033 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2039 tlen = inp[0] + (inp[1]<<8);
2040 inp += 2; /* skip length field */
2043 *chainpp = inp + tlen;
2052 /* format a packet as a response */
2053 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2058 outp = (smb_t *) op;
2060 /* zero the basic structure through the smb_wct field, and zero the data
2061 * size field, assuming that wct stays zero; otherwise, you have to
2062 * explicitly set the data size field, too.
2064 inSmbp = (smb_t *) inp;
2065 memset(outp, 0, sizeof(smb_t)+2);
2071 outp->com = inSmbp->com;
2072 outp->tid = inSmbp->tid;
2073 outp->pid = inSmbp->pid;
2074 outp->uid = inSmbp->uid;
2075 outp->mid = inSmbp->mid;
2076 outp->res[0] = inSmbp->res[0];
2077 outp->res[1] = inSmbp->res[1];
2078 op->inCom = inSmbp->com;
2080 outp->reb = 0x80; /* SERVER_RESP */
2081 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2083 /* copy fields in generic packet area */
2084 op->wctp = &outp->wct;
2087 /* send a (probably response) packet; vcp tells us to whom to send it.
2088 * we compute the length by looking at wct and bcc fields.
2090 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2107 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2110 memset((char *)ncbp, 0, sizeof(NCB));
2112 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2113 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2114 extra += tp[0] + (tp[1]<<8);
2115 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2116 extra += 3; /* wct and length fields */
2118 ncbp->ncb_length = extra; /* bytes to send */
2119 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2120 ncbp->ncb_lana_num = vcp->lana;
2121 ncbp->ncb_command = NCBSEND; /* op means send data */
2123 ncbp->ncb_buffer = (char *) inp;/* packet */
2124 code = Netbios(ncbp);
2126 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2127 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2129 /* copy header information from virtual to DOS address space */
2130 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2131 code = Netbios(ncbp, dos_ncb);
2135 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2141 void smb_MapNTError(long code, unsigned long *NTStatusp)
2143 unsigned long NTStatus;
2145 /* map CM_ERROR_* errors to NT 32-bit status codes */
2146 /* NT Status codes are listed in ntstatus.h not winerror.h */
2147 if (code == CM_ERROR_NOSUCHCELL) {
2148 NTStatus = 0xC000000FL; /* No such file */
2150 else if (code == CM_ERROR_NOSUCHVOLUME) {
2151 NTStatus = 0xC000000FL; /* No such file */
2153 else if (code == CM_ERROR_TIMEDOUT) {
2154 NTStatus = 0xC00000CFL; /* Sharing Paused */
2156 else if (code == CM_ERROR_RETRY) {
2157 NTStatus = 0xC000022DL; /* Retry */
2159 else if (code == CM_ERROR_NOACCESS) {
2160 NTStatus = 0xC0000022L; /* Access denied */
2162 else if (code == CM_ERROR_READONLY) {
2163 NTStatus = 0xC00000A2L; /* Write protected */
2165 else if (code == CM_ERROR_NOSUCHFILE) {
2166 NTStatus = 0xC000000FL; /* No such file */
2168 else if (code == CM_ERROR_NOSUCHPATH) {
2169 NTStatus = 0xC000003AL; /* Object path not found */
2171 else if (code == CM_ERROR_TOOBIG) {
2172 NTStatus = 0xC000007BL; /* Invalid image format */
2174 else if (code == CM_ERROR_INVAL) {
2175 NTStatus = 0xC000000DL; /* Invalid parameter */
2177 else if (code == CM_ERROR_BADFD) {
2178 NTStatus = 0xC0000008L; /* Invalid handle */
2180 else if (code == CM_ERROR_BADFDOP) {
2181 NTStatus = 0xC0000022L; /* Access denied */
2183 else if (code == CM_ERROR_EXISTS) {
2184 NTStatus = 0xC0000035L; /* Object name collision */
2186 else if (code == CM_ERROR_NOTEMPTY) {
2187 NTStatus = 0xC0000101L; /* Directory not empty */
2189 else if (code == CM_ERROR_CROSSDEVLINK) {
2190 NTStatus = 0xC00000D4L; /* Not same device */
2192 else if (code == CM_ERROR_NOTDIR) {
2193 NTStatus = 0xC0000103L; /* Not a directory */
2195 else if (code == CM_ERROR_ISDIR) {
2196 NTStatus = 0xC00000BAL; /* File is a directory */
2198 else if (code == CM_ERROR_BADOP) {
2199 NTStatus = 0xC09820FFL; /* SMB no support */
2201 else if (code == CM_ERROR_BADSHARENAME) {
2202 NTStatus = 0xC00000CCL; /* Bad network name */
2204 else if (code == CM_ERROR_NOIPC) {
2206 NTStatus = 0xC0000022L; /* Access Denied */
2208 NTStatus = 0xC000013DL; /* Remote Resources */
2211 else if (code == CM_ERROR_CLOCKSKEW) {
2212 NTStatus = 0xC0000133L; /* Time difference at DC */
2214 else if (code == CM_ERROR_BADTID) {
2215 NTStatus = 0xC0982005L; /* SMB bad TID */
2217 else if (code == CM_ERROR_USESTD) {
2218 NTStatus = 0xC09820FBL; /* SMB use standard */
2220 else if (code == CM_ERROR_QUOTA) {
2221 NTStatus = 0xC0000044L; /* Quota exceeded */
2223 else if (code == CM_ERROR_SPACE) {
2224 NTStatus = 0xC000007FL; /* Disk full */
2226 else if (code == CM_ERROR_ATSYS) {
2227 NTStatus = 0xC0000033L; /* Object name invalid */
2229 else if (code == CM_ERROR_BADNTFILENAME) {
2230 NTStatus = 0xC0000033L; /* Object name invalid */
2232 else if (code == CM_ERROR_WOULDBLOCK) {
2233 NTStatus = 0xC0000055L; /* Lock not granted */
2235 else if (code == CM_ERROR_PARTIALWRITE) {
2236 NTStatus = 0xC000007FL; /* Disk full */
2238 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2239 NTStatus = 0xC0000023L; /* Buffer too small */
2241 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2242 NTStatus = 0xC0000035L; /* Object name collision */
2244 else if (code == CM_ERROR_BADPASSWORD) {
2245 NTStatus = 0xC000006DL; /* unknown username or bad password */
2247 else if (code == CM_ERROR_BADLOGONTYPE) {
2248 NTStatus = 0xC000015BL; /* logon type not granted */
2250 else if (code == CM_ERROR_GSSCONTINUE) {
2251 NTStatus = 0xC0000016L; /* more processing required */
2254 NTStatus = 0xC0982001L; /* SMB non-specific error */
2257 *NTStatusp = NTStatus;
2258 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2261 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2262 unsigned char *classp)
2264 unsigned char class;
2265 unsigned short error;
2267 /* map CM_ERROR_* errors to SMB errors */
2268 if (code == CM_ERROR_NOSUCHCELL) {
2270 error = 3; /* bad path */
2272 else if (code == CM_ERROR_NOSUCHVOLUME) {
2274 error = 3; /* bad path */
2276 else if (code == CM_ERROR_TIMEDOUT) {
2278 error = 81; /* server is paused */
2280 else if (code == CM_ERROR_RETRY) {
2281 class = 2; /* shouldn't happen */
2284 else if (code == CM_ERROR_NOACCESS) {
2286 error = 4; /* bad access */
2288 else if (code == CM_ERROR_READONLY) {
2290 error = 19; /* read only */
2292 else if (code == CM_ERROR_NOSUCHFILE) {
2294 error = 2; /* ENOENT! */
2296 else if (code == CM_ERROR_NOSUCHPATH) {
2298 error = 3; /* Bad path */
2300 else if (code == CM_ERROR_TOOBIG) {
2302 error = 11; /* bad format */
2304 else if (code == CM_ERROR_INVAL) {
2305 class = 2; /* server non-specific error code */
2308 else if (code == CM_ERROR_BADFD) {
2310 error = 6; /* invalid file handle */
2312 else if (code == CM_ERROR_BADFDOP) {
2313 class = 1; /* invalid op on FD */
2316 else if (code == CM_ERROR_EXISTS) {
2318 error = 80; /* file already exists */
2320 else if (code == CM_ERROR_NOTEMPTY) {
2322 error = 5; /* delete directory not empty */
2324 else if (code == CM_ERROR_CROSSDEVLINK) {
2326 error = 17; /* EXDEV */
2328 else if (code == CM_ERROR_NOTDIR) {
2329 class = 1; /* bad path */
2332 else if (code == CM_ERROR_ISDIR) {
2333 class = 1; /* access denied; DOS doesn't have a good match */
2336 else if (code == CM_ERROR_BADOP) {
2340 else if (code == CM_ERROR_BADSHARENAME) {
2344 else if (code == CM_ERROR_NOIPC) {
2346 error = 4; /* bad access */
2348 else if (code == CM_ERROR_CLOCKSKEW) {
2349 class = 1; /* invalid function */
2352 else if (code == CM_ERROR_BADTID) {
2356 else if (code == CM_ERROR_USESTD) {
2360 else if (code == CM_ERROR_REMOTECONN) {
2364 else if (code == CM_ERROR_QUOTA) {
2365 if (vcp->flags & SMB_VCFLAG_USEV3) {
2367 error = 39; /* disk full */
2371 error = 5; /* access denied */
2374 else if (code == CM_ERROR_SPACE) {
2375 if (vcp->flags & SMB_VCFLAG_USEV3) {
2377 error = 39; /* disk full */
2381 error = 5; /* access denied */
2384 else if (code == CM_ERROR_PARTIALWRITE) {
2386 error = 39; /* disk full */
2388 else if (code == CM_ERROR_ATSYS) {
2390 error = 2; /* ENOENT */
2392 else if (code == CM_ERROR_WOULDBLOCK) {
2394 error = 33; /* lock conflict */
2396 else if (code == CM_ERROR_NOFILES) {
2398 error = 18; /* no files in search */
2400 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2402 error = 183; /* Samba uses this */
2404 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2405 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2407 error = 2; /* bad password */
2416 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2419 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2421 return CM_ERROR_BADOP;
2424 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2426 unsigned short EchoCount, i;
2427 char *data, *outdata;
2430 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2432 for (i=1; i<=EchoCount; i++) {
2433 data = smb_GetSMBData(inp, &dataSize);
2434 smb_SetSMBParm(outp, 0, i);
2435 smb_SetSMBDataLength(outp, dataSize);
2436 outdata = smb_GetSMBData(outp, NULL);
2437 memcpy(outdata, data, dataSize);
2438 smb_SendPacket(vcp, outp);
2444 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2447 long count, minCount, finalCount;
2451 cm_user_t *userp = NULL;
2455 char *rawBuf = NULL;
2457 dos_ptr rawBuf = NULL;
2464 fd = smb_GetSMBParm(inp, 0);
2465 count = smb_GetSMBParm(inp, 3);
2466 minCount = smb_GetSMBParm(inp, 4);
2467 offset.HighPart = 0; /* too bad */
2468 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2470 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2471 fd, offset.LowPart, count);
2473 fidp = smb_FindFID(vcp, fd, 0);
2477 lock_ObtainMutex(&smb_RawBufLock);
2479 /* Get a raw buf, from head of list */
2480 rawBuf = smb_RawBufs;
2482 smb_RawBufs = *(char **)smb_RawBufs;
2484 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2487 lock_ReleaseMutex(&smb_RawBufLock);
2491 if (fidp->flags & SMB_FID_IOCTL)
2494 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2496 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2499 /* Give back raw buffer */
2500 lock_ObtainMutex(&smb_RawBufLock);
2502 *((char **) rawBuf) = smb_RawBufs;
2504 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2507 smb_RawBufs = rawBuf;
2508 lock_ReleaseMutex(&smb_RawBufLock);
2511 smb_ReleaseFID(fidp);
2515 userp = smb_GetUser(vcp, inp);
2518 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2520 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2521 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2522 userp, &finalCount, TRUE /* rawFlag */);
2529 cm_ReleaseUser(userp);
2532 smb_ReleaseFID(fidp);
2537 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2539 memset((char *)ncbp, 0, sizeof(NCB));
2541 ncbp->ncb_length = (unsigned short) finalCount;
2542 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2543 ncbp->ncb_lana_num = vcp->lana;
2544 ncbp->ncb_command = NCBSEND;
2545 ncbp->ncb_buffer = rawBuf;
2548 code = Netbios(ncbp);
2550 code = Netbios(ncbp, dos_ncb);
2553 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2556 /* Give back raw buffer */
2557 lock_ObtainMutex(&smb_RawBufLock);
2559 *((char **) rawBuf) = smb_RawBufs;
2561 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2564 smb_RawBufs = rawBuf;
2565 lock_ReleaseMutex(&smb_RawBufLock);
2571 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2576 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2581 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2588 int protoIndex; /* index we're using */
2593 char protocol_array[10][1024]; /* protocol signature of the client */
2594 int caps; /* capabilities */
2597 TIME_ZONE_INFORMATION tzi;
2599 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2603 DWORD now = GetCurrentTime();
2604 if (now - last_msg_time >= 30000
2605 && now - last_msg_time <= 90000) {
2607 "Setting dead_vcp %x", active_vcp);
2609 smb_ReleaseVC(dead_vcp);
2611 "Previous dead_vcp %x", dead_vcp);
2613 smb_HoldVC(active_vcp);
2614 dead_vcp = active_vcp;
2615 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2620 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2622 namep = smb_GetSMBData(inp, &dbytes);
2625 coreProtoIndex = -1; /* not found */
2628 while(namex < dbytes) {
2629 osi_Log1(smb_logp, "Protocol %s",
2630 osi_LogSaveString(smb_logp, namep+1));
2631 strcpy(protocol_array[tcounter], namep+1);
2633 /* namep points at the first protocol, or really, a 0x02
2634 * byte preceding the null-terminated ASCII name.
2636 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2637 coreProtoIndex = tcounter;
2639 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2640 v3ProtoIndex = tcounter;
2642 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2643 NTProtoIndex = tcounter;
2646 /* compute size of protocol entry */
2647 entryLength = strlen(namep+1);
2648 entryLength += 2; /* 0x02 bytes and null termination */
2650 /* advance over this protocol entry */
2651 namex += entryLength;
2652 namep += entryLength;
2653 tcounter++; /* which proto entry we're looking at */
2656 if (NTProtoIndex != -1) {
2657 protoIndex = NTProtoIndex;
2658 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2660 else if (v3ProtoIndex != -1) {
2661 protoIndex = v3ProtoIndex;
2662 vcp->flags |= SMB_VCFLAG_USEV3;
2664 else if (coreProtoIndex != -1) {
2665 protoIndex = coreProtoIndex;
2666 vcp->flags |= SMB_VCFLAG_USECORE;
2668 else protoIndex = -1;
2670 if (protoIndex == -1)
2671 return CM_ERROR_INVAL;
2672 else if (NTProtoIndex != -1) {
2673 smb_SetSMBParm(outp, 0, protoIndex);
2674 if (smb_authType != SMB_AUTH_NONE) {
2675 smb_SetSMBParmByte(outp, 1,
2676 NEGOTIATE_SECURITY_USER_LEVEL |
2677 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2679 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2681 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2682 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2683 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2684 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2685 /* The session key is not a well documented field however most clients
2686 * will echo back the session key to the server. Currently we are using
2687 * the same value for all sessions. We should generate a random value
2688 * and store it into the vcp
2690 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2691 smb_SetSMBParm(outp, 8, 1);
2693 * Tried changing the capabilities to support for W2K - defect 117695
2694 * Maybe something else needs to be changed here?
2698 smb_SetSMBParmLong(outp, 9, 0x43fd);
2700 smb_SetSMBParmLong(outp, 9, 0x251);
2703 * 32-bit error codes *
2707 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2708 NTNEGOTIATE_CAPABILITY_NTFIND |
2709 NTNEGOTIATE_CAPABILITY_RAWMODE |
2710 NTNEGOTIATE_CAPABILITY_NTSMB;
2712 if ( smb_authType == SMB_AUTH_EXTENDED )
2713 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2715 smb_SetSMBParmLong(outp, 9, caps);
2717 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2718 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2719 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2721 GetTimeZoneInformation(&tzi);
2722 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2724 if (smb_authType == SMB_AUTH_NTLM) {
2725 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2726 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2727 /* paste in encryption key */
2728 datap = smb_GetSMBData(outp, NULL);
2729 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2730 /* and the faux domain name */
2731 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2732 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2736 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2738 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2740 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2742 datap = smb_GetSMBData(outp, NULL);
2743 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2746 datap += sizeof(smb_ServerGUID);
2747 memcpy(datap, secBlob, secBlobLength);
2751 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2752 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2755 else if (v3ProtoIndex != -1) {
2756 smb_SetSMBParm(outp, 0, protoIndex);
2758 /* NOTE: Extended authentication cannot be negotiated with v3
2759 * therefore we fail over to NTLM
2761 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2762 smb_SetSMBParm(outp, 1,
2763 NEGOTIATE_SECURITY_USER_LEVEL |
2764 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2766 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2768 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2769 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2770 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2771 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2772 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2773 smb_SetSMBParm(outp, 7, 1);
2775 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2776 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2777 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2779 GetTimeZoneInformation(&tzi);
2780 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2782 /* NOTE: Extended authentication cannot be negotiated with v3
2783 * therefore we fail over to NTLM
2785 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2786 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2787 smb_SetSMBParm(outp, 12, 0); /* resvd */
2788 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2789 datap = smb_GetSMBData(outp, NULL);
2790 /* paste in a new encryption key */
2791 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2792 /* and the faux domain name */
2793 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2795 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2796 smb_SetSMBParm(outp, 12, 0); /* resvd */
2797 smb_SetSMBDataLength(outp, 0);
2800 else if (coreProtoIndex != -1) { /* not really supported anymore */
2801 smb_SetSMBParm(outp, 0, protoIndex);
2802 smb_SetSMBDataLength(outp, 0);
2807 void smb_Daemon(void *parmp)
2809 afs_uint32 count = 0;
2814 if ((count % 72) == 0) { /* every five minutes */
2816 long old_localZero = smb_localZero;
2818 /* Initialize smb_localZero */
2819 myTime.tm_isdst = -1; /* compute whether on DST or not */
2820 myTime.tm_year = 70;
2826 smb_localZero = mktime(&myTime);
2828 smb_CalculateNowTZ();
2830 #ifdef AFS_FREELANCE
2831 if ( smb_localZero != old_localZero )
2832 cm_noteLocalMountPointChange();
2835 /* XXX GC dir search entries */
2839 void smb_WaitingLocksDaemon()
2841 smb_waitingLock_t *wL, *nwL;
2844 smb_packet_t *inp, *outp;
2849 lock_ObtainWrite(&smb_globalLock);
2850 nwL = smb_allWaitingLocks;
2852 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2861 lock_ObtainWrite(&smb_globalLock);
2863 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2864 lock_ReleaseWrite(&smb_globalLock);
2865 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2866 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2867 if (code == CM_ERROR_WOULDBLOCK) {
2869 if (wL->timeRemaining != 0xffffffff
2870 && (wL->timeRemaining -= 1000) < 0)
2879 ncbp->ncb_length = inp->ncb_length;
2880 inp->spacep = cm_GetSpace();
2882 /* Remove waitingLock from list */
2883 lock_ObtainWrite(&smb_globalLock);
2884 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2886 lock_ReleaseWrite(&smb_globalLock);
2888 /* Resume packet processing */
2890 smb_SetSMBDataLength(outp, 0);
2891 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2892 outp->resumeCode = code;
2894 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2897 cm_FreeSpace(inp->spacep);
2898 smb_FreePacket(inp);
2899 smb_FreePacket(outp);
2907 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2909 osi_Log0(smb_logp, "SMB receive get disk attributes");
2911 smb_SetSMBParm(outp, 0, 32000);
2912 smb_SetSMBParm(outp, 1, 64);
2913 smb_SetSMBParm(outp, 2, 1024);
2914 smb_SetSMBParm(outp, 3, 30000);
2915 smb_SetSMBParm(outp, 4, 0);
2916 smb_SetSMBDataLength(outp, 0);
2920 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2924 unsigned short newTid;
2925 char shareName[256];
2933 osi_Log0(smb_logp, "SMB receive tree connect");
2935 /* parse input parameters */
2936 tp = smb_GetSMBData(inp, NULL);
2937 pathp = smb_ParseASCIIBlock(tp, &tp);
2938 passwordp = smb_ParseASCIIBlock(tp, &tp);
2939 tp = strrchr(pathp, '\\');
2941 return CM_ERROR_BADSMB;
2942 strcpy(shareName, tp+1);
2944 userp = smb_GetUser(vcp, inp);
2946 lock_ObtainMutex(&vcp->mx);
2947 newTid = vcp->tidCounter++;
2948 lock_ReleaseMutex(&vcp->mx);
2950 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2951 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2952 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2954 smb_ReleaseUID(uidp);
2956 smb_ReleaseTID(tidp);
2957 return CM_ERROR_BADSHARENAME;
2959 lock_ObtainMutex(&tidp->mx);
2960 tidp->userp = userp;
2961 tidp->pathname = sharePath;
2962 lock_ReleaseMutex(&tidp->mx);
2963 smb_ReleaseTID(tidp);
2965 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2966 smb_SetSMBParm(rsp, 1, newTid);
2967 smb_SetSMBDataLength(rsp, 0);
2969 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2973 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2977 if (*inp++ != 0x1) return NULL;
2978 tlen = inp[0] + (inp[1]<<8);
2979 inp += 2; /* skip length field */
2982 *chainpp = inp + tlen;
2985 if (lengthp) *lengthp = tlen;
2990 /* set maskp to the mask part of the incoming path.
2991 * Mask is 11 bytes long (8.3 with the dot elided).
2992 * Returns true if succeeds with a valid name, otherwise it does
2993 * its best, but returns false.
2995 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3003 /* starts off valid */
3006 /* mask starts out all blanks */
3007 memset(maskp, ' ', 11);
3009 /* find last backslash, or use whole thing if there is none */
3010 tp = strrchr(pathp, '\\');
3011 if (!tp) tp = pathp;
3012 else tp++; /* skip slash */
3016 /* names starting with a dot are illegal */
3017 if (*tp == '.') valid8Dot3 = 0;
3021 if (tc == 0) return valid8Dot3;
3022 if (tc == '.' || tc == '"') break;
3023 if (i < 8) *up++ = tc;
3024 else valid8Dot3 = 0;
3027 /* if we get here, tp point after the dot */
3028 up = maskp+8; /* ext goes here */
3035 if (tc == '.' || tc == '"')
3038 /* copy extension if not too long */
3048 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3058 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3060 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3064 /* otherwise, we have a valid 8.3 name; see if we have a match,
3065 * treating '?' as a wildcard in maskp (but not in the file name).
3067 tp1 = umask; /* real name, in mask format */
3068 tp2 = maskp; /* mask, in mask format */
3069 for(i=0; i<11; i++) {
3070 tc1 = *tp1++; /* char from real name */
3071 tc2 = *tp2++; /* char from mask */
3072 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3073 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3076 if (tc2 == '?' && tc1 != ' ')
3083 /* we got a match */
3087 char *smb_FindMask(char *pathp)
3091 tp = strrchr(pathp, '\\'); /* find last slash */
3094 return tp+1; /* skip the slash */
3096 return pathp; /* no slash, return the entire path */
3099 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3101 unsigned char *pathp;
3103 unsigned char mask[11];
3104 unsigned char *statBlockp;
3105 unsigned char initStatBlock[21];
3108 osi_Log0(smb_logp, "SMB receive search volume");
3110 /* pull pathname and stat block out of request */
3111 tp = smb_GetSMBData(inp, NULL);
3112 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3113 osi_assert(pathp != NULL);
3114 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3115 osi_assert(statBlockp != NULL);
3117 statBlockp = initStatBlock;
3121 /* for returning to caller */
3122 smb_Get8Dot3MaskFromPath(mask, pathp);
3124 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3125 tp = smb_GetSMBData(outp, NULL);
3127 *tp++ = 43; /* bytes in a dir entry */
3128 *tp++ = 0; /* high byte in counter */
3130 /* now marshall the dir entry, starting with the search status */
3131 *tp++ = statBlockp[0]; /* Reserved */
3132 memcpy(tp, mask, 11); tp += 11; /* FileName */
3134 /* now pass back server use info, with 1st byte non-zero */
3136 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3138 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3140 *tp++ = 0x8; /* attribute: volume */
3150 /* 4 byte file size */
3156 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3157 memset(tp, ' ', 13);
3160 /* set the length of the data part of the packet to 43 + 3, for the dir
3161 * entry plus the 5 and the length fields.
3163 smb_SetSMBDataLength(outp, 46);
3167 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3168 cm_user_t *userp, cm_req_t *reqp)
3176 smb_dirListPatch_t *patchp;
3177 smb_dirListPatch_t *npatchp;
3179 for(patchp = *dirPatchespp; patchp; patchp =
3180 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3182 dptr = patchp->dptr;
3184 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3186 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3187 *dptr++ = SMB_ATTR_HIDDEN;
3190 lock_ObtainMutex(&scp->mx);
3191 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3192 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3194 lock_ReleaseMutex(&scp->mx);
3195 cm_ReleaseSCache(scp);
3196 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3197 *dptr++ = SMB_ATTR_HIDDEN;
3201 attr = smb_Attributes(scp);
3202 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3203 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3204 attr |= SMB_ATTR_HIDDEN;
3208 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3211 shortTemp = dosTime & 0xffff;
3212 *((u_short *)dptr) = shortTemp;
3215 /* and copy out date */
3216 shortTemp = (dosTime>>16) & 0xffff;
3217 *((u_short *)dptr) = shortTemp;
3220 /* copy out file length */
3221 *((u_long *)dptr) = scp->length.LowPart;
3223 lock_ReleaseMutex(&scp->mx);
3224 cm_ReleaseSCache(scp);
3227 /* now free the patches */
3228 for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
3229 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3233 /* and mark the list as empty */
3234 *dirPatchespp = NULL;
3239 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3248 smb_dirListPatch_t *dirListPatchesp;
3249 smb_dirListPatch_t *curPatchp;
3253 osi_hyper_t dirLength;
3254 osi_hyper_t bufferOffset;
3255 osi_hyper_t curOffset;
3257 unsigned char *inCookiep;
3258 smb_dirSearch_t *dsp;
3262 unsigned long clientCookie;
3263 cm_pageHeader_t *pageHeaderp;
3264 cm_user_t *userp = NULL;
3271 long nextEntryCookie;
3272 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3273 char resByte; /* reserved byte from the cookie */
3274 char *op; /* output data ptr */
3275 char *origOp; /* original value of op */
3276 cm_space_t *spacep; /* for pathname buffer */
3287 maxCount = smb_GetSMBParm(inp, 0);
3289 dirListPatchesp = NULL;
3291 caseFold = CM_FLAG_CASEFOLD;
3293 tp = smb_GetSMBData(inp, NULL);
3294 pathp = smb_ParseASCIIBlock(tp, &tp);
3295 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3297 /* bail out if request looks bad */
3298 if (!tp || !pathp) {
3299 return CM_ERROR_BADSMB;
3302 /* We can handle long names */
3303 if (vcp->flags & SMB_VCFLAG_USENT)
3304 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3306 /* make sure we got a whole search status */
3307 if (dataLength < 21) {
3308 nextCookie = 0; /* start at the beginning of the dir */
3311 attribute = smb_GetSMBParm(inp, 1);
3313 /* handle volume info in another function */
3314 if (attribute & 0x8)
3315 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3317 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3318 maxCount, osi_LogSaveString(smb_logp, pathp));
3320 if (*pathp == 0) { /* null pathp, treat as root dir */
3321 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3322 return CM_ERROR_NOFILES;
3326 dsp = smb_NewDirSearch(0);
3327 dsp->attribute = attribute;
3328 smb_Get8Dot3MaskFromPath(mask, pathp);
3329 memcpy(dsp->mask, mask, 11);
3331 /* track if this is likely to match a lot of entries */
3332 if (smb_IsStarMask(mask)) starPattern = 1;
3333 else starPattern = 0;
3336 /* pull the next cookie value out of the search status block */
3337 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3338 + (inCookiep[16]<<24);
3339 dsp = smb_FindDirSearch(inCookiep[12]);
3341 /* can't find dir search status; fatal error */
3342 return CM_ERROR_BADFD;
3344 attribute = dsp->attribute;
3345 resByte = inCookiep[0];
3347 /* copy out client cookie, in host byte order. Don't bother
3348 * interpreting it, since we're just passing it through, anyway.
3350 memcpy(&clientCookie, &inCookiep[17], 4);
3352 memcpy(mask, dsp->mask, 11);
3354 /* assume we're doing a star match if it has continued for more
3360 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3361 nextCookie, dsp->cookie, attribute);
3363 userp = smb_GetUser(vcp, inp);
3365 /* try to get the vnode for the path name next */
3366 lock_ObtainMutex(&dsp->mx);
3373 spacep = inp->spacep;
3374 smb_StripLastComponent(spacep->data, NULL, pathp);
3375 lock_ReleaseMutex(&dsp->mx);
3376 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3378 lock_ReleaseMutex(&dsp->mx);
3379 cm_ReleaseUser(userp);
3380 smb_DeleteDirSearch(dsp);
3381 smb_ReleaseDirSearch(dsp);
3382 return CM_ERROR_NOFILES;
3384 code = cm_NameI(cm_rootSCachep, spacep->data,
3385 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3386 lock_ObtainMutex(&dsp->mx);
3388 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3390 /* we need one hold for the entry we just stored into,
3391 * and one for our own processing. When we're done with this
3392 * function, we'll drop the one for our own processing.
3393 * We held it once from the namei call, and so we do another hold
3397 lock_ObtainMutex(&scp->mx);
3398 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3399 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3400 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3401 dsp->flags |= SMB_DIRSEARCH_BULKST;
3403 lock_ReleaseMutex(&scp->mx);
3406 lock_ReleaseMutex(&dsp->mx);
3408 cm_ReleaseUser(userp);
3409 smb_DeleteDirSearch(dsp);
3410 smb_ReleaseDirSearch(dsp);
3414 /* reserves space for parameter; we'll adjust it again later to the
3415 * real count of the # of entries we returned once we've actually
3416 * assembled the directory listing.
3418 smb_SetSMBParm(outp, 0, 0);
3420 /* get the directory size */
3421 lock_ObtainMutex(&scp->mx);
3422 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3423 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3425 lock_ReleaseMutex(&scp->mx);
3426 cm_ReleaseSCache(scp);
3427 cm_ReleaseUser(userp);
3428 smb_DeleteDirSearch(dsp);
3429 smb_ReleaseDirSearch(dsp);
3433 dirLength = scp->length;
3435 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3436 curOffset.HighPart = 0;
3437 curOffset.LowPart = nextCookie;
3438 origOp = op = smb_GetSMBData(outp, NULL);
3439 /* and write out the basic header */
3440 *op++ = 5; /* variable block */
3441 op += 2; /* skip vbl block length; we'll fill it in later */
3445 /* make sure that curOffset.LowPart doesn't point to the first
3446 * 32 bytes in the 2nd through last dir page, and that it doesn't
3447 * point at the first 13 32-byte chunks in the first dir page,
3448 * since those are dir and page headers, and don't contain useful
3451 temp = curOffset.LowPart & (2048-1);
3452 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3453 /* we're in the first page */
3454 if (temp < 13*32) temp = 13*32;
3457 /* we're in a later dir page */
3458 if (temp < 32) temp = 32;
3461 /* make sure the low order 5 bits are zero */
3464 /* now put temp bits back ito curOffset.LowPart */
3465 curOffset.LowPart &= ~(2048-1);
3466 curOffset.LowPart |= temp;
3468 /* check if we've returned all the names that will fit in the
3471 if (returnedNames >= maxCount)
3474 /* check if we've passed the dir's EOF */
3475 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3477 /* see if we can use the bufferp we have now; compute in which page
3478 * the current offset would be, and check whether that's the offset
3479 * of the buffer we have. If not, get the buffer.
3481 thyper.HighPart = curOffset.HighPart;
3482 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3483 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3486 buf_Release(bufferp);
3489 lock_ReleaseMutex(&scp->mx);
3490 lock_ObtainRead(&scp->bufCreateLock);
3491 code = buf_Get(scp, &thyper, &bufferp);
3492 lock_ReleaseRead(&scp->bufCreateLock);
3494 /* now, if we're doing a star match, do bulk fetching of all of
3495 * the status info for files in the dir.
3498 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3500 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3501 && LargeIntegerGreaterThanOrEqualTo(thyper,
3502 scp->bulkStatProgress)) {
3503 /* Don't bulk stat if risking timeout */
3504 int now = GetCurrentTime();
3505 if (now - req.startTime > 5000) {
3506 scp->bulkStatProgress = thyper;
3507 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3508 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3510 cm_TryBulkStat(scp, &thyper, userp, &req);
3514 lock_ObtainMutex(&scp->mx);
3517 bufferOffset = thyper;
3519 /* now get the data in the cache */
3521 code = cm_SyncOp(scp, bufferp, userp, &req,
3523 CM_SCACHESYNC_NEEDCALLBACK
3524 | CM_SCACHESYNC_READ);
3527 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3529 /* otherwise, load the buffer and try again */
3530 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3535 buf_Release(bufferp);
3539 } /* if (wrong buffer) ... */
3541 /* now we have the buffer containing the entry we're interested in; copy
3542 * it out if it represents a non-deleted entry.
3544 entryInDir = curOffset.LowPart & (2048-1);
3545 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3547 /* page header will help tell us which entries are free. Page header
3548 * can change more often than once per buffer, since AFS 3 dir page size
3549 * may be less than (but not more than a buffer package buffer.
3551 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3552 temp &= ~(2048 - 1); /* turn off intra-page bits */
3553 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3555 /* now determine which entry we're looking at in the page. If it is
3556 * free (there's a free bitmap at the start of the dir), we should
3557 * skip these 32 bytes.
3559 slotInPage = (entryInDir & 0x7e0) >> 5;
3560 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3561 /* this entry is free */
3562 numDirChunks = 1; /* only skip this guy */
3566 tp = bufferp->datap + entryInBuffer;
3567 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3569 /* while we're here, compute the next entry's location, too,
3570 * since we'll need it when writing out the cookie into the dir
3573 * XXXX Probably should do more sanity checking.
3575 numDirChunks = cm_NameEntries(dep->name, NULL);
3577 /* compute the offset of the cookie representing the next entry */
3578 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3580 /* Compute 8.3 name if necessary */
3581 actualName = dep->name;
3582 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3583 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3584 actualName = shortName;
3587 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3588 /* this is one of the entries to use: it is not deleted
3589 * and it matches the star pattern we're looking for.
3592 /* Eliminate entries that don't match requested
3595 /* no hidden files */
3596 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3599 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3601 /* We have already done the cm_TryBulkStat above */
3602 fid.cell = scp->fid.cell;
3603 fid.volume = scp->fid.volume;
3604 fid.vnode = ntohl(dep->fid.vnode);
3605 fid.unique = ntohl(dep->fid.unique);
3606 fileType = cm_FindFileType(&fid);
3607 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3608 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3610 if (fileType == CM_SCACHETYPE_DIRECTORY)
3615 memcpy(op, mask, 11); op += 11;
3616 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3617 *op++ = nextEntryCookie & 0xff;
3618 *op++ = (nextEntryCookie>>8) & 0xff;
3619 *op++ = (nextEntryCookie>>16) & 0xff;
3620 *op++ = (nextEntryCookie>>24) & 0xff;
3621 memcpy(op, &clientCookie, 4); op += 4;
3623 /* now we emit the attribute. This is sort of tricky,
3624 * since we need to really stat the file to find out
3625 * what type of entry we've got. Right now, we're
3626 * copying out data from a buffer, while holding the
3627 * scp locked, so it isn't really convenient to stat
3628 * something now. We'll put in a place holder now,
3629 * and make a second pass before returning this to get
3630 * the real attributes. So, we just skip the data for
3631 * now, and adjust it later. We allocate a patch
3632 * record to make it easy to find this point later.
3633 * The replay will happen at a time when it is safe to
3634 * unlock the directory.
3636 curPatchp = malloc(sizeof(*curPatchp));
3637 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3638 curPatchp->dptr = op;
3639 curPatchp->fid.cell = scp->fid.cell;
3640 curPatchp->fid.volume = scp->fid.volume;
3641 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3642 curPatchp->fid.unique = ntohl(dep->fid.unique);
3644 /* do hidden attribute here since name won't be around when applying
3648 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3649 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3651 curPatchp->flags = 0;
3653 op += 9; /* skip attr, time, date and size */
3655 /* zero out name area. The spec says to pad with
3656 * spaces, but Samba doesn't, and neither do we.
3660 /* finally, we get to copy out the name; we know that
3661 * it fits in 8.3 or the pattern wouldn't match, but it
3662 * never hurts to be sure.
3664 strncpy(op, actualName, 13);
3666 /* Uppercase if requested by client */
3667 if ((((smb_t *)inp)->flg2 & 1) == 0)
3672 /* now, adjust the # of entries copied */
3674 } /* if we're including this name */
3677 /* and adjust curOffset to be where the new cookie is */
3678 thyper.HighPart = 0;
3679 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3680 curOffset = LargeIntegerAdd(thyper, curOffset);
3681 } /* while copying data for dir listing */
3683 /* release the mutex */
3684 lock_ReleaseMutex(&scp->mx);
3685 if (bufferp) buf_Release(bufferp);
3687 /* apply and free last set of patches; if not doing a star match, this
3688 * will be empty, but better safe (and freeing everything) than sorry.
3690 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3692 /* special return code for unsuccessful search */
3693 if (code == 0 && dataLength < 21 && returnedNames == 0)
3694 code = CM_ERROR_NOFILES;
3696 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3697 returnedNames, code);
3700 smb_DeleteDirSearch(dsp);
3701 smb_ReleaseDirSearch(dsp);
3702 cm_ReleaseSCache(scp);
3703 cm_ReleaseUser(userp);
3707 /* finalize the output buffer */
3708 smb_SetSMBParm(outp, 0, returnedNames);
3709 temp = (long) (op - origOp);
3710 smb_SetSMBDataLength(outp, temp);
3712 /* the data area is a variable block, which has a 5 (already there)
3713 * followed by the length of the # of data bytes. We now know this to
3714 * be "temp," although that includes the 3 bytes of vbl block header.
3715 * Deduct for them and fill in the length field.
3717 temp -= 3; /* deduct vbl block info */
3718 osi_assert(temp == (43 * returnedNames));
3719 origOp[1] = temp & 0xff;
3720 origOp[2] = (temp>>8) & 0xff;
3721 if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3722 smb_ReleaseDirSearch(dsp);
3723 cm_ReleaseSCache(scp);
3724 cm_ReleaseUser(userp);
3728 /* verify that this is a valid path to a directory. I don't know why they
3729 * don't use the get file attributes call.
3731 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3735 cm_scache_t *rootScp;
3736 cm_scache_t *newScp;
3745 pathp = smb_GetSMBData(inp, NULL);
3746 pathp = smb_ParseASCIIBlock(pathp, NULL);
3747 osi_Log1(smb_logp, "SMB receive check path %s",
3748 osi_LogSaveString(smb_logp, pathp));
3751 return CM_ERROR_BADFD;
3754 rootScp = cm_rootSCachep;
3756 userp = smb_GetUser(vcp, inp);
3758 caseFold = CM_FLAG_CASEFOLD;
3760 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3762 cm_ReleaseUser(userp);
3763 return CM_ERROR_NOSUCHPATH;
3765 code = cm_NameI(rootScp, pathp,
3766 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3767 userp, tidPathp, &req, &newScp);
3770 cm_ReleaseUser(userp);
3774 /* now lock the vnode with a callback; returns with newScp locked */
3775 lock_ObtainMutex(&newScp->mx);
3776 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3777 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3778 if (code && code != CM_ERROR_NOACCESS) {
3779 lock_ReleaseMutex(&newScp->mx);
3780 cm_ReleaseSCache(newScp);
3781 cm_ReleaseUser(userp);
3785 attrs = smb_Attributes(newScp);
3787 if (!(attrs & 0x10))
3788 code = CM_ERROR_NOTDIR;
3790 lock_ReleaseMutex(&newScp->mx);
3792 cm_ReleaseSCache(newScp);
3793 cm_ReleaseUser(userp);
3797 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3801 cm_scache_t *rootScp;
3802 unsigned short attribute;
3804 cm_scache_t *newScp;
3813 /* decode basic attributes we're passed */
3814 attribute = smb_GetSMBParm(inp, 0);
3815 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3817 pathp = smb_GetSMBData(inp, NULL);
3818 pathp = smb_ParseASCIIBlock(pathp, NULL);
3821 return CM_ERROR_BADSMB;
3824 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3825 dosTime, attribute);
3827 rootScp = cm_rootSCachep;
3829 userp = smb_GetUser(vcp, inp);
3831 caseFold = CM_FLAG_CASEFOLD;
3833 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3835 cm_ReleaseUser(userp);
3836 return CM_ERROR_NOSUCHFILE;
3838 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3839 tidPathp, &req, &newScp);
3842 cm_ReleaseUser(userp);
3846 /* now lock the vnode with a callback; returns with newScp locked; we
3847 * need the current status to determine what the new status is, in some
3850 lock_ObtainMutex(&newScp->mx);
3851 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3852 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3854 lock_ReleaseMutex(&newScp->mx);
3855 cm_ReleaseSCache(newScp);
3856 cm_ReleaseUser(userp);
3860 /* Check for RO volume */
3861 if (newScp->flags & CM_SCACHEFLAG_RO) {
3862 lock_ReleaseMutex(&newScp->mx);
3863 cm_ReleaseSCache(newScp);
3864 cm_ReleaseUser(userp);
3865 return CM_ERROR_READONLY;
3868 /* prepare for setattr call */
3871 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3872 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3874 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3875 /* we're told to make a writable file read-only */
3876 attr.unixModeBits = newScp->unixModeBits & ~0222;
3877 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3879 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3880 /* we're told to make a read-only file writable */
3881 attr.unixModeBits = newScp->unixModeBits | 0222;
3882 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3884 lock_ReleaseMutex(&newScp->mx);
3886 /* now call setattr */
3888 code = cm_SetAttr(newScp, &attr, userp, &req);
3892 cm_ReleaseSCache(newScp);
3893 cm_ReleaseUser(userp);
3898 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3902 cm_scache_t *rootScp;
3903 cm_scache_t *newScp, *dscp;
3915 pathp = smb_GetSMBData(inp, NULL);
3916 pathp = smb_ParseASCIIBlock(pathp, NULL);
3919 return CM_ERROR_BADSMB;
3922 if (*pathp == 0) /* null path */
3925 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3926 osi_LogSaveString(smb_logp, pathp));
3928 rootScp = cm_rootSCachep;
3930 userp = smb_GetUser(vcp, inp);
3932 /* we shouldn't need this for V3 requests, but we seem to */
3933 caseFold = CM_FLAG_CASEFOLD;
3935 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3937 cm_ReleaseUser(userp);
3938 return CM_ERROR_NOSUCHFILE;
3942 * XXX Strange hack XXX
3944 * As of Patch 5 (16 July 97), we are having the following problem:
3945 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3946 * requests to look up "desktop.ini" in all the subdirectories.
3947 * This can cause zillions of timeouts looking up non-existent cells
3948 * and volumes, especially in the top-level directory.
3950 * We have not found any way to avoid this or work around it except
3951 * to explicitly ignore the requests for mount points that haven't
3952 * yet been evaluated and for directories that haven't yet been
3955 * We should modify this hack to provide a fake desktop.ini file
3956 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3958 spacep = inp->spacep;
3959 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3960 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3961 code = cm_NameI(rootScp, spacep->data,
3962 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3963 userp, tidPathp, &req, &dscp);
3965 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3966 && !dscp->mountRootFidp)
3967 code = CM_ERROR_NOSUCHFILE;
3968 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3969 cm_buf_t *bp = buf_Find(dscp, &hzero);
3973 code = CM_ERROR_NOSUCHFILE;
3975 cm_ReleaseSCache(dscp);
3977 cm_ReleaseUser(userp);
3983 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3984 tidPathp, &req, &newScp);
3987 cm_ReleaseUser(userp);
3991 /* now lock the vnode with a callback; returns with newScp locked */
3992 lock_ObtainMutex(&newScp->mx);
3993 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3994 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3996 lock_ReleaseMutex(&newScp->mx);
3997 cm_ReleaseSCache(newScp);
3998 cm_ReleaseUser(userp);
4003 /* use smb_Attributes instead. Also the fact that a file is
4004 * in a readonly volume doesn't mean it shojuld be marked as RO
4006 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
4007 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4008 attrs = SMB_ATTR_DIRECTORY;
4011 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4012 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4014 attrs = smb_Attributes(newScp);
4017 smb_SetSMBParm(outp, 0, attrs);
4019 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4020 smb_SetSMBParm(outp, 1, dosTime & 0xffff);
4021 smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
4022 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4023 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4024 smb_SetSMBParm(outp, 5, 0);
4025 smb_SetSMBParm(outp, 6, 0);
4026 smb_SetSMBParm(outp, 7, 0);
4027 smb_SetSMBParm(outp, 8, 0);
4028 smb_SetSMBParm(outp, 9, 0);
4029 smb_SetSMBDataLength(outp, 0);
4030 lock_ReleaseMutex(&newScp->mx);
4032 cm_ReleaseSCache(newScp);
4033 cm_ReleaseUser(userp);
4038 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4042 osi_Log0(smb_logp, "SMB receive tree disconnect");
4044 /* find the tree and free it */
4045 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4047 lock_ObtainMutex(&tidp->mx);
4048 tidp->flags |= SMB_TIDFLAG_DELETE;
4049 lock_ReleaseMutex(&tidp->mx);
4050 smb_ReleaseTID(tidp);
4056 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4074 pathp = smb_GetSMBData(inp, NULL);
4075 pathp = smb_ParseASCIIBlock(pathp, NULL);
4077 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4079 #ifdef DEBUG_VERBOSE
4083 hexpath = osi_HexifyString( pathp );
4084 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4089 share = smb_GetSMBParm(inp, 0);
4090 attribute = smb_GetSMBParm(inp, 1);
4092 spacep = inp->spacep;
4093 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4094 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4095 /* special case magic file name for receiving IOCTL requests
4096 * (since IOCTL calls themselves aren't getting through).
4098 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4099 smb_SetupIoctlFid(fidp, spacep);
4100 smb_SetSMBParm(outp, 0, fidp->fid);
4101 smb_SetSMBParm(outp, 1, 0); /* attrs */
4102 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4103 smb_SetSMBParm(outp, 3, 0);
4104 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4105 smb_SetSMBParm(outp, 5, 0x7fff);
4106 /* pass the open mode back */
4107 smb_SetSMBParm(outp, 6, (share & 0xf));
4108 smb_SetSMBDataLength(outp, 0);
4109 smb_ReleaseFID(fidp);
4113 userp = smb_GetUser(vcp, inp);
4115 caseFold = CM_FLAG_CASEFOLD;
4117 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4119 cm_ReleaseUser(userp);
4120 return CM_ERROR_NOSUCHPATH;
4122 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4123 tidPathp, &req, &scp);
4126 cm_ReleaseUser(userp);
4130 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4132 cm_ReleaseSCache(scp);
4133 cm_ReleaseUser(userp);
4137 /* don't need callback to check file type, since file types never
4138 * change, and namei and cm_Lookup all stat the object at least once on
4139 * a successful return.
4141 if (scp->fileType != CM_SCACHETYPE_FILE) {
4142 cm_ReleaseSCache(scp);
4143 cm_ReleaseUser(userp);
4144 return CM_ERROR_ISDIR;
4147 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4150 /* save a pointer to the vnode */
4153 if ((share & 0xf) == 0)
4154 fidp->flags |= SMB_FID_OPENREAD;
4155 else if ((share & 0xf) == 1)
4156 fidp->flags |= SMB_FID_OPENWRITE;
4158 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4160 lock_ObtainMutex(&scp->mx);
4161 smb_SetSMBParm(outp, 0, fidp->fid);
4162 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4163 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4164 smb_SetSMBParm(outp, 2, dosTime & 0xffff);
4165 smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
4166 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4167 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4168 /* pass the open mode back; XXXX add access checks */
4169 smb_SetSMBParm(outp, 6, (share & 0xf));
4170 smb_SetSMBDataLength(outp, 0);
4171 lock_ReleaseMutex(&scp->mx);
4174 cm_Open(scp, 0, userp);
4176 /* send and free packet */
4177 smb_ReleaseFID(fidp);
4178 cm_ReleaseUser(userp);
4179 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4183 typedef struct smb_unlinkRock {
4188 char *maskp; /* pointer to the star pattern */
4193 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4196 smb_unlinkRock_t *rockp;
4204 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4205 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4206 caseFold |= CM_FLAG_8DOT3;
4208 matchName = dep->name;
4209 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4211 && (rockp->flags & SMB_MASKFLAG_TILDE)
4212 && !cm_Is8Dot3(dep->name)) {
4213 cm_Gen8Dot3Name(dep, shortName, NULL);
4214 matchName = shortName;
4215 /* 8.3 matches are always case insensitive */
4216 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4219 osi_Log1(smb_logp, "Unlinking %s",
4220 osi_LogSaveString(smb_logp, matchName));
4221 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4222 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4223 smb_NotifyChange(FILE_ACTION_REMOVED,
4224 FILE_NOTIFY_CHANGE_FILE_NAME,
4225 dscp, dep->name, NULL, TRUE);
4228 /* If we made a case sensitive exact match, we might as well quit now. */
4229 if(!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4230 code = CM_ERROR_STOPNOW;
4238 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4247 smb_unlinkRock_t rock;
4256 attribute = smb_GetSMBParm(inp, 0);
4258 tp = smb_GetSMBData(inp, NULL);
4259 pathp = smb_ParseASCIIBlock(tp, &tp);
4261 osi_Log1(smb_logp, "SMB receive unlink %s",
4262 osi_LogSaveString(smb_logp, pathp));
4264 spacep = inp->spacep;
4265 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4267 userp = smb_GetUser(vcp, inp);
4269 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4271 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4273 cm_ReleaseUser(userp);
4274 return CM_ERROR_NOSUCHPATH;
4276 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4280 cm_ReleaseUser(userp);
4284 /* otherwise, scp points to the parent directory. */
4291 rock.maskp = smb_FindMask(pathp);
4292 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4295 thyper.HighPart = 0;
4301 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4302 * match. If that fails, we do a case insensitve match.
4304 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4305 !smb_IsStarMask(rock.maskp)) {
4306 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4309 thyper.HighPart = 0;
4310 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4315 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4317 if (code == CM_ERROR_STOPNOW)
4320 cm_ReleaseUser(userp);
4322 cm_ReleaseSCache(dscp);
4324 if (code == 0 && !rock.any)
4325 code = CM_ERROR_NOSUCHFILE;
4329 typedef struct smb_renameRock {
4330 cm_scache_t *odscp; /* old dir */
4331 cm_scache_t *ndscp; /* new dir */
4332 cm_user_t *userp; /* user */
4333 cm_req_t *reqp; /* request struct */
4334 smb_vc_t *vcp; /* virtual circuit */
4335 char *maskp; /* pointer to star pattern of old file name */
4336 int flags; /* tilde, casefold, etc */
4337 char *newNamep; /* ptr to the new file's name */
4340 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4343 smb_renameRock_t *rockp;
4348 rockp = (smb_renameRock_t *) vrockp;
4350 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4351 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4352 caseFold |= CM_FLAG_8DOT3;
4354 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4356 && (rockp->flags & SMB_MASKFLAG_TILDE)
4357 && !cm_Is8Dot3(dep->name)) {
4358 cm_Gen8Dot3Name(dep, shortName, NULL);
4359 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4362 code = cm_Rename(rockp->odscp, dep->name,
4363 rockp->ndscp, rockp->newNamep, rockp->userp,
4365 /* if the call worked, stop doing the search now, since we
4366 * really only want to rename one file.
4369 code = CM_ERROR_STOPNOW;
4376 long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4382 cm_space_t *spacep = NULL;
4383 smb_renameRock_t rock;
4384 cm_scache_t *oldDscp = NULL;
4385 cm_scache_t *newDscp = NULL;
4386 cm_scache_t *tmpscp= NULL;
4387 cm_scache_t *tmpscp2 = NULL;
4399 tp = smb_GetSMBData(inp, NULL);
4400 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4401 newPathp = smb_ParseASCIIBlock(tp, &tp);
4403 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4404 osi_LogSaveString(smb_logp, oldPathp),
4405 osi_LogSaveString(smb_logp, newPathp));
4407 spacep = inp->spacep;
4408 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4410 userp = smb_GetUser(vcp, inp);
4413 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4414 * what actually exists is foo/baz. I don't know why the code used to be
4415 * the way it was. 1/29/96
4417 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4419 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4421 * caseFold = CM_FLAG_CASEFOLD;
4423 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4425 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4427 cm_ReleaseUser(userp);
4428 return CM_ERROR_NOSUCHPATH;
4430 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4431 userp, tidPathp, &req, &oldDscp);
4434 cm_ReleaseUser(userp);
4438 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4439 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4440 userp, tidPathp, &req, &newDscp);
4443 cm_ReleaseSCache(oldDscp);
4444 cm_ReleaseUser(userp);
4448 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4449 * next, get the component names, and lower case them.
4452 /* handle the old name first */
4454 oldLastNamep = oldPathp;
4458 /* and handle the new name, too */
4460 newLastNamep = newPathp;
4464 /* TODO: The old name could be a wildcard. The new name must not be */
4466 /* do the vnode call */
4467 rock.odscp = oldDscp;
4468 rock.ndscp = newDscp;
4472 rock.maskp = oldLastNamep;
4473 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4474 rock.newNamep = newLastNamep;
4476 /* Check if the file already exists; if so return error */
4477 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4478 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4479 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4480 osi_LogSaveString(afsd_logp, newLastNamep));
4482 /* Check if the old and the new names differ only in case. If so return
4483 * success, else return CM_ERROR_EXISTS
4485 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4487 /* This would be a success only if the old file is *as same as* the new file */
4488 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4490 if (tmpscp == tmpscp2)
4493 code = CM_ERROR_EXISTS;
4494 cm_ReleaseSCache(tmpscp2);
4497 code = CM_ERROR_NOSUCHFILE;
4500 /* file exist, do not rename, also fixes move */
4501 osi_Log0(smb_logp, "Can't rename. Target already exists");
4502 code = CM_ERROR_EXISTS;
4506 cm_ReleaseSCache(tmpscp);
4507 cm_ReleaseSCache(newDscp);
4508 cm_ReleaseSCache(oldDscp);
4509 cm_ReleaseUser(userp);
4513 /* Now search the directory for the pattern, and do the appropriate rename when found */
4514 thyper.LowPart = 0; /* search dir from here */
4515 thyper.HighPart = 0;
4517 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4519 if (code == CM_ERROR_STOPNOW)
4522 code = CM_ERROR_NOSUCHFILE;
4524 /* Handle Change Notification */
4526 * Being lazy, not distinguishing between files and dirs in this
4527 * filter, since we'd have to do a lookup.
4529 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4530 if (oldDscp == newDscp) {
4531 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4532 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4533 filter, oldDscp, oldLastNamep,
4534 newLastNamep, TRUE);
4536 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4537 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4538 filter, oldDscp, oldLastNamep,
4540 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4541 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4542 filter, newDscp, newLastNamep,
4547 cm_ReleaseSCache(tmpscp);
4548 cm_ReleaseUser(userp);
4549 cm_ReleaseSCache(oldDscp);
4550 cm_ReleaseSCache(newDscp);
4554 typedef struct smb_rmdirRock {
4558 char *maskp; /* pointer to the star pattern */
4563 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4566 smb_rmdirRock_t *rockp;
4571 rockp = (smb_rmdirRock_t *) vrockp;
4573 matchName = dep->name;
4574 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4575 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4577 match = (strcmp(matchName, rockp->maskp) == 0);
4579 && (rockp->flags & SMB_MASKFLAG_TILDE)
4580 && !cm_Is8Dot3(dep->name)) {
4581 cm_Gen8Dot3Name(dep, shortName, NULL);
4582 matchName = shortName;
4583 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4586 osi_Log1(smb_logp, "Removing directory %s",
4587 osi_LogSaveString(smb_logp, matchName));
4588 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4589 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4590 smb_NotifyChange(FILE_ACTION_REMOVED,
4591 FILE_NOTIFY_CHANGE_DIR_NAME,
4592 dscp, dep->name, NULL, TRUE);
4601 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4609 smb_rmdirRock_t rock;
4618 tp = smb_GetSMBData(inp, NULL);
4619 pathp = smb_ParseASCIIBlock(tp, &tp);
4621 spacep = inp->spacep;
4622 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4624 userp = smb_GetUser(vcp, inp);
4626 caseFold = CM_FLAG_CASEFOLD;
4628 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4630 cm_ReleaseUser(userp);
4631 return CM_ERROR_NOSUCHPATH;
4633 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4634 userp, tidPathp, &req, &dscp);
4637 cm_ReleaseUser(userp);
4641 /* otherwise, scp points to the parent directory. */
4648 rock.maskp = lastNamep;
4649 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4652 thyper.HighPart = 0;
4656 /* First do a case sensitive match, and if that fails, do a case insensitive match */
4657 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4658 if (code == 0 && !rock.any) {
4660 thyper.HighPart = 0;
4661 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4662 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4665 cm_ReleaseUser(userp);
4667 cm_ReleaseSCache(dscp);
4669 if (code == 0 && !rock.any)
4670 code = CM_ERROR_NOSUCHFILE;
4674 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4684 fid = smb_GetSMBParm(inp, 0);
4686 osi_Log1(smb_logp, "SMB flush fid %d", fid);
4688 fid = smb_ChainFID(fid, inp);
4689 fidp = smb_FindFID(vcp, fid, 0);
4690 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4692 smb_ReleaseFID(fidp);
4693 return CM_ERROR_BADFD;
4696 userp = smb_GetUser(vcp, inp);
4698 lock_ObtainMutex(&fidp->mx);
4699 if (fidp->flags & SMB_FID_OPENWRITE)
4700 code = cm_FSync(fidp->scp, userp, &req);
4703 lock_ReleaseMutex(&fidp->mx);
4705 smb_ReleaseFID(fidp);
4707 cm_ReleaseUser(userp);
4712 struct smb_FullNameRock {
4718 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4722 struct smb_FullNameRock *vrockp;
4724 vrockp = (struct smb_FullNameRock *)rockp;
4726 if (!cm_Is8Dot3(dep->name)) {
4727 cm_Gen8Dot3Name(dep, shortName, NULL);
4729 if (cm_stricmp(shortName, vrockp->name) == 0) {
4730 vrockp->fullName = strdup(dep->name);
4731 return CM_ERROR_STOPNOW;
4734 if (cm_stricmp(dep->name, vrockp->name) == 0
4735 && ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode
4736 && ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4737 vrockp->fullName = strdup(dep->name);
4738 return CM_ERROR_STOPNOW;
4743 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4744 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4746 struct smb_FullNameRock rock;
4752 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL,
4754 if (code == CM_ERROR_STOPNOW)
4755 *newPathp = rock.fullName;
4757 *newPathp = strdup(pathp);
4760 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4771 fid = smb_GetSMBParm(inp, 0);
4772 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4774 osi_Log1(smb_logp, "SMB close fid %d", fid);
4776 fid = smb_ChainFID(fid, inp);
4777 fidp = smb_FindFID(vcp, fid, 0);
4779 return CM_ERROR_BADFD;
4782 userp = smb_GetUser(vcp, inp);
4784 lock_ObtainMutex(&fidp->mx);
4786 /* Don't jump the gun on an async raw write */
4787 while (fidp->raw_writers) {
4788 lock_ReleaseMutex(&fidp->mx);
4789 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4790 lock_ObtainMutex(&fidp->mx);
4793 fidp->flags |= SMB_FID_DELETE;
4795 /* watch for ioctl closes, and read-only opens */
4796 if (fidp->scp != NULL
4797 && (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4798 == SMB_FID_OPENWRITE) {
4799 if (dosTime != 0 && dosTime != -1) {
4800 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4801 /* This fixes defect 10958 */
4802 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
4803 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
4805 code = cm_FSync(fidp->scp, userp, &req);
4810 if (fidp->flags & SMB_FID_DELONCLOSE) {
4811 cm_scache_t *dscp = fidp->NTopen_dscp;
4812 char *pathp = fidp->NTopen_pathp;
4815 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
4816 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
4817 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
4818 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4819 smb_NotifyChange(FILE_ACTION_REMOVED,
4820 FILE_NOTIFY_CHANGE_DIR_NAME,
4821 dscp, fullPathp, NULL, TRUE);
4825 code = cm_Unlink(dscp, fullPathp, userp, &req);
4826 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4827 smb_NotifyChange(FILE_ACTION_REMOVED,
4828 FILE_NOTIFY_CHANGE_FILE_NAME,
4829 dscp, fullPathp, NULL, TRUE);
4833 lock_ReleaseMutex(&fidp->mx);
4835 if (fidp->flags & SMB_FID_NTOPEN) {
4836 cm_ReleaseSCache(fidp->NTopen_dscp);
4837 free(fidp->NTopen_pathp);
4839 if (fidp->NTopen_wholepathp)
4840 free(fidp->NTopen_wholepathp);
4842 smb_ReleaseFID(fidp);
4843 cm_ReleaseUser(userp);
4848 * smb_ReadData -- common code for Read, Read And X, and Raw Read
4851 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4852 cm_user_t *userp, long *readp)
4854 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4855 cm_user_t *userp, long *readp, int dosflag)
4862 osi_hyper_t fileLength;
4864 osi_hyper_t lastByte;
4865 osi_hyper_t bufferOffset;
4866 long bufIndex, nbytes;
4876 lock_ObtainMutex(&fidp->mx);
4878 lock_ObtainMutex(&scp->mx);
4880 if (offset.HighPart == 0) {
4881 chunk = offset.LowPart >> cm_logChunkSize;
4882 if (chunk != fidp->curr_chunk) {
4883 fidp->prev_chunk = fidp->curr_chunk;
4884 fidp->curr_chunk = chunk;
4886 if (fidp->curr_chunk == fidp->prev_chunk + 1)
4890 /* start by looking up the file's end */
4891 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4892 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4893 if (code) goto done;
4895 /* now we have the entry locked, look up the length */
4896 fileLength = scp->length;
4898 /* adjust count down so that it won't go past EOF */
4899 thyper.LowPart = count;
4900 thyper.HighPart = 0;
4901 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
4903 if (LargeIntegerGreaterThan(thyper, fileLength)) {
4904 /* we'd read past EOF, so just stop at fileLength bytes.
4905 * Start by computing how many bytes remain in the file.
4907 thyper = LargeIntegerSubtract(fileLength, offset);
4909 /* if we are past EOF, read 0 bytes */
4910 if (LargeIntegerLessThanZero(thyper))
4913 count = thyper.LowPart;
4918 /* now, copy the data one buffer at a time,
4919 * until we've filled the request packet
4922 /* if we've copied all the data requested, we're done */
4923 if (count <= 0) break;
4925 /* otherwise, load up a buffer of data */
4926 thyper.HighPart = offset.HighPart;
4927 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4928 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4931 buf_Release(bufferp);
4934 lock_ReleaseMutex(&scp->mx);
4936 lock_ObtainRead(&scp->bufCreateLock);
4937 code = buf_Get(scp, &thyper, &bufferp);
4938 lock_ReleaseRead(&scp->bufCreateLock);
4940 lock_ObtainMutex(&scp->mx);
4941 if (code) goto done;
4942 bufferOffset = thyper;
4944 /* now get the data in the cache */
4946 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4947 CM_SCACHESYNC_NEEDCALLBACK
4948 | CM_SCACHESYNC_READ);
4949 if (code) goto done;
4951 if (cm_HaveBuffer(scp, bufferp, 0)) break;
4953 /* otherwise, load the buffer and try again */
4954 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4958 buf_Release(bufferp);
4962 } /* if (wrong buffer) ... */
4964 /* now we have the right buffer loaded. Copy out the
4965 * data from here to the user's buffer.
4967 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4969 /* and figure out how many bytes we want from this buffer */
4970 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
4971 if (nbytes > count) nbytes = count; /* don't go past EOF */
4973 /* now copy the data */
4976 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
4979 memcpy(op, bufferp->datap + bufIndex, nbytes);
4981 /* adjust counters, pointers, etc. */
4984 thyper.LowPart = nbytes;
4985 thyper.HighPart = 0;
4986 offset = LargeIntegerAdd(thyper, offset);
4990 lock_ReleaseMutex(&scp->mx);
4991 lock_ReleaseMutex(&fidp->mx);
4993 buf_Release(bufferp);
4995 if (code == 0 && sequential)
4996 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5002 * smb_WriteData -- common code for Write and Raw Write
5005 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5006 cm_user_t *userp, long *writtenp)
5008 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5009 cm_user_t *userp, long *writtenp, int dosflag)
5016 osi_hyper_t fileLength; /* file's length at start of write */
5017 osi_hyper_t minLength; /* don't read past this */
5018 long nbytes; /* # of bytes to transfer this iteration */
5020 osi_hyper_t thyper; /* hyper tmp variable */
5021 osi_hyper_t bufferOffset;
5022 long bufIndex; /* index in buffer where our data is */
5024 osi_hyper_t writeBackOffset; /* offset of region to write back when
5029 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5030 fidp->fid, offsetp->LowPart, count);
5038 lock_ObtainMutex(&fidp->mx);
5040 lock_ObtainMutex(&scp->mx);
5042 /* start by looking up the file's end */
5043 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5045 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5046 CM_SCACHESYNC_NEEDCALLBACK
5047 | CM_SCACHESYNC_SETSTATUS
5048 | CM_SCACHESYNC_GETSTATUS);
5049 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5054 /* make sure we have a writable FD */
5055 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5056 code = CM_ERROR_BADFDOP;
5060 /* now we have the entry locked, look up the length */
5061 fileLength = scp->length;
5062 minLength = fileLength;
5063 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5064 minLength = scp->serverLength;
5066 /* adjust file length if we extend past EOF */
5067 thyper.LowPart = count;
5068 thyper.HighPart = 0;
5069 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5070 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5071 /* we'd write past EOF, so extend the file */
5072 scp->mask |= CM_SCACHEMASK_LENGTH;
5073 scp->length = thyper;
5074 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5076 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5078 /* now, if the new position (thyper) and the old (offset) are in
5079 * different storeback windows, remember to store back the previous
5080 * storeback window when we're done with the write.
5082 if ((thyper.LowPart & (-cm_chunkSize)) !=
5083 (offset.LowPart & (-cm_chunkSize))) {
5084 /* they're different */
5086 writeBackOffset.HighPart = offset.HighPart;
5087 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5092 /* now, copy the data one buffer at a time, until we've filled the
5095 /* if we've copied all the data requested, we're done */
5096 if (count <= 0) break;
5098 /* handle over quota or out of space */
5099 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5100 *writtenp = written;
5104 /* otherwise, load up a buffer of data */
5105 thyper.HighPart = offset.HighPart;
5106 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5107 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5110 lock_ReleaseMutex(&bufferp->mx);
5111 buf_Release(bufferp);
5114 lock_ReleaseMutex(&scp->mx);
5116 lock_ObtainRead(&scp->bufCreateLock);
5117 code = buf_Get(scp, &thyper, &bufferp);
5118 lock_ReleaseRead(&scp->bufCreateLock);
5120 lock_ObtainMutex(&bufferp->mx);
5121 lock_ObtainMutex(&scp->mx);
5122 if (code) goto done;
5124 bufferOffset = thyper;
5126 /* now get the data in the cache */
5128 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5130 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5131 CM_SCACHESYNC_NEEDCALLBACK
5132 | CM_SCACHESYNC_WRITE
5133 | CM_SCACHESYNC_BUFLOCKED);
5134 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5139 /* If we're overwriting the entire buffer, or
5140 * if we're writing at or past EOF, mark the
5141 * buffer as current so we don't call
5142 * cm_GetBuffer. This skips the fetch from the
5143 * server in those cases where we're going to
5144 * obliterate all the data in the buffer anyway,
5145 * or in those cases where there is no useful
5146 * data at the server to start with.
5148 * Use minLength instead of scp->length, since
5149 * the latter has already been updated by this
5152 if (LargeIntegerGreaterThanOrEqualTo(
5153 bufferp->offset, minLength)
5154 || LargeIntegerEqualTo(offset, bufferp->offset)
5155 && (count >= buf_bufferSize
5156 || LargeIntegerGreaterThanOrEqualTo(
5157 LargeIntegerAdd(offset,
5158 ConvertLongToLargeInteger(count)),
5160 if (count < buf_bufferSize
5161 && bufferp->dataVersion == -1)
5162 memset(bufferp->datap, 0,
5164 bufferp->dataVersion = scp->dataVersion;
5167 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5169 /* otherwise, load the buffer and try again */
5170 lock_ReleaseMutex(&bufferp->mx);
5171 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5173 lock_ReleaseMutex(&scp->mx);
5174 lock_ObtainMutex(&bufferp->mx);
5175 lock_ObtainMutex(&scp->mx);
5179 lock_ReleaseMutex(&bufferp->mx);
5180 buf_Release(bufferp);
5184 } /* if (wrong buffer) ... */
5186 /* now we have the right buffer loaded. Copy out the
5187 * data from here to the user's buffer.
5189 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5191 /* and figure out how many bytes we want from this buffer */
5192 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5194 nbytes = count; /* don't go past end of request */
5196 /* now copy the data */
5199 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5202 memcpy(bufferp->datap + bufIndex, op, nbytes);
5203 buf_SetDirty(bufferp);
5205 /* and record the last writer */
5206 if (bufferp->userp != userp) {
5209 cm_ReleaseUser(bufferp->userp);
5210 bufferp->userp = userp;
5213 /* adjust counters, pointers, etc. */
5217 thyper.LowPart = nbytes;
5218 thyper.HighPart = 0;
5219 offset = LargeIntegerAdd(thyper, offset);
5223 lock_ReleaseMutex(&scp->mx);
5224 lock_ReleaseMutex(&fidp->mx);
5226 lock_ReleaseMutex(&bufferp->mx);
5227 buf_Release(bufferp);
5230 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5231 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5232 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5233 fidp->NTopen_dscp, fidp->NTopen_pathp,
5237 if (code == 0 && doWriteBack) {
5239 lock_ObtainMutex(&scp->mx);
5240 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5242 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5243 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5245 lock_ReleaseMutex(&scp->mx);
5246 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5247 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5250 osi_Log2(smb_logp, "smb_WriteData fid %d returns %d",
5255 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5258 long count, written = 0;
5263 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5265 int inDataBlockCount;
5267 fd = smb_GetSMBParm(inp, 0);
5268 count = smb_GetSMBParm(inp, 1);
5269 offset.HighPart = 0; /* too bad */
5270 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5272 op = smb_GetSMBData(inp, NULL);
5273 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5275 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5276 fd, offset.LowPart, count);
5278 fd = smb_ChainFID(fd, inp);
5279 fidp = smb_FindFID(vcp, fd, 0);
5281 return CM_ERROR_BADFD;
5284 if (fidp->flags & SMB_FID_IOCTL)
5285 return smb_IoctlWrite(fidp, vcp, inp, outp);
5287 userp = smb_GetUser(vcp, inp);
5289 /* special case: 0 bytes transferred means truncate to this position */
5295 truncAttr.mask = CM_ATTRMASK_LENGTH;
5296 truncAttr.length.LowPart = offset.LowPart;
5297 truncAttr.length.HighPart = 0;
5298 lock_ObtainMutex(&fidp->mx);
5299 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5300 lock_ReleaseMutex(&fidp->mx);
5301 smb_SetSMBParm(outp, 0, /* count */ 0);
5302 smb_SetSMBDataLength(outp, 0);
5303 fidp->flags |= SMB_FID_LENGTHSETDONE;
5308 * Work around bug in NT client
5310 * When copying a file, the NT client should first copy the data,
5311 * then copy the last write time. But sometimes the NT client does
5312 * these in the wrong order, so the data copies would inadvertently
5313 * cause the last write time to be overwritten. We try to detect this,
5314 * and don't set client mod time if we think that would go against the
5317 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5318 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5319 fidp->scp->clientModTime = time(NULL);
5323 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5325 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5327 if (code == 0 && written < count)
5328 code = CM_ERROR_PARTIALWRITE;
5330 /* set the packet data length to 3 bytes for the data block header,
5331 * plus the size of the data.
5333 smb_SetSMBParm(outp, 0, written);
5334 smb_SetSMBDataLength(outp, 0);
5337 smb_ReleaseFID(fidp);
5338 cm_ReleaseUser(userp);
5343 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5344 NCB *ncbp, raw_write_cont_t *rwcp)
5357 fd = smb_GetSMBParm(inp, 0);
5358 fidp = smb_FindFID(vcp, fd, 0);
5360 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5361 rwcp->offset.LowPart, rwcp->count);
5363 userp = smb_GetUser(vcp, inp);
5367 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5370 rawBuf = (dos_ptr) rwcp->buf;
5371 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5372 (unsigned char *) rawBuf, userp,
5376 if (rwcp->writeMode & 0x1) { /* synchronous */
5379 smb_FormatResponsePacket(vcp, inp, outp);
5380 op = (smb_t *) outp;
5381 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5382 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5383 smb_SetSMBDataLength(outp, 0);
5384 smb_SendPacket(vcp, outp);
5385 smb_FreePacket(outp);
5387 else { /* asynchronous */
5388 lock_ObtainMutex(&fidp->mx);
5389 fidp->raw_writers--;
5390 if (fidp->raw_writers == 0)
5391 thrd_SetEvent(fidp->raw_write_event);
5392 lock_ReleaseMutex(&fidp->mx);
5395 /* Give back raw buffer */
5396 lock_ObtainMutex(&smb_RawBufLock);
5398 *((char **)rawBuf) = smb_RawBufs;
5400 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5402 smb_RawBufs = rawBuf;
5403 lock_ReleaseMutex(&smb_RawBufLock);
5405 smb_ReleaseFID(fidp);
5406 cm_ReleaseUser(userp);
5409 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5414 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5417 long count, written = 0;
5424 unsigned short writeMode;
5431 fd = smb_GetSMBParm(inp, 0);
5432 totalCount = smb_GetSMBParm(inp, 1);
5433 count = smb_GetSMBParm(inp, 10);
5434 offset.HighPart = 0; /* too bad */
5435 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5436 writeMode = smb_GetSMBParm(inp, 7);
5438 op = (char *) inp->data;
5439 op += smb_GetSMBParm(inp, 11);
5442 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5443 fd, offset.LowPart, count, writeMode);
5445 fd = smb_ChainFID(fd, inp);
5446 fidp = smb_FindFID(vcp, fd, 0);
5448 return CM_ERROR_BADFD;
5451 userp = smb_GetUser(vcp, inp);
5454 * Work around bug in NT client
5456 * When copying a file, the NT client should first copy the data,
5457 * then copy the last write time. But sometimes the NT client does
5458 * these in the wrong order, so the data copies would inadvertently
5459 * cause the last write time to be overwritten. We try to detect this,
5460 * and don't set client mod time if we think that would go against the
5463 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5464 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5465 fidp->scp->clientModTime = time(NULL);
5469 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5471 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5473 if (code == 0 && written < count)
5474 code = CM_ERROR_PARTIALWRITE;
5476 /* Get a raw buffer */
5479 lock_ObtainMutex(&smb_RawBufLock);
5481 /* Get a raw buf, from head of list */
5482 rawBuf = smb_RawBufs;
5484 smb_RawBufs = *(char **)smb_RawBufs;
5486 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5490 code = CM_ERROR_USESTD;
5492 lock_ReleaseMutex(&smb_RawBufLock);
5495 /* Don't allow a premature Close */
5496 if (code == 0 && (writeMode & 1) == 0) {
5497 lock_ObtainMutex(&fidp->mx);
5498 fidp->raw_writers++;
5499 thrd_ResetEvent(fidp->raw_write_event);
5500 lock_ReleaseMutex(&fidp->mx);
5503 smb_ReleaseFID(fidp);
5504 cm_ReleaseUser(userp);
5507 smb_SetSMBParm(outp, 0, written);
5508 smb_SetSMBDataLength(outp, 0);
5509 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5516 rwcp->offset.HighPart = 0;
5517 rwcp->offset.LowPart = offset.LowPart + count;
5518 rwcp->count = totalCount - count;
5519 rwcp->writeMode = writeMode;
5520 rwcp->alreadyWritten = written;
5522 /* set the packet data length to 3 bytes for the data block header,
5523 * plus the size of the data.
5525 smb_SetSMBParm(outp, 0, 0xffff);
5526 smb_SetSMBDataLength(outp, 0);
5531 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5534 long count, finalCount;
5541 fd = smb_GetSMBParm(inp, 0);
5542 count = smb_GetSMBParm(inp, 1);
5543 offset.HighPart = 0; /* too bad */
5544 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5546 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5547 fd, offset.LowPart, count);
5549 fd = smb_ChainFID(fd, inp);
5550 fidp = smb_FindFID(vcp, fd, 0);
5552 return CM_ERROR_BADFD;
5555 if (fidp->flags & SMB_FID_IOCTL) {
5556 return smb_IoctlRead(fidp, vcp, inp, outp);
5559 userp = smb_GetUser(vcp, inp);
5561 /* remember this for final results */
5562 smb_SetSMBParm(outp, 0, count);
5563 smb_SetSMBParm(outp, 1, 0);
5564 smb_SetSMBParm(outp, 2, 0);
5565 smb_SetSMBParm(outp, 3, 0);
5566 smb_SetSMBParm(outp, 4, 0);
5568 /* set the packet data length to 3 bytes for the data block header,
5569 * plus the size of the data.
5571 smb_SetSMBDataLength(outp, count+3);
5573 /* get op ptr after putting in the parms, since otherwise we don't
5574 * know where the data really is.
5576 op = smb_GetSMBData(outp, NULL);
5578 /* now emit the data block header: 1 byte of type and 2 bytes of length */
5579 *op++ = 1; /* data block marker */
5580 *op++ = (unsigned char) (count & 0xff);
5581 *op++ = (unsigned char) ((count >> 8) & 0xff);
5584 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5586 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5589 /* fix some things up */
5590 smb_SetSMBParm(outp, 0, finalCount);
5591 smb_SetSMBDataLength(outp, finalCount+3);
5593 smb_ReleaseFID(fidp);
5595 cm_ReleaseUser(userp);
5599 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5606 cm_scache_t *dscp; /* dir we're dealing with */
5607 cm_scache_t *scp; /* file we're creating */
5609 int initialModeBits;
5619 /* compute initial mode bits based on read-only flag in attributes */
5620 initialModeBits = 0777;
5622 tp = smb_GetSMBData(inp, NULL);
5623 pathp = smb_ParseASCIIBlock(tp, &tp);
5625 if (strcmp(pathp, "\\") == 0)
5626 return CM_ERROR_EXISTS;
5628 spacep = inp->spacep;
5629 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5631 userp = smb_GetUser(vcp, inp);
5633 caseFold = CM_FLAG_CASEFOLD;
5635 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5637 cm_ReleaseUser(userp);
5638 return CM_ERROR_NOSUCHPATH;
5641 code = cm_NameI(cm_rootSCachep, spacep->data,
5642 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5643 userp, tidPathp, &req, &dscp);
5646 cm_ReleaseUser(userp);
5650 /* otherwise, scp points to the parent directory. Do a lookup, and
5651 * fail if we find it. Otherwise, we do the create.
5657 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5658 if (scp) cm_ReleaseSCache(scp);
5659 if (code != CM_ERROR_NOSUCHFILE) {
5660 if (code == 0) code = CM_ERROR_EXISTS;
5661 cm_ReleaseSCache(dscp);
5662 cm_ReleaseUser(userp);
5666 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5667 setAttr.clientModTime = time(NULL);
5668 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5669 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5670 smb_NotifyChange(FILE_ACTION_ADDED,
5671 FILE_NOTIFY_CHANGE_DIR_NAME,
5672 dscp, lastNamep, NULL, TRUE);
5674 /* we don't need this any longer */
5675 cm_ReleaseSCache(dscp);
5678 /* something went wrong creating or truncating the file */
5679 cm_ReleaseUser(userp);
5683 /* otherwise we succeeded */
5684 smb_SetSMBDataLength(outp, 0);
5685 cm_ReleaseUser(userp);
5690 BOOL smb_IsLegalFilename(char *filename)
5693 * Find the longest substring of filename that does not contain
5694 * any of the chars in illegalChars. If that substring is less
5695 * than the length of the whole string, then one or more of the
5696 * illegal chars is in filename.
5698 if (strcspn(filename, illegalChars) < strlen(filename))
5704 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5712 cm_scache_t *dscp; /* dir we're dealing with */
5713 cm_scache_t *scp; /* file we're creating */
5715 int initialModeBits;
5727 excl = (inp->inCom == 0x03)? 0 : 1;
5729 attributes = smb_GetSMBParm(inp, 0);
5730 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5732 /* compute initial mode bits based on read-only flag in attributes */
5733 initialModeBits = 0666;
5734 if (attributes & 1) initialModeBits &= ~0222;
5736 tp = smb_GetSMBData(inp, NULL);
5737 pathp = smb_ParseASCIIBlock(tp, &tp);
5739 spacep = inp->spacep;
5740 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5742 userp = smb_GetUser(vcp, inp);
5744 caseFold = CM_FLAG_CASEFOLD;
5746 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5748 cm_ReleaseUser(userp);
5749 return CM_ERROR_NOSUCHPATH;
5751 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5752 userp, tidPathp, &req, &dscp);
5755 cm_ReleaseUser(userp);
5759 /* otherwise, scp points to the parent directory. Do a lookup, and
5760 * truncate the file if we find it, otherwise we create the file.
5762 if (!lastNamep) lastNamep = pathp;
5765 if (!smb_IsLegalFilename(lastNamep))
5766 return CM_ERROR_BADNTFILENAME;
5768 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
5769 #ifdef DEBUG_VERBOSE
5772 hexp = osi_HexifyString( lastNamep );
5773 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5778 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5779 if (code && code != CM_ERROR_NOSUCHFILE) {
5780 cm_ReleaseSCache(dscp);
5781 cm_ReleaseUser(userp);
5785 /* if we get here, if code is 0, the file exists and is represented by
5786 * scp. Otherwise, we have to create it.
5790 /* oops, file shouldn't be there */
5791 cm_ReleaseSCache(dscp);
5792 cm_ReleaseSCache(scp);
5793 cm_ReleaseUser(userp);
5794 return CM_ERROR_EXISTS;
5797 setAttr.mask = CM_ATTRMASK_LENGTH;
5798 setAttr.length.LowPart = 0;
5799 setAttr.length.HighPart = 0;
5800 code = cm_SetAttr(scp, &setAttr, userp, &req);
5803 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5804 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5805 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5807 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5808 smb_NotifyChange(FILE_ACTION_ADDED,
5809 FILE_NOTIFY_CHANGE_FILE_NAME,
5810 dscp, lastNamep, NULL, TRUE);
5811 if (!excl && code == CM_ERROR_EXISTS) {
5812 /* not an exclusive create, and someone else tried
5813 * creating it already, then we open it anyway. We
5814 * don't bother retrying after this, since if this next
5815 * fails, that means that the file was deleted after
5816 * we started this call.
5818 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
5821 setAttr.mask = CM_ATTRMASK_LENGTH;
5822 setAttr.length.LowPart = 0;
5823 setAttr.length.HighPart = 0;
5824 code = cm_SetAttr(scp, &setAttr, userp, &req);
5829 /* we don't need this any longer */
5830 cm_ReleaseSCache(dscp);
5833 /* something went wrong creating or truncating the file */
5834 if (scp) cm_ReleaseSCache(scp);
5835 cm_ReleaseUser(userp);
5839 /* make sure we only open files */
5840 if (scp->fileType != CM_SCACHETYPE_FILE) {
5841 cm_ReleaseSCache(scp);
5842 cm_ReleaseUser(userp);
5843 return CM_ERROR_ISDIR;
5846 /* now all we have to do is open the file itself */
5847 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5850 /* save a pointer to the vnode */
5853 /* always create it open for read/write */
5854 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
5856 smb_ReleaseFID(fidp);
5858 smb_SetSMBParm(outp, 0, fidp->fid);
5859 smb_SetSMBDataLength(outp, 0);
5861 cm_Open(scp, 0, userp);
5863 cm_ReleaseUser(userp);
5864 /* leave scp held since we put it in fidp->scp */
5868 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5881 fd = smb_GetSMBParm(inp, 0);
5882 whence = smb_GetSMBParm(inp, 1);
5883 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5885 /* try to find the file descriptor */
5886 fd = smb_ChainFID(fd, inp);
5887 fidp = smb_FindFID(vcp, fd, 0);
5888 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5889 return CM_ERROR_BADFD;
5892 userp = smb_GetUser(vcp, inp);
5894 lock_ObtainMutex(&fidp->mx);
5896 lock_ObtainMutex(&scp->mx);
5897 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5898 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5901 /* offset from current offset */
5902 offset += fidp->offset;
5904 else if (whence == 2) {
5905 /* offset from current EOF */
5906 offset += scp->length.LowPart;
5908 fidp->offset = offset;
5909 smb_SetSMBParm(outp, 0, offset & 0xffff);
5910 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
5911 smb_SetSMBDataLength(outp, 0);
5913 lock_ReleaseMutex(&scp->mx);
5914 lock_ReleaseMutex(&fidp->mx);
5915 smb_ReleaseFID(fidp);
5916 cm_ReleaseUser(userp);
5920 /* dispatch all of the requests received in a packet. Due to chaining, this may
5921 * be more than one request.
5923 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5924 NCB *ncbp, raw_write_cont_t *rwcp)
5928 unsigned long code = 0;
5929 unsigned char *outWctp;
5930 int nparms; /* # of bytes of parameters */
5932 int nbytes; /* bytes of data, excluding count */
5935 unsigned short errCode;
5936 unsigned long NTStatus;
5938 unsigned char errClass;
5939 unsigned int oldGen;
5940 DWORD oldTime, newTime;
5942 /* get easy pointer to the data */
5943 smbp = (smb_t *) inp->data;
5945 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
5946 /* setup the basic parms for the initial request in the packet */
5947 inp->inCom = smbp->com;
5948 inp->wctp = &smbp->wct;
5950 inp->ncb_length = ncbp->ncb_length;
5955 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
5956 /* log it and discard it */
5961 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5962 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
5964 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
5965 1, ncbp->ncb_length, ptbuf, inp);
5966 DeregisterEventSource(h);
5968 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
5973 /* We are an ongoing op */
5974 thrd_Increment(&ongoingOps);
5976 /* set up response packet for receiving output */
5977 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
5978 smb_FormatResponsePacket(vcp, inp, outp);
5979 outWctp = outp->wctp;
5981 /* Remember session generation number and time */
5982 oldGen = sessionGen;
5983 oldTime = GetCurrentTime();
5985 while(inp->inCom != 0xff) {
5986 dp = &smb_dispatchTable[inp->inCom];
5988 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
5989 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
5990 code = outp->resumeCode;
5994 /* process each request in the packet; inCom, wctp and inCount
5995 * are already set up.
5997 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6000 /* now do the dispatch */
6001 /* start by formatting the response record a little, as a default */
6002 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6004 outWctp[1] = 0xff; /* no operation */
6005 outWctp[2] = 0; /* padding */
6010 /* not a chained request, this is a more reasonable default */
6011 outWctp[0] = 0; /* wct of zero */
6012 outWctp[1] = 0; /* and bcc (word) of zero */
6016 /* once set, stays set. Doesn't matter, since we never chain
6017 * "no response" calls.
6019 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6023 /* we have a recognized operation */
6025 if (inp->inCom == 0x1d)
6027 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6030 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
6031 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
6032 code = (*(dp->procp)) (vcp, inp, outp);
6033 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6034 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6037 if (oldGen != sessionGen) {
6042 newTime = GetCurrentTime();
6043 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6044 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6045 newTime - oldTime, ncbp->ncb_length);
6047 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6048 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6049 DeregisterEventSource(h);
6051 osi_Log1(smb_logp, "Pkt straddled session startup, "
6052 "ncb length %d", ncbp->ncb_length);
6056 /* bad opcode, fail the request, after displaying it */
6059 #endif /* NOTSERVICE */
6063 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6064 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6065 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6066 if (code == IDCANCEL) showErrors = 0;
6069 code = CM_ERROR_BADOP;
6072 /* catastrophic failure: log as much as possible */
6073 if (code == CM_ERROR_BADSMB) {
6080 "Invalid SMB, ncb_length %d",
6083 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6084 sprintf(s, "Invalid SMB message, length %d",
6087 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6088 1, ncbp->ncb_length, ptbuf, smbp);
6089 DeregisterEventSource(h);
6092 #endif /* NOTSERVICE */
6094 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6097 code = CM_ERROR_INVAL;
6100 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6101 thrd_Decrement(&ongoingOps);
6106 /* now, if we failed, turn the current response into an empty
6107 * one, and fill in the response packet's error code.
6110 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6111 smb_MapNTError(code, &NTStatus);
6112 outWctp = outp->wctp;
6113 smbp = (smb_t *) &outp->data;
6114 if (code != CM_ERROR_PARTIALWRITE
6115 && code != CM_ERROR_BUFFERTOOSMALL
6116 && code != CM_ERROR_GSSCONTINUE) {
6117 /* nuke wct and bcc. For a partial
6118 * write or an in-process authentication handshake,
6119 * assume they're OK.
6125 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6126 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6127 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6128 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6129 smbp->flg2 |= 0x4000;
6133 smb_MapCoreError(code, vcp, &errCode, &errClass);
6134 outWctp = outp->wctp;
6135 smbp = (smb_t *) &outp->data;
6136 if (code != CM_ERROR_PARTIALWRITE) {
6137 /* nuke wct and bcc. For a partial
6138 * write, assume they're OK.
6144 smbp->errLow = (unsigned char) (errCode & 0xff);
6145 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6146 smbp->rcls = errClass;
6149 } /* error occurred */
6151 /* if we're here, we've finished one request. Look to see if
6152 * this is a chained opcode. If it is, setup things to process
6153 * the chained request, and setup the output buffer to hold the
6154 * chained response. Start by finding the next input record.
6156 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6157 break; /* not a chained req */
6158 tp = inp->wctp; /* points to start of last request */
6159 /* in a chained request, the first two
6160 * parm fields are required, and are
6161 * AndXCommand/AndXReserved and
6163 if (tp[0] < 2) break;
6164 if (tp[1] == 0xff) break; /* no more chained opcodes */
6166 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6169 /* and now append the next output request to the end of this
6170 * last request. Begin by finding out where the last response
6171 * ends, since that's where we'll put our new response.
6173 outWctp = outp->wctp; /* ptr to out parameters */
6174 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6175 nparms = outWctp[0] << 1;
6176 tp = outWctp + nparms + 1; /* now points to bcc field */
6177 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6178 tp += 2 /* for the count itself */ + nbytes;
6179 /* tp now points to the new output record; go back and patch the
6180 * second parameter (off2) to point to the new record.
6182 temp = (unsigned int)tp - ((unsigned int) outp->data);
6183 outWctp[3] = (unsigned char) (temp & 0xff);
6184 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6185 outWctp[2] = 0; /* padding */
6186 outWctp[1] = inp->inCom; /* next opcode */
6188 /* finally, setup for the next iteration */
6191 } /* while loop over all requests in the packet */
6193 /* done logging out, turn off logging-out flag */
6194 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6195 vcp->justLoggedOut = NULL;
6198 free(loggedOutName);
6199 loggedOutName = NULL;
6200 smb_ReleaseUID(loggedOutUserp);
6201 loggedOutUserp = NULL;
6205 /* now send the output packet, and return */
6207 smb_SendPacket(vcp, outp);
6208 thrd_Decrement(&ongoingOps);
6210 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6212 smb_ReleaseVC(active_vcp);
6214 "Replacing active_vcp %x with %x", active_vcp, vcp);
6218 last_msg_time = GetCurrentTime();
6220 else if (active_vcp == vcp) {
6221 smb_ReleaseVC(active_vcp);
6229 /* Wait for Netbios() calls to return, and make the results available to server
6230 * threads. Note that server threads can't wait on the NCBevents array
6231 * themselves, because NCB events are manual-reset, and the servers would race
6232 * each other to reset them.
6234 void smb_ClientWaiter(void *parmp)
6240 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6242 if (code == WAIT_OBJECT_0)
6245 /* error checking */
6246 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6248 int abandonIdx = code - WAIT_ABANDONED_0;
6249 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6252 if (code == WAIT_IO_COMPLETION)
6254 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6258 if (code == WAIT_TIMEOUT)
6260 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6263 if (code == WAIT_FAILED)
6265 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6268 idx = code - WAIT_OBJECT_0;
6270 /* check idx range! */
6271 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6273 /* this is fatal - log as much as possible */
6274 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6278 thrd_ResetEvent(NCBevents[idx]);
6279 thrd_SetEvent(NCBreturns[0][idx]);
6285 * Try to have one NCBRECV request waiting for every live session. Not more
6286 * than one, because if there is more than one, it's hard to handle Write Raw.
6288 void smb_ServerWaiter(void *parmp)
6291 int idx_session, idx_NCB;
6299 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6301 if (code == WAIT_OBJECT_0)
6304 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6306 int abandonIdx = code - WAIT_ABANDONED_0;
6307 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6310 if (code == WAIT_IO_COMPLETION)
6312 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6316 if (code == WAIT_TIMEOUT)
6318 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6321 if (code == WAIT_FAILED)
6323 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6326 idx_session = code - WAIT_OBJECT_0;
6328 /* check idx range! */
6329 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6331 /* this is fatal - log as much as possible */
6332 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6338 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6340 if (code == WAIT_OBJECT_0)
6343 /* error checking */
6344 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6346 int abandonIdx = code - WAIT_ABANDONED_0;
6347 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6350 if (code == WAIT_IO_COMPLETION)
6352 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6356 if (code == WAIT_TIMEOUT)
6358 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6361 if (code == WAIT_FAILED)
6363 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6366 idx_NCB = code - WAIT_OBJECT_0;
6368 /* check idx range! */
6369 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6371 /* this is fatal - log as much as possible */
6372 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6376 /* Link them together */
6377 NCBsessions[idx_NCB] = idx_session;
6380 ncbp = NCBs[idx_NCB];
6382 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6384 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6385 ncbp->ncb_command = NCBRECV | ASYNCH;
6386 ncbp->ncb_lana_num = lanas[idx_session];
6388 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6389 ncbp->ncb_event = NCBevents[idx_NCB];
6390 ncbp->ncb_length = SMB_PACKETSIZE;
6393 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6394 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6395 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6396 ncbp->ncb_length = SMB_PACKETSIZE;
6397 Netbios(ncbp, dos_ncb);
6403 * The top level loop for handling SMB request messages. Each server thread
6404 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6405 * NCB and buffer for the incoming request are loaned to us.
6407 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6408 * to immediately send a request for the rest of the data. This must come
6409 * before any other traffic for that session, so we delay setting the session
6410 * event until that data has come in.
6412 void smb_Server(VOID *parmp)
6414 int myIdx = (int) parmp;
6418 smb_packet_t *outbufp;
6420 int idx_NCB, idx_session;
6422 smb_vc_t *vcp = NULL;
6429 outbufp = GetPacket();
6430 outbufp->ncbp = outncbp;
6434 /* check for demo expiration */
6436 unsigned long tod = time((void *) 0);
6437 if (tod > EXPIREDATE) {
6438 (*smb_MBfunc)(NULL, "AFS demo expiration",
6440 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6444 #endif /* !NOEXPIRE */
6446 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6448 if (code == WAIT_OBJECT_0) {
6452 /* error checking */
6453 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6455 int abandonIdx = code - WAIT_ABANDONED_0;
6456 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6459 if (code == WAIT_IO_COMPLETION)
6461 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6465 if (code == WAIT_TIMEOUT)
6467 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6470 if (code == WAIT_FAILED)
6472 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6475 idx_NCB = code - WAIT_OBJECT_0;
6477 /* check idx range! */
6478 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6480 /* this is fatal - log as much as possible */
6481 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6485 ncbp = NCBs[idx_NCB];
6487 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6489 idx_session = NCBsessions[idx_NCB];
6490 rc = ncbp->ncb_retcode;
6492 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6493 osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6496 case NRC_GOODRET: break;
6499 /* Can this happen? Or is it just my
6506 /* Client closed session */
6507 if (reportSessionStartups)
6509 osi_Log1(smb_logp, "session [ %d ] closed", idx_session);
6511 dead_sessions[idx_session] = TRUE;
6514 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6515 /* Should also release vcp. [done] 2004-05-11 jaltman
6517 * sanity check that all TID's are gone.
6519 * TODO: check if we could use LSNs[idx_session] instead,
6520 * also cleanup after dead vcp
6525 "dead_vcp already set, %x",
6527 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6529 "setting dead_vcp %x, user struct %x",
6533 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6535 if (vcp->justLoggedOut) {
6537 loggedOutTime = vcp->logoffTime;
6539 strdup(vcp->justLoggedOut->unp->name);
6540 loggedOutUserp = vcp->justLoggedOut;
6541 lock_ObtainWrite(&smb_rctLock);
6542 loggedOutUserp->refCount++;
6543 lock_ReleaseWrite(&smb_rctLock);
6549 /* Treat as transient error */
6556 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6557 sprintf(s, "SMB message incomplete, length %d",
6560 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6562 ncbp->ncb_length, ptbuf,
6564 DeregisterEventSource(h);
6567 "dispatch smb recv failed, message incomplete, ncb_length %d",
6570 "SMB message incomplete, "
6571 "length %d", ncbp->ncb_length);
6574 * We used to discard the packet.
6575 * Instead, try handling it normally.
6583 /* A weird error code. Log it, sleep, and
6585 if (vcp && vcp->errorCount++ > 3) {
6586 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6587 dead_sessions[idx_session] = TRUE;
6591 thrd_SetEvent(SessionEvents[idx_session]);
6596 /* Success, so now dispatch on all the data in the packet */
6598 smb_concurrentCalls++;
6599 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6600 smb_maxObsConcurrentCalls = smb_concurrentCalls;
6604 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6606 * If at this point vcp is NULL (implies that packet was invalid)
6607 * then we are in big trouble. This means either :
6608 * a) we have the wrong NCB.
6609 * b) Netbios screwed up the call.
6610 * Obviously this implies that
6611 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
6612 * lanas[idx_session] != ncbp->ncb_lana_num )
6613 * Either way, we can't do anything with this packet.
6614 * Log, sleep and resume.
6623 "LSNs[idx_session]=[%d],"
6624 "lanas[idx_session]=[%d],"
6625 "ncbp->ncb_lsn=[%d],"
6626 "ncbp->ncb_lana_num=[%d]",
6630 ncbp->ncb_lana_num);
6634 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6636 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6637 DeregisterEventSource(h);
6640 /* Also log in the trace log. */
6641 osi_Log4(smb_logp, "Server: BAD VCP!"
6642 "LSNs[idx_session]=[%d],"
6643 "lanas[idx_session]=[%d],"
6644 "ncbp->ncb_lsn=[%d],"
6645 "ncbp->ncb_lana_num=[%d]",
6649 ncbp->ncb_lana_num);
6651 /* thrd_Sleep(1000); Don't bother sleeping */
6652 thrd_SetEvent(SessionEvents[idx_session]);
6653 smb_concurrentCalls--;
6658 vcp->errorCount = 0;
6659 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6661 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6662 /* copy whole packet to virtual memory */
6663 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6665 bufp->dos_pkt / 16, bufp);*/
6667 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6669 smbp = (smb_t *)bufp->data;
6672 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6676 if (smbp->com == 0x1d) {
6677 /* Special handling for Write Raw */
6678 raw_write_cont_t rwc;
6679 EVENT_HANDLE rwevent;
6680 char eventName[MAX_PATH];
6682 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6683 if (rwc.code == 0) {
6684 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6685 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6686 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6687 ncbp->ncb_command = NCBRECV | ASYNCH;
6688 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6689 ncbp->ncb_lana_num = vcp->lana;
6690 ncbp->ncb_buffer = rwc.buf;
6691 ncbp->ncb_length = 65535;
6692 ncbp->ncb_event = rwevent;
6696 Netbios(ncbp, dos_ncb);
6698 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6699 thrd_CloseHandle(rwevent);
6701 thrd_SetEvent(SessionEvents[idx_session]);
6703 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6704 } else if (smbp->com == 0xa0) {
6706 * Serialize the handling for NT Transact
6709 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6710 thrd_SetEvent(SessionEvents[idx_session]);
6712 thrd_SetEvent(SessionEvents[idx_session]);
6713 /* TODO: what else needs to be serialized? */
6714 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6716 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6718 __except( smb_ServerExceptionFilter() ) {
6722 smb_concurrentCalls--;
6725 thrd_SetEvent(NCBavails[idx_NCB]);
6732 * Exception filter for the server threads. If an exception occurs in the
6733 * dispatch routines, which is where exceptions are most common, then do a
6734 * force trace and give control to upstream exception handlers. Useful for
6737 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6738 DWORD smb_ServerExceptionFilter(void) {
6739 /* While this is not the best time to do a trace, if it succeeds, then
6740 * we have a trace (assuming tracing was enabled). Otherwise, this should
6741 * throw a second exception.
6746 ptbuf[0] = "Unhandled exception forcing trace";
6748 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6750 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6751 DeregisterEventSource(h);
6754 afsd_ForceTrace(TRUE);
6755 return EXCEPTION_CONTINUE_SEARCH;
6760 * Create a new NCB and associated events, packet buffer, and "space" buffer.
6761 * If the number of server threads is M, and the number of live sessions is
6762 * N, then the number of NCB's in use at any time either waiting for, or
6763 * holding, received messages is M + N, so that is how many NCB's get created.
6765 void InitNCBslot(int idx)
6767 struct smb_packet *bufp;
6768 EVENT_HANDLE retHandle;
6770 char eventName[MAX_PATH];
6772 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
6774 NCBs[idx] = GetNCB();
6775 sprintf(eventName,"NCBavails[%d]", idx);
6776 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6777 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6778 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6780 sprintf(eventName,"NCBevents[%d]", idx);
6781 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
6782 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6783 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6785 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
6786 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6787 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6788 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6789 for (i=0; i<smb_NumServerThreads; i++)
6790 NCBreturns[i][idx] = retHandle;
6792 bufp->spacep = cm_GetSpace();
6796 /* listen for new connections */
6797 void smb_Listener(void *parmp)
6805 char rname[NCBNAMSZ+1];
6806 char cname[MAX_COMPUTERNAME_LENGTH+1];
6807 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
6812 int lana = (int) parmp;
6816 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6819 /* retrieve computer name */
6820 GetComputerName(cname, &cnamelen);
6824 memset(ncbp, 0, sizeof(NCB));
6828 /* check for demo expiration */
6830 unsigned long tod = time((void *) 0);
6831 if (tod > EXPIREDATE) {
6832 (*smb_MBfunc)(NULL, "AFS demo expiration",
6834 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6842 #endif /* !NOEXPIRE */
6844 ncbp->ncb_command = NCBLISTEN;
6845 ncbp->ncb_rto = 0; /* No receive timeout */
6846 ncbp->ncb_sto = 0; /* No send timeout */
6848 /* pad out with spaces instead of null termination */
6849 len = strlen(smb_localNamep);
6850 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
6851 for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
6853 strcpy(ncbp->ncb_callname, "*");
6854 for(i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
6856 ncbp->ncb_lana_num = lana;
6859 code = Netbios(ncbp);
6861 code = Netbios(ncbp, dos_ncb);
6870 /* terminate silently if shutdown flag is set */
6871 if (smbShutdownFlag == 1) {
6880 "NCBLISTEN lana=%d failed with code %d",
6881 ncbp->ncb_lana_num, code);
6883 "Client exiting due to network failure. Please restart client.\n");
6887 "Client exiting due to network failure. Please restart client.\n"
6888 "NCBLISTEN lana=%d failed with code %d",
6889 ncbp->ncb_lana_num, code);
6891 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
6892 MB_OK|MB_SERVICE_NOTIFICATION);
6893 osi_assert(tbuffer);
6896 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
6897 ncbp->ncb_lana_num, code);
6898 fprintf(stderr, "\nClient exiting due to network failure "
6899 "(possibly due to power-saving mode)\n");
6900 fprintf(stderr, "Please restart client.\n");
6901 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
6905 /* check for remote conns */
6906 /* first get remote name and insert null terminator */
6907 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
6908 for (i=NCBNAMSZ; i>0; i--) {
6909 if (rname[i-1] != ' ' && rname[i-1] != 0) {
6915 /* compare with local name */
6917 if (strncmp(rname, cname, NCBNAMSZ) != 0)
6918 flags |= SMB_VCFLAG_REMOTECONN;
6920 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
6922 lock_ObtainMutex(&smb_ListenerLock);
6924 /* New generation */
6927 /* Log session startup */
6929 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
6931 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
6933 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
6934 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
6936 if (reportSessionStartups) {
6942 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6943 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
6945 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
6947 DeregisterEventSource(h);
6950 fprintf(stderr, "%s: New session %d starting from host %s\n",
6951 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
6955 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
6956 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
6959 /* now ncbp->ncb_lsn is the connection ID */
6960 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
6961 vcp->flags |= flags;
6962 strcpy(vcp->rname, rname);
6964 /* Allocate slot in session arrays */
6965 /* Re-use dead session if possible, otherwise add one more */
6966 /* But don't look at session[0], it is reserved */
6967 for (i = 1; i < numSessions; i++) {
6968 if (dead_sessions[i]) {
6969 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
6970 dead_sessions[i] = FALSE;
6975 /* assert that we do not exceed the maximum number of sessions or NCBs.
6976 * we should probably want to wait for a session to be freed in case
6980 osi_assert(i < Sessionmax - 1);
6981 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
6983 LSNs[i] = ncbp->ncb_lsn;
6984 lanas[i] = ncbp->ncb_lana_num;
6986 if (i == numSessions) {
6987 /* Add new NCB for new session */
6988 char eventName[MAX_PATH];
6990 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
6992 InitNCBslot(numNCBs);
6994 thrd_SetEvent(NCBavails[0]);
6995 thrd_SetEvent(NCBevents[0]);
6996 for (j = 0; j < smb_NumServerThreads; j++)
6997 thrd_SetEvent(NCBreturns[j][0]);
6998 /* Also add new session event */
6999 sprintf(eventName, "SessionEvents[%d]", i);
7000 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7001 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7002 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7004 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7005 thrd_SetEvent(SessionEvents[0]);
7007 thrd_SetEvent(SessionEvents[i]);
7010 lock_ReleaseMutex(&smb_ListenerLock);
7012 } /* dispatch while loop */
7015 /* initialize Netbios */
7016 void smb_NetbiosInit()
7022 int i, lana, code, l;
7024 int delname_tried=0;
7027 OSVERSIONINFO Version;
7029 /* AFAIK, this is the default for the ms loopback adapter.*/
7030 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
7031 /*******************************************************************/
7033 /* Get the version of Windows */
7034 memset(&Version, 0x00, sizeof(Version));
7035 Version.dwOSVersionInfoSize = sizeof(Version);
7036 GetVersionEx(&Version);
7038 /* setup the NCB system */
7041 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7045 if (smb_LANadapter == -1) {
7046 ncbp->ncb_command = NCBENUM;
7047 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7048 ncbp->ncb_length = sizeof(lana_list);
7049 code = Netbios(ncbp);
7051 sprintf(s, "Netbios NCBENUM error code %d", code);
7052 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7053 osi_panic(s, __FILE__, __LINE__);
7057 lana_list.length = 1;
7058 lana_list.lana[0] = smb_LANadapter;
7061 for (i = 0; i < lana_list.length; i++) {
7062 /* reset the adaptor: in Win32, this is required for every process, and
7063 * acts as an init call, not as a real hardware reset.
7065 ncbp->ncb_command = NCBRESET;
7066 ncbp->ncb_callname[0] = 100;
7067 ncbp->ncb_callname[2] = 100;
7068 ncbp->ncb_lana_num = lana_list.lana[i];
7069 code = Netbios(ncbp);
7071 code = ncbp->ncb_retcode;
7073 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7074 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7075 lana_list.lana[i] = 255; /* invalid lana */
7077 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7078 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7082 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7083 we will just fake the LANA list */
7084 if (smb_LANadapter == -1) {
7085 for (i = 0; i < 8; i++)
7086 lana_list.lana[i] = i;
7087 lana_list.length = 8;
7090 lana_list.length = 1;
7091 lana_list.lana[0] = smb_LANadapter;
7095 /* and declare our name so we can receive connections */
7096 memset(ncbp, 0, sizeof(*ncbp));
7097 len=lstrlen(smb_localNamep);
7098 memset(smb_sharename,' ',NCBNAMSZ);
7099 memcpy(smb_sharename,smb_localNamep,len);
7100 sprintf(s, "lana_list.length %d", lana_list.length);
7101 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7103 /* Keep the name so we can unregister it later */
7104 for (l = 0; l < lana_list.length; l++) {
7105 lana = lana_list.lana[l];
7107 ncbp->ncb_command = NCBADDNAME;
7108 ncbp->ncb_lana_num = lana;
7109 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7111 code = Netbios(ncbp);
7113 code = Netbios(ncbp, dos_ncb);
7116 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7117 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7119 char name[NCBNAMSZ+1];
7121 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7122 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7125 if (code == 0) code = ncbp->ncb_retcode;
7127 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7129 /* we only use one LANA with djgpp */
7130 lana_list.lana[0] = lana;
7131 lana_list.length = 1;
7135 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7136 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7137 if (code == NRC_BRIDGE) { /* invalid LANA num */
7138 lana_list.lana[l] = 255;
7141 else if (code == NRC_DUPNAME) {
7142 osi_Log0(smb_logp, "Name already exists; try to delete it");
7143 memset(ncbp, 0, sizeof(*ncbp));
7144 ncbp->ncb_command = NCBDELNAME;
7145 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7146 ncbp->ncb_lana_num = lana;
7148 code = Netbios(ncbp);
7150 code = Netbios(ncbp, dos_ncb);
7152 if (code == 0) code = ncbp->ncb_retcode;
7154 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7155 osi_Log0(smb_logp, s);
7157 if (code != 0 || delname_tried) {
7158 lana_list.lana[l] = 255;
7160 else if (code == 0) {
7161 if (!delname_tried) {
7169 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7170 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7171 lana_list.lana[l] = 255; /* invalid lana */
7172 osi_panic(s, __FILE__, __LINE__);
7176 lana_found = 1; /* at least one worked */
7183 osi_assert(lana_list.length >= 0);
7185 sprintf(s, "No valid LANA numbers found!");
7186 osi_panic(s, __FILE__, __LINE__);
7189 /* we're done with the NCB now */
7193 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7210 EVENT_HANDLE retHandle;
7211 char eventName[MAX_PATH];
7214 smb_MBfunc = aMBfunc;
7218 /* check for demo expiration */
7220 unsigned long tod = time((void *) 0);
7221 if (tod > EXPIREDATE) {
7223 (*smb_MBfunc)(NULL, "AFS demo expiration", "afsd",
7224 MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
7227 fprintf(stderr, "AFS demo expiration\n");
7232 #endif /* !NOEXPIRE */
7235 smb_LANadapter = LANadapt;
7237 /* Initialize smb_localZero */
7238 myTime.tm_isdst = -1; /* compute whether on DST or not */
7239 myTime.tm_year = 70;
7245 smb_localZero = mktime(&myTime);
7247 /* Initialize kludge-GMT */
7248 smb_CalculateNowTZ();
7250 #ifdef AFS_FREELANCE_CLIENT
7251 /* Make sure the root.afs volume has the correct time */
7252 cm_noteLocalMountPointChange();
7255 /* initialize the remote debugging log */
7258 /* remember the name */
7259 len = strlen(snamep);
7260 smb_localNamep = malloc(len+1);
7261 strcpy(smb_localNamep, snamep);
7262 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7264 /* and the global lock */
7265 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7266 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7268 /* Raw I/O data structures */
7269 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7271 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7273 /* 4 Raw I/O buffers */
7275 smb_RawBufs = calloc(65536,1);
7276 *((char **)smb_RawBufs) = NULL;
7277 for (i=0; i<3; i++) {
7278 char *rawBuf = calloc(65536,1);
7279 *((char **)rawBuf) = smb_RawBufs;
7280 smb_RawBufs = rawBuf;
7283 npar = 65536 >> 4; /* number of paragraphs */
7284 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7286 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7288 osi_panic("",__FILE__,__LINE__);
7291 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7294 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7296 _farpokel(_dos_ds, smb_RawBufs, NULL);
7297 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7298 npar = 65536 >> 4; /* number of paragraphs */
7299 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7301 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7303 osi_panic("",__FILE__,__LINE__);
7306 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7309 rawBuf = (seg * 16) + 0; /* DOS physical address */
7310 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7311 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7312 smb_RawBufs = rawBuf;
7316 /* global free lists */
7317 smb_ncbFreeListp = NULL;
7318 smb_packetFreeListp = NULL;
7322 /* Initialize listener and server structures */
7324 memset(dead_sessions, 0, sizeof(dead_sessions));
7325 sprintf(eventName, "SessionEvents[0]");
7326 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7327 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7328 afsi_log("Event Object Already Exists: %s", eventName);
7330 smb_NumServerThreads = nThreads;
7331 sprintf(eventName, "NCBavails[0]");
7332 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7333 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7334 afsi_log("Event Object Already Exists: %s", eventName);
7335 sprintf(eventName, "NCBevents[0]");
7336 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7337 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7338 afsi_log("Event Object Already Exists: %s", eventName);
7339 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7340 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7341 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7342 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7343 afsi_log("Event Object Already Exists: %s", eventName);
7344 for (i = 0; i < smb_NumServerThreads; i++) {
7345 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7346 NCBreturns[i][0] = retHandle;
7348 for (i = 1; i <= nThreads; i++)
7350 numNCBs = nThreads + 1;
7352 /* Initialize dispatch table */
7353 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7354 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7355 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7356 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7357 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7358 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7359 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7360 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7361 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7362 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7363 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7364 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7365 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7366 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7367 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7368 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7369 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7370 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7371 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7372 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7373 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7374 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7375 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7376 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7377 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7378 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7379 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7380 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7381 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7382 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7383 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7384 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7385 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7386 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7387 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7388 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7389 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7390 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7391 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7392 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7393 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7394 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7395 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7396 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7397 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7398 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7399 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7400 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7401 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7402 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7403 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7404 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7405 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7406 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7407 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7408 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7409 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7410 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7411 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7412 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7413 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7414 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7415 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;
7416 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;
7417 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;
7418 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;
7419 for(i=0xd0; i<= 0xd7; i++) {
7420 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7423 /* setup tran 2 dispatch table */
7424 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7425 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7426 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7427 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7428 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7429 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7430 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7431 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7432 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7433 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7434 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7435 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7436 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7437 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2MKDir;
7439 /* setup the rap dispatch table */
7440 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
7441 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
7442 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
7443 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
7444 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
7448 /* if we are doing SMB authentication we have register outselves as a logon process */
7449 if (smb_authType != SMB_AUTH_NONE) {
7451 LSA_STRING afsProcessName;
7452 LSA_OPERATIONAL_MODE dummy; /*junk*/
7454 afsProcessName.Buffer = "OpenAFSClientDaemon";
7455 afsProcessName.Length = strlen(afsProcessName.Buffer);
7456 afsProcessName.MaximumLength = afsProcessName.Length + 1;
7458 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
7460 if (nts == STATUS_SUCCESS) {
7461 LSA_STRING packageName;
7462 /* we are registered. Find out the security package id */
7463 packageName.Buffer = MSV1_0_PACKAGE_NAME;
7464 packageName.Length = strlen(packageName.Buffer);
7465 packageName.MaximumLength = packageName.Length + 1;
7466 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
7467 if (nts == STATUS_SUCCESS) {
7468 smb_lsaLogonOrigin.Buffer = "OpenAFS";
7469 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
7470 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
7472 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
7475 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
7478 if (nts != STATUS_SUCCESS) {
7479 /* something went wrong. We report the error and revert back to no authentication
7480 because we can't perform any auth requests without a successful lsa handle
7481 or sec package id. */
7482 afsi_log("Reverting to NO SMB AUTH");
7483 smb_authType = SMB_AUTH_NONE;
7486 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
7487 * time prevents the failure of authentication when logged into Windows with an
7488 * external Kerberos principal mapped to a local account.
7490 else if ( smb_authType == SMB_AUTH_EXTENDED) {
7491 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
7492 * then the only option is NTLMSSP anyway; so just fallback.
7497 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
7498 if (secBlobLength == 0) {
7499 smb_authType = SMB_AUTH_NTLM;
7500 afsi_log("Reverting to SMB AUTH NTLM");
7509 /* Now get ourselves a domain name. */
7510 /* For now we are using the local computer name as the domain name.
7511 * It is actually the domain for local logins, and we are acting as
7512 * a local SMB server.
7514 bufsize = sizeof(smb_ServerDomainName) - 1;
7515 GetComputerName(smb_ServerDomainName, &bufsize);
7516 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
7517 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
7520 /* Start listeners, waiters, servers, and daemons */
7522 for (i = 0; i < lana_list.length; i++) {
7523 if (lana_list.lana[i] == 255) continue;
7524 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7525 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7526 osi_assert(phandle != NULL);
7527 thrd_CloseHandle(phandle);
7531 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7532 NULL, 0, &lpid, "smb_ClientWaiter");
7533 osi_assert(phandle != NULL);
7534 thrd_CloseHandle(phandle);
7537 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7538 NULL, 0, &lpid, "smb_ServerWaiter");
7539 osi_assert(phandle != NULL);
7540 thrd_CloseHandle(phandle);
7542 for (i=0; i<nThreads; i++) {
7543 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7544 (void *) i, 0, &lpid, "smb_Server");
7545 osi_assert(phandle != NULL);
7546 thrd_CloseHandle(phandle);
7549 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7550 NULL, 0, &lpid, "smb_Daemon");
7551 osi_assert(phandle != NULL);
7552 thrd_CloseHandle(phandle);
7554 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7555 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7556 osi_assert(phandle != NULL);
7557 thrd_CloseHandle(phandle);
7566 void smb_Shutdown(void)
7575 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7577 /* setup the NCB system */
7580 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7583 /* Block new sessions by setting shutdown flag */
7584 smbShutdownFlag = 1;
7586 /* Hang up all sessions */
7587 memset((char *)ncbp, 0, sizeof(NCB));
7588 for (i = 1; i < numSessions; i++)
7590 if (dead_sessions[i])
7593 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7594 ncbp->ncb_command = NCBHANGUP;
7595 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
7596 ncbp->ncb_lsn = LSNs[i];
7598 code = Netbios(ncbp);
7600 code = Netbios(ncbp, dos_ncb);
7602 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7603 if (code == 0) code = ncbp->ncb_retcode;
7605 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7606 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7610 /* Delete Netbios name */
7611 memset((char *)ncbp, 0, sizeof(NCB));
7612 for (i = 0; i < lana_list.length; i++) {
7613 if (lana_list.lana[i] == 255) continue;
7614 ncbp->ncb_command = NCBDELNAME;
7615 ncbp->ncb_lana_num = lana_list.lana[i];
7616 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7618 code = Netbios(ncbp);
7620 code = Netbios(ncbp, dos_ncb);
7622 if (code == 0) code = ncbp->ncb_retcode;
7624 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7625 ncbp->ncb_lana_num, code);
7631 /* Get the UNC \\<servername>\<sharename> prefix. */
7632 char *smb_GetSharename()
7636 /* Make sure we have been properly initialized. */
7637 if (smb_localNamep == NULL)
7640 /* Allocate space for \\<servername>\<sharename>, plus the
7643 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7644 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7650 void smb_LogPacket(smb_packet_t *packet)
7653 unsigned length, paramlen, datalen, i, j;
7655 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7659 osi_Log0(smb_logp, "*** SMB packet dump ***");
7661 vp = (BYTE *) packet->data;
7663 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7664 length = paramlen + 2 + datalen;
7667 for(i=0;i < length; i+=16)
7669 memset( buf, ' ', 80 );
7674 buf[strlen(buf)] = ' ';
7676 cp = (BYTE*) buf + 7;
7678 for(j=0;j < 16 && (i+j)<length; j++)
7680 *(cp++) = hex[vp[i+j] >> 4];
7681 *(cp++) = hex[vp[i+j] & 0xf];
7691 for(j=0;j < 16 && (i+j)<length;j++)
7693 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7704 osi_Log0( smb_logp, buf );
7707 osi_Log0(smb_logp, "*** End SMB packet dump ***");
7711 #endif /* NOTSERVICE */
7713 int smb_DumpVCP(FILE *outputFile, char *cookie)
7720 lock_ObtainRead(&smb_rctLock);
7722 sprintf(output, "begin dumping vcpsp\n");
7723 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7725 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
7729 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7730 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7731 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7733 sprintf(output, "begin dumping fidsp\n");
7734 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7736 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
7738 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",
7739 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
7740 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
7741 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7742 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7745 sprintf(output, "done dumping fidsp\n");
7746 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7749 sprintf(output, "done dumping vcpsp\n");
7750 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7752 lock_ReleaseRead(&smb_rctLock);