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
10 //#define NOTSERVICE 1
13 #include <afs/param.h>
19 #include <sys/timeb.h>
35 #include "lanahelper.h"
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
41 smb_vc_t *dead_vcp = NULL;
42 smb_vc_t *active_vcp = NULL;
44 /* TODO; logout mechanism needs to be thread-safe */
45 char *loggedOutName = NULL;
46 smb_user_t *loggedOutUserp = NULL;
49 int smbShutdownFlag = 0;
51 int smb_LogoffTokenTransfer;
52 time_t smb_LogoffTransferTimeout;
54 DWORD last_msg_time = 0;
58 unsigned int sessionGen = 0;
60 extern void afsi_log(char *pattern, ...);
61 extern HANDLE afsi_file;
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t smb_ListenerLock;
72 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
75 long smb_maxObsConcurrentCalls=0;
76 long smb_concurrentCalls=0;
78 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
80 smb_packet_t *smb_packetFreeListp;
81 smb_ncb_t *smb_ncbFreeListp;
83 int smb_NumServerThreads;
85 int numNCBs, numSessions, numVCs;
87 int smb_maxVCPerServer;
88 int smb_maxMpxRequests;
90 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
92 ULONG smb_lsaSecPackage;
93 LSA_STRING smb_lsaLogonOrigin;
95 #define NCBmax MAXIMUM_WAIT_OBJECTS
96 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
97 EVENT_HANDLE **NCBreturns;
98 DWORD NCBsessions[NCBmax];
100 struct smb_packet *bufs[NCBmax];
102 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
103 EVENT_HANDLE SessionEvents[Sessionmax];
104 unsigned short LSNs[Sessionmax];
105 int lanas[Sessionmax];
106 BOOL dead_sessions[Sessionmax];
110 osi_mutex_t smb_RawBufLock;
112 #define SMB_RAW_BUFS 4
114 int smb_RawBufSel[SMB_RAW_BUFS];
119 #define SMB_MASKFLAG_TILDE 1
120 #define SMB_MASKFLAG_CASEFOLD 2
122 #define RAWTIMEOUT INFINITE
125 typedef struct raw_write_cont {
138 /* dir search stuff */
139 long smb_dirSearchCounter = 1;
140 smb_dirSearch_t *smb_firstDirSearchp;
141 smb_dirSearch_t *smb_lastDirSearchp;
143 /* hide dot files? */
144 int smb_hideDotFiles;
146 /* global state about V3 protocols */
147 int smb_useV3; /* try to negotiate V3 */
150 static showErrors = 1;
151 /* MessageBox or something like it */
152 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
153 extern HANDLE WaitToTerminate;
157 * Time in Unix format of midnight, 1/1/1970 local time.
158 * When added to dosUTime, gives Unix (AFS) time.
160 long smb_localZero = 0;
162 /* Time difference for converting to kludge-GMT */
165 char *smb_localNamep = NULL;
167 smb_vc_t *smb_allVCsp;
169 smb_username_t *usernamesp = NULL;
171 smb_waitingLock_t *smb_allWaitingLocks;
174 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
175 NCB *ncbp, raw_write_cont_t *rwcp);
176 void smb_NetbiosInit();
178 #ifndef AFS_WIN95_ENV
179 DWORD smb_ServerExceptionFilter(void);
182 extern char cm_HostName[];
183 extern char cm_confDir[];
187 #define LPTSTR char *
188 #define GetComputerName(str, sizep) \
189 strcpy((str), cm_HostName); \
190 *(sizep) = strlen(cm_HostName)
194 void smb_LogPacket(smb_packet_t *packet);
195 #endif /* LOG_PACKET */
196 extern char AFSConfigKeyName[];
198 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
199 int smb_ServerDomainNameLength = 0;
200 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
201 int smb_ServerOSLength = sizeof(smb_ServerOS);
202 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
203 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
205 /* Faux server GUID. This is never checked. */
206 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
208 char * myCrt_Dispatch(int i)
213 return "(00)ReceiveCoreMakeDir";
215 return "(01)ReceiveCoreRemoveDir";
217 return "(02)ReceiveCoreOpen";
219 return "(03)ReceiveCoreCreate";
221 return "(04)ReceiveCoreClose";
223 return "(05)ReceiveCoreFlush";
225 return "(06)ReceiveCoreUnlink";
227 return "(07)ReceiveCoreRename";
229 return "(08)ReceiveCoreGetFileAttributes";
231 return "(09)ReceiveCoreSetFileAttributes";
233 return "(0a)ReceiveCoreRead";
235 return "(0b)ReceiveCoreWrite";
237 return "(0c)ReceiveCoreLockRecord";
239 return "(0d)ReceiveCoreUnlockRecord";
241 return "(0e)SendCoreBadOp";
243 return "(0f)ReceiveCoreCreate";
245 return "(10)ReceiveCoreCheckPath";
247 return "(11)SendCoreBadOp";
249 return "(12)ReceiveCoreSeek";
251 return "(1a)ReceiveCoreReadRaw";
253 return "(1d)ReceiveCoreWriteRawDummy";
255 return "(22)ReceiveV3SetAttributes";
257 return "(23)ReceiveV3GetAttributes";
259 return "(24)ReceiveV3LockingX";
261 return "(25)ReceiveV3Trans";
263 return "(26)ReceiveV3Trans[aux]";
265 return "(29)SendCoreBadOp";
267 return "(2b)ReceiveCoreEcho";
269 return "(2d)ReceiveV3OpenX";
271 return "(2e)ReceiveV3ReadX";
273 return "(32)ReceiveV3Tran2A";
275 return "(33)ReceiveV3Tran2A[aux]";
277 return "(34)ReceiveV3FindClose";
279 return "(35)ReceiveV3FindNotifyClose";
281 return "(70)ReceiveCoreTreeConnect";
283 return "(71)ReceiveCoreTreeDisconnect";
285 return "(72)ReceiveNegotiate";
287 return "(73)ReceiveV3SessionSetupX";
289 return "(74)ReceiveV3UserLogoffX";
291 return "(75)ReceiveV3TreeConnectX";
293 return "(80)ReceiveCoreGetDiskAttributes";
295 return "(81)ReceiveCoreSearchDir";
299 return "(83)FindUnique";
301 return "(84)FindClose";
303 return "(A0)ReceiveNTTransact";
305 return "(A2)ReceiveNTCreateX";
307 return "(A4)ReceiveNTCancel";
309 return "(A5)ReceiveNTRename";
311 return "(C0)OpenPrintFile";
313 return "(C1)WritePrintFile";
315 return "(C2)ClosePrintFile";
317 return "(C3)GetPrintQueue";
319 return "(D8)ReadBulk";
321 return "(D9)WriteBulk";
323 return "(DA)WriteBulkData";
325 return "unknown SMB op";
329 char * myCrt_2Dispatch(int i)
334 return "unknown SMB op-2";
336 return "S(00)CreateFile";
338 return "S(01)FindFirst";
340 return "S(02)FindNext"; /* FindNext */
342 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
346 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
348 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
350 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
352 return "S(08)??_ReceiveTran2SetFileInfo";
354 return "S(09)??_ReceiveTran2FSCTL";
356 return "S(0a)_ReceiveTran2IOCTL";
358 return "S(0b)_ReceiveTran2FindNotifyFirst";
360 return "S(0c)_ReceiveTran2FindNotifyNext";
362 return "S(0d)_ReceiveTran2CreateDirectory";
364 return "S(0e)_ReceiveTran2SessionSetup";
368 char * myCrt_RapDispatch(int i)
373 return "unknown RAP OP";
375 return "RAP(0)NetShareEnum";
377 return "RAP(1)NetShareGetInfo";
379 return "RAP(13)NetServerGetInfo";
381 return "RAP(63)NetWkStaGetInfo";
385 /* scache must be locked */
386 unsigned int smb_Attributes(cm_scache_t *scp)
390 if (scp->fileType == CM_SCACHETYPE_DIRECTORY
391 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
392 attrs = SMB_ATTR_DIRECTORY;
397 * We used to mark a file RO if it was in an RO volume, but that
398 * turns out to be impolitic in NT. See defect 10007.
401 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
403 if ((scp->unixModeBits & 0222) == 0)
404 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
409 /* Check if the named file/dir is a dotfile/dotdir */
410 /* String pointed to by lastComp can have leading slashes, but otherwise should have
411 no other patch components */
412 unsigned int smb_IsDotFile(char *lastComp) {
415 /* skip over slashes */
416 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
421 /* nulls, curdir and parent dir doesn't count */
427 if(*(s+1) == '.' && !*(s + 2))
434 static int ExtractBits(WORD bits, short start, short len)
441 num = bits << (16 - end);
442 num = num >> ((16 - end) + start);
448 void ShowUnixTime(char *FuncName, time_t unixTime)
453 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
455 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
456 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
458 int day, month, year, sec, min, hour;
461 day = ExtractBits(wDate, 0, 5);
462 month = ExtractBits(wDate, 5, 4);
463 year = ExtractBits(wDate, 9, 7) + 1980;
465 sec = ExtractBits(wTime, 0, 5);
466 min = ExtractBits(wTime, 5, 6);
467 hour = ExtractBits(wTime, 11, 5);
469 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
470 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
476 /* Determine if we are observing daylight savings time */
477 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
479 TIME_ZONE_INFORMATION timeZoneInformation;
480 SYSTEMTIME utc, local, localDST;
482 /* Get the time zone info. NT uses this to calc if we are in DST. */
483 GetTimeZoneInformation(&timeZoneInformation);
485 /* Return the daylight bias */
486 *pDstBias = timeZoneInformation.DaylightBias;
488 /* Return the bias */
489 *pBias = timeZoneInformation.Bias;
491 /* Now determine if DST is being observed */
493 /* Get the UTC (GMT) time */
496 /* Convert UTC time to local time using the time zone info. If we are
497 observing DST, the calculated local time will include this.
499 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
501 /* Set the daylight bias to 0. The daylight bias is the amount of change
502 * in time that we use for daylight savings time. By setting this to 0
503 * we cause there to be no change in time during daylight savings time.
505 timeZoneInformation.DaylightBias = 0;
507 /* Convert the utc time to local time again, but this time without any
508 adjustment for daylight savings time.
510 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
512 /* If the two times are different, then it means that the localDST that
513 we calculated includes the daylight bias, and therefore we are
514 observing daylight savings time.
516 *pDST = localDST.wHour != local.wHour;
519 /* Determine if we are observing daylight savings time */
520 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
526 *pDstBias = -60; /* where can this be different? */
532 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
534 BOOL dst; /* Will be TRUE if observing DST */
535 LONG dstBias; /* Offset from local time if observing DST */
536 LONG bias; /* Offset from GMT for local time */
539 * This function will adjust the last write time to compensate
540 * for two bugs in the smb client:
542 * 1) During Daylight Savings Time, the LastWriteTime is ahead
543 * in time by the DaylightBias (ignoring the sign - the
544 * DaylightBias is always stored as a negative number). If
545 * the DaylightBias is -60, then the LastWriteTime will be
546 * ahead by 60 minutes.
548 * 2) If the local time zone is a positive offset from GMT, then
549 * the LastWriteTime will be the correct local time plus the
550 * Bias (ignoring the sign - a positive offset from GMT is
551 * always stored as a negative Bias). If the Bias is -120,
552 * then the LastWriteTime will be ahead by 120 minutes.
554 * These bugs can occur at the same time.
557 GetTimeZoneInfo(&dst, &dstBias, &bias);
559 /* First adjust for DST */
561 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
563 /* Now adjust for a positive offset from GMT (a negative bias). */
565 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
569 * Calculate the difference (in seconds) between local time and GMT.
570 * This enables us to convert file times to kludge-GMT.
576 struct tm gmt_tm, local_tm;
577 int days, hours, minutes, seconds;
580 gmt_tm = *(gmtime(&t));
581 local_tm = *(localtime(&t));
583 days = local_tm.tm_yday - gmt_tm.tm_yday;
584 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
586 /* There is a problem with DST immediately after the time change
587 * which may continue to exist until the machine is rebooted
589 - (local_tm.tm_isdst ? 1 : 0)
592 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
593 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
599 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
604 time_t ersatz_unixTime;
607 * Must use kludge-GMT instead of real GMT.
608 * kludge-GMT is computed by adding time zone difference to localtime.
611 * ltp = gmtime(&unixTime);
613 ersatz_unixTime = unixTime - smb_NowTZ;
614 ltp = localtime(&ersatz_unixTime);
616 /* if we fail, make up something */
619 localJunk.tm_year = 89 - 20;
620 localJunk.tm_mon = 4;
621 localJunk.tm_mday = 12;
622 localJunk.tm_hour = 0;
623 localJunk.tm_min = 0;
624 localJunk.tm_sec = 0;
627 stm.wYear = ltp->tm_year + 1900;
628 stm.wMonth = ltp->tm_mon + 1;
629 stm.wDayOfWeek = ltp->tm_wday;
630 stm.wDay = ltp->tm_mday;
631 stm.wHour = ltp->tm_hour;
632 stm.wMinute = ltp->tm_min;
633 stm.wSecond = ltp->tm_sec;
634 stm.wMilliseconds = 0;
636 SystemTimeToFileTime(&stm, largeTimep);
639 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
641 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
642 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
643 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
645 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
647 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
648 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
650 *ft = LargeIntegerMultiplyByLong(*ft, 60);
651 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
654 ut = ConvertLongToLargeInteger(unixTime);
655 ut = LargeIntegerMultiplyByLong(ut, 10000000);
656 *ft = LargeIntegerAdd(*ft, ut);
661 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
667 FileTimeToSystemTime(largeTimep, &stm);
669 lt.tm_year = stm.wYear - 1900;
670 lt.tm_mon = stm.wMonth - 1;
671 lt.tm_wday = stm.wDayOfWeek;
672 lt.tm_mday = stm.wDay;
673 lt.tm_hour = stm.wHour;
674 lt.tm_min = stm.wMinute;
675 lt.tm_sec = stm.wSecond;
678 save_timezone = _timezone;
679 _timezone += smb_NowTZ;
680 *unixTimep = mktime(<);
681 _timezone = save_timezone;
684 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
686 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
687 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
688 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
692 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
693 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
694 a = LargeIntegerMultiplyByLong(a, 60);
695 a = LargeIntegerMultiplyByLong(a, 10000000);
697 /* subtract it from ft */
698 a = LargeIntegerSubtract(*ft, a);
700 /* divide down to seconds */
701 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
705 void smb_SearchTimeFromUnixTime(long *dosTimep, time_t unixTime)
713 ltp = localtime((time_t*) &t);
715 /* if we fail, make up something */
718 localJunk.tm_year = 89 - 20;
719 localJunk.tm_mon = 4;
720 localJunk.tm_mday = 12;
721 localJunk.tm_hour = 0;
722 localJunk.tm_min = 0;
723 localJunk.tm_sec = 0;
726 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
727 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
728 *dosTimep = (dosDate<<16) | dosTime;
731 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
733 unsigned short dosDate;
734 unsigned short dosTime;
737 dosDate = searchTime & 0xffff;
738 dosTime = (searchTime >> 16) & 0xffff;
740 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
741 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
742 localTm.tm_mday = (dosDate) & 0x1f;
743 localTm.tm_hour = (dosTime>>11) & 0x1f;
744 localTm.tm_min = (dosTime >> 5) & 0x3f;
745 localTm.tm_sec = (dosTime & 0x1f) * 2;
746 localTm.tm_isdst = -1; /* compute whether DST in effect */
748 *unixTimep = mktime(&localTm);
751 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
753 *dosUTimep = unixTime - smb_localZero;
756 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
759 *unixTimep = dosTime + smb_localZero;
761 /* dosTime seems to be already adjusted for GMT */
762 *unixTimep = dosTime;
766 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
770 lock_ObtainWrite(&smb_rctLock);
771 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
772 if (lsn == vcp->lsn && lana == vcp->lana) {
777 if (!vcp && (flags & SMB_FLAG_CREATE)) {
778 vcp = malloc(sizeof(*vcp));
779 memset(vcp, 0, sizeof(*vcp));
780 vcp->vcID = numVCs++;
784 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
785 vcp->nextp = smb_allVCsp;
787 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
792 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
793 /* We must obtain a challenge for extended auth
794 * in case the client negotiates smb v3
797 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
798 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
801 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
803 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
810 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
812 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
813 LsaFreeReturnBuffer(lsaResp);
816 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
818 lock_ReleaseWrite(&smb_rctLock);
822 int smb_IsStarMask(char *maskp)
827 for(i=0; i<11; i++) {
829 if (tc == '?' || tc == '*' || tc == '>') return 1;
834 void smb_ReleaseVC(smb_vc_t *vcp)
836 lock_ObtainWrite(&smb_rctLock);
837 osi_assert(vcp->refCount-- > 0);
838 lock_ReleaseWrite(&smb_rctLock);
841 void smb_HoldVC(smb_vc_t *vcp)
843 lock_ObtainWrite(&smb_rctLock);
845 lock_ReleaseWrite(&smb_rctLock);
848 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
852 lock_ObtainWrite(&smb_rctLock);
853 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
854 if (tid == tidp->tid) {
859 if (!tidp && (flags & SMB_FLAG_CREATE)) {
860 tidp = malloc(sizeof(*tidp));
861 memset(tidp, 0, sizeof(*tidp));
862 tidp->nextp = vcp->tidsp;
867 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
870 lock_ReleaseWrite(&smb_rctLock);
874 void smb_ReleaseTID(smb_tid_t *tidp)
883 lock_ObtainWrite(&smb_rctLock);
884 osi_assert(tidp->refCount-- > 0);
885 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
886 ltpp = &tidp->vcp->tidsp;
887 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
888 if (tp == tidp) break;
890 osi_assert(tp != NULL);
892 lock_FinalizeMutex(&tidp->mx);
893 userp = tidp->userp; /* remember to drop ref later */
896 lock_ReleaseWrite(&smb_rctLock);
898 cm_ReleaseUser(userp);
905 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
907 smb_user_t *uidp = NULL;
909 lock_ObtainWrite(&smb_rctLock);
910 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
911 if (uid == uidp->userID) {
913 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
914 (int)vcp, uidp->userID,
915 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
919 if (!uidp && (flags & SMB_FLAG_CREATE)) {
920 uidp = malloc(sizeof(*uidp));
921 memset(uidp, 0, sizeof(*uidp));
922 uidp->nextp = vcp->usersp;
927 lock_InitializeMutex(&uidp->mx, "user_t mutex");
929 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 : ""));
931 lock_ReleaseWrite(&smb_rctLock);
935 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
937 smb_username_t *unp= NULL;
939 lock_ObtainWrite(&smb_rctLock);
940 for(unp = usernamesp; unp; unp = unp->nextp) {
941 if (stricmp(unp->name, usern) == 0 &&
942 stricmp(unp->machine, machine) == 0) {
947 if (!unp && (flags & SMB_FLAG_CREATE)) {
948 unp = malloc(sizeof(*unp));
949 memset(unp, 0, sizeof(*unp));
951 unp->nextp = usernamesp;
952 unp->name = strdup(usern);
953 unp->machine = strdup(machine);
955 lock_InitializeMutex(&unp->mx, "username_t mutex");
957 lock_ReleaseWrite(&smb_rctLock);
961 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
963 smb_user_t *uidp= NULL;
965 lock_ObtainWrite(&smb_rctLock);
966 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
969 if (stricmp(uidp->unp->name, usern) == 0) {
971 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
976 lock_ReleaseWrite(&smb_rctLock);
979 void smb_ReleaseUID(smb_user_t *uidp)
988 lock_ObtainWrite(&smb_rctLock);
989 osi_assert(uidp->refCount-- > 0);
990 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
991 lupp = &uidp->vcp->usersp;
992 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
993 if (up == uidp) break;
995 osi_assert(up != NULL);
997 lock_FinalizeMutex(&uidp->mx);
999 userp = uidp->unp->userp; /* remember to drop ref later */
1000 uidp->unp->userp = NULL;
1005 lock_ReleaseWrite(&smb_rctLock);
1007 cm_ReleaseUserVCRef(userp);
1008 cm_ReleaseUser(userp);
1015 /* retrieve a held reference to a user structure corresponding to an incoming
1017 * corresponding release function is cm_ReleaseUser.
1019 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1025 smbp = (smb_t *) inp;
1026 uidp = smb_FindUID(vcp, smbp->uid, 0);
1027 if ((!uidp) || (!uidp->unp))
1030 lock_ObtainMutex(&uidp->mx);
1031 up = uidp->unp->userp;
1033 lock_ReleaseMutex(&uidp->mx);
1035 smb_ReleaseUID(uidp);
1041 * Return a pointer to a pathname extracted from a TID structure. The
1042 * TID structure is not held; assume it won't go away.
1044 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1049 tidp = smb_FindTID(vcp, tid, 0);
1053 if(tidp->flags & SMB_TIDFLAG_IPC) {
1054 code = CM_ERROR_TIDIPC;
1055 /* tidp->pathname would be NULL, but that's fine */
1057 *treepath = tidp->pathname;
1058 smb_ReleaseTID(tidp);
1063 /* check to see if we have a chained fid, that is, a fid that comes from an
1064 * OpenAndX message that ran earlier in this packet. In this case, the fid
1065 * field in a read, for example, request, isn't set, since the value is
1066 * supposed to be inherited from the openAndX call.
1068 int smb_ChainFID(int fid, smb_packet_t *inp)
1070 if (inp->fid == 0 || inp->inCount == 0)
1076 /* are we a priv'd user? What does this mean on NT? */
1077 int smb_SUser(cm_user_t *userp)
1082 /* find a file ID. If we pass in 0 we select an used File ID.
1083 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1084 * smb_fid_t data structure if desired File ID cannot be found.
1086 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1091 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1094 lock_ObtainWrite(&smb_rctLock);
1095 /* figure out if we need to allocate a new file ID */
1098 fid = vcp->fidCounter;
1102 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1103 if (fid == fidp->fid) {
1114 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1115 char eventName[MAX_PATH];
1117 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1118 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1119 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1120 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1121 thrd_CloseHandle(event);
1128 fidp = malloc(sizeof(*fidp));
1129 memset(fidp, 0, sizeof(*fidp));
1130 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1134 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1136 fidp->curr_chunk = fidp->prev_chunk = -2;
1137 fidp->raw_write_event = event;
1139 vcp->fidCounter = fid+1;
1140 if (vcp->fidCounter == 0)
1141 vcp->fidCounter = 1;
1144 lock_ReleaseWrite(&smb_rctLock);
1148 void smb_ReleaseFID(smb_fid_t *fidp)
1151 smb_vc_t *vcp = NULL;
1152 smb_ioctl_t *ioctlp;
1158 lock_ObtainWrite(&smb_rctLock);
1159 osi_assert(fidp->refCount-- > 0);
1160 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1162 if (!(fidp->flags & SMB_FID_IOCTL))
1164 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1165 thrd_CloseHandle(fidp->raw_write_event);
1167 /* and see if there is ioctl stuff to free */
1168 ioctlp = fidp->ioctlp;
1170 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1171 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1172 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1178 /* do not call smb_ReleaseVC() because we already have the lock */
1181 lock_ReleaseWrite(&smb_rctLock);
1183 /* now release the scache structure */
1185 cm_ReleaseSCache(scp);
1189 * Case-insensitive search for one string in another;
1190 * used to find variable names in submount pathnames.
1192 static char *smb_stristr(char *str1, char *str2)
1196 for (cursor = str1; *cursor; cursor++)
1197 if (stricmp(cursor, str2) == 0)
1204 * Substitute a variable value for its name in a submount pathname. Variable
1205 * name has been identified by smb_stristr() and is in substr. Variable name
1206 * length (plus one) is in substr_size. Variable value is in newstr.
1208 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1213 strcpy(temp, substr + substr_size - 1);
1214 strcpy(substr, newstr);
1218 char VNUserName[] = "%USERNAME%";
1219 char VNLCUserName[] = "%LCUSERNAME%";
1220 char VNComputerName[] = "%COMPUTERNAME%";
1221 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1224 /* List available shares */
1225 int smb_ListShares()
1229 char shareBuf[4096];
1237 /*strcpy(shareNameList[num_shares], "all");
1238 strcpy(pathNameList[num_shares++], "/afs");*/
1239 fprintf(stderr, "The following shares are available:\n");
1240 fprintf(stderr, "Share Name (AFS Path)\n");
1241 fprintf(stderr, "---------------------\n");
1242 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1245 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1246 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1248 strcpy(sbmtpath, cm_confDir);
1250 strcat(sbmtpath, "/afsdsbmt.ini");
1251 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1252 shareBuf, sizeof(shareBuf),
1258 this_share = shareBuf;
1262 /*strcpy(shareNameList[num_shares], this_share);*/
1263 len = GetPrivateProfileString("AFS Submounts", this_share,
1270 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1273 if (*p == '\\') *p = '/'; /* change to / */
1277 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1278 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1281 while (*this_share != 0) this_share++; /* find next NUL */
1282 this_share++; /* skip past the NUL */
1283 } while (*this_share != 0); /* stop at final NUL */
1289 typedef struct smb_findShare_rock {
1293 } smb_findShare_rock_t;
1295 #define SMB_FINDSHARE_EXACT_MATCH 1
1296 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1298 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1302 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1303 if(!strnicmp(dep->name, vrock->shareName, 12)) {
1304 if(!stricmp(dep->name, vrock->shareName))
1305 matchType = SMB_FINDSHARE_EXACT_MATCH;
1307 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1308 if(vrock->match) free(vrock->match);
1309 vrock->match = strdup(dep->name);
1310 vrock->matchType = matchType;
1312 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1313 return CM_ERROR_STOPNOW;
1319 /* find a shareName in the table of submounts */
1320 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1324 char pathName[1024];
1329 char sbmtpath[MAX_PATH];
1334 DWORD allSubmount = 1;
1336 /* if allSubmounts == 0, only return the //mountRoot/all share
1337 * if in fact it has been been created in the subMounts table.
1338 * This is to allow sites that want to restrict access to the
1341 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1342 0, KEY_QUERY_VALUE, &parmKey);
1343 if (code == ERROR_SUCCESS) {
1344 len = sizeof(allSubmount);
1345 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1346 (BYTE *) &allSubmount, &len);
1347 if (code != ERROR_SUCCESS) {
1350 RegCloseKey (parmKey);
1353 if (allSubmount && _stricmp(shareName, "all") == 0) {
1358 /* In case, the all share is disabled we need to still be able
1359 * to handle ioctl requests
1361 if (_stricmp(shareName, "ioctl$") == 0) {
1362 *pathNamep = strdup("/.__ioctl__");
1366 if (_stricmp(shareName, "IPC$") == 0 ||
1367 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1368 _stricmp(shareName, "DESKTOP.INI") == 0
1375 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1376 0, KEY_QUERY_VALUE, &parmKey);
1377 if (code == ERROR_SUCCESS) {
1378 len = sizeof(pathName);
1379 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1380 (BYTE *) pathName, &len);
1381 if (code != ERROR_SUCCESS)
1383 RegCloseKey (parmKey);
1388 strcpy(sbmtpath, cm_confDir);
1389 strcat(sbmtpath, "/afsdsbmt.ini");
1390 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1391 pathName, sizeof(pathName), sbmtpath);
1393 if (len != 0 && len != sizeof(pathName) - 1) {
1394 /* We can accept either unix or PC style AFS pathnames. Convert
1395 * Unix-style to PC style here for internal use.
1398 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1399 p += strlen(cm_mountRoot); /* skip mount path */
1402 if (*q == '/') *q = '\\'; /* change to \ */
1408 if (var = smb_stristr(p, VNUserName)) {
1409 if (uidp && uidp->unp)
1410 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1412 smb_subst(p, var, sizeof(VNUserName)," ");
1414 else if (var = smb_stristr(p, VNLCUserName))
1416 if (uidp && uidp->unp)
1417 strcpy(temp, uidp->unp->name);
1421 smb_subst(p, var, sizeof(VNLCUserName), temp);
1423 else if (var = smb_stristr(p, VNComputerName))
1425 sizeTemp = sizeof(temp);
1426 GetComputerName((LPTSTR)temp, &sizeTemp);
1427 smb_subst(p, var, sizeof(VNComputerName), temp);
1429 else if (var = smb_stristr(p, VNLCComputerName))
1431 sizeTemp = sizeof(temp);
1432 GetComputerName((LPTSTR)temp, &sizeTemp);
1434 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1439 *pathNamep = strdup(p);
1444 /* First lookup shareName in root.afs */
1446 smb_findShare_rock_t vrock;
1448 char * p = shareName;
1451 /* attempt to locate a partial match in root.afs. This is because
1452 when using the ANSI RAP calls, the share name is limited to 13 chars
1453 and hence is truncated. Of course we prefer exact matches. */
1455 thyper.HighPart = 0;
1458 vrock.shareName = shareName;
1460 vrock.matchType = 0;
1462 cm_HoldSCache(cm_rootSCachep);
1463 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1464 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1465 cm_ReleaseSCache(cm_rootSCachep);
1467 if(vrock.matchType) {
1468 sprintf(pathName,"/%s/",vrock.match);
1469 *pathNamep = strdup(strlwr(pathName));
1474 /* if we get here, there was no match for the share in root.afs */
1475 /* so try to create \\<netbiosName>\<cellname> */
1480 /* Get the full name for this cell */
1481 code = cm_SearchCellFile(p, temp, 0, 0);
1482 #ifdef AFS_AFSDB_ENV
1483 if (code && cm_dnsEnabled) {
1485 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1488 /* construct the path */
1490 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1491 *pathNamep = strdup(strlwr(pathName));
1500 /* Client-side offline caching policy types */
1501 #define CSC_POLICY_MANUAL 0
1502 #define CSC_POLICY_DOCUMENTS 1
1503 #define CSC_POLICY_PROGRAMS 2
1504 #define CSC_POLICY_DISABLE 3
1506 int smb_FindShareCSCPolicy(char *shareName)
1512 int retval = CSC_POLICY_MANUAL;
1514 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1515 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1518 REG_OPTION_NON_VOLATILE,
1524 len = sizeof(policy);
1525 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1527 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1529 else if (stricmp(policy, "documents") == 0)
1531 retval = CSC_POLICY_DOCUMENTS;
1533 else if (stricmp(policy, "programs") == 0)
1535 retval = CSC_POLICY_PROGRAMS;
1537 else if (stricmp(policy, "disable") == 0)
1539 retval = CSC_POLICY_DISABLE;
1542 RegCloseKey(hkCSCPolicy);
1546 /* find a dir search structure by cookie value, and return it held.
1547 * Must be called with smb_globalLock held.
1549 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1551 smb_dirSearch_t *dsp;
1553 for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1554 if (dsp->cookie == cookie) {
1555 if (dsp != smb_firstDirSearchp) {
1556 /* move to head of LRU queue, too, if we're not already there */
1557 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1558 smb_lastDirSearchp = (smb_dirSearch_t *)
1560 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1561 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1562 if (!smb_lastDirSearchp)
1563 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1572 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1574 lock_ObtainWrite(&smb_globalLock);
1575 dsp->flags |= SMB_DIRSEARCH_DELETE;
1576 lock_ReleaseWrite(&smb_globalLock);
1577 lock_ObtainMutex(&dsp->mx);
1578 if(dsp->scp != NULL) {
1579 lock_ObtainMutex(&dsp->scp->mx);
1580 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1581 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1582 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1583 dsp->scp->bulkStatProgress = hones;
1585 lock_ReleaseMutex(&dsp->scp->mx);
1587 lock_ReleaseMutex(&dsp->mx);
1590 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1596 lock_ObtainWrite(&smb_globalLock);
1597 osi_assert(dsp->refCount-- > 0);
1598 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1599 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1600 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1601 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1602 lock_FinalizeMutex(&dsp->mx);
1606 lock_ReleaseWrite(&smb_globalLock);
1608 /* do this now to avoid spurious locking hierarchy creation */
1609 if (scp) cm_ReleaseSCache(scp);
1612 /* find a dir search structure by cookie value, and return it held */
1613 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1615 smb_dirSearch_t *dsp;
1617 lock_ObtainWrite(&smb_globalLock);
1618 dsp = smb_FindDirSearchNL(cookie);
1619 lock_ReleaseWrite(&smb_globalLock);
1623 /* GC some dir search entries, in the address space expected by the specific protocol.
1624 * Must be called with smb_globalLock held; release the lock temporarily.
1626 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1627 void smb_GCDirSearches(int isV3)
1629 smb_dirSearch_t *prevp;
1630 smb_dirSearch_t *tp;
1631 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1635 victimCount = 0; /* how many have we got so far */
1636 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1637 /* we'll move tp from queue, so
1640 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1641 /* if no one is using this guy, and we're either in the new protocol,
1642 * or we're in the old one and this is a small enough ID to be useful
1643 * to the old protocol, GC this guy.
1645 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1646 /* hold and delete */
1647 tp->flags |= SMB_DIRSEARCH_DELETE;
1648 victimsp[victimCount++] = tp;
1652 /* don't do more than this */
1653 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1656 /* now release them */
1657 lock_ReleaseWrite(&smb_globalLock);
1658 for(i = 0; i < victimCount; i++) {
1659 smb_ReleaseDirSearch(victimsp[i]);
1661 lock_ObtainWrite(&smb_globalLock);
1664 /* function for allocating a dir search entry. We need these to remember enough context
1665 * since we don't get passed the path from call to call during a directory search.
1667 * Returns a held dir search structure, and bumps the reference count on the vnode,
1668 * since it saves a pointer to the vnode.
1670 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1672 smb_dirSearch_t *dsp;
1676 lock_ObtainWrite(&smb_globalLock);
1679 /* what's the biggest ID allowed in this version of the protocol */
1680 if (isV3) maxAllowed = 65535;
1681 else maxAllowed = 255;
1684 /* twice so we have enough tries to find guys we GC after one pass;
1685 * 10 extra is just in case I mis-counted.
1687 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1688 __FILE__, __LINE__);
1689 if (smb_dirSearchCounter > maxAllowed) {
1690 smb_dirSearchCounter = 1;
1691 smb_GCDirSearches(isV3); /* GC some (drops global lock) */
1693 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1695 /* don't need to watch for refcount zero and deleted, since
1696 * we haven't dropped the global lock.
1699 ++smb_dirSearchCounter;
1703 dsp = malloc(sizeof(*dsp));
1704 memset(dsp, 0, sizeof(*dsp));
1705 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1706 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1707 dsp->cookie = smb_dirSearchCounter;
1708 ++smb_dirSearchCounter;
1710 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1711 dsp->lastTime = osi_Time();
1714 lock_ReleaseWrite(&smb_globalLock);
1718 static smb_packet_t *GetPacket(void)
1722 unsigned int npar, seg, tb_sel;
1725 lock_ObtainWrite(&smb_globalLock);
1726 tbp = smb_packetFreeListp;
1728 smb_packetFreeListp = tbp->nextp;
1729 lock_ReleaseWrite(&smb_globalLock);
1732 tbp = calloc(65540,1);
1734 tbp = malloc(sizeof(smb_packet_t));
1736 tbp->magic = SMB_PACKETMAGIC;
1739 tbp->resumeCode = 0;
1745 tbp->ncb_length = 0;
1750 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1753 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1755 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1757 osi_panic("",__FILE__,__LINE__);
1760 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1765 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1766 tbp->dos_pkt_sel = tb_sel;
1769 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1774 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1778 memcpy(tbp, pkt, sizeof(smb_packet_t));
1779 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1783 static NCB *GetNCB(void)
1788 unsigned int npar, seg, tb_sel;
1791 lock_ObtainWrite(&smb_globalLock);
1792 tbp = smb_ncbFreeListp;
1794 smb_ncbFreeListp = tbp->nextp;
1795 lock_ReleaseWrite(&smb_globalLock);
1798 tbp = calloc(sizeof(*tbp),1);
1800 tbp = malloc(sizeof(*tbp));
1801 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1804 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1806 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1808 osi_panic("",__FILE__,__LINE__);
1810 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1815 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1816 tbp->dos_ncb_sel = tb_sel;
1818 tbp->magic = SMB_NCBMAGIC;
1821 osi_assert(tbp->magic == SMB_NCBMAGIC);
1823 memset(&tbp->ncb, 0, sizeof(NCB));
1826 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1831 void smb_FreePacket(smb_packet_t *tbp)
1833 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1835 lock_ObtainWrite(&smb_globalLock);
1836 tbp->nextp = smb_packetFreeListp;
1837 smb_packetFreeListp = tbp;
1838 tbp->magic = SMB_PACKETMAGIC;
1841 tbp->resumeCode = 0;
1847 tbp->ncb_length = 0;
1849 lock_ReleaseWrite(&smb_globalLock);
1852 static void FreeNCB(NCB *bufferp)
1856 tbp = (smb_ncb_t *) bufferp;
1857 osi_assert(tbp->magic == SMB_NCBMAGIC);
1859 lock_ObtainWrite(&smb_globalLock);
1860 tbp->nextp = smb_ncbFreeListp;
1861 smb_ncbFreeListp = tbp;
1862 lock_ReleaseWrite(&smb_globalLock);
1865 /* get a ptr to the data part of a packet, and its count */
1866 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1870 unsigned char *afterParmsp;
1872 parmBytes = *smbp->wctp << 1;
1873 afterParmsp = smbp->wctp + parmBytes + 1;
1875 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1876 if (nbytesp) *nbytesp = dataBytes;
1878 /* don't forget to skip the data byte count, since it follows
1879 * the parameters; that's where the "2" comes from below.
1881 return (unsigned char *) (afterParmsp + 2);
1884 /* must set all the returned parameters before playing around with the
1885 * data region, since the data region is located past the end of the
1886 * variable number of parameters.
1888 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1890 unsigned char *afterParmsp;
1892 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1894 *afterParmsp++ = dsize & 0xff;
1895 *afterParmsp = (dsize>>8) & 0xff;
1898 /* return the parm'th parameter in the smbp packet */
1899 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1902 unsigned char *parmDatap;
1904 parmCount = *smbp->wctp;
1906 if (parm >= parmCount) {
1911 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1913 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1914 parm, parmCount, smbp->ncb_length);
1917 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1918 1, smbp->ncb_length, ptbuf, smbp);
1919 DeregisterEventSource(h);
1921 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1922 osi_panic(s, __FILE__, __LINE__);
1924 parmDatap = smbp->wctp + (2*parm) + 1;
1926 return parmDatap[0] + (parmDatap[1] << 8);
1929 /* return the parm'th parameter in the smbp packet */
1930 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1933 unsigned char *parmDatap;
1935 parmCount = *smbp->wctp;
1937 if (parm * 2 + offset >= parmCount * 2) {
1942 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1944 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1945 parm, offset, parmCount, smbp->ncb_length);
1948 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1949 1, smbp->ncb_length, ptbuf, smbp);
1950 DeregisterEventSource(h);
1952 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1953 osi_panic(s, __FILE__, __LINE__);
1955 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1957 return parmDatap[0] + (parmDatap[1] << 8);
1960 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1964 /* make sure we have enough slots */
1965 if (*smbp->wctp <= slot)
1966 *smbp->wctp = slot+1;
1968 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1969 *parmDatap++ = parmValue & 0xff;
1970 *parmDatap = (parmValue>>8) & 0xff;
1973 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1977 /* make sure we have enough slots */
1978 if (*smbp->wctp <= slot)
1979 *smbp->wctp = slot+2;
1981 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1982 *parmDatap++ = parmValue & 0xff;
1983 *parmDatap++ = (parmValue>>8) & 0xff;
1984 *parmDatap++ = (parmValue>>16) & 0xff;
1985 *parmDatap++ = (parmValue>>24) & 0xff;
1988 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1993 /* make sure we have enough slots */
1994 if (*smbp->wctp <= slot)
1995 *smbp->wctp = slot+4;
1997 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1999 *parmDatap++ = *parmValuep++;
2002 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2006 /* make sure we have enough slots */
2007 if (*smbp->wctp <= slot) {
2008 if (smbp->oddByte) {
2010 *smbp->wctp = slot+1;
2015 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2016 *parmDatap++ = parmValue & 0xff;
2019 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2023 lastSlashp = strrchr(inPathp, '\\');
2025 *lastComponentp = lastSlashp;
2028 if (inPathp == lastSlashp)
2030 *outPathp++ = *inPathp++;
2039 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2044 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2049 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2055 tlen = inp[0] + (inp[1]<<8);
2056 inp += 2; /* skip length field */
2059 *chainpp = inp + tlen;
2068 /* format a packet as a response */
2069 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2074 outp = (smb_t *) op;
2076 /* zero the basic structure through the smb_wct field, and zero the data
2077 * size field, assuming that wct stays zero; otherwise, you have to
2078 * explicitly set the data size field, too.
2080 inSmbp = (smb_t *) inp;
2081 memset(outp, 0, sizeof(smb_t)+2);
2087 outp->com = inSmbp->com;
2088 outp->tid = inSmbp->tid;
2089 outp->pid = inSmbp->pid;
2090 outp->uid = inSmbp->uid;
2091 outp->mid = inSmbp->mid;
2092 outp->res[0] = inSmbp->res[0];
2093 outp->res[1] = inSmbp->res[1];
2094 op->inCom = inSmbp->com;
2096 outp->reb = 0x80; /* SERVER_RESP */
2097 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2099 /* copy fields in generic packet area */
2100 op->wctp = &outp->wct;
2103 /* send a (probably response) packet; vcp tells us to whom to send it.
2104 * we compute the length by looking at wct and bcc fields.
2106 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2123 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2126 memset((char *)ncbp, 0, sizeof(NCB));
2128 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2129 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2130 extra += tp[0] + (tp[1]<<8);
2131 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2132 extra += 3; /* wct and length fields */
2134 ncbp->ncb_length = extra; /* bytes to send */
2135 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2136 ncbp->ncb_lana_num = vcp->lana;
2137 ncbp->ncb_command = NCBSEND; /* op means send data */
2139 ncbp->ncb_buffer = (char *) inp;/* packet */
2140 code = Netbios(ncbp);
2142 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2143 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2145 /* copy header information from virtual to DOS address space */
2146 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2147 code = Netbios(ncbp, dos_ncb);
2151 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2157 void smb_MapNTError(long code, unsigned long *NTStatusp)
2159 unsigned long NTStatus;
2161 /* map CM_ERROR_* errors to NT 32-bit status codes */
2162 /* NT Status codes are listed in ntstatus.h not winerror.h */
2163 if (code == CM_ERROR_NOSUCHCELL) {
2164 NTStatus = 0xC000000FL; /* No such file */
2166 else if (code == CM_ERROR_NOSUCHVOLUME) {
2167 NTStatus = 0xC000000FL; /* No such file */
2169 else if (code == CM_ERROR_TIMEDOUT) {
2170 NTStatus = 0xC00000CFL; /* Sharing Paused */
2172 else if (code == CM_ERROR_RETRY) {
2173 NTStatus = 0xC000022DL; /* Retry */
2175 else if (code == CM_ERROR_NOACCESS) {
2176 NTStatus = 0xC0000022L; /* Access denied */
2178 else if (code == CM_ERROR_READONLY) {
2179 NTStatus = 0xC00000A2L; /* Write protected */
2181 else if (code == CM_ERROR_NOSUCHFILE) {
2182 NTStatus = 0xC000000FL; /* No such file */
2184 else if (code == CM_ERROR_NOSUCHPATH) {
2185 NTStatus = 0xC000003AL; /* Object path not found */
2187 else if (code == CM_ERROR_TOOBIG) {
2188 NTStatus = 0xC000007BL; /* Invalid image format */
2190 else if (code == CM_ERROR_INVAL) {
2191 NTStatus = 0xC000000DL; /* Invalid parameter */
2193 else if (code == CM_ERROR_BADFD) {
2194 NTStatus = 0xC0000008L; /* Invalid handle */
2196 else if (code == CM_ERROR_BADFDOP) {
2197 NTStatus = 0xC0000022L; /* Access denied */
2199 else if (code == CM_ERROR_EXISTS) {
2200 NTStatus = 0xC0000035L; /* Object name collision */
2202 else if (code == CM_ERROR_NOTEMPTY) {
2203 NTStatus = 0xC0000101L; /* Directory not empty */
2205 else if (code == CM_ERROR_CROSSDEVLINK) {
2206 NTStatus = 0xC00000D4L; /* Not same device */
2208 else if (code == CM_ERROR_NOTDIR) {
2209 NTStatus = 0xC0000103L; /* Not a directory */
2211 else if (code == CM_ERROR_ISDIR) {
2212 NTStatus = 0xC00000BAL; /* File is a directory */
2214 else if (code == CM_ERROR_BADOP) {
2216 /* I have no idea where this comes from */
2217 NTStatus = 0xC09820FFL; /* SMB no support */
2219 NTStatus = 0xC00000BBL; /* Not supported */
2220 #endif /* COMMENT */
2222 else if (code == CM_ERROR_BADSHARENAME) {
2223 NTStatus = 0xC00000CCL; /* Bad network name */
2225 else if (code == CM_ERROR_NOIPC) {
2227 NTStatus = 0xC0000022L; /* Access Denied */
2229 NTStatus = 0xC000013DL; /* Remote Resources */
2232 else if (code == CM_ERROR_CLOCKSKEW) {
2233 NTStatus = 0xC0000133L; /* Time difference at DC */
2235 else if (code == CM_ERROR_BADTID) {
2236 NTStatus = 0xC0982005L; /* SMB bad TID */
2238 else if (code == CM_ERROR_USESTD) {
2239 NTStatus = 0xC09820FBL; /* SMB use standard */
2241 else if (code == CM_ERROR_QUOTA) {
2243 NTStatus = 0xC0000044L; /* Quota exceeded */
2245 NTStatus = 0xC000007FL; /* Disk full */
2248 else if (code == CM_ERROR_SPACE) {
2249 NTStatus = 0xC000007FL; /* Disk full */
2251 else if (code == CM_ERROR_ATSYS) {
2252 NTStatus = 0xC0000033L; /* Object name invalid */
2254 else if (code == CM_ERROR_BADNTFILENAME) {
2255 NTStatus = 0xC0000033L; /* Object name invalid */
2257 else if (code == CM_ERROR_WOULDBLOCK) {
2258 NTStatus = 0xC0000055L; /* Lock not granted */
2260 else if (code == CM_ERROR_PARTIALWRITE) {
2261 NTStatus = 0xC000007FL; /* Disk full */
2263 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2264 NTStatus = 0xC0000023L; /* Buffer too small */
2266 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2267 NTStatus = 0xC0000035L; /* Object name collision */
2269 else if (code == CM_ERROR_BADPASSWORD) {
2270 NTStatus = 0xC000006DL; /* unknown username or bad password */
2272 else if (code == CM_ERROR_BADLOGONTYPE) {
2273 NTStatus = 0xC000015BL; /* logon type not granted */
2275 else if (code == CM_ERROR_GSSCONTINUE) {
2276 NTStatus = 0xC0000016L; /* more processing required */
2279 NTStatus = 0xC0982001L; /* SMB non-specific error */
2282 *NTStatusp = NTStatus;
2283 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2286 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2287 unsigned char *classp)
2289 unsigned char class;
2290 unsigned short error;
2292 /* map CM_ERROR_* errors to SMB errors */
2293 if (code == CM_ERROR_NOSUCHCELL) {
2295 error = 3; /* bad path */
2297 else if (code == CM_ERROR_NOSUCHVOLUME) {
2299 error = 3; /* bad path */
2301 else if (code == CM_ERROR_TIMEDOUT) {
2303 error = 81; /* server is paused */
2305 else if (code == CM_ERROR_RETRY) {
2306 class = 2; /* shouldn't happen */
2309 else if (code == CM_ERROR_NOACCESS) {
2311 error = 4; /* bad access */
2313 else if (code == CM_ERROR_READONLY) {
2315 error = 19; /* read only */
2317 else if (code == CM_ERROR_NOSUCHFILE) {
2319 error = 2; /* ENOENT! */
2321 else if (code == CM_ERROR_NOSUCHPATH) {
2323 error = 3; /* Bad path */
2325 else if (code == CM_ERROR_TOOBIG) {
2327 error = 11; /* bad format */
2329 else if (code == CM_ERROR_INVAL) {
2330 class = 2; /* server non-specific error code */
2333 else if (code == CM_ERROR_BADFD) {
2335 error = 6; /* invalid file handle */
2337 else if (code == CM_ERROR_BADFDOP) {
2338 class = 1; /* invalid op on FD */
2341 else if (code == CM_ERROR_EXISTS) {
2343 error = 80; /* file already exists */
2345 else if (code == CM_ERROR_NOTEMPTY) {
2347 error = 5; /* delete directory not empty */
2349 else if (code == CM_ERROR_CROSSDEVLINK) {
2351 error = 17; /* EXDEV */
2353 else if (code == CM_ERROR_NOTDIR) {
2354 class = 1; /* bad path */
2357 else if (code == CM_ERROR_ISDIR) {
2358 class = 1; /* access denied; DOS doesn't have a good match */
2361 else if (code == CM_ERROR_BADOP) {
2365 else if (code == CM_ERROR_BADSHARENAME) {
2369 else if (code == CM_ERROR_NOIPC) {
2371 error = 4; /* bad access */
2373 else if (code == CM_ERROR_CLOCKSKEW) {
2374 class = 1; /* invalid function */
2377 else if (code == CM_ERROR_BADTID) {
2381 else if (code == CM_ERROR_USESTD) {
2385 else if (code == CM_ERROR_REMOTECONN) {
2389 else if (code == CM_ERROR_QUOTA) {
2390 if (vcp->flags & SMB_VCFLAG_USEV3) {
2392 error = 39; /* disk full */
2396 error = 5; /* access denied */
2399 else if (code == CM_ERROR_SPACE) {
2400 if (vcp->flags & SMB_VCFLAG_USEV3) {
2402 error = 39; /* disk full */
2406 error = 5; /* access denied */
2409 else if (code == CM_ERROR_PARTIALWRITE) {
2411 error = 39; /* disk full */
2413 else if (code == CM_ERROR_ATSYS) {
2415 error = 2; /* ENOENT */
2417 else if (code == CM_ERROR_WOULDBLOCK) {
2419 error = 33; /* lock conflict */
2421 else if (code == CM_ERROR_NOFILES) {
2423 error = 18; /* no files in search */
2425 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2427 error = 183; /* Samba uses this */
2429 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2430 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2432 error = 2; /* bad password */
2441 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2444 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2446 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2447 return CM_ERROR_BADOP;
2450 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2452 unsigned short EchoCount, i;
2453 char *data, *outdata;
2456 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2458 for (i=1; i<=EchoCount; i++) {
2459 data = smb_GetSMBData(inp, &dataSize);
2460 smb_SetSMBParm(outp, 0, i);
2461 smb_SetSMBDataLength(outp, dataSize);
2462 outdata = smb_GetSMBData(outp, NULL);
2463 memcpy(outdata, data, dataSize);
2464 smb_SendPacket(vcp, outp);
2470 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2473 long count, minCount, finalCount;
2477 cm_user_t *userp = NULL;
2481 char *rawBuf = NULL;
2483 dos_ptr rawBuf = NULL;
2490 fd = smb_GetSMBParm(inp, 0);
2491 count = smb_GetSMBParm(inp, 3);
2492 minCount = smb_GetSMBParm(inp, 4);
2493 offset.HighPart = 0; /* too bad */
2494 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2496 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2497 fd, offset.LowPart, count);
2499 fidp = smb_FindFID(vcp, fd, 0);
2503 lock_ObtainMutex(&smb_RawBufLock);
2505 /* Get a raw buf, from head of list */
2506 rawBuf = smb_RawBufs;
2508 smb_RawBufs = *(char **)smb_RawBufs;
2510 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2513 lock_ReleaseMutex(&smb_RawBufLock);
2517 if (fidp->flags & SMB_FID_IOCTL)
2520 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2522 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2525 /* Give back raw buffer */
2526 lock_ObtainMutex(&smb_RawBufLock);
2528 *((char **) rawBuf) = smb_RawBufs;
2530 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2533 smb_RawBufs = rawBuf;
2534 lock_ReleaseMutex(&smb_RawBufLock);
2537 smb_ReleaseFID(fidp);
2541 userp = smb_GetUser(vcp, inp);
2544 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2546 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2547 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2548 userp, &finalCount, TRUE /* rawFlag */);
2555 cm_ReleaseUser(userp);
2558 smb_ReleaseFID(fidp);
2563 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2565 memset((char *)ncbp, 0, sizeof(NCB));
2567 ncbp->ncb_length = (unsigned short) finalCount;
2568 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2569 ncbp->ncb_lana_num = vcp->lana;
2570 ncbp->ncb_command = NCBSEND;
2571 ncbp->ncb_buffer = rawBuf;
2574 code = Netbios(ncbp);
2576 code = Netbios(ncbp, dos_ncb);
2579 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2582 /* Give back raw buffer */
2583 lock_ObtainMutex(&smb_RawBufLock);
2585 *((char **) rawBuf) = smb_RawBufs;
2587 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2590 smb_RawBufs = rawBuf;
2591 lock_ReleaseMutex(&smb_RawBufLock);
2597 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2599 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2604 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2606 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2611 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2618 int protoIndex; /* index we're using */
2623 char protocol_array[10][1024]; /* protocol signature of the client */
2624 int caps; /* capabilities */
2627 TIME_ZONE_INFORMATION tzi;
2629 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2633 DWORD now = GetCurrentTime();
2634 if (now - last_msg_time >= 30000
2635 && now - last_msg_time <= 90000) {
2637 "Setting dead_vcp %x", active_vcp);
2639 smb_ReleaseVC(dead_vcp);
2641 "Previous dead_vcp %x", dead_vcp);
2643 smb_HoldVC(active_vcp);
2644 dead_vcp = active_vcp;
2645 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2650 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2652 namep = smb_GetSMBData(inp, &dbytes);
2655 coreProtoIndex = -1; /* not found */
2658 while(namex < dbytes) {
2659 osi_Log1(smb_logp, "Protocol %s",
2660 osi_LogSaveString(smb_logp, namep+1));
2661 strcpy(protocol_array[tcounter], namep+1);
2663 /* namep points at the first protocol, or really, a 0x02
2664 * byte preceding the null-terminated ASCII name.
2666 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2667 coreProtoIndex = tcounter;
2669 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2670 v3ProtoIndex = tcounter;
2672 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2673 NTProtoIndex = tcounter;
2676 /* compute size of protocol entry */
2677 entryLength = strlen(namep+1);
2678 entryLength += 2; /* 0x02 bytes and null termination */
2680 /* advance over this protocol entry */
2681 namex += entryLength;
2682 namep += entryLength;
2683 tcounter++; /* which proto entry we're looking at */
2686 if (NTProtoIndex != -1) {
2687 protoIndex = NTProtoIndex;
2688 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2690 else if (v3ProtoIndex != -1) {
2691 protoIndex = v3ProtoIndex;
2692 vcp->flags |= SMB_VCFLAG_USEV3;
2694 else if (coreProtoIndex != -1) {
2695 protoIndex = coreProtoIndex;
2696 vcp->flags |= SMB_VCFLAG_USECORE;
2698 else protoIndex = -1;
2700 if (protoIndex == -1)
2701 return CM_ERROR_INVAL;
2702 else if (NTProtoIndex != -1) {
2703 smb_SetSMBParm(outp, 0, protoIndex);
2704 if (smb_authType != SMB_AUTH_NONE) {
2705 smb_SetSMBParmByte(outp, 1,
2706 NEGOTIATE_SECURITY_USER_LEVEL |
2707 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2709 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2711 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2712 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2713 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2714 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2715 /* The session key is not a well documented field however most clients
2716 * will echo back the session key to the server. Currently we are using
2717 * the same value for all sessions. We should generate a random value
2718 * and store it into the vcp
2720 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2721 smb_SetSMBParm(outp, 8, 1);
2723 * Tried changing the capabilities to support for W2K - defect 117695
2724 * Maybe something else needs to be changed here?
2728 smb_SetSMBParmLong(outp, 9, 0x43fd);
2730 smb_SetSMBParmLong(outp, 9, 0x251);
2733 * 32-bit error codes *
2737 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2738 NTNEGOTIATE_CAPABILITY_NTFIND |
2739 NTNEGOTIATE_CAPABILITY_RAWMODE |
2740 NTNEGOTIATE_CAPABILITY_NTSMB;
2742 if ( smb_authType == SMB_AUTH_EXTENDED )
2743 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2745 smb_SetSMBParmLong(outp, 9, caps);
2747 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2748 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2749 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2751 GetTimeZoneInformation(&tzi);
2752 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2754 if (smb_authType == SMB_AUTH_NTLM) {
2755 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2756 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2757 /* paste in encryption key */
2758 datap = smb_GetSMBData(outp, NULL);
2759 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2760 /* and the faux domain name */
2761 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2762 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2766 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2768 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2770 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2772 datap = smb_GetSMBData(outp, NULL);
2773 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2776 datap += sizeof(smb_ServerGUID);
2777 memcpy(datap, secBlob, secBlobLength);
2781 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2782 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2785 else if (v3ProtoIndex != -1) {
2786 smb_SetSMBParm(outp, 0, protoIndex);
2788 /* NOTE: Extended authentication cannot be negotiated with v3
2789 * therefore we fail over to NTLM
2791 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2792 smb_SetSMBParm(outp, 1,
2793 NEGOTIATE_SECURITY_USER_LEVEL |
2794 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2796 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2798 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2799 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2800 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2801 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2802 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2803 smb_SetSMBParm(outp, 7, 1);
2805 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2806 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2807 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2809 GetTimeZoneInformation(&tzi);
2810 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2812 /* NOTE: Extended authentication cannot be negotiated with v3
2813 * therefore we fail over to NTLM
2815 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2816 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2817 smb_SetSMBParm(outp, 12, 0); /* resvd */
2818 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2819 datap = smb_GetSMBData(outp, NULL);
2820 /* paste in a new encryption key */
2821 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2822 /* and the faux domain name */
2823 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2825 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2826 smb_SetSMBParm(outp, 12, 0); /* resvd */
2827 smb_SetSMBDataLength(outp, 0);
2830 else if (coreProtoIndex != -1) { /* not really supported anymore */
2831 smb_SetSMBParm(outp, 0, protoIndex);
2832 smb_SetSMBDataLength(outp, 0);
2837 void smb_Daemon(void *parmp)
2839 afs_uint32 count = 0;
2844 if ((count % 72) == 0) { /* every five minutes */
2846 long old_localZero = smb_localZero;
2848 /* Initialize smb_localZero */
2849 myTime.tm_isdst = -1; /* compute whether on DST or not */
2850 myTime.tm_year = 70;
2856 smb_localZero = mktime(&myTime);
2858 smb_CalculateNowTZ();
2860 #ifdef AFS_FREELANCE
2861 if ( smb_localZero != old_localZero )
2862 cm_noteLocalMountPointChange();
2865 /* XXX GC dir search entries */
2869 void smb_WaitingLocksDaemon()
2871 smb_waitingLock_t *wL, *nwL;
2874 smb_packet_t *inp, *outp;
2879 lock_ObtainWrite(&smb_globalLock);
2880 nwL = smb_allWaitingLocks;
2882 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2891 lock_ObtainWrite(&smb_globalLock);
2893 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2894 lock_ReleaseWrite(&smb_globalLock);
2895 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2896 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2897 if (code == CM_ERROR_WOULDBLOCK) {
2899 if (wL->timeRemaining != 0xffffffff
2900 && (wL->timeRemaining -= 1000) < 0)
2909 ncbp->ncb_length = inp->ncb_length;
2910 inp->spacep = cm_GetSpace();
2912 /* Remove waitingLock from list */
2913 lock_ObtainWrite(&smb_globalLock);
2914 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2916 lock_ReleaseWrite(&smb_globalLock);
2918 /* Resume packet processing */
2920 smb_SetSMBDataLength(outp, 0);
2921 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2922 outp->resumeCode = code;
2924 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2927 cm_FreeSpace(inp->spacep);
2928 smb_FreePacket(inp);
2929 smb_FreePacket(outp);
2937 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2939 osi_Log0(smb_logp, "SMB receive get disk attributes");
2941 smb_SetSMBParm(outp, 0, 32000);
2942 smb_SetSMBParm(outp, 1, 64);
2943 smb_SetSMBParm(outp, 2, 1024);
2944 smb_SetSMBParm(outp, 3, 30000);
2945 smb_SetSMBParm(outp, 4, 0);
2946 smb_SetSMBDataLength(outp, 0);
2950 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2954 unsigned short newTid;
2955 char shareName[256];
2963 osi_Log0(smb_logp, "SMB receive tree connect");
2965 /* parse input parameters */
2966 tp = smb_GetSMBData(inp, NULL);
2967 pathp = smb_ParseASCIIBlock(tp, &tp);
2968 passwordp = smb_ParseASCIIBlock(tp, &tp);
2969 tp = strrchr(pathp, '\\');
2971 return CM_ERROR_BADSMB;
2972 strcpy(shareName, tp+1);
2974 userp = smb_GetUser(vcp, inp);
2976 lock_ObtainMutex(&vcp->mx);
2977 newTid = vcp->tidCounter++;
2978 lock_ReleaseMutex(&vcp->mx);
2980 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2981 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
2982 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
2984 smb_ReleaseUID(uidp);
2986 smb_ReleaseTID(tidp);
2987 return CM_ERROR_BADSHARENAME;
2989 lock_ObtainMutex(&tidp->mx);
2990 tidp->userp = userp;
2991 tidp->pathname = sharePath;
2992 lock_ReleaseMutex(&tidp->mx);
2993 smb_ReleaseTID(tidp);
2995 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2996 smb_SetSMBParm(rsp, 1, newTid);
2997 smb_SetSMBDataLength(rsp, 0);
2999 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3003 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3007 if (*inp++ != 0x1) return NULL;
3008 tlen = inp[0] + (inp[1]<<8);
3009 inp += 2; /* skip length field */
3012 *chainpp = inp + tlen;
3015 if (lengthp) *lengthp = tlen;
3020 /* set maskp to the mask part of the incoming path.
3021 * Mask is 11 bytes long (8.3 with the dot elided).
3022 * Returns true if succeeds with a valid name, otherwise it does
3023 * its best, but returns false.
3025 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3033 /* starts off valid */
3036 /* mask starts out all blanks */
3037 memset(maskp, ' ', 11);
3039 /* find last backslash, or use whole thing if there is none */
3040 tp = strrchr(pathp, '\\');
3041 if (!tp) tp = pathp;
3042 else tp++; /* skip slash */
3046 /* names starting with a dot are illegal */
3047 if (*tp == '.') valid8Dot3 = 0;
3051 if (tc == 0) return valid8Dot3;
3052 if (tc == '.' || tc == '"') break;
3053 if (i < 8) *up++ = tc;
3054 else valid8Dot3 = 0;
3057 /* if we get here, tp point after the dot */
3058 up = maskp+8; /* ext goes here */
3065 if (tc == '.' || tc == '"')
3068 /* copy extension if not too long */
3078 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3088 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3090 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3094 /* otherwise, we have a valid 8.3 name; see if we have a match,
3095 * treating '?' as a wildcard in maskp (but not in the file name).
3097 tp1 = umask; /* real name, in mask format */
3098 tp2 = maskp; /* mask, in mask format */
3099 for(i=0; i<11; i++) {
3100 tc1 = *tp1++; /* char from real name */
3101 tc2 = *tp2++; /* char from mask */
3102 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3103 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3106 if (tc2 == '?' && tc1 != ' ')
3113 /* we got a match */
3117 char *smb_FindMask(char *pathp)
3121 tp = strrchr(pathp, '\\'); /* find last slash */
3124 return tp+1; /* skip the slash */
3126 return pathp; /* no slash, return the entire path */
3129 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3131 unsigned char *pathp;
3133 unsigned char mask[11];
3134 unsigned char *statBlockp;
3135 unsigned char initStatBlock[21];
3138 osi_Log0(smb_logp, "SMB receive search volume");
3140 /* pull pathname and stat block out of request */
3141 tp = smb_GetSMBData(inp, NULL);
3142 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3143 osi_assert(pathp != NULL);
3144 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3145 osi_assert(statBlockp != NULL);
3147 statBlockp = initStatBlock;
3151 /* for returning to caller */
3152 smb_Get8Dot3MaskFromPath(mask, pathp);
3154 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3155 tp = smb_GetSMBData(outp, NULL);
3157 *tp++ = 43; /* bytes in a dir entry */
3158 *tp++ = 0; /* high byte in counter */
3160 /* now marshall the dir entry, starting with the search status */
3161 *tp++ = statBlockp[0]; /* Reserved */
3162 memcpy(tp, mask, 11); tp += 11; /* FileName */
3164 /* now pass back server use info, with 1st byte non-zero */
3166 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3168 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3170 *tp++ = 0x8; /* attribute: volume */
3180 /* 4 byte file size */
3186 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3187 memset(tp, ' ', 13);
3190 /* set the length of the data part of the packet to 43 + 3, for the dir
3191 * entry plus the 5 and the length fields.
3193 smb_SetSMBDataLength(outp, 46);
3197 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3198 cm_user_t *userp, cm_req_t *reqp)
3206 smb_dirListPatch_t *patchp;
3207 smb_dirListPatch_t *npatchp;
3209 for (patchp = *dirPatchespp; patchp; patchp =
3210 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3212 dptr = patchp->dptr;
3214 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3216 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3217 *dptr++ = SMB_ATTR_HIDDEN;
3220 lock_ObtainMutex(&scp->mx);
3221 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3222 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3224 lock_ReleaseMutex(&scp->mx);
3225 cm_ReleaseSCache(scp);
3226 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3227 *dptr++ = SMB_ATTR_HIDDEN;
3231 attr = smb_Attributes(scp);
3232 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3233 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3234 attr |= SMB_ATTR_HIDDEN;
3238 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3241 shortTemp = dosTime & 0xffff;
3242 *((u_short *)dptr) = shortTemp;
3245 /* and copy out date */
3246 shortTemp = (dosTime>>16) & 0xffff;
3247 *((u_short *)dptr) = shortTemp;
3250 /* copy out file length */
3251 *((u_long *)dptr) = scp->length.LowPart;
3253 lock_ReleaseMutex(&scp->mx);
3254 cm_ReleaseSCache(scp);
3257 /* now free the patches */
3258 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3259 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3263 /* and mark the list as empty */
3264 *dirPatchespp = NULL;
3269 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3278 smb_dirListPatch_t *dirListPatchesp;
3279 smb_dirListPatch_t *curPatchp;
3283 osi_hyper_t dirLength;
3284 osi_hyper_t bufferOffset;
3285 osi_hyper_t curOffset;
3287 unsigned char *inCookiep;
3288 smb_dirSearch_t *dsp;
3292 unsigned long clientCookie;
3293 cm_pageHeader_t *pageHeaderp;
3294 cm_user_t *userp = NULL;
3301 long nextEntryCookie;
3302 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3303 char resByte; /* reserved byte from the cookie */
3304 char *op; /* output data ptr */
3305 char *origOp; /* original value of op */
3306 cm_space_t *spacep; /* for pathname buffer */
3317 maxCount = smb_GetSMBParm(inp, 0);
3319 dirListPatchesp = NULL;
3321 caseFold = CM_FLAG_CASEFOLD;
3323 tp = smb_GetSMBData(inp, NULL);
3324 pathp = smb_ParseASCIIBlock(tp, &tp);
3325 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3327 /* bail out if request looks bad */
3328 if (!tp || !pathp) {
3329 return CM_ERROR_BADSMB;
3332 /* We can handle long names */
3333 if (vcp->flags & SMB_VCFLAG_USENT)
3334 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3336 /* make sure we got a whole search status */
3337 if (dataLength < 21) {
3338 nextCookie = 0; /* start at the beginning of the dir */
3341 attribute = smb_GetSMBParm(inp, 1);
3343 /* handle volume info in another function */
3344 if (attribute & 0x8)
3345 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3347 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3348 maxCount, osi_LogSaveString(smb_logp, pathp));
3350 if (*pathp == 0) { /* null pathp, treat as root dir */
3351 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3352 return CM_ERROR_NOFILES;
3356 dsp = smb_NewDirSearch(0);
3357 dsp->attribute = attribute;
3358 smb_Get8Dot3MaskFromPath(mask, pathp);
3359 memcpy(dsp->mask, mask, 11);
3361 /* track if this is likely to match a lot of entries */
3362 if (smb_IsStarMask(mask)) starPattern = 1;
3363 else starPattern = 0;
3366 /* pull the next cookie value out of the search status block */
3367 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3368 + (inCookiep[16]<<24);
3369 dsp = smb_FindDirSearch(inCookiep[12]);
3371 /* can't find dir search status; fatal error */
3372 return CM_ERROR_BADFD;
3374 attribute = dsp->attribute;
3375 resByte = inCookiep[0];
3377 /* copy out client cookie, in host byte order. Don't bother
3378 * interpreting it, since we're just passing it through, anyway.
3380 memcpy(&clientCookie, &inCookiep[17], 4);
3382 memcpy(mask, dsp->mask, 11);
3384 /* assume we're doing a star match if it has continued for more
3390 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3391 nextCookie, dsp->cookie, attribute);
3393 userp = smb_GetUser(vcp, inp);
3395 /* try to get the vnode for the path name next */
3396 lock_ObtainMutex(&dsp->mx);
3403 spacep = inp->spacep;
3404 smb_StripLastComponent(spacep->data, NULL, pathp);
3405 lock_ReleaseMutex(&dsp->mx);
3406 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3408 lock_ReleaseMutex(&dsp->mx);
3409 cm_ReleaseUser(userp);
3410 smb_DeleteDirSearch(dsp);
3411 smb_ReleaseDirSearch(dsp);
3412 return CM_ERROR_NOFILES;
3414 code = cm_NameI(cm_rootSCachep, spacep->data,
3415 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3416 lock_ObtainMutex(&dsp->mx);
3418 if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3420 /* we need one hold for the entry we just stored into,
3421 * and one for our own processing. When we're done with this
3422 * function, we'll drop the one for our own processing.
3423 * We held it once from the namei call, and so we do another hold
3427 lock_ObtainMutex(&scp->mx);
3428 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3429 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3430 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3431 dsp->flags |= SMB_DIRSEARCH_BULKST;
3433 lock_ReleaseMutex(&scp->mx);
3436 lock_ReleaseMutex(&dsp->mx);
3438 cm_ReleaseUser(userp);
3439 smb_DeleteDirSearch(dsp);
3440 smb_ReleaseDirSearch(dsp);
3444 /* reserves space for parameter; we'll adjust it again later to the
3445 * real count of the # of entries we returned once we've actually
3446 * assembled the directory listing.
3448 smb_SetSMBParm(outp, 0, 0);
3450 /* get the directory size */
3451 lock_ObtainMutex(&scp->mx);
3452 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3453 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3455 lock_ReleaseMutex(&scp->mx);
3456 cm_ReleaseSCache(scp);
3457 cm_ReleaseUser(userp);
3458 smb_DeleteDirSearch(dsp);
3459 smb_ReleaseDirSearch(dsp);
3463 dirLength = scp->length;
3465 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3466 curOffset.HighPart = 0;
3467 curOffset.LowPart = nextCookie;
3468 origOp = op = smb_GetSMBData(outp, NULL);
3469 /* and write out the basic header */
3470 *op++ = 5; /* variable block */
3471 op += 2; /* skip vbl block length; we'll fill it in later */
3475 /* make sure that curOffset.LowPart doesn't point to the first
3476 * 32 bytes in the 2nd through last dir page, and that it doesn't
3477 * point at the first 13 32-byte chunks in the first dir page,
3478 * since those are dir and page headers, and don't contain useful
3481 temp = curOffset.LowPart & (2048-1);
3482 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3483 /* we're in the first page */
3484 if (temp < 13*32) temp = 13*32;
3487 /* we're in a later dir page */
3488 if (temp < 32) temp = 32;
3491 /* make sure the low order 5 bits are zero */
3494 /* now put temp bits back ito curOffset.LowPart */
3495 curOffset.LowPart &= ~(2048-1);
3496 curOffset.LowPart |= temp;
3498 /* check if we've returned all the names that will fit in the
3501 if (returnedNames >= maxCount)
3504 /* check if we've passed the dir's EOF */
3505 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3507 /* see if we can use the bufferp we have now; compute in which page
3508 * the current offset would be, and check whether that's the offset
3509 * of the buffer we have. If not, get the buffer.
3511 thyper.HighPart = curOffset.HighPart;
3512 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3513 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3516 buf_Release(bufferp);
3519 lock_ReleaseMutex(&scp->mx);
3520 lock_ObtainRead(&scp->bufCreateLock);
3521 code = buf_Get(scp, &thyper, &bufferp);
3522 lock_ReleaseRead(&scp->bufCreateLock);
3524 /* now, if we're doing a star match, do bulk fetching of all of
3525 * the status info for files in the dir.
3528 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3530 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3531 LargeIntegerGreaterThanOrEqualTo(thyper,
3532 scp->bulkStatProgress)) {
3533 /* Don't bulk stat if risking timeout */
3534 int now = GetCurrentTime();
3535 if (now - req.startTime > 5000) {
3536 scp->bulkStatProgress = thyper;
3537 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3538 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3540 cm_TryBulkStat(scp, &thyper, userp, &req);
3544 lock_ObtainMutex(&scp->mx);
3547 bufferOffset = thyper;
3549 /* now get the data in the cache */
3551 code = cm_SyncOp(scp, bufferp, userp, &req,
3553 CM_SCACHESYNC_NEEDCALLBACK |
3554 CM_SCACHESYNC_READ);
3557 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3559 /* otherwise, load the buffer and try again */
3560 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3564 buf_Release(bufferp);
3568 } /* if (wrong buffer) ... */
3570 /* now we have the buffer containing the entry we're interested in; copy
3571 * it out if it represents a non-deleted entry.
3573 entryInDir = curOffset.LowPart & (2048-1);
3574 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3576 /* page header will help tell us which entries are free. Page header
3577 * can change more often than once per buffer, since AFS 3 dir page size
3578 * may be less than (but not more than a buffer package buffer.
3580 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3581 temp &= ~(2048 - 1); /* turn off intra-page bits */
3582 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3584 /* now determine which entry we're looking at in the page. If it is
3585 * free (there's a free bitmap at the start of the dir), we should
3586 * skip these 32 bytes.
3588 slotInPage = (entryInDir & 0x7e0) >> 5;
3589 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3590 /* this entry is free */
3591 numDirChunks = 1; /* only skip this guy */
3595 tp = bufferp->datap + entryInBuffer;
3596 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3598 /* while we're here, compute the next entry's location, too,
3599 * since we'll need it when writing out the cookie into the dir
3602 * XXXX Probably should do more sanity checking.
3604 numDirChunks = cm_NameEntries(dep->name, NULL);
3606 /* compute the offset of the cookie representing the next entry */
3607 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3609 /* Compute 8.3 name if necessary */
3610 actualName = dep->name;
3611 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3612 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3613 actualName = shortName;
3616 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3617 /* this is one of the entries to use: it is not deleted
3618 * and it matches the star pattern we're looking for.
3621 /* Eliminate entries that don't match requested
3624 /* no hidden files */
3625 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3628 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3630 /* We have already done the cm_TryBulkStat above */
3631 fid.cell = scp->fid.cell;
3632 fid.volume = scp->fid.volume;
3633 fid.vnode = ntohl(dep->fid.vnode);
3634 fid.unique = ntohl(dep->fid.unique);
3635 fileType = cm_FindFileType(&fid);
3636 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3637 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3639 if (fileType == CM_SCACHETYPE_DIRECTORY)
3644 memcpy(op, mask, 11); op += 11;
3645 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3646 *op++ = nextEntryCookie & 0xff;
3647 *op++ = (nextEntryCookie>>8) & 0xff;
3648 *op++ = (nextEntryCookie>>16) & 0xff;
3649 *op++ = (nextEntryCookie>>24) & 0xff;
3650 memcpy(op, &clientCookie, 4); op += 4;
3652 /* now we emit the attribute. This is sort of tricky,
3653 * since we need to really stat the file to find out
3654 * what type of entry we've got. Right now, we're
3655 * copying out data from a buffer, while holding the
3656 * scp locked, so it isn't really convenient to stat
3657 * something now. We'll put in a place holder now,
3658 * and make a second pass before returning this to get
3659 * the real attributes. So, we just skip the data for
3660 * now, and adjust it later. We allocate a patch
3661 * record to make it easy to find this point later.
3662 * The replay will happen at a time when it is safe to
3663 * unlock the directory.
3665 curPatchp = malloc(sizeof(*curPatchp));
3666 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3667 curPatchp->dptr = op;
3668 curPatchp->fid.cell = scp->fid.cell;
3669 curPatchp->fid.volume = scp->fid.volume;
3670 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3671 curPatchp->fid.unique = ntohl(dep->fid.unique);
3673 /* do hidden attribute here since name won't be around when applying
3677 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3678 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3680 curPatchp->flags = 0;
3682 op += 9; /* skip attr, time, date and size */
3684 /* zero out name area. The spec says to pad with
3685 * spaces, but Samba doesn't, and neither do we.
3689 /* finally, we get to copy out the name; we know that
3690 * it fits in 8.3 or the pattern wouldn't match, but it
3691 * never hurts to be sure.
3693 strncpy(op, actualName, 13);
3695 /* Uppercase if requested by client */
3696 if ((((smb_t *)inp)->flg2 & 1) == 0)
3701 /* now, adjust the # of entries copied */
3703 } /* if we're including this name */
3706 /* and adjust curOffset to be where the new cookie is */
3707 thyper.HighPart = 0;
3708 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3709 curOffset = LargeIntegerAdd(thyper, curOffset);
3710 } /* while copying data for dir listing */
3712 /* release the mutex */
3713 lock_ReleaseMutex(&scp->mx);
3714 if (bufferp) buf_Release(bufferp);
3716 /* apply and free last set of patches; if not doing a star match, this
3717 * will be empty, but better safe (and freeing everything) than sorry.
3719 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3721 /* special return code for unsuccessful search */
3722 if (code == 0 && dataLength < 21 && returnedNames == 0)
3723 code = CM_ERROR_NOFILES;
3725 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3726 returnedNames, code);
3729 smb_DeleteDirSearch(dsp);
3730 smb_ReleaseDirSearch(dsp);
3731 cm_ReleaseSCache(scp);
3732 cm_ReleaseUser(userp);
3736 /* finalize the output buffer */
3737 smb_SetSMBParm(outp, 0, returnedNames);
3738 temp = (long) (op - origOp);
3739 smb_SetSMBDataLength(outp, temp);
3741 /* the data area is a variable block, which has a 5 (already there)
3742 * followed by the length of the # of data bytes. We now know this to
3743 * be "temp," although that includes the 3 bytes of vbl block header.
3744 * Deduct for them and fill in the length field.
3746 temp -= 3; /* deduct vbl block info */
3747 osi_assert(temp == (43 * returnedNames));
3748 origOp[1] = temp & 0xff;
3749 origOp[2] = (temp>>8) & 0xff;
3750 if (returnedNames == 0)
3751 smb_DeleteDirSearch(dsp);
3752 smb_ReleaseDirSearch(dsp);
3753 cm_ReleaseSCache(scp);
3754 cm_ReleaseUser(userp);
3758 /* verify that this is a valid path to a directory. I don't know why they
3759 * don't use the get file attributes call.
3761 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3765 cm_scache_t *rootScp;
3766 cm_scache_t *newScp;
3775 pathp = smb_GetSMBData(inp, NULL);
3776 pathp = smb_ParseASCIIBlock(pathp, NULL);
3777 osi_Log1(smb_logp, "SMB receive check path %s",
3778 osi_LogSaveString(smb_logp, pathp));
3781 return CM_ERROR_BADFD;
3784 rootScp = cm_rootSCachep;
3786 userp = smb_GetUser(vcp, inp);
3788 caseFold = CM_FLAG_CASEFOLD;
3790 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3792 cm_ReleaseUser(userp);
3793 return CM_ERROR_NOSUCHPATH;
3795 code = cm_NameI(rootScp, pathp,
3796 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3797 userp, tidPathp, &req, &newScp);
3800 cm_ReleaseUser(userp);
3804 /* now lock the vnode with a callback; returns with newScp locked */
3805 lock_ObtainMutex(&newScp->mx);
3806 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3807 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3808 if (code && code != CM_ERROR_NOACCESS) {
3809 lock_ReleaseMutex(&newScp->mx);
3810 cm_ReleaseSCache(newScp);
3811 cm_ReleaseUser(userp);
3815 attrs = smb_Attributes(newScp);
3817 if (!(attrs & 0x10))
3818 code = CM_ERROR_NOTDIR;
3820 lock_ReleaseMutex(&newScp->mx);
3822 cm_ReleaseSCache(newScp);
3823 cm_ReleaseUser(userp);
3827 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3831 cm_scache_t *rootScp;
3832 unsigned short attribute;
3834 cm_scache_t *newScp;
3843 /* decode basic attributes we're passed */
3844 attribute = smb_GetSMBParm(inp, 0);
3845 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3847 pathp = smb_GetSMBData(inp, NULL);
3848 pathp = smb_ParseASCIIBlock(pathp, NULL);
3851 return CM_ERROR_BADSMB;
3854 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3855 dosTime, attribute);
3857 rootScp = cm_rootSCachep;
3859 userp = smb_GetUser(vcp, inp);
3861 caseFold = CM_FLAG_CASEFOLD;
3863 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3865 cm_ReleaseUser(userp);
3866 return CM_ERROR_NOSUCHFILE;
3868 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3869 tidPathp, &req, &newScp);
3872 cm_ReleaseUser(userp);
3876 /* now lock the vnode with a callback; returns with newScp locked; we
3877 * need the current status to determine what the new status is, in some
3880 lock_ObtainMutex(&newScp->mx);
3881 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3882 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3884 lock_ReleaseMutex(&newScp->mx);
3885 cm_ReleaseSCache(newScp);
3886 cm_ReleaseUser(userp);
3890 /* Check for RO volume */
3891 if (newScp->flags & CM_SCACHEFLAG_RO) {
3892 lock_ReleaseMutex(&newScp->mx);
3893 cm_ReleaseSCache(newScp);
3894 cm_ReleaseUser(userp);
3895 return CM_ERROR_READONLY;
3898 /* prepare for setattr call */
3901 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3902 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3904 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3905 /* we're told to make a writable file read-only */
3906 attr.unixModeBits = newScp->unixModeBits & ~0222;
3907 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3909 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3910 /* we're told to make a read-only file writable */
3911 attr.unixModeBits = newScp->unixModeBits | 0222;
3912 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3914 lock_ReleaseMutex(&newScp->mx);
3916 /* now call setattr */
3918 code = cm_SetAttr(newScp, &attr, userp, &req);
3922 cm_ReleaseSCache(newScp);
3923 cm_ReleaseUser(userp);
3928 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3932 cm_scache_t *rootScp;
3933 cm_scache_t *newScp, *dscp;
3945 pathp = smb_GetSMBData(inp, NULL);
3946 pathp = smb_ParseASCIIBlock(pathp, NULL);
3949 return CM_ERROR_BADSMB;
3952 if (*pathp == 0) /* null path */
3955 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3956 osi_LogSaveString(smb_logp, pathp));
3958 rootScp = cm_rootSCachep;
3960 userp = smb_GetUser(vcp, inp);
3962 /* we shouldn't need this for V3 requests, but we seem to */
3963 caseFold = CM_FLAG_CASEFOLD;
3965 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3967 cm_ReleaseUser(userp);
3968 return CM_ERROR_NOSUCHFILE;
3972 * XXX Strange hack XXX
3974 * As of Patch 5 (16 July 97), we are having the following problem:
3975 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3976 * requests to look up "desktop.ini" in all the subdirectories.
3977 * This can cause zillions of timeouts looking up non-existent cells
3978 * and volumes, especially in the top-level directory.
3980 * We have not found any way to avoid this or work around it except
3981 * to explicitly ignore the requests for mount points that haven't
3982 * yet been evaluated and for directories that haven't yet been
3985 * We should modify this hack to provide a fake desktop.ini file
3986 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3988 spacep = inp->spacep;
3989 smb_StripLastComponent(spacep->data, &lastComp, pathp);
3990 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3991 code = cm_NameI(rootScp, spacep->data,
3992 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3993 userp, tidPathp, &req, &dscp);
3995 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT &&
3996 !dscp->mountRootFidp)
3997 code = CM_ERROR_NOSUCHFILE;
3998 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3999 cm_buf_t *bp = buf_Find(dscp, &hzero);
4003 code = CM_ERROR_NOSUCHFILE;
4005 cm_ReleaseSCache(dscp);
4007 cm_ReleaseUser(userp);
4013 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4014 tidPathp, &req, &newScp);
4016 cm_ReleaseUser(userp);
4020 /* now lock the vnode with a callback; returns with newScp locked */
4021 lock_ObtainMutex(&newScp->mx);
4022 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4023 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4025 lock_ReleaseMutex(&newScp->mx);
4026 cm_ReleaseSCache(newScp);
4027 cm_ReleaseUser(userp);
4032 /* use smb_Attributes instead. Also the fact that a file is
4033 * in a readonly volume doesn't mean it shojuld be marked as RO
4035 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4036 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4037 attrs = SMB_ATTR_DIRECTORY;
4040 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4041 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4043 attrs = smb_Attributes(newScp);
4046 smb_SetSMBParm(outp, 0, attrs);
4048 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4049 smb_SetSMBParm(outp, 1, dosTime & 0xffff);
4050 smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
4051 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4052 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4053 smb_SetSMBParm(outp, 5, 0);
4054 smb_SetSMBParm(outp, 6, 0);
4055 smb_SetSMBParm(outp, 7, 0);
4056 smb_SetSMBParm(outp, 8, 0);
4057 smb_SetSMBParm(outp, 9, 0);
4058 smb_SetSMBDataLength(outp, 0);
4059 lock_ReleaseMutex(&newScp->mx);
4061 cm_ReleaseSCache(newScp);
4062 cm_ReleaseUser(userp);
4067 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4071 osi_Log0(smb_logp, "SMB receive tree disconnect");
4073 /* find the tree and free it */
4074 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4076 lock_ObtainMutex(&tidp->mx);
4077 tidp->flags |= SMB_TIDFLAG_DELETE;
4078 lock_ReleaseMutex(&tidp->mx);
4079 smb_ReleaseTID(tidp);
4085 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4103 pathp = smb_GetSMBData(inp, NULL);
4104 pathp = smb_ParseASCIIBlock(pathp, NULL);
4106 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4108 #ifdef DEBUG_VERBOSE
4112 hexpath = osi_HexifyString( pathp );
4113 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4118 share = smb_GetSMBParm(inp, 0);
4119 attribute = smb_GetSMBParm(inp, 1);
4121 spacep = inp->spacep;
4122 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4123 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4124 /* special case magic file name for receiving IOCTL requests
4125 * (since IOCTL calls themselves aren't getting through).
4127 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4128 smb_SetupIoctlFid(fidp, spacep);
4129 smb_SetSMBParm(outp, 0, fidp->fid);
4130 smb_SetSMBParm(outp, 1, 0); /* attrs */
4131 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4132 smb_SetSMBParm(outp, 3, 0);
4133 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4134 smb_SetSMBParm(outp, 5, 0x7fff);
4135 /* pass the open mode back */
4136 smb_SetSMBParm(outp, 6, (share & 0xf));
4137 smb_SetSMBDataLength(outp, 0);
4138 smb_ReleaseFID(fidp);
4142 userp = smb_GetUser(vcp, inp);
4144 caseFold = CM_FLAG_CASEFOLD;
4146 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4148 cm_ReleaseUser(userp);
4149 return CM_ERROR_NOSUCHPATH;
4151 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4152 tidPathp, &req, &scp);
4155 cm_ReleaseUser(userp);
4159 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4161 cm_ReleaseSCache(scp);
4162 cm_ReleaseUser(userp);
4166 /* don't need callback to check file type, since file types never
4167 * change, and namei and cm_Lookup all stat the object at least once on
4168 * a successful return.
4170 if (scp->fileType != CM_SCACHETYPE_FILE) {
4171 cm_ReleaseSCache(scp);
4172 cm_ReleaseUser(userp);
4173 return CM_ERROR_ISDIR;
4176 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4179 /* save a pointer to the vnode */
4182 if ((share & 0xf) == 0)
4183 fidp->flags |= SMB_FID_OPENREAD;
4184 else if ((share & 0xf) == 1)
4185 fidp->flags |= SMB_FID_OPENWRITE;
4187 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4189 lock_ObtainMutex(&scp->mx);
4190 smb_SetSMBParm(outp, 0, fidp->fid);
4191 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4192 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4193 smb_SetSMBParm(outp, 2, dosTime & 0xffff);
4194 smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
4195 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4196 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4197 /* pass the open mode back; XXXX add access checks */
4198 smb_SetSMBParm(outp, 6, (share & 0xf));
4199 smb_SetSMBDataLength(outp, 0);
4200 lock_ReleaseMutex(&scp->mx);
4203 cm_Open(scp, 0, userp);
4205 /* send and free packet */
4206 smb_ReleaseFID(fidp);
4207 cm_ReleaseUser(userp);
4208 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4212 typedef struct smb_unlinkRock {
4217 char *maskp; /* pointer to the star pattern */
4222 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4225 smb_unlinkRock_t *rockp;
4233 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4234 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4235 caseFold |= CM_FLAG_8DOT3;
4237 matchName = dep->name;
4238 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4240 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4241 !cm_Is8Dot3(dep->name)) {
4242 cm_Gen8Dot3Name(dep, shortName, NULL);
4243 matchName = shortName;
4244 /* 8.3 matches are always case insensitive */
4245 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4248 osi_Log1(smb_logp, "Unlinking %s",
4249 osi_LogSaveString(smb_logp, matchName));
4250 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4251 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4252 smb_NotifyChange(FILE_ACTION_REMOVED,
4253 FILE_NOTIFY_CHANGE_FILE_NAME,
4254 dscp, dep->name, NULL, TRUE);
4258 /* If we made a case sensitive exact match, we might as well quit now. */
4259 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4260 code = CM_ERROR_STOPNOW;
4268 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4277 smb_unlinkRock_t rock;
4286 attribute = smb_GetSMBParm(inp, 0);
4288 tp = smb_GetSMBData(inp, NULL);
4289 pathp = smb_ParseASCIIBlock(tp, &tp);
4291 osi_Log1(smb_logp, "SMB receive unlink %s",
4292 osi_LogSaveString(smb_logp, pathp));
4294 spacep = inp->spacep;
4295 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4297 userp = smb_GetUser(vcp, inp);
4299 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4301 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4303 cm_ReleaseUser(userp);
4304 return CM_ERROR_NOSUCHPATH;
4306 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4310 cm_ReleaseUser(userp);
4314 /* otherwise, scp points to the parent directory. */
4321 rock.maskp = smb_FindMask(pathp);
4322 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4325 thyper.HighPart = 0;
4331 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4332 * match. If that fails, we do a case insensitve match.
4334 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4335 !smb_IsStarMask(rock.maskp)) {
4336 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4339 thyper.HighPart = 0;
4340 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4345 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4347 if (code == CM_ERROR_STOPNOW)
4350 cm_ReleaseUser(userp);
4352 cm_ReleaseSCache(dscp);
4354 if (code == 0 && !rock.any)
4355 code = CM_ERROR_NOSUCHFILE;
4359 typedef struct smb_renameRock {
4360 cm_scache_t *odscp; /* old dir */
4361 cm_scache_t *ndscp; /* new dir */
4362 cm_user_t *userp; /* user */
4363 cm_req_t *reqp; /* request struct */
4364 smb_vc_t *vcp; /* virtual circuit */
4365 char *maskp; /* pointer to star pattern of old file name */
4366 int flags; /* tilde, casefold, etc */
4367 char *newNamep; /* ptr to the new file's name */
4370 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4373 smb_renameRock_t *rockp;
4378 rockp = (smb_renameRock_t *) vrockp;
4380 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4381 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4382 caseFold |= CM_FLAG_8DOT3;
4384 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4386 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4387 !cm_Is8Dot3(dep->name)) {
4388 cm_Gen8Dot3Name(dep, shortName, NULL);
4389 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4392 code = cm_Rename(rockp->odscp, dep->name,
4393 rockp->ndscp, rockp->newNamep, rockp->userp,
4395 /* if the call worked, stop doing the search now, since we
4396 * really only want to rename one file.
4399 code = CM_ERROR_STOPNOW;
4408 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4411 cm_space_t *spacep = NULL;
4412 smb_renameRock_t rock;
4413 cm_scache_t *oldDscp = NULL;
4414 cm_scache_t *newDscp = NULL;
4415 cm_scache_t *tmpscp= NULL;
4416 cm_scache_t *tmpscp2 = NULL;
4426 userp = smb_GetUser(vcp, inp);
4427 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4429 cm_ReleaseUser(userp);
4430 return CM_ERROR_NOSUCHPATH;
4434 spacep = inp->spacep;
4435 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4438 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4439 * what actually exists is foo/baz. I don't know why the code used to be
4440 * the way it was. 1/29/96
4442 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4444 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4446 * caseFold = CM_FLAG_CASEFOLD;
4448 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4449 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4450 userp, tidPathp, &req, &oldDscp);
4453 cm_ReleaseUser(userp);
4457 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4458 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4459 userp, tidPathp, &req, &newDscp);
4462 cm_ReleaseSCache(oldDscp);
4463 cm_ReleaseUser(userp);
4467 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4468 * next, get the component names, and lower case them.
4471 /* handle the old name first */
4473 oldLastNamep = oldPathp;
4477 /* and handle the new name, too */
4479 newLastNamep = newPathp;
4483 /* TODO: The old name could be a wildcard. The new name must not be */
4485 /* do the vnode call */
4486 rock.odscp = oldDscp;
4487 rock.ndscp = newDscp;
4491 rock.maskp = oldLastNamep;
4492 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4493 rock.newNamep = newLastNamep;
4495 /* Check if the file already exists; if so return error */
4496 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4497 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4498 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4499 osi_LogSaveString(afsd_logp, newLastNamep));
4501 /* Check if the old and the new names differ only in case. If so return
4502 * success, else return CM_ERROR_EXISTS
4504 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4506 /* This would be a success only if the old file is *as same as* the new file */
4507 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4509 if (tmpscp == tmpscp2)
4512 code = CM_ERROR_EXISTS;
4513 cm_ReleaseSCache(tmpscp2);
4516 code = CM_ERROR_NOSUCHFILE;
4519 /* file exist, do not rename, also fixes move */
4520 osi_Log0(smb_logp, "Can't rename. Target already exists");
4521 code = CM_ERROR_EXISTS;
4525 cm_ReleaseSCache(tmpscp);
4526 cm_ReleaseSCache(newDscp);
4527 cm_ReleaseSCache(oldDscp);
4528 cm_ReleaseUser(userp);
4532 /* Now search the directory for the pattern, and do the appropriate rename when found */
4533 thyper.LowPart = 0; /* search dir from here */
4534 thyper.HighPart = 0;
4536 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4538 if (code == CM_ERROR_STOPNOW)
4541 code = CM_ERROR_NOSUCHFILE;
4543 /* Handle Change Notification */
4545 * Being lazy, not distinguishing between files and dirs in this
4546 * filter, since we'd have to do a lookup.
4548 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4549 if (oldDscp == newDscp) {
4550 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4551 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4552 filter, oldDscp, oldLastNamep,
4553 newLastNamep, TRUE);
4555 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4556 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4557 filter, oldDscp, oldLastNamep,
4559 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4560 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4561 filter, newDscp, newLastNamep,
4566 cm_ReleaseSCache(tmpscp);
4567 cm_ReleaseUser(userp);
4568 cm_ReleaseSCache(oldDscp);
4569 cm_ReleaseSCache(newDscp);
4574 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4577 cm_space_t *spacep = NULL;
4578 cm_scache_t *oldDscp = NULL;
4579 cm_scache_t *newDscp = NULL;
4580 cm_scache_t *tmpscp= NULL;
4581 cm_scache_t *tmpscp2 = NULL;
4582 cm_scache_t *sscp = NULL;
4591 userp = smb_GetUser(vcp, inp);
4593 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4595 cm_ReleaseUser(userp);
4596 return CM_ERROR_NOSUCHPATH;
4601 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4603 spacep = inp->spacep;
4604 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4606 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4607 userp, tidPathp, &req, &oldDscp);
4609 cm_ReleaseUser(userp);
4613 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4614 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4615 userp, tidPathp, &req, &newDscp);
4617 cm_ReleaseSCache(oldDscp);
4618 cm_ReleaseUser(userp);
4622 /* Now, although we did two lookups for the two directories (because the same
4623 * directory can be referenced through different paths), we only allow hard links
4624 * within the same directory. */
4625 if (oldDscp != newDscp) {
4626 cm_ReleaseSCache(oldDscp);
4627 cm_ReleaseSCache(newDscp);
4628 cm_ReleaseUser(userp);
4629 return CM_ERROR_CROSSDEVLINK;
4632 /* handle the old name first */
4634 oldLastNamep = oldPathp;
4638 /* and handle the new name, too */
4640 newLastNamep = newPathp;
4644 /* now lookup the old name */
4645 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4646 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4648 cm_ReleaseSCache(oldDscp);
4649 cm_ReleaseSCache(newDscp);
4650 cm_ReleaseUser(userp);
4654 /* Check if the file already exists; if so return error */
4655 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4656 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4657 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4658 osi_LogSaveString(afsd_logp, newLastNamep));
4660 /* if the existing link is to the same file, then we return success */
4662 if(sscp == tmpscp) {
4665 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
4666 code = CM_ERROR_EXISTS;
4671 cm_ReleaseSCache(tmpscp);
4672 cm_ReleaseSCache(sscp);
4673 cm_ReleaseSCache(newDscp);
4674 cm_ReleaseSCache(oldDscp);
4675 cm_ReleaseUser(userp);
4679 /* now create the hardlink */
4680 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
4681 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
4682 osi_Log1(smb_logp," Link returns %d", code);
4684 /* Handle Change Notification */
4686 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
4687 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4688 smb_NotifyChange(FILE_ACTION_ADDED,
4689 filter, newDscp, newLastNamep,
4694 cm_ReleaseSCache(tmpscp);
4695 cm_ReleaseUser(userp);
4696 cm_ReleaseSCache(sscp);
4697 cm_ReleaseSCache(oldDscp);
4698 cm_ReleaseSCache(newDscp);
4703 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4709 tp = smb_GetSMBData(inp, NULL);
4710 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4711 newPathp = smb_ParseASCIIBlock(tp, &tp);
4713 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4714 osi_LogSaveString(smb_logp, oldPathp),
4715 osi_LogSaveString(smb_logp, newPathp));
4717 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
4722 typedef struct smb_rmdirRock {
4726 char *maskp; /* pointer to the star pattern */
4731 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4734 smb_rmdirRock_t *rockp;
4739 rockp = (smb_rmdirRock_t *) vrockp;
4741 matchName = dep->name;
4742 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4743 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4745 match = (strcmp(matchName, rockp->maskp) == 0);
4747 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4748 !cm_Is8Dot3(dep->name)) {
4749 cm_Gen8Dot3Name(dep, shortName, NULL);
4750 matchName = shortName;
4751 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4754 osi_Log1(smb_logp, "Removing directory %s",
4755 osi_LogSaveString(smb_logp, matchName));
4756 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4757 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4758 smb_NotifyChange(FILE_ACTION_REMOVED,
4759 FILE_NOTIFY_CHANGE_DIR_NAME,
4760 dscp, dep->name, NULL, TRUE);
4769 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4777 smb_rmdirRock_t rock;
4786 tp = smb_GetSMBData(inp, NULL);
4787 pathp = smb_ParseASCIIBlock(tp, &tp);
4789 spacep = inp->spacep;
4790 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4792 userp = smb_GetUser(vcp, inp);
4794 caseFold = CM_FLAG_CASEFOLD;
4796 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4798 cm_ReleaseUser(userp);
4799 return CM_ERROR_NOSUCHPATH;
4801 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4802 userp, tidPathp, &req, &dscp);
4805 cm_ReleaseUser(userp);
4809 /* otherwise, scp points to the parent directory. */
4816 rock.maskp = lastNamep;
4817 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4820 thyper.HighPart = 0;
4824 /* First do a case sensitive match, and if that fails, do a case insensitive match */
4825 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4826 if (code == 0 && !rock.any) {
4828 thyper.HighPart = 0;
4829 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4830 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4833 cm_ReleaseUser(userp);
4835 cm_ReleaseSCache(dscp);
4837 if (code == 0 && !rock.any)
4838 code = CM_ERROR_NOSUCHFILE;
4842 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4852 fid = smb_GetSMBParm(inp, 0);
4854 osi_Log1(smb_logp, "SMB flush fid %d", fid);
4856 fid = smb_ChainFID(fid, inp);
4857 fidp = smb_FindFID(vcp, fid, 0);
4858 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4860 smb_ReleaseFID(fidp);
4861 return CM_ERROR_BADFD;
4864 userp = smb_GetUser(vcp, inp);
4866 lock_ObtainMutex(&fidp->mx);
4867 if (fidp->flags & SMB_FID_OPENWRITE)
4868 code = cm_FSync(fidp->scp, userp, &req);
4871 lock_ReleaseMutex(&fidp->mx);
4873 smb_ReleaseFID(fidp);
4875 cm_ReleaseUser(userp);
4880 struct smb_FullNameRock {
4886 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4890 struct smb_FullNameRock *vrockp;
4892 vrockp = (struct smb_FullNameRock *)rockp;
4894 if (!cm_Is8Dot3(dep->name)) {
4895 cm_Gen8Dot3Name(dep, shortName, NULL);
4897 if (cm_stricmp(shortName, vrockp->name) == 0) {
4898 vrockp->fullName = strdup(dep->name);
4899 return CM_ERROR_STOPNOW;
4902 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
4903 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
4904 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4905 vrockp->fullName = strdup(dep->name);
4906 return CM_ERROR_STOPNOW;
4911 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4912 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4914 struct smb_FullNameRock rock;
4920 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL,
4922 if (code == CM_ERROR_STOPNOW)
4923 *newPathp = rock.fullName;
4925 *newPathp = strdup(pathp);
4928 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4939 fid = smb_GetSMBParm(inp, 0);
4940 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4942 osi_Log1(smb_logp, "SMB close fid %d", fid);
4944 fid = smb_ChainFID(fid, inp);
4945 fidp = smb_FindFID(vcp, fid, 0);
4947 return CM_ERROR_BADFD;
4950 userp = smb_GetUser(vcp, inp);
4952 lock_ObtainMutex(&fidp->mx);
4954 /* Don't jump the gun on an async raw write */
4955 while (fidp->raw_writers) {
4956 lock_ReleaseMutex(&fidp->mx);
4957 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4958 lock_ObtainMutex(&fidp->mx);
4961 fidp->flags |= SMB_FID_DELETE;
4963 /* watch for ioctl closes, and read-only opens */
4964 if (fidp->scp != NULL &&
4965 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4966 == SMB_FID_OPENWRITE) {
4967 if (dosTime != 0 && dosTime != -1) {
4968 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4969 /* This fixes defect 10958 */
4970 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
4971 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
4973 code = cm_FSync(fidp->scp, userp, &req);
4978 if (fidp->flags & SMB_FID_DELONCLOSE) {
4979 cm_scache_t *dscp = fidp->NTopen_dscp;
4980 char *pathp = fidp->NTopen_pathp;
4983 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
4984 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
4985 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
4986 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4987 smb_NotifyChange(FILE_ACTION_REMOVED,
4988 FILE_NOTIFY_CHANGE_DIR_NAME,
4989 dscp, fullPathp, NULL, TRUE);
4993 code = cm_Unlink(dscp, fullPathp, userp, &req);
4994 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4995 smb_NotifyChange(FILE_ACTION_REMOVED,
4996 FILE_NOTIFY_CHANGE_FILE_NAME,
4997 dscp, fullPathp, NULL, TRUE);
5001 lock_ReleaseMutex(&fidp->mx);
5003 if (fidp->flags & SMB_FID_NTOPEN) {
5004 cm_ReleaseSCache(fidp->NTopen_dscp);
5005 free(fidp->NTopen_pathp);
5007 if (fidp->NTopen_wholepathp)
5008 free(fidp->NTopen_wholepathp);
5010 smb_ReleaseFID(fidp);
5011 cm_ReleaseUser(userp);
5016 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5019 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5020 cm_user_t *userp, long *readp)
5022 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5023 cm_user_t *userp, long *readp, int dosflag)
5030 osi_hyper_t fileLength;
5032 osi_hyper_t lastByte;
5033 osi_hyper_t bufferOffset;
5034 long bufIndex, nbytes;
5044 lock_ObtainMutex(&fidp->mx);
5046 lock_ObtainMutex(&scp->mx);
5048 if (offset.HighPart == 0) {
5049 chunk = offset.LowPart >> cm_logChunkSize;
5050 if (chunk != fidp->curr_chunk) {
5051 fidp->prev_chunk = fidp->curr_chunk;
5052 fidp->curr_chunk = chunk;
5054 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5058 /* start by looking up the file's end */
5059 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5060 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5061 if (code) goto done;
5063 /* now we have the entry locked, look up the length */
5064 fileLength = scp->length;
5066 /* adjust count down so that it won't go past EOF */
5067 thyper.LowPart = count;
5068 thyper.HighPart = 0;
5069 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5071 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5072 /* we'd read past EOF, so just stop at fileLength bytes.
5073 * Start by computing how many bytes remain in the file.
5075 thyper = LargeIntegerSubtract(fileLength, offset);
5077 /* if we are past EOF, read 0 bytes */
5078 if (LargeIntegerLessThanZero(thyper))
5081 count = thyper.LowPart;
5086 /* now, copy the data one buffer at a time,
5087 * until we've filled the request packet
5090 /* if we've copied all the data requested, we're done */
5091 if (count <= 0) break;
5093 /* otherwise, load up a buffer of data */
5094 thyper.HighPart = offset.HighPart;
5095 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5096 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5099 buf_Release(bufferp);
5102 lock_ReleaseMutex(&scp->mx);
5104 lock_ObtainRead(&scp->bufCreateLock);
5105 code = buf_Get(scp, &thyper, &bufferp);
5106 lock_ReleaseRead(&scp->bufCreateLock);
5108 lock_ObtainMutex(&scp->mx);
5109 if (code) goto done;
5110 bufferOffset = thyper;
5112 /* now get the data in the cache */
5114 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5115 CM_SCACHESYNC_NEEDCALLBACK |
5116 CM_SCACHESYNC_READ);
5117 if (code) goto done;
5119 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5121 /* otherwise, load the buffer and try again */
5122 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5126 buf_Release(bufferp);
5130 } /* if (wrong buffer) ... */
5132 /* now we have the right buffer loaded. Copy out the
5133 * data from here to the user's buffer.
5135 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5137 /* and figure out how many bytes we want from this buffer */
5138 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5139 if (nbytes > count) nbytes = count; /* don't go past EOF */
5141 /* now copy the data */
5144 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5147 memcpy(op, bufferp->datap + bufIndex, nbytes);
5149 /* adjust counters, pointers, etc. */
5152 thyper.LowPart = nbytes;
5153 thyper.HighPart = 0;
5154 offset = LargeIntegerAdd(thyper, offset);
5158 lock_ReleaseMutex(&scp->mx);
5159 lock_ReleaseMutex(&fidp->mx);
5161 buf_Release(bufferp);
5163 if (code == 0 && sequential)
5164 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5170 * smb_WriteData -- common code for Write and Raw Write
5173 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5174 cm_user_t *userp, long *writtenp)
5176 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5177 cm_user_t *userp, long *writtenp, int dosflag)
5184 osi_hyper_t fileLength; /* file's length at start of write */
5185 osi_hyper_t minLength; /* don't read past this */
5186 long nbytes; /* # of bytes to transfer this iteration */
5188 osi_hyper_t thyper; /* hyper tmp variable */
5189 osi_hyper_t bufferOffset;
5190 long bufIndex; /* index in buffer where our data is */
5192 osi_hyper_t writeBackOffset;/* offset of region to write back when
5197 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5198 fidp->fid, offsetp->LowPart, count);
5208 lock_ObtainMutex(&fidp->mx);
5210 lock_ObtainMutex(&scp->mx);
5212 /* start by looking up the file's end */
5213 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5215 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5216 CM_SCACHESYNC_NEEDCALLBACK
5217 | CM_SCACHESYNC_SETSTATUS
5218 | CM_SCACHESYNC_GETSTATUS);
5219 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5224 /* make sure we have a writable FD */
5225 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5226 code = CM_ERROR_BADFDOP;
5230 /* now we have the entry locked, look up the length */
5231 fileLength = scp->length;
5232 minLength = fileLength;
5233 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5234 minLength = scp->serverLength;
5236 /* adjust file length if we extend past EOF */
5237 thyper.LowPart = count;
5238 thyper.HighPart = 0;
5239 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5240 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5241 /* we'd write past EOF, so extend the file */
5242 scp->mask |= CM_SCACHEMASK_LENGTH;
5243 scp->length = thyper;
5244 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5246 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5248 /* now, if the new position (thyper) and the old (offset) are in
5249 * different storeback windows, remember to store back the previous
5250 * storeback window when we're done with the write.
5252 if ((thyper.LowPart & (-cm_chunkSize)) !=
5253 (offset.LowPart & (-cm_chunkSize))) {
5254 /* they're different */
5256 writeBackOffset.HighPart = offset.HighPart;
5257 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5262 /* now, copy the data one buffer at a time, until we've filled the
5265 /* if we've copied all the data requested, we're done */
5269 /* handle over quota or out of space */
5270 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5271 *writtenp = written;
5272 code = CM_ERROR_QUOTA;
5276 /* otherwise, load up a buffer of data */
5277 thyper.HighPart = offset.HighPart;
5278 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5279 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5282 lock_ReleaseMutex(&bufferp->mx);
5283 buf_Release(bufferp);
5286 lock_ReleaseMutex(&scp->mx);
5288 lock_ObtainRead(&scp->bufCreateLock);
5289 code = buf_Get(scp, &thyper, &bufferp);
5290 lock_ReleaseRead(&scp->bufCreateLock);
5292 lock_ObtainMutex(&bufferp->mx);
5293 lock_ObtainMutex(&scp->mx);
5294 if (code) goto done;
5296 bufferOffset = thyper;
5298 /* now get the data in the cache */
5300 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5302 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5303 CM_SCACHESYNC_NEEDCALLBACK
5304 | CM_SCACHESYNC_WRITE
5305 | CM_SCACHESYNC_BUFLOCKED);
5306 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5311 /* If we're overwriting the entire buffer, or
5312 * if we're writing at or past EOF, mark the
5313 * buffer as current so we don't call
5314 * cm_GetBuffer. This skips the fetch from the
5315 * server in those cases where we're going to
5316 * obliterate all the data in the buffer anyway,
5317 * or in those cases where there is no useful
5318 * data at the server to start with.
5320 * Use minLength instead of scp->length, since
5321 * the latter has already been updated by this
5324 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5325 || LargeIntegerEqualTo(offset, bufferp->offset)
5326 && (count >= buf_bufferSize
5327 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5328 ConvertLongToLargeInteger(count)),
5330 if (count < buf_bufferSize
5331 && bufferp->dataVersion == -1)
5332 memset(bufferp->datap, 0,
5334 bufferp->dataVersion = scp->dataVersion;
5337 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5339 /* otherwise, load the buffer and try again */
5340 lock_ReleaseMutex(&bufferp->mx);
5341 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5343 lock_ReleaseMutex(&scp->mx);
5344 lock_ObtainMutex(&bufferp->mx);
5345 lock_ObtainMutex(&scp->mx);
5349 lock_ReleaseMutex(&bufferp->mx);
5350 buf_Release(bufferp);
5354 } /* if (wrong buffer) ... */
5356 /* now we have the right buffer loaded. Copy out the
5357 * data from here to the user's buffer.
5359 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5361 /* and figure out how many bytes we want from this buffer */
5362 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5364 nbytes = count; /* don't go past end of request */
5366 /* now copy the data */
5369 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5372 memcpy(bufferp->datap + bufIndex, op, nbytes);
5373 buf_SetDirty(bufferp);
5375 /* and record the last writer */
5376 if (bufferp->userp != userp) {
5379 cm_ReleaseUser(bufferp->userp);
5380 bufferp->userp = userp;
5383 /* adjust counters, pointers, etc. */
5387 thyper.LowPart = nbytes;
5388 thyper.HighPart = 0;
5389 offset = LargeIntegerAdd(thyper, offset);
5393 lock_ReleaseMutex(&scp->mx);
5394 lock_ReleaseMutex(&fidp->mx);
5396 lock_ReleaseMutex(&bufferp->mx);
5397 buf_Release(bufferp);
5400 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5401 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5402 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5403 fidp->NTopen_dscp, fidp->NTopen_pathp,
5407 if (code == 0 && doWriteBack) {
5409 lock_ObtainMutex(&scp->mx);
5410 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5412 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5413 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5415 lock_ReleaseMutex(&scp->mx);
5416 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5417 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5420 osi_Log2(smb_logp, "smb_WriteData fid %d returns %d written %d",
5421 fidp->fid, code, *writtenp);
5425 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5428 long count, written = 0, total_written = 0;
5433 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5435 int inDataBlockCount;
5437 fd = smb_GetSMBParm(inp, 0);
5438 count = smb_GetSMBParm(inp, 1);
5439 offset.HighPart = 0; /* too bad */
5440 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5442 op = smb_GetSMBData(inp, NULL);
5443 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5445 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5446 fd, offset.LowPart, count);
5448 fd = smb_ChainFID(fd, inp);
5449 fidp = smb_FindFID(vcp, fd, 0);
5451 return CM_ERROR_BADFD;
5454 if (fidp->flags & SMB_FID_IOCTL)
5455 return smb_IoctlWrite(fidp, vcp, inp, outp);
5457 userp = smb_GetUser(vcp, inp);
5459 /* special case: 0 bytes transferred means truncate to this position */
5465 truncAttr.mask = CM_ATTRMASK_LENGTH;
5466 truncAttr.length.LowPart = offset.LowPart;
5467 truncAttr.length.HighPart = 0;
5468 lock_ObtainMutex(&fidp->mx);
5469 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5470 lock_ReleaseMutex(&fidp->mx);
5471 smb_SetSMBParm(outp, 0, /* count */ 0);
5472 smb_SetSMBDataLength(outp, 0);
5473 fidp->flags |= SMB_FID_LENGTHSETDONE;
5478 * Work around bug in NT client
5480 * When copying a file, the NT client should first copy the data,
5481 * then copy the last write time. But sometimes the NT client does
5482 * these in the wrong order, so the data copies would inadvertently
5483 * cause the last write time to be overwritten. We try to detect this,
5484 * and don't set client mod time if we think that would go against the
5487 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5488 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5489 fidp->scp->clientModTime = time(NULL);
5493 while ( code == 0 && count > 0 ) {
5495 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5497 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5499 if (code == 0 && written == 0)
5500 code = CM_ERROR_PARTIALWRITE;
5502 offset.LowPart += written;
5504 total_written += written;
5508 /* set the packet data length to 3 bytes for the data block header,
5509 * plus the size of the data.
5511 smb_SetSMBParm(outp, 0, total_written);
5512 smb_SetSMBDataLength(outp, 0);
5515 smb_ReleaseFID(fidp);
5516 cm_ReleaseUser(userp);
5521 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5522 NCB *ncbp, raw_write_cont_t *rwcp)
5535 fd = smb_GetSMBParm(inp, 0);
5536 fidp = smb_FindFID(vcp, fd, 0);
5538 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5539 rwcp->offset.LowPart, rwcp->count);
5541 userp = smb_GetUser(vcp, inp);
5545 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5548 rawBuf = (dos_ptr) rwcp->buf;
5549 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5550 (unsigned char *) rawBuf, userp,
5554 if (rwcp->writeMode & 0x1) { /* synchronous */
5557 smb_FormatResponsePacket(vcp, inp, outp);
5558 op = (smb_t *) outp;
5559 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5560 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5561 smb_SetSMBDataLength(outp, 0);
5562 smb_SendPacket(vcp, outp);
5563 smb_FreePacket(outp);
5565 else { /* asynchronous */
5566 lock_ObtainMutex(&fidp->mx);
5567 fidp->raw_writers--;
5568 if (fidp->raw_writers == 0)
5569 thrd_SetEvent(fidp->raw_write_event);
5570 lock_ReleaseMutex(&fidp->mx);
5573 /* Give back raw buffer */
5574 lock_ObtainMutex(&smb_RawBufLock);
5576 *((char **)rawBuf) = smb_RawBufs;
5578 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5580 smb_RawBufs = rawBuf;
5581 lock_ReleaseMutex(&smb_RawBufLock);
5583 smb_ReleaseFID(fidp);
5584 cm_ReleaseUser(userp);
5587 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5592 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5595 long count, written = 0, total_written = 0;
5602 unsigned short writeMode;
5609 fd = smb_GetSMBParm(inp, 0);
5610 totalCount = smb_GetSMBParm(inp, 1);
5611 count = smb_GetSMBParm(inp, 10);
5612 offset.HighPart = 0; /* too bad */
5613 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5614 writeMode = smb_GetSMBParm(inp, 7);
5616 op = (char *) inp->data;
5617 op += smb_GetSMBParm(inp, 11);
5620 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5621 fd, offset.LowPart, count, writeMode);
5623 fd = smb_ChainFID(fd, inp);
5624 fidp = smb_FindFID(vcp, fd, 0);
5626 return CM_ERROR_BADFD;
5629 userp = smb_GetUser(vcp, inp);
5632 * Work around bug in NT client
5634 * When copying a file, the NT client should first copy the data,
5635 * then copy the last write time. But sometimes the NT client does
5636 * these in the wrong order, so the data copies would inadvertently
5637 * cause the last write time to be overwritten. We try to detect this,
5638 * and don't set client mod time if we think that would go against the
5641 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5642 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5643 fidp->scp->clientModTime = time(NULL);
5647 while ( code == 0 && count > 0 ) {
5649 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5651 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5653 if (code == 0 && written == 0)
5654 code = CM_ERROR_PARTIALWRITE;
5656 offset.LowPart += written;
5658 total_written += written;
5662 /* Get a raw buffer */
5665 lock_ObtainMutex(&smb_RawBufLock);
5667 /* Get a raw buf, from head of list */
5668 rawBuf = smb_RawBufs;
5670 smb_RawBufs = *(char **)smb_RawBufs;
5672 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5676 code = CM_ERROR_USESTD;
5678 lock_ReleaseMutex(&smb_RawBufLock);
5681 /* Don't allow a premature Close */
5682 if (code == 0 && (writeMode & 1) == 0) {
5683 lock_ObtainMutex(&fidp->mx);
5684 fidp->raw_writers++;
5685 thrd_ResetEvent(fidp->raw_write_event);
5686 lock_ReleaseMutex(&fidp->mx);
5689 smb_ReleaseFID(fidp);
5690 cm_ReleaseUser(userp);
5693 smb_SetSMBParm(outp, 0, total_written);
5694 smb_SetSMBDataLength(outp, 0);
5695 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5702 rwcp->offset.HighPart = 0;
5703 rwcp->offset.LowPart = offset.LowPart + count;
5704 rwcp->count = totalCount - count;
5705 rwcp->writeMode = writeMode;
5706 rwcp->alreadyWritten = total_written;
5708 /* set the packet data length to 3 bytes for the data block header,
5709 * plus the size of the data.
5711 smb_SetSMBParm(outp, 0, 0xffff);
5712 smb_SetSMBDataLength(outp, 0);
5717 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5720 long count, finalCount;
5727 fd = smb_GetSMBParm(inp, 0);
5728 count = smb_GetSMBParm(inp, 1);
5729 offset.HighPart = 0; /* too bad */
5730 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5732 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5733 fd, offset.LowPart, count);
5735 fd = smb_ChainFID(fd, inp);
5736 fidp = smb_FindFID(vcp, fd, 0);
5738 return CM_ERROR_BADFD;
5741 if (fidp->flags & SMB_FID_IOCTL) {
5742 return smb_IoctlRead(fidp, vcp, inp, outp);
5745 userp = smb_GetUser(vcp, inp);
5747 /* remember this for final results */
5748 smb_SetSMBParm(outp, 0, count);
5749 smb_SetSMBParm(outp, 1, 0);
5750 smb_SetSMBParm(outp, 2, 0);
5751 smb_SetSMBParm(outp, 3, 0);
5752 smb_SetSMBParm(outp, 4, 0);
5754 /* set the packet data length to 3 bytes for the data block header,
5755 * plus the size of the data.
5757 smb_SetSMBDataLength(outp, count+3);
5759 /* get op ptr after putting in the parms, since otherwise we don't
5760 * know where the data really is.
5762 op = smb_GetSMBData(outp, NULL);
5764 /* now emit the data block header: 1 byte of type and 2 bytes of length */
5765 *op++ = 1; /* data block marker */
5766 *op++ = (unsigned char) (count & 0xff);
5767 *op++ = (unsigned char) ((count >> 8) & 0xff);
5770 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5772 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5775 /* fix some things up */
5776 smb_SetSMBParm(outp, 0, finalCount);
5777 smb_SetSMBDataLength(outp, finalCount+3);
5779 smb_ReleaseFID(fidp);
5781 cm_ReleaseUser(userp);
5785 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5792 cm_scache_t *dscp; /* dir we're dealing with */
5793 cm_scache_t *scp; /* file we're creating */
5795 int initialModeBits;
5805 /* compute initial mode bits based on read-only flag in attributes */
5806 initialModeBits = 0777;
5808 tp = smb_GetSMBData(inp, NULL);
5809 pathp = smb_ParseASCIIBlock(tp, &tp);
5811 if (strcmp(pathp, "\\") == 0)
5812 return CM_ERROR_EXISTS;
5814 spacep = inp->spacep;
5815 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5817 userp = smb_GetUser(vcp, inp);
5819 caseFold = CM_FLAG_CASEFOLD;
5821 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5823 cm_ReleaseUser(userp);
5824 return CM_ERROR_NOSUCHPATH;
5827 code = cm_NameI(cm_rootSCachep, spacep->data,
5828 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5829 userp, tidPathp, &req, &dscp);
5832 cm_ReleaseUser(userp);
5836 /* otherwise, scp points to the parent directory. Do a lookup, and
5837 * fail if we find it. Otherwise, we do the create.
5843 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5844 if (scp) cm_ReleaseSCache(scp);
5845 if (code != CM_ERROR_NOSUCHFILE) {
5846 if (code == 0) code = CM_ERROR_EXISTS;
5847 cm_ReleaseSCache(dscp);
5848 cm_ReleaseUser(userp);
5852 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5853 setAttr.clientModTime = time(NULL);
5854 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5855 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5856 smb_NotifyChange(FILE_ACTION_ADDED,
5857 FILE_NOTIFY_CHANGE_DIR_NAME,
5858 dscp, lastNamep, NULL, TRUE);
5860 /* we don't need this any longer */
5861 cm_ReleaseSCache(dscp);
5864 /* something went wrong creating or truncating the file */
5865 cm_ReleaseUser(userp);
5869 /* otherwise we succeeded */
5870 smb_SetSMBDataLength(outp, 0);
5871 cm_ReleaseUser(userp);
5876 BOOL smb_IsLegalFilename(char *filename)
5879 * Find the longest substring of filename that does not contain
5880 * any of the chars in illegalChars. If that substring is less
5881 * than the length of the whole string, then one or more of the
5882 * illegal chars is in filename.
5884 if (strcspn(filename, illegalChars) < strlen(filename))
5890 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5898 cm_scache_t *dscp; /* dir we're dealing with */
5899 cm_scache_t *scp; /* file we're creating */
5901 int initialModeBits;
5913 excl = (inp->inCom == 0x03)? 0 : 1;
5915 attributes = smb_GetSMBParm(inp, 0);
5916 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5918 /* compute initial mode bits based on read-only flag in attributes */
5919 initialModeBits = 0666;
5920 if (attributes & 1) initialModeBits &= ~0222;
5922 tp = smb_GetSMBData(inp, NULL);
5923 pathp = smb_ParseASCIIBlock(tp, &tp);
5925 spacep = inp->spacep;
5926 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5928 userp = smb_GetUser(vcp, inp);
5930 caseFold = CM_FLAG_CASEFOLD;
5932 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5934 cm_ReleaseUser(userp);
5935 return CM_ERROR_NOSUCHPATH;
5937 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5938 userp, tidPathp, &req, &dscp);
5941 cm_ReleaseUser(userp);
5945 /* otherwise, scp points to the parent directory. Do a lookup, and
5946 * truncate the file if we find it, otherwise we create the file.
5948 if (!lastNamep) lastNamep = pathp;
5951 if (!smb_IsLegalFilename(lastNamep))
5952 return CM_ERROR_BADNTFILENAME;
5954 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
5955 #ifdef DEBUG_VERBOSE
5958 hexp = osi_HexifyString( lastNamep );
5959 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5964 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5965 if (code && code != CM_ERROR_NOSUCHFILE) {
5966 cm_ReleaseSCache(dscp);
5967 cm_ReleaseUser(userp);
5971 /* if we get here, if code is 0, the file exists and is represented by
5972 * scp. Otherwise, we have to create it.
5976 /* oops, file shouldn't be there */
5977 cm_ReleaseSCache(dscp);
5978 cm_ReleaseSCache(scp);
5979 cm_ReleaseUser(userp);
5980 return CM_ERROR_EXISTS;
5983 setAttr.mask = CM_ATTRMASK_LENGTH;
5984 setAttr.length.LowPart = 0;
5985 setAttr.length.HighPart = 0;
5986 code = cm_SetAttr(scp, &setAttr, userp, &req);
5989 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5990 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5991 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5993 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5994 smb_NotifyChange(FILE_ACTION_ADDED,
5995 FILE_NOTIFY_CHANGE_FILE_NAME,
5996 dscp, lastNamep, NULL, TRUE);
5997 if (!excl && code == CM_ERROR_EXISTS) {
5998 /* not an exclusive create, and someone else tried
5999 * creating it already, then we open it anyway. We
6000 * don't bother retrying after this, since if this next
6001 * fails, that means that the file was deleted after
6002 * we started this call.
6004 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6007 setAttr.mask = CM_ATTRMASK_LENGTH;
6008 setAttr.length.LowPart = 0;
6009 setAttr.length.HighPart = 0;
6010 code = cm_SetAttr(scp, &setAttr, userp, &req);
6015 /* we don't need this any longer */
6016 cm_ReleaseSCache(dscp);
6019 /* something went wrong creating or truncating the file */
6020 if (scp) cm_ReleaseSCache(scp);
6021 cm_ReleaseUser(userp);
6025 /* make sure we only open files */
6026 if (scp->fileType != CM_SCACHETYPE_FILE) {
6027 cm_ReleaseSCache(scp);
6028 cm_ReleaseUser(userp);
6029 return CM_ERROR_ISDIR;
6032 /* now all we have to do is open the file itself */
6033 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6036 /* save a pointer to the vnode */
6039 /* always create it open for read/write */
6040 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6042 smb_ReleaseFID(fidp);
6044 smb_SetSMBParm(outp, 0, fidp->fid);
6045 smb_SetSMBDataLength(outp, 0);
6047 cm_Open(scp, 0, userp);
6049 cm_ReleaseUser(userp);
6050 /* leave scp held since we put it in fidp->scp */
6054 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6067 fd = smb_GetSMBParm(inp, 0);
6068 whence = smb_GetSMBParm(inp, 1);
6069 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6071 /* try to find the file descriptor */
6072 fd = smb_ChainFID(fd, inp);
6073 fidp = smb_FindFID(vcp, fd, 0);
6074 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6075 return CM_ERROR_BADFD;
6078 userp = smb_GetUser(vcp, inp);
6080 lock_ObtainMutex(&fidp->mx);
6082 lock_ObtainMutex(&scp->mx);
6083 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6084 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6087 /* offset from current offset */
6088 offset += fidp->offset;
6090 else if (whence == 2) {
6091 /* offset from current EOF */
6092 offset += scp->length.LowPart;
6094 fidp->offset = offset;
6095 smb_SetSMBParm(outp, 0, offset & 0xffff);
6096 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6097 smb_SetSMBDataLength(outp, 0);
6099 lock_ReleaseMutex(&scp->mx);
6100 lock_ReleaseMutex(&fidp->mx);
6101 smb_ReleaseFID(fidp);
6102 cm_ReleaseUser(userp);
6106 /* dispatch all of the requests received in a packet. Due to chaining, this may
6107 * be more than one request.
6109 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6110 NCB *ncbp, raw_write_cont_t *rwcp)
6114 unsigned long code = 0;
6115 unsigned char *outWctp;
6116 int nparms; /* # of bytes of parameters */
6118 int nbytes; /* bytes of data, excluding count */
6121 unsigned short errCode;
6122 unsigned long NTStatus;
6124 unsigned char errClass;
6125 unsigned int oldGen;
6126 DWORD oldTime, newTime;
6128 /* get easy pointer to the data */
6129 smbp = (smb_t *) inp->data;
6131 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6132 /* setup the basic parms for the initial request in the packet */
6133 inp->inCom = smbp->com;
6134 inp->wctp = &smbp->wct;
6136 inp->ncb_length = ncbp->ncb_length;
6141 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6142 /* log it and discard it */
6147 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6148 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6150 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6151 1, ncbp->ncb_length, ptbuf, inp);
6152 DeregisterEventSource(h);
6154 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6159 /* We are an ongoing op */
6160 thrd_Increment(&ongoingOps);
6162 /* set up response packet for receiving output */
6163 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6164 smb_FormatResponsePacket(vcp, inp, outp);
6165 outWctp = outp->wctp;
6167 /* Remember session generation number and time */
6168 oldGen = sessionGen;
6169 oldTime = GetCurrentTime();
6171 while (inp->inCom != 0xff) {
6172 dp = &smb_dispatchTable[inp->inCom];
6174 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6175 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6176 code = outp->resumeCode;
6180 /* process each request in the packet; inCom, wctp and inCount
6181 * are already set up.
6183 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6186 /* now do the dispatch */
6187 /* start by formatting the response record a little, as a default */
6188 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6190 outWctp[1] = 0xff; /* no operation */
6191 outWctp[2] = 0; /* padding */
6196 /* not a chained request, this is a more reasonable default */
6197 outWctp[0] = 0; /* wct of zero */
6198 outWctp[1] = 0; /* and bcc (word) of zero */
6202 /* once set, stays set. Doesn't matter, since we never chain
6203 * "no response" calls.
6205 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6209 /* we have a recognized operation */
6211 if (inp->inCom == 0x1d)
6213 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6216 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
6217 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
6218 code = (*(dp->procp)) (vcp, inp, outp);
6219 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6220 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6222 if ( code == CM_ERROR_BADSMB ||
6223 code == CM_ERROR_BADOP )
6225 #endif /* LOG_PACKET */
6228 if (oldGen != sessionGen) {
6233 newTime = GetCurrentTime();
6234 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6235 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6236 newTime - oldTime, ncbp->ncb_length);
6238 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6239 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6240 DeregisterEventSource(h);
6242 osi_Log1(smb_logp, "Pkt straddled session startup, "
6243 "ncb length %d", ncbp->ncb_length);
6247 /* bad opcode, fail the request, after displaying it */
6248 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6251 #endif /* LOG_PACKET */
6255 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6256 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6257 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6258 if (code == IDCANCEL)
6262 code = CM_ERROR_BADOP;
6265 /* catastrophic failure: log as much as possible */
6266 if (code == CM_ERROR_BADSMB) {
6273 "Invalid SMB, ncb_length %d",
6276 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6277 sprintf(s, "Invalid SMB message, length %d",
6280 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6281 1, ncbp->ncb_length, ptbuf, smbp);
6282 DeregisterEventSource(h);
6285 #endif /* LOG_PACKET */
6287 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6290 code = CM_ERROR_INVAL;
6293 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6294 thrd_Decrement(&ongoingOps);
6299 /* now, if we failed, turn the current response into an empty
6300 * one, and fill in the response packet's error code.
6303 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6304 smb_MapNTError(code, &NTStatus);
6305 outWctp = outp->wctp;
6306 smbp = (smb_t *) &outp->data;
6307 if (code != CM_ERROR_PARTIALWRITE
6308 && code != CM_ERROR_BUFFERTOOSMALL
6309 && code != CM_ERROR_GSSCONTINUE) {
6310 /* nuke wct and bcc. For a partial
6311 * write or an in-process authentication handshake,
6312 * assume they're OK.
6318 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6319 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6320 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6321 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6322 smbp->flg2 |= 0x4000;
6326 smb_MapCoreError(code, vcp, &errCode, &errClass);
6327 outWctp = outp->wctp;
6328 smbp = (smb_t *) &outp->data;
6329 if (code != CM_ERROR_PARTIALWRITE) {
6330 /* nuke wct and bcc. For a partial
6331 * write, assume they're OK.
6337 smbp->errLow = (unsigned char) (errCode & 0xff);
6338 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6339 smbp->rcls = errClass;
6342 } /* error occurred */
6344 /* if we're here, we've finished one request. Look to see if
6345 * this is a chained opcode. If it is, setup things to process
6346 * the chained request, and setup the output buffer to hold the
6347 * chained response. Start by finding the next input record.
6349 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6350 break; /* not a chained req */
6351 tp = inp->wctp; /* points to start of last request */
6352 /* in a chained request, the first two
6353 * parm fields are required, and are
6354 * AndXCommand/AndXReserved and
6356 if (tp[0] < 2) break;
6357 if (tp[1] == 0xff) break; /* no more chained opcodes */
6359 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6362 /* and now append the next output request to the end of this
6363 * last request. Begin by finding out where the last response
6364 * ends, since that's where we'll put our new response.
6366 outWctp = outp->wctp; /* ptr to out parameters */
6367 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6368 nparms = outWctp[0] << 1;
6369 tp = outWctp + nparms + 1; /* now points to bcc field */
6370 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6371 tp += 2 /* for the count itself */ + nbytes;
6372 /* tp now points to the new output record; go back and patch the
6373 * second parameter (off2) to point to the new record.
6375 temp = (unsigned int)tp - ((unsigned int) outp->data);
6376 outWctp[3] = (unsigned char) (temp & 0xff);
6377 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6378 outWctp[2] = 0; /* padding */
6379 outWctp[1] = inp->inCom; /* next opcode */
6381 /* finally, setup for the next iteration */
6384 } /* while loop over all requests in the packet */
6386 /* done logging out, turn off logging-out flag */
6387 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6388 vcp->justLoggedOut = NULL;
6391 free(loggedOutName);
6392 loggedOutName = NULL;
6393 smb_ReleaseUID(loggedOutUserp);
6394 loggedOutUserp = NULL;
6398 /* now send the output packet, and return */
6400 smb_SendPacket(vcp, outp);
6401 thrd_Decrement(&ongoingOps);
6403 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6405 smb_ReleaseVC(active_vcp);
6407 "Replacing active_vcp %x with %x", active_vcp, vcp);
6411 last_msg_time = GetCurrentTime();
6413 else if (active_vcp == vcp) {
6414 smb_ReleaseVC(active_vcp);
6422 /* Wait for Netbios() calls to return, and make the results available to server
6423 * threads. Note that server threads can't wait on the NCBevents array
6424 * themselves, because NCB events are manual-reset, and the servers would race
6425 * each other to reset them.
6427 void smb_ClientWaiter(void *parmp)
6433 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6435 if (code == WAIT_OBJECT_0)
6438 /* error checking */
6439 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6441 int abandonIdx = code - WAIT_ABANDONED_0;
6442 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6445 if (code == WAIT_IO_COMPLETION)
6447 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6451 if (code == WAIT_TIMEOUT)
6453 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6456 if (code == WAIT_FAILED)
6458 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6461 idx = code - WAIT_OBJECT_0;
6463 /* check idx range! */
6464 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6466 /* this is fatal - log as much as possible */
6467 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6471 thrd_ResetEvent(NCBevents[idx]);
6472 thrd_SetEvent(NCBreturns[0][idx]);
6478 * Try to have one NCBRECV request waiting for every live session. Not more
6479 * than one, because if there is more than one, it's hard to handle Write Raw.
6481 void smb_ServerWaiter(void *parmp)
6484 int idx_session, idx_NCB;
6492 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6494 if (code == WAIT_OBJECT_0)
6497 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6499 int abandonIdx = code - WAIT_ABANDONED_0;
6500 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6503 if (code == WAIT_IO_COMPLETION)
6505 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6509 if (code == WAIT_TIMEOUT)
6511 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6514 if (code == WAIT_FAILED)
6516 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6519 idx_session = code - WAIT_OBJECT_0;
6521 /* check idx range! */
6522 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6524 /* this is fatal - log as much as possible */
6525 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6531 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6533 if (code == WAIT_OBJECT_0)
6536 /* error checking */
6537 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6539 int abandonIdx = code - WAIT_ABANDONED_0;
6540 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6543 if (code == WAIT_IO_COMPLETION)
6545 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6549 if (code == WAIT_TIMEOUT)
6551 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6554 if (code == WAIT_FAILED)
6556 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6559 idx_NCB = code - WAIT_OBJECT_0;
6561 /* check idx range! */
6562 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6564 /* this is fatal - log as much as possible */
6565 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6569 /* Link them together */
6570 NCBsessions[idx_NCB] = idx_session;
6573 ncbp = NCBs[idx_NCB];
6575 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6577 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6578 ncbp->ncb_command = NCBRECV | ASYNCH;
6579 ncbp->ncb_lana_num = lanas[idx_session];
6581 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6582 ncbp->ncb_event = NCBevents[idx_NCB];
6583 ncbp->ncb_length = SMB_PACKETSIZE;
6586 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6587 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6588 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6589 ncbp->ncb_length = SMB_PACKETSIZE;
6590 Netbios(ncbp, dos_ncb);
6596 * The top level loop for handling SMB request messages. Each server thread
6597 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6598 * NCB and buffer for the incoming request are loaned to us.
6600 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6601 * to immediately send a request for the rest of the data. This must come
6602 * before any other traffic for that session, so we delay setting the session
6603 * event until that data has come in.
6605 void smb_Server(VOID *parmp)
6607 int myIdx = (int) parmp;
6611 smb_packet_t *outbufp;
6613 int idx_NCB, idx_session;
6615 smb_vc_t *vcp = NULL;
6622 outbufp = GetPacket();
6623 outbufp->ncbp = outncbp;
6626 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6628 if (code == WAIT_OBJECT_0) {
6632 /* error checking */
6633 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6635 int abandonIdx = code - WAIT_ABANDONED_0;
6636 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6639 if (code == WAIT_IO_COMPLETION)
6641 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6645 if (code == WAIT_TIMEOUT)
6647 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6650 if (code == WAIT_FAILED)
6652 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6655 idx_NCB = code - WAIT_OBJECT_0;
6657 /* check idx range! */
6658 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6660 /* this is fatal - log as much as possible */
6661 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6665 ncbp = NCBs[idx_NCB];
6667 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6669 idx_session = NCBsessions[idx_NCB];
6670 rc = ncbp->ncb_retcode;
6672 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6673 osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6676 case NRC_GOODRET: break;
6679 /* Can this happen? Or is it just my
6686 /* Client closed session */
6687 if (reportSessionStartups)
6689 osi_Log1(smb_logp, "session [ %d ] closed", idx_session);
6691 dead_sessions[idx_session] = TRUE;
6694 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6695 /* Should also release vcp. [done] 2004-05-11 jaltman
6697 * sanity check that all TID's are gone.
6699 * TODO: check if we could use LSNs[idx_session] instead,
6700 * also cleanup after dead vcp
6705 "dead_vcp already set, %x",
6707 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6709 "setting dead_vcp %x, user struct %x",
6713 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6715 if (vcp->justLoggedOut) {
6717 loggedOutTime = vcp->logoffTime;
6718 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
6719 loggedOutUserp = vcp->justLoggedOut;
6720 lock_ObtainWrite(&smb_rctLock);
6721 loggedOutUserp->refCount++;
6722 lock_ReleaseWrite(&smb_rctLock);
6728 /* Treat as transient error */
6735 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6736 sprintf(s, "SMB message incomplete, length %d",
6739 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6741 ncbp->ncb_length, ptbuf,
6743 DeregisterEventSource(h);
6746 "dispatch smb recv failed, message incomplete, ncb_length %d",
6749 "SMB message incomplete, "
6750 "length %d", ncbp->ncb_length);
6753 * We used to discard the packet.
6754 * Instead, try handling it normally.
6762 /* A weird error code. Log it, sleep, and
6764 if (vcp && vcp->errorCount++ > 3) {
6765 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6766 dead_sessions[idx_session] = TRUE;
6770 thrd_SetEvent(SessionEvents[idx_session]);
6775 /* Success, so now dispatch on all the data in the packet */
6777 smb_concurrentCalls++;
6778 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6779 smb_maxObsConcurrentCalls = smb_concurrentCalls;
6783 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6785 * If at this point vcp is NULL (implies that packet was invalid)
6786 * then we are in big trouble. This means either :
6787 * a) we have the wrong NCB.
6788 * b) Netbios screwed up the call.
6789 * Obviously this implies that
6790 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
6791 * lanas[idx_session] != ncbp->ncb_lana_num )
6792 * Either way, we can't do anything with this packet.
6793 * Log, sleep and resume.
6802 "LSNs[idx_session]=[%d],"
6803 "lanas[idx_session]=[%d],"
6804 "ncbp->ncb_lsn=[%d],"
6805 "ncbp->ncb_lana_num=[%d]",
6809 ncbp->ncb_lana_num);
6813 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6815 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6816 DeregisterEventSource(h);
6819 /* Also log in the trace log. */
6820 osi_Log4(smb_logp, "Server: BAD VCP!"
6821 "LSNs[idx_session]=[%d],"
6822 "lanas[idx_session]=[%d],"
6823 "ncbp->ncb_lsn=[%d],"
6824 "ncbp->ncb_lana_num=[%d]",
6828 ncbp->ncb_lana_num);
6830 /* thrd_Sleep(1000); Don't bother sleeping */
6831 thrd_SetEvent(SessionEvents[idx_session]);
6832 smb_concurrentCalls--;
6837 vcp->errorCount = 0;
6838 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6840 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6841 /* copy whole packet to virtual memory */
6842 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6844 bufp->dos_pkt / 16, bufp);*/
6846 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6848 smbp = (smb_t *)bufp->data;
6851 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6855 if (smbp->com == 0x1d) {
6856 /* Special handling for Write Raw */
6857 raw_write_cont_t rwc;
6858 EVENT_HANDLE rwevent;
6859 char eventName[MAX_PATH];
6861 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6862 if (rwc.code == 0) {
6863 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6864 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6865 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6866 ncbp->ncb_command = NCBRECV | ASYNCH;
6867 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6868 ncbp->ncb_lana_num = vcp->lana;
6869 ncbp->ncb_buffer = rwc.buf;
6870 ncbp->ncb_length = 65535;
6871 ncbp->ncb_event = rwevent;
6875 Netbios(ncbp, dos_ncb);
6877 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6878 thrd_CloseHandle(rwevent);
6880 thrd_SetEvent(SessionEvents[idx_session]);
6882 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6884 else if (smbp->com == 0xa0) {
6886 * Serialize the handling for NT Transact
6889 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6890 thrd_SetEvent(SessionEvents[idx_session]);
6892 thrd_SetEvent(SessionEvents[idx_session]);
6893 /* TODO: what else needs to be serialized? */
6894 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6896 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6898 __except( smb_ServerExceptionFilter() ) {
6902 smb_concurrentCalls--;
6905 thrd_SetEvent(NCBavails[idx_NCB]);
6912 * Exception filter for the server threads. If an exception occurs in the
6913 * dispatch routines, which is where exceptions are most common, then do a
6914 * force trace and give control to upstream exception handlers. Useful for
6917 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6918 DWORD smb_ServerExceptionFilter(void) {
6919 /* While this is not the best time to do a trace, if it succeeds, then
6920 * we have a trace (assuming tracing was enabled). Otherwise, this should
6921 * throw a second exception.
6926 ptbuf[0] = "Unhandled exception forcing trace";
6928 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6930 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6931 DeregisterEventSource(h);
6934 afsd_ForceTrace(TRUE);
6935 return EXCEPTION_CONTINUE_SEARCH;
6940 * Create a new NCB and associated events, packet buffer, and "space" buffer.
6941 * If the number of server threads is M, and the number of live sessions is
6942 * N, then the number of NCB's in use at any time either waiting for, or
6943 * holding, received messages is M + N, so that is how many NCB's get created.
6945 void InitNCBslot(int idx)
6947 struct smb_packet *bufp;
6948 EVENT_HANDLE retHandle;
6950 char eventName[MAX_PATH];
6952 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
6954 NCBs[idx] = GetNCB();
6955 sprintf(eventName,"NCBavails[%d]", idx);
6956 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6957 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6958 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6960 sprintf(eventName,"NCBevents[%d]", idx);
6961 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
6962 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6963 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6965 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
6966 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6967 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6968 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6969 for (i=0; i<smb_NumServerThreads; i++)
6970 NCBreturns[i][idx] = retHandle;
6972 bufp->spacep = cm_GetSpace();
6976 /* listen for new connections */
6977 void smb_Listener(void *parmp)
6985 char rname[NCBNAMSZ+1];
6986 char cname[MAX_COMPUTERNAME_LENGTH+1];
6987 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
6992 int lana = (int) parmp;
6996 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6999 /* retrieve computer name */
7000 GetComputerName(cname, &cnamelen);
7004 memset(ncbp, 0, sizeof(NCB));
7007 ncbp->ncb_command = NCBLISTEN;
7008 ncbp->ncb_rto = 0; /* No receive timeout */
7009 ncbp->ncb_sto = 0; /* No send timeout */
7011 /* pad out with spaces instead of null termination */
7012 len = strlen(smb_localNamep);
7013 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7014 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7016 strcpy(ncbp->ncb_callname, "*");
7017 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7019 ncbp->ncb_lana_num = lana;
7022 code = Netbios(ncbp);
7024 code = Netbios(ncbp, dos_ncb);
7033 /* terminate silently if shutdown flag is set */
7034 if (smbShutdownFlag == 1) {
7043 "NCBLISTEN lana=%d failed with code %d",
7044 ncbp->ncb_lana_num, code);
7046 "Client exiting due to network failure. Please restart client.\n");
7050 "Client exiting due to network failure. Please restart client.\n"
7051 "NCBLISTEN lana=%d failed with code %d",
7052 ncbp->ncb_lana_num, code);
7054 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7055 MB_OK|MB_SERVICE_NOTIFICATION);
7056 osi_assert(tbuffer);
7059 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7060 ncbp->ncb_lana_num, code);
7061 fprintf(stderr, "\nClient exiting due to network failure "
7062 "(possibly due to power-saving mode)\n");
7063 fprintf(stderr, "Please restart client.\n");
7064 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7068 /* check for remote conns */
7069 /* first get remote name and insert null terminator */
7070 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7071 for (i=NCBNAMSZ; i>0; i--) {
7072 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7078 /* compare with local name */
7080 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7081 flags |= SMB_VCFLAG_REMOTECONN;
7083 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7085 lock_ObtainMutex(&smb_ListenerLock);
7087 /* New generation */
7090 /* Log session startup */
7092 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7094 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7095 #endif /* NOTSERVICE */
7096 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7097 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7099 if (reportSessionStartups) {
7105 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7106 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7108 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7110 DeregisterEventSource(h);
7113 fprintf(stderr, "%s: New session %d starting from host %s\n",
7114 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7118 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7119 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7122 /* now ncbp->ncb_lsn is the connection ID */
7123 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7124 vcp->flags |= flags;
7125 strcpy(vcp->rname, rname);
7127 /* Allocate slot in session arrays */
7128 /* Re-use dead session if possible, otherwise add one more */
7129 /* But don't look at session[0], it is reserved */
7130 for (i = 1; i < numSessions; i++) {
7131 if (dead_sessions[i]) {
7132 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7133 dead_sessions[i] = FALSE;
7138 /* assert that we do not exceed the maximum number of sessions or NCBs.
7139 * we should probably want to wait for a session to be freed in case
7143 osi_assert(i < Sessionmax - 1);
7144 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7146 LSNs[i] = ncbp->ncb_lsn;
7147 lanas[i] = ncbp->ncb_lana_num;
7149 if (i == numSessions) {
7150 /* Add new NCB for new session */
7151 char eventName[MAX_PATH];
7153 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7155 InitNCBslot(numNCBs);
7157 thrd_SetEvent(NCBavails[0]);
7158 thrd_SetEvent(NCBevents[0]);
7159 for (j = 0; j < smb_NumServerThreads; j++)
7160 thrd_SetEvent(NCBreturns[j][0]);
7161 /* Also add new session event */
7162 sprintf(eventName, "SessionEvents[%d]", i);
7163 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7164 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7165 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7167 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7168 thrd_SetEvent(SessionEvents[0]);
7170 thrd_SetEvent(SessionEvents[i]);
7173 lock_ReleaseMutex(&smb_ListenerLock);
7175 } /* dispatch while loop */
7178 /* initialize Netbios */
7179 void smb_NetbiosInit()
7185 int i, lana, code, l;
7187 int delname_tried=0;
7190 OSVERSIONINFO Version;
7192 /* AFAIK, this is the default for the ms loopback adapter.*/
7193 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
7194 /*******************************************************************/
7196 /* Get the version of Windows */
7197 memset(&Version, 0x00, sizeof(Version));
7198 Version.dwOSVersionInfoSize = sizeof(Version);
7199 GetVersionEx(&Version);
7201 /* setup the NCB system */
7204 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7208 if (smb_LANadapter == -1) {
7209 ncbp->ncb_command = NCBENUM;
7210 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7211 ncbp->ncb_length = sizeof(lana_list);
7212 code = Netbios(ncbp);
7214 sprintf(s, "Netbios NCBENUM error code %d", code);
7215 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7216 osi_panic(s, __FILE__, __LINE__);
7220 lana_list.length = 1;
7221 lana_list.lana[0] = smb_LANadapter;
7224 for (i = 0; i < lana_list.length; i++) {
7225 /* reset the adaptor: in Win32, this is required for every process, and
7226 * acts as an init call, not as a real hardware reset.
7228 ncbp->ncb_command = NCBRESET;
7229 ncbp->ncb_callname[0] = 100;
7230 ncbp->ncb_callname[2] = 100;
7231 ncbp->ncb_lana_num = lana_list.lana[i];
7232 code = Netbios(ncbp);
7234 code = ncbp->ncb_retcode;
7236 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7237 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7238 lana_list.lana[i] = 255; /* invalid lana */
7240 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7241 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7245 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7246 we will just fake the LANA list */
7247 if (smb_LANadapter == -1) {
7248 for (i = 0; i < 8; i++)
7249 lana_list.lana[i] = i;
7250 lana_list.length = 8;
7253 lana_list.length = 1;
7254 lana_list.lana[0] = smb_LANadapter;
7258 /* and declare our name so we can receive connections */
7259 memset(ncbp, 0, sizeof(*ncbp));
7260 len=lstrlen(smb_localNamep);
7261 memset(smb_sharename,' ',NCBNAMSZ);
7262 memcpy(smb_sharename,smb_localNamep,len);
7263 sprintf(s, "lana_list.length %d", lana_list.length);
7264 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7266 /* Keep the name so we can unregister it later */
7267 for (l = 0; l < lana_list.length; l++) {
7268 lana = lana_list.lana[l];
7270 ncbp->ncb_command = NCBADDNAME;
7271 ncbp->ncb_lana_num = lana;
7272 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7274 code = Netbios(ncbp);
7276 code = Netbios(ncbp, dos_ncb);
7279 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7280 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7282 char name[NCBNAMSZ+1];
7284 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7285 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7288 if (code == 0) code = ncbp->ncb_retcode;
7290 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7292 /* we only use one LANA with djgpp */
7293 lana_list.lana[0] = lana;
7294 lana_list.length = 1;
7298 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7299 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7300 if (code == NRC_BRIDGE) { /* invalid LANA num */
7301 lana_list.lana[l] = 255;
7304 else if (code == NRC_DUPNAME) {
7305 osi_Log0(smb_logp, "Name already exists; try to delete it");
7306 memset(ncbp, 0, sizeof(*ncbp));
7307 ncbp->ncb_command = NCBDELNAME;
7308 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7309 ncbp->ncb_lana_num = lana;
7311 code = Netbios(ncbp);
7313 code = Netbios(ncbp, dos_ncb);
7316 code = ncbp->ncb_retcode;
7318 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7319 osi_Log0(smb_logp, s);
7321 if (code != 0 || delname_tried) {
7322 lana_list.lana[l] = 255;
7324 else if (code == 0) {
7325 if (!delname_tried) {
7333 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7334 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7335 lana_list.lana[l] = 255; /* invalid lana */
7336 osi_panic(s, __FILE__, __LINE__);
7340 lana_found = 1; /* at least one worked */
7347 osi_assert(lana_list.length >= 0);
7349 sprintf(s, "No valid LANA numbers found!");
7350 osi_panic(s, __FILE__, __LINE__);
7353 /* we're done with the NCB now */
7357 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7374 EVENT_HANDLE retHandle;
7375 char eventName[MAX_PATH];
7378 smb_MBfunc = aMBfunc;
7382 smb_LANadapter = LANadapt;
7384 /* Initialize smb_localZero */
7385 myTime.tm_isdst = -1; /* compute whether on DST or not */
7386 myTime.tm_year = 70;
7392 smb_localZero = mktime(&myTime);
7394 /* Initialize kludge-GMT */
7395 smb_CalculateNowTZ();
7397 #ifdef AFS_FREELANCE_CLIENT
7398 /* Make sure the root.afs volume has the correct time */
7399 cm_noteLocalMountPointChange();
7402 /* initialize the remote debugging log */
7405 /* remember the name */
7406 len = strlen(snamep);
7407 smb_localNamep = malloc(len+1);
7408 strcpy(smb_localNamep, snamep);
7409 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7411 /* and the global lock */
7412 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7413 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7415 /* Raw I/O data structures */
7416 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7418 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7420 /* 4 Raw I/O buffers */
7422 smb_RawBufs = calloc(65536,1);
7423 *((char **)smb_RawBufs) = NULL;
7424 for (i=0; i<3; i++) {
7425 char *rawBuf = calloc(65536,1);
7426 *((char **)rawBuf) = smb_RawBufs;
7427 smb_RawBufs = rawBuf;
7430 npar = 65536 >> 4; /* number of paragraphs */
7431 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7433 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7435 osi_panic("",__FILE__,__LINE__);
7438 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7441 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7443 _farpokel(_dos_ds, smb_RawBufs, NULL);
7444 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7445 npar = 65536 >> 4; /* number of paragraphs */
7446 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7448 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7450 osi_panic("",__FILE__,__LINE__);
7453 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7456 rawBuf = (seg * 16) + 0; /* DOS physical address */
7457 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7458 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7459 smb_RawBufs = rawBuf;
7463 /* global free lists */
7464 smb_ncbFreeListp = NULL;
7465 smb_packetFreeListp = NULL;
7469 /* Initialize listener and server structures */
7471 memset(dead_sessions, 0, sizeof(dead_sessions));
7472 sprintf(eventName, "SessionEvents[0]");
7473 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7474 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7475 afsi_log("Event Object Already Exists: %s", eventName);
7477 smb_NumServerThreads = nThreads;
7478 sprintf(eventName, "NCBavails[0]");
7479 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7480 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7481 afsi_log("Event Object Already Exists: %s", eventName);
7482 sprintf(eventName, "NCBevents[0]");
7483 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7484 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7485 afsi_log("Event Object Already Exists: %s", eventName);
7486 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7487 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7488 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7489 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7490 afsi_log("Event Object Already Exists: %s", eventName);
7491 for (i = 0; i < smb_NumServerThreads; i++) {
7492 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7493 NCBreturns[i][0] = retHandle;
7495 for (i = 1; i <= nThreads; i++)
7497 numNCBs = nThreads + 1;
7499 /* Initialize dispatch table */
7500 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7501 /* Prepare the table for unknown operations */
7502 for(i=0; i<= SMB_NOPCODES; i++) {
7503 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7505 /* Fill in the ones we do know */
7506 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7507 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7508 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7509 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7510 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7511 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7512 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7513 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7514 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7515 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7516 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7517 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7518 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7519 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7520 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7521 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7522 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7523 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7524 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7525 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7526 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7527 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7528 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7529 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7530 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7531 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7532 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7533 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7534 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7535 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7536 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7537 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7538 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7539 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7540 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7541 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7542 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7543 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7544 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7545 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7546 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7547 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7548 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7549 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7550 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7551 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7552 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7553 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7554 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7555 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7556 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7557 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7558 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7559 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7560 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7561 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7562 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
7563 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
7564 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
7565 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7566 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7567 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7568 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7569 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7570 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
7571 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
7572 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
7573 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
7574 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
7575 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
7576 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
7577 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
7579 /* setup tran 2 dispatch table */
7580 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7581 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7582 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7583 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7584 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7585 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7586 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7587 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7588 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7589 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7590 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7591 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7592 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7593 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
7594 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
7595 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2GetDFSReferral;
7596 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2ReportDFSInconsistency;
7598 /* setup the rap dispatch table */
7599 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
7600 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
7601 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
7602 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
7603 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
7607 /* if we are doing SMB authentication we have register outselves as a logon process */
7608 if (smb_authType != SMB_AUTH_NONE) {
7610 LSA_STRING afsProcessName;
7611 LSA_OPERATIONAL_MODE dummy; /*junk*/
7613 afsProcessName.Buffer = "OpenAFSClientDaemon";
7614 afsProcessName.Length = strlen(afsProcessName.Buffer);
7615 afsProcessName.MaximumLength = afsProcessName.Length + 1;
7617 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
7619 if (nts == STATUS_SUCCESS) {
7620 LSA_STRING packageName;
7621 /* we are registered. Find out the security package id */
7622 packageName.Buffer = MSV1_0_PACKAGE_NAME;
7623 packageName.Length = strlen(packageName.Buffer);
7624 packageName.MaximumLength = packageName.Length + 1;
7625 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
7626 if (nts == STATUS_SUCCESS) {
7627 smb_lsaLogonOrigin.Buffer = "OpenAFS";
7628 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
7629 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
7631 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
7634 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
7637 if (nts != STATUS_SUCCESS) {
7638 /* something went wrong. We report the error and revert back to no authentication
7639 because we can't perform any auth requests without a successful lsa handle
7640 or sec package id. */
7641 afsi_log("Reverting to NO SMB AUTH");
7642 smb_authType = SMB_AUTH_NONE;
7645 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
7646 * time prevents the failure of authentication when logged into Windows with an
7647 * external Kerberos principal mapped to a local account.
7649 else if ( smb_authType == SMB_AUTH_EXTENDED) {
7650 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
7651 * then the only option is NTLMSSP anyway; so just fallback.
7656 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
7657 if (secBlobLength == 0) {
7658 smb_authType = SMB_AUTH_NTLM;
7659 afsi_log("Reverting to SMB AUTH NTLM");
7668 /* Now get ourselves a domain name. */
7669 /* For now we are using the local computer name as the domain name.
7670 * It is actually the domain for local logins, and we are acting as
7671 * a local SMB server.
7673 bufsize = sizeof(smb_ServerDomainName) - 1;
7674 GetComputerName(smb_ServerDomainName, &bufsize);
7675 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
7676 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
7679 /* Start listeners, waiters, servers, and daemons */
7681 for (i = 0; i < lana_list.length; i++) {
7682 if (lana_list.lana[i] == 255) continue;
7683 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7684 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7685 osi_assert(phandle != NULL);
7686 thrd_CloseHandle(phandle);
7690 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7691 NULL, 0, &lpid, "smb_ClientWaiter");
7692 osi_assert(phandle != NULL);
7693 thrd_CloseHandle(phandle);
7696 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7697 NULL, 0, &lpid, "smb_ServerWaiter");
7698 osi_assert(phandle != NULL);
7699 thrd_CloseHandle(phandle);
7701 for (i=0; i<nThreads; i++) {
7702 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7703 (void *) i, 0, &lpid, "smb_Server");
7704 osi_assert(phandle != NULL);
7705 thrd_CloseHandle(phandle);
7708 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7709 NULL, 0, &lpid, "smb_Daemon");
7710 osi_assert(phandle != NULL);
7711 thrd_CloseHandle(phandle);
7713 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7714 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7715 osi_assert(phandle != NULL);
7716 thrd_CloseHandle(phandle);
7725 void smb_Shutdown(void)
7734 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7736 /* setup the NCB system */
7739 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7742 /* Block new sessions by setting shutdown flag */
7743 smbShutdownFlag = 1;
7745 /* Hang up all sessions */
7746 memset((char *)ncbp, 0, sizeof(NCB));
7747 for (i = 1; i < numSessions; i++)
7749 if (dead_sessions[i])
7752 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7753 ncbp->ncb_command = NCBHANGUP;
7754 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
7755 ncbp->ncb_lsn = LSNs[i];
7757 code = Netbios(ncbp);
7759 code = Netbios(ncbp, dos_ncb);
7761 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7762 if (code == 0) code = ncbp->ncb_retcode;
7764 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7765 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7769 /* Delete Netbios name */
7770 memset((char *)ncbp, 0, sizeof(NCB));
7771 for (i = 0; i < lana_list.length; i++) {
7772 if (lana_list.lana[i] == 255) continue;
7773 ncbp->ncb_command = NCBDELNAME;
7774 ncbp->ncb_lana_num = lana_list.lana[i];
7775 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7777 code = Netbios(ncbp);
7779 code = Netbios(ncbp, dos_ncb);
7782 code = ncbp->ncb_retcode;
7784 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7785 ncbp->ncb_lana_num, code);
7791 /* Get the UNC \\<servername>\<sharename> prefix. */
7792 char *smb_GetSharename()
7796 /* Make sure we have been properly initialized. */
7797 if (smb_localNamep == NULL)
7800 /* Allocate space for \\<servername>\<sharename>, plus the
7803 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7804 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7810 void smb_LogPacket(smb_packet_t *packet)
7813 unsigned length, paramlen, datalen, i, j;
7815 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7817 if (!packet) return;
7819 osi_Log0(smb_logp, "*** SMB packet dump ***");
7821 vp = (BYTE *) packet->data;
7823 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7824 length = paramlen + 2 + datalen;
7827 for (i=0;i < length; i+=16)
7829 memset( buf, ' ', 80 );
7834 buf[strlen(buf)] = ' ';
7836 cp = (BYTE*) buf + 7;
7838 for (j=0;j < 16 && (i+j)<length; j++)
7840 *(cp++) = hex[vp[i+j] >> 4];
7841 *(cp++) = hex[vp[i+j] & 0xf];
7851 for (j=0;j < 16 && (i+j)<length;j++)
7853 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7864 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
7867 osi_Log0(smb_logp, "*** End SMB packet dump ***");
7869 #endif /* LOG_PACKET */
7872 int smb_DumpVCP(FILE *outputFile, char *cookie)
7879 lock_ObtainRead(&smb_rctLock);
7881 sprintf(output, "begin dumping vcpsp\n");
7882 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7884 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
7888 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7889 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7890 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7892 sprintf(output, "begin dumping fidsp\n");
7893 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7895 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
7897 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",
7898 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
7899 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
7900 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7901 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7904 sprintf(output, "done dumping fidsp\n");
7905 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7908 sprintf(output, "done dumping vcpsp\n");
7909 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7911 lock_ReleaseRead(&smb_rctLock);