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 EVENT_HANDLE *smb_ServerShutdown;
99 DWORD NCBsessions[NCBmax];
101 struct smb_packet *bufs[NCBmax];
103 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
104 EVENT_HANDLE SessionEvents[Sessionmax];
105 unsigned short LSNs[Sessionmax];
106 int lanas[Sessionmax];
107 BOOL dead_sessions[Sessionmax];
111 osi_mutex_t smb_RawBufLock;
113 #define SMB_RAW_BUFS 4
115 int smb_RawBufSel[SMB_RAW_BUFS];
120 #define SMB_MASKFLAG_TILDE 1
121 #define SMB_MASKFLAG_CASEFOLD 2
123 #define RAWTIMEOUT INFINITE
126 typedef struct raw_write_cont {
139 /* dir search stuff */
140 long smb_dirSearchCounter = 1;
141 smb_dirSearch_t *smb_firstDirSearchp;
142 smb_dirSearch_t *smb_lastDirSearchp;
144 /* hide dot files? */
145 int smb_hideDotFiles;
147 /* global state about V3 protocols */
148 int smb_useV3; /* try to negotiate V3 */
151 static showErrors = 1;
152 /* MessageBox or something like it */
153 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
154 extern HANDLE WaitToTerminate;
158 * Time in Unix format of midnight, 1/1/1970 local time.
159 * When added to dosUTime, gives Unix (AFS) time.
161 time_t smb_localZero = 0;
163 /* Time difference for converting to kludge-GMT */
166 char *smb_localNamep = NULL;
168 smb_vc_t *smb_allVCsp;
170 smb_username_t *usernamesp = NULL;
172 smb_waitingLock_t *smb_allWaitingLocks;
175 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
176 NCB *ncbp, raw_write_cont_t *rwcp);
177 void smb_NetbiosInit();
179 #ifndef AFS_WIN95_ENV
180 DWORD smb_ServerExceptionFilter(void);
183 extern char cm_HostName[];
184 extern char cm_confDir[];
188 #define LPTSTR char *
189 #define GetComputerName(str, sizep) \
190 strcpy((str), cm_HostName); \
191 *(sizep) = strlen(cm_HostName)
195 void smb_LogPacket(smb_packet_t *packet);
196 #endif /* LOG_PACKET */
197 extern char AFSConfigKeyName[];
199 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
200 int smb_ServerDomainNameLength = 0;
201 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
202 int smb_ServerOSLength = sizeof(smb_ServerOS);
203 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
204 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
206 /* Faux server GUID. This is never checked. */
207 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
209 char * myCrt_Dispatch(int i)
214 return "(00)ReceiveCoreMakeDir";
216 return "(01)ReceiveCoreRemoveDir";
218 return "(02)ReceiveCoreOpen";
220 return "(03)ReceiveCoreCreate";
222 return "(04)ReceiveCoreClose";
224 return "(05)ReceiveCoreFlush";
226 return "(06)ReceiveCoreUnlink";
228 return "(07)ReceiveCoreRename";
230 return "(08)ReceiveCoreGetFileAttributes";
232 return "(09)ReceiveCoreSetFileAttributes";
234 return "(0a)ReceiveCoreRead";
236 return "(0b)ReceiveCoreWrite";
238 return "(0c)ReceiveCoreLockRecord";
240 return "(0d)ReceiveCoreUnlockRecord";
242 return "(0e)SendCoreBadOp";
244 return "(0f)ReceiveCoreCreate";
246 return "(10)ReceiveCoreCheckPath";
248 return "(11)SendCoreBadOp";
250 return "(12)ReceiveCoreSeek";
252 return "(1a)ReceiveCoreReadRaw";
254 return "(1d)ReceiveCoreWriteRawDummy";
256 return "(22)ReceiveV3SetAttributes";
258 return "(23)ReceiveV3GetAttributes";
260 return "(24)ReceiveV3LockingX";
262 return "(25)ReceiveV3Trans";
264 return "(26)ReceiveV3Trans[aux]";
266 return "(29)SendCoreBadOp";
268 return "(2b)ReceiveCoreEcho";
270 return "(2d)ReceiveV3OpenX";
272 return "(2e)ReceiveV3ReadX";
274 return "(32)ReceiveV3Tran2A";
276 return "(33)ReceiveV3Tran2A[aux]";
278 return "(34)ReceiveV3FindClose";
280 return "(35)ReceiveV3FindNotifyClose";
282 return "(70)ReceiveCoreTreeConnect";
284 return "(71)ReceiveCoreTreeDisconnect";
286 return "(72)ReceiveNegotiate";
288 return "(73)ReceiveV3SessionSetupX";
290 return "(74)ReceiveV3UserLogoffX";
292 return "(75)ReceiveV3TreeConnectX";
294 return "(80)ReceiveCoreGetDiskAttributes";
296 return "(81)ReceiveCoreSearchDir";
300 return "(83)FindUnique";
302 return "(84)FindClose";
304 return "(A0)ReceiveNTTransact";
306 return "(A2)ReceiveNTCreateX";
308 return "(A4)ReceiveNTCancel";
310 return "(A5)ReceiveNTRename";
312 return "(C0)OpenPrintFile";
314 return "(C1)WritePrintFile";
316 return "(C2)ClosePrintFile";
318 return "(C3)GetPrintQueue";
320 return "(D8)ReadBulk";
322 return "(D9)WriteBulk";
324 return "(DA)WriteBulkData";
326 return "unknown SMB op";
330 char * myCrt_2Dispatch(int i)
335 return "unknown SMB op-2";
337 return "S(00)CreateFile";
339 return "S(01)FindFirst";
341 return "S(02)FindNext"; /* FindNext */
343 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
347 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
349 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
351 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
353 return "S(08)??_ReceiveTran2SetFileInfo";
355 return "S(09)??_ReceiveTran2FSCTL";
357 return "S(0a)_ReceiveTran2IOCTL";
359 return "S(0b)_ReceiveTran2FindNotifyFirst";
361 return "S(0c)_ReceiveTran2FindNotifyNext";
363 return "S(0d)_ReceiveTran2CreateDirectory";
365 return "S(0e)_ReceiveTran2SessionSetup";
369 char * myCrt_RapDispatch(int i)
374 return "unknown RAP OP";
376 return "RAP(0)NetShareEnum";
378 return "RAP(1)NetShareGetInfo";
380 return "RAP(13)NetServerGetInfo";
382 return "RAP(63)NetWkStaGetInfo";
386 /* scache must be locked */
387 unsigned int smb_Attributes(cm_scache_t *scp)
391 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
392 scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
394 attrs = SMB_ATTR_DIRECTORY;
395 #ifdef SPECIAL_FOLDERS
396 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
397 #endif /* SPECIAL_FOLDERS */
402 * We used to mark a file RO if it was in an RO volume, but that
403 * turns out to be impolitic in NT. See defect 10007.
406 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
408 if ((scp->unixModeBits & 0222) == 0)
409 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
414 /* Check if the named file/dir is a dotfile/dotdir */
415 /* String pointed to by lastComp can have leading slashes, but otherwise should have
416 no other patch components */
417 unsigned int smb_IsDotFile(char *lastComp) {
420 /* skip over slashes */
421 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
426 /* nulls, curdir and parent dir doesn't count */
432 if(*(s+1) == '.' && !*(s + 2))
439 static int ExtractBits(WORD bits, short start, short len)
446 num = bits << (16 - end);
447 num = num >> ((16 - end) + start);
453 void ShowUnixTime(char *FuncName, time_t unixTime)
458 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
460 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
461 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
463 int day, month, year, sec, min, hour;
466 day = ExtractBits(wDate, 0, 5);
467 month = ExtractBits(wDate, 5, 4);
468 year = ExtractBits(wDate, 9, 7) + 1980;
470 sec = ExtractBits(wTime, 0, 5);
471 min = ExtractBits(wTime, 5, 6);
472 hour = ExtractBits(wTime, 11, 5);
474 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
475 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
481 /* Determine if we are observing daylight savings time */
482 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
484 TIME_ZONE_INFORMATION timeZoneInformation;
485 SYSTEMTIME utc, local, localDST;
487 /* Get the time zone info. NT uses this to calc if we are in DST. */
488 GetTimeZoneInformation(&timeZoneInformation);
490 /* Return the daylight bias */
491 *pDstBias = timeZoneInformation.DaylightBias;
493 /* Return the bias */
494 *pBias = timeZoneInformation.Bias;
496 /* Now determine if DST is being observed */
498 /* Get the UTC (GMT) time */
501 /* Convert UTC time to local time using the time zone info. If we are
502 observing DST, the calculated local time will include this.
504 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
506 /* Set the daylight bias to 0. The daylight bias is the amount of change
507 * in time that we use for daylight savings time. By setting this to 0
508 * we cause there to be no change in time during daylight savings time.
510 timeZoneInformation.DaylightBias = 0;
512 /* Convert the utc time to local time again, but this time without any
513 adjustment for daylight savings time.
515 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
517 /* If the two times are different, then it means that the localDST that
518 we calculated includes the daylight bias, and therefore we are
519 observing daylight savings time.
521 *pDST = localDST.wHour != local.wHour;
524 /* Determine if we are observing daylight savings time */
525 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
531 *pDstBias = -60; /* where can this be different? */
537 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
539 BOOL dst; /* Will be TRUE if observing DST */
540 LONG dstBias; /* Offset from local time if observing DST */
541 LONG bias; /* Offset from GMT for local time */
544 * This function will adjust the last write time to compensate
545 * for two bugs in the smb client:
547 * 1) During Daylight Savings Time, the LastWriteTime is ahead
548 * in time by the DaylightBias (ignoring the sign - the
549 * DaylightBias is always stored as a negative number). If
550 * the DaylightBias is -60, then the LastWriteTime will be
551 * ahead by 60 minutes.
553 * 2) If the local time zone is a positive offset from GMT, then
554 * the LastWriteTime will be the correct local time plus the
555 * Bias (ignoring the sign - a positive offset from GMT is
556 * always stored as a negative Bias). If the Bias is -120,
557 * then the LastWriteTime will be ahead by 120 minutes.
559 * These bugs can occur at the same time.
562 GetTimeZoneInfo(&dst, &dstBias, &bias);
564 /* First adjust for DST */
566 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
568 /* Now adjust for a positive offset from GMT (a negative bias). */
570 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
574 * Calculate the difference (in seconds) between local time and GMT.
575 * This enables us to convert file times to kludge-GMT.
581 struct tm gmt_tm, local_tm;
582 int days, hours, minutes, seconds;
585 gmt_tm = *(gmtime(&t));
586 local_tm = *(localtime(&t));
588 days = local_tm.tm_yday - gmt_tm.tm_yday;
589 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
591 /* There is a problem with DST immediately after the time change
592 * which may continue to exist until the machine is rebooted
594 - (local_tm.tm_isdst ? 1 : 0)
597 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
598 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
604 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
609 time_t ersatz_unixTime;
612 * Must use kludge-GMT instead of real GMT.
613 * kludge-GMT is computed by adding time zone difference to localtime.
616 * ltp = gmtime(&unixTime);
618 ersatz_unixTime = unixTime - smb_NowTZ;
619 ltp = localtime(&ersatz_unixTime);
621 /* if we fail, make up something */
624 localJunk.tm_year = 89 - 20;
625 localJunk.tm_mon = 4;
626 localJunk.tm_mday = 12;
627 localJunk.tm_hour = 0;
628 localJunk.tm_min = 0;
629 localJunk.tm_sec = 0;
632 stm.wYear = ltp->tm_year + 1900;
633 stm.wMonth = ltp->tm_mon + 1;
634 stm.wDayOfWeek = ltp->tm_wday;
635 stm.wDay = ltp->tm_mday;
636 stm.wHour = ltp->tm_hour;
637 stm.wMinute = ltp->tm_min;
638 stm.wSecond = ltp->tm_sec;
639 stm.wMilliseconds = 0;
641 SystemTimeToFileTime(&stm, largeTimep);
644 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
646 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
647 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
648 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
650 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
652 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
653 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
655 *ft = LargeIntegerMultiplyByLong(*ft, 60);
656 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
659 ut = ConvertLongToLargeInteger(unixTime);
660 ut = LargeIntegerMultiplyByLong(ut, 10000000);
661 *ft = LargeIntegerAdd(*ft, ut);
666 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
672 FileTimeToSystemTime(largeTimep, &stm);
674 lt.tm_year = stm.wYear - 1900;
675 lt.tm_mon = stm.wMonth - 1;
676 lt.tm_wday = stm.wDayOfWeek;
677 lt.tm_mday = stm.wDay;
678 lt.tm_hour = stm.wHour;
679 lt.tm_min = stm.wMinute;
680 lt.tm_sec = stm.wSecond;
683 save_timezone = _timezone;
684 _timezone += smb_NowTZ;
685 *unixTimep = mktime(<);
686 _timezone = save_timezone;
689 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
691 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
692 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
693 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
697 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
698 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
699 a = LargeIntegerMultiplyByLong(a, 60);
700 a = LargeIntegerMultiplyByLong(a, 10000000);
702 /* subtract it from ft */
703 a = LargeIntegerSubtract(*ft, a);
705 /* divide down to seconds */
706 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
710 void smb_SearchTimeFromUnixTime(time_t *dosTimep, time_t unixTime)
718 ltp = localtime((time_t*) &t);
720 /* if we fail, make up something */
723 localJunk.tm_year = 89 - 20;
724 localJunk.tm_mon = 4;
725 localJunk.tm_mday = 12;
726 localJunk.tm_hour = 0;
727 localJunk.tm_min = 0;
728 localJunk.tm_sec = 0;
731 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
732 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
733 *dosTimep = (dosDate<<16) | dosTime;
736 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
738 unsigned short dosDate;
739 unsigned short dosTime;
742 dosDate = (unsigned short) (searchTime & 0xffff);
743 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
745 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
746 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
747 localTm.tm_mday = (dosDate) & 0x1f;
748 localTm.tm_hour = (dosTime>>11) & 0x1f;
749 localTm.tm_min = (dosTime >> 5) & 0x3f;
750 localTm.tm_sec = (dosTime & 0x1f) * 2;
751 localTm.tm_isdst = -1; /* compute whether DST in effect */
753 *unixTimep = mktime(&localTm);
756 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
758 *dosUTimep = unixTime - smb_localZero;
761 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
764 *unixTimep = dosTime + smb_localZero;
766 /* dosTime seems to be already adjusted for GMT */
767 *unixTimep = dosTime;
771 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
775 lock_ObtainWrite(&smb_rctLock);
776 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
777 if (lsn == vcp->lsn && lana == vcp->lana) {
782 if (!vcp && (flags & SMB_FLAG_CREATE)) {
783 vcp = malloc(sizeof(*vcp));
784 memset(vcp, 0, sizeof(*vcp));
785 vcp->vcID = numVCs++;
789 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
790 vcp->nextp = smb_allVCsp;
792 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
797 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
798 /* We must obtain a challenge for extended auth
799 * in case the client negotiates smb v3
802 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
803 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
806 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
808 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
815 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
817 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
818 LsaFreeReturnBuffer(lsaResp);
821 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
823 lock_ReleaseWrite(&smb_rctLock);
827 int smb_IsStarMask(char *maskp)
832 for(i=0; i<11; i++) {
834 if (tc == '?' || tc == '*' || tc == '>') return 1;
839 void smb_ReleaseVC(smb_vc_t *vcp)
841 lock_ObtainWrite(&smb_rctLock);
842 osi_assert(vcp->refCount-- > 0);
843 lock_ReleaseWrite(&smb_rctLock);
846 void smb_HoldVC(smb_vc_t *vcp)
848 lock_ObtainWrite(&smb_rctLock);
850 lock_ReleaseWrite(&smb_rctLock);
853 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
857 lock_ObtainWrite(&smb_rctLock);
858 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
859 if (tid == tidp->tid) {
864 if (!tidp && (flags & SMB_FLAG_CREATE)) {
865 tidp = malloc(sizeof(*tidp));
866 memset(tidp, 0, sizeof(*tidp));
867 tidp->nextp = vcp->tidsp;
872 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
875 lock_ReleaseWrite(&smb_rctLock);
879 void smb_ReleaseTID(smb_tid_t *tidp)
888 lock_ObtainWrite(&smb_rctLock);
889 osi_assert(tidp->refCount-- > 0);
890 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
891 ltpp = &tidp->vcp->tidsp;
892 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
893 if (tp == tidp) break;
895 osi_assert(tp != NULL);
897 lock_FinalizeMutex(&tidp->mx);
898 userp = tidp->userp; /* remember to drop ref later */
901 lock_ReleaseWrite(&smb_rctLock);
903 cm_ReleaseUser(userp);
910 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
912 smb_user_t *uidp = NULL;
914 lock_ObtainWrite(&smb_rctLock);
915 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
916 if (uid == uidp->userID) {
918 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
919 (int)vcp, uidp->userID,
920 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
924 if (!uidp && (flags & SMB_FLAG_CREATE)) {
925 uidp = malloc(sizeof(*uidp));
926 memset(uidp, 0, sizeof(*uidp));
927 uidp->nextp = vcp->usersp;
932 lock_InitializeMutex(&uidp->mx, "user_t mutex");
934 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 : ""));
936 lock_ReleaseWrite(&smb_rctLock);
940 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
942 smb_username_t *unp= NULL;
944 lock_ObtainWrite(&smb_rctLock);
945 for(unp = usernamesp; unp; unp = unp->nextp) {
946 if (stricmp(unp->name, usern) == 0 &&
947 stricmp(unp->machine, machine) == 0) {
952 if (!unp && (flags & SMB_FLAG_CREATE)) {
953 unp = malloc(sizeof(*unp));
954 memset(unp, 0, sizeof(*unp));
956 unp->nextp = usernamesp;
957 unp->name = strdup(usern);
958 unp->machine = strdup(machine);
960 lock_InitializeMutex(&unp->mx, "username_t mutex");
962 lock_ReleaseWrite(&smb_rctLock);
966 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
968 smb_user_t *uidp= NULL;
970 lock_ObtainWrite(&smb_rctLock);
971 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
974 if (stricmp(uidp->unp->name, usern) == 0) {
976 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
981 lock_ReleaseWrite(&smb_rctLock);
984 void smb_ReleaseUID(smb_user_t *uidp)
993 lock_ObtainWrite(&smb_rctLock);
994 osi_assert(uidp->refCount-- > 0);
995 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
996 lupp = &uidp->vcp->usersp;
997 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
998 if (up == uidp) break;
1000 osi_assert(up != NULL);
1002 lock_FinalizeMutex(&uidp->mx);
1004 userp = uidp->unp->userp; /* remember to drop ref later */
1005 uidp->unp->userp = NULL;
1010 lock_ReleaseWrite(&smb_rctLock);
1012 cm_ReleaseUserVCRef(userp);
1013 cm_ReleaseUser(userp);
1020 /* retrieve a held reference to a user structure corresponding to an incoming
1022 * corresponding release function is cm_ReleaseUser.
1024 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1030 smbp = (smb_t *) inp;
1031 uidp = smb_FindUID(vcp, smbp->uid, 0);
1032 if ((!uidp) || (!uidp->unp))
1035 lock_ObtainMutex(&uidp->mx);
1036 up = uidp->unp->userp;
1038 lock_ReleaseMutex(&uidp->mx);
1040 smb_ReleaseUID(uidp);
1046 * Return a pointer to a pathname extracted from a TID structure. The
1047 * TID structure is not held; assume it won't go away.
1049 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1054 tidp = smb_FindTID(vcp, tid, 0);
1058 if(tidp->flags & SMB_TIDFLAG_IPC) {
1059 code = CM_ERROR_TIDIPC;
1060 /* tidp->pathname would be NULL, but that's fine */
1062 *treepath = tidp->pathname;
1063 smb_ReleaseTID(tidp);
1068 /* check to see if we have a chained fid, that is, a fid that comes from an
1069 * OpenAndX message that ran earlier in this packet. In this case, the fid
1070 * field in a read, for example, request, isn't set, since the value is
1071 * supposed to be inherited from the openAndX call.
1073 int smb_ChainFID(int fid, smb_packet_t *inp)
1075 if (inp->fid == 0 || inp->inCount == 0)
1081 /* are we a priv'd user? What does this mean on NT? */
1082 int smb_SUser(cm_user_t *userp)
1087 /* find a file ID. If we pass in 0 we select an used File ID.
1088 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1089 * smb_fid_t data structure if desired File ID cannot be found.
1091 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1096 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1099 lock_ObtainWrite(&smb_rctLock);
1100 /* figure out if we need to allocate a new file ID */
1103 fid = vcp->fidCounter;
1107 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1108 if (fid == fidp->fid) {
1119 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1120 char eventName[MAX_PATH];
1122 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1123 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1124 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1125 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1126 thrd_CloseHandle(event);
1133 fidp = malloc(sizeof(*fidp));
1134 memset(fidp, 0, sizeof(*fidp));
1135 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1139 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1141 fidp->curr_chunk = fidp->prev_chunk = -2;
1142 fidp->raw_write_event = event;
1144 vcp->fidCounter = fid+1;
1145 if (vcp->fidCounter == 0)
1146 vcp->fidCounter = 1;
1149 lock_ReleaseWrite(&smb_rctLock);
1153 void smb_ReleaseFID(smb_fid_t *fidp)
1156 smb_vc_t *vcp = NULL;
1157 smb_ioctl_t *ioctlp;
1163 lock_ObtainWrite(&smb_rctLock);
1164 osi_assert(fidp->refCount-- > 0);
1165 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1167 if (!(fidp->flags & SMB_FID_IOCTL))
1169 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1170 thrd_CloseHandle(fidp->raw_write_event);
1172 /* and see if there is ioctl stuff to free */
1173 ioctlp = fidp->ioctlp;
1175 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1176 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1177 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1183 /* do not call smb_ReleaseVC() because we already have the lock */
1186 lock_ReleaseWrite(&smb_rctLock);
1188 /* now release the scache structure */
1190 cm_ReleaseSCache(scp);
1194 * Case-insensitive search for one string in another;
1195 * used to find variable names in submount pathnames.
1197 static char *smb_stristr(char *str1, char *str2)
1201 for (cursor = str1; *cursor; cursor++)
1202 if (stricmp(cursor, str2) == 0)
1209 * Substitute a variable value for its name in a submount pathname. Variable
1210 * name has been identified by smb_stristr() and is in substr. Variable name
1211 * length (plus one) is in substr_size. Variable value is in newstr.
1213 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1218 strcpy(temp, substr + substr_size - 1);
1219 strcpy(substr, newstr);
1223 char VNUserName[] = "%USERNAME%";
1224 char VNLCUserName[] = "%LCUSERNAME%";
1225 char VNComputerName[] = "%COMPUTERNAME%";
1226 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1229 /* List available shares */
1230 int smb_ListShares()
1234 char shareBuf[4096];
1242 /*strcpy(shareNameList[num_shares], "all");
1243 strcpy(pathNameList[num_shares++], "/afs");*/
1244 fprintf(stderr, "The following shares are available:\n");
1245 fprintf(stderr, "Share Name (AFS Path)\n");
1246 fprintf(stderr, "---------------------\n");
1247 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1250 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1251 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1253 strcpy(sbmtpath, cm_confDir);
1255 strcat(sbmtpath, "/afsdsbmt.ini");
1256 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1257 shareBuf, sizeof(shareBuf),
1263 this_share = shareBuf;
1267 /*strcpy(shareNameList[num_shares], this_share);*/
1268 len = GetPrivateProfileString("AFS Submounts", this_share,
1275 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1278 if (*p == '\\') *p = '/'; /* change to / */
1282 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1283 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1286 while (*this_share != 0) this_share++; /* find next NUL */
1287 this_share++; /* skip past the NUL */
1288 } while (*this_share != 0); /* stop at final NUL */
1294 typedef struct smb_findShare_rock {
1298 } smb_findShare_rock_t;
1300 #define SMB_FINDSHARE_EXACT_MATCH 1
1301 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1303 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1307 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1308 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1309 if(!stricmp(dep->name, vrock->shareName))
1310 matchType = SMB_FINDSHARE_EXACT_MATCH;
1312 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1313 if(vrock->match) free(vrock->match);
1314 vrock->match = strdup(dep->name);
1315 vrock->matchType = matchType;
1317 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1318 return CM_ERROR_STOPNOW;
1324 /* find a shareName in the table of submounts */
1325 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1329 char pathName[1024];
1334 char sbmtpath[MAX_PATH];
1339 DWORD allSubmount = 1;
1341 /* if allSubmounts == 0, only return the //mountRoot/all share
1342 * if in fact it has been been created in the subMounts table.
1343 * This is to allow sites that want to restrict access to the
1346 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1347 0, KEY_QUERY_VALUE, &parmKey);
1348 if (code == ERROR_SUCCESS) {
1349 len = sizeof(allSubmount);
1350 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1351 (BYTE *) &allSubmount, &len);
1352 if (code != ERROR_SUCCESS) {
1355 RegCloseKey (parmKey);
1358 if (allSubmount && _stricmp(shareName, "all") == 0) {
1363 /* In case, the all share is disabled we need to still be able
1364 * to handle ioctl requests
1366 if (_stricmp(shareName, "ioctl$") == 0) {
1367 *pathNamep = strdup("/.__ioctl__");
1371 if (_stricmp(shareName, "IPC$") == 0 ||
1372 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1373 _stricmp(shareName, "DESKTOP.INI") == 0
1380 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1381 0, KEY_QUERY_VALUE, &parmKey);
1382 if (code == ERROR_SUCCESS) {
1383 len = sizeof(pathName);
1384 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1385 (BYTE *) pathName, &len);
1386 if (code != ERROR_SUCCESS)
1388 RegCloseKey (parmKey);
1393 strcpy(sbmtpath, cm_confDir);
1394 strcat(sbmtpath, "/afsdsbmt.ini");
1395 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1396 pathName, sizeof(pathName), sbmtpath);
1398 if (len != 0 && len != sizeof(pathName) - 1) {
1399 /* We can accept either unix or PC style AFS pathnames. Convert
1400 * Unix-style to PC style here for internal use.
1403 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1404 p += strlen(cm_mountRoot); /* skip mount path */
1407 if (*q == '/') *q = '\\'; /* change to \ */
1413 if (var = smb_stristr(p, VNUserName)) {
1414 if (uidp && uidp->unp)
1415 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1417 smb_subst(p, var, sizeof(VNUserName)," ");
1419 else if (var = smb_stristr(p, VNLCUserName))
1421 if (uidp && uidp->unp)
1422 strcpy(temp, uidp->unp->name);
1426 smb_subst(p, var, sizeof(VNLCUserName), temp);
1428 else if (var = smb_stristr(p, VNComputerName))
1430 sizeTemp = sizeof(temp);
1431 GetComputerName((LPTSTR)temp, &sizeTemp);
1432 smb_subst(p, var, sizeof(VNComputerName), temp);
1434 else if (var = smb_stristr(p, VNLCComputerName))
1436 sizeTemp = sizeof(temp);
1437 GetComputerName((LPTSTR)temp, &sizeTemp);
1439 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1444 *pathNamep = strdup(p);
1449 /* First lookup shareName in root.afs */
1451 smb_findShare_rock_t vrock;
1453 char * p = shareName;
1456 /* attempt to locate a partial match in root.afs. This is because
1457 when using the ANSI RAP calls, the share name is limited to 13 chars
1458 and hence is truncated. Of course we prefer exact matches. */
1460 thyper.HighPart = 0;
1463 vrock.shareName = shareName;
1465 vrock.matchType = 0;
1467 cm_HoldSCache(cm_rootSCachep);
1468 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1469 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1470 cm_ReleaseSCache(cm_rootSCachep);
1472 if (vrock.matchType) {
1473 sprintf(pathName,"/%s/",vrock.match);
1474 *pathNamep = strdup(strlwr(pathName));
1479 /* if we get here, there was no match for the share in root.afs */
1480 /* so try to create \\<netbiosName>\<cellname> */
1485 /* Get the full name for this cell */
1486 code = cm_SearchCellFile(p, temp, 0, 0);
1487 #ifdef AFS_AFSDB_ENV
1488 if (code && cm_dnsEnabled) {
1490 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1493 /* construct the path */
1495 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1496 *pathNamep = strdup(strlwr(pathName));
1505 /* Client-side offline caching policy types */
1506 #define CSC_POLICY_MANUAL 0
1507 #define CSC_POLICY_DOCUMENTS 1
1508 #define CSC_POLICY_PROGRAMS 2
1509 #define CSC_POLICY_DISABLE 3
1511 int smb_FindShareCSCPolicy(char *shareName)
1517 int retval = CSC_POLICY_MANUAL;
1519 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1520 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1523 REG_OPTION_NON_VOLATILE,
1529 len = sizeof(policy);
1530 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1532 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1534 else if (stricmp(policy, "documents") == 0)
1536 retval = CSC_POLICY_DOCUMENTS;
1538 else if (stricmp(policy, "programs") == 0)
1540 retval = CSC_POLICY_PROGRAMS;
1542 else if (stricmp(policy, "disable") == 0)
1544 retval = CSC_POLICY_DISABLE;
1547 RegCloseKey(hkCSCPolicy);
1551 /* find a dir search structure by cookie value, and return it held.
1552 * Must be called with smb_globalLock held.
1554 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1556 smb_dirSearch_t *dsp;
1558 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1559 if (dsp->cookie == cookie) {
1560 if (dsp != smb_firstDirSearchp) {
1561 /* move to head of LRU queue, too, if we're not already there */
1562 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1563 smb_lastDirSearchp = (smb_dirSearch_t *)
1565 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1566 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1567 if (!smb_lastDirSearchp)
1568 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1570 lock_ObtainMutex(&dsp->mx);
1572 lock_ReleaseMutex(&dsp->mx);
1579 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1581 lock_ObtainWrite(&smb_globalLock);
1582 lock_ObtainMutex(&dsp->mx);
1583 dsp->flags |= SMB_DIRSEARCH_DELETE;
1584 if (dsp->scp != NULL) {
1585 lock_ObtainMutex(&dsp->scp->mx);
1586 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1587 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1588 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1589 dsp->scp->bulkStatProgress = hones;
1591 lock_ReleaseMutex(&dsp->scp->mx);
1593 lock_ReleaseMutex(&dsp->mx);
1594 lock_ReleaseWrite(&smb_globalLock);
1597 /* Must be called with the smb_globalLock held */
1598 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1604 lock_ObtainMutex(&dsp->mx);
1605 osi_assert(dsp->refCount-- > 0);
1606 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1607 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1608 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1609 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1610 lock_ReleaseMutex(&dsp->mx);
1611 lock_FinalizeMutex(&dsp->mx);
1615 lock_ReleaseMutex(&dsp->mx);
1617 /* do this now to avoid spurious locking hierarchy creation */
1618 if (scp) cm_ReleaseSCache(scp);
1621 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1623 lock_ObtainWrite(&smb_globalLock);
1624 smb_ReleaseDirSearchNoLock(dsp);
1625 lock_ReleaseWrite(&smb_globalLock);
1628 /* find a dir search structure by cookie value, and return it held */
1629 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1631 smb_dirSearch_t *dsp;
1633 lock_ObtainWrite(&smb_globalLock);
1634 dsp = smb_FindDirSearchNoLock(cookie);
1635 lock_ReleaseWrite(&smb_globalLock);
1639 /* GC some dir search entries, in the address space expected by the specific protocol.
1640 * Must be called with smb_globalLock held; release the lock temporarily.
1642 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1643 void smb_GCDirSearches(int isV3)
1645 smb_dirSearch_t *prevp;
1646 smb_dirSearch_t *tp;
1647 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1651 victimCount = 0; /* how many have we got so far */
1652 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1653 /* we'll move tp from queue, so
1656 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1657 /* if no one is using this guy, and we're either in the new protocol,
1658 * or we're in the old one and this is a small enough ID to be useful
1659 * to the old protocol, GC this guy.
1661 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1662 /* hold and delete */
1663 tp->flags |= SMB_DIRSEARCH_DELETE;
1664 victimsp[victimCount++] = tp;
1668 /* don't do more than this */
1669 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1673 /* now release them */
1674 for (i = 0; i < victimCount; i++) {
1675 smb_ReleaseDirSearchNoLock(victimsp[i]);
1679 /* function for allocating a dir search entry. We need these to remember enough context
1680 * since we don't get passed the path from call to call during a directory search.
1682 * Returns a held dir search structure, and bumps the reference count on the vnode,
1683 * since it saves a pointer to the vnode.
1685 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1687 smb_dirSearch_t *dsp;
1691 lock_ObtainWrite(&smb_globalLock);
1694 /* what's the biggest ID allowed in this version of the protocol */
1695 maxAllowed = isV3 ? 65535 : 255;
1698 /* twice so we have enough tries to find guys we GC after one pass;
1699 * 10 extra is just in case I mis-counted.
1701 if (++counter > 2*maxAllowed+10)
1702 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1704 if (smb_dirSearchCounter > maxAllowed) {
1705 smb_dirSearchCounter = 1;
1706 smb_GCDirSearches(isV3); /* GC some */
1708 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1710 /* don't need to watch for refcount zero and deleted, since
1711 * we haven't dropped the global lock.
1713 lock_ObtainMutex(&dsp->mx);
1715 lock_ReleaseMutex(&dsp->mx);
1716 ++smb_dirSearchCounter;
1720 dsp = malloc(sizeof(*dsp));
1721 memset(dsp, 0, sizeof(*dsp));
1722 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1723 if (!smb_lastDirSearchp)
1724 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1725 dsp->cookie = smb_dirSearchCounter;
1726 ++smb_dirSearchCounter;
1728 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1729 dsp->lastTime = osi_Time();
1732 lock_ReleaseWrite(&smb_globalLock);
1736 static smb_packet_t *GetPacket(void)
1740 unsigned int npar, seg, tb_sel;
1743 lock_ObtainWrite(&smb_globalLock);
1744 tbp = smb_packetFreeListp;
1746 smb_packetFreeListp = tbp->nextp;
1747 lock_ReleaseWrite(&smb_globalLock);
1750 tbp = calloc(65540,1);
1752 tbp = malloc(sizeof(smb_packet_t));
1754 tbp->magic = SMB_PACKETMAGIC;
1757 tbp->resumeCode = 0;
1763 tbp->ncb_length = 0;
1768 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1771 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1773 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1775 osi_panic("",__FILE__,__LINE__);
1778 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1783 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1784 tbp->dos_pkt_sel = tb_sel;
1787 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1792 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1796 memcpy(tbp, pkt, sizeof(smb_packet_t));
1797 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1801 static NCB *GetNCB(void)
1806 unsigned int npar, seg, tb_sel;
1809 lock_ObtainWrite(&smb_globalLock);
1810 tbp = smb_ncbFreeListp;
1812 smb_ncbFreeListp = tbp->nextp;
1813 lock_ReleaseWrite(&smb_globalLock);
1816 tbp = calloc(sizeof(*tbp),1);
1818 tbp = malloc(sizeof(*tbp));
1819 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1822 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1824 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1826 osi_panic("",__FILE__,__LINE__);
1828 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1833 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1834 tbp->dos_ncb_sel = tb_sel;
1836 tbp->magic = SMB_NCBMAGIC;
1839 osi_assert(tbp->magic == SMB_NCBMAGIC);
1841 memset(&tbp->ncb, 0, sizeof(NCB));
1844 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1849 void smb_FreePacket(smb_packet_t *tbp)
1851 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1853 lock_ObtainWrite(&smb_globalLock);
1854 tbp->nextp = smb_packetFreeListp;
1855 smb_packetFreeListp = tbp;
1856 tbp->magic = SMB_PACKETMAGIC;
1859 tbp->resumeCode = 0;
1865 tbp->ncb_length = 0;
1867 lock_ReleaseWrite(&smb_globalLock);
1870 static void FreeNCB(NCB *bufferp)
1874 tbp = (smb_ncb_t *) bufferp;
1875 osi_assert(tbp->magic == SMB_NCBMAGIC);
1877 lock_ObtainWrite(&smb_globalLock);
1878 tbp->nextp = smb_ncbFreeListp;
1879 smb_ncbFreeListp = tbp;
1880 lock_ReleaseWrite(&smb_globalLock);
1883 /* get a ptr to the data part of a packet, and its count */
1884 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1888 unsigned char *afterParmsp;
1890 parmBytes = *smbp->wctp << 1;
1891 afterParmsp = smbp->wctp + parmBytes + 1;
1893 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1894 if (nbytesp) *nbytesp = dataBytes;
1896 /* don't forget to skip the data byte count, since it follows
1897 * the parameters; that's where the "2" comes from below.
1899 return (unsigned char *) (afterParmsp + 2);
1902 /* must set all the returned parameters before playing around with the
1903 * data region, since the data region is located past the end of the
1904 * variable number of parameters.
1906 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1908 unsigned char *afterParmsp;
1910 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1912 *afterParmsp++ = dsize & 0xff;
1913 *afterParmsp = (dsize>>8) & 0xff;
1916 /* return the parm'th parameter in the smbp packet */
1917 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1920 unsigned char *parmDatap;
1922 parmCount = *smbp->wctp;
1924 if (parm >= parmCount) {
1929 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1931 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1932 parm, parmCount, smbp->ncb_length);
1935 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1936 1, smbp->ncb_length, ptbuf, smbp);
1937 DeregisterEventSource(h);
1939 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1940 osi_panic(s, __FILE__, __LINE__);
1942 parmDatap = smbp->wctp + (2*parm) + 1;
1944 return parmDatap[0] + (parmDatap[1] << 8);
1947 /* return the parm'th parameter in the smbp packet */
1948 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1951 unsigned char *parmDatap;
1953 parmCount = *smbp->wctp;
1955 if (parm * 2 + offset >= parmCount * 2) {
1960 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1962 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1963 parm, offset, parmCount, smbp->ncb_length);
1966 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1967 1, smbp->ncb_length, ptbuf, smbp);
1968 DeregisterEventSource(h);
1970 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1971 osi_panic(s, __FILE__, __LINE__);
1973 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1975 return parmDatap[0] + (parmDatap[1] << 8);
1978 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1982 /* make sure we have enough slots */
1983 if (*smbp->wctp <= slot)
1984 *smbp->wctp = slot+1;
1986 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1987 *parmDatap++ = parmValue & 0xff;
1988 *parmDatap = (parmValue>>8) & 0xff;
1991 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1995 /* make sure we have enough slots */
1996 if (*smbp->wctp <= slot)
1997 *smbp->wctp = slot+2;
1999 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2000 *parmDatap++ = parmValue & 0xff;
2001 *parmDatap++ = (parmValue>>8) & 0xff;
2002 *parmDatap++ = (parmValue>>16) & 0xff;
2003 *parmDatap++ = (parmValue>>24) & 0xff;
2006 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2011 /* make sure we have enough slots */
2012 if (*smbp->wctp <= slot)
2013 *smbp->wctp = slot+4;
2015 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2017 *parmDatap++ = *parmValuep++;
2020 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2024 /* make sure we have enough slots */
2025 if (*smbp->wctp <= slot) {
2026 if (smbp->oddByte) {
2028 *smbp->wctp = slot+1;
2033 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2034 *parmDatap++ = parmValue & 0xff;
2037 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2041 lastSlashp = strrchr(inPathp, '\\');
2043 *lastComponentp = lastSlashp;
2046 if (inPathp == lastSlashp)
2048 *outPathp++ = *inPathp++;
2057 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2062 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2067 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2073 tlen = inp[0] + (inp[1]<<8);
2074 inp += 2; /* skip length field */
2077 *chainpp = inp + tlen;
2086 /* format a packet as a response */
2087 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2092 outp = (smb_t *) op;
2094 /* zero the basic structure through the smb_wct field, and zero the data
2095 * size field, assuming that wct stays zero; otherwise, you have to
2096 * explicitly set the data size field, too.
2098 inSmbp = (smb_t *) inp;
2099 memset(outp, 0, sizeof(smb_t)+2);
2105 outp->com = inSmbp->com;
2106 outp->tid = inSmbp->tid;
2107 outp->pid = inSmbp->pid;
2108 outp->uid = inSmbp->uid;
2109 outp->mid = inSmbp->mid;
2110 outp->res[0] = inSmbp->res[0];
2111 outp->res[1] = inSmbp->res[1];
2112 op->inCom = inSmbp->com;
2114 outp->reb = 0x80; /* SERVER_RESP */
2115 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2117 /* copy fields in generic packet area */
2118 op->wctp = &outp->wct;
2121 /* send a (probably response) packet; vcp tells us to whom to send it.
2122 * we compute the length by looking at wct and bcc fields.
2124 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2141 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2144 memset((char *)ncbp, 0, sizeof(NCB));
2146 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2147 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2148 extra += tp[0] + (tp[1]<<8);
2149 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2150 extra += 3; /* wct and length fields */
2152 ncbp->ncb_length = extra; /* bytes to send */
2153 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2154 ncbp->ncb_lana_num = vcp->lana;
2155 ncbp->ncb_command = NCBSEND; /* op means send data */
2157 ncbp->ncb_buffer = (char *) inp;/* packet */
2158 code = Netbios(ncbp);
2160 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2161 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2163 /* copy header information from virtual to DOS address space */
2164 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2165 code = Netbios(ncbp, dos_ncb);
2169 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2175 void smb_MapNTError(long code, unsigned long *NTStatusp)
2177 unsigned long NTStatus;
2179 /* map CM_ERROR_* errors to NT 32-bit status codes */
2180 /* NT Status codes are listed in ntstatus.h not winerror.h */
2181 if (code == CM_ERROR_NOSUCHCELL) {
2182 NTStatus = 0xC000000FL; /* No such file */
2184 else if (code == CM_ERROR_NOSUCHVOLUME) {
2185 NTStatus = 0xC000000FL; /* No such file */
2187 else if (code == CM_ERROR_TIMEDOUT) {
2188 NTStatus = 0xC00000CFL; /* Sharing Paused */
2190 else if (code == CM_ERROR_RETRY) {
2191 NTStatus = 0xC000022DL; /* Retry */
2193 else if (code == CM_ERROR_NOACCESS) {
2194 NTStatus = 0xC0000022L; /* Access denied */
2196 else if (code == CM_ERROR_READONLY) {
2197 NTStatus = 0xC00000A2L; /* Write protected */
2199 else if (code == CM_ERROR_NOSUCHFILE) {
2200 NTStatus = 0xC000000FL; /* No such file */
2202 else if (code == CM_ERROR_NOSUCHPATH) {
2203 NTStatus = 0xC000003AL; /* Object path not found */
2205 else if (code == CM_ERROR_TOOBIG) {
2206 NTStatus = 0xC000007BL; /* Invalid image format */
2208 else if (code == CM_ERROR_INVAL) {
2209 NTStatus = 0xC000000DL; /* Invalid parameter */
2211 else if (code == CM_ERROR_BADFD) {
2212 NTStatus = 0xC0000008L; /* Invalid handle */
2214 else if (code == CM_ERROR_BADFDOP) {
2215 NTStatus = 0xC0000022L; /* Access denied */
2217 else if (code == CM_ERROR_EXISTS) {
2218 NTStatus = 0xC0000035L; /* Object name collision */
2220 else if (code == CM_ERROR_NOTEMPTY) {
2221 NTStatus = 0xC0000101L; /* Directory not empty */
2223 else if (code == CM_ERROR_CROSSDEVLINK) {
2224 NTStatus = 0xC00000D4L; /* Not same device */
2226 else if (code == CM_ERROR_NOTDIR) {
2227 NTStatus = 0xC0000103L; /* Not a directory */
2229 else if (code == CM_ERROR_ISDIR) {
2230 NTStatus = 0xC00000BAL; /* File is a directory */
2232 else if (code == CM_ERROR_BADOP) {
2234 /* I have no idea where this comes from */
2235 NTStatus = 0xC09820FFL; /* SMB no support */
2237 NTStatus = 0xC00000BBL; /* Not supported */
2238 #endif /* COMMENT */
2240 else if (code == CM_ERROR_BADSHARENAME) {
2241 NTStatus = 0xC00000CCL; /* Bad network name */
2243 else if (code == CM_ERROR_NOIPC) {
2245 NTStatus = 0xC0000022L; /* Access Denied */
2247 NTStatus = 0xC000013DL; /* Remote Resources */
2250 else if (code == CM_ERROR_CLOCKSKEW) {
2251 NTStatus = 0xC0000133L; /* Time difference at DC */
2253 else if (code == CM_ERROR_BADTID) {
2254 NTStatus = 0xC0982005L; /* SMB bad TID */
2256 else if (code == CM_ERROR_USESTD) {
2257 NTStatus = 0xC09820FBL; /* SMB use standard */
2259 else if (code == CM_ERROR_QUOTA) {
2261 NTStatus = 0xC0000044L; /* Quota exceeded */
2263 NTStatus = 0xC000007FL; /* Disk full */
2266 else if (code == CM_ERROR_SPACE) {
2267 NTStatus = 0xC000007FL; /* Disk full */
2269 else if (code == CM_ERROR_ATSYS) {
2270 NTStatus = 0xC0000033L; /* Object name invalid */
2272 else if (code == CM_ERROR_BADNTFILENAME) {
2273 NTStatus = 0xC0000033L; /* Object name invalid */
2275 else if (code == CM_ERROR_WOULDBLOCK) {
2276 NTStatus = 0xC0000055L; /* Lock not granted */
2278 else if (code == CM_ERROR_PARTIALWRITE) {
2279 NTStatus = 0xC000007FL; /* Disk full */
2281 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2282 NTStatus = 0xC0000023L; /* Buffer too small */
2284 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2285 NTStatus = 0xC0000035L; /* Object name collision */
2287 else if (code == CM_ERROR_BADPASSWORD) {
2288 NTStatus = 0xC000006DL; /* unknown username or bad password */
2290 else if (code == CM_ERROR_BADLOGONTYPE) {
2291 NTStatus = 0xC000015BL; /* logon type not granted */
2293 else if (code == CM_ERROR_GSSCONTINUE) {
2294 NTStatus = 0xC0000016L; /* more processing required */
2296 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2298 NTStatus = 0xC0000280L; /* reparse point not resolved */
2300 NTStatus = 0xC0000022L; /* Access Denied */
2304 NTStatus = 0xC0982001L; /* SMB non-specific error */
2307 *NTStatusp = NTStatus;
2308 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2311 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2312 unsigned char *classp)
2314 unsigned char class;
2315 unsigned short error;
2317 /* map CM_ERROR_* errors to SMB errors */
2318 if (code == CM_ERROR_NOSUCHCELL) {
2320 error = 3; /* bad path */
2322 else if (code == CM_ERROR_NOSUCHVOLUME) {
2324 error = 3; /* bad path */
2326 else if (code == CM_ERROR_TIMEDOUT) {
2328 error = 81; /* server is paused */
2330 else if (code == CM_ERROR_RETRY) {
2331 class = 2; /* shouldn't happen */
2334 else if (code == CM_ERROR_NOACCESS) {
2336 error = 4; /* bad access */
2338 else if (code == CM_ERROR_READONLY) {
2340 error = 19; /* read only */
2342 else if (code == CM_ERROR_NOSUCHFILE) {
2344 error = 2; /* ENOENT! */
2346 else if (code == CM_ERROR_NOSUCHPATH) {
2348 error = 3; /* Bad path */
2350 else if (code == CM_ERROR_TOOBIG) {
2352 error = 11; /* bad format */
2354 else if (code == CM_ERROR_INVAL) {
2355 class = 2; /* server non-specific error code */
2358 else if (code == CM_ERROR_BADFD) {
2360 error = 6; /* invalid file handle */
2362 else if (code == CM_ERROR_BADFDOP) {
2363 class = 1; /* invalid op on FD */
2366 else if (code == CM_ERROR_EXISTS) {
2368 error = 80; /* file already exists */
2370 else if (code == CM_ERROR_NOTEMPTY) {
2372 error = 5; /* delete directory not empty */
2374 else if (code == CM_ERROR_CROSSDEVLINK) {
2376 error = 17; /* EXDEV */
2378 else if (code == CM_ERROR_NOTDIR) {
2379 class = 1; /* bad path */
2382 else if (code == CM_ERROR_ISDIR) {
2383 class = 1; /* access denied; DOS doesn't have a good match */
2386 else if (code == CM_ERROR_BADOP) {
2390 else if (code == CM_ERROR_BADSHARENAME) {
2394 else if (code == CM_ERROR_NOIPC) {
2396 error = 4; /* bad access */
2398 else if (code == CM_ERROR_CLOCKSKEW) {
2399 class = 1; /* invalid function */
2402 else if (code == CM_ERROR_BADTID) {
2406 else if (code == CM_ERROR_USESTD) {
2410 else if (code == CM_ERROR_REMOTECONN) {
2414 else if (code == CM_ERROR_QUOTA) {
2415 if (vcp->flags & SMB_VCFLAG_USEV3) {
2417 error = 39; /* disk full */
2421 error = 5; /* access denied */
2424 else if (code == CM_ERROR_SPACE) {
2425 if (vcp->flags & SMB_VCFLAG_USEV3) {
2427 error = 39; /* disk full */
2431 error = 5; /* access denied */
2434 else if (code == CM_ERROR_PARTIALWRITE) {
2436 error = 39; /* disk full */
2438 else if (code == CM_ERROR_ATSYS) {
2440 error = 2; /* ENOENT */
2442 else if (code == CM_ERROR_WOULDBLOCK) {
2444 error = 33; /* lock conflict */
2446 else if (code == CM_ERROR_NOFILES) {
2448 error = 18; /* no files in search */
2450 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2452 error = 183; /* Samba uses this */
2454 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2455 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2457 error = 2; /* bad password */
2466 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2469 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2471 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2472 return CM_ERROR_BADOP;
2475 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2477 unsigned short EchoCount, i;
2478 char *data, *outdata;
2481 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2483 for (i=1; i<=EchoCount; i++) {
2484 data = smb_GetSMBData(inp, &dataSize);
2485 smb_SetSMBParm(outp, 0, i);
2486 smb_SetSMBDataLength(outp, dataSize);
2487 outdata = smb_GetSMBData(outp, NULL);
2488 memcpy(outdata, data, dataSize);
2489 smb_SendPacket(vcp, outp);
2495 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2498 long count, minCount, finalCount;
2502 cm_user_t *userp = NULL;
2506 char *rawBuf = NULL;
2508 dos_ptr rawBuf = NULL;
2515 fd = smb_GetSMBParm(inp, 0);
2516 count = smb_GetSMBParm(inp, 3);
2517 minCount = smb_GetSMBParm(inp, 4);
2518 offset.HighPart = 0; /* too bad */
2519 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2521 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2522 fd, offset.LowPart, count);
2524 fidp = smb_FindFID(vcp, fd, 0);
2528 lock_ObtainMutex(&smb_RawBufLock);
2530 /* Get a raw buf, from head of list */
2531 rawBuf = smb_RawBufs;
2533 smb_RawBufs = *(char **)smb_RawBufs;
2535 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2538 lock_ReleaseMutex(&smb_RawBufLock);
2542 if (fidp->flags & SMB_FID_IOCTL)
2545 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2547 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2550 /* Give back raw buffer */
2551 lock_ObtainMutex(&smb_RawBufLock);
2553 *((char **) rawBuf) = smb_RawBufs;
2555 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2558 smb_RawBufs = rawBuf;
2559 lock_ReleaseMutex(&smb_RawBufLock);
2562 smb_ReleaseFID(fidp);
2566 userp = smb_GetUser(vcp, inp);
2569 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2571 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2572 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2573 userp, &finalCount, TRUE /* rawFlag */);
2580 cm_ReleaseUser(userp);
2583 smb_ReleaseFID(fidp);
2588 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2590 memset((char *)ncbp, 0, sizeof(NCB));
2592 ncbp->ncb_length = (unsigned short) finalCount;
2593 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2594 ncbp->ncb_lana_num = vcp->lana;
2595 ncbp->ncb_command = NCBSEND;
2596 ncbp->ncb_buffer = rawBuf;
2599 code = Netbios(ncbp);
2601 code = Netbios(ncbp, dos_ncb);
2604 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2607 /* Give back raw buffer */
2608 lock_ObtainMutex(&smb_RawBufLock);
2610 *((char **) rawBuf) = smb_RawBufs;
2612 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2615 smb_RawBufs = rawBuf;
2616 lock_ReleaseMutex(&smb_RawBufLock);
2622 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2624 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2629 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2631 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2636 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2643 int protoIndex; /* index we're using */
2648 char protocol_array[10][1024]; /* protocol signature of the client */
2649 int caps; /* capabilities */
2652 TIME_ZONE_INFORMATION tzi;
2654 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2658 DWORD now = GetCurrentTime();
2659 if (now - last_msg_time >= 30000
2660 && now - last_msg_time <= 90000) {
2662 "Setting dead_vcp %x", active_vcp);
2664 smb_ReleaseVC(dead_vcp);
2666 "Previous dead_vcp %x", dead_vcp);
2668 smb_HoldVC(active_vcp);
2669 dead_vcp = active_vcp;
2670 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2675 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2677 namep = smb_GetSMBData(inp, &dbytes);
2680 coreProtoIndex = -1; /* not found */
2683 while(namex < dbytes) {
2684 osi_Log1(smb_logp, "Protocol %s",
2685 osi_LogSaveString(smb_logp, namep+1));
2686 strcpy(protocol_array[tcounter], namep+1);
2688 /* namep points at the first protocol, or really, a 0x02
2689 * byte preceding the null-terminated ASCII name.
2691 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2692 coreProtoIndex = tcounter;
2694 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2695 v3ProtoIndex = tcounter;
2697 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2698 NTProtoIndex = tcounter;
2701 /* compute size of protocol entry */
2702 entryLength = strlen(namep+1);
2703 entryLength += 2; /* 0x02 bytes and null termination */
2705 /* advance over this protocol entry */
2706 namex += entryLength;
2707 namep += entryLength;
2708 tcounter++; /* which proto entry we're looking at */
2711 if (NTProtoIndex != -1) {
2712 protoIndex = NTProtoIndex;
2713 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2715 else if (v3ProtoIndex != -1) {
2716 protoIndex = v3ProtoIndex;
2717 vcp->flags |= SMB_VCFLAG_USEV3;
2719 else if (coreProtoIndex != -1) {
2720 protoIndex = coreProtoIndex;
2721 vcp->flags |= SMB_VCFLAG_USECORE;
2723 else protoIndex = -1;
2725 if (protoIndex == -1)
2726 return CM_ERROR_INVAL;
2727 else if (NTProtoIndex != -1) {
2728 smb_SetSMBParm(outp, 0, protoIndex);
2729 if (smb_authType != SMB_AUTH_NONE) {
2730 smb_SetSMBParmByte(outp, 1,
2731 NEGOTIATE_SECURITY_USER_LEVEL |
2732 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2734 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2736 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2737 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2738 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2739 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2740 /* The session key is not a well documented field however most clients
2741 * will echo back the session key to the server. Currently we are using
2742 * the same value for all sessions. We should generate a random value
2743 * and store it into the vcp
2745 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2746 smb_SetSMBParm(outp, 8, 1);
2748 * Tried changing the capabilities to support for W2K - defect 117695
2749 * Maybe something else needs to be changed here?
2753 smb_SetSMBParmLong(outp, 9, 0x43fd);
2755 smb_SetSMBParmLong(outp, 9, 0x251);
2758 * 32-bit error codes *
2762 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2763 NTNEGOTIATE_CAPABILITY_NTFIND |
2764 NTNEGOTIATE_CAPABILITY_RAWMODE |
2765 NTNEGOTIATE_CAPABILITY_NTSMB;
2767 if ( smb_authType == SMB_AUTH_EXTENDED )
2768 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2770 smb_SetSMBParmLong(outp, 9, caps);
2772 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2773 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2774 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2776 GetTimeZoneInformation(&tzi);
2777 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2779 if (smb_authType == SMB_AUTH_NTLM) {
2780 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2781 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2782 /* paste in encryption key */
2783 datap = smb_GetSMBData(outp, NULL);
2784 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2785 /* and the faux domain name */
2786 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2787 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2791 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2793 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2795 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2797 datap = smb_GetSMBData(outp, NULL);
2798 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2801 datap += sizeof(smb_ServerGUID);
2802 memcpy(datap, secBlob, secBlobLength);
2806 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2807 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2810 else if (v3ProtoIndex != -1) {
2811 smb_SetSMBParm(outp, 0, protoIndex);
2813 /* NOTE: Extended authentication cannot be negotiated with v3
2814 * therefore we fail over to NTLM
2816 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2817 smb_SetSMBParm(outp, 1,
2818 NEGOTIATE_SECURITY_USER_LEVEL |
2819 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2821 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2823 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2824 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2825 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2826 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2827 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2828 smb_SetSMBParm(outp, 7, 1);
2830 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2831 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2832 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2834 GetTimeZoneInformation(&tzi);
2835 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2837 /* NOTE: Extended authentication cannot be negotiated with v3
2838 * therefore we fail over to NTLM
2840 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2841 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2842 smb_SetSMBParm(outp, 12, 0); /* resvd */
2843 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2844 datap = smb_GetSMBData(outp, NULL);
2845 /* paste in a new encryption key */
2846 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2847 /* and the faux domain name */
2848 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2850 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2851 smb_SetSMBParm(outp, 12, 0); /* resvd */
2852 smb_SetSMBDataLength(outp, 0);
2855 else if (coreProtoIndex != -1) { /* not really supported anymore */
2856 smb_SetSMBParm(outp, 0, protoIndex);
2857 smb_SetSMBDataLength(outp, 0);
2862 void smb_Daemon(void *parmp)
2864 afs_uint32 count = 0;
2866 while(smbShutdownFlag == 0) {
2870 if (smbShutdownFlag == 1)
2873 if ((count % 72) == 0) { /* every five minutes */
2875 time_t old_localZero = smb_localZero;
2877 /* Initialize smb_localZero */
2878 myTime.tm_isdst = -1; /* compute whether on DST or not */
2879 myTime.tm_year = 70;
2885 smb_localZero = mktime(&myTime);
2887 smb_CalculateNowTZ();
2889 #ifdef AFS_FREELANCE
2890 if ( smb_localZero != old_localZero )
2891 cm_noteLocalMountPointChange();
2894 /* XXX GC dir search entries */
2898 void smb_WaitingLocksDaemon()
2900 smb_waitingLock_t *wL, *nwL;
2903 smb_packet_t *inp, *outp;
2908 lock_ObtainWrite(&smb_globalLock);
2909 nwL = smb_allWaitingLocks;
2911 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2920 lock_ObtainWrite(&smb_globalLock);
2922 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2923 lock_ReleaseWrite(&smb_globalLock);
2924 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2925 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2926 if (code == CM_ERROR_WOULDBLOCK) {
2928 if (wL->timeRemaining != 0xffffffff
2929 && (wL->timeRemaining -= 1000) < 0)
2938 ncbp->ncb_length = inp->ncb_length;
2939 inp->spacep = cm_GetSpace();
2941 /* Remove waitingLock from list */
2942 lock_ObtainWrite(&smb_globalLock);
2943 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2945 lock_ReleaseWrite(&smb_globalLock);
2947 /* Resume packet processing */
2949 smb_SetSMBDataLength(outp, 0);
2950 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2951 outp->resumeCode = code;
2953 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2956 cm_FreeSpace(inp->spacep);
2957 smb_FreePacket(inp);
2958 smb_FreePacket(outp);
2966 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2968 osi_Log0(smb_logp, "SMB receive get disk attributes");
2970 smb_SetSMBParm(outp, 0, 32000);
2971 smb_SetSMBParm(outp, 1, 64);
2972 smb_SetSMBParm(outp, 2, 1024);
2973 smb_SetSMBParm(outp, 3, 30000);
2974 smb_SetSMBParm(outp, 4, 0);
2975 smb_SetSMBDataLength(outp, 0);
2979 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2983 unsigned short newTid;
2984 char shareName[256];
2992 osi_Log0(smb_logp, "SMB receive tree connect");
2994 /* parse input parameters */
2995 tp = smb_GetSMBData(inp, NULL);
2996 pathp = smb_ParseASCIIBlock(tp, &tp);
2997 passwordp = smb_ParseASCIIBlock(tp, &tp);
2998 tp = strrchr(pathp, '\\');
3000 return CM_ERROR_BADSMB;
3001 strcpy(shareName, tp+1);
3003 userp = smb_GetUser(vcp, inp);
3005 lock_ObtainMutex(&vcp->mx);
3006 newTid = vcp->tidCounter++;
3007 lock_ReleaseMutex(&vcp->mx);
3009 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3010 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3011 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3013 smb_ReleaseUID(uidp);
3015 smb_ReleaseTID(tidp);
3016 return CM_ERROR_BADSHARENAME;
3018 lock_ObtainMutex(&tidp->mx);
3019 tidp->userp = userp;
3020 tidp->pathname = sharePath;
3021 lock_ReleaseMutex(&tidp->mx);
3022 smb_ReleaseTID(tidp);
3024 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3025 smb_SetSMBParm(rsp, 1, newTid);
3026 smb_SetSMBDataLength(rsp, 0);
3028 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3032 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3036 if (*inp++ != 0x1) return NULL;
3037 tlen = inp[0] + (inp[1]<<8);
3038 inp += 2; /* skip length field */
3041 *chainpp = inp + tlen;
3044 if (lengthp) *lengthp = tlen;
3049 /* set maskp to the mask part of the incoming path.
3050 * Mask is 11 bytes long (8.3 with the dot elided).
3051 * Returns true if succeeds with a valid name, otherwise it does
3052 * its best, but returns false.
3054 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3062 /* starts off valid */
3065 /* mask starts out all blanks */
3066 memset(maskp, ' ', 11);
3068 /* find last backslash, or use whole thing if there is none */
3069 tp = strrchr(pathp, '\\');
3070 if (!tp) tp = pathp;
3071 else tp++; /* skip slash */
3075 /* names starting with a dot are illegal */
3076 if (*tp == '.') valid8Dot3 = 0;
3080 if (tc == 0) return valid8Dot3;
3081 if (tc == '.' || tc == '"') break;
3082 if (i < 8) *up++ = tc;
3083 else valid8Dot3 = 0;
3086 /* if we get here, tp point after the dot */
3087 up = maskp+8; /* ext goes here */
3094 if (tc == '.' || tc == '"')
3097 /* copy extension if not too long */
3107 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3117 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3119 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3123 /* otherwise, we have a valid 8.3 name; see if we have a match,
3124 * treating '?' as a wildcard in maskp (but not in the file name).
3126 tp1 = umask; /* real name, in mask format */
3127 tp2 = maskp; /* mask, in mask format */
3128 for(i=0; i<11; i++) {
3129 tc1 = *tp1++; /* char from real name */
3130 tc2 = *tp2++; /* char from mask */
3131 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3132 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3135 if (tc2 == '?' && tc1 != ' ')
3142 /* we got a match */
3146 char *smb_FindMask(char *pathp)
3150 tp = strrchr(pathp, '\\'); /* find last slash */
3153 return tp+1; /* skip the slash */
3155 return pathp; /* no slash, return the entire path */
3158 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3160 unsigned char *pathp;
3162 unsigned char mask[11];
3163 unsigned char *statBlockp;
3164 unsigned char initStatBlock[21];
3167 osi_Log0(smb_logp, "SMB receive search volume");
3169 /* pull pathname and stat block out of request */
3170 tp = smb_GetSMBData(inp, NULL);
3171 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3172 osi_assert(pathp != NULL);
3173 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3174 osi_assert(statBlockp != NULL);
3176 statBlockp = initStatBlock;
3180 /* for returning to caller */
3181 smb_Get8Dot3MaskFromPath(mask, pathp);
3183 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3184 tp = smb_GetSMBData(outp, NULL);
3186 *tp++ = 43; /* bytes in a dir entry */
3187 *tp++ = 0; /* high byte in counter */
3189 /* now marshall the dir entry, starting with the search status */
3190 *tp++ = statBlockp[0]; /* Reserved */
3191 memcpy(tp, mask, 11); tp += 11; /* FileName */
3193 /* now pass back server use info, with 1st byte non-zero */
3195 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3197 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3199 *tp++ = 0x8; /* attribute: volume */
3209 /* 4 byte file size */
3215 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3216 memset(tp, ' ', 13);
3219 /* set the length of the data part of the packet to 43 + 3, for the dir
3220 * entry plus the 5 and the length fields.
3222 smb_SetSMBDataLength(outp, 46);
3226 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3227 cm_user_t *userp, cm_req_t *reqp)
3235 smb_dirListPatch_t *patchp;
3236 smb_dirListPatch_t *npatchp;
3238 for (patchp = *dirPatchespp; patchp; patchp =
3239 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3241 dptr = patchp->dptr;
3243 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3245 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3246 *dptr++ = SMB_ATTR_HIDDEN;
3249 lock_ObtainMutex(&scp->mx);
3250 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3251 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3253 lock_ReleaseMutex(&scp->mx);
3254 cm_ReleaseSCache(scp);
3255 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3256 *dptr++ = SMB_ATTR_HIDDEN;
3260 attr = smb_Attributes(scp);
3261 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3262 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3263 attr |= SMB_ATTR_HIDDEN;
3267 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3270 shortTemp = (unsigned short) (dosTime & 0xffff);
3271 *((u_short *)dptr) = shortTemp;
3274 /* and copy out date */
3275 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3276 *((u_short *)dptr) = shortTemp;
3279 /* copy out file length */
3280 *((u_long *)dptr) = scp->length.LowPart;
3282 lock_ReleaseMutex(&scp->mx);
3283 cm_ReleaseSCache(scp);
3286 /* now free the patches */
3287 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3288 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3292 /* and mark the list as empty */
3293 *dirPatchespp = NULL;
3298 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3307 smb_dirListPatch_t *dirListPatchesp;
3308 smb_dirListPatch_t *curPatchp;
3312 osi_hyper_t dirLength;
3313 osi_hyper_t bufferOffset;
3314 osi_hyper_t curOffset;
3316 unsigned char *inCookiep;
3317 smb_dirSearch_t *dsp;
3321 unsigned long clientCookie;
3322 cm_pageHeader_t *pageHeaderp;
3323 cm_user_t *userp = NULL;
3330 long nextEntryCookie;
3331 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3332 char resByte; /* reserved byte from the cookie */
3333 char *op; /* output data ptr */
3334 char *origOp; /* original value of op */
3335 cm_space_t *spacep; /* for pathname buffer */
3346 maxCount = smb_GetSMBParm(inp, 0);
3348 dirListPatchesp = NULL;
3350 caseFold = CM_FLAG_CASEFOLD;
3352 tp = smb_GetSMBData(inp, NULL);
3353 pathp = smb_ParseASCIIBlock(tp, &tp);
3354 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3356 /* bail out if request looks bad */
3357 if (!tp || !pathp) {
3358 return CM_ERROR_BADSMB;
3361 /* We can handle long names */
3362 if (vcp->flags & SMB_VCFLAG_USENT)
3363 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3365 /* make sure we got a whole search status */
3366 if (dataLength < 21) {
3367 nextCookie = 0; /* start at the beginning of the dir */
3370 attribute = smb_GetSMBParm(inp, 1);
3372 /* handle volume info in another function */
3373 if (attribute & 0x8)
3374 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3376 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3377 maxCount, osi_LogSaveString(smb_logp, pathp));
3379 if (*pathp == 0) { /* null pathp, treat as root dir */
3380 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3381 return CM_ERROR_NOFILES;
3385 dsp = smb_NewDirSearch(0);
3386 dsp->attribute = attribute;
3387 smb_Get8Dot3MaskFromPath(mask, pathp);
3388 memcpy(dsp->mask, mask, 11);
3390 /* track if this is likely to match a lot of entries */
3391 if (smb_IsStarMask(mask)) starPattern = 1;
3392 else starPattern = 0;
3395 /* pull the next cookie value out of the search status block */
3396 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3397 + (inCookiep[16]<<24);
3398 dsp = smb_FindDirSearch(inCookiep[12]);
3400 /* can't find dir search status; fatal error */
3401 return CM_ERROR_BADFD;
3403 attribute = dsp->attribute;
3404 resByte = inCookiep[0];
3406 /* copy out client cookie, in host byte order. Don't bother
3407 * interpreting it, since we're just passing it through, anyway.
3409 memcpy(&clientCookie, &inCookiep[17], 4);
3411 memcpy(mask, dsp->mask, 11);
3413 /* assume we're doing a star match if it has continued for more
3419 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3420 nextCookie, dsp->cookie, attribute);
3422 userp = smb_GetUser(vcp, inp);
3424 /* try to get the vnode for the path name next */
3425 lock_ObtainMutex(&dsp->mx);
3432 spacep = inp->spacep;
3433 smb_StripLastComponent(spacep->data, NULL, pathp);
3434 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3436 lock_ReleaseMutex(&dsp->mx);
3437 cm_ReleaseUser(userp);
3438 smb_DeleteDirSearch(dsp);
3439 smb_ReleaseDirSearch(dsp);
3440 return CM_ERROR_NOFILES;
3442 code = cm_NameI(cm_rootSCachep, spacep->data,
3443 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3446 cm_ReleaseSCache(dsp->scp);
3448 /* we need one hold for the entry we just stored into,
3449 * and one for our own processing. When we're done with this
3450 * function, we'll drop the one for our own processing.
3451 * We held it once from the namei call, and so we do another hold
3455 lock_ObtainMutex(&scp->mx);
3456 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3457 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3458 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3459 dsp->flags |= SMB_DIRSEARCH_BULKST;
3461 lock_ReleaseMutex(&scp->mx);
3464 lock_ReleaseMutex(&dsp->mx);
3466 cm_ReleaseUser(userp);
3467 smb_DeleteDirSearch(dsp);
3468 smb_ReleaseDirSearch(dsp);
3472 /* reserves space for parameter; we'll adjust it again later to the
3473 * real count of the # of entries we returned once we've actually
3474 * assembled the directory listing.
3476 smb_SetSMBParm(outp, 0, 0);
3478 /* get the directory size */
3479 lock_ObtainMutex(&scp->mx);
3480 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3481 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3483 lock_ReleaseMutex(&scp->mx);
3484 cm_ReleaseSCache(scp);
3485 cm_ReleaseUser(userp);
3486 smb_DeleteDirSearch(dsp);
3487 smb_ReleaseDirSearch(dsp);
3491 dirLength = scp->length;
3493 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3494 curOffset.HighPart = 0;
3495 curOffset.LowPart = nextCookie;
3496 origOp = op = smb_GetSMBData(outp, NULL);
3497 /* and write out the basic header */
3498 *op++ = 5; /* variable block */
3499 op += 2; /* skip vbl block length; we'll fill it in later */
3503 /* make sure that curOffset.LowPart doesn't point to the first
3504 * 32 bytes in the 2nd through last dir page, and that it doesn't
3505 * point at the first 13 32-byte chunks in the first dir page,
3506 * since those are dir and page headers, and don't contain useful
3509 temp = curOffset.LowPart & (2048-1);
3510 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3511 /* we're in the first page */
3512 if (temp < 13*32) temp = 13*32;
3515 /* we're in a later dir page */
3516 if (temp < 32) temp = 32;
3519 /* make sure the low order 5 bits are zero */
3522 /* now put temp bits back ito curOffset.LowPart */
3523 curOffset.LowPart &= ~(2048-1);
3524 curOffset.LowPart |= temp;
3526 /* check if we've returned all the names that will fit in the
3529 if (returnedNames >= maxCount)
3532 /* check if we've passed the dir's EOF */
3533 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3535 /* see if we can use the bufferp we have now; compute in which page
3536 * the current offset would be, and check whether that's the offset
3537 * of the buffer we have. If not, get the buffer.
3539 thyper.HighPart = curOffset.HighPart;
3540 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3541 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3544 buf_Release(bufferp);
3547 lock_ReleaseMutex(&scp->mx);
3548 lock_ObtainRead(&scp->bufCreateLock);
3549 code = buf_Get(scp, &thyper, &bufferp);
3550 lock_ReleaseRead(&scp->bufCreateLock);
3551 lock_ObtainMutex(&dsp->mx);
3553 /* now, if we're doing a star match, do bulk fetching of all of
3554 * the status info for files in the dir.
3557 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3558 lock_ObtainMutex(&scp->mx);
3559 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3560 LargeIntegerGreaterThanOrEqualTo(thyper,
3561 scp->bulkStatProgress)) {
3562 /* Don't bulk stat if risking timeout */
3563 int now = GetCurrentTime();
3564 if (now - req.startTime > 5000) {
3565 scp->bulkStatProgress = thyper;
3566 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3567 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3569 cm_TryBulkStat(scp, &thyper, userp, &req);
3572 lock_ObtainMutex(&scp->mx);
3574 lock_ReleaseMutex(&dsp->mx);
3578 bufferOffset = thyper;
3580 /* now get the data in the cache */
3582 code = cm_SyncOp(scp, bufferp, userp, &req,
3584 CM_SCACHESYNC_NEEDCALLBACK |
3585 CM_SCACHESYNC_READ);
3588 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3590 /* otherwise, load the buffer and try again */
3591 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3595 buf_Release(bufferp);
3599 } /* if (wrong buffer) ... */
3601 /* now we have the buffer containing the entry we're interested in; copy
3602 * it out if it represents a non-deleted entry.
3604 entryInDir = curOffset.LowPart & (2048-1);
3605 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3607 /* page header will help tell us which entries are free. Page header
3608 * can change more often than once per buffer, since AFS 3 dir page size
3609 * may be less than (but not more than a buffer package buffer.
3611 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3612 temp &= ~(2048 - 1); /* turn off intra-page bits */
3613 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3615 /* now determine which entry we're looking at in the page. If it is
3616 * free (there's a free bitmap at the start of the dir), we should
3617 * skip these 32 bytes.
3619 slotInPage = (entryInDir & 0x7e0) >> 5;
3620 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3621 /* this entry is free */
3622 numDirChunks = 1; /* only skip this guy */
3626 tp = bufferp->datap + entryInBuffer;
3627 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3629 /* while we're here, compute the next entry's location, too,
3630 * since we'll need it when writing out the cookie into the dir
3633 * XXXX Probably should do more sanity checking.
3635 numDirChunks = cm_NameEntries(dep->name, NULL);
3637 /* compute the offset of the cookie representing the next entry */
3638 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3640 /* Compute 8.3 name if necessary */
3641 actualName = dep->name;
3642 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3643 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3644 actualName = shortName;
3647 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3648 /* this is one of the entries to use: it is not deleted
3649 * and it matches the star pattern we're looking for.
3652 /* Eliminate entries that don't match requested
3655 /* no hidden files */
3656 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3659 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3661 /* We have already done the cm_TryBulkStat above */
3662 fid.cell = scp->fid.cell;
3663 fid.volume = scp->fid.volume;
3664 fid.vnode = ntohl(dep->fid.vnode);
3665 fid.unique = ntohl(dep->fid.unique);
3666 fileType = cm_FindFileType(&fid);
3667 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3668 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3670 if (fileType == CM_SCACHETYPE_DIRECTORY)
3675 memcpy(op, mask, 11); op += 11;
3676 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3677 *op++ = nextEntryCookie & 0xff;
3678 *op++ = (nextEntryCookie>>8) & 0xff;
3679 *op++ = (nextEntryCookie>>16) & 0xff;
3680 *op++ = (nextEntryCookie>>24) & 0xff;
3681 memcpy(op, &clientCookie, 4); op += 4;
3683 /* now we emit the attribute. This is sort of tricky,
3684 * since we need to really stat the file to find out
3685 * what type of entry we've got. Right now, we're
3686 * copying out data from a buffer, while holding the
3687 * scp locked, so it isn't really convenient to stat
3688 * something now. We'll put in a place holder now,
3689 * and make a second pass before returning this to get
3690 * the real attributes. So, we just skip the data for
3691 * now, and adjust it later. We allocate a patch
3692 * record to make it easy to find this point later.
3693 * The replay will happen at a time when it is safe to
3694 * unlock the directory.
3696 curPatchp = malloc(sizeof(*curPatchp));
3697 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3698 curPatchp->dptr = op;
3699 curPatchp->fid.cell = scp->fid.cell;
3700 curPatchp->fid.volume = scp->fid.volume;
3701 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3702 curPatchp->fid.unique = ntohl(dep->fid.unique);
3704 /* do hidden attribute here since name won't be around when applying
3708 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3709 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3711 curPatchp->flags = 0;
3713 op += 9; /* skip attr, time, date and size */
3715 /* zero out name area. The spec says to pad with
3716 * spaces, but Samba doesn't, and neither do we.
3720 /* finally, we get to copy out the name; we know that
3721 * it fits in 8.3 or the pattern wouldn't match, but it
3722 * never hurts to be sure.
3724 strncpy(op, actualName, 13);
3726 /* Uppercase if requested by client */
3727 if ((((smb_t *)inp)->flg2 & 1) == 0)
3732 /* now, adjust the # of entries copied */
3734 } /* if we're including this name */
3737 /* and adjust curOffset to be where the new cookie is */
3738 thyper.HighPart = 0;
3739 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3740 curOffset = LargeIntegerAdd(thyper, curOffset);
3741 } /* while copying data for dir listing */
3743 /* release the mutex */
3744 lock_ReleaseMutex(&scp->mx);
3745 if (bufferp) buf_Release(bufferp);
3747 /* apply and free last set of patches; if not doing a star match, this
3748 * will be empty, but better safe (and freeing everything) than sorry.
3750 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3752 /* special return code for unsuccessful search */
3753 if (code == 0 && dataLength < 21 && returnedNames == 0)
3754 code = CM_ERROR_NOFILES;
3756 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3757 returnedNames, code);
3760 smb_DeleteDirSearch(dsp);
3761 smb_ReleaseDirSearch(dsp);
3762 cm_ReleaseSCache(scp);
3763 cm_ReleaseUser(userp);
3767 /* finalize the output buffer */
3768 smb_SetSMBParm(outp, 0, returnedNames);
3769 temp = (long) (op - origOp);
3770 smb_SetSMBDataLength(outp, temp);
3772 /* the data area is a variable block, which has a 5 (already there)
3773 * followed by the length of the # of data bytes. We now know this to
3774 * be "temp," although that includes the 3 bytes of vbl block header.
3775 * Deduct for them and fill in the length field.
3777 temp -= 3; /* deduct vbl block info */
3778 osi_assert(temp == (43 * returnedNames));
3779 origOp[1] = temp & 0xff;
3780 origOp[2] = (temp>>8) & 0xff;
3781 if (returnedNames == 0)
3782 smb_DeleteDirSearch(dsp);
3783 smb_ReleaseDirSearch(dsp);
3784 cm_ReleaseSCache(scp);
3785 cm_ReleaseUser(userp);
3789 /* verify that this is a valid path to a directory. I don't know why they
3790 * don't use the get file attributes call.
3792 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3796 cm_scache_t *rootScp;
3797 cm_scache_t *newScp;
3806 pathp = smb_GetSMBData(inp, NULL);
3807 pathp = smb_ParseASCIIBlock(pathp, NULL);
3808 osi_Log1(smb_logp, "SMB receive check path %s",
3809 osi_LogSaveString(smb_logp, pathp));
3812 return CM_ERROR_BADFD;
3815 rootScp = cm_rootSCachep;
3817 userp = smb_GetUser(vcp, inp);
3819 caseFold = CM_FLAG_CASEFOLD;
3821 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3823 cm_ReleaseUser(userp);
3824 return CM_ERROR_NOSUCHPATH;
3826 code = cm_NameI(rootScp, pathp,
3827 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3828 userp, tidPathp, &req, &newScp);
3831 cm_ReleaseUser(userp);
3835 /* now lock the vnode with a callback; returns with newScp locked */
3836 lock_ObtainMutex(&newScp->mx);
3837 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3838 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3839 if (code && code != CM_ERROR_NOACCESS) {
3840 lock_ReleaseMutex(&newScp->mx);
3841 cm_ReleaseSCache(newScp);
3842 cm_ReleaseUser(userp);
3846 attrs = smb_Attributes(newScp);
3848 if (!(attrs & 0x10))
3849 code = CM_ERROR_NOTDIR;
3851 lock_ReleaseMutex(&newScp->mx);
3853 cm_ReleaseSCache(newScp);
3854 cm_ReleaseUser(userp);
3858 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3862 cm_scache_t *rootScp;
3863 unsigned short attribute;
3865 cm_scache_t *newScp;
3874 /* decode basic attributes we're passed */
3875 attribute = smb_GetSMBParm(inp, 0);
3876 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3878 pathp = smb_GetSMBData(inp, NULL);
3879 pathp = smb_ParseASCIIBlock(pathp, NULL);
3882 return CM_ERROR_BADSMB;
3885 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3886 dosTime, attribute);
3888 rootScp = cm_rootSCachep;
3890 userp = smb_GetUser(vcp, inp);
3892 caseFold = CM_FLAG_CASEFOLD;
3894 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3896 cm_ReleaseUser(userp);
3897 return CM_ERROR_NOSUCHFILE;
3899 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3900 tidPathp, &req, &newScp);
3903 cm_ReleaseUser(userp);
3907 /* now lock the vnode with a callback; returns with newScp locked; we
3908 * need the current status to determine what the new status is, in some
3911 lock_ObtainMutex(&newScp->mx);
3912 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3913 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3915 lock_ReleaseMutex(&newScp->mx);
3916 cm_ReleaseSCache(newScp);
3917 cm_ReleaseUser(userp);
3921 /* Check for RO volume */
3922 if (newScp->flags & CM_SCACHEFLAG_RO) {
3923 lock_ReleaseMutex(&newScp->mx);
3924 cm_ReleaseSCache(newScp);
3925 cm_ReleaseUser(userp);
3926 return CM_ERROR_READONLY;
3929 /* prepare for setattr call */
3932 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3933 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3935 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3936 /* we're told to make a writable file read-only */
3937 attr.unixModeBits = newScp->unixModeBits & ~0222;
3938 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3940 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3941 /* we're told to make a read-only file writable */
3942 attr.unixModeBits = newScp->unixModeBits | 0222;
3943 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3945 lock_ReleaseMutex(&newScp->mx);
3947 /* now call setattr */
3949 code = cm_SetAttr(newScp, &attr, userp, &req);
3953 cm_ReleaseSCache(newScp);
3954 cm_ReleaseUser(userp);
3959 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3963 cm_scache_t *rootScp;
3964 cm_scache_t *newScp, *dscp;
3976 pathp = smb_GetSMBData(inp, NULL);
3977 pathp = smb_ParseASCIIBlock(pathp, NULL);
3980 return CM_ERROR_BADSMB;
3983 if (*pathp == 0) /* null path */
3986 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3987 osi_LogSaveString(smb_logp, pathp));
3989 rootScp = cm_rootSCachep;
3991 userp = smb_GetUser(vcp, inp);
3993 /* we shouldn't need this for V3 requests, but we seem to */
3994 caseFold = CM_FLAG_CASEFOLD;
3996 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3998 cm_ReleaseUser(userp);
3999 return CM_ERROR_NOSUCHFILE;
4003 * XXX Strange hack XXX
4005 * As of Patch 5 (16 July 97), we are having the following problem:
4006 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4007 * requests to look up "desktop.ini" in all the subdirectories.
4008 * This can cause zillions of timeouts looking up non-existent cells
4009 * and volumes, especially in the top-level directory.
4011 * We have not found any way to avoid this or work around it except
4012 * to explicitly ignore the requests for mount points that haven't
4013 * yet been evaluated and for directories that haven't yet been
4016 * We should modify this hack to provide a fake desktop.ini file
4017 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4019 spacep = inp->spacep;
4020 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4021 #ifndef SPECIAL_FOLDERS
4022 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4023 code = cm_NameI(rootScp, spacep->data,
4024 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4025 userp, tidPathp, &req, &dscp);
4027 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT &&
4028 !dscp->mountRootFidp)
4029 code = CM_ERROR_NOSUCHFILE;
4030 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4031 cm_buf_t *bp = buf_Find(dscp, &hzero);
4035 code = CM_ERROR_NOSUCHFILE;
4037 cm_ReleaseSCache(dscp);
4039 cm_ReleaseUser(userp);
4044 #endif /* SPECIAL_FOLDERS */
4046 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4047 tidPathp, &req, &newScp);
4049 cm_ReleaseUser(userp);
4053 /* now lock the vnode with a callback; returns with newScp locked */
4054 lock_ObtainMutex(&newScp->mx);
4055 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4056 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4058 lock_ReleaseMutex(&newScp->mx);
4059 cm_ReleaseSCache(newScp);
4060 cm_ReleaseUser(userp);
4065 /* use smb_Attributes instead. Also the fact that a file is
4066 * in a readonly volume doesn't mean it shojuld be marked as RO
4068 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4069 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4070 attrs = SMB_ATTR_DIRECTORY;
4073 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4074 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4076 attrs = smb_Attributes(newScp);
4079 smb_SetSMBParm(outp, 0, attrs);
4081 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4082 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4083 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4084 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4085 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4086 smb_SetSMBParm(outp, 5, 0);
4087 smb_SetSMBParm(outp, 6, 0);
4088 smb_SetSMBParm(outp, 7, 0);
4089 smb_SetSMBParm(outp, 8, 0);
4090 smb_SetSMBParm(outp, 9, 0);
4091 smb_SetSMBDataLength(outp, 0);
4092 lock_ReleaseMutex(&newScp->mx);
4094 cm_ReleaseSCache(newScp);
4095 cm_ReleaseUser(userp);
4100 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4104 osi_Log0(smb_logp, "SMB receive tree disconnect");
4106 /* find the tree and free it */
4107 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4109 lock_ObtainMutex(&tidp->mx);
4110 tidp->flags |= SMB_TIDFLAG_DELETE;
4111 lock_ReleaseMutex(&tidp->mx);
4112 smb_ReleaseTID(tidp);
4118 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4136 pathp = smb_GetSMBData(inp, NULL);
4137 pathp = smb_ParseASCIIBlock(pathp, NULL);
4139 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4141 #ifdef DEBUG_VERBOSE
4145 hexpath = osi_HexifyString( pathp );
4146 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4151 share = smb_GetSMBParm(inp, 0);
4152 attribute = smb_GetSMBParm(inp, 1);
4154 spacep = inp->spacep;
4155 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4156 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4157 /* special case magic file name for receiving IOCTL requests
4158 * (since IOCTL calls themselves aren't getting through).
4160 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4161 smb_SetupIoctlFid(fidp, spacep);
4162 smb_SetSMBParm(outp, 0, fidp->fid);
4163 smb_SetSMBParm(outp, 1, 0); /* attrs */
4164 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4165 smb_SetSMBParm(outp, 3, 0);
4166 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4167 smb_SetSMBParm(outp, 5, 0x7fff);
4168 /* pass the open mode back */
4169 smb_SetSMBParm(outp, 6, (share & 0xf));
4170 smb_SetSMBDataLength(outp, 0);
4171 smb_ReleaseFID(fidp);
4175 userp = smb_GetUser(vcp, inp);
4177 caseFold = CM_FLAG_CASEFOLD;
4179 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4181 cm_ReleaseUser(userp);
4182 return CM_ERROR_NOSUCHPATH;
4184 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4185 tidPathp, &req, &scp);
4188 cm_ReleaseUser(userp);
4192 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4194 cm_ReleaseSCache(scp);
4195 cm_ReleaseUser(userp);
4199 /* don't need callback to check file type, since file types never
4200 * change, and namei and cm_Lookup all stat the object at least once on
4201 * a successful return.
4203 if (scp->fileType != CM_SCACHETYPE_FILE) {
4204 cm_ReleaseSCache(scp);
4205 cm_ReleaseUser(userp);
4206 return CM_ERROR_ISDIR;
4209 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4212 /* save a pointer to the vnode */
4215 if ((share & 0xf) == 0)
4216 fidp->flags |= SMB_FID_OPENREAD;
4217 else if ((share & 0xf) == 1)
4218 fidp->flags |= SMB_FID_OPENWRITE;
4220 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4222 lock_ObtainMutex(&scp->mx);
4223 smb_SetSMBParm(outp, 0, fidp->fid);
4224 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4225 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4226 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4227 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4228 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4229 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4230 /* pass the open mode back; XXXX add access checks */
4231 smb_SetSMBParm(outp, 6, (share & 0xf));
4232 smb_SetSMBDataLength(outp, 0);
4233 lock_ReleaseMutex(&scp->mx);
4236 cm_Open(scp, 0, userp);
4238 /* send and free packet */
4239 smb_ReleaseFID(fidp);
4240 cm_ReleaseUser(userp);
4241 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4245 typedef struct smb_unlinkRock {
4250 char *maskp; /* pointer to the star pattern */
4255 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4258 smb_unlinkRock_t *rockp;
4266 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4267 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4268 caseFold |= CM_FLAG_8DOT3;
4270 matchName = dep->name;
4271 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4273 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4274 !cm_Is8Dot3(dep->name)) {
4275 cm_Gen8Dot3Name(dep, shortName, NULL);
4276 matchName = shortName;
4277 /* 8.3 matches are always case insensitive */
4278 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4281 osi_Log1(smb_logp, "Unlinking %s",
4282 osi_LogSaveString(smb_logp, matchName));
4283 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4284 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4285 smb_NotifyChange(FILE_ACTION_REMOVED,
4286 FILE_NOTIFY_CHANGE_FILE_NAME,
4287 dscp, dep->name, NULL, TRUE);
4291 /* If we made a case sensitive exact match, we might as well quit now. */
4292 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4293 code = CM_ERROR_STOPNOW;
4301 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4310 smb_unlinkRock_t rock;
4319 attribute = smb_GetSMBParm(inp, 0);
4321 tp = smb_GetSMBData(inp, NULL);
4322 pathp = smb_ParseASCIIBlock(tp, &tp);
4324 osi_Log1(smb_logp, "SMB receive unlink %s",
4325 osi_LogSaveString(smb_logp, pathp));
4327 spacep = inp->spacep;
4328 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4330 userp = smb_GetUser(vcp, inp);
4332 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4334 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4336 cm_ReleaseUser(userp);
4337 return CM_ERROR_NOSUCHPATH;
4339 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4343 cm_ReleaseUser(userp);
4347 /* otherwise, scp points to the parent directory. */
4354 rock.maskp = smb_FindMask(pathp);
4355 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4358 thyper.HighPart = 0;
4364 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4365 * match. If that fails, we do a case insensitve match.
4367 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4368 !smb_IsStarMask(rock.maskp)) {
4369 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4372 thyper.HighPart = 0;
4373 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4378 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4380 if (code == CM_ERROR_STOPNOW)
4383 cm_ReleaseUser(userp);
4385 cm_ReleaseSCache(dscp);
4387 if (code == 0 && !rock.any)
4388 code = CM_ERROR_NOSUCHFILE;
4392 typedef struct smb_renameRock {
4393 cm_scache_t *odscp; /* old dir */
4394 cm_scache_t *ndscp; /* new dir */
4395 cm_user_t *userp; /* user */
4396 cm_req_t *reqp; /* request struct */
4397 smb_vc_t *vcp; /* virtual circuit */
4398 char *maskp; /* pointer to star pattern of old file name */
4399 int flags; /* tilde, casefold, etc */
4400 char *newNamep; /* ptr to the new file's name */
4403 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4406 smb_renameRock_t *rockp;
4411 rockp = (smb_renameRock_t *) vrockp;
4413 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4414 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4415 caseFold |= CM_FLAG_8DOT3;
4417 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4419 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4420 !cm_Is8Dot3(dep->name)) {
4421 cm_Gen8Dot3Name(dep, shortName, NULL);
4422 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4425 code = cm_Rename(rockp->odscp, dep->name,
4426 rockp->ndscp, rockp->newNamep, rockp->userp,
4428 /* if the call worked, stop doing the search now, since we
4429 * really only want to rename one file.
4432 code = CM_ERROR_STOPNOW;
4441 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4444 cm_space_t *spacep = NULL;
4445 smb_renameRock_t rock;
4446 cm_scache_t *oldDscp = NULL;
4447 cm_scache_t *newDscp = NULL;
4448 cm_scache_t *tmpscp= NULL;
4449 cm_scache_t *tmpscp2 = NULL;
4459 userp = smb_GetUser(vcp, inp);
4460 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4462 cm_ReleaseUser(userp);
4463 return CM_ERROR_NOSUCHPATH;
4467 spacep = inp->spacep;
4468 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4471 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4472 * what actually exists is foo/baz. I don't know why the code used to be
4473 * the way it was. 1/29/96
4475 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4477 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4479 * caseFold = CM_FLAG_CASEFOLD;
4481 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4482 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4483 userp, tidPathp, &req, &oldDscp);
4486 cm_ReleaseUser(userp);
4490 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4491 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4492 userp, tidPathp, &req, &newDscp);
4495 cm_ReleaseSCache(oldDscp);
4496 cm_ReleaseUser(userp);
4500 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4501 * next, get the component names, and lower case them.
4504 /* handle the old name first */
4506 oldLastNamep = oldPathp;
4510 /* and handle the new name, too */
4512 newLastNamep = newPathp;
4516 /* TODO: The old name could be a wildcard. The new name must not be */
4518 /* do the vnode call */
4519 rock.odscp = oldDscp;
4520 rock.ndscp = newDscp;
4524 rock.maskp = oldLastNamep;
4525 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4526 rock.newNamep = newLastNamep;
4528 /* Check if the file already exists; if so return error */
4529 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4530 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4531 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4532 osi_LogSaveString(afsd_logp, newLastNamep));
4534 /* Check if the old and the new names differ only in case. If so return
4535 * success, else return CM_ERROR_EXISTS
4537 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4539 /* This would be a success only if the old file is *as same as* the new file */
4540 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4542 if (tmpscp == tmpscp2)
4545 code = CM_ERROR_EXISTS;
4546 cm_ReleaseSCache(tmpscp2);
4549 code = CM_ERROR_NOSUCHFILE;
4552 /* file exist, do not rename, also fixes move */
4553 osi_Log0(smb_logp, "Can't rename. Target already exists");
4554 code = CM_ERROR_EXISTS;
4558 cm_ReleaseSCache(tmpscp);
4559 cm_ReleaseSCache(newDscp);
4560 cm_ReleaseSCache(oldDscp);
4561 cm_ReleaseUser(userp);
4565 /* Now search the directory for the pattern, and do the appropriate rename when found */
4566 thyper.LowPart = 0; /* search dir from here */
4567 thyper.HighPart = 0;
4569 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4571 if (code == CM_ERROR_STOPNOW)
4574 code = CM_ERROR_NOSUCHFILE;
4576 /* Handle Change Notification */
4578 * Being lazy, not distinguishing between files and dirs in this
4579 * filter, since we'd have to do a lookup.
4581 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4582 if (oldDscp == newDscp) {
4583 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4584 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4585 filter, oldDscp, oldLastNamep,
4586 newLastNamep, TRUE);
4588 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4589 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4590 filter, oldDscp, oldLastNamep,
4592 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4593 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4594 filter, newDscp, newLastNamep,
4599 cm_ReleaseSCache(tmpscp);
4600 cm_ReleaseUser(userp);
4601 cm_ReleaseSCache(oldDscp);
4602 cm_ReleaseSCache(newDscp);
4607 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4610 cm_space_t *spacep = NULL;
4611 cm_scache_t *oldDscp = NULL;
4612 cm_scache_t *newDscp = NULL;
4613 cm_scache_t *tmpscp= NULL;
4614 cm_scache_t *tmpscp2 = NULL;
4615 cm_scache_t *sscp = NULL;
4624 userp = smb_GetUser(vcp, inp);
4626 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4628 cm_ReleaseUser(userp);
4629 return CM_ERROR_NOSUCHPATH;
4634 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4636 spacep = inp->spacep;
4637 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4639 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4640 userp, tidPathp, &req, &oldDscp);
4642 cm_ReleaseUser(userp);
4646 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4647 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4648 userp, tidPathp, &req, &newDscp);
4650 cm_ReleaseSCache(oldDscp);
4651 cm_ReleaseUser(userp);
4655 /* Now, although we did two lookups for the two directories (because the same
4656 * directory can be referenced through different paths), we only allow hard links
4657 * within the same directory. */
4658 if (oldDscp != newDscp) {
4659 cm_ReleaseSCache(oldDscp);
4660 cm_ReleaseSCache(newDscp);
4661 cm_ReleaseUser(userp);
4662 return CM_ERROR_CROSSDEVLINK;
4665 /* handle the old name first */
4667 oldLastNamep = oldPathp;
4671 /* and handle the new name, too */
4673 newLastNamep = newPathp;
4677 /* now lookup the old name */
4678 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4679 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4681 cm_ReleaseSCache(oldDscp);
4682 cm_ReleaseSCache(newDscp);
4683 cm_ReleaseUser(userp);
4687 /* Check if the file already exists; if so return error */
4688 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4689 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4690 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4691 osi_LogSaveString(afsd_logp, newLastNamep));
4693 /* if the existing link is to the same file, then we return success */
4695 if(sscp == tmpscp) {
4698 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
4699 code = CM_ERROR_EXISTS;
4704 cm_ReleaseSCache(tmpscp);
4705 cm_ReleaseSCache(sscp);
4706 cm_ReleaseSCache(newDscp);
4707 cm_ReleaseSCache(oldDscp);
4708 cm_ReleaseUser(userp);
4712 /* now create the hardlink */
4713 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
4714 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
4715 osi_Log1(smb_logp," Link returns %d", code);
4717 /* Handle Change Notification */
4719 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
4720 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4721 smb_NotifyChange(FILE_ACTION_ADDED,
4722 filter, newDscp, newLastNamep,
4727 cm_ReleaseSCache(tmpscp);
4728 cm_ReleaseUser(userp);
4729 cm_ReleaseSCache(sscp);
4730 cm_ReleaseSCache(oldDscp);
4731 cm_ReleaseSCache(newDscp);
4736 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4742 tp = smb_GetSMBData(inp, NULL);
4743 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4744 newPathp = smb_ParseASCIIBlock(tp, &tp);
4746 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4747 osi_LogSaveString(smb_logp, oldPathp),
4748 osi_LogSaveString(smb_logp, newPathp));
4750 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
4755 typedef struct smb_rmdirRock {
4759 char *maskp; /* pointer to the star pattern */
4764 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4767 smb_rmdirRock_t *rockp;
4772 rockp = (smb_rmdirRock_t *) vrockp;
4774 matchName = dep->name;
4775 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4776 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4778 match = (strcmp(matchName, rockp->maskp) == 0);
4780 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4781 !cm_Is8Dot3(dep->name)) {
4782 cm_Gen8Dot3Name(dep, shortName, NULL);
4783 matchName = shortName;
4784 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4787 osi_Log1(smb_logp, "Removing directory %s",
4788 osi_LogSaveString(smb_logp, matchName));
4789 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4790 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4791 smb_NotifyChange(FILE_ACTION_REMOVED,
4792 FILE_NOTIFY_CHANGE_DIR_NAME,
4793 dscp, dep->name, NULL, TRUE);
4802 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4810 smb_rmdirRock_t rock;
4819 tp = smb_GetSMBData(inp, NULL);
4820 pathp = smb_ParseASCIIBlock(tp, &tp);
4822 spacep = inp->spacep;
4823 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4825 userp = smb_GetUser(vcp, inp);
4827 caseFold = CM_FLAG_CASEFOLD;
4829 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4831 cm_ReleaseUser(userp);
4832 return CM_ERROR_NOSUCHPATH;
4834 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4835 userp, tidPathp, &req, &dscp);
4838 cm_ReleaseUser(userp);
4842 /* otherwise, scp points to the parent directory. */
4849 rock.maskp = lastNamep;
4850 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4853 thyper.HighPart = 0;
4857 /* First do a case sensitive match, and if that fails, do a case insensitive match */
4858 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4859 if (code == 0 && !rock.any) {
4861 thyper.HighPart = 0;
4862 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4863 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4866 cm_ReleaseUser(userp);
4868 cm_ReleaseSCache(dscp);
4870 if (code == 0 && !rock.any)
4871 code = CM_ERROR_NOSUCHFILE;
4875 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4885 fid = smb_GetSMBParm(inp, 0);
4887 osi_Log1(smb_logp, "SMB flush fid %d", fid);
4889 fid = smb_ChainFID(fid, inp);
4890 fidp = smb_FindFID(vcp, fid, 0);
4891 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4893 smb_ReleaseFID(fidp);
4894 return CM_ERROR_BADFD;
4897 userp = smb_GetUser(vcp, inp);
4899 lock_ObtainMutex(&fidp->mx);
4900 if (fidp->flags & SMB_FID_OPENWRITE)
4901 code = cm_FSync(fidp->scp, userp, &req);
4904 lock_ReleaseMutex(&fidp->mx);
4906 smb_ReleaseFID(fidp);
4908 cm_ReleaseUser(userp);
4913 struct smb_FullNameRock {
4919 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4923 struct smb_FullNameRock *vrockp;
4925 vrockp = (struct smb_FullNameRock *)rockp;
4927 if (!cm_Is8Dot3(dep->name)) {
4928 cm_Gen8Dot3Name(dep, shortName, NULL);
4930 if (cm_stricmp(shortName, vrockp->name) == 0) {
4931 vrockp->fullName = strdup(dep->name);
4932 return CM_ERROR_STOPNOW;
4935 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
4936 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
4937 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4938 vrockp->fullName = strdup(dep->name);
4939 return CM_ERROR_STOPNOW;
4944 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4945 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4947 struct smb_FullNameRock rock;
4953 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
4954 if (code == CM_ERROR_STOPNOW)
4955 *newPathp = rock.fullName;
4957 *newPathp = strdup(pathp);
4960 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4971 fid = smb_GetSMBParm(inp, 0);
4972 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4974 osi_Log1(smb_logp, "SMB close fid %d", fid);
4976 fid = smb_ChainFID(fid, inp);
4977 fidp = smb_FindFID(vcp, fid, 0);
4979 return CM_ERROR_BADFD;
4982 userp = smb_GetUser(vcp, inp);
4984 lock_ObtainMutex(&fidp->mx);
4986 /* Don't jump the gun on an async raw write */
4987 while (fidp->raw_writers) {
4988 lock_ReleaseMutex(&fidp->mx);
4989 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4990 lock_ObtainMutex(&fidp->mx);
4993 fidp->flags |= SMB_FID_DELETE;
4995 /* watch for ioctl closes, and read-only opens */
4996 if (fidp->scp != NULL &&
4997 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4998 == SMB_FID_OPENWRITE) {
4999 if (dosTime != 0 && dosTime != -1) {
5000 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5001 /* This fixes defect 10958 */
5002 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5003 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5005 code = cm_FSync(fidp->scp, userp, &req);
5010 if (fidp->flags & SMB_FID_DELONCLOSE) {
5011 cm_scache_t *dscp = fidp->NTopen_dscp;
5012 char *pathp = fidp->NTopen_pathp;
5015 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5016 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5017 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5018 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5019 smb_NotifyChange(FILE_ACTION_REMOVED,
5020 FILE_NOTIFY_CHANGE_DIR_NAME,
5021 dscp, fullPathp, NULL, TRUE);
5025 code = cm_Unlink(dscp, fullPathp, userp, &req);
5026 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5027 smb_NotifyChange(FILE_ACTION_REMOVED,
5028 FILE_NOTIFY_CHANGE_FILE_NAME,
5029 dscp, fullPathp, NULL, TRUE);
5033 lock_ReleaseMutex(&fidp->mx);
5035 if (fidp->flags & SMB_FID_NTOPEN) {
5036 cm_ReleaseSCache(fidp->NTopen_dscp);
5037 free(fidp->NTopen_pathp);
5039 if (fidp->NTopen_wholepathp)
5040 free(fidp->NTopen_wholepathp);
5042 smb_ReleaseFID(fidp);
5043 cm_ReleaseUser(userp);
5048 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5051 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5052 cm_user_t *userp, long *readp)
5054 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5055 cm_user_t *userp, long *readp, int dosflag)
5062 osi_hyper_t fileLength;
5064 osi_hyper_t lastByte;
5065 osi_hyper_t bufferOffset;
5066 long bufIndex, nbytes;
5076 lock_ObtainMutex(&fidp->mx);
5078 lock_ObtainMutex(&scp->mx);
5080 if (offset.HighPart == 0) {
5081 chunk = offset.LowPart >> cm_logChunkSize;
5082 if (chunk != fidp->curr_chunk) {
5083 fidp->prev_chunk = fidp->curr_chunk;
5084 fidp->curr_chunk = chunk;
5086 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5090 /* start by looking up the file's end */
5091 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5092 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5093 if (code) goto done;
5095 /* now we have the entry locked, look up the length */
5096 fileLength = scp->length;
5098 /* adjust count down so that it won't go past EOF */
5099 thyper.LowPart = count;
5100 thyper.HighPart = 0;
5101 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5103 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5104 /* we'd read past EOF, so just stop at fileLength bytes.
5105 * Start by computing how many bytes remain in the file.
5107 thyper = LargeIntegerSubtract(fileLength, offset);
5109 /* if we are past EOF, read 0 bytes */
5110 if (LargeIntegerLessThanZero(thyper))
5113 count = thyper.LowPart;
5118 /* now, copy the data one buffer at a time,
5119 * until we've filled the request packet
5122 /* if we've copied all the data requested, we're done */
5123 if (count <= 0) break;
5125 /* otherwise, load up a buffer of data */
5126 thyper.HighPart = offset.HighPart;
5127 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5128 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5131 buf_Release(bufferp);
5134 lock_ReleaseMutex(&scp->mx);
5136 lock_ObtainRead(&scp->bufCreateLock);
5137 code = buf_Get(scp, &thyper, &bufferp);
5138 lock_ReleaseRead(&scp->bufCreateLock);
5140 lock_ObtainMutex(&scp->mx);
5141 if (code) goto done;
5142 bufferOffset = thyper;
5144 /* now get the data in the cache */
5146 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5147 CM_SCACHESYNC_NEEDCALLBACK |
5148 CM_SCACHESYNC_READ);
5149 if (code) goto done;
5151 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5153 /* otherwise, load the buffer and try again */
5154 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5158 buf_Release(bufferp);
5162 } /* if (wrong buffer) ... */
5164 /* now we have the right buffer loaded. Copy out the
5165 * data from here to the user's buffer.
5167 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5169 /* and figure out how many bytes we want from this buffer */
5170 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5171 if (nbytes > count) nbytes = count; /* don't go past EOF */
5173 /* now copy the data */
5176 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5179 memcpy(op, bufferp->datap + bufIndex, nbytes);
5181 /* adjust counters, pointers, etc. */
5184 thyper.LowPart = nbytes;
5185 thyper.HighPart = 0;
5186 offset = LargeIntegerAdd(thyper, offset);
5190 lock_ReleaseMutex(&scp->mx);
5191 lock_ReleaseMutex(&fidp->mx);
5193 buf_Release(bufferp);
5195 if (code == 0 && sequential)
5196 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5202 * smb_WriteData -- common code for Write and Raw Write
5205 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5206 cm_user_t *userp, long *writtenp)
5208 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5209 cm_user_t *userp, long *writtenp, int dosflag)
5216 osi_hyper_t fileLength; /* file's length at start of write */
5217 osi_hyper_t minLength; /* don't read past this */
5218 long nbytes; /* # of bytes to transfer this iteration */
5220 osi_hyper_t thyper; /* hyper tmp variable */
5221 osi_hyper_t bufferOffset;
5222 long bufIndex; /* index in buffer where our data is */
5224 osi_hyper_t writeBackOffset;/* offset of region to write back when
5229 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5230 fidp->fid, offsetp->LowPart, count);
5240 lock_ObtainMutex(&fidp->mx);
5242 lock_ObtainMutex(&scp->mx);
5244 /* start by looking up the file's end */
5245 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5247 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5248 CM_SCACHESYNC_NEEDCALLBACK
5249 | CM_SCACHESYNC_SETSTATUS
5250 | CM_SCACHESYNC_GETSTATUS);
5251 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5256 /* make sure we have a writable FD */
5257 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5258 code = CM_ERROR_BADFDOP;
5262 /* now we have the entry locked, look up the length */
5263 fileLength = scp->length;
5264 minLength = fileLength;
5265 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5266 minLength = scp->serverLength;
5268 /* adjust file length if we extend past EOF */
5269 thyper.LowPart = count;
5270 thyper.HighPart = 0;
5271 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5272 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5273 /* we'd write past EOF, so extend the file */
5274 scp->mask |= CM_SCACHEMASK_LENGTH;
5275 scp->length = thyper;
5276 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5278 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5280 /* now, if the new position (thyper) and the old (offset) are in
5281 * different storeback windows, remember to store back the previous
5282 * storeback window when we're done with the write.
5284 if ((thyper.LowPart & (-cm_chunkSize)) !=
5285 (offset.LowPart & (-cm_chunkSize))) {
5286 /* they're different */
5288 writeBackOffset.HighPart = offset.HighPart;
5289 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5294 /* now, copy the data one buffer at a time, until we've filled the
5297 /* if we've copied all the data requested, we're done */
5301 /* handle over quota or out of space */
5302 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5303 *writtenp = written;
5304 code = CM_ERROR_QUOTA;
5308 /* otherwise, load up a buffer of data */
5309 thyper.HighPart = offset.HighPart;
5310 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5311 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5314 lock_ReleaseMutex(&bufferp->mx);
5315 buf_Release(bufferp);
5318 lock_ReleaseMutex(&scp->mx);
5320 lock_ObtainRead(&scp->bufCreateLock);
5321 code = buf_Get(scp, &thyper, &bufferp);
5322 lock_ReleaseRead(&scp->bufCreateLock);
5324 lock_ObtainMutex(&bufferp->mx);
5325 lock_ObtainMutex(&scp->mx);
5326 if (code) goto done;
5328 bufferOffset = thyper;
5330 /* now get the data in the cache */
5332 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5334 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5335 CM_SCACHESYNC_NEEDCALLBACK
5336 | CM_SCACHESYNC_WRITE
5337 | CM_SCACHESYNC_BUFLOCKED);
5338 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5343 /* If we're overwriting the entire buffer, or
5344 * if we're writing at or past EOF, mark the
5345 * buffer as current so we don't call
5346 * cm_GetBuffer. This skips the fetch from the
5347 * server in those cases where we're going to
5348 * obliterate all the data in the buffer anyway,
5349 * or in those cases where there is no useful
5350 * data at the server to start with.
5352 * Use minLength instead of scp->length, since
5353 * the latter has already been updated by this
5356 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5357 || LargeIntegerEqualTo(offset, bufferp->offset)
5358 && (count >= buf_bufferSize
5359 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5360 ConvertLongToLargeInteger(count)),
5362 if (count < buf_bufferSize
5363 && bufferp->dataVersion == -1)
5364 memset(bufferp->datap, 0,
5366 bufferp->dataVersion = scp->dataVersion;
5369 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5371 /* otherwise, load the buffer and try again */
5372 lock_ReleaseMutex(&bufferp->mx);
5373 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5375 lock_ReleaseMutex(&scp->mx);
5376 lock_ObtainMutex(&bufferp->mx);
5377 lock_ObtainMutex(&scp->mx);
5381 lock_ReleaseMutex(&bufferp->mx);
5382 buf_Release(bufferp);
5386 } /* if (wrong buffer) ... */
5388 /* now we have the right buffer loaded. Copy out the
5389 * data from here to the user's buffer.
5391 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5393 /* and figure out how many bytes we want from this buffer */
5394 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5396 nbytes = count; /* don't go past end of request */
5398 /* now copy the data */
5401 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5404 memcpy(bufferp->datap + bufIndex, op, nbytes);
5405 buf_SetDirty(bufferp);
5407 /* and record the last writer */
5408 if (bufferp->userp != userp) {
5411 cm_ReleaseUser(bufferp->userp);
5412 bufferp->userp = userp;
5415 /* adjust counters, pointers, etc. */
5419 thyper.LowPart = nbytes;
5420 thyper.HighPart = 0;
5421 offset = LargeIntegerAdd(thyper, offset);
5425 lock_ReleaseMutex(&scp->mx);
5426 lock_ReleaseMutex(&fidp->mx);
5428 lock_ReleaseMutex(&bufferp->mx);
5429 buf_Release(bufferp);
5432 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5433 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5434 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5435 fidp->NTopen_dscp, fidp->NTopen_pathp,
5439 if (code == 0 && doWriteBack) {
5441 lock_ObtainMutex(&scp->mx);
5442 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5444 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5445 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5447 lock_ReleaseMutex(&scp->mx);
5448 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5449 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5452 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5453 fidp->fid, code, *writtenp);
5457 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5460 long count, written = 0, total_written = 0;
5465 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5467 int inDataBlockCount;
5469 fd = smb_GetSMBParm(inp, 0);
5470 count = smb_GetSMBParm(inp, 1);
5471 offset.HighPart = 0; /* too bad */
5472 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5474 op = smb_GetSMBData(inp, NULL);
5475 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5477 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5478 fd, offset.LowPart, count);
5480 fd = smb_ChainFID(fd, inp);
5481 fidp = smb_FindFID(vcp, fd, 0);
5483 return CM_ERROR_BADFD;
5486 if (fidp->flags & SMB_FID_IOCTL)
5487 return smb_IoctlWrite(fidp, vcp, inp, outp);
5489 userp = smb_GetUser(vcp, inp);
5491 /* special case: 0 bytes transferred means truncate to this position */
5497 truncAttr.mask = CM_ATTRMASK_LENGTH;
5498 truncAttr.length.LowPart = offset.LowPart;
5499 truncAttr.length.HighPart = 0;
5500 lock_ObtainMutex(&fidp->mx);
5501 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5502 lock_ReleaseMutex(&fidp->mx);
5503 smb_SetSMBParm(outp, 0, /* count */ 0);
5504 smb_SetSMBDataLength(outp, 0);
5505 fidp->flags |= SMB_FID_LENGTHSETDONE;
5510 * Work around bug in NT client
5512 * When copying a file, the NT client should first copy the data,
5513 * then copy the last write time. But sometimes the NT client does
5514 * these in the wrong order, so the data copies would inadvertently
5515 * cause the last write time to be overwritten. We try to detect this,
5516 * and don't set client mod time if we think that would go against the
5519 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5520 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5521 fidp->scp->clientModTime = time(NULL);
5525 while ( code == 0 && count > 0 ) {
5527 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5529 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5531 if (code == 0 && written == 0)
5532 code = CM_ERROR_PARTIALWRITE;
5534 offset.LowPart += written;
5536 total_written += written;
5540 /* set the packet data length to 3 bytes for the data block header,
5541 * plus the size of the data.
5543 smb_SetSMBParm(outp, 0, total_written);
5544 smb_SetSMBDataLength(outp, 0);
5547 smb_ReleaseFID(fidp);
5548 cm_ReleaseUser(userp);
5553 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5554 NCB *ncbp, raw_write_cont_t *rwcp)
5567 fd = smb_GetSMBParm(inp, 0);
5568 fidp = smb_FindFID(vcp, fd, 0);
5570 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5571 rwcp->offset.LowPart, rwcp->count);
5573 userp = smb_GetUser(vcp, inp);
5577 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5580 rawBuf = (dos_ptr) rwcp->buf;
5581 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5582 (unsigned char *) rawBuf, userp,
5586 if (rwcp->writeMode & 0x1) { /* synchronous */
5589 smb_FormatResponsePacket(vcp, inp, outp);
5590 op = (smb_t *) outp;
5591 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5592 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5593 smb_SetSMBDataLength(outp, 0);
5594 smb_SendPacket(vcp, outp);
5595 smb_FreePacket(outp);
5597 else { /* asynchronous */
5598 lock_ObtainMutex(&fidp->mx);
5599 fidp->raw_writers--;
5600 if (fidp->raw_writers == 0)
5601 thrd_SetEvent(fidp->raw_write_event);
5602 lock_ReleaseMutex(&fidp->mx);
5605 /* Give back raw buffer */
5606 lock_ObtainMutex(&smb_RawBufLock);
5608 *((char **)rawBuf) = smb_RawBufs;
5610 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5612 smb_RawBufs = rawBuf;
5613 lock_ReleaseMutex(&smb_RawBufLock);
5615 smb_ReleaseFID(fidp);
5616 cm_ReleaseUser(userp);
5619 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5624 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5627 long count, written = 0, total_written = 0;
5634 unsigned short writeMode;
5641 fd = smb_GetSMBParm(inp, 0);
5642 totalCount = smb_GetSMBParm(inp, 1);
5643 count = smb_GetSMBParm(inp, 10);
5644 offset.HighPart = 0; /* too bad */
5645 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5646 writeMode = smb_GetSMBParm(inp, 7);
5648 op = (char *) inp->data;
5649 op += smb_GetSMBParm(inp, 11);
5652 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5653 fd, offset.LowPart, count, writeMode);
5655 fd = smb_ChainFID(fd, inp);
5656 fidp = smb_FindFID(vcp, fd, 0);
5658 return CM_ERROR_BADFD;
5661 userp = smb_GetUser(vcp, inp);
5664 * Work around bug in NT client
5666 * When copying a file, the NT client should first copy the data,
5667 * then copy the last write time. But sometimes the NT client does
5668 * these in the wrong order, so the data copies would inadvertently
5669 * cause the last write time to be overwritten. We try to detect this,
5670 * and don't set client mod time if we think that would go against the
5673 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5674 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5675 fidp->scp->clientModTime = time(NULL);
5679 while ( code == 0 && count > 0 ) {
5681 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5683 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5685 if (code == 0 && written == 0)
5686 code = CM_ERROR_PARTIALWRITE;
5688 offset.LowPart += written;
5690 total_written += written;
5694 /* Get a raw buffer */
5697 lock_ObtainMutex(&smb_RawBufLock);
5699 /* Get a raw buf, from head of list */
5700 rawBuf = smb_RawBufs;
5702 smb_RawBufs = *(char **)smb_RawBufs;
5704 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5708 code = CM_ERROR_USESTD;
5710 lock_ReleaseMutex(&smb_RawBufLock);
5713 /* Don't allow a premature Close */
5714 if (code == 0 && (writeMode & 1) == 0) {
5715 lock_ObtainMutex(&fidp->mx);
5716 fidp->raw_writers++;
5717 thrd_ResetEvent(fidp->raw_write_event);
5718 lock_ReleaseMutex(&fidp->mx);
5721 smb_ReleaseFID(fidp);
5722 cm_ReleaseUser(userp);
5725 smb_SetSMBParm(outp, 0, total_written);
5726 smb_SetSMBDataLength(outp, 0);
5727 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5734 rwcp->offset.HighPart = 0;
5735 rwcp->offset.LowPart = offset.LowPart + count;
5736 rwcp->count = totalCount - count;
5737 rwcp->writeMode = writeMode;
5738 rwcp->alreadyWritten = total_written;
5740 /* set the packet data length to 3 bytes for the data block header,
5741 * plus the size of the data.
5743 smb_SetSMBParm(outp, 0, 0xffff);
5744 smb_SetSMBDataLength(outp, 0);
5749 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5752 long count, finalCount;
5759 fd = smb_GetSMBParm(inp, 0);
5760 count = smb_GetSMBParm(inp, 1);
5761 offset.HighPart = 0; /* too bad */
5762 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5764 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5765 fd, offset.LowPart, count);
5767 fd = smb_ChainFID(fd, inp);
5768 fidp = smb_FindFID(vcp, fd, 0);
5770 return CM_ERROR_BADFD;
5773 if (fidp->flags & SMB_FID_IOCTL) {
5774 return smb_IoctlRead(fidp, vcp, inp, outp);
5777 userp = smb_GetUser(vcp, inp);
5779 /* remember this for final results */
5780 smb_SetSMBParm(outp, 0, count);
5781 smb_SetSMBParm(outp, 1, 0);
5782 smb_SetSMBParm(outp, 2, 0);
5783 smb_SetSMBParm(outp, 3, 0);
5784 smb_SetSMBParm(outp, 4, 0);
5786 /* set the packet data length to 3 bytes for the data block header,
5787 * plus the size of the data.
5789 smb_SetSMBDataLength(outp, count+3);
5791 /* get op ptr after putting in the parms, since otherwise we don't
5792 * know where the data really is.
5794 op = smb_GetSMBData(outp, NULL);
5796 /* now emit the data block header: 1 byte of type and 2 bytes of length */
5797 *op++ = 1; /* data block marker */
5798 *op++ = (unsigned char) (count & 0xff);
5799 *op++ = (unsigned char) ((count >> 8) & 0xff);
5802 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5804 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5807 /* fix some things up */
5808 smb_SetSMBParm(outp, 0, finalCount);
5809 smb_SetSMBDataLength(outp, finalCount+3);
5811 smb_ReleaseFID(fidp);
5813 cm_ReleaseUser(userp);
5817 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5824 cm_scache_t *dscp; /* dir we're dealing with */
5825 cm_scache_t *scp; /* file we're creating */
5827 int initialModeBits;
5837 /* compute initial mode bits based on read-only flag in attributes */
5838 initialModeBits = 0777;
5840 tp = smb_GetSMBData(inp, NULL);
5841 pathp = smb_ParseASCIIBlock(tp, &tp);
5843 if (strcmp(pathp, "\\") == 0)
5844 return CM_ERROR_EXISTS;
5846 spacep = inp->spacep;
5847 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5849 userp = smb_GetUser(vcp, inp);
5851 caseFold = CM_FLAG_CASEFOLD;
5853 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5855 cm_ReleaseUser(userp);
5856 return CM_ERROR_NOSUCHPATH;
5859 code = cm_NameI(cm_rootSCachep, spacep->data,
5860 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5861 userp, tidPathp, &req, &dscp);
5864 cm_ReleaseUser(userp);
5868 /* otherwise, scp points to the parent directory. Do a lookup, and
5869 * fail if we find it. Otherwise, we do the create.
5875 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5876 if (scp) cm_ReleaseSCache(scp);
5877 if (code != CM_ERROR_NOSUCHFILE) {
5878 if (code == 0) code = CM_ERROR_EXISTS;
5879 cm_ReleaseSCache(dscp);
5880 cm_ReleaseUser(userp);
5884 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5885 setAttr.clientModTime = time(NULL);
5886 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5887 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5888 smb_NotifyChange(FILE_ACTION_ADDED,
5889 FILE_NOTIFY_CHANGE_DIR_NAME,
5890 dscp, lastNamep, NULL, TRUE);
5892 /* we don't need this any longer */
5893 cm_ReleaseSCache(dscp);
5896 /* something went wrong creating or truncating the file */
5897 cm_ReleaseUser(userp);
5901 /* otherwise we succeeded */
5902 smb_SetSMBDataLength(outp, 0);
5903 cm_ReleaseUser(userp);
5908 BOOL smb_IsLegalFilename(char *filename)
5911 * Find the longest substring of filename that does not contain
5912 * any of the chars in illegalChars. If that substring is less
5913 * than the length of the whole string, then one or more of the
5914 * illegal chars is in filename.
5916 if (strcspn(filename, illegalChars) < strlen(filename))
5922 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5930 cm_scache_t *dscp; /* dir we're dealing with */
5931 cm_scache_t *scp; /* file we're creating */
5933 int initialModeBits;
5945 excl = (inp->inCom == 0x03)? 0 : 1;
5947 attributes = smb_GetSMBParm(inp, 0);
5948 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5950 /* compute initial mode bits based on read-only flag in attributes */
5951 initialModeBits = 0666;
5952 if (attributes & 1) initialModeBits &= ~0222;
5954 tp = smb_GetSMBData(inp, NULL);
5955 pathp = smb_ParseASCIIBlock(tp, &tp);
5957 spacep = inp->spacep;
5958 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5960 userp = smb_GetUser(vcp, inp);
5962 caseFold = CM_FLAG_CASEFOLD;
5964 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5966 cm_ReleaseUser(userp);
5967 return CM_ERROR_NOSUCHPATH;
5969 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5970 userp, tidPathp, &req, &dscp);
5973 cm_ReleaseUser(userp);
5977 /* otherwise, scp points to the parent directory. Do a lookup, and
5978 * truncate the file if we find it, otherwise we create the file.
5980 if (!lastNamep) lastNamep = pathp;
5983 if (!smb_IsLegalFilename(lastNamep))
5984 return CM_ERROR_BADNTFILENAME;
5986 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
5987 #ifdef DEBUG_VERBOSE
5990 hexp = osi_HexifyString( lastNamep );
5991 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5996 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5997 if (code && code != CM_ERROR_NOSUCHFILE) {
5998 cm_ReleaseSCache(dscp);
5999 cm_ReleaseUser(userp);
6003 /* if we get here, if code is 0, the file exists and is represented by
6004 * scp. Otherwise, we have to create it.
6008 /* oops, file shouldn't be there */
6009 cm_ReleaseSCache(dscp);
6010 cm_ReleaseSCache(scp);
6011 cm_ReleaseUser(userp);
6012 return CM_ERROR_EXISTS;
6015 setAttr.mask = CM_ATTRMASK_LENGTH;
6016 setAttr.length.LowPart = 0;
6017 setAttr.length.HighPart = 0;
6018 code = cm_SetAttr(scp, &setAttr, userp, &req);
6021 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6022 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6023 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6025 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6026 smb_NotifyChange(FILE_ACTION_ADDED,
6027 FILE_NOTIFY_CHANGE_FILE_NAME,
6028 dscp, lastNamep, NULL, TRUE);
6029 if (!excl && code == CM_ERROR_EXISTS) {
6030 /* not an exclusive create, and someone else tried
6031 * creating it already, then we open it anyway. We
6032 * don't bother retrying after this, since if this next
6033 * fails, that means that the file was deleted after
6034 * we started this call.
6036 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6039 setAttr.mask = CM_ATTRMASK_LENGTH;
6040 setAttr.length.LowPart = 0;
6041 setAttr.length.HighPart = 0;
6042 code = cm_SetAttr(scp, &setAttr, userp, &req);
6047 /* we don't need this any longer */
6048 cm_ReleaseSCache(dscp);
6051 /* something went wrong creating or truncating the file */
6052 if (scp) cm_ReleaseSCache(scp);
6053 cm_ReleaseUser(userp);
6057 /* make sure we only open files */
6058 if (scp->fileType != CM_SCACHETYPE_FILE) {
6059 cm_ReleaseSCache(scp);
6060 cm_ReleaseUser(userp);
6061 return CM_ERROR_ISDIR;
6064 /* now all we have to do is open the file itself */
6065 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6068 /* save a pointer to the vnode */
6071 /* always create it open for read/write */
6072 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6074 smb_ReleaseFID(fidp);
6076 smb_SetSMBParm(outp, 0, fidp->fid);
6077 smb_SetSMBDataLength(outp, 0);
6079 cm_Open(scp, 0, userp);
6081 cm_ReleaseUser(userp);
6082 /* leave scp held since we put it in fidp->scp */
6086 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6099 fd = smb_GetSMBParm(inp, 0);
6100 whence = smb_GetSMBParm(inp, 1);
6101 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6103 /* try to find the file descriptor */
6104 fd = smb_ChainFID(fd, inp);
6105 fidp = smb_FindFID(vcp, fd, 0);
6106 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6107 return CM_ERROR_BADFD;
6110 userp = smb_GetUser(vcp, inp);
6112 lock_ObtainMutex(&fidp->mx);
6114 lock_ObtainMutex(&scp->mx);
6115 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6116 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6119 /* offset from current offset */
6120 offset += fidp->offset;
6122 else if (whence == 2) {
6123 /* offset from current EOF */
6124 offset += scp->length.LowPart;
6126 fidp->offset = offset;
6127 smb_SetSMBParm(outp, 0, offset & 0xffff);
6128 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6129 smb_SetSMBDataLength(outp, 0);
6131 lock_ReleaseMutex(&scp->mx);
6132 lock_ReleaseMutex(&fidp->mx);
6133 smb_ReleaseFID(fidp);
6134 cm_ReleaseUser(userp);
6138 /* dispatch all of the requests received in a packet. Due to chaining, this may
6139 * be more than one request.
6141 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6142 NCB *ncbp, raw_write_cont_t *rwcp)
6146 unsigned long code = 0;
6147 unsigned char *outWctp;
6148 int nparms; /* # of bytes of parameters */
6150 int nbytes; /* bytes of data, excluding count */
6153 unsigned short errCode;
6154 unsigned long NTStatus;
6156 unsigned char errClass;
6157 unsigned int oldGen;
6158 DWORD oldTime, newTime;
6160 /* get easy pointer to the data */
6161 smbp = (smb_t *) inp->data;
6163 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6164 /* setup the basic parms for the initial request in the packet */
6165 inp->inCom = smbp->com;
6166 inp->wctp = &smbp->wct;
6168 inp->ncb_length = ncbp->ncb_length;
6173 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6174 /* log it and discard it */
6179 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6180 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6182 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6183 1, ncbp->ncb_length, ptbuf, inp);
6184 DeregisterEventSource(h);
6186 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6191 /* We are an ongoing op */
6192 thrd_Increment(&ongoingOps);
6194 /* set up response packet for receiving output */
6195 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6196 smb_FormatResponsePacket(vcp, inp, outp);
6197 outWctp = outp->wctp;
6199 /* Remember session generation number and time */
6200 oldGen = sessionGen;
6201 oldTime = GetCurrentTime();
6203 while (inp->inCom != 0xff) {
6204 dp = &smb_dispatchTable[inp->inCom];
6206 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6207 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6208 code = outp->resumeCode;
6212 /* process each request in the packet; inCom, wctp and inCount
6213 * are already set up.
6215 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6218 /* now do the dispatch */
6219 /* start by formatting the response record a little, as a default */
6220 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6222 outWctp[1] = 0xff; /* no operation */
6223 outWctp[2] = 0; /* padding */
6228 /* not a chained request, this is a more reasonable default */
6229 outWctp[0] = 0; /* wct of zero */
6230 outWctp[1] = 0; /* and bcc (word) of zero */
6234 /* once set, stays set. Doesn't matter, since we never chain
6235 * "no response" calls.
6237 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6241 /* we have a recognized operation */
6243 if (inp->inCom == 0x1d)
6245 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6248 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
6249 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
6250 code = (*(dp->procp)) (vcp, inp, outp);
6251 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6252 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6254 if ( code == CM_ERROR_BADSMB ||
6255 code == CM_ERROR_BADOP )
6257 #endif /* LOG_PACKET */
6260 if (oldGen != sessionGen) {
6265 newTime = GetCurrentTime();
6266 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6267 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6268 newTime - oldTime, ncbp->ncb_length);
6270 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6271 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6272 DeregisterEventSource(h);
6274 osi_Log1(smb_logp, "Pkt straddled session startup, "
6275 "ncb length %d", ncbp->ncb_length);
6279 /* bad opcode, fail the request, after displaying it */
6280 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6283 #endif /* LOG_PACKET */
6287 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6288 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6289 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6290 if (code == IDCANCEL)
6294 code = CM_ERROR_BADOP;
6297 /* catastrophic failure: log as much as possible */
6298 if (code == CM_ERROR_BADSMB) {
6305 "Invalid SMB, ncb_length %d",
6308 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6309 sprintf(s, "Invalid SMB message, length %d",
6312 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6313 1, ncbp->ncb_length, ptbuf, smbp);
6314 DeregisterEventSource(h);
6317 #endif /* LOG_PACKET */
6319 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6322 code = CM_ERROR_INVAL;
6325 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6326 thrd_Decrement(&ongoingOps);
6331 /* now, if we failed, turn the current response into an empty
6332 * one, and fill in the response packet's error code.
6335 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6336 smb_MapNTError(code, &NTStatus);
6337 outWctp = outp->wctp;
6338 smbp = (smb_t *) &outp->data;
6339 if (code != CM_ERROR_PARTIALWRITE
6340 && code != CM_ERROR_BUFFERTOOSMALL
6341 && code != CM_ERROR_GSSCONTINUE) {
6342 /* nuke wct and bcc. For a partial
6343 * write or an in-process authentication handshake,
6344 * assume they're OK.
6350 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6351 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6352 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6353 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6354 smbp->flg2 |= 0x4000;
6358 smb_MapCoreError(code, vcp, &errCode, &errClass);
6359 outWctp = outp->wctp;
6360 smbp = (smb_t *) &outp->data;
6361 if (code != CM_ERROR_PARTIALWRITE) {
6362 /* nuke wct and bcc. For a partial
6363 * write, assume they're OK.
6369 smbp->errLow = (unsigned char) (errCode & 0xff);
6370 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6371 smbp->rcls = errClass;
6374 } /* error occurred */
6376 /* if we're here, we've finished one request. Look to see if
6377 * this is a chained opcode. If it is, setup things to process
6378 * the chained request, and setup the output buffer to hold the
6379 * chained response. Start by finding the next input record.
6381 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6382 break; /* not a chained req */
6383 tp = inp->wctp; /* points to start of last request */
6384 /* in a chained request, the first two
6385 * parm fields are required, and are
6386 * AndXCommand/AndXReserved and
6388 if (tp[0] < 2) break;
6389 if (tp[1] == 0xff) break; /* no more chained opcodes */
6391 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6394 /* and now append the next output request to the end of this
6395 * last request. Begin by finding out where the last response
6396 * ends, since that's where we'll put our new response.
6398 outWctp = outp->wctp; /* ptr to out parameters */
6399 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6400 nparms = outWctp[0] << 1;
6401 tp = outWctp + nparms + 1; /* now points to bcc field */
6402 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6403 tp += 2 /* for the count itself */ + nbytes;
6404 /* tp now points to the new output record; go back and patch the
6405 * second parameter (off2) to point to the new record.
6407 temp = (unsigned int)tp - ((unsigned int) outp->data);
6408 outWctp[3] = (unsigned char) (temp & 0xff);
6409 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6410 outWctp[2] = 0; /* padding */
6411 outWctp[1] = inp->inCom; /* next opcode */
6413 /* finally, setup for the next iteration */
6416 } /* while loop over all requests in the packet */
6418 /* done logging out, turn off logging-out flag */
6419 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6420 vcp->justLoggedOut = NULL;
6423 free(loggedOutName);
6424 loggedOutName = NULL;
6425 smb_ReleaseUID(loggedOutUserp);
6426 loggedOutUserp = NULL;
6430 /* now send the output packet, and return */
6432 smb_SendPacket(vcp, outp);
6433 thrd_Decrement(&ongoingOps);
6435 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6437 smb_ReleaseVC(active_vcp);
6439 "Replacing active_vcp %x with %x", active_vcp, vcp);
6443 last_msg_time = GetCurrentTime();
6445 else if (active_vcp == vcp) {
6446 smb_ReleaseVC(active_vcp);
6454 /* Wait for Netbios() calls to return, and make the results available to server
6455 * threads. Note that server threads can't wait on the NCBevents array
6456 * themselves, because NCB events are manual-reset, and the servers would race
6457 * each other to reset them.
6459 void smb_ClientWaiter(void *parmp)
6465 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6467 if (code == WAIT_OBJECT_0) {
6468 if (smbShutdownFlag == 1)
6474 /* error checking */
6475 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6477 int abandonIdx = code - WAIT_ABANDONED_0;
6478 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6481 if (code == WAIT_IO_COMPLETION)
6483 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6487 if (code == WAIT_TIMEOUT)
6489 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6492 if (code == WAIT_FAILED)
6494 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6497 idx = code - WAIT_OBJECT_0;
6499 /* check idx range! */
6500 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6502 /* this is fatal - log as much as possible */
6503 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6507 thrd_ResetEvent(NCBevents[idx]);
6508 thrd_SetEvent(NCBreturns[0][idx]);
6514 * Try to have one NCBRECV request waiting for every live session. Not more
6515 * than one, because if there is more than one, it's hard to handle Write Raw.
6517 void smb_ServerWaiter(void *parmp)
6520 int idx_session, idx_NCB;
6528 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6530 if (code == WAIT_OBJECT_0) {
6531 if ( smbShutdownFlag == 1 )
6537 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6539 int abandonIdx = code - WAIT_ABANDONED_0;
6540 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6543 if (code == WAIT_IO_COMPLETION)
6545 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6549 if (code == WAIT_TIMEOUT)
6551 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6554 if (code == WAIT_FAILED)
6556 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6559 idx_session = code - WAIT_OBJECT_0;
6561 /* check idx range! */
6562 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6564 /* this is fatal - log as much as possible */
6565 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6571 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6573 if (code == WAIT_OBJECT_0) {
6574 if ( smbShutdownFlag == 1 )
6580 /* error checking */
6581 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6583 int abandonIdx = code - WAIT_ABANDONED_0;
6584 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6587 if (code == WAIT_IO_COMPLETION)
6589 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6593 if (code == WAIT_TIMEOUT)
6595 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6598 if (code == WAIT_FAILED)
6600 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6603 idx_NCB = code - WAIT_OBJECT_0;
6605 /* check idx range! */
6606 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6608 /* this is fatal - log as much as possible */
6609 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6613 /* Link them together */
6614 NCBsessions[idx_NCB] = idx_session;
6617 ncbp = NCBs[idx_NCB];
6618 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6619 ncbp->ncb_command = NCBRECV | ASYNCH;
6620 ncbp->ncb_lana_num = lanas[idx_session];
6622 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6623 ncbp->ncb_event = NCBevents[idx_NCB];
6624 ncbp->ncb_length = SMB_PACKETSIZE;
6627 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6628 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6629 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6630 ncbp->ncb_length = SMB_PACKETSIZE;
6631 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6632 Netbios(ncbp, dos_ncb);
6638 * The top level loop for handling SMB request messages. Each server thread
6639 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6640 * NCB and buffer for the incoming request are loaned to us.
6642 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6643 * to immediately send a request for the rest of the data. This must come
6644 * before any other traffic for that session, so we delay setting the session
6645 * event until that data has come in.
6647 void smb_Server(VOID *parmp)
6649 int myIdx = (int) parmp;
6653 smb_packet_t *outbufp;
6655 int idx_NCB, idx_session;
6657 smb_vc_t *vcp = NULL;
6664 outbufp = GetPacket();
6665 outbufp->ncbp = outncbp;
6668 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6671 /* terminate silently if shutdown flag is set */
6672 if (code == WAIT_OBJECT_0) {
6673 if (smbShutdownFlag == 1) {
6674 thrd_SetEvent(smb_ServerShutdown[myIdx]);
6680 /* error checking */
6681 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6683 int abandonIdx = code - WAIT_ABANDONED_0;
6684 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6687 if (code == WAIT_IO_COMPLETION)
6689 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6693 if (code == WAIT_TIMEOUT)
6695 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6698 if (code == WAIT_FAILED)
6700 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6703 idx_NCB = code - WAIT_OBJECT_0;
6705 /* check idx range! */
6706 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6708 /* this is fatal - log as much as possible */
6709 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6713 ncbp = NCBs[idx_NCB];
6715 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6717 idx_session = NCBsessions[idx_NCB];
6718 rc = ncbp->ncb_retcode;
6720 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6721 osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6724 case NRC_GOODRET: break;
6727 /* Can this happen? Or is it just my
6734 /* Client closed session */
6735 if (reportSessionStartups)
6737 osi_Log1(smb_logp, "session [ %d ] closed", idx_session);
6739 dead_sessions[idx_session] = TRUE;
6742 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6743 /* Should also release vcp. [done] 2004-05-11 jaltman
6745 * sanity check that all TID's are gone.
6747 * TODO: check if we could use LSNs[idx_session] instead,
6748 * also cleanup after dead vcp
6753 "dead_vcp already set, %x",
6755 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6757 "setting dead_vcp %x, user struct %x",
6761 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6763 if (vcp->justLoggedOut) {
6765 loggedOutTime = vcp->logoffTime;
6766 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
6767 loggedOutUserp = vcp->justLoggedOut;
6768 lock_ObtainWrite(&smb_rctLock);
6769 loggedOutUserp->refCount++;
6770 lock_ReleaseWrite(&smb_rctLock);
6776 /* Treat as transient error */
6783 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6784 sprintf(s, "SMB message incomplete, length %d",
6787 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6789 ncbp->ncb_length, ptbuf,
6791 DeregisterEventSource(h);
6794 "dispatch smb recv failed, message incomplete, ncb_length %d",
6797 "SMB message incomplete, "
6798 "length %d", ncbp->ncb_length);
6801 * We used to discard the packet.
6802 * Instead, try handling it normally.
6810 /* A weird error code. Log it, sleep, and
6812 if (vcp && vcp->errorCount++ > 3) {
6813 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6814 dead_sessions[idx_session] = TRUE;
6818 thrd_SetEvent(SessionEvents[idx_session]);
6823 /* Success, so now dispatch on all the data in the packet */
6825 smb_concurrentCalls++;
6826 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6827 smb_maxObsConcurrentCalls = smb_concurrentCalls;
6831 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6833 * If at this point vcp is NULL (implies that packet was invalid)
6834 * then we are in big trouble. This means either :
6835 * a) we have the wrong NCB.
6836 * b) Netbios screwed up the call.
6837 * Obviously this implies that
6838 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
6839 * lanas[idx_session] != ncbp->ncb_lana_num )
6840 * Either way, we can't do anything with this packet.
6841 * Log, sleep and resume.
6850 "LSNs[idx_session]=[%d],"
6851 "lanas[idx_session]=[%d],"
6852 "ncbp->ncb_lsn=[%d],"
6853 "ncbp->ncb_lana_num=[%d]",
6857 ncbp->ncb_lana_num);
6861 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6863 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6864 DeregisterEventSource(h);
6867 /* Also log in the trace log. */
6868 osi_Log4(smb_logp, "Server: BAD VCP!"
6869 "LSNs[idx_session]=[%d],"
6870 "lanas[idx_session]=[%d],"
6871 "ncbp->ncb_lsn=[%d],"
6872 "ncbp->ncb_lana_num=[%d]",
6876 ncbp->ncb_lana_num);
6878 /* thrd_Sleep(1000); Don't bother sleeping */
6879 thrd_SetEvent(SessionEvents[idx_session]);
6880 smb_concurrentCalls--;
6885 vcp->errorCount = 0;
6886 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6888 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6889 /* copy whole packet to virtual memory */
6890 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6892 bufp->dos_pkt / 16, bufp);*/
6894 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6896 smbp = (smb_t *)bufp->data;
6899 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6903 if (smbp->com == 0x1d) {
6904 /* Special handling for Write Raw */
6905 raw_write_cont_t rwc;
6906 EVENT_HANDLE rwevent;
6907 char eventName[MAX_PATH];
6909 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6910 if (rwc.code == 0) {
6911 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6912 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6913 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6914 ncbp->ncb_command = NCBRECV | ASYNCH;
6915 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6916 ncbp->ncb_lana_num = vcp->lana;
6917 ncbp->ncb_buffer = rwc.buf;
6918 ncbp->ncb_length = 65535;
6919 ncbp->ncb_event = rwevent;
6923 Netbios(ncbp, dos_ncb);
6925 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6926 thrd_CloseHandle(rwevent);
6928 thrd_SetEvent(SessionEvents[idx_session]);
6930 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6932 else if (smbp->com == 0xa0) {
6934 * Serialize the handling for NT Transact
6937 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6938 thrd_SetEvent(SessionEvents[idx_session]);
6940 thrd_SetEvent(SessionEvents[idx_session]);
6941 /* TODO: what else needs to be serialized? */
6942 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6944 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6946 __except( smb_ServerExceptionFilter() ) {
6950 smb_concurrentCalls--;
6953 thrd_SetEvent(NCBavails[idx_NCB]);
6960 * Exception filter for the server threads. If an exception occurs in the
6961 * dispatch routines, which is where exceptions are most common, then do a
6962 * force trace and give control to upstream exception handlers. Useful for
6965 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6966 DWORD smb_ServerExceptionFilter(void) {
6967 /* While this is not the best time to do a trace, if it succeeds, then
6968 * we have a trace (assuming tracing was enabled). Otherwise, this should
6969 * throw a second exception.
6974 ptbuf[0] = "Unhandled exception forcing trace";
6976 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6978 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6979 DeregisterEventSource(h);
6982 afsd_ForceTrace(TRUE);
6983 buf_ForceTrace(TRUE);
6984 return EXCEPTION_CONTINUE_SEARCH;
6989 * Create a new NCB and associated events, packet buffer, and "space" buffer.
6990 * If the number of server threads is M, and the number of live sessions is
6991 * N, then the number of NCB's in use at any time either waiting for, or
6992 * holding, received messages is M + N, so that is how many NCB's get created.
6994 void InitNCBslot(int idx)
6996 struct smb_packet *bufp;
6997 EVENT_HANDLE retHandle;
6999 char eventName[MAX_PATH];
7001 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7003 NCBs[idx] = GetNCB();
7004 sprintf(eventName,"NCBavails[%d]", idx);
7005 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7006 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7007 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7009 sprintf(eventName,"NCBevents[%d]", idx);
7010 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7011 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7012 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7014 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7015 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7016 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7017 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7018 for (i=0; i<smb_NumServerThreads; i++)
7019 NCBreturns[i][idx] = retHandle;
7021 bufp->spacep = cm_GetSpace();
7025 /* listen for new connections */
7026 void smb_Listener(void *parmp)
7034 char rname[NCBNAMSZ+1];
7035 char cname[MAX_COMPUTERNAME_LENGTH+1];
7036 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7041 int lana = (int) parmp;
7045 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7048 /* retrieve computer name */
7049 GetComputerName(cname, &cnamelen);
7053 memset(ncbp, 0, sizeof(NCB));
7056 ncbp->ncb_command = NCBLISTEN;
7057 ncbp->ncb_rto = 0; /* No receive timeout */
7058 ncbp->ncb_sto = 0; /* No send timeout */
7060 /* pad out with spaces instead of null termination */
7061 len = strlen(smb_localNamep);
7062 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7063 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7065 strcpy(ncbp->ncb_callname, "*");
7066 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7068 ncbp->ncb_lana_num = lana;
7071 code = Netbios(ncbp);
7073 code = Netbios(ncbp, dos_ncb);
7082 /* terminate silently if shutdown flag is set */
7083 if (smbShutdownFlag == 1) {
7092 "NCBLISTEN lana=%d failed with code %d",
7093 ncbp->ncb_lana_num, code);
7095 "Client exiting due to network failure. Please restart client.\n");
7099 "Client exiting due to network failure. Please restart client.\n"
7100 "NCBLISTEN lana=%d failed with code %d",
7101 ncbp->ncb_lana_num, code);
7103 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7104 MB_OK|MB_SERVICE_NOTIFICATION);
7105 osi_assert(tbuffer);
7108 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7109 ncbp->ncb_lana_num, code);
7110 fprintf(stderr, "\nClient exiting due to network failure "
7111 "(possibly due to power-saving mode)\n");
7112 fprintf(stderr, "Please restart client.\n");
7113 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7117 /* check for remote conns */
7118 /* first get remote name and insert null terminator */
7119 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7120 for (i=NCBNAMSZ; i>0; i--) {
7121 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7127 /* compare with local name */
7129 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7130 flags |= SMB_VCFLAG_REMOTECONN;
7132 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7134 lock_ObtainMutex(&smb_ListenerLock);
7136 /* New generation */
7139 /* Log session startup */
7141 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7143 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7144 #endif /* NOTSERVICE */
7145 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7146 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7148 if (reportSessionStartups) {
7154 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7155 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7157 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7159 DeregisterEventSource(h);
7162 fprintf(stderr, "%s: New session %d starting from host %s\n",
7163 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7167 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7168 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7171 /* now ncbp->ncb_lsn is the connection ID */
7172 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7173 vcp->flags |= flags;
7174 strcpy(vcp->rname, rname);
7176 /* Allocate slot in session arrays */
7177 /* Re-use dead session if possible, otherwise add one more */
7178 /* But don't look at session[0], it is reserved */
7179 for (i = 1; i < numSessions; i++) {
7180 if (dead_sessions[i]) {
7181 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7182 dead_sessions[i] = FALSE;
7187 /* assert that we do not exceed the maximum number of sessions or NCBs.
7188 * we should probably want to wait for a session to be freed in case
7192 osi_assert(i < Sessionmax - 1);
7193 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7195 LSNs[i] = ncbp->ncb_lsn;
7196 lanas[i] = ncbp->ncb_lana_num;
7198 if (i == numSessions) {
7199 /* Add new NCB for new session */
7200 char eventName[MAX_PATH];
7202 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7204 InitNCBslot(numNCBs);
7206 thrd_SetEvent(NCBavails[0]);
7207 thrd_SetEvent(NCBevents[0]);
7208 for (j = 0; j < smb_NumServerThreads; j++)
7209 thrd_SetEvent(NCBreturns[j][0]);
7210 /* Also add new session event */
7211 sprintf(eventName, "SessionEvents[%d]", i);
7212 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7213 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7214 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7216 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7217 thrd_SetEvent(SessionEvents[0]);
7219 thrd_SetEvent(SessionEvents[i]);
7222 lock_ReleaseMutex(&smb_ListenerLock);
7224 } /* dispatch while loop */
7227 /* initialize Netbios */
7228 void smb_NetbiosInit()
7234 int i, lana, code, l;
7236 int delname_tried=0;
7239 OSVERSIONINFO Version;
7241 /* AFAIK, this is the default for the ms loopback adapter.*/
7242 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
7243 /*******************************************************************/
7245 /* Get the version of Windows */
7246 memset(&Version, 0x00, sizeof(Version));
7247 Version.dwOSVersionInfoSize = sizeof(Version);
7248 GetVersionEx(&Version);
7250 /* setup the NCB system */
7253 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7257 if (smb_LANadapter == -1) {
7258 ncbp->ncb_command = NCBENUM;
7259 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7260 ncbp->ncb_length = sizeof(lana_list);
7261 code = Netbios(ncbp);
7263 sprintf(s, "Netbios NCBENUM error code %d", code);
7264 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7265 osi_panic(s, __FILE__, __LINE__);
7269 lana_list.length = 1;
7270 lana_list.lana[0] = smb_LANadapter;
7273 for (i = 0; i < lana_list.length; i++) {
7274 /* reset the adaptor: in Win32, this is required for every process, and
7275 * acts as an init call, not as a real hardware reset.
7277 ncbp->ncb_command = NCBRESET;
7278 ncbp->ncb_callname[0] = 100;
7279 ncbp->ncb_callname[2] = 100;
7280 ncbp->ncb_lana_num = lana_list.lana[i];
7281 code = Netbios(ncbp);
7283 code = ncbp->ncb_retcode;
7285 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7286 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7287 lana_list.lana[i] = 255; /* invalid lana */
7289 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7290 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7294 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7295 we will just fake the LANA list */
7296 if (smb_LANadapter == -1) {
7297 for (i = 0; i < 8; i++)
7298 lana_list.lana[i] = i;
7299 lana_list.length = 8;
7302 lana_list.length = 1;
7303 lana_list.lana[0] = smb_LANadapter;
7307 /* and declare our name so we can receive connections */
7308 memset(ncbp, 0, sizeof(*ncbp));
7309 len=lstrlen(smb_localNamep);
7310 memset(smb_sharename,' ',NCBNAMSZ);
7311 memcpy(smb_sharename,smb_localNamep,len);
7312 sprintf(s, "lana_list.length %d", lana_list.length);
7313 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7315 /* Keep the name so we can unregister it later */
7316 for (l = 0; l < lana_list.length; l++) {
7317 lana = lana_list.lana[l];
7319 ncbp->ncb_command = NCBADDNAME;
7320 ncbp->ncb_lana_num = lana;
7321 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7323 code = Netbios(ncbp);
7325 code = Netbios(ncbp, dos_ncb);
7328 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7329 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7331 char name[NCBNAMSZ+1];
7333 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7334 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7337 if (code == 0) code = ncbp->ncb_retcode;
7339 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7341 /* we only use one LANA with djgpp */
7342 lana_list.lana[0] = lana;
7343 lana_list.length = 1;
7347 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7348 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7349 if (code == NRC_BRIDGE) { /* invalid LANA num */
7350 lana_list.lana[l] = 255;
7353 else if (code == NRC_DUPNAME) {
7354 osi_Log0(smb_logp, "Name already exists; try to delete it");
7355 memset(ncbp, 0, sizeof(*ncbp));
7356 ncbp->ncb_command = NCBDELNAME;
7357 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7358 ncbp->ncb_lana_num = lana;
7360 code = Netbios(ncbp);
7362 code = Netbios(ncbp, dos_ncb);
7365 code = ncbp->ncb_retcode;
7367 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7368 osi_Log0(smb_logp, s);
7370 if (code != 0 || delname_tried) {
7371 lana_list.lana[l] = 255;
7373 else if (code == 0) {
7374 if (!delname_tried) {
7382 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7383 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7384 lana_list.lana[l] = 255; /* invalid lana */
7385 osi_panic(s, __FILE__, __LINE__);
7389 lana_found = 1; /* at least one worked */
7396 osi_assert(lana_list.length >= 0);
7398 sprintf(s, "No valid LANA numbers found!");
7399 osi_panic(s, __FILE__, __LINE__);
7402 /* we're done with the NCB now */
7406 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7423 EVENT_HANDLE retHandle;
7424 char eventName[MAX_PATH];
7427 smb_MBfunc = aMBfunc;
7431 smb_LANadapter = LANadapt;
7433 /* Initialize smb_localZero */
7434 myTime.tm_isdst = -1; /* compute whether on DST or not */
7435 myTime.tm_year = 70;
7441 smb_localZero = mktime(&myTime);
7443 /* Initialize kludge-GMT */
7444 smb_CalculateNowTZ();
7446 #ifdef AFS_FREELANCE_CLIENT
7447 /* Make sure the root.afs volume has the correct time */
7448 cm_noteLocalMountPointChange();
7451 /* initialize the remote debugging log */
7454 /* remember the name */
7455 len = strlen(snamep);
7456 smb_localNamep = malloc(len+1);
7457 strcpy(smb_localNamep, snamep);
7458 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7460 /* and the global lock */
7461 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7462 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7464 /* Raw I/O data structures */
7465 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7467 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7469 /* 4 Raw I/O buffers */
7471 smb_RawBufs = calloc(65536,1);
7472 *((char **)smb_RawBufs) = NULL;
7473 for (i=0; i<3; i++) {
7474 char *rawBuf = calloc(65536,1);
7475 *((char **)rawBuf) = smb_RawBufs;
7476 smb_RawBufs = rawBuf;
7479 npar = 65536 >> 4; /* number of paragraphs */
7480 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7482 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7484 osi_panic("",__FILE__,__LINE__);
7487 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7490 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7492 _farpokel(_dos_ds, smb_RawBufs, NULL);
7493 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7494 npar = 65536 >> 4; /* number of paragraphs */
7495 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7497 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7499 osi_panic("",__FILE__,__LINE__);
7502 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7505 rawBuf = (seg * 16) + 0; /* DOS physical address */
7506 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7507 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7508 smb_RawBufs = rawBuf;
7512 /* global free lists */
7513 smb_ncbFreeListp = NULL;
7514 smb_packetFreeListp = NULL;
7518 /* Initialize listener and server structures */
7520 memset(dead_sessions, 0, sizeof(dead_sessions));
7521 sprintf(eventName, "SessionEvents[0]");
7522 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7523 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7524 afsi_log("Event Object Already Exists: %s", eventName);
7526 smb_NumServerThreads = nThreads;
7527 sprintf(eventName, "NCBavails[0]");
7528 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7529 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7530 afsi_log("Event Object Already Exists: %s", eventName);
7531 sprintf(eventName, "NCBevents[0]");
7532 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7533 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7534 afsi_log("Event Object Already Exists: %s", eventName);
7535 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7536 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7537 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7538 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7539 afsi_log("Event Object Already Exists: %s", eventName);
7540 for (i = 0; i < smb_NumServerThreads; i++) {
7541 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7542 NCBreturns[i][0] = retHandle;
7545 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
7546 for (i = 0; i < smb_NumServerThreads; i++) {
7547 sprintf(eventName, "smb_ServerShutdown[%d]", i);
7548 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7549 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7550 afsi_log("Event Object Already Exists: %s", eventName);
7553 for (i = 1; i <= nThreads; i++)
7555 numNCBs = nThreads + 1;
7557 /* Initialize dispatch table */
7558 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7559 /* Prepare the table for unknown operations */
7560 for(i=0; i<= SMB_NOPCODES; i++) {
7561 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7563 /* Fill in the ones we do know */
7564 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7565 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7566 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7567 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7568 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7569 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7570 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7571 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7572 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7573 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7574 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7575 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7576 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7577 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7578 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7579 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7580 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7581 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7582 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7583 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7584 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7585 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7586 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7587 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7588 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7589 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7590 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7591 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7592 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7593 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7594 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7595 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7596 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7597 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7598 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7599 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7600 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7601 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7602 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7603 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7604 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7605 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7606 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7607 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7608 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7609 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7610 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7611 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7612 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7613 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7614 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7615 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7616 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7617 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7618 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7619 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7620 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
7621 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
7622 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
7623 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7624 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7625 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7626 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7627 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7628 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
7629 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
7630 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
7631 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
7632 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
7633 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
7634 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
7635 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
7637 /* setup tran 2 dispatch table */
7638 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7639 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7640 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7641 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7642 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7643 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7644 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7645 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7646 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7647 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7648 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7649 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7650 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7651 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
7652 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
7653 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2GetDFSReferral;
7654 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2ReportDFSInconsistency;
7656 /* setup the rap dispatch table */
7657 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
7658 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
7659 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
7660 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
7661 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
7665 /* if we are doing SMB authentication we have register outselves as a logon process */
7666 if (smb_authType != SMB_AUTH_NONE) {
7668 LSA_STRING afsProcessName;
7669 LSA_OPERATIONAL_MODE dummy; /*junk*/
7671 afsProcessName.Buffer = "OpenAFSClientDaemon";
7672 afsProcessName.Length = strlen(afsProcessName.Buffer);
7673 afsProcessName.MaximumLength = afsProcessName.Length + 1;
7675 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
7677 if (nts == STATUS_SUCCESS) {
7678 LSA_STRING packageName;
7679 /* we are registered. Find out the security package id */
7680 packageName.Buffer = MSV1_0_PACKAGE_NAME;
7681 packageName.Length = strlen(packageName.Buffer);
7682 packageName.MaximumLength = packageName.Length + 1;
7683 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
7684 if (nts == STATUS_SUCCESS) {
7685 smb_lsaLogonOrigin.Buffer = "OpenAFS";
7686 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
7687 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
7689 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
7692 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
7695 if (nts != STATUS_SUCCESS) {
7696 /* something went wrong. We report the error and revert back to no authentication
7697 because we can't perform any auth requests without a successful lsa handle
7698 or sec package id. */
7699 afsi_log("Reverting to NO SMB AUTH");
7700 smb_authType = SMB_AUTH_NONE;
7703 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
7704 * time prevents the failure of authentication when logged into Windows with an
7705 * external Kerberos principal mapped to a local account.
7707 else if ( smb_authType == SMB_AUTH_EXTENDED) {
7708 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
7709 * then the only option is NTLMSSP anyway; so just fallback.
7714 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
7715 if (secBlobLength == 0) {
7716 smb_authType = SMB_AUTH_NTLM;
7717 afsi_log("Reverting to SMB AUTH NTLM");
7726 /* Now get ourselves a domain name. */
7727 /* For now we are using the local computer name as the domain name.
7728 * It is actually the domain for local logins, and we are acting as
7729 * a local SMB server.
7731 bufsize = sizeof(smb_ServerDomainName) - 1;
7732 GetComputerName(smb_ServerDomainName, &bufsize);
7733 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
7734 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
7737 /* Start listeners, waiters, servers, and daemons */
7739 for (i = 0; i < lana_list.length; i++) {
7740 if (lana_list.lana[i] == 255) continue;
7741 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7742 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7743 osi_assert(phandle != NULL);
7744 thrd_CloseHandle(phandle);
7748 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7749 NULL, 0, &lpid, "smb_ClientWaiter");
7750 osi_assert(phandle != NULL);
7751 thrd_CloseHandle(phandle);
7754 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7755 NULL, 0, &lpid, "smb_ServerWaiter");
7756 osi_assert(phandle != NULL);
7757 thrd_CloseHandle(phandle);
7759 for (i=0; i<nThreads; i++) {
7760 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7761 (void *) i, 0, &lpid, "smb_Server");
7762 osi_assert(phandle != NULL);
7763 thrd_CloseHandle(phandle);
7766 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7767 NULL, 0, &lpid, "smb_Daemon");
7768 osi_assert(phandle != NULL);
7769 thrd_CloseHandle(phandle);
7771 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7772 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7773 osi_assert(phandle != NULL);
7774 thrd_CloseHandle(phandle);
7783 void smb_Shutdown(void)
7792 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7794 /* setup the NCB system */
7797 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7800 /* Block new sessions by setting shutdown flag */
7801 smbShutdownFlag = 1;
7803 /* Hang up all sessions */
7804 memset((char *)ncbp, 0, sizeof(NCB));
7805 for (i = 1; i < numSessions; i++)
7807 if (dead_sessions[i])
7810 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7811 ncbp->ncb_command = NCBHANGUP;
7812 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
7813 ncbp->ncb_lsn = LSNs[i];
7815 code = Netbios(ncbp);
7817 code = Netbios(ncbp, dos_ncb);
7819 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7820 if (code == 0) code = ncbp->ncb_retcode;
7822 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7823 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7827 /* Delete Netbios name */
7828 memset((char *)ncbp, 0, sizeof(NCB));
7829 for (i = 0; i < lana_list.length; i++) {
7830 if (lana_list.lana[i] == 255) continue;
7831 ncbp->ncb_command = NCBDELNAME;
7832 ncbp->ncb_lana_num = lana_list.lana[i];
7833 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7835 code = Netbios(ncbp);
7837 code = Netbios(ncbp, dos_ncb);
7840 code = ncbp->ncb_retcode;
7842 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7843 ncbp->ncb_lana_num, code);
7848 /* Trigger the shutdown of all SMB threads */
7849 for (i = 0; i < smb_NumServerThreads; i++)
7850 thrd_SetEvent(NCBreturns[i][0]);
7852 thrd_SetEvent(NCBevents[0]);
7853 thrd_SetEvent(SessionEvents[0]);
7854 thrd_SetEvent(NCBavails[0]);
7856 for (i = 0;i < smb_NumServerThreads; i++) {
7857 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], INFINITE);
7858 if (code == WAIT_OBJECT_0) {
7861 afsi_log("smb_Shutdown[%d] wait error",i);
7866 /* Get the UNC \\<servername>\<sharename> prefix. */
7867 char *smb_GetSharename()
7871 /* Make sure we have been properly initialized. */
7872 if (smb_localNamep == NULL)
7875 /* Allocate space for \\<servername>\<sharename>, plus the
7878 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7879 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7885 void smb_LogPacket(smb_packet_t *packet)
7888 unsigned length, paramlen, datalen, i, j;
7890 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7892 if (!packet) return;
7894 osi_Log0(smb_logp, "*** SMB packet dump ***");
7896 vp = (BYTE *) packet->data;
7898 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7899 length = paramlen + 2 + datalen;
7902 for (i=0;i < length; i+=16)
7904 memset( buf, ' ', 80 );
7909 buf[strlen(buf)] = ' ';
7911 cp = (BYTE*) buf + 7;
7913 for (j=0;j < 16 && (i+j)<length; j++)
7915 *(cp++) = hex[vp[i+j] >> 4];
7916 *(cp++) = hex[vp[i+j] & 0xf];
7926 for (j=0;j < 16 && (i+j)<length;j++)
7928 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7939 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
7942 osi_Log0(smb_logp, "*** End SMB packet dump ***");
7944 #endif /* LOG_PACKET */
7947 int smb_DumpVCP(FILE *outputFile, char *cookie)
7954 lock_ObtainRead(&smb_rctLock);
7956 sprintf(output, "begin dumping vcpsp\n");
7957 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7959 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
7963 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7964 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7965 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7967 sprintf(output, "begin dumping fidsp\n");
7968 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7970 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
7972 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",
7973 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
7974 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
7975 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7976 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7979 sprintf(output, "done dumping fidsp\n");
7980 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7983 sprintf(output, "done dumping vcpsp\n");
7984 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7986 lock_ReleaseRead(&smb_rctLock);