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";
367 return "S(10)_ReceiveTran2GetDfsReferral";
369 return "S(11)_ReceiveTran2ReportDfsInconsistency";
373 char * myCrt_RapDispatch(int i)
378 return "unknown RAP OP";
380 return "RAP(0)NetShareEnum";
382 return "RAP(1)NetShareGetInfo";
384 return "RAP(13)NetServerGetInfo";
386 return "RAP(63)NetWkStaGetInfo";
390 /* scache must be locked */
391 unsigned int smb_Attributes(cm_scache_t *scp)
395 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
396 scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
398 attrs = SMB_ATTR_DIRECTORY;
399 #ifdef SPECIAL_FOLDERS
400 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
401 #endif /* SPECIAL_FOLDERS */
406 * We used to mark a file RO if it was in an RO volume, but that
407 * turns out to be impolitic in NT. See defect 10007.
410 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
412 if ((scp->unixModeBits & 0222) == 0)
413 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
418 /* Check if the named file/dir is a dotfile/dotdir */
419 /* String pointed to by lastComp can have leading slashes, but otherwise should have
420 no other patch components */
421 unsigned int smb_IsDotFile(char *lastComp) {
424 /* skip over slashes */
425 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
430 /* nulls, curdir and parent dir doesn't count */
436 if(*(s+1) == '.' && !*(s + 2))
443 static int ExtractBits(WORD bits, short start, short len)
450 num = bits << (16 - end);
451 num = num >> ((16 - end) + start);
457 void ShowUnixTime(char *FuncName, time_t unixTime)
462 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
464 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
465 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
467 int day, month, year, sec, min, hour;
470 day = ExtractBits(wDate, 0, 5);
471 month = ExtractBits(wDate, 5, 4);
472 year = ExtractBits(wDate, 9, 7) + 1980;
474 sec = ExtractBits(wTime, 0, 5);
475 min = ExtractBits(wTime, 5, 6);
476 hour = ExtractBits(wTime, 11, 5);
478 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
479 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
485 /* Determine if we are observing daylight savings time */
486 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
488 TIME_ZONE_INFORMATION timeZoneInformation;
489 SYSTEMTIME utc, local, localDST;
491 /* Get the time zone info. NT uses this to calc if we are in DST. */
492 GetTimeZoneInformation(&timeZoneInformation);
494 /* Return the daylight bias */
495 *pDstBias = timeZoneInformation.DaylightBias;
497 /* Return the bias */
498 *pBias = timeZoneInformation.Bias;
500 /* Now determine if DST is being observed */
502 /* Get the UTC (GMT) time */
505 /* Convert UTC time to local time using the time zone info. If we are
506 observing DST, the calculated local time will include this.
508 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
510 /* Set the daylight bias to 0. The daylight bias is the amount of change
511 * in time that we use for daylight savings time. By setting this to 0
512 * we cause there to be no change in time during daylight savings time.
514 timeZoneInformation.DaylightBias = 0;
516 /* Convert the utc time to local time again, but this time without any
517 adjustment for daylight savings time.
519 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
521 /* If the two times are different, then it means that the localDST that
522 we calculated includes the daylight bias, and therefore we are
523 observing daylight savings time.
525 *pDST = localDST.wHour != local.wHour;
528 /* Determine if we are observing daylight savings time */
529 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
535 *pDstBias = -60; /* where can this be different? */
541 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
543 BOOL dst; /* Will be TRUE if observing DST */
544 LONG dstBias; /* Offset from local time if observing DST */
545 LONG bias; /* Offset from GMT for local time */
548 * This function will adjust the last write time to compensate
549 * for two bugs in the smb client:
551 * 1) During Daylight Savings Time, the LastWriteTime is ahead
552 * in time by the DaylightBias (ignoring the sign - the
553 * DaylightBias is always stored as a negative number). If
554 * the DaylightBias is -60, then the LastWriteTime will be
555 * ahead by 60 minutes.
557 * 2) If the local time zone is a positive offset from GMT, then
558 * the LastWriteTime will be the correct local time plus the
559 * Bias (ignoring the sign - a positive offset from GMT is
560 * always stored as a negative Bias). If the Bias is -120,
561 * then the LastWriteTime will be ahead by 120 minutes.
563 * These bugs can occur at the same time.
566 GetTimeZoneInfo(&dst, &dstBias, &bias);
568 /* First adjust for DST */
570 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
572 /* Now adjust for a positive offset from GMT (a negative bias). */
574 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
578 * Calculate the difference (in seconds) between local time and GMT.
579 * This enables us to convert file times to kludge-GMT.
585 struct tm gmt_tm, local_tm;
586 int days, hours, minutes, seconds;
589 gmt_tm = *(gmtime(&t));
590 local_tm = *(localtime(&t));
592 days = local_tm.tm_yday - gmt_tm.tm_yday;
593 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
595 /* There is a problem with DST immediately after the time change
596 * which may continue to exist until the machine is rebooted
598 - (local_tm.tm_isdst ? 1 : 0)
601 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
602 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
608 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
613 time_t ersatz_unixTime;
616 * Must use kludge-GMT instead of real GMT.
617 * kludge-GMT is computed by adding time zone difference to localtime.
620 * ltp = gmtime(&unixTime);
622 ersatz_unixTime = unixTime - smb_NowTZ;
623 ltp = localtime(&ersatz_unixTime);
625 /* if we fail, make up something */
628 localJunk.tm_year = 89 - 20;
629 localJunk.tm_mon = 4;
630 localJunk.tm_mday = 12;
631 localJunk.tm_hour = 0;
632 localJunk.tm_min = 0;
633 localJunk.tm_sec = 0;
636 stm.wYear = ltp->tm_year + 1900;
637 stm.wMonth = ltp->tm_mon + 1;
638 stm.wDayOfWeek = ltp->tm_wday;
639 stm.wDay = ltp->tm_mday;
640 stm.wHour = ltp->tm_hour;
641 stm.wMinute = ltp->tm_min;
642 stm.wSecond = ltp->tm_sec;
643 stm.wMilliseconds = 0;
645 SystemTimeToFileTime(&stm, largeTimep);
648 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
650 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
651 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
652 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
654 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
656 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
657 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
659 *ft = LargeIntegerMultiplyByLong(*ft, 60);
660 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
663 ut = ConvertLongToLargeInteger(unixTime);
664 ut = LargeIntegerMultiplyByLong(ut, 10000000);
665 *ft = LargeIntegerAdd(*ft, ut);
670 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
676 FileTimeToSystemTime(largeTimep, &stm);
678 lt.tm_year = stm.wYear - 1900;
679 lt.tm_mon = stm.wMonth - 1;
680 lt.tm_wday = stm.wDayOfWeek;
681 lt.tm_mday = stm.wDay;
682 lt.tm_hour = stm.wHour;
683 lt.tm_min = stm.wMinute;
684 lt.tm_sec = stm.wSecond;
687 save_timezone = _timezone;
688 _timezone += smb_NowTZ;
689 *unixTimep = mktime(<);
690 _timezone = save_timezone;
693 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
695 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
696 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
697 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
701 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
702 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
703 a = LargeIntegerMultiplyByLong(a, 60);
704 a = LargeIntegerMultiplyByLong(a, 10000000);
706 /* subtract it from ft */
707 a = LargeIntegerSubtract(*ft, a);
709 /* divide down to seconds */
710 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
714 void smb_SearchTimeFromUnixTime(time_t *dosTimep, time_t unixTime)
722 ltp = localtime((time_t*) &t);
724 /* if we fail, make up something */
727 localJunk.tm_year = 89 - 20;
728 localJunk.tm_mon = 4;
729 localJunk.tm_mday = 12;
730 localJunk.tm_hour = 0;
731 localJunk.tm_min = 0;
732 localJunk.tm_sec = 0;
735 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
736 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
737 *dosTimep = (dosDate<<16) | dosTime;
740 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
742 unsigned short dosDate;
743 unsigned short dosTime;
746 dosDate = (unsigned short) (searchTime & 0xffff);
747 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
749 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
750 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
751 localTm.tm_mday = (dosDate) & 0x1f;
752 localTm.tm_hour = (dosTime>>11) & 0x1f;
753 localTm.tm_min = (dosTime >> 5) & 0x3f;
754 localTm.tm_sec = (dosTime & 0x1f) * 2;
755 localTm.tm_isdst = -1; /* compute whether DST in effect */
757 *unixTimep = mktime(&localTm);
760 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
762 *dosUTimep = unixTime - smb_localZero;
765 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
768 *unixTimep = dosTime + smb_localZero;
770 /* dosTime seems to be already adjusted for GMT */
771 *unixTimep = dosTime;
775 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
779 lock_ObtainWrite(&smb_rctLock);
780 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
781 if (lsn == vcp->lsn && lana == vcp->lana) {
786 if (!vcp && (flags & SMB_FLAG_CREATE)) {
787 vcp = malloc(sizeof(*vcp));
788 memset(vcp, 0, sizeof(*vcp));
789 vcp->vcID = numVCs++;
793 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
794 vcp->nextp = smb_allVCsp;
796 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
801 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
802 /* We must obtain a challenge for extended auth
803 * in case the client negotiates smb v3
806 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
807 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
810 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
812 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
819 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
821 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
822 LsaFreeReturnBuffer(lsaResp);
825 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
827 lock_ReleaseWrite(&smb_rctLock);
831 int smb_IsStarMask(char *maskp)
836 for(i=0; i<11; i++) {
838 if (tc == '?' || tc == '*' || tc == '>') return 1;
843 void smb_ReleaseVC(smb_vc_t *vcp)
845 lock_ObtainWrite(&smb_rctLock);
846 osi_assert(vcp->refCount-- > 0);
847 lock_ReleaseWrite(&smb_rctLock);
850 void smb_HoldVC(smb_vc_t *vcp)
852 lock_ObtainWrite(&smb_rctLock);
854 lock_ReleaseWrite(&smb_rctLock);
857 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
861 lock_ObtainWrite(&smb_rctLock);
862 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
863 if (tid == tidp->tid) {
868 if (!tidp && (flags & SMB_FLAG_CREATE)) {
869 tidp = malloc(sizeof(*tidp));
870 memset(tidp, 0, sizeof(*tidp));
871 tidp->nextp = vcp->tidsp;
876 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
879 lock_ReleaseWrite(&smb_rctLock);
883 void smb_ReleaseTID(smb_tid_t *tidp)
892 lock_ObtainWrite(&smb_rctLock);
893 osi_assert(tidp->refCount-- > 0);
894 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
895 ltpp = &tidp->vcp->tidsp;
896 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
897 if (tp == tidp) break;
899 osi_assert(tp != NULL);
901 lock_FinalizeMutex(&tidp->mx);
902 userp = tidp->userp; /* remember to drop ref later */
905 lock_ReleaseWrite(&smb_rctLock);
907 cm_ReleaseUser(userp);
914 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
916 smb_user_t *uidp = NULL;
918 lock_ObtainWrite(&smb_rctLock);
919 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
920 if (uid == uidp->userID) {
922 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
923 (int)vcp, uidp->userID,
924 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
928 if (!uidp && (flags & SMB_FLAG_CREATE)) {
929 uidp = malloc(sizeof(*uidp));
930 memset(uidp, 0, sizeof(*uidp));
931 uidp->nextp = vcp->usersp;
936 lock_InitializeMutex(&uidp->mx, "user_t mutex");
938 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 : ""));
940 lock_ReleaseWrite(&smb_rctLock);
944 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
946 smb_username_t *unp= NULL;
948 lock_ObtainWrite(&smb_rctLock);
949 for(unp = usernamesp; unp; unp = unp->nextp) {
950 if (stricmp(unp->name, usern) == 0 &&
951 stricmp(unp->machine, machine) == 0) {
956 if (!unp && (flags & SMB_FLAG_CREATE)) {
957 unp = malloc(sizeof(*unp));
958 memset(unp, 0, sizeof(*unp));
960 unp->nextp = usernamesp;
961 unp->name = strdup(usern);
962 unp->machine = strdup(machine);
964 lock_InitializeMutex(&unp->mx, "username_t mutex");
966 lock_ReleaseWrite(&smb_rctLock);
970 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
972 smb_user_t *uidp= NULL;
974 lock_ObtainWrite(&smb_rctLock);
975 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
978 if (stricmp(uidp->unp->name, usern) == 0) {
980 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
985 lock_ReleaseWrite(&smb_rctLock);
988 void smb_ReleaseUID(smb_user_t *uidp)
997 lock_ObtainWrite(&smb_rctLock);
998 osi_assert(uidp->refCount-- > 0);
999 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1000 lupp = &uidp->vcp->usersp;
1001 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1002 if (up == uidp) break;
1004 osi_assert(up != NULL);
1006 lock_FinalizeMutex(&uidp->mx);
1008 userp = uidp->unp->userp; /* remember to drop ref later */
1009 uidp->unp->userp = NULL;
1014 lock_ReleaseWrite(&smb_rctLock);
1016 cm_ReleaseUserVCRef(userp);
1017 cm_ReleaseUser(userp);
1024 /* retrieve a held reference to a user structure corresponding to an incoming
1026 * corresponding release function is cm_ReleaseUser.
1028 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1034 smbp = (smb_t *) inp;
1035 uidp = smb_FindUID(vcp, smbp->uid, 0);
1036 if ((!uidp) || (!uidp->unp))
1039 lock_ObtainMutex(&uidp->mx);
1040 up = uidp->unp->userp;
1042 lock_ReleaseMutex(&uidp->mx);
1044 smb_ReleaseUID(uidp);
1050 * Return a pointer to a pathname extracted from a TID structure. The
1051 * TID structure is not held; assume it won't go away.
1053 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1058 tidp = smb_FindTID(vcp, tid, 0);
1062 if(tidp->flags & SMB_TIDFLAG_IPC) {
1063 code = CM_ERROR_TIDIPC;
1064 /* tidp->pathname would be NULL, but that's fine */
1066 *treepath = tidp->pathname;
1067 smb_ReleaseTID(tidp);
1072 /* check to see if we have a chained fid, that is, a fid that comes from an
1073 * OpenAndX message that ran earlier in this packet. In this case, the fid
1074 * field in a read, for example, request, isn't set, since the value is
1075 * supposed to be inherited from the openAndX call.
1077 int smb_ChainFID(int fid, smb_packet_t *inp)
1079 if (inp->fid == 0 || inp->inCount == 0)
1085 /* are we a priv'd user? What does this mean on NT? */
1086 int smb_SUser(cm_user_t *userp)
1091 /* find a file ID. If we pass in 0 we select an used File ID.
1092 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1093 * smb_fid_t data structure if desired File ID cannot be found.
1095 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1100 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1103 lock_ObtainWrite(&smb_rctLock);
1104 /* figure out if we need to allocate a new file ID */
1107 fid = vcp->fidCounter;
1111 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1112 if (fid == fidp->fid) {
1123 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1124 char eventName[MAX_PATH];
1126 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1127 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1128 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1129 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1130 thrd_CloseHandle(event);
1137 fidp = malloc(sizeof(*fidp));
1138 memset(fidp, 0, sizeof(*fidp));
1139 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1143 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1145 fidp->curr_chunk = fidp->prev_chunk = -2;
1146 fidp->raw_write_event = event;
1148 vcp->fidCounter = fid+1;
1149 if (vcp->fidCounter == 0)
1150 vcp->fidCounter = 1;
1153 lock_ReleaseWrite(&smb_rctLock);
1157 void smb_ReleaseFID(smb_fid_t *fidp)
1160 smb_vc_t *vcp = NULL;
1161 smb_ioctl_t *ioctlp;
1167 lock_ObtainWrite(&smb_rctLock);
1168 osi_assert(fidp->refCount-- > 0);
1169 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1171 if (!(fidp->flags & SMB_FID_IOCTL))
1173 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1174 thrd_CloseHandle(fidp->raw_write_event);
1176 /* and see if there is ioctl stuff to free */
1177 ioctlp = fidp->ioctlp;
1179 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1180 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1181 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1187 /* do not call smb_ReleaseVC() because we already have the lock */
1190 lock_ReleaseWrite(&smb_rctLock);
1192 /* now release the scache structure */
1194 cm_ReleaseSCache(scp);
1198 * Case-insensitive search for one string in another;
1199 * used to find variable names in submount pathnames.
1201 static char *smb_stristr(char *str1, char *str2)
1205 for (cursor = str1; *cursor; cursor++)
1206 if (stricmp(cursor, str2) == 0)
1213 * Substitute a variable value for its name in a submount pathname. Variable
1214 * name has been identified by smb_stristr() and is in substr. Variable name
1215 * length (plus one) is in substr_size. Variable value is in newstr.
1217 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1222 strcpy(temp, substr + substr_size - 1);
1223 strcpy(substr, newstr);
1227 char VNUserName[] = "%USERNAME%";
1228 char VNLCUserName[] = "%LCUSERNAME%";
1229 char VNComputerName[] = "%COMPUTERNAME%";
1230 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1233 /* List available shares */
1234 int smb_ListShares()
1238 char shareBuf[4096];
1246 /*strcpy(shareNameList[num_shares], "all");
1247 strcpy(pathNameList[num_shares++], "/afs");*/
1248 fprintf(stderr, "The following shares are available:\n");
1249 fprintf(stderr, "Share Name (AFS Path)\n");
1250 fprintf(stderr, "---------------------\n");
1251 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1254 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1255 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1257 strcpy(sbmtpath, cm_confDir);
1259 strcat(sbmtpath, "/afsdsbmt.ini");
1260 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1261 shareBuf, sizeof(shareBuf),
1267 this_share = shareBuf;
1271 /*strcpy(shareNameList[num_shares], this_share);*/
1272 len = GetPrivateProfileString("AFS Submounts", this_share,
1279 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1282 if (*p == '\\') *p = '/'; /* change to / */
1286 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1287 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1290 while (*this_share != 0) this_share++; /* find next NUL */
1291 this_share++; /* skip past the NUL */
1292 } while (*this_share != 0); /* stop at final NUL */
1298 typedef struct smb_findShare_rock {
1302 } smb_findShare_rock_t;
1304 #define SMB_FINDSHARE_EXACT_MATCH 1
1305 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1307 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1311 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1312 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1313 if(!stricmp(dep->name, vrock->shareName))
1314 matchType = SMB_FINDSHARE_EXACT_MATCH;
1316 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1317 if(vrock->match) free(vrock->match);
1318 vrock->match = strdup(dep->name);
1319 vrock->matchType = matchType;
1321 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1322 return CM_ERROR_STOPNOW;
1328 /* find a shareName in the table of submounts */
1329 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1333 char pathName[1024];
1338 char sbmtpath[MAX_PATH];
1343 DWORD allSubmount = 1;
1345 /* if allSubmounts == 0, only return the //mountRoot/all share
1346 * if in fact it has been been created in the subMounts table.
1347 * This is to allow sites that want to restrict access to the
1350 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1351 0, KEY_QUERY_VALUE, &parmKey);
1352 if (code == ERROR_SUCCESS) {
1353 len = sizeof(allSubmount);
1354 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1355 (BYTE *) &allSubmount, &len);
1356 if (code != ERROR_SUCCESS) {
1359 RegCloseKey (parmKey);
1362 if (allSubmount && _stricmp(shareName, "all") == 0) {
1367 /* In case, the all share is disabled we need to still be able
1368 * to handle ioctl requests
1370 if (_stricmp(shareName, "ioctl$") == 0) {
1371 *pathNamep = strdup("/.__ioctl__");
1375 if (_stricmp(shareName, "IPC$") == 0 ||
1376 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1377 _stricmp(shareName, "DESKTOP.INI") == 0
1384 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1385 0, KEY_QUERY_VALUE, &parmKey);
1386 if (code == ERROR_SUCCESS) {
1387 len = sizeof(pathName);
1388 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1389 (BYTE *) pathName, &len);
1390 if (code != ERROR_SUCCESS)
1392 RegCloseKey (parmKey);
1397 strcpy(sbmtpath, cm_confDir);
1398 strcat(sbmtpath, "/afsdsbmt.ini");
1399 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1400 pathName, sizeof(pathName), sbmtpath);
1402 if (len != 0 && len != sizeof(pathName) - 1) {
1403 /* We can accept either unix or PC style AFS pathnames. Convert
1404 * Unix-style to PC style here for internal use.
1407 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1408 p += strlen(cm_mountRoot); /* skip mount path */
1411 if (*q == '/') *q = '\\'; /* change to \ */
1417 if (var = smb_stristr(p, VNUserName)) {
1418 if (uidp && uidp->unp)
1419 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1421 smb_subst(p, var, sizeof(VNUserName)," ");
1423 else if (var = smb_stristr(p, VNLCUserName))
1425 if (uidp && uidp->unp)
1426 strcpy(temp, uidp->unp->name);
1430 smb_subst(p, var, sizeof(VNLCUserName), temp);
1432 else if (var = smb_stristr(p, VNComputerName))
1434 sizeTemp = sizeof(temp);
1435 GetComputerName((LPTSTR)temp, &sizeTemp);
1436 smb_subst(p, var, sizeof(VNComputerName), temp);
1438 else if (var = smb_stristr(p, VNLCComputerName))
1440 sizeTemp = sizeof(temp);
1441 GetComputerName((LPTSTR)temp, &sizeTemp);
1443 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1448 *pathNamep = strdup(p);
1453 /* First lookup shareName in root.afs */
1455 smb_findShare_rock_t vrock;
1457 char * p = shareName;
1460 /* attempt to locate a partial match in root.afs. This is because
1461 when using the ANSI RAP calls, the share name is limited to 13 chars
1462 and hence is truncated. Of course we prefer exact matches. */
1464 thyper.HighPart = 0;
1467 vrock.shareName = shareName;
1469 vrock.matchType = 0;
1471 cm_HoldSCache(cm_rootSCachep);
1472 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1473 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1474 cm_ReleaseSCache(cm_rootSCachep);
1476 if (vrock.matchType) {
1477 sprintf(pathName,"/%s/",vrock.match);
1478 *pathNamep = strdup(strlwr(pathName));
1483 /* if we get here, there was no match for the share in root.afs */
1484 /* so try to create \\<netbiosName>\<cellname> */
1489 /* Get the full name for this cell */
1490 code = cm_SearchCellFile(p, temp, 0, 0);
1491 #ifdef AFS_AFSDB_ENV
1492 if (code && cm_dnsEnabled) {
1494 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1497 /* construct the path */
1499 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1500 *pathNamep = strdup(strlwr(pathName));
1509 /* Client-side offline caching policy types */
1510 #define CSC_POLICY_MANUAL 0
1511 #define CSC_POLICY_DOCUMENTS 1
1512 #define CSC_POLICY_PROGRAMS 2
1513 #define CSC_POLICY_DISABLE 3
1515 int smb_FindShareCSCPolicy(char *shareName)
1521 int retval = CSC_POLICY_MANUAL;
1523 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1524 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1527 REG_OPTION_NON_VOLATILE,
1533 len = sizeof(policy);
1534 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1536 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1538 else if (stricmp(policy, "documents") == 0)
1540 retval = CSC_POLICY_DOCUMENTS;
1542 else if (stricmp(policy, "programs") == 0)
1544 retval = CSC_POLICY_PROGRAMS;
1546 else if (stricmp(policy, "disable") == 0)
1548 retval = CSC_POLICY_DISABLE;
1551 RegCloseKey(hkCSCPolicy);
1555 /* find a dir search structure by cookie value, and return it held.
1556 * Must be called with smb_globalLock held.
1558 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1560 smb_dirSearch_t *dsp;
1562 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1563 if (dsp->cookie == cookie) {
1564 if (dsp != smb_firstDirSearchp) {
1565 /* move to head of LRU queue, too, if we're not already there */
1566 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1567 smb_lastDirSearchp = (smb_dirSearch_t *)
1569 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1570 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1571 if (!smb_lastDirSearchp)
1572 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1574 lock_ObtainMutex(&dsp->mx);
1576 lock_ReleaseMutex(&dsp->mx);
1583 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1585 lock_ObtainWrite(&smb_globalLock);
1586 lock_ObtainMutex(&dsp->mx);
1587 dsp->flags |= SMB_DIRSEARCH_DELETE;
1588 if (dsp->scp != NULL) {
1589 lock_ObtainMutex(&dsp->scp->mx);
1590 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1591 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1592 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1593 dsp->scp->bulkStatProgress = hones;
1595 lock_ReleaseMutex(&dsp->scp->mx);
1597 lock_ReleaseMutex(&dsp->mx);
1598 lock_ReleaseWrite(&smb_globalLock);
1601 /* Must be called with the smb_globalLock held */
1602 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1608 lock_ObtainMutex(&dsp->mx);
1609 osi_assert(dsp->refCount-- > 0);
1610 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1611 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1612 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1613 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1614 lock_ReleaseMutex(&dsp->mx);
1615 lock_FinalizeMutex(&dsp->mx);
1619 lock_ReleaseMutex(&dsp->mx);
1621 /* do this now to avoid spurious locking hierarchy creation */
1622 if (scp) cm_ReleaseSCache(scp);
1625 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1627 lock_ObtainWrite(&smb_globalLock);
1628 smb_ReleaseDirSearchNoLock(dsp);
1629 lock_ReleaseWrite(&smb_globalLock);
1632 /* find a dir search structure by cookie value, and return it held */
1633 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1635 smb_dirSearch_t *dsp;
1637 lock_ObtainWrite(&smb_globalLock);
1638 dsp = smb_FindDirSearchNoLock(cookie);
1639 lock_ReleaseWrite(&smb_globalLock);
1643 /* GC some dir search entries, in the address space expected by the specific protocol.
1644 * Must be called with smb_globalLock held; release the lock temporarily.
1646 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1647 void smb_GCDirSearches(int isV3)
1649 smb_dirSearch_t *prevp;
1650 smb_dirSearch_t *tp;
1651 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1655 victimCount = 0; /* how many have we got so far */
1656 for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1657 /* we'll move tp from queue, so
1660 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1661 /* if no one is using this guy, and we're either in the new protocol,
1662 * or we're in the old one and this is a small enough ID to be useful
1663 * to the old protocol, GC this guy.
1665 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1666 /* hold and delete */
1667 tp->flags |= SMB_DIRSEARCH_DELETE;
1668 victimsp[victimCount++] = tp;
1672 /* don't do more than this */
1673 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1677 /* now release them */
1678 for (i = 0; i < victimCount; i++) {
1679 smb_ReleaseDirSearchNoLock(victimsp[i]);
1683 /* function for allocating a dir search entry. We need these to remember enough context
1684 * since we don't get passed the path from call to call during a directory search.
1686 * Returns a held dir search structure, and bumps the reference count on the vnode,
1687 * since it saves a pointer to the vnode.
1689 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1691 smb_dirSearch_t *dsp;
1695 lock_ObtainWrite(&smb_globalLock);
1698 /* what's the biggest ID allowed in this version of the protocol */
1699 maxAllowed = isV3 ? 65535 : 255;
1702 /* twice so we have enough tries to find guys we GC after one pass;
1703 * 10 extra is just in case I mis-counted.
1705 if (++counter > 2*maxAllowed+10)
1706 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1708 if (smb_dirSearchCounter > maxAllowed) {
1709 smb_dirSearchCounter = 1;
1710 smb_GCDirSearches(isV3); /* GC some */
1712 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1714 /* don't need to watch for refcount zero and deleted, since
1715 * we haven't dropped the global lock.
1717 lock_ObtainMutex(&dsp->mx);
1719 lock_ReleaseMutex(&dsp->mx);
1720 ++smb_dirSearchCounter;
1724 dsp = malloc(sizeof(*dsp));
1725 memset(dsp, 0, sizeof(*dsp));
1726 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1727 if (!smb_lastDirSearchp)
1728 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1729 dsp->cookie = smb_dirSearchCounter;
1730 ++smb_dirSearchCounter;
1732 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1733 dsp->lastTime = osi_Time();
1736 lock_ReleaseWrite(&smb_globalLock);
1740 static smb_packet_t *GetPacket(void)
1744 unsigned int npar, seg, tb_sel;
1747 lock_ObtainWrite(&smb_globalLock);
1748 tbp = smb_packetFreeListp;
1750 smb_packetFreeListp = tbp->nextp;
1751 lock_ReleaseWrite(&smb_globalLock);
1754 tbp = calloc(65540,1);
1756 tbp = malloc(sizeof(smb_packet_t));
1758 tbp->magic = SMB_PACKETMAGIC;
1761 tbp->resumeCode = 0;
1767 tbp->ncb_length = 0;
1772 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1775 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1777 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1779 osi_panic("",__FILE__,__LINE__);
1782 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1787 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1788 tbp->dos_pkt_sel = tb_sel;
1791 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1796 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1800 memcpy(tbp, pkt, sizeof(smb_packet_t));
1801 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1805 static NCB *GetNCB(void)
1810 unsigned int npar, seg, tb_sel;
1813 lock_ObtainWrite(&smb_globalLock);
1814 tbp = smb_ncbFreeListp;
1816 smb_ncbFreeListp = tbp->nextp;
1817 lock_ReleaseWrite(&smb_globalLock);
1820 tbp = calloc(sizeof(*tbp),1);
1822 tbp = malloc(sizeof(*tbp));
1823 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1826 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1828 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1830 osi_panic("",__FILE__,__LINE__);
1832 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1837 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1838 tbp->dos_ncb_sel = tb_sel;
1840 tbp->magic = SMB_NCBMAGIC;
1843 osi_assert(tbp->magic == SMB_NCBMAGIC);
1845 memset(&tbp->ncb, 0, sizeof(NCB));
1848 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1853 void smb_FreePacket(smb_packet_t *tbp)
1855 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1857 lock_ObtainWrite(&smb_globalLock);
1858 tbp->nextp = smb_packetFreeListp;
1859 smb_packetFreeListp = tbp;
1860 tbp->magic = SMB_PACKETMAGIC;
1863 tbp->resumeCode = 0;
1869 tbp->ncb_length = 0;
1871 lock_ReleaseWrite(&smb_globalLock);
1874 static void FreeNCB(NCB *bufferp)
1878 tbp = (smb_ncb_t *) bufferp;
1879 osi_assert(tbp->magic == SMB_NCBMAGIC);
1881 lock_ObtainWrite(&smb_globalLock);
1882 tbp->nextp = smb_ncbFreeListp;
1883 smb_ncbFreeListp = tbp;
1884 lock_ReleaseWrite(&smb_globalLock);
1887 /* get a ptr to the data part of a packet, and its count */
1888 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1892 unsigned char *afterParmsp;
1894 parmBytes = *smbp->wctp << 1;
1895 afterParmsp = smbp->wctp + parmBytes + 1;
1897 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1898 if (nbytesp) *nbytesp = dataBytes;
1900 /* don't forget to skip the data byte count, since it follows
1901 * the parameters; that's where the "2" comes from below.
1903 return (unsigned char *) (afterParmsp + 2);
1906 /* must set all the returned parameters before playing around with the
1907 * data region, since the data region is located past the end of the
1908 * variable number of parameters.
1910 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1912 unsigned char *afterParmsp;
1914 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1916 *afterParmsp++ = dsize & 0xff;
1917 *afterParmsp = (dsize>>8) & 0xff;
1920 /* return the parm'th parameter in the smbp packet */
1921 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1924 unsigned char *parmDatap;
1926 parmCount = *smbp->wctp;
1928 if (parm >= parmCount) {
1933 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1935 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1936 parm, parmCount, smbp->ncb_length);
1939 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1940 1, smbp->ncb_length, ptbuf, smbp);
1941 DeregisterEventSource(h);
1943 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1944 osi_panic(s, __FILE__, __LINE__);
1946 parmDatap = smbp->wctp + (2*parm) + 1;
1948 return parmDatap[0] + (parmDatap[1] << 8);
1951 /* return the parm'th parameter in the smbp packet */
1952 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1955 unsigned char *parmDatap;
1957 parmCount = *smbp->wctp;
1959 if (parm * 2 + offset >= parmCount * 2) {
1964 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1966 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1967 parm, offset, parmCount, smbp->ncb_length);
1970 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1971 1, smbp->ncb_length, ptbuf, smbp);
1972 DeregisterEventSource(h);
1974 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1975 osi_panic(s, __FILE__, __LINE__);
1977 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1979 return parmDatap[0] + (parmDatap[1] << 8);
1982 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1986 /* make sure we have enough slots */
1987 if (*smbp->wctp <= slot)
1988 *smbp->wctp = slot+1;
1990 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1991 *parmDatap++ = parmValue & 0xff;
1992 *parmDatap = (parmValue>>8) & 0xff;
1995 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1999 /* make sure we have enough slots */
2000 if (*smbp->wctp <= slot)
2001 *smbp->wctp = slot+2;
2003 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2004 *parmDatap++ = parmValue & 0xff;
2005 *parmDatap++ = (parmValue>>8) & 0xff;
2006 *parmDatap++ = (parmValue>>16) & 0xff;
2007 *parmDatap++ = (parmValue>>24) & 0xff;
2010 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2015 /* make sure we have enough slots */
2016 if (*smbp->wctp <= slot)
2017 *smbp->wctp = slot+4;
2019 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2021 *parmDatap++ = *parmValuep++;
2024 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2028 /* make sure we have enough slots */
2029 if (*smbp->wctp <= slot) {
2030 if (smbp->oddByte) {
2032 *smbp->wctp = slot+1;
2037 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2038 *parmDatap++ = parmValue & 0xff;
2041 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2045 lastSlashp = strrchr(inPathp, '\\');
2047 *lastComponentp = lastSlashp;
2050 if (inPathp == lastSlashp)
2052 *outPathp++ = *inPathp++;
2061 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2066 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2071 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2077 tlen = inp[0] + (inp[1]<<8);
2078 inp += 2; /* skip length field */
2081 *chainpp = inp + tlen;
2090 /* format a packet as a response */
2091 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2096 outp = (smb_t *) op;
2098 /* zero the basic structure through the smb_wct field, and zero the data
2099 * size field, assuming that wct stays zero; otherwise, you have to
2100 * explicitly set the data size field, too.
2102 inSmbp = (smb_t *) inp;
2103 memset(outp, 0, sizeof(smb_t)+2);
2109 outp->com = inSmbp->com;
2110 outp->tid = inSmbp->tid;
2111 outp->pid = inSmbp->pid;
2112 outp->uid = inSmbp->uid;
2113 outp->mid = inSmbp->mid;
2114 outp->res[0] = inSmbp->res[0];
2115 outp->res[1] = inSmbp->res[1];
2116 op->inCom = inSmbp->com;
2118 outp->reb = 0x80; /* SERVER_RESP */
2119 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2121 /* copy fields in generic packet area */
2122 op->wctp = &outp->wct;
2125 /* send a (probably response) packet; vcp tells us to whom to send it.
2126 * we compute the length by looking at wct and bcc fields.
2128 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2145 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2148 memset((char *)ncbp, 0, sizeof(NCB));
2150 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2151 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2152 extra += tp[0] + (tp[1]<<8);
2153 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2154 extra += 3; /* wct and length fields */
2156 ncbp->ncb_length = extra; /* bytes to send */
2157 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2158 ncbp->ncb_lana_num = vcp->lana;
2159 ncbp->ncb_command = NCBSEND; /* op means send data */
2161 ncbp->ncb_buffer = (char *) inp;/* packet */
2162 code = Netbios(ncbp);
2164 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2165 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2167 /* copy header information from virtual to DOS address space */
2168 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2169 code = Netbios(ncbp, dos_ncb);
2173 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2179 void smb_MapNTError(long code, unsigned long *NTStatusp)
2181 unsigned long NTStatus;
2183 /* map CM_ERROR_* errors to NT 32-bit status codes */
2184 /* NT Status codes are listed in ntstatus.h not winerror.h */
2185 if (code == CM_ERROR_NOSUCHCELL) {
2186 NTStatus = 0xC000000FL; /* No such file */
2188 else if (code == CM_ERROR_NOSUCHVOLUME) {
2189 NTStatus = 0xC000000FL; /* No such file */
2191 else if (code == CM_ERROR_TIMEDOUT) {
2192 NTStatus = 0xC00000CFL; /* Sharing Paused */
2194 else if (code == CM_ERROR_RETRY) {
2195 NTStatus = 0xC000022DL; /* Retry */
2197 else if (code == CM_ERROR_NOACCESS) {
2198 NTStatus = 0xC0000022L; /* Access denied */
2200 else if (code == CM_ERROR_READONLY) {
2201 NTStatus = 0xC00000A2L; /* Write protected */
2203 else if (code == CM_ERROR_NOSUCHFILE) {
2204 NTStatus = 0xC000000FL; /* No such file */
2206 else if (code == CM_ERROR_NOSUCHPATH) {
2207 NTStatus = 0xC000003AL; /* Object path not found */
2209 else if (code == CM_ERROR_TOOBIG) {
2210 NTStatus = 0xC000007BL; /* Invalid image format */
2212 else if (code == CM_ERROR_INVAL) {
2213 NTStatus = 0xC000000DL; /* Invalid parameter */
2215 else if (code == CM_ERROR_BADFD) {
2216 NTStatus = 0xC0000008L; /* Invalid handle */
2218 else if (code == CM_ERROR_BADFDOP) {
2219 NTStatus = 0xC0000022L; /* Access denied */
2221 else if (code == CM_ERROR_EXISTS) {
2222 NTStatus = 0xC0000035L; /* Object name collision */
2224 else if (code == CM_ERROR_NOTEMPTY) {
2225 NTStatus = 0xC0000101L; /* Directory not empty */
2227 else if (code == CM_ERROR_CROSSDEVLINK) {
2228 NTStatus = 0xC00000D4L; /* Not same device */
2230 else if (code == CM_ERROR_NOTDIR) {
2231 NTStatus = 0xC0000103L; /* Not a directory */
2233 else if (code == CM_ERROR_ISDIR) {
2234 NTStatus = 0xC00000BAL; /* File is a directory */
2236 else if (code == CM_ERROR_BADOP) {
2238 /* I have no idea where this comes from */
2239 NTStatus = 0xC09820FFL; /* SMB no support */
2241 NTStatus = 0xC00000BBL; /* Not supported */
2242 #endif /* COMMENT */
2244 else if (code == CM_ERROR_BADSHARENAME) {
2245 NTStatus = 0xC00000CCL; /* Bad network name */
2247 else if (code == CM_ERROR_NOIPC) {
2249 NTStatus = 0xC0000022L; /* Access Denied */
2251 NTStatus = 0xC000013DL; /* Remote Resources */
2254 else if (code == CM_ERROR_CLOCKSKEW) {
2255 NTStatus = 0xC0000133L; /* Time difference at DC */
2257 else if (code == CM_ERROR_BADTID) {
2258 NTStatus = 0xC0982005L; /* SMB bad TID */
2260 else if (code == CM_ERROR_USESTD) {
2261 NTStatus = 0xC09820FBL; /* SMB use standard */
2263 else if (code == CM_ERROR_QUOTA) {
2265 NTStatus = 0xC0000044L; /* Quota exceeded */
2267 NTStatus = 0xC000007FL; /* Disk full */
2270 else if (code == CM_ERROR_SPACE) {
2271 NTStatus = 0xC000007FL; /* Disk full */
2273 else if (code == CM_ERROR_ATSYS) {
2274 NTStatus = 0xC0000033L; /* Object name invalid */
2276 else if (code == CM_ERROR_BADNTFILENAME) {
2277 NTStatus = 0xC0000033L; /* Object name invalid */
2279 else if (code == CM_ERROR_WOULDBLOCK) {
2280 NTStatus = 0xC0000055L; /* Lock not granted */
2282 else if (code == CM_ERROR_PARTIALWRITE) {
2283 NTStatus = 0xC000007FL; /* Disk full */
2285 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2286 NTStatus = 0xC0000023L; /* Buffer too small */
2288 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2289 NTStatus = 0xC0000035L; /* Object name collision */
2291 else if (code == CM_ERROR_BADPASSWORD) {
2292 NTStatus = 0xC000006DL; /* unknown username or bad password */
2294 else if (code == CM_ERROR_BADLOGONTYPE) {
2295 NTStatus = 0xC000015BL; /* logon type not granted */
2297 else if (code == CM_ERROR_GSSCONTINUE) {
2298 NTStatus = 0xC0000016L; /* more processing required */
2300 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2302 NTStatus = 0xC0000280L; /* reparse point not resolved */
2304 NTStatus = 0xC0000022L; /* Access Denied */
2308 NTStatus = 0xC0982001L; /* SMB non-specific error */
2311 *NTStatusp = NTStatus;
2312 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2315 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2316 unsigned char *classp)
2318 unsigned char class;
2319 unsigned short error;
2321 /* map CM_ERROR_* errors to SMB errors */
2322 if (code == CM_ERROR_NOSUCHCELL) {
2324 error = 3; /* bad path */
2326 else if (code == CM_ERROR_NOSUCHVOLUME) {
2328 error = 3; /* bad path */
2330 else if (code == CM_ERROR_TIMEDOUT) {
2332 error = 81; /* server is paused */
2334 else if (code == CM_ERROR_RETRY) {
2335 class = 2; /* shouldn't happen */
2338 else if (code == CM_ERROR_NOACCESS) {
2340 error = 4; /* bad access */
2342 else if (code == CM_ERROR_READONLY) {
2344 error = 19; /* read only */
2346 else if (code == CM_ERROR_NOSUCHFILE) {
2348 error = 2; /* ENOENT! */
2350 else if (code == CM_ERROR_NOSUCHPATH) {
2352 error = 3; /* Bad path */
2354 else if (code == CM_ERROR_TOOBIG) {
2356 error = 11; /* bad format */
2358 else if (code == CM_ERROR_INVAL) {
2359 class = 2; /* server non-specific error code */
2362 else if (code == CM_ERROR_BADFD) {
2364 error = 6; /* invalid file handle */
2366 else if (code == CM_ERROR_BADFDOP) {
2367 class = 1; /* invalid op on FD */
2370 else if (code == CM_ERROR_EXISTS) {
2372 error = 80; /* file already exists */
2374 else if (code == CM_ERROR_NOTEMPTY) {
2376 error = 5; /* delete directory not empty */
2378 else if (code == CM_ERROR_CROSSDEVLINK) {
2380 error = 17; /* EXDEV */
2382 else if (code == CM_ERROR_NOTDIR) {
2383 class = 1; /* bad path */
2386 else if (code == CM_ERROR_ISDIR) {
2387 class = 1; /* access denied; DOS doesn't have a good match */
2390 else if (code == CM_ERROR_BADOP) {
2394 else if (code == CM_ERROR_BADSHARENAME) {
2398 else if (code == CM_ERROR_NOIPC) {
2400 error = 4; /* bad access */
2402 else if (code == CM_ERROR_CLOCKSKEW) {
2403 class = 1; /* invalid function */
2406 else if (code == CM_ERROR_BADTID) {
2410 else if (code == CM_ERROR_USESTD) {
2414 else if (code == CM_ERROR_REMOTECONN) {
2418 else if (code == CM_ERROR_QUOTA) {
2419 if (vcp->flags & SMB_VCFLAG_USEV3) {
2421 error = 39; /* disk full */
2425 error = 5; /* access denied */
2428 else if (code == CM_ERROR_SPACE) {
2429 if (vcp->flags & SMB_VCFLAG_USEV3) {
2431 error = 39; /* disk full */
2435 error = 5; /* access denied */
2438 else if (code == CM_ERROR_PARTIALWRITE) {
2440 error = 39; /* disk full */
2442 else if (code == CM_ERROR_ATSYS) {
2444 error = 2; /* ENOENT */
2446 else if (code == CM_ERROR_WOULDBLOCK) {
2448 error = 33; /* lock conflict */
2450 else if (code == CM_ERROR_NOFILES) {
2452 error = 18; /* no files in search */
2454 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2456 error = 183; /* Samba uses this */
2458 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2459 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2461 error = 2; /* bad password */
2470 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2473 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2475 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2476 return CM_ERROR_BADOP;
2479 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2481 unsigned short EchoCount, i;
2482 char *data, *outdata;
2485 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2487 for (i=1; i<=EchoCount; i++) {
2488 data = smb_GetSMBData(inp, &dataSize);
2489 smb_SetSMBParm(outp, 0, i);
2490 smb_SetSMBDataLength(outp, dataSize);
2491 outdata = smb_GetSMBData(outp, NULL);
2492 memcpy(outdata, data, dataSize);
2493 smb_SendPacket(vcp, outp);
2499 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2502 long count, minCount, finalCount;
2506 cm_user_t *userp = NULL;
2510 char *rawBuf = NULL;
2512 dos_ptr rawBuf = NULL;
2519 fd = smb_GetSMBParm(inp, 0);
2520 count = smb_GetSMBParm(inp, 3);
2521 minCount = smb_GetSMBParm(inp, 4);
2522 offset.HighPart = 0; /* too bad */
2523 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2525 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2526 fd, offset.LowPart, count);
2528 fidp = smb_FindFID(vcp, fd, 0);
2532 lock_ObtainMutex(&smb_RawBufLock);
2534 /* Get a raw buf, from head of list */
2535 rawBuf = smb_RawBufs;
2537 smb_RawBufs = *(char **)smb_RawBufs;
2539 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2542 lock_ReleaseMutex(&smb_RawBufLock);
2546 if (fidp->flags & SMB_FID_IOCTL)
2549 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2551 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2554 /* Give back raw buffer */
2555 lock_ObtainMutex(&smb_RawBufLock);
2557 *((char **) rawBuf) = smb_RawBufs;
2559 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2562 smb_RawBufs = rawBuf;
2563 lock_ReleaseMutex(&smb_RawBufLock);
2566 smb_ReleaseFID(fidp);
2570 userp = smb_GetUser(vcp, inp);
2573 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2575 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2576 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2577 userp, &finalCount, TRUE /* rawFlag */);
2584 cm_ReleaseUser(userp);
2587 smb_ReleaseFID(fidp);
2592 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2594 memset((char *)ncbp, 0, sizeof(NCB));
2596 ncbp->ncb_length = (unsigned short) finalCount;
2597 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2598 ncbp->ncb_lana_num = vcp->lana;
2599 ncbp->ncb_command = NCBSEND;
2600 ncbp->ncb_buffer = rawBuf;
2603 code = Netbios(ncbp);
2605 code = Netbios(ncbp, dos_ncb);
2608 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2611 /* Give back raw buffer */
2612 lock_ObtainMutex(&smb_RawBufLock);
2614 *((char **) rawBuf) = smb_RawBufs;
2616 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2619 smb_RawBufs = rawBuf;
2620 lock_ReleaseMutex(&smb_RawBufLock);
2626 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2628 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2633 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2635 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2640 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2647 int protoIndex; /* index we're using */
2652 char protocol_array[10][1024]; /* protocol signature of the client */
2653 int caps; /* capabilities */
2656 TIME_ZONE_INFORMATION tzi;
2658 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2662 DWORD now = GetCurrentTime();
2663 if (now - last_msg_time >= 30000
2664 && now - last_msg_time <= 90000) {
2666 "Setting dead_vcp %x", active_vcp);
2668 smb_ReleaseVC(dead_vcp);
2670 "Previous dead_vcp %x", dead_vcp);
2672 smb_HoldVC(active_vcp);
2673 dead_vcp = active_vcp;
2674 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2679 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2681 namep = smb_GetSMBData(inp, &dbytes);
2684 coreProtoIndex = -1; /* not found */
2687 while(namex < dbytes) {
2688 osi_Log1(smb_logp, "Protocol %s",
2689 osi_LogSaveString(smb_logp, namep+1));
2690 strcpy(protocol_array[tcounter], namep+1);
2692 /* namep points at the first protocol, or really, a 0x02
2693 * byte preceding the null-terminated ASCII name.
2695 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2696 coreProtoIndex = tcounter;
2698 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2699 v3ProtoIndex = tcounter;
2701 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2702 NTProtoIndex = tcounter;
2705 /* compute size of protocol entry */
2706 entryLength = strlen(namep+1);
2707 entryLength += 2; /* 0x02 bytes and null termination */
2709 /* advance over this protocol entry */
2710 namex += entryLength;
2711 namep += entryLength;
2712 tcounter++; /* which proto entry we're looking at */
2715 if (NTProtoIndex != -1) {
2716 protoIndex = NTProtoIndex;
2717 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2719 else if (v3ProtoIndex != -1) {
2720 protoIndex = v3ProtoIndex;
2721 vcp->flags |= SMB_VCFLAG_USEV3;
2723 else if (coreProtoIndex != -1) {
2724 protoIndex = coreProtoIndex;
2725 vcp->flags |= SMB_VCFLAG_USECORE;
2727 else protoIndex = -1;
2729 if (protoIndex == -1)
2730 return CM_ERROR_INVAL;
2731 else if (NTProtoIndex != -1) {
2732 smb_SetSMBParm(outp, 0, protoIndex);
2733 if (smb_authType != SMB_AUTH_NONE) {
2734 smb_SetSMBParmByte(outp, 1,
2735 NEGOTIATE_SECURITY_USER_LEVEL |
2736 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2738 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2740 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2741 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2742 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2743 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2744 /* The session key is not a well documented field however most clients
2745 * will echo back the session key to the server. Currently we are using
2746 * the same value for all sessions. We should generate a random value
2747 * and store it into the vcp
2749 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2750 smb_SetSMBParm(outp, 8, 1);
2752 * Tried changing the capabilities to support for W2K - defect 117695
2753 * Maybe something else needs to be changed here?
2757 smb_SetSMBParmLong(outp, 9, 0x43fd);
2759 smb_SetSMBParmLong(outp, 9, 0x251);
2762 * 32-bit error codes *
2766 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2767 NTNEGOTIATE_CAPABILITY_NTFIND |
2768 NTNEGOTIATE_CAPABILITY_RAWMODE |
2769 NTNEGOTIATE_CAPABILITY_NTSMB;
2771 if ( smb_authType == SMB_AUTH_EXTENDED )
2772 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2774 smb_SetSMBParmLong(outp, 9, caps);
2776 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2777 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2778 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2780 GetTimeZoneInformation(&tzi);
2781 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2783 if (smb_authType == SMB_AUTH_NTLM) {
2784 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2785 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2786 /* paste in encryption key */
2787 datap = smb_GetSMBData(outp, NULL);
2788 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2789 /* and the faux domain name */
2790 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2791 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2795 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2797 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2799 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2801 datap = smb_GetSMBData(outp, NULL);
2802 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2805 datap += sizeof(smb_ServerGUID);
2806 memcpy(datap, secBlob, secBlobLength);
2810 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2811 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2814 else if (v3ProtoIndex != -1) {
2815 smb_SetSMBParm(outp, 0, protoIndex);
2817 /* NOTE: Extended authentication cannot be negotiated with v3
2818 * therefore we fail over to NTLM
2820 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2821 smb_SetSMBParm(outp, 1,
2822 NEGOTIATE_SECURITY_USER_LEVEL |
2823 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2825 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2827 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2828 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2829 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2830 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2831 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2832 smb_SetSMBParm(outp, 7, 1);
2834 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2835 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2836 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2838 GetTimeZoneInformation(&tzi);
2839 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2841 /* NOTE: Extended authentication cannot be negotiated with v3
2842 * therefore we fail over to NTLM
2844 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2845 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2846 smb_SetSMBParm(outp, 12, 0); /* resvd */
2847 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2848 datap = smb_GetSMBData(outp, NULL);
2849 /* paste in a new encryption key */
2850 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2851 /* and the faux domain name */
2852 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2854 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2855 smb_SetSMBParm(outp, 12, 0); /* resvd */
2856 smb_SetSMBDataLength(outp, 0);
2859 else if (coreProtoIndex != -1) { /* not really supported anymore */
2860 smb_SetSMBParm(outp, 0, protoIndex);
2861 smb_SetSMBDataLength(outp, 0);
2866 void smb_Daemon(void *parmp)
2868 afs_uint32 count = 0;
2870 while(smbShutdownFlag == 0) {
2874 if (smbShutdownFlag == 1)
2877 if ((count % 72) == 0) { /* every five minutes */
2879 time_t old_localZero = smb_localZero;
2881 /* Initialize smb_localZero */
2882 myTime.tm_isdst = -1; /* compute whether on DST or not */
2883 myTime.tm_year = 70;
2889 smb_localZero = mktime(&myTime);
2891 smb_CalculateNowTZ();
2893 #ifdef AFS_FREELANCE
2894 if ( smb_localZero != old_localZero )
2895 cm_noteLocalMountPointChange();
2898 /* XXX GC dir search entries */
2902 void smb_WaitingLocksDaemon()
2904 smb_waitingLock_t *wL, *nwL;
2907 smb_packet_t *inp, *outp;
2912 lock_ObtainWrite(&smb_globalLock);
2913 nwL = smb_allWaitingLocks;
2915 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2924 lock_ObtainWrite(&smb_globalLock);
2926 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2927 lock_ReleaseWrite(&smb_globalLock);
2928 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2929 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2930 if (code == CM_ERROR_WOULDBLOCK) {
2932 if (wL->timeRemaining != 0xffffffff
2933 && (wL->timeRemaining -= 1000) < 0)
2942 ncbp->ncb_length = inp->ncb_length;
2943 inp->spacep = cm_GetSpace();
2945 /* Remove waitingLock from list */
2946 lock_ObtainWrite(&smb_globalLock);
2947 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2949 lock_ReleaseWrite(&smb_globalLock);
2951 /* Resume packet processing */
2953 smb_SetSMBDataLength(outp, 0);
2954 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2955 outp->resumeCode = code;
2957 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2960 cm_FreeSpace(inp->spacep);
2961 smb_FreePacket(inp);
2962 smb_FreePacket(outp);
2970 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2972 osi_Log0(smb_logp, "SMB receive get disk attributes");
2974 smb_SetSMBParm(outp, 0, 32000);
2975 smb_SetSMBParm(outp, 1, 64);
2976 smb_SetSMBParm(outp, 2, 1024);
2977 smb_SetSMBParm(outp, 3, 30000);
2978 smb_SetSMBParm(outp, 4, 0);
2979 smb_SetSMBDataLength(outp, 0);
2983 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2987 unsigned short newTid;
2988 char shareName[256];
2996 osi_Log0(smb_logp, "SMB receive tree connect");
2998 /* parse input parameters */
2999 tp = smb_GetSMBData(inp, NULL);
3000 pathp = smb_ParseASCIIBlock(tp, &tp);
3001 passwordp = smb_ParseASCIIBlock(tp, &tp);
3002 tp = strrchr(pathp, '\\');
3004 return CM_ERROR_BADSMB;
3005 strcpy(shareName, tp+1);
3007 userp = smb_GetUser(vcp, inp);
3009 lock_ObtainMutex(&vcp->mx);
3010 newTid = vcp->tidCounter++;
3011 lock_ReleaseMutex(&vcp->mx);
3013 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3014 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3015 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3017 smb_ReleaseUID(uidp);
3019 smb_ReleaseTID(tidp);
3020 return CM_ERROR_BADSHARENAME;
3022 lock_ObtainMutex(&tidp->mx);
3023 tidp->userp = userp;
3024 tidp->pathname = sharePath;
3025 lock_ReleaseMutex(&tidp->mx);
3026 smb_ReleaseTID(tidp);
3028 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3029 smb_SetSMBParm(rsp, 1, newTid);
3030 smb_SetSMBDataLength(rsp, 0);
3032 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3036 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3040 if (*inp++ != 0x1) return NULL;
3041 tlen = inp[0] + (inp[1]<<8);
3042 inp += 2; /* skip length field */
3045 *chainpp = inp + tlen;
3048 if (lengthp) *lengthp = tlen;
3053 /* set maskp to the mask part of the incoming path.
3054 * Mask is 11 bytes long (8.3 with the dot elided).
3055 * Returns true if succeeds with a valid name, otherwise it does
3056 * its best, but returns false.
3058 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3066 /* starts off valid */
3069 /* mask starts out all blanks */
3070 memset(maskp, ' ', 11);
3072 /* find last backslash, or use whole thing if there is none */
3073 tp = strrchr(pathp, '\\');
3074 if (!tp) tp = pathp;
3075 else tp++; /* skip slash */
3079 /* names starting with a dot are illegal */
3080 if (*tp == '.') valid8Dot3 = 0;
3084 if (tc == 0) return valid8Dot3;
3085 if (tc == '.' || tc == '"') break;
3086 if (i < 8) *up++ = tc;
3087 else valid8Dot3 = 0;
3090 /* if we get here, tp point after the dot */
3091 up = maskp+8; /* ext goes here */
3098 if (tc == '.' || tc == '"')
3101 /* copy extension if not too long */
3111 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3121 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3123 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3127 /* otherwise, we have a valid 8.3 name; see if we have a match,
3128 * treating '?' as a wildcard in maskp (but not in the file name).
3130 tp1 = umask; /* real name, in mask format */
3131 tp2 = maskp; /* mask, in mask format */
3132 for(i=0; i<11; i++) {
3133 tc1 = *tp1++; /* char from real name */
3134 tc2 = *tp2++; /* char from mask */
3135 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3136 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3139 if (tc2 == '?' && tc1 != ' ')
3146 /* we got a match */
3150 char *smb_FindMask(char *pathp)
3154 tp = strrchr(pathp, '\\'); /* find last slash */
3157 return tp+1; /* skip the slash */
3159 return pathp; /* no slash, return the entire path */
3162 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3164 unsigned char *pathp;
3166 unsigned char mask[11];
3167 unsigned char *statBlockp;
3168 unsigned char initStatBlock[21];
3171 osi_Log0(smb_logp, "SMB receive search volume");
3173 /* pull pathname and stat block out of request */
3174 tp = smb_GetSMBData(inp, NULL);
3175 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3176 osi_assert(pathp != NULL);
3177 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3178 osi_assert(statBlockp != NULL);
3180 statBlockp = initStatBlock;
3184 /* for returning to caller */
3185 smb_Get8Dot3MaskFromPath(mask, pathp);
3187 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3188 tp = smb_GetSMBData(outp, NULL);
3190 *tp++ = 43; /* bytes in a dir entry */
3191 *tp++ = 0; /* high byte in counter */
3193 /* now marshall the dir entry, starting with the search status */
3194 *tp++ = statBlockp[0]; /* Reserved */
3195 memcpy(tp, mask, 11); tp += 11; /* FileName */
3197 /* now pass back server use info, with 1st byte non-zero */
3199 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3201 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3203 *tp++ = 0x8; /* attribute: volume */
3213 /* 4 byte file size */
3219 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3220 memset(tp, ' ', 13);
3223 /* set the length of the data part of the packet to 43 + 3, for the dir
3224 * entry plus the 5 and the length fields.
3226 smb_SetSMBDataLength(outp, 46);
3230 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3231 cm_user_t *userp, cm_req_t *reqp)
3239 smb_dirListPatch_t *patchp;
3240 smb_dirListPatch_t *npatchp;
3242 for (patchp = *dirPatchespp; patchp; patchp =
3243 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3245 dptr = patchp->dptr;
3247 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3249 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3250 *dptr++ = SMB_ATTR_HIDDEN;
3253 lock_ObtainMutex(&scp->mx);
3254 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3255 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3257 lock_ReleaseMutex(&scp->mx);
3258 cm_ReleaseSCache(scp);
3259 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3260 *dptr++ = SMB_ATTR_HIDDEN;
3264 attr = smb_Attributes(scp);
3265 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3266 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3267 attr |= SMB_ATTR_HIDDEN;
3271 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3274 shortTemp = (unsigned short) (dosTime & 0xffff);
3275 *((u_short *)dptr) = shortTemp;
3278 /* and copy out date */
3279 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3280 *((u_short *)dptr) = shortTemp;
3283 /* copy out file length */
3284 *((u_long *)dptr) = scp->length.LowPart;
3286 lock_ReleaseMutex(&scp->mx);
3287 cm_ReleaseSCache(scp);
3290 /* now free the patches */
3291 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3292 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3296 /* and mark the list as empty */
3297 *dirPatchespp = NULL;
3302 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3311 smb_dirListPatch_t *dirListPatchesp;
3312 smb_dirListPatch_t *curPatchp;
3316 osi_hyper_t dirLength;
3317 osi_hyper_t bufferOffset;
3318 osi_hyper_t curOffset;
3320 unsigned char *inCookiep;
3321 smb_dirSearch_t *dsp;
3325 unsigned long clientCookie;
3326 cm_pageHeader_t *pageHeaderp;
3327 cm_user_t *userp = NULL;
3334 long nextEntryCookie;
3335 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3336 char resByte; /* reserved byte from the cookie */
3337 char *op; /* output data ptr */
3338 char *origOp; /* original value of op */
3339 cm_space_t *spacep; /* for pathname buffer */
3350 maxCount = smb_GetSMBParm(inp, 0);
3352 dirListPatchesp = NULL;
3354 caseFold = CM_FLAG_CASEFOLD;
3356 tp = smb_GetSMBData(inp, NULL);
3357 pathp = smb_ParseASCIIBlock(tp, &tp);
3358 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3360 /* bail out if request looks bad */
3361 if (!tp || !pathp) {
3362 return CM_ERROR_BADSMB;
3365 /* We can handle long names */
3366 if (vcp->flags & SMB_VCFLAG_USENT)
3367 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3369 /* make sure we got a whole search status */
3370 if (dataLength < 21) {
3371 nextCookie = 0; /* start at the beginning of the dir */
3374 attribute = smb_GetSMBParm(inp, 1);
3376 /* handle volume info in another function */
3377 if (attribute & 0x8)
3378 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3380 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3381 maxCount, osi_LogSaveString(smb_logp, pathp));
3383 if (*pathp == 0) { /* null pathp, treat as root dir */
3384 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3385 return CM_ERROR_NOFILES;
3389 dsp = smb_NewDirSearch(0);
3390 dsp->attribute = attribute;
3391 smb_Get8Dot3MaskFromPath(mask, pathp);
3392 memcpy(dsp->mask, mask, 11);
3394 /* track if this is likely to match a lot of entries */
3395 if (smb_IsStarMask(mask)) starPattern = 1;
3396 else starPattern = 0;
3399 /* pull the next cookie value out of the search status block */
3400 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3401 + (inCookiep[16]<<24);
3402 dsp = smb_FindDirSearch(inCookiep[12]);
3404 /* can't find dir search status; fatal error */
3405 return CM_ERROR_BADFD;
3407 attribute = dsp->attribute;
3408 resByte = inCookiep[0];
3410 /* copy out client cookie, in host byte order. Don't bother
3411 * interpreting it, since we're just passing it through, anyway.
3413 memcpy(&clientCookie, &inCookiep[17], 4);
3415 memcpy(mask, dsp->mask, 11);
3417 /* assume we're doing a star match if it has continued for more
3423 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3424 nextCookie, dsp->cookie, attribute);
3426 userp = smb_GetUser(vcp, inp);
3428 /* try to get the vnode for the path name next */
3429 lock_ObtainMutex(&dsp->mx);
3436 spacep = inp->spacep;
3437 smb_StripLastComponent(spacep->data, NULL, pathp);
3438 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3440 lock_ReleaseMutex(&dsp->mx);
3441 cm_ReleaseUser(userp);
3442 smb_DeleteDirSearch(dsp);
3443 smb_ReleaseDirSearch(dsp);
3444 return CM_ERROR_NOFILES;
3446 code = cm_NameI(cm_rootSCachep, spacep->data,
3447 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3450 cm_ReleaseSCache(dsp->scp);
3452 /* we need one hold for the entry we just stored into,
3453 * and one for our own processing. When we're done with this
3454 * function, we'll drop the one for our own processing.
3455 * We held it once from the namei call, and so we do another hold
3459 lock_ObtainMutex(&scp->mx);
3460 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3461 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3462 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3463 dsp->flags |= SMB_DIRSEARCH_BULKST;
3465 lock_ReleaseMutex(&scp->mx);
3468 lock_ReleaseMutex(&dsp->mx);
3470 cm_ReleaseUser(userp);
3471 smb_DeleteDirSearch(dsp);
3472 smb_ReleaseDirSearch(dsp);
3476 /* reserves space for parameter; we'll adjust it again later to the
3477 * real count of the # of entries we returned once we've actually
3478 * assembled the directory listing.
3480 smb_SetSMBParm(outp, 0, 0);
3482 /* get the directory size */
3483 lock_ObtainMutex(&scp->mx);
3484 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3485 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3487 lock_ReleaseMutex(&scp->mx);
3488 cm_ReleaseSCache(scp);
3489 cm_ReleaseUser(userp);
3490 smb_DeleteDirSearch(dsp);
3491 smb_ReleaseDirSearch(dsp);
3495 dirLength = scp->length;
3497 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3498 curOffset.HighPart = 0;
3499 curOffset.LowPart = nextCookie;
3500 origOp = op = smb_GetSMBData(outp, NULL);
3501 /* and write out the basic header */
3502 *op++ = 5; /* variable block */
3503 op += 2; /* skip vbl block length; we'll fill it in later */
3507 /* make sure that curOffset.LowPart doesn't point to the first
3508 * 32 bytes in the 2nd through last dir page, and that it doesn't
3509 * point at the first 13 32-byte chunks in the first dir page,
3510 * since those are dir and page headers, and don't contain useful
3513 temp = curOffset.LowPart & (2048-1);
3514 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3515 /* we're in the first page */
3516 if (temp < 13*32) temp = 13*32;
3519 /* we're in a later dir page */
3520 if (temp < 32) temp = 32;
3523 /* make sure the low order 5 bits are zero */
3526 /* now put temp bits back ito curOffset.LowPart */
3527 curOffset.LowPart &= ~(2048-1);
3528 curOffset.LowPart |= temp;
3530 /* check if we've returned all the names that will fit in the
3533 if (returnedNames >= maxCount)
3536 /* check if we've passed the dir's EOF */
3537 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3539 /* see if we can use the bufferp we have now; compute in which page
3540 * the current offset would be, and check whether that's the offset
3541 * of the buffer we have. If not, get the buffer.
3543 thyper.HighPart = curOffset.HighPart;
3544 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3545 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3548 buf_Release(bufferp);
3551 lock_ReleaseMutex(&scp->mx);
3552 lock_ObtainRead(&scp->bufCreateLock);
3553 code = buf_Get(scp, &thyper, &bufferp);
3554 lock_ReleaseRead(&scp->bufCreateLock);
3555 lock_ObtainMutex(&dsp->mx);
3557 /* now, if we're doing a star match, do bulk fetching of all of
3558 * the status info for files in the dir.
3561 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3562 lock_ObtainMutex(&scp->mx);
3563 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3564 LargeIntegerGreaterThanOrEqualTo(thyper,
3565 scp->bulkStatProgress)) {
3566 /* Don't bulk stat if risking timeout */
3567 int now = GetCurrentTime();
3568 if (now - req.startTime > 5000) {
3569 scp->bulkStatProgress = thyper;
3570 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3571 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3573 cm_TryBulkStat(scp, &thyper, userp, &req);
3576 lock_ObtainMutex(&scp->mx);
3578 lock_ReleaseMutex(&dsp->mx);
3582 bufferOffset = thyper;
3584 /* now get the data in the cache */
3586 code = cm_SyncOp(scp, bufferp, userp, &req,
3588 CM_SCACHESYNC_NEEDCALLBACK |
3589 CM_SCACHESYNC_READ);
3592 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3594 /* otherwise, load the buffer and try again */
3595 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3599 buf_Release(bufferp);
3603 } /* if (wrong buffer) ... */
3605 /* now we have the buffer containing the entry we're interested in; copy
3606 * it out if it represents a non-deleted entry.
3608 entryInDir = curOffset.LowPart & (2048-1);
3609 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3611 /* page header will help tell us which entries are free. Page header
3612 * can change more often than once per buffer, since AFS 3 dir page size
3613 * may be less than (but not more than a buffer package buffer.
3615 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3616 temp &= ~(2048 - 1); /* turn off intra-page bits */
3617 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3619 /* now determine which entry we're looking at in the page. If it is
3620 * free (there's a free bitmap at the start of the dir), we should
3621 * skip these 32 bytes.
3623 slotInPage = (entryInDir & 0x7e0) >> 5;
3624 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3625 /* this entry is free */
3626 numDirChunks = 1; /* only skip this guy */
3630 tp = bufferp->datap + entryInBuffer;
3631 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3633 /* while we're here, compute the next entry's location, too,
3634 * since we'll need it when writing out the cookie into the dir
3637 * XXXX Probably should do more sanity checking.
3639 numDirChunks = cm_NameEntries(dep->name, NULL);
3641 /* compute the offset of the cookie representing the next entry */
3642 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3644 /* Compute 8.3 name if necessary */
3645 actualName = dep->name;
3646 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3647 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3648 actualName = shortName;
3651 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3652 /* this is one of the entries to use: it is not deleted
3653 * and it matches the star pattern we're looking for.
3656 /* Eliminate entries that don't match requested
3659 /* no hidden files */
3660 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3663 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3665 /* We have already done the cm_TryBulkStat above */
3666 fid.cell = scp->fid.cell;
3667 fid.volume = scp->fid.volume;
3668 fid.vnode = ntohl(dep->fid.vnode);
3669 fid.unique = ntohl(dep->fid.unique);
3670 fileType = cm_FindFileType(&fid);
3671 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3672 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3674 if (fileType == CM_SCACHETYPE_DIRECTORY)
3679 memcpy(op, mask, 11); op += 11;
3680 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3681 *op++ = nextEntryCookie & 0xff;
3682 *op++ = (nextEntryCookie>>8) & 0xff;
3683 *op++ = (nextEntryCookie>>16) & 0xff;
3684 *op++ = (nextEntryCookie>>24) & 0xff;
3685 memcpy(op, &clientCookie, 4); op += 4;
3687 /* now we emit the attribute. This is sort of tricky,
3688 * since we need to really stat the file to find out
3689 * what type of entry we've got. Right now, we're
3690 * copying out data from a buffer, while holding the
3691 * scp locked, so it isn't really convenient to stat
3692 * something now. We'll put in a place holder now,
3693 * and make a second pass before returning this to get
3694 * the real attributes. So, we just skip the data for
3695 * now, and adjust it later. We allocate a patch
3696 * record to make it easy to find this point later.
3697 * The replay will happen at a time when it is safe to
3698 * unlock the directory.
3700 curPatchp = malloc(sizeof(*curPatchp));
3701 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3702 curPatchp->dptr = op;
3703 curPatchp->fid.cell = scp->fid.cell;
3704 curPatchp->fid.volume = scp->fid.volume;
3705 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3706 curPatchp->fid.unique = ntohl(dep->fid.unique);
3708 /* do hidden attribute here since name won't be around when applying
3712 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3713 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3715 curPatchp->flags = 0;
3717 op += 9; /* skip attr, time, date and size */
3719 /* zero out name area. The spec says to pad with
3720 * spaces, but Samba doesn't, and neither do we.
3724 /* finally, we get to copy out the name; we know that
3725 * it fits in 8.3 or the pattern wouldn't match, but it
3726 * never hurts to be sure.
3728 strncpy(op, actualName, 13);
3730 /* Uppercase if requested by client */
3731 if ((((smb_t *)inp)->flg2 & 1) == 0)
3736 /* now, adjust the # of entries copied */
3738 } /* if we're including this name */
3741 /* and adjust curOffset to be where the new cookie is */
3742 thyper.HighPart = 0;
3743 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3744 curOffset = LargeIntegerAdd(thyper, curOffset);
3745 } /* while copying data for dir listing */
3747 /* release the mutex */
3748 lock_ReleaseMutex(&scp->mx);
3749 if (bufferp) buf_Release(bufferp);
3751 /* apply and free last set of patches; if not doing a star match, this
3752 * will be empty, but better safe (and freeing everything) than sorry.
3754 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3756 /* special return code for unsuccessful search */
3757 if (code == 0 && dataLength < 21 && returnedNames == 0)
3758 code = CM_ERROR_NOFILES;
3760 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3761 returnedNames, code);
3764 smb_DeleteDirSearch(dsp);
3765 smb_ReleaseDirSearch(dsp);
3766 cm_ReleaseSCache(scp);
3767 cm_ReleaseUser(userp);
3771 /* finalize the output buffer */
3772 smb_SetSMBParm(outp, 0, returnedNames);
3773 temp = (long) (op - origOp);
3774 smb_SetSMBDataLength(outp, temp);
3776 /* the data area is a variable block, which has a 5 (already there)
3777 * followed by the length of the # of data bytes. We now know this to
3778 * be "temp," although that includes the 3 bytes of vbl block header.
3779 * Deduct for them and fill in the length field.
3781 temp -= 3; /* deduct vbl block info */
3782 osi_assert(temp == (43 * returnedNames));
3783 origOp[1] = temp & 0xff;
3784 origOp[2] = (temp>>8) & 0xff;
3785 if (returnedNames == 0)
3786 smb_DeleteDirSearch(dsp);
3787 smb_ReleaseDirSearch(dsp);
3788 cm_ReleaseSCache(scp);
3789 cm_ReleaseUser(userp);
3793 /* verify that this is a valid path to a directory. I don't know why they
3794 * don't use the get file attributes call.
3796 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3800 cm_scache_t *rootScp;
3801 cm_scache_t *newScp;
3810 pathp = smb_GetSMBData(inp, NULL);
3811 pathp = smb_ParseASCIIBlock(pathp, NULL);
3812 osi_Log1(smb_logp, "SMB receive check path %s",
3813 osi_LogSaveString(smb_logp, pathp));
3816 return CM_ERROR_BADFD;
3819 rootScp = cm_rootSCachep;
3821 userp = smb_GetUser(vcp, inp);
3823 caseFold = CM_FLAG_CASEFOLD;
3825 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3827 cm_ReleaseUser(userp);
3828 return CM_ERROR_NOSUCHPATH;
3830 code = cm_NameI(rootScp, pathp,
3831 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3832 userp, tidPathp, &req, &newScp);
3835 cm_ReleaseUser(userp);
3839 /* now lock the vnode with a callback; returns with newScp locked */
3840 lock_ObtainMutex(&newScp->mx);
3841 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3842 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3843 if (code && code != CM_ERROR_NOACCESS) {
3844 lock_ReleaseMutex(&newScp->mx);
3845 cm_ReleaseSCache(newScp);
3846 cm_ReleaseUser(userp);
3850 attrs = smb_Attributes(newScp);
3852 if (!(attrs & 0x10))
3853 code = CM_ERROR_NOTDIR;
3855 lock_ReleaseMutex(&newScp->mx);
3857 cm_ReleaseSCache(newScp);
3858 cm_ReleaseUser(userp);
3862 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3866 cm_scache_t *rootScp;
3867 unsigned short attribute;
3869 cm_scache_t *newScp;
3878 /* decode basic attributes we're passed */
3879 attribute = smb_GetSMBParm(inp, 0);
3880 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3882 pathp = smb_GetSMBData(inp, NULL);
3883 pathp = smb_ParseASCIIBlock(pathp, NULL);
3886 return CM_ERROR_BADSMB;
3889 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3890 dosTime, attribute);
3892 rootScp = cm_rootSCachep;
3894 userp = smb_GetUser(vcp, inp);
3896 caseFold = CM_FLAG_CASEFOLD;
3898 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3900 cm_ReleaseUser(userp);
3901 return CM_ERROR_NOSUCHFILE;
3903 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3904 tidPathp, &req, &newScp);
3907 cm_ReleaseUser(userp);
3911 /* now lock the vnode with a callback; returns with newScp locked; we
3912 * need the current status to determine what the new status is, in some
3915 lock_ObtainMutex(&newScp->mx);
3916 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3917 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3919 lock_ReleaseMutex(&newScp->mx);
3920 cm_ReleaseSCache(newScp);
3921 cm_ReleaseUser(userp);
3925 /* Check for RO volume */
3926 if (newScp->flags & CM_SCACHEFLAG_RO) {
3927 lock_ReleaseMutex(&newScp->mx);
3928 cm_ReleaseSCache(newScp);
3929 cm_ReleaseUser(userp);
3930 return CM_ERROR_READONLY;
3933 /* prepare for setattr call */
3936 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3937 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3939 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3940 /* we're told to make a writable file read-only */
3941 attr.unixModeBits = newScp->unixModeBits & ~0222;
3942 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3944 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3945 /* we're told to make a read-only file writable */
3946 attr.unixModeBits = newScp->unixModeBits | 0222;
3947 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3949 lock_ReleaseMutex(&newScp->mx);
3951 /* now call setattr */
3953 code = cm_SetAttr(newScp, &attr, userp, &req);
3957 cm_ReleaseSCache(newScp);
3958 cm_ReleaseUser(userp);
3963 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3967 cm_scache_t *rootScp;
3968 cm_scache_t *newScp, *dscp;
3980 pathp = smb_GetSMBData(inp, NULL);
3981 pathp = smb_ParseASCIIBlock(pathp, NULL);
3984 return CM_ERROR_BADSMB;
3987 if (*pathp == 0) /* null path */
3990 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3991 osi_LogSaveString(smb_logp, pathp));
3993 rootScp = cm_rootSCachep;
3995 userp = smb_GetUser(vcp, inp);
3997 /* we shouldn't need this for V3 requests, but we seem to */
3998 caseFold = CM_FLAG_CASEFOLD;
4000 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4002 cm_ReleaseUser(userp);
4003 return CM_ERROR_NOSUCHFILE;
4007 * XXX Strange hack XXX
4009 * As of Patch 5 (16 July 97), we are having the following problem:
4010 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4011 * requests to look up "desktop.ini" in all the subdirectories.
4012 * This can cause zillions of timeouts looking up non-existent cells
4013 * and volumes, especially in the top-level directory.
4015 * We have not found any way to avoid this or work around it except
4016 * to explicitly ignore the requests for mount points that haven't
4017 * yet been evaluated and for directories that haven't yet been
4020 * We should modify this hack to provide a fake desktop.ini file
4021 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4023 spacep = inp->spacep;
4024 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4025 #ifndef SPECIAL_FOLDERS
4026 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4027 code = cm_NameI(rootScp, spacep->data,
4028 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4029 userp, tidPathp, &req, &dscp);
4031 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT &&
4032 !dscp->mountRootFidp)
4033 code = CM_ERROR_NOSUCHFILE;
4034 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4035 cm_buf_t *bp = buf_Find(dscp, &hzero);
4039 code = CM_ERROR_NOSUCHFILE;
4041 cm_ReleaseSCache(dscp);
4043 cm_ReleaseUser(userp);
4048 #endif /* SPECIAL_FOLDERS */
4050 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4051 tidPathp, &req, &newScp);
4053 cm_ReleaseUser(userp);
4057 /* now lock the vnode with a callback; returns with newScp locked */
4058 lock_ObtainMutex(&newScp->mx);
4059 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4060 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4062 lock_ReleaseMutex(&newScp->mx);
4063 cm_ReleaseSCache(newScp);
4064 cm_ReleaseUser(userp);
4069 /* use smb_Attributes instead. Also the fact that a file is
4070 * in a readonly volume doesn't mean it shojuld be marked as RO
4072 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4073 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4074 attrs = SMB_ATTR_DIRECTORY;
4077 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4078 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4080 attrs = smb_Attributes(newScp);
4083 smb_SetSMBParm(outp, 0, attrs);
4085 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4086 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4087 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4088 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4089 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4090 smb_SetSMBParm(outp, 5, 0);
4091 smb_SetSMBParm(outp, 6, 0);
4092 smb_SetSMBParm(outp, 7, 0);
4093 smb_SetSMBParm(outp, 8, 0);
4094 smb_SetSMBParm(outp, 9, 0);
4095 smb_SetSMBDataLength(outp, 0);
4096 lock_ReleaseMutex(&newScp->mx);
4098 cm_ReleaseSCache(newScp);
4099 cm_ReleaseUser(userp);
4104 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4108 osi_Log0(smb_logp, "SMB receive tree disconnect");
4110 /* find the tree and free it */
4111 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4113 lock_ObtainMutex(&tidp->mx);
4114 tidp->flags |= SMB_TIDFLAG_DELETE;
4115 lock_ReleaseMutex(&tidp->mx);
4116 smb_ReleaseTID(tidp);
4122 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4140 pathp = smb_GetSMBData(inp, NULL);
4141 pathp = smb_ParseASCIIBlock(pathp, NULL);
4143 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4145 #ifdef DEBUG_VERBOSE
4149 hexpath = osi_HexifyString( pathp );
4150 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4155 share = smb_GetSMBParm(inp, 0);
4156 attribute = smb_GetSMBParm(inp, 1);
4158 spacep = inp->spacep;
4159 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4160 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4161 /* special case magic file name for receiving IOCTL requests
4162 * (since IOCTL calls themselves aren't getting through).
4164 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4165 smb_SetupIoctlFid(fidp, spacep);
4166 smb_SetSMBParm(outp, 0, fidp->fid);
4167 smb_SetSMBParm(outp, 1, 0); /* attrs */
4168 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4169 smb_SetSMBParm(outp, 3, 0);
4170 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4171 smb_SetSMBParm(outp, 5, 0x7fff);
4172 /* pass the open mode back */
4173 smb_SetSMBParm(outp, 6, (share & 0xf));
4174 smb_SetSMBDataLength(outp, 0);
4175 smb_ReleaseFID(fidp);
4179 userp = smb_GetUser(vcp, inp);
4181 caseFold = CM_FLAG_CASEFOLD;
4183 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4185 cm_ReleaseUser(userp);
4186 return CM_ERROR_NOSUCHPATH;
4188 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4189 tidPathp, &req, &scp);
4192 cm_ReleaseUser(userp);
4196 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4198 cm_ReleaseSCache(scp);
4199 cm_ReleaseUser(userp);
4203 /* don't need callback to check file type, since file types never
4204 * change, and namei and cm_Lookup all stat the object at least once on
4205 * a successful return.
4207 if (scp->fileType != CM_SCACHETYPE_FILE) {
4208 cm_ReleaseSCache(scp);
4209 cm_ReleaseUser(userp);
4210 return CM_ERROR_ISDIR;
4213 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4216 /* save a pointer to the vnode */
4219 if ((share & 0xf) == 0)
4220 fidp->flags |= SMB_FID_OPENREAD;
4221 else if ((share & 0xf) == 1)
4222 fidp->flags |= SMB_FID_OPENWRITE;
4224 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4226 lock_ObtainMutex(&scp->mx);
4227 smb_SetSMBParm(outp, 0, fidp->fid);
4228 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4229 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4230 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4231 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4232 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4233 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4234 /* pass the open mode back; XXXX add access checks */
4235 smb_SetSMBParm(outp, 6, (share & 0xf));
4236 smb_SetSMBDataLength(outp, 0);
4237 lock_ReleaseMutex(&scp->mx);
4240 cm_Open(scp, 0, userp);
4242 /* send and free packet */
4243 smb_ReleaseFID(fidp);
4244 cm_ReleaseUser(userp);
4245 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4249 typedef struct smb_unlinkRock {
4254 char *maskp; /* pointer to the star pattern */
4259 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4262 smb_unlinkRock_t *rockp;
4270 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4271 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4272 caseFold |= CM_FLAG_8DOT3;
4274 matchName = dep->name;
4275 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4277 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4278 !cm_Is8Dot3(dep->name)) {
4279 cm_Gen8Dot3Name(dep, shortName, NULL);
4280 matchName = shortName;
4281 /* 8.3 matches are always case insensitive */
4282 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4285 osi_Log1(smb_logp, "Unlinking %s",
4286 osi_LogSaveString(smb_logp, matchName));
4287 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4288 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4289 smb_NotifyChange(FILE_ACTION_REMOVED,
4290 FILE_NOTIFY_CHANGE_FILE_NAME,
4291 dscp, dep->name, NULL, TRUE);
4295 /* If we made a case sensitive exact match, we might as well quit now. */
4296 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4297 code = CM_ERROR_STOPNOW;
4305 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4314 smb_unlinkRock_t rock;
4323 attribute = smb_GetSMBParm(inp, 0);
4325 tp = smb_GetSMBData(inp, NULL);
4326 pathp = smb_ParseASCIIBlock(tp, &tp);
4328 osi_Log1(smb_logp, "SMB receive unlink %s",
4329 osi_LogSaveString(smb_logp, pathp));
4331 spacep = inp->spacep;
4332 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4334 userp = smb_GetUser(vcp, inp);
4336 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4338 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4340 cm_ReleaseUser(userp);
4341 return CM_ERROR_NOSUCHPATH;
4343 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4347 cm_ReleaseUser(userp);
4351 /* otherwise, scp points to the parent directory. */
4358 rock.maskp = smb_FindMask(pathp);
4359 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4362 thyper.HighPart = 0;
4368 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4369 * match. If that fails, we do a case insensitve match.
4371 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4372 !smb_IsStarMask(rock.maskp)) {
4373 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4376 thyper.HighPart = 0;
4377 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4382 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4384 if (code == CM_ERROR_STOPNOW)
4387 cm_ReleaseUser(userp);
4389 cm_ReleaseSCache(dscp);
4391 if (code == 0 && !rock.any)
4392 code = CM_ERROR_NOSUCHFILE;
4396 typedef struct smb_renameRock {
4397 cm_scache_t *odscp; /* old dir */
4398 cm_scache_t *ndscp; /* new dir */
4399 cm_user_t *userp; /* user */
4400 cm_req_t *reqp; /* request struct */
4401 smb_vc_t *vcp; /* virtual circuit */
4402 char *maskp; /* pointer to star pattern of old file name */
4403 int flags; /* tilde, casefold, etc */
4404 char *newNamep; /* ptr to the new file's name */
4407 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4410 smb_renameRock_t *rockp;
4415 rockp = (smb_renameRock_t *) vrockp;
4417 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4418 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4419 caseFold |= CM_FLAG_8DOT3;
4421 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4423 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4424 !cm_Is8Dot3(dep->name)) {
4425 cm_Gen8Dot3Name(dep, shortName, NULL);
4426 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4429 code = cm_Rename(rockp->odscp, dep->name,
4430 rockp->ndscp, rockp->newNamep, rockp->userp,
4432 /* if the call worked, stop doing the search now, since we
4433 * really only want to rename one file.
4436 code = CM_ERROR_STOPNOW;
4445 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4448 cm_space_t *spacep = NULL;
4449 smb_renameRock_t rock;
4450 cm_scache_t *oldDscp = NULL;
4451 cm_scache_t *newDscp = NULL;
4452 cm_scache_t *tmpscp= NULL;
4453 cm_scache_t *tmpscp2 = NULL;
4463 userp = smb_GetUser(vcp, inp);
4464 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4466 cm_ReleaseUser(userp);
4467 return CM_ERROR_NOSUCHPATH;
4471 spacep = inp->spacep;
4472 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4475 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4476 * what actually exists is foo/baz. I don't know why the code used to be
4477 * the way it was. 1/29/96
4479 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4481 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4483 * caseFold = CM_FLAG_CASEFOLD;
4485 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4486 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4487 userp, tidPathp, &req, &oldDscp);
4490 cm_ReleaseUser(userp);
4494 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4495 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4496 userp, tidPathp, &req, &newDscp);
4499 cm_ReleaseSCache(oldDscp);
4500 cm_ReleaseUser(userp);
4504 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4505 * next, get the component names, and lower case them.
4508 /* handle the old name first */
4510 oldLastNamep = oldPathp;
4514 /* and handle the new name, too */
4516 newLastNamep = newPathp;
4520 /* TODO: The old name could be a wildcard. The new name must not be */
4522 /* do the vnode call */
4523 rock.odscp = oldDscp;
4524 rock.ndscp = newDscp;
4528 rock.maskp = oldLastNamep;
4529 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4530 rock.newNamep = newLastNamep;
4532 /* Check if the file already exists; if so return error */
4533 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4534 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4535 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4536 osi_LogSaveString(afsd_logp, newLastNamep));
4538 /* Check if the old and the new names differ only in case. If so return
4539 * success, else return CM_ERROR_EXISTS
4541 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4543 /* This would be a success only if the old file is *as same as* the new file */
4544 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4546 if (tmpscp == tmpscp2)
4549 code = CM_ERROR_EXISTS;
4550 cm_ReleaseSCache(tmpscp2);
4553 code = CM_ERROR_NOSUCHFILE;
4556 /* file exist, do not rename, also fixes move */
4557 osi_Log0(smb_logp, "Can't rename. Target already exists");
4558 code = CM_ERROR_EXISTS;
4562 cm_ReleaseSCache(tmpscp);
4563 cm_ReleaseSCache(newDscp);
4564 cm_ReleaseSCache(oldDscp);
4565 cm_ReleaseUser(userp);
4569 /* Now search the directory for the pattern, and do the appropriate rename when found */
4570 thyper.LowPart = 0; /* search dir from here */
4571 thyper.HighPart = 0;
4573 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4575 if (code == CM_ERROR_STOPNOW)
4578 code = CM_ERROR_NOSUCHFILE;
4580 /* Handle Change Notification */
4582 * Being lazy, not distinguishing between files and dirs in this
4583 * filter, since we'd have to do a lookup.
4585 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4586 if (oldDscp == newDscp) {
4587 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4588 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4589 filter, oldDscp, oldLastNamep,
4590 newLastNamep, TRUE);
4592 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4593 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4594 filter, oldDscp, oldLastNamep,
4596 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4597 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4598 filter, newDscp, newLastNamep,
4603 cm_ReleaseSCache(tmpscp);
4604 cm_ReleaseUser(userp);
4605 cm_ReleaseSCache(oldDscp);
4606 cm_ReleaseSCache(newDscp);
4611 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4614 cm_space_t *spacep = NULL;
4615 cm_scache_t *oldDscp = NULL;
4616 cm_scache_t *newDscp = NULL;
4617 cm_scache_t *tmpscp= NULL;
4618 cm_scache_t *tmpscp2 = NULL;
4619 cm_scache_t *sscp = NULL;
4628 userp = smb_GetUser(vcp, inp);
4630 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4632 cm_ReleaseUser(userp);
4633 return CM_ERROR_NOSUCHPATH;
4638 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4640 spacep = inp->spacep;
4641 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4643 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4644 userp, tidPathp, &req, &oldDscp);
4646 cm_ReleaseUser(userp);
4650 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4651 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4652 userp, tidPathp, &req, &newDscp);
4654 cm_ReleaseSCache(oldDscp);
4655 cm_ReleaseUser(userp);
4659 /* Now, although we did two lookups for the two directories (because the same
4660 * directory can be referenced through different paths), we only allow hard links
4661 * within the same directory. */
4662 if (oldDscp != newDscp) {
4663 cm_ReleaseSCache(oldDscp);
4664 cm_ReleaseSCache(newDscp);
4665 cm_ReleaseUser(userp);
4666 return CM_ERROR_CROSSDEVLINK;
4669 /* handle the old name first */
4671 oldLastNamep = oldPathp;
4675 /* and handle the new name, too */
4677 newLastNamep = newPathp;
4681 /* now lookup the old name */
4682 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4683 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4685 cm_ReleaseSCache(oldDscp);
4686 cm_ReleaseSCache(newDscp);
4687 cm_ReleaseUser(userp);
4691 /* Check if the file already exists; if so return error */
4692 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4693 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4694 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4695 osi_LogSaveString(afsd_logp, newLastNamep));
4697 /* if the existing link is to the same file, then we return success */
4699 if(sscp == tmpscp) {
4702 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
4703 code = CM_ERROR_EXISTS;
4708 cm_ReleaseSCache(tmpscp);
4709 cm_ReleaseSCache(sscp);
4710 cm_ReleaseSCache(newDscp);
4711 cm_ReleaseSCache(oldDscp);
4712 cm_ReleaseUser(userp);
4716 /* now create the hardlink */
4717 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
4718 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
4719 osi_Log1(smb_logp," Link returns %d", code);
4721 /* Handle Change Notification */
4723 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
4724 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4725 smb_NotifyChange(FILE_ACTION_ADDED,
4726 filter, newDscp, newLastNamep,
4731 cm_ReleaseSCache(tmpscp);
4732 cm_ReleaseUser(userp);
4733 cm_ReleaseSCache(sscp);
4734 cm_ReleaseSCache(oldDscp);
4735 cm_ReleaseSCache(newDscp);
4740 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4746 tp = smb_GetSMBData(inp, NULL);
4747 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4748 newPathp = smb_ParseASCIIBlock(tp, &tp);
4750 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4751 osi_LogSaveString(smb_logp, oldPathp),
4752 osi_LogSaveString(smb_logp, newPathp));
4754 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
4759 typedef struct smb_rmdirRock {
4763 char *maskp; /* pointer to the star pattern */
4768 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4771 smb_rmdirRock_t *rockp;
4776 rockp = (smb_rmdirRock_t *) vrockp;
4778 matchName = dep->name;
4779 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4780 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4782 match = (strcmp(matchName, rockp->maskp) == 0);
4784 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4785 !cm_Is8Dot3(dep->name)) {
4786 cm_Gen8Dot3Name(dep, shortName, NULL);
4787 matchName = shortName;
4788 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4791 osi_Log1(smb_logp, "Removing directory %s",
4792 osi_LogSaveString(smb_logp, matchName));
4793 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4794 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4795 smb_NotifyChange(FILE_ACTION_REMOVED,
4796 FILE_NOTIFY_CHANGE_DIR_NAME,
4797 dscp, dep->name, NULL, TRUE);
4806 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4814 smb_rmdirRock_t rock;
4823 tp = smb_GetSMBData(inp, NULL);
4824 pathp = smb_ParseASCIIBlock(tp, &tp);
4826 spacep = inp->spacep;
4827 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4829 userp = smb_GetUser(vcp, inp);
4831 caseFold = CM_FLAG_CASEFOLD;
4833 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4835 cm_ReleaseUser(userp);
4836 return CM_ERROR_NOSUCHPATH;
4838 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4839 userp, tidPathp, &req, &dscp);
4842 cm_ReleaseUser(userp);
4846 /* otherwise, scp points to the parent directory. */
4853 rock.maskp = lastNamep;
4854 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4857 thyper.HighPart = 0;
4861 /* First do a case sensitive match, and if that fails, do a case insensitive match */
4862 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4863 if (code == 0 && !rock.any) {
4865 thyper.HighPart = 0;
4866 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4867 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4870 cm_ReleaseUser(userp);
4872 cm_ReleaseSCache(dscp);
4874 if (code == 0 && !rock.any)
4875 code = CM_ERROR_NOSUCHFILE;
4879 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4889 fid = smb_GetSMBParm(inp, 0);
4891 osi_Log1(smb_logp, "SMB flush fid %d", fid);
4893 fid = smb_ChainFID(fid, inp);
4894 fidp = smb_FindFID(vcp, fid, 0);
4895 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4897 smb_ReleaseFID(fidp);
4898 return CM_ERROR_BADFD;
4901 userp = smb_GetUser(vcp, inp);
4903 lock_ObtainMutex(&fidp->mx);
4904 if (fidp->flags & SMB_FID_OPENWRITE)
4905 code = cm_FSync(fidp->scp, userp, &req);
4908 lock_ReleaseMutex(&fidp->mx);
4910 smb_ReleaseFID(fidp);
4912 cm_ReleaseUser(userp);
4917 struct smb_FullNameRock {
4923 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4927 struct smb_FullNameRock *vrockp;
4929 vrockp = (struct smb_FullNameRock *)rockp;
4931 if (!cm_Is8Dot3(dep->name)) {
4932 cm_Gen8Dot3Name(dep, shortName, NULL);
4934 if (cm_stricmp(shortName, vrockp->name) == 0) {
4935 vrockp->fullName = strdup(dep->name);
4936 return CM_ERROR_STOPNOW;
4939 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
4940 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
4941 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4942 vrockp->fullName = strdup(dep->name);
4943 return CM_ERROR_STOPNOW;
4948 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4949 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4951 struct smb_FullNameRock rock;
4957 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
4958 if (code == CM_ERROR_STOPNOW)
4959 *newPathp = rock.fullName;
4961 *newPathp = strdup(pathp);
4964 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4975 fid = smb_GetSMBParm(inp, 0);
4976 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4978 osi_Log1(smb_logp, "SMB close fid %d", fid);
4980 fid = smb_ChainFID(fid, inp);
4981 fidp = smb_FindFID(vcp, fid, 0);
4983 return CM_ERROR_BADFD;
4986 userp = smb_GetUser(vcp, inp);
4988 lock_ObtainMutex(&fidp->mx);
4990 /* Don't jump the gun on an async raw write */
4991 while (fidp->raw_writers) {
4992 lock_ReleaseMutex(&fidp->mx);
4993 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4994 lock_ObtainMutex(&fidp->mx);
4997 fidp->flags |= SMB_FID_DELETE;
4999 /* watch for ioctl closes, and read-only opens */
5000 if (fidp->scp != NULL &&
5001 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5002 == SMB_FID_OPENWRITE) {
5003 if (dosTime != 0 && dosTime != -1) {
5004 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5005 /* This fixes defect 10958 */
5006 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5007 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5009 code = cm_FSync(fidp->scp, userp, &req);
5014 if (fidp->flags & SMB_FID_DELONCLOSE) {
5015 cm_scache_t *dscp = fidp->NTopen_dscp;
5016 char *pathp = fidp->NTopen_pathp;
5019 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5020 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5021 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5022 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5023 smb_NotifyChange(FILE_ACTION_REMOVED,
5024 FILE_NOTIFY_CHANGE_DIR_NAME,
5025 dscp, fullPathp, NULL, TRUE);
5029 code = cm_Unlink(dscp, fullPathp, userp, &req);
5030 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5031 smb_NotifyChange(FILE_ACTION_REMOVED,
5032 FILE_NOTIFY_CHANGE_FILE_NAME,
5033 dscp, fullPathp, NULL, TRUE);
5037 lock_ReleaseMutex(&fidp->mx);
5039 if (fidp->flags & SMB_FID_NTOPEN) {
5040 cm_ReleaseSCache(fidp->NTopen_dscp);
5041 free(fidp->NTopen_pathp);
5043 if (fidp->NTopen_wholepathp)
5044 free(fidp->NTopen_wholepathp);
5046 smb_ReleaseFID(fidp);
5047 cm_ReleaseUser(userp);
5052 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5055 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5056 cm_user_t *userp, long *readp)
5058 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5059 cm_user_t *userp, long *readp, int dosflag)
5066 osi_hyper_t fileLength;
5068 osi_hyper_t lastByte;
5069 osi_hyper_t bufferOffset;
5070 long bufIndex, nbytes;
5080 lock_ObtainMutex(&fidp->mx);
5082 lock_ObtainMutex(&scp->mx);
5084 if (offset.HighPart == 0) {
5085 chunk = offset.LowPart >> cm_logChunkSize;
5086 if (chunk != fidp->curr_chunk) {
5087 fidp->prev_chunk = fidp->curr_chunk;
5088 fidp->curr_chunk = chunk;
5090 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5094 /* start by looking up the file's end */
5095 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5096 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5097 if (code) goto done;
5099 /* now we have the entry locked, look up the length */
5100 fileLength = scp->length;
5102 /* adjust count down so that it won't go past EOF */
5103 thyper.LowPart = count;
5104 thyper.HighPart = 0;
5105 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5107 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5108 /* we'd read past EOF, so just stop at fileLength bytes.
5109 * Start by computing how many bytes remain in the file.
5111 thyper = LargeIntegerSubtract(fileLength, offset);
5113 /* if we are past EOF, read 0 bytes */
5114 if (LargeIntegerLessThanZero(thyper))
5117 count = thyper.LowPart;
5122 /* now, copy the data one buffer at a time,
5123 * until we've filled the request packet
5126 /* if we've copied all the data requested, we're done */
5127 if (count <= 0) break;
5129 /* otherwise, load up a buffer of data */
5130 thyper.HighPart = offset.HighPart;
5131 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5132 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5135 buf_Release(bufferp);
5138 lock_ReleaseMutex(&scp->mx);
5140 lock_ObtainRead(&scp->bufCreateLock);
5141 code = buf_Get(scp, &thyper, &bufferp);
5142 lock_ReleaseRead(&scp->bufCreateLock);
5144 lock_ObtainMutex(&scp->mx);
5145 if (code) goto done;
5146 bufferOffset = thyper;
5148 /* now get the data in the cache */
5150 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5151 CM_SCACHESYNC_NEEDCALLBACK |
5152 CM_SCACHESYNC_READ);
5153 if (code) goto done;
5155 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5157 /* otherwise, load the buffer and try again */
5158 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5162 buf_Release(bufferp);
5166 } /* if (wrong buffer) ... */
5168 /* now we have the right buffer loaded. Copy out the
5169 * data from here to the user's buffer.
5171 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5173 /* and figure out how many bytes we want from this buffer */
5174 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5175 if (nbytes > count) nbytes = count; /* don't go past EOF */
5177 /* now copy the data */
5180 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5183 memcpy(op, bufferp->datap + bufIndex, nbytes);
5185 /* adjust counters, pointers, etc. */
5188 thyper.LowPart = nbytes;
5189 thyper.HighPart = 0;
5190 offset = LargeIntegerAdd(thyper, offset);
5194 lock_ReleaseMutex(&scp->mx);
5195 lock_ReleaseMutex(&fidp->mx);
5197 buf_Release(bufferp);
5199 if (code == 0 && sequential)
5200 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5206 * smb_WriteData -- common code for Write and Raw Write
5209 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5210 cm_user_t *userp, long *writtenp)
5212 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5213 cm_user_t *userp, long *writtenp, int dosflag)
5220 osi_hyper_t fileLength; /* file's length at start of write */
5221 osi_hyper_t minLength; /* don't read past this */
5222 long nbytes; /* # of bytes to transfer this iteration */
5224 osi_hyper_t thyper; /* hyper tmp variable */
5225 osi_hyper_t bufferOffset;
5226 long bufIndex; /* index in buffer where our data is */
5228 osi_hyper_t writeBackOffset;/* offset of region to write back when
5233 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5234 fidp->fid, offsetp->LowPart, count);
5244 lock_ObtainMutex(&fidp->mx);
5246 lock_ObtainMutex(&scp->mx);
5248 /* start by looking up the file's end */
5249 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5251 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5252 CM_SCACHESYNC_NEEDCALLBACK
5253 | CM_SCACHESYNC_SETSTATUS
5254 | CM_SCACHESYNC_GETSTATUS);
5255 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5260 /* make sure we have a writable FD */
5261 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5262 code = CM_ERROR_BADFDOP;
5266 /* now we have the entry locked, look up the length */
5267 fileLength = scp->length;
5268 minLength = fileLength;
5269 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5270 minLength = scp->serverLength;
5272 /* adjust file length if we extend past EOF */
5273 thyper.LowPart = count;
5274 thyper.HighPart = 0;
5275 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5276 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5277 /* we'd write past EOF, so extend the file */
5278 scp->mask |= CM_SCACHEMASK_LENGTH;
5279 scp->length = thyper;
5280 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5282 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5284 /* now, if the new position (thyper) and the old (offset) are in
5285 * different storeback windows, remember to store back the previous
5286 * storeback window when we're done with the write.
5288 if ((thyper.LowPart & (-cm_chunkSize)) !=
5289 (offset.LowPart & (-cm_chunkSize))) {
5290 /* they're different */
5292 writeBackOffset.HighPart = offset.HighPart;
5293 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5298 /* now, copy the data one buffer at a time, until we've filled the
5301 /* if we've copied all the data requested, we're done */
5305 /* handle over quota or out of space */
5306 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5307 *writtenp = written;
5308 code = CM_ERROR_QUOTA;
5312 /* otherwise, load up a buffer of data */
5313 thyper.HighPart = offset.HighPart;
5314 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5315 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5318 lock_ReleaseMutex(&bufferp->mx);
5319 buf_Release(bufferp);
5322 lock_ReleaseMutex(&scp->mx);
5324 lock_ObtainRead(&scp->bufCreateLock);
5325 code = buf_Get(scp, &thyper, &bufferp);
5326 lock_ReleaseRead(&scp->bufCreateLock);
5328 lock_ObtainMutex(&bufferp->mx);
5329 lock_ObtainMutex(&scp->mx);
5330 if (code) goto done;
5332 bufferOffset = thyper;
5334 /* now get the data in the cache */
5336 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5338 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5339 CM_SCACHESYNC_NEEDCALLBACK
5340 | CM_SCACHESYNC_WRITE
5341 | CM_SCACHESYNC_BUFLOCKED);
5342 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5347 /* If we're overwriting the entire buffer, or
5348 * if we're writing at or past EOF, mark the
5349 * buffer as current so we don't call
5350 * cm_GetBuffer. This skips the fetch from the
5351 * server in those cases where we're going to
5352 * obliterate all the data in the buffer anyway,
5353 * or in those cases where there is no useful
5354 * data at the server to start with.
5356 * Use minLength instead of scp->length, since
5357 * the latter has already been updated by this
5360 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5361 || LargeIntegerEqualTo(offset, bufferp->offset)
5362 && (count >= buf_bufferSize
5363 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5364 ConvertLongToLargeInteger(count)),
5366 if (count < buf_bufferSize
5367 && bufferp->dataVersion == -1)
5368 memset(bufferp->datap, 0,
5370 bufferp->dataVersion = scp->dataVersion;
5373 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5375 /* otherwise, load the buffer and try again */
5376 lock_ReleaseMutex(&bufferp->mx);
5377 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5379 lock_ReleaseMutex(&scp->mx);
5380 lock_ObtainMutex(&bufferp->mx);
5381 lock_ObtainMutex(&scp->mx);
5385 lock_ReleaseMutex(&bufferp->mx);
5386 buf_Release(bufferp);
5390 } /* if (wrong buffer) ... */
5392 /* now we have the right buffer loaded. Copy out the
5393 * data from here to the user's buffer.
5395 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5397 /* and figure out how many bytes we want from this buffer */
5398 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5400 nbytes = count; /* don't go past end of request */
5402 /* now copy the data */
5405 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5408 memcpy(bufferp->datap + bufIndex, op, nbytes);
5409 buf_SetDirty(bufferp);
5411 /* and record the last writer */
5412 if (bufferp->userp != userp) {
5415 cm_ReleaseUser(bufferp->userp);
5416 bufferp->userp = userp;
5419 /* adjust counters, pointers, etc. */
5423 thyper.LowPart = nbytes;
5424 thyper.HighPart = 0;
5425 offset = LargeIntegerAdd(thyper, offset);
5429 lock_ReleaseMutex(&scp->mx);
5430 lock_ReleaseMutex(&fidp->mx);
5432 lock_ReleaseMutex(&bufferp->mx);
5433 buf_Release(bufferp);
5436 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5437 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5438 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5439 fidp->NTopen_dscp, fidp->NTopen_pathp,
5443 if (code == 0 && doWriteBack) {
5445 lock_ObtainMutex(&scp->mx);
5446 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5448 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5449 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5451 lock_ReleaseMutex(&scp->mx);
5452 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5453 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5456 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5457 fidp->fid, code, *writtenp);
5461 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5464 long count, written = 0, total_written = 0;
5469 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5471 int inDataBlockCount;
5473 fd = smb_GetSMBParm(inp, 0);
5474 count = smb_GetSMBParm(inp, 1);
5475 offset.HighPart = 0; /* too bad */
5476 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5478 op = smb_GetSMBData(inp, NULL);
5479 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5481 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5482 fd, offset.LowPart, count);
5484 fd = smb_ChainFID(fd, inp);
5485 fidp = smb_FindFID(vcp, fd, 0);
5487 return CM_ERROR_BADFD;
5490 if (fidp->flags & SMB_FID_IOCTL)
5491 return smb_IoctlWrite(fidp, vcp, inp, outp);
5493 userp = smb_GetUser(vcp, inp);
5495 /* special case: 0 bytes transferred means truncate to this position */
5501 truncAttr.mask = CM_ATTRMASK_LENGTH;
5502 truncAttr.length.LowPart = offset.LowPart;
5503 truncAttr.length.HighPart = 0;
5504 lock_ObtainMutex(&fidp->mx);
5505 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5506 lock_ReleaseMutex(&fidp->mx);
5507 smb_SetSMBParm(outp, 0, /* count */ 0);
5508 smb_SetSMBDataLength(outp, 0);
5509 fidp->flags |= SMB_FID_LENGTHSETDONE;
5514 * Work around bug in NT client
5516 * When copying a file, the NT client should first copy the data,
5517 * then copy the last write time. But sometimes the NT client does
5518 * these in the wrong order, so the data copies would inadvertently
5519 * cause the last write time to be overwritten. We try to detect this,
5520 * and don't set client mod time if we think that would go against the
5523 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5524 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5525 fidp->scp->clientModTime = time(NULL);
5529 while ( code == 0 && count > 0 ) {
5531 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5533 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5535 if (code == 0 && written == 0)
5536 code = CM_ERROR_PARTIALWRITE;
5538 offset.LowPart += written;
5540 total_written += written;
5544 /* set the packet data length to 3 bytes for the data block header,
5545 * plus the size of the data.
5547 smb_SetSMBParm(outp, 0, total_written);
5548 smb_SetSMBDataLength(outp, 0);
5551 smb_ReleaseFID(fidp);
5552 cm_ReleaseUser(userp);
5557 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5558 NCB *ncbp, raw_write_cont_t *rwcp)
5571 fd = smb_GetSMBParm(inp, 0);
5572 fidp = smb_FindFID(vcp, fd, 0);
5574 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5575 rwcp->offset.LowPart, rwcp->count);
5577 userp = smb_GetUser(vcp, inp);
5581 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5584 rawBuf = (dos_ptr) rwcp->buf;
5585 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5586 (unsigned char *) rawBuf, userp,
5590 if (rwcp->writeMode & 0x1) { /* synchronous */
5593 smb_FormatResponsePacket(vcp, inp, outp);
5594 op = (smb_t *) outp;
5595 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5596 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5597 smb_SetSMBDataLength(outp, 0);
5598 smb_SendPacket(vcp, outp);
5599 smb_FreePacket(outp);
5601 else { /* asynchronous */
5602 lock_ObtainMutex(&fidp->mx);
5603 fidp->raw_writers--;
5604 if (fidp->raw_writers == 0)
5605 thrd_SetEvent(fidp->raw_write_event);
5606 lock_ReleaseMutex(&fidp->mx);
5609 /* Give back raw buffer */
5610 lock_ObtainMutex(&smb_RawBufLock);
5612 *((char **)rawBuf) = smb_RawBufs;
5614 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5616 smb_RawBufs = rawBuf;
5617 lock_ReleaseMutex(&smb_RawBufLock);
5619 smb_ReleaseFID(fidp);
5620 cm_ReleaseUser(userp);
5623 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5628 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5631 long count, written = 0, total_written = 0;
5638 unsigned short writeMode;
5645 fd = smb_GetSMBParm(inp, 0);
5646 totalCount = smb_GetSMBParm(inp, 1);
5647 count = smb_GetSMBParm(inp, 10);
5648 offset.HighPart = 0; /* too bad */
5649 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5650 writeMode = smb_GetSMBParm(inp, 7);
5652 op = (char *) inp->data;
5653 op += smb_GetSMBParm(inp, 11);
5656 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5657 fd, offset.LowPart, count, writeMode);
5659 fd = smb_ChainFID(fd, inp);
5660 fidp = smb_FindFID(vcp, fd, 0);
5662 return CM_ERROR_BADFD;
5665 userp = smb_GetUser(vcp, inp);
5668 * Work around bug in NT client
5670 * When copying a file, the NT client should first copy the data,
5671 * then copy the last write time. But sometimes the NT client does
5672 * these in the wrong order, so the data copies would inadvertently
5673 * cause the last write time to be overwritten. We try to detect this,
5674 * and don't set client mod time if we think that would go against the
5677 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5678 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5679 fidp->scp->clientModTime = time(NULL);
5683 while ( code == 0 && count > 0 ) {
5685 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5687 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5689 if (code == 0 && written == 0)
5690 code = CM_ERROR_PARTIALWRITE;
5692 offset.LowPart += written;
5694 total_written += written;
5698 /* Get a raw buffer */
5701 lock_ObtainMutex(&smb_RawBufLock);
5703 /* Get a raw buf, from head of list */
5704 rawBuf = smb_RawBufs;
5706 smb_RawBufs = *(char **)smb_RawBufs;
5708 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5712 code = CM_ERROR_USESTD;
5714 lock_ReleaseMutex(&smb_RawBufLock);
5717 /* Don't allow a premature Close */
5718 if (code == 0 && (writeMode & 1) == 0) {
5719 lock_ObtainMutex(&fidp->mx);
5720 fidp->raw_writers++;
5721 thrd_ResetEvent(fidp->raw_write_event);
5722 lock_ReleaseMutex(&fidp->mx);
5725 smb_ReleaseFID(fidp);
5726 cm_ReleaseUser(userp);
5729 smb_SetSMBParm(outp, 0, total_written);
5730 smb_SetSMBDataLength(outp, 0);
5731 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5738 rwcp->offset.HighPart = 0;
5739 rwcp->offset.LowPart = offset.LowPart + count;
5740 rwcp->count = totalCount - count;
5741 rwcp->writeMode = writeMode;
5742 rwcp->alreadyWritten = total_written;
5744 /* set the packet data length to 3 bytes for the data block header,
5745 * plus the size of the data.
5747 smb_SetSMBParm(outp, 0, 0xffff);
5748 smb_SetSMBDataLength(outp, 0);
5753 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5756 long count, finalCount;
5763 fd = smb_GetSMBParm(inp, 0);
5764 count = smb_GetSMBParm(inp, 1);
5765 offset.HighPart = 0; /* too bad */
5766 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5768 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5769 fd, offset.LowPart, count);
5771 fd = smb_ChainFID(fd, inp);
5772 fidp = smb_FindFID(vcp, fd, 0);
5774 return CM_ERROR_BADFD;
5777 if (fidp->flags & SMB_FID_IOCTL) {
5778 return smb_IoctlRead(fidp, vcp, inp, outp);
5781 userp = smb_GetUser(vcp, inp);
5783 /* remember this for final results */
5784 smb_SetSMBParm(outp, 0, count);
5785 smb_SetSMBParm(outp, 1, 0);
5786 smb_SetSMBParm(outp, 2, 0);
5787 smb_SetSMBParm(outp, 3, 0);
5788 smb_SetSMBParm(outp, 4, 0);
5790 /* set the packet data length to 3 bytes for the data block header,
5791 * plus the size of the data.
5793 smb_SetSMBDataLength(outp, count+3);
5795 /* get op ptr after putting in the parms, since otherwise we don't
5796 * know where the data really is.
5798 op = smb_GetSMBData(outp, NULL);
5800 /* now emit the data block header: 1 byte of type and 2 bytes of length */
5801 *op++ = 1; /* data block marker */
5802 *op++ = (unsigned char) (count & 0xff);
5803 *op++ = (unsigned char) ((count >> 8) & 0xff);
5806 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5808 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5811 /* fix some things up */
5812 smb_SetSMBParm(outp, 0, finalCount);
5813 smb_SetSMBDataLength(outp, finalCount+3);
5815 smb_ReleaseFID(fidp);
5817 cm_ReleaseUser(userp);
5821 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5828 cm_scache_t *dscp; /* dir we're dealing with */
5829 cm_scache_t *scp; /* file we're creating */
5831 int initialModeBits;
5841 /* compute initial mode bits based on read-only flag in attributes */
5842 initialModeBits = 0777;
5844 tp = smb_GetSMBData(inp, NULL);
5845 pathp = smb_ParseASCIIBlock(tp, &tp);
5847 if (strcmp(pathp, "\\") == 0)
5848 return CM_ERROR_EXISTS;
5850 spacep = inp->spacep;
5851 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5853 userp = smb_GetUser(vcp, inp);
5855 caseFold = CM_FLAG_CASEFOLD;
5857 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5859 cm_ReleaseUser(userp);
5860 return CM_ERROR_NOSUCHPATH;
5863 code = cm_NameI(cm_rootSCachep, spacep->data,
5864 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5865 userp, tidPathp, &req, &dscp);
5868 cm_ReleaseUser(userp);
5872 /* otherwise, scp points to the parent directory. Do a lookup, and
5873 * fail if we find it. Otherwise, we do the create.
5879 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5880 if (scp) cm_ReleaseSCache(scp);
5881 if (code != CM_ERROR_NOSUCHFILE) {
5882 if (code == 0) code = CM_ERROR_EXISTS;
5883 cm_ReleaseSCache(dscp);
5884 cm_ReleaseUser(userp);
5888 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5889 setAttr.clientModTime = time(NULL);
5890 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5891 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5892 smb_NotifyChange(FILE_ACTION_ADDED,
5893 FILE_NOTIFY_CHANGE_DIR_NAME,
5894 dscp, lastNamep, NULL, TRUE);
5896 /* we don't need this any longer */
5897 cm_ReleaseSCache(dscp);
5900 /* something went wrong creating or truncating the file */
5901 cm_ReleaseUser(userp);
5905 /* otherwise we succeeded */
5906 smb_SetSMBDataLength(outp, 0);
5907 cm_ReleaseUser(userp);
5912 BOOL smb_IsLegalFilename(char *filename)
5915 * Find the longest substring of filename that does not contain
5916 * any of the chars in illegalChars. If that substring is less
5917 * than the length of the whole string, then one or more of the
5918 * illegal chars is in filename.
5920 if (strcspn(filename, illegalChars) < strlen(filename))
5926 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5934 cm_scache_t *dscp; /* dir we're dealing with */
5935 cm_scache_t *scp; /* file we're creating */
5937 int initialModeBits;
5949 excl = (inp->inCom == 0x03)? 0 : 1;
5951 attributes = smb_GetSMBParm(inp, 0);
5952 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5954 /* compute initial mode bits based on read-only flag in attributes */
5955 initialModeBits = 0666;
5956 if (attributes & 1) initialModeBits &= ~0222;
5958 tp = smb_GetSMBData(inp, NULL);
5959 pathp = smb_ParseASCIIBlock(tp, &tp);
5961 spacep = inp->spacep;
5962 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5964 userp = smb_GetUser(vcp, inp);
5966 caseFold = CM_FLAG_CASEFOLD;
5968 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5970 cm_ReleaseUser(userp);
5971 return CM_ERROR_NOSUCHPATH;
5973 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5974 userp, tidPathp, &req, &dscp);
5977 cm_ReleaseUser(userp);
5981 /* otherwise, scp points to the parent directory. Do a lookup, and
5982 * truncate the file if we find it, otherwise we create the file.
5984 if (!lastNamep) lastNamep = pathp;
5987 if (!smb_IsLegalFilename(lastNamep))
5988 return CM_ERROR_BADNTFILENAME;
5990 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
5991 #ifdef DEBUG_VERBOSE
5994 hexp = osi_HexifyString( lastNamep );
5995 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6000 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6001 if (code && code != CM_ERROR_NOSUCHFILE) {
6002 cm_ReleaseSCache(dscp);
6003 cm_ReleaseUser(userp);
6007 /* if we get here, if code is 0, the file exists and is represented by
6008 * scp. Otherwise, we have to create it.
6012 /* oops, file shouldn't be there */
6013 cm_ReleaseSCache(dscp);
6014 cm_ReleaseSCache(scp);
6015 cm_ReleaseUser(userp);
6016 return CM_ERROR_EXISTS;
6019 setAttr.mask = CM_ATTRMASK_LENGTH;
6020 setAttr.length.LowPart = 0;
6021 setAttr.length.HighPart = 0;
6022 code = cm_SetAttr(scp, &setAttr, userp, &req);
6025 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6026 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6027 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6029 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6030 smb_NotifyChange(FILE_ACTION_ADDED,
6031 FILE_NOTIFY_CHANGE_FILE_NAME,
6032 dscp, lastNamep, NULL, TRUE);
6033 if (!excl && code == CM_ERROR_EXISTS) {
6034 /* not an exclusive create, and someone else tried
6035 * creating it already, then we open it anyway. We
6036 * don't bother retrying after this, since if this next
6037 * fails, that means that the file was deleted after
6038 * we started this call.
6040 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6043 setAttr.mask = CM_ATTRMASK_LENGTH;
6044 setAttr.length.LowPart = 0;
6045 setAttr.length.HighPart = 0;
6046 code = cm_SetAttr(scp, &setAttr, userp, &req);
6051 /* we don't need this any longer */
6052 cm_ReleaseSCache(dscp);
6055 /* something went wrong creating or truncating the file */
6056 if (scp) cm_ReleaseSCache(scp);
6057 cm_ReleaseUser(userp);
6061 /* make sure we only open files */
6062 if (scp->fileType != CM_SCACHETYPE_FILE) {
6063 cm_ReleaseSCache(scp);
6064 cm_ReleaseUser(userp);
6065 return CM_ERROR_ISDIR;
6068 /* now all we have to do is open the file itself */
6069 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6072 /* save a pointer to the vnode */
6075 /* always create it open for read/write */
6076 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6078 smb_ReleaseFID(fidp);
6080 smb_SetSMBParm(outp, 0, fidp->fid);
6081 smb_SetSMBDataLength(outp, 0);
6083 cm_Open(scp, 0, userp);
6085 cm_ReleaseUser(userp);
6086 /* leave scp held since we put it in fidp->scp */
6090 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6103 fd = smb_GetSMBParm(inp, 0);
6104 whence = smb_GetSMBParm(inp, 1);
6105 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6107 /* try to find the file descriptor */
6108 fd = smb_ChainFID(fd, inp);
6109 fidp = smb_FindFID(vcp, fd, 0);
6110 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6111 return CM_ERROR_BADFD;
6114 userp = smb_GetUser(vcp, inp);
6116 lock_ObtainMutex(&fidp->mx);
6118 lock_ObtainMutex(&scp->mx);
6119 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6120 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6123 /* offset from current offset */
6124 offset += fidp->offset;
6126 else if (whence == 2) {
6127 /* offset from current EOF */
6128 offset += scp->length.LowPart;
6130 fidp->offset = offset;
6131 smb_SetSMBParm(outp, 0, offset & 0xffff);
6132 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6133 smb_SetSMBDataLength(outp, 0);
6135 lock_ReleaseMutex(&scp->mx);
6136 lock_ReleaseMutex(&fidp->mx);
6137 smb_ReleaseFID(fidp);
6138 cm_ReleaseUser(userp);
6142 /* dispatch all of the requests received in a packet. Due to chaining, this may
6143 * be more than one request.
6145 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6146 NCB *ncbp, raw_write_cont_t *rwcp)
6150 unsigned long code = 0;
6151 unsigned char *outWctp;
6152 int nparms; /* # of bytes of parameters */
6154 int nbytes; /* bytes of data, excluding count */
6157 unsigned short errCode;
6158 unsigned long NTStatus;
6160 unsigned char errClass;
6161 unsigned int oldGen;
6162 DWORD oldTime, newTime;
6164 /* get easy pointer to the data */
6165 smbp = (smb_t *) inp->data;
6167 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6168 /* setup the basic parms for the initial request in the packet */
6169 inp->inCom = smbp->com;
6170 inp->wctp = &smbp->wct;
6172 inp->ncb_length = ncbp->ncb_length;
6177 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6178 /* log it and discard it */
6183 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6184 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6186 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6187 1, ncbp->ncb_length, ptbuf, inp);
6188 DeregisterEventSource(h);
6190 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6195 /* We are an ongoing op */
6196 thrd_Increment(&ongoingOps);
6198 /* set up response packet for receiving output */
6199 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6200 smb_FormatResponsePacket(vcp, inp, outp);
6201 outWctp = outp->wctp;
6203 /* Remember session generation number and time */
6204 oldGen = sessionGen;
6205 oldTime = GetCurrentTime();
6207 while (inp->inCom != 0xff) {
6208 dp = &smb_dispatchTable[inp->inCom];
6210 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6211 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6212 code = outp->resumeCode;
6216 /* process each request in the packet; inCom, wctp and inCount
6217 * are already set up.
6219 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6222 /* now do the dispatch */
6223 /* start by formatting the response record a little, as a default */
6224 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6226 outWctp[1] = 0xff; /* no operation */
6227 outWctp[2] = 0; /* padding */
6232 /* not a chained request, this is a more reasonable default */
6233 outWctp[0] = 0; /* wct of zero */
6234 outWctp[1] = 0; /* and bcc (word) of zero */
6238 /* once set, stays set. Doesn't matter, since we never chain
6239 * "no response" calls.
6241 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6245 /* we have a recognized operation */
6247 if (inp->inCom == 0x1d)
6249 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6252 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
6253 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
6254 code = (*(dp->procp)) (vcp, inp, outp);
6255 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6256 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6258 if ( code == CM_ERROR_BADSMB ||
6259 code == CM_ERROR_BADOP )
6261 #endif /* LOG_PACKET */
6264 if (oldGen != sessionGen) {
6269 newTime = GetCurrentTime();
6270 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6271 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6272 newTime - oldTime, ncbp->ncb_length);
6274 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6275 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6276 DeregisterEventSource(h);
6278 osi_Log1(smb_logp, "Pkt straddled session startup, "
6279 "ncb length %d", ncbp->ncb_length);
6283 /* bad opcode, fail the request, after displaying it */
6284 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6287 #endif /* LOG_PACKET */
6291 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6292 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6293 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6294 if (code == IDCANCEL)
6298 code = CM_ERROR_BADOP;
6301 /* catastrophic failure: log as much as possible */
6302 if (code == CM_ERROR_BADSMB) {
6309 "Invalid SMB, ncb_length %d",
6312 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6313 sprintf(s, "Invalid SMB message, length %d",
6316 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6317 1, ncbp->ncb_length, ptbuf, smbp);
6318 DeregisterEventSource(h);
6321 #endif /* LOG_PACKET */
6323 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6326 code = CM_ERROR_INVAL;
6329 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6330 thrd_Decrement(&ongoingOps);
6335 /* now, if we failed, turn the current response into an empty
6336 * one, and fill in the response packet's error code.
6339 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6340 smb_MapNTError(code, &NTStatus);
6341 outWctp = outp->wctp;
6342 smbp = (smb_t *) &outp->data;
6343 if (code != CM_ERROR_PARTIALWRITE
6344 && code != CM_ERROR_BUFFERTOOSMALL
6345 && code != CM_ERROR_GSSCONTINUE) {
6346 /* nuke wct and bcc. For a partial
6347 * write or an in-process authentication handshake,
6348 * assume they're OK.
6354 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6355 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6356 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6357 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6358 smbp->flg2 |= 0x4000;
6362 smb_MapCoreError(code, vcp, &errCode, &errClass);
6363 outWctp = outp->wctp;
6364 smbp = (smb_t *) &outp->data;
6365 if (code != CM_ERROR_PARTIALWRITE) {
6366 /* nuke wct and bcc. For a partial
6367 * write, assume they're OK.
6373 smbp->errLow = (unsigned char) (errCode & 0xff);
6374 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6375 smbp->rcls = errClass;
6378 } /* error occurred */
6380 /* if we're here, we've finished one request. Look to see if
6381 * this is a chained opcode. If it is, setup things to process
6382 * the chained request, and setup the output buffer to hold the
6383 * chained response. Start by finding the next input record.
6385 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6386 break; /* not a chained req */
6387 tp = inp->wctp; /* points to start of last request */
6388 /* in a chained request, the first two
6389 * parm fields are required, and are
6390 * AndXCommand/AndXReserved and
6392 if (tp[0] < 2) break;
6393 if (tp[1] == 0xff) break; /* no more chained opcodes */
6395 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6398 /* and now append the next output request to the end of this
6399 * last request. Begin by finding out where the last response
6400 * ends, since that's where we'll put our new response.
6402 outWctp = outp->wctp; /* ptr to out parameters */
6403 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6404 nparms = outWctp[0] << 1;
6405 tp = outWctp + nparms + 1; /* now points to bcc field */
6406 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6407 tp += 2 /* for the count itself */ + nbytes;
6408 /* tp now points to the new output record; go back and patch the
6409 * second parameter (off2) to point to the new record.
6411 temp = (unsigned int)tp - ((unsigned int) outp->data);
6412 outWctp[3] = (unsigned char) (temp & 0xff);
6413 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6414 outWctp[2] = 0; /* padding */
6415 outWctp[1] = inp->inCom; /* next opcode */
6417 /* finally, setup for the next iteration */
6420 } /* while loop over all requests in the packet */
6422 /* done logging out, turn off logging-out flag */
6423 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6424 vcp->justLoggedOut = NULL;
6427 free(loggedOutName);
6428 loggedOutName = NULL;
6429 smb_ReleaseUID(loggedOutUserp);
6430 loggedOutUserp = NULL;
6434 /* now send the output packet, and return */
6436 smb_SendPacket(vcp, outp);
6437 thrd_Decrement(&ongoingOps);
6439 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6441 smb_ReleaseVC(active_vcp);
6443 "Replacing active_vcp %x with %x", active_vcp, vcp);
6447 last_msg_time = GetCurrentTime();
6449 else if (active_vcp == vcp) {
6450 smb_ReleaseVC(active_vcp);
6458 /* Wait for Netbios() calls to return, and make the results available to server
6459 * threads. Note that server threads can't wait on the NCBevents array
6460 * themselves, because NCB events are manual-reset, and the servers would race
6461 * each other to reset them.
6463 void smb_ClientWaiter(void *parmp)
6469 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6471 if (code == WAIT_OBJECT_0) {
6472 if (smbShutdownFlag == 1)
6478 /* error checking */
6479 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6481 int abandonIdx = code - WAIT_ABANDONED_0;
6482 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6485 if (code == WAIT_IO_COMPLETION)
6487 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6491 if (code == WAIT_TIMEOUT)
6493 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6496 if (code == WAIT_FAILED)
6498 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6501 idx = code - WAIT_OBJECT_0;
6503 /* check idx range! */
6504 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6506 /* this is fatal - log as much as possible */
6507 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6511 thrd_ResetEvent(NCBevents[idx]);
6512 thrd_SetEvent(NCBreturns[0][idx]);
6518 * Try to have one NCBRECV request waiting for every live session. Not more
6519 * than one, because if there is more than one, it's hard to handle Write Raw.
6521 void smb_ServerWaiter(void *parmp)
6524 int idx_session, idx_NCB;
6532 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6534 if (code == WAIT_OBJECT_0) {
6535 if ( smbShutdownFlag == 1 )
6541 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6543 int abandonIdx = code - WAIT_ABANDONED_0;
6544 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6547 if (code == WAIT_IO_COMPLETION)
6549 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6553 if (code == WAIT_TIMEOUT)
6555 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6558 if (code == WAIT_FAILED)
6560 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6563 idx_session = code - WAIT_OBJECT_0;
6565 /* check idx range! */
6566 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6568 /* this is fatal - log as much as possible */
6569 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6575 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6577 if (code == WAIT_OBJECT_0) {
6578 if ( smbShutdownFlag == 1 )
6584 /* error checking */
6585 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6587 int abandonIdx = code - WAIT_ABANDONED_0;
6588 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6591 if (code == WAIT_IO_COMPLETION)
6593 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6597 if (code == WAIT_TIMEOUT)
6599 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6602 if (code == WAIT_FAILED)
6604 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6607 idx_NCB = code - WAIT_OBJECT_0;
6609 /* check idx range! */
6610 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6612 /* this is fatal - log as much as possible */
6613 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6617 /* Link them together */
6618 NCBsessions[idx_NCB] = idx_session;
6621 ncbp = NCBs[idx_NCB];
6622 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6623 ncbp->ncb_command = NCBRECV | ASYNCH;
6624 ncbp->ncb_lana_num = lanas[idx_session];
6626 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6627 ncbp->ncb_event = NCBevents[idx_NCB];
6628 ncbp->ncb_length = SMB_PACKETSIZE;
6631 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6632 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6633 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6634 ncbp->ncb_length = SMB_PACKETSIZE;
6635 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6636 Netbios(ncbp, dos_ncb);
6642 * The top level loop for handling SMB request messages. Each server thread
6643 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6644 * NCB and buffer for the incoming request are loaned to us.
6646 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6647 * to immediately send a request for the rest of the data. This must come
6648 * before any other traffic for that session, so we delay setting the session
6649 * event until that data has come in.
6651 void smb_Server(VOID *parmp)
6653 int myIdx = (int) parmp;
6657 smb_packet_t *outbufp;
6659 int idx_NCB, idx_session;
6661 smb_vc_t *vcp = NULL;
6668 outbufp = GetPacket();
6669 outbufp->ncbp = outncbp;
6672 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6675 /* terminate silently if shutdown flag is set */
6676 if (code == WAIT_OBJECT_0) {
6677 if (smbShutdownFlag == 1) {
6678 thrd_SetEvent(smb_ServerShutdown[myIdx]);
6684 /* error checking */
6685 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6687 int abandonIdx = code - WAIT_ABANDONED_0;
6688 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6691 if (code == WAIT_IO_COMPLETION)
6693 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6697 if (code == WAIT_TIMEOUT)
6699 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6702 if (code == WAIT_FAILED)
6704 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6707 idx_NCB = code - WAIT_OBJECT_0;
6709 /* check idx range! */
6710 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6712 /* this is fatal - log as much as possible */
6713 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6717 ncbp = NCBs[idx_NCB];
6719 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6721 idx_session = NCBsessions[idx_NCB];
6722 rc = ncbp->ncb_retcode;
6724 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6725 osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6728 case NRC_GOODRET: break;
6731 /* Can this happen? Or is it just my
6738 /* Client closed session */
6739 if (reportSessionStartups)
6741 osi_Log1(smb_logp, "session [ %d ] closed", idx_session);
6743 dead_sessions[idx_session] = TRUE;
6746 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6747 /* Should also release vcp. [done] 2004-05-11 jaltman
6749 * sanity check that all TID's are gone.
6751 * TODO: check if we could use LSNs[idx_session] instead,
6752 * also cleanup after dead vcp
6757 "dead_vcp already set, %x",
6759 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6761 "setting dead_vcp %x, user struct %x",
6765 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6767 if (vcp->justLoggedOut) {
6769 loggedOutTime = vcp->logoffTime;
6770 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
6771 loggedOutUserp = vcp->justLoggedOut;
6772 lock_ObtainWrite(&smb_rctLock);
6773 loggedOutUserp->refCount++;
6774 lock_ReleaseWrite(&smb_rctLock);
6780 /* Treat as transient error */
6787 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6788 sprintf(s, "SMB message incomplete, length %d",
6791 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6793 ncbp->ncb_length, ptbuf,
6795 DeregisterEventSource(h);
6798 "dispatch smb recv failed, message incomplete, ncb_length %d",
6801 "SMB message incomplete, "
6802 "length %d", ncbp->ncb_length);
6805 * We used to discard the packet.
6806 * Instead, try handling it normally.
6814 /* A weird error code. Log it, sleep, and
6816 if (vcp && vcp->errorCount++ > 3) {
6817 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6818 dead_sessions[idx_session] = TRUE;
6822 thrd_SetEvent(SessionEvents[idx_session]);
6827 /* Success, so now dispatch on all the data in the packet */
6829 smb_concurrentCalls++;
6830 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6831 smb_maxObsConcurrentCalls = smb_concurrentCalls;
6835 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6837 * If at this point vcp is NULL (implies that packet was invalid)
6838 * then we are in big trouble. This means either :
6839 * a) we have the wrong NCB.
6840 * b) Netbios screwed up the call.
6841 * Obviously this implies that
6842 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
6843 * lanas[idx_session] != ncbp->ncb_lana_num )
6844 * Either way, we can't do anything with this packet.
6845 * Log, sleep and resume.
6854 "LSNs[idx_session]=[%d],"
6855 "lanas[idx_session]=[%d],"
6856 "ncbp->ncb_lsn=[%d],"
6857 "ncbp->ncb_lana_num=[%d]",
6861 ncbp->ncb_lana_num);
6865 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6867 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6868 DeregisterEventSource(h);
6871 /* Also log in the trace log. */
6872 osi_Log4(smb_logp, "Server: BAD VCP!"
6873 "LSNs[idx_session]=[%d],"
6874 "lanas[idx_session]=[%d],"
6875 "ncbp->ncb_lsn=[%d],"
6876 "ncbp->ncb_lana_num=[%d]",
6880 ncbp->ncb_lana_num);
6882 /* thrd_Sleep(1000); Don't bother sleeping */
6883 thrd_SetEvent(SessionEvents[idx_session]);
6884 smb_concurrentCalls--;
6889 vcp->errorCount = 0;
6890 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6892 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6893 /* copy whole packet to virtual memory */
6894 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6896 bufp->dos_pkt / 16, bufp);*/
6898 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6900 smbp = (smb_t *)bufp->data;
6903 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6907 if (smbp->com == 0x1d) {
6908 /* Special handling for Write Raw */
6909 raw_write_cont_t rwc;
6910 EVENT_HANDLE rwevent;
6911 char eventName[MAX_PATH];
6913 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6914 if (rwc.code == 0) {
6915 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6916 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6917 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6918 ncbp->ncb_command = NCBRECV | ASYNCH;
6919 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6920 ncbp->ncb_lana_num = vcp->lana;
6921 ncbp->ncb_buffer = rwc.buf;
6922 ncbp->ncb_length = 65535;
6923 ncbp->ncb_event = rwevent;
6927 Netbios(ncbp, dos_ncb);
6929 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6930 thrd_CloseHandle(rwevent);
6932 thrd_SetEvent(SessionEvents[idx_session]);
6934 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6936 else if (smbp->com == 0xa0) {
6938 * Serialize the handling for NT Transact
6941 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6942 thrd_SetEvent(SessionEvents[idx_session]);
6944 thrd_SetEvent(SessionEvents[idx_session]);
6945 /* TODO: what else needs to be serialized? */
6946 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6948 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6950 __except( smb_ServerExceptionFilter() ) {
6954 smb_concurrentCalls--;
6957 thrd_SetEvent(NCBavails[idx_NCB]);
6964 * Exception filter for the server threads. If an exception occurs in the
6965 * dispatch routines, which is where exceptions are most common, then do a
6966 * force trace and give control to upstream exception handlers. Useful for
6969 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6970 DWORD smb_ServerExceptionFilter(void) {
6971 /* While this is not the best time to do a trace, if it succeeds, then
6972 * we have a trace (assuming tracing was enabled). Otherwise, this should
6973 * throw a second exception.
6978 ptbuf[0] = "Unhandled exception forcing trace";
6980 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6982 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6983 DeregisterEventSource(h);
6986 afsd_ForceTrace(TRUE);
6987 buf_ForceTrace(TRUE);
6988 return EXCEPTION_CONTINUE_SEARCH;
6993 * Create a new NCB and associated events, packet buffer, and "space" buffer.
6994 * If the number of server threads is M, and the number of live sessions is
6995 * N, then the number of NCB's in use at any time either waiting for, or
6996 * holding, received messages is M + N, so that is how many NCB's get created.
6998 void InitNCBslot(int idx)
7000 struct smb_packet *bufp;
7001 EVENT_HANDLE retHandle;
7003 char eventName[MAX_PATH];
7005 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7007 NCBs[idx] = GetNCB();
7008 sprintf(eventName,"NCBavails[%d]", idx);
7009 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7010 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7011 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7013 sprintf(eventName,"NCBevents[%d]", idx);
7014 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7015 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7016 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7018 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7019 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7020 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7021 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7022 for (i=0; i<smb_NumServerThreads; i++)
7023 NCBreturns[i][idx] = retHandle;
7025 bufp->spacep = cm_GetSpace();
7029 /* listen for new connections */
7030 void smb_Listener(void *parmp)
7038 char rname[NCBNAMSZ+1];
7039 char cname[MAX_COMPUTERNAME_LENGTH+1];
7040 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7045 int lana = (int) parmp;
7049 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7052 /* retrieve computer name */
7053 GetComputerName(cname, &cnamelen);
7057 memset(ncbp, 0, sizeof(NCB));
7060 ncbp->ncb_command = NCBLISTEN;
7061 ncbp->ncb_rto = 0; /* No receive timeout */
7062 ncbp->ncb_sto = 0; /* No send timeout */
7064 /* pad out with spaces instead of null termination */
7065 len = strlen(smb_localNamep);
7066 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7067 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7069 strcpy(ncbp->ncb_callname, "*");
7070 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7072 ncbp->ncb_lana_num = lana;
7075 code = Netbios(ncbp);
7077 code = Netbios(ncbp, dos_ncb);
7086 /* terminate silently if shutdown flag is set */
7087 if (smbShutdownFlag == 1) {
7096 "NCBLISTEN lana=%d failed with code %d",
7097 ncbp->ncb_lana_num, code);
7099 "Client exiting due to network failure. Please restart client.\n");
7103 "Client exiting due to network failure. Please restart client.\n"
7104 "NCBLISTEN lana=%d failed with code %d",
7105 ncbp->ncb_lana_num, code);
7107 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7108 MB_OK|MB_SERVICE_NOTIFICATION);
7109 osi_assert(tbuffer);
7112 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7113 ncbp->ncb_lana_num, code);
7114 fprintf(stderr, "\nClient exiting due to network failure "
7115 "(possibly due to power-saving mode)\n");
7116 fprintf(stderr, "Please restart client.\n");
7117 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7121 /* check for remote conns */
7122 /* first get remote name and insert null terminator */
7123 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7124 for (i=NCBNAMSZ; i>0; i--) {
7125 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7131 /* compare with local name */
7133 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7134 flags |= SMB_VCFLAG_REMOTECONN;
7136 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7138 lock_ObtainMutex(&smb_ListenerLock);
7140 /* New generation */
7143 /* Log session startup */
7145 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7147 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7148 #endif /* NOTSERVICE */
7149 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7150 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7152 if (reportSessionStartups) {
7158 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7159 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7161 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7163 DeregisterEventSource(h);
7166 fprintf(stderr, "%s: New session %d starting from host %s\n",
7167 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7171 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7172 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7175 /* now ncbp->ncb_lsn is the connection ID */
7176 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7177 vcp->flags |= flags;
7178 strcpy(vcp->rname, rname);
7180 /* Allocate slot in session arrays */
7181 /* Re-use dead session if possible, otherwise add one more */
7182 /* But don't look at session[0], it is reserved */
7183 for (i = 1; i < numSessions; i++) {
7184 if (dead_sessions[i]) {
7185 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7186 dead_sessions[i] = FALSE;
7191 /* assert that we do not exceed the maximum number of sessions or NCBs.
7192 * we should probably want to wait for a session to be freed in case
7196 osi_assert(i < Sessionmax - 1);
7197 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7199 LSNs[i] = ncbp->ncb_lsn;
7200 lanas[i] = ncbp->ncb_lana_num;
7202 if (i == numSessions) {
7203 /* Add new NCB for new session */
7204 char eventName[MAX_PATH];
7206 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7208 InitNCBslot(numNCBs);
7210 thrd_SetEvent(NCBavails[0]);
7211 thrd_SetEvent(NCBevents[0]);
7212 for (j = 0; j < smb_NumServerThreads; j++)
7213 thrd_SetEvent(NCBreturns[j][0]);
7214 /* Also add new session event */
7215 sprintf(eventName, "SessionEvents[%d]", i);
7216 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7217 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7218 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7220 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7221 thrd_SetEvent(SessionEvents[0]);
7223 thrd_SetEvent(SessionEvents[i]);
7226 lock_ReleaseMutex(&smb_ListenerLock);
7228 } /* dispatch while loop */
7231 /* initialize Netbios */
7232 void smb_NetbiosInit()
7238 int i, lana, code, l;
7240 int delname_tried=0;
7243 OSVERSIONINFO Version;
7245 /* AFAIK, this is the default for the ms loopback adapter.*/
7246 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
7247 /*******************************************************************/
7249 /* Get the version of Windows */
7250 memset(&Version, 0x00, sizeof(Version));
7251 Version.dwOSVersionInfoSize = sizeof(Version);
7252 GetVersionEx(&Version);
7254 /* setup the NCB system */
7257 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7261 if (smb_LANadapter == -1) {
7262 ncbp->ncb_command = NCBENUM;
7263 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7264 ncbp->ncb_length = sizeof(lana_list);
7265 code = Netbios(ncbp);
7267 sprintf(s, "Netbios NCBENUM error code %d", code);
7268 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7269 osi_panic(s, __FILE__, __LINE__);
7273 lana_list.length = 1;
7274 lana_list.lana[0] = smb_LANadapter;
7277 for (i = 0; i < lana_list.length; i++) {
7278 /* reset the adaptor: in Win32, this is required for every process, and
7279 * acts as an init call, not as a real hardware reset.
7281 ncbp->ncb_command = NCBRESET;
7282 ncbp->ncb_callname[0] = 100;
7283 ncbp->ncb_callname[2] = 100;
7284 ncbp->ncb_lana_num = lana_list.lana[i];
7285 code = Netbios(ncbp);
7287 code = ncbp->ncb_retcode;
7289 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7290 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7291 lana_list.lana[i] = 255; /* invalid lana */
7293 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7294 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7298 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7299 we will just fake the LANA list */
7300 if (smb_LANadapter == -1) {
7301 for (i = 0; i < 8; i++)
7302 lana_list.lana[i] = i;
7303 lana_list.length = 8;
7306 lana_list.length = 1;
7307 lana_list.lana[0] = smb_LANadapter;
7311 /* and declare our name so we can receive connections */
7312 memset(ncbp, 0, sizeof(*ncbp));
7313 len=lstrlen(smb_localNamep);
7314 memset(smb_sharename,' ',NCBNAMSZ);
7315 memcpy(smb_sharename,smb_localNamep,len);
7316 sprintf(s, "lana_list.length %d", lana_list.length);
7317 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7319 /* Keep the name so we can unregister it later */
7320 for (l = 0; l < lana_list.length; l++) {
7321 lana = lana_list.lana[l];
7323 ncbp->ncb_command = NCBADDNAME;
7324 ncbp->ncb_lana_num = lana;
7325 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7327 code = Netbios(ncbp);
7329 code = Netbios(ncbp, dos_ncb);
7332 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7333 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7335 char name[NCBNAMSZ+1];
7337 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7338 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7341 if (code == 0) code = ncbp->ncb_retcode;
7343 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7345 /* we only use one LANA with djgpp */
7346 lana_list.lana[0] = lana;
7347 lana_list.length = 1;
7351 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7352 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7353 if (code == NRC_BRIDGE) { /* invalid LANA num */
7354 lana_list.lana[l] = 255;
7357 else if (code == NRC_DUPNAME) {
7358 osi_Log0(smb_logp, "Name already exists; try to delete it");
7359 memset(ncbp, 0, sizeof(*ncbp));
7360 ncbp->ncb_command = NCBDELNAME;
7361 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7362 ncbp->ncb_lana_num = lana;
7364 code = Netbios(ncbp);
7366 code = Netbios(ncbp, dos_ncb);
7369 code = ncbp->ncb_retcode;
7371 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7372 osi_Log0(smb_logp, s);
7374 if (code != 0 || delname_tried) {
7375 lana_list.lana[l] = 255;
7377 else if (code == 0) {
7378 if (!delname_tried) {
7386 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7387 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7388 lana_list.lana[l] = 255; /* invalid lana */
7389 osi_panic(s, __FILE__, __LINE__);
7393 lana_found = 1; /* at least one worked */
7400 osi_assert(lana_list.length >= 0);
7402 sprintf(s, "No valid LANA numbers found!");
7403 osi_panic(s, __FILE__, __LINE__);
7406 /* we're done with the NCB now */
7410 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7427 EVENT_HANDLE retHandle;
7428 char eventName[MAX_PATH];
7431 smb_MBfunc = aMBfunc;
7435 smb_LANadapter = LANadapt;
7437 /* Initialize smb_localZero */
7438 myTime.tm_isdst = -1; /* compute whether on DST or not */
7439 myTime.tm_year = 70;
7445 smb_localZero = mktime(&myTime);
7447 /* Initialize kludge-GMT */
7448 smb_CalculateNowTZ();
7450 #ifdef AFS_FREELANCE_CLIENT
7451 /* Make sure the root.afs volume has the correct time */
7452 cm_noteLocalMountPointChange();
7455 /* initialize the remote debugging log */
7458 /* remember the name */
7459 len = strlen(snamep);
7460 smb_localNamep = malloc(len+1);
7461 strcpy(smb_localNamep, snamep);
7462 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7464 /* and the global lock */
7465 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7466 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7468 /* Raw I/O data structures */
7469 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7471 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7473 /* 4 Raw I/O buffers */
7475 smb_RawBufs = calloc(65536,1);
7476 *((char **)smb_RawBufs) = NULL;
7477 for (i=0; i<3; i++) {
7478 char *rawBuf = calloc(65536,1);
7479 *((char **)rawBuf) = smb_RawBufs;
7480 smb_RawBufs = rawBuf;
7483 npar = 65536 >> 4; /* number of paragraphs */
7484 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7486 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7488 osi_panic("",__FILE__,__LINE__);
7491 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7494 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7496 _farpokel(_dos_ds, smb_RawBufs, NULL);
7497 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7498 npar = 65536 >> 4; /* number of paragraphs */
7499 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7501 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7503 osi_panic("",__FILE__,__LINE__);
7506 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7509 rawBuf = (seg * 16) + 0; /* DOS physical address */
7510 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7511 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7512 smb_RawBufs = rawBuf;
7516 /* global free lists */
7517 smb_ncbFreeListp = NULL;
7518 smb_packetFreeListp = NULL;
7522 /* Initialize listener and server structures */
7524 memset(dead_sessions, 0, sizeof(dead_sessions));
7525 sprintf(eventName, "SessionEvents[0]");
7526 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7527 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7528 afsi_log("Event Object Already Exists: %s", eventName);
7530 smb_NumServerThreads = nThreads;
7531 sprintf(eventName, "NCBavails[0]");
7532 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7533 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7534 afsi_log("Event Object Already Exists: %s", eventName);
7535 sprintf(eventName, "NCBevents[0]");
7536 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7537 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7538 afsi_log("Event Object Already Exists: %s", eventName);
7539 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7540 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7541 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7542 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7543 afsi_log("Event Object Already Exists: %s", eventName);
7544 for (i = 0; i < smb_NumServerThreads; i++) {
7545 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7546 NCBreturns[i][0] = retHandle;
7549 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
7550 for (i = 0; i < smb_NumServerThreads; i++) {
7551 sprintf(eventName, "smb_ServerShutdown[%d]", i);
7552 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7553 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7554 afsi_log("Event Object Already Exists: %s", eventName);
7557 for (i = 1; i <= nThreads; i++)
7559 numNCBs = nThreads + 1;
7561 /* Initialize dispatch table */
7562 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7563 /* Prepare the table for unknown operations */
7564 for(i=0; i<= SMB_NOPCODES; i++) {
7565 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7567 /* Fill in the ones we do know */
7568 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7569 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7570 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7571 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7572 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7573 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7574 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7575 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7576 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7577 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7578 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7579 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7580 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7581 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7582 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7583 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7584 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7585 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7586 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7587 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7588 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7589 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7590 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7591 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7592 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7593 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7594 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7595 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7596 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7597 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7598 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7599 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7600 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7601 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7602 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7603 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7604 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7605 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7606 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7607 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7608 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7609 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7610 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7611 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7612 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7613 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7614 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7615 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7616 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7617 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7618 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7619 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7620 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7621 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7622 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7623 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7624 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
7625 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
7626 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
7627 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7628 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7629 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7630 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7631 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7632 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
7633 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
7634 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
7635 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
7636 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
7637 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
7638 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
7639 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
7641 /* setup tran 2 dispatch table */
7642 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7643 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7644 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7645 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7646 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7647 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7648 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7649 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7650 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7651 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7652 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7653 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7654 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7655 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
7656 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
7657 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
7658 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
7660 /* setup the rap dispatch table */
7661 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
7662 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
7663 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
7664 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
7665 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
7669 /* if we are doing SMB authentication we have register outselves as a logon process */
7670 if (smb_authType != SMB_AUTH_NONE) {
7672 LSA_STRING afsProcessName;
7673 LSA_OPERATIONAL_MODE dummy; /*junk*/
7675 afsProcessName.Buffer = "OpenAFSClientDaemon";
7676 afsProcessName.Length = strlen(afsProcessName.Buffer);
7677 afsProcessName.MaximumLength = afsProcessName.Length + 1;
7679 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
7681 if (nts == STATUS_SUCCESS) {
7682 LSA_STRING packageName;
7683 /* we are registered. Find out the security package id */
7684 packageName.Buffer = MSV1_0_PACKAGE_NAME;
7685 packageName.Length = strlen(packageName.Buffer);
7686 packageName.MaximumLength = packageName.Length + 1;
7687 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
7688 if (nts == STATUS_SUCCESS) {
7689 smb_lsaLogonOrigin.Buffer = "OpenAFS";
7690 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
7691 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
7693 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
7696 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
7699 if (nts != STATUS_SUCCESS) {
7700 /* something went wrong. We report the error and revert back to no authentication
7701 because we can't perform any auth requests without a successful lsa handle
7702 or sec package id. */
7703 afsi_log("Reverting to NO SMB AUTH");
7704 smb_authType = SMB_AUTH_NONE;
7707 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
7708 * time prevents the failure of authentication when logged into Windows with an
7709 * external Kerberos principal mapped to a local account.
7711 else if ( smb_authType == SMB_AUTH_EXTENDED) {
7712 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
7713 * then the only option is NTLMSSP anyway; so just fallback.
7718 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
7719 if (secBlobLength == 0) {
7720 smb_authType = SMB_AUTH_NTLM;
7721 afsi_log("Reverting to SMB AUTH NTLM");
7730 /* Now get ourselves a domain name. */
7731 /* For now we are using the local computer name as the domain name.
7732 * It is actually the domain for local logins, and we are acting as
7733 * a local SMB server.
7735 bufsize = sizeof(smb_ServerDomainName) - 1;
7736 GetComputerName(smb_ServerDomainName, &bufsize);
7737 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
7738 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
7741 /* Start listeners, waiters, servers, and daemons */
7743 for (i = 0; i < lana_list.length; i++) {
7744 if (lana_list.lana[i] == 255) continue;
7745 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7746 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7747 osi_assert(phandle != NULL);
7748 thrd_CloseHandle(phandle);
7752 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7753 NULL, 0, &lpid, "smb_ClientWaiter");
7754 osi_assert(phandle != NULL);
7755 thrd_CloseHandle(phandle);
7758 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7759 NULL, 0, &lpid, "smb_ServerWaiter");
7760 osi_assert(phandle != NULL);
7761 thrd_CloseHandle(phandle);
7763 for (i=0; i<nThreads; i++) {
7764 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7765 (void *) i, 0, &lpid, "smb_Server");
7766 osi_assert(phandle != NULL);
7767 thrd_CloseHandle(phandle);
7770 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7771 NULL, 0, &lpid, "smb_Daemon");
7772 osi_assert(phandle != NULL);
7773 thrd_CloseHandle(phandle);
7775 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7776 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7777 osi_assert(phandle != NULL);
7778 thrd_CloseHandle(phandle);
7787 void smb_Shutdown(void)
7796 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7798 /* setup the NCB system */
7801 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7804 /* Block new sessions by setting shutdown flag */
7805 smbShutdownFlag = 1;
7807 /* Hang up all sessions */
7808 memset((char *)ncbp, 0, sizeof(NCB));
7809 for (i = 1; i < numSessions; i++)
7811 if (dead_sessions[i])
7814 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7815 ncbp->ncb_command = NCBHANGUP;
7816 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
7817 ncbp->ncb_lsn = LSNs[i];
7819 code = Netbios(ncbp);
7821 code = Netbios(ncbp, dos_ncb);
7823 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7824 if (code == 0) code = ncbp->ncb_retcode;
7826 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7827 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7831 /* Delete Netbios name */
7832 memset((char *)ncbp, 0, sizeof(NCB));
7833 for (i = 0; i < lana_list.length; i++) {
7834 if (lana_list.lana[i] == 255) continue;
7835 ncbp->ncb_command = NCBDELNAME;
7836 ncbp->ncb_lana_num = lana_list.lana[i];
7837 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7839 code = Netbios(ncbp);
7841 code = Netbios(ncbp, dos_ncb);
7844 code = ncbp->ncb_retcode;
7846 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7847 ncbp->ncb_lana_num, code);
7852 /* Trigger the shutdown of all SMB threads */
7853 for (i = 0; i < smb_NumServerThreads; i++)
7854 thrd_SetEvent(NCBreturns[i][0]);
7856 thrd_SetEvent(NCBevents[0]);
7857 thrd_SetEvent(SessionEvents[0]);
7858 thrd_SetEvent(NCBavails[0]);
7860 for (i = 0;i < smb_NumServerThreads; i++) {
7861 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], INFINITE);
7862 if (code == WAIT_OBJECT_0) {
7865 afsi_log("smb_Shutdown[%d] wait error",i);
7870 /* Get the UNC \\<servername>\<sharename> prefix. */
7871 char *smb_GetSharename()
7875 /* Make sure we have been properly initialized. */
7876 if (smb_localNamep == NULL)
7879 /* Allocate space for \\<servername>\<sharename>, plus the
7882 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7883 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7889 void smb_LogPacket(smb_packet_t *packet)
7892 unsigned length, paramlen, datalen, i, j;
7894 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7896 if (!packet) return;
7898 osi_Log0(smb_logp, "*** SMB packet dump ***");
7900 vp = (BYTE *) packet->data;
7902 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7903 length = paramlen + 2 + datalen;
7906 for (i=0;i < length; i+=16)
7908 memset( buf, ' ', 80 );
7913 buf[strlen(buf)] = ' ';
7915 cp = (BYTE*) buf + 7;
7917 for (j=0;j < 16 && (i+j)<length; j++)
7919 *(cp++) = hex[vp[i+j] >> 4];
7920 *(cp++) = hex[vp[i+j] & 0xf];
7930 for (j=0;j < 16 && (i+j)<length;j++)
7932 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7943 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
7946 osi_Log0(smb_logp, "*** End SMB packet dump ***");
7948 #endif /* LOG_PACKET */
7951 int smb_DumpVCP(FILE *outputFile, char *cookie)
7958 lock_ObtainRead(&smb_rctLock);
7960 sprintf(output, "begin dumping vcpsp\n");
7961 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7963 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
7967 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7968 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7969 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7971 sprintf(output, "begin dumping fidsp\n");
7972 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7974 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
7976 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",
7977 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
7978 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
7979 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7980 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7983 sprintf(output, "done dumping fidsp\n");
7984 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7987 sprintf(output, "done dumping vcpsp\n");
7988 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7990 lock_ReleaseRead(&smb_rctLock);