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 int smb_StoreAnsiFilenames = 0;
56 DWORD last_msg_time = 0;
60 unsigned int sessionGen = 0;
62 extern void afsi_log(char *pattern, ...);
63 extern HANDLE afsi_file;
65 osi_hyper_t hzero = {0, 0};
66 osi_hyper_t hones = {0xFFFFFFFF, -1};
69 osi_rwlock_t smb_globalLock;
70 osi_rwlock_t smb_rctLock;
71 osi_mutex_t smb_ListenerLock;
74 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
85 int smb_NumServerThreads;
87 int numNCBs, numSessions, numVCs;
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
92 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
94 ULONG smb_lsaSecPackage;
95 LSA_STRING smb_lsaLogonOrigin;
97 #define NCBmax MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
99 EVENT_HANDLE **NCBreturns;
100 EVENT_HANDLE *smb_ServerShutdown;
101 DWORD NCBsessions[NCBmax];
103 struct smb_packet *bufs[NCBmax];
105 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
106 EVENT_HANDLE SessionEvents[Sessionmax];
107 unsigned short LSNs[Sessionmax];
108 int lanas[Sessionmax];
109 BOOL dead_sessions[Sessionmax];
113 osi_mutex_t smb_RawBufLock;
115 #define SMB_RAW_BUFS 4
117 int smb_RawBufSel[SMB_RAW_BUFS];
122 #define SMB_MASKFLAG_TILDE 1
123 #define SMB_MASKFLAG_CASEFOLD 2
125 #define RAWTIMEOUT INFINITE
128 typedef struct raw_write_cont {
141 /* dir search stuff */
142 long smb_dirSearchCounter = 1;
143 smb_dirSearch_t *smb_firstDirSearchp;
144 smb_dirSearch_t *smb_lastDirSearchp;
146 /* hide dot files? */
147 int smb_hideDotFiles;
149 /* global state about V3 protocols */
150 int smb_useV3; /* try to negotiate V3 */
153 static showErrors = 1;
154 /* MessageBox or something like it */
155 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
156 extern HANDLE WaitToTerminate;
160 * Time in Unix format of midnight, 1/1/1970 local time.
161 * When added to dosUTime, gives Unix (AFS) time.
163 time_t smb_localZero = 0;
165 /* Time difference for converting to kludge-GMT */
168 char *smb_localNamep = NULL;
170 smb_vc_t *smb_allVCsp;
172 smb_username_t *usernamesp = NULL;
174 smb_waitingLock_t *smb_allWaitingLocks;
177 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
178 NCB *ncbp, raw_write_cont_t *rwcp);
179 void smb_NetbiosInit();
181 #ifndef AFS_WIN95_ENV
182 DWORD smb_ServerExceptionFilter(void);
185 extern char cm_HostName[];
186 extern char cm_confDir[];
190 #define LPTSTR char *
191 #define GetComputerName(str, sizep) \
192 strcpy((str), cm_HostName); \
193 *(sizep) = strlen(cm_HostName)
197 void smb_LogPacket(smb_packet_t *packet);
198 #endif /* LOG_PACKET */
199 extern char AFSConfigKeyName[];
201 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
202 int smb_ServerDomainNameLength = 0;
203 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
204 int smb_ServerOSLength = sizeof(smb_ServerOS);
205 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
206 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
208 /* Faux server GUID. This is never checked. */
209 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
211 char * myCrt_Dispatch(int i)
216 return "(00)ReceiveCoreMakeDir";
218 return "(01)ReceiveCoreRemoveDir";
220 return "(02)ReceiveCoreOpen";
222 return "(03)ReceiveCoreCreate";
224 return "(04)ReceiveCoreClose";
226 return "(05)ReceiveCoreFlush";
228 return "(06)ReceiveCoreUnlink";
230 return "(07)ReceiveCoreRename";
232 return "(08)ReceiveCoreGetFileAttributes";
234 return "(09)ReceiveCoreSetFileAttributes";
236 return "(0a)ReceiveCoreRead";
238 return "(0b)ReceiveCoreWrite";
240 return "(0c)ReceiveCoreLockRecord";
242 return "(0d)ReceiveCoreUnlockRecord";
244 return "(0e)SendCoreBadOp";
246 return "(0f)ReceiveCoreCreate";
248 return "(10)ReceiveCoreCheckPath";
250 return "(11)SendCoreBadOp";
252 return "(12)ReceiveCoreSeek";
254 return "(1a)ReceiveCoreReadRaw";
256 return "(1d)ReceiveCoreWriteRawDummy";
258 return "(22)ReceiveV3SetAttributes";
260 return "(23)ReceiveV3GetAttributes";
262 return "(24)ReceiveV3LockingX";
264 return "(25)ReceiveV3Trans";
266 return "(26)ReceiveV3Trans[aux]";
268 return "(29)SendCoreBadOp";
270 return "(2b)ReceiveCoreEcho";
272 return "(2d)ReceiveV3OpenX";
274 return "(2e)ReceiveV3ReadX";
276 return "(32)ReceiveV3Tran2A";
278 return "(33)ReceiveV3Tran2A[aux]";
280 return "(34)ReceiveV3FindClose";
282 return "(35)ReceiveV3FindNotifyClose";
284 return "(70)ReceiveCoreTreeConnect";
286 return "(71)ReceiveCoreTreeDisconnect";
288 return "(72)ReceiveNegotiate";
290 return "(73)ReceiveV3SessionSetupX";
292 return "(74)ReceiveV3UserLogoffX";
294 return "(75)ReceiveV3TreeConnectX";
296 return "(80)ReceiveCoreGetDiskAttributes";
298 return "(81)ReceiveCoreSearchDir";
302 return "(83)FindUnique";
304 return "(84)FindClose";
306 return "(A0)ReceiveNTTransact";
308 return "(A2)ReceiveNTCreateX";
310 return "(A4)ReceiveNTCancel";
312 return "(A5)ReceiveNTRename";
314 return "(C0)OpenPrintFile";
316 return "(C1)WritePrintFile";
318 return "(C2)ClosePrintFile";
320 return "(C3)GetPrintQueue";
322 return "(D8)ReadBulk";
324 return "(D9)WriteBulk";
326 return "(DA)WriteBulkData";
328 return "unknown SMB op";
332 char * myCrt_2Dispatch(int i)
337 return "unknown SMB op-2";
339 return "S(00)CreateFile";
341 return "S(01)FindFirst";
343 return "S(02)FindNext"; /* FindNext */
345 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
349 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
351 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
353 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
355 return "S(08)??_ReceiveTran2SetFileInfo";
357 return "S(09)??_ReceiveTran2FSCTL";
359 return "S(0a)_ReceiveTran2IOCTL";
361 return "S(0b)_ReceiveTran2FindNotifyFirst";
363 return "S(0c)_ReceiveTran2FindNotifyNext";
365 return "S(0d)_ReceiveTran2CreateDirectory";
367 return "S(0e)_ReceiveTran2SessionSetup";
369 return "S(10)_ReceiveTran2GetDfsReferral";
371 return "S(11)_ReceiveTran2ReportDfsInconsistency";
375 char * myCrt_RapDispatch(int i)
380 return "unknown RAP OP";
382 return "RAP(0)NetShareEnum";
384 return "RAP(1)NetShareGetInfo";
386 return "RAP(13)NetServerGetInfo";
388 return "RAP(63)NetWkStaGetInfo";
392 /* scache must be locked */
393 unsigned int smb_Attributes(cm_scache_t *scp)
397 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
398 scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
400 attrs = SMB_ATTR_DIRECTORY;
401 #ifdef SPECIAL_FOLDERS
402 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
403 #endif /* SPECIAL_FOLDERS */
408 * We used to mark a file RO if it was in an RO volume, but that
409 * turns out to be impolitic in NT. See defect 10007.
412 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
414 if ((scp->unixModeBits & 0222) == 0)
415 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
420 /* Check if the named file/dir is a dotfile/dotdir */
421 /* String pointed to by lastComp can have leading slashes, but otherwise should have
422 no other patch components */
423 unsigned int smb_IsDotFile(char *lastComp) {
426 /* skip over slashes */
427 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
432 /* nulls, curdir and parent dir doesn't count */
438 if(*(s+1) == '.' && !*(s + 2))
445 static int ExtractBits(WORD bits, short start, short len)
452 num = bits << (16 - end);
453 num = num >> ((16 - end) + start);
459 void ShowUnixTime(char *FuncName, time_t unixTime)
464 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
466 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
467 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
469 int day, month, year, sec, min, hour;
472 day = ExtractBits(wDate, 0, 5);
473 month = ExtractBits(wDate, 5, 4);
474 year = ExtractBits(wDate, 9, 7) + 1980;
476 sec = ExtractBits(wTime, 0, 5);
477 min = ExtractBits(wTime, 5, 6);
478 hour = ExtractBits(wTime, 11, 5);
480 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
481 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
487 /* Determine if we are observing daylight savings time */
488 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
490 TIME_ZONE_INFORMATION timeZoneInformation;
491 SYSTEMTIME utc, local, localDST;
493 /* Get the time zone info. NT uses this to calc if we are in DST. */
494 GetTimeZoneInformation(&timeZoneInformation);
496 /* Return the daylight bias */
497 *pDstBias = timeZoneInformation.DaylightBias;
499 /* Return the bias */
500 *pBias = timeZoneInformation.Bias;
502 /* Now determine if DST is being observed */
504 /* Get the UTC (GMT) time */
507 /* Convert UTC time to local time using the time zone info. If we are
508 observing DST, the calculated local time will include this.
510 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
512 /* Set the daylight bias to 0. The daylight bias is the amount of change
513 * in time that we use for daylight savings time. By setting this to 0
514 * we cause there to be no change in time during daylight savings time.
516 timeZoneInformation.DaylightBias = 0;
518 /* Convert the utc time to local time again, but this time without any
519 adjustment for daylight savings time.
521 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
523 /* If the two times are different, then it means that the localDST that
524 we calculated includes the daylight bias, and therefore we are
525 observing daylight savings time.
527 *pDST = localDST.wHour != local.wHour;
530 /* Determine if we are observing daylight savings time */
531 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
537 *pDstBias = -60; /* where can this be different? */
543 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
545 BOOL dst; /* Will be TRUE if observing DST */
546 LONG dstBias; /* Offset from local time if observing DST */
547 LONG bias; /* Offset from GMT for local time */
550 * This function will adjust the last write time to compensate
551 * for two bugs in the smb client:
553 * 1) During Daylight Savings Time, the LastWriteTime is ahead
554 * in time by the DaylightBias (ignoring the sign - the
555 * DaylightBias is always stored as a negative number). If
556 * the DaylightBias is -60, then the LastWriteTime will be
557 * ahead by 60 minutes.
559 * 2) If the local time zone is a positive offset from GMT, then
560 * the LastWriteTime will be the correct local time plus the
561 * Bias (ignoring the sign - a positive offset from GMT is
562 * always stored as a negative Bias). If the Bias is -120,
563 * then the LastWriteTime will be ahead by 120 minutes.
565 * These bugs can occur at the same time.
568 GetTimeZoneInfo(&dst, &dstBias, &bias);
570 /* First adjust for DST */
572 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
574 /* Now adjust for a positive offset from GMT (a negative bias). */
576 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
580 * Calculate the difference (in seconds) between local time and GMT.
581 * This enables us to convert file times to kludge-GMT.
587 struct tm gmt_tm, local_tm;
588 int days, hours, minutes, seconds;
591 gmt_tm = *(gmtime(&t));
592 local_tm = *(localtime(&t));
594 days = local_tm.tm_yday - gmt_tm.tm_yday;
595 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
597 /* There is a problem with DST immediately after the time change
598 * which may continue to exist until the machine is rebooted
600 - (local_tm.tm_isdst ? 1 : 0)
603 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
604 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
610 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
615 time_t ersatz_unixTime;
618 * Must use kludge-GMT instead of real GMT.
619 * kludge-GMT is computed by adding time zone difference to localtime.
622 * ltp = gmtime(&unixTime);
624 ersatz_unixTime = unixTime - smb_NowTZ;
625 ltp = localtime(&ersatz_unixTime);
627 /* if we fail, make up something */
630 localJunk.tm_year = 89 - 20;
631 localJunk.tm_mon = 4;
632 localJunk.tm_mday = 12;
633 localJunk.tm_hour = 0;
634 localJunk.tm_min = 0;
635 localJunk.tm_sec = 0;
638 stm.wYear = ltp->tm_year + 1900;
639 stm.wMonth = ltp->tm_mon + 1;
640 stm.wDayOfWeek = ltp->tm_wday;
641 stm.wDay = ltp->tm_mday;
642 stm.wHour = ltp->tm_hour;
643 stm.wMinute = ltp->tm_min;
644 stm.wSecond = ltp->tm_sec;
645 stm.wMilliseconds = 0;
647 SystemTimeToFileTime(&stm, largeTimep);
650 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
652 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
653 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
654 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
656 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
658 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
659 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
661 *ft = LargeIntegerMultiplyByLong(*ft, 60);
662 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
665 ut = ConvertLongToLargeInteger(unixTime);
666 ut = LargeIntegerMultiplyByLong(ut, 10000000);
667 *ft = LargeIntegerAdd(*ft, ut);
672 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
678 FileTimeToSystemTime(largeTimep, &stm);
680 lt.tm_year = stm.wYear - 1900;
681 lt.tm_mon = stm.wMonth - 1;
682 lt.tm_wday = stm.wDayOfWeek;
683 lt.tm_mday = stm.wDay;
684 lt.tm_hour = stm.wHour;
685 lt.tm_min = stm.wMinute;
686 lt.tm_sec = stm.wSecond;
689 save_timezone = _timezone;
690 _timezone += smb_NowTZ;
691 *unixTimep = mktime(<);
692 _timezone = save_timezone;
695 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
697 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
698 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
699 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
703 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
704 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
705 a = LargeIntegerMultiplyByLong(a, 60);
706 a = LargeIntegerMultiplyByLong(a, 10000000);
708 /* subtract it from ft */
709 a = LargeIntegerSubtract(*ft, a);
711 /* divide down to seconds */
712 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
716 void smb_SearchTimeFromUnixTime(time_t *dosTimep, time_t unixTime)
724 ltp = localtime((time_t*) &t);
726 /* if we fail, make up something */
729 localJunk.tm_year = 89 - 20;
730 localJunk.tm_mon = 4;
731 localJunk.tm_mday = 12;
732 localJunk.tm_hour = 0;
733 localJunk.tm_min = 0;
734 localJunk.tm_sec = 0;
737 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
738 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
739 *dosTimep = (dosDate<<16) | dosTime;
742 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
744 unsigned short dosDate;
745 unsigned short dosTime;
748 dosDate = (unsigned short) (searchTime & 0xffff);
749 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
751 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
752 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
753 localTm.tm_mday = (dosDate) & 0x1f;
754 localTm.tm_hour = (dosTime>>11) & 0x1f;
755 localTm.tm_min = (dosTime >> 5) & 0x3f;
756 localTm.tm_sec = (dosTime & 0x1f) * 2;
757 localTm.tm_isdst = -1; /* compute whether DST in effect */
759 *unixTimep = mktime(&localTm);
762 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
764 *dosUTimep = unixTime - smb_localZero;
767 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
770 *unixTimep = dosTime + smb_localZero;
772 /* dosTime seems to be already adjusted for GMT */
773 *unixTimep = dosTime;
777 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
781 lock_ObtainWrite(&smb_rctLock);
782 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
783 if (lsn == vcp->lsn && lana == vcp->lana) {
788 if (!vcp && (flags & SMB_FLAG_CREATE)) {
789 vcp = malloc(sizeof(*vcp));
790 memset(vcp, 0, sizeof(*vcp));
791 vcp->vcID = numVCs++;
795 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
796 vcp->nextp = smb_allVCsp;
798 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
803 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
804 /* We must obtain a challenge for extended auth
805 * in case the client negotiates smb v3
808 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
809 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
812 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
814 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
821 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
823 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
824 LsaFreeReturnBuffer(lsaResp);
827 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
829 lock_ReleaseWrite(&smb_rctLock);
833 int smb_IsStarMask(char *maskp)
838 for(i=0; i<11; i++) {
840 if (tc == '?' || tc == '*' || tc == '>') return 1;
845 void smb_ReleaseVC(smb_vc_t *vcp)
847 lock_ObtainWrite(&smb_rctLock);
848 osi_assert(vcp->refCount-- > 0);
849 lock_ReleaseWrite(&smb_rctLock);
852 void smb_HoldVC(smb_vc_t *vcp)
854 lock_ObtainWrite(&smb_rctLock);
856 lock_ReleaseWrite(&smb_rctLock);
859 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
863 lock_ObtainWrite(&smb_rctLock);
864 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
865 if (tid == tidp->tid) {
870 if (!tidp && (flags & SMB_FLAG_CREATE)) {
871 tidp = malloc(sizeof(*tidp));
872 memset(tidp, 0, sizeof(*tidp));
873 tidp->nextp = vcp->tidsp;
878 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
881 lock_ReleaseWrite(&smb_rctLock);
885 void smb_ReleaseTID(smb_tid_t *tidp)
894 lock_ObtainWrite(&smb_rctLock);
895 osi_assert(tidp->refCount-- > 0);
896 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
897 ltpp = &tidp->vcp->tidsp;
898 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
899 if (tp == tidp) break;
901 osi_assert(tp != NULL);
903 lock_FinalizeMutex(&tidp->mx);
904 userp = tidp->userp; /* remember to drop ref later */
907 lock_ReleaseWrite(&smb_rctLock);
909 cm_ReleaseUser(userp);
916 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
918 smb_user_t *uidp = NULL;
920 lock_ObtainWrite(&smb_rctLock);
921 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
922 if (uid == uidp->userID) {
924 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
925 (int)vcp, uidp->userID,
926 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
930 if (!uidp && (flags & SMB_FLAG_CREATE)) {
931 uidp = malloc(sizeof(*uidp));
932 memset(uidp, 0, sizeof(*uidp));
933 uidp->nextp = vcp->usersp;
938 lock_InitializeMutex(&uidp->mx, "user_t mutex");
940 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 : ""));
942 lock_ReleaseWrite(&smb_rctLock);
946 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
948 smb_username_t *unp= NULL;
950 lock_ObtainWrite(&smb_rctLock);
951 for(unp = usernamesp; unp; unp = unp->nextp) {
952 if (stricmp(unp->name, usern) == 0 &&
953 stricmp(unp->machine, machine) == 0) {
958 if (!unp && (flags & SMB_FLAG_CREATE)) {
959 unp = malloc(sizeof(*unp));
960 memset(unp, 0, sizeof(*unp));
962 unp->nextp = usernamesp;
963 unp->name = strdup(usern);
964 unp->machine = strdup(machine);
966 lock_InitializeMutex(&unp->mx, "username_t mutex");
968 lock_ReleaseWrite(&smb_rctLock);
972 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
974 smb_user_t *uidp= NULL;
976 lock_ObtainWrite(&smb_rctLock);
977 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
980 if (stricmp(uidp->unp->name, usern) == 0) {
982 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
987 lock_ReleaseWrite(&smb_rctLock);
990 void smb_ReleaseUID(smb_user_t *uidp)
999 lock_ObtainWrite(&smb_rctLock);
1000 osi_assert(uidp->refCount-- > 0);
1001 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1002 lupp = &uidp->vcp->usersp;
1003 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1004 if (up == uidp) break;
1006 osi_assert(up != NULL);
1008 lock_FinalizeMutex(&uidp->mx);
1010 userp = uidp->unp->userp; /* remember to drop ref later */
1011 uidp->unp->userp = NULL;
1016 lock_ReleaseWrite(&smb_rctLock);
1018 cm_ReleaseUserVCRef(userp);
1019 cm_ReleaseUser(userp);
1026 /* retrieve a held reference to a user structure corresponding to an incoming
1028 * corresponding release function is cm_ReleaseUser.
1030 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1036 smbp = (smb_t *) inp;
1037 uidp = smb_FindUID(vcp, smbp->uid, 0);
1038 if ((!uidp) || (!uidp->unp))
1041 lock_ObtainMutex(&uidp->mx);
1042 up = uidp->unp->userp;
1044 lock_ReleaseMutex(&uidp->mx);
1046 smb_ReleaseUID(uidp);
1052 * Return a pointer to a pathname extracted from a TID structure. The
1053 * TID structure is not held; assume it won't go away.
1055 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1060 tidp = smb_FindTID(vcp, tid, 0);
1064 if(tidp->flags & SMB_TIDFLAG_IPC) {
1065 code = CM_ERROR_TIDIPC;
1066 /* tidp->pathname would be NULL, but that's fine */
1068 *treepath = tidp->pathname;
1069 smb_ReleaseTID(tidp);
1074 /* check to see if we have a chained fid, that is, a fid that comes from an
1075 * OpenAndX message that ran earlier in this packet. In this case, the fid
1076 * field in a read, for example, request, isn't set, since the value is
1077 * supposed to be inherited from the openAndX call.
1079 int smb_ChainFID(int fid, smb_packet_t *inp)
1081 if (inp->fid == 0 || inp->inCount == 0)
1087 /* are we a priv'd user? What does this mean on NT? */
1088 int smb_SUser(cm_user_t *userp)
1093 /* find a file ID. If we pass in 0 we select an used File ID.
1094 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1095 * smb_fid_t data structure if desired File ID cannot be found.
1097 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1102 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1105 lock_ObtainWrite(&smb_rctLock);
1106 /* figure out if we need to allocate a new file ID */
1109 fid = vcp->fidCounter;
1113 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1114 if (fid == fidp->fid) {
1125 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1126 char eventName[MAX_PATH];
1128 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1129 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1130 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1131 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1132 thrd_CloseHandle(event);
1139 fidp = malloc(sizeof(*fidp));
1140 memset(fidp, 0, sizeof(*fidp));
1141 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1145 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1147 fidp->curr_chunk = fidp->prev_chunk = -2;
1148 fidp->raw_write_event = event;
1150 vcp->fidCounter = fid+1;
1151 if (vcp->fidCounter == 0)
1152 vcp->fidCounter = 1;
1155 lock_ReleaseWrite(&smb_rctLock);
1159 void smb_ReleaseFID(smb_fid_t *fidp)
1162 smb_vc_t *vcp = NULL;
1163 smb_ioctl_t *ioctlp;
1169 lock_ObtainWrite(&smb_rctLock);
1170 osi_assert(fidp->refCount-- > 0);
1171 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1173 if (!(fidp->flags & SMB_FID_IOCTL))
1175 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1176 thrd_CloseHandle(fidp->raw_write_event);
1178 /* and see if there is ioctl stuff to free */
1179 ioctlp = fidp->ioctlp;
1181 if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1182 if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1183 if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1189 /* do not call smb_ReleaseVC() because we already have the lock */
1192 lock_ReleaseWrite(&smb_rctLock);
1194 /* now release the scache structure */
1196 cm_ReleaseSCache(scp);
1200 * Case-insensitive search for one string in another;
1201 * used to find variable names in submount pathnames.
1203 static char *smb_stristr(char *str1, char *str2)
1207 for (cursor = str1; *cursor; cursor++)
1208 if (stricmp(cursor, str2) == 0)
1215 * Substitute a variable value for its name in a submount pathname. Variable
1216 * name has been identified by smb_stristr() and is in substr. Variable name
1217 * length (plus one) is in substr_size. Variable value is in newstr.
1219 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1224 strcpy(temp, substr + substr_size - 1);
1225 strcpy(substr, newstr);
1229 char VNUserName[] = "%USERNAME%";
1230 char VNLCUserName[] = "%LCUSERNAME%";
1231 char VNComputerName[] = "%COMPUTERNAME%";
1232 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1235 /* List available shares */
1236 int smb_ListShares()
1240 char shareBuf[4096];
1248 /*strcpy(shareNameList[num_shares], "all");
1249 strcpy(pathNameList[num_shares++], "/afs");*/
1250 fprintf(stderr, "The following shares are available:\n");
1251 fprintf(stderr, "Share Name (AFS Path)\n");
1252 fprintf(stderr, "---------------------\n");
1253 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1256 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1257 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1259 strcpy(sbmtpath, cm_confDir);
1261 strcat(sbmtpath, "/afsdsbmt.ini");
1262 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1263 shareBuf, sizeof(shareBuf),
1269 this_share = shareBuf;
1273 /*strcpy(shareNameList[num_shares], this_share);*/
1274 len = GetPrivateProfileString("AFS Submounts", this_share,
1281 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1284 if (*p == '\\') *p = '/'; /* change to / */
1288 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1289 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1292 while (*this_share != 0) this_share++; /* find next NUL */
1293 this_share++; /* skip past the NUL */
1294 } while (*this_share != 0); /* stop at final NUL */
1300 typedef struct smb_findShare_rock {
1304 } smb_findShare_rock_t;
1306 #define SMB_FINDSHARE_EXACT_MATCH 1
1307 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1309 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1313 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1314 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1315 if(!stricmp(dep->name, vrock->shareName))
1316 matchType = SMB_FINDSHARE_EXACT_MATCH;
1318 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1319 if(vrock->match) free(vrock->match);
1320 vrock->match = strdup(dep->name);
1321 vrock->matchType = matchType;
1323 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1324 return CM_ERROR_STOPNOW;
1330 /* find a shareName in the table of submounts */
1331 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1335 char pathName[1024];
1340 char sbmtpath[MAX_PATH];
1345 DWORD allSubmount = 1;
1347 /* if allSubmounts == 0, only return the //mountRoot/all share
1348 * if in fact it has been been created in the subMounts table.
1349 * This is to allow sites that want to restrict access to the
1352 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1353 0, KEY_QUERY_VALUE, &parmKey);
1354 if (code == ERROR_SUCCESS) {
1355 len = sizeof(allSubmount);
1356 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1357 (BYTE *) &allSubmount, &len);
1358 if (code != ERROR_SUCCESS) {
1361 RegCloseKey (parmKey);
1364 if (allSubmount && _stricmp(shareName, "all") == 0) {
1369 /* In case, the all share is disabled we need to still be able
1370 * to handle ioctl requests
1372 if (_stricmp(shareName, "ioctl$") == 0) {
1373 *pathNamep = strdup("/.__ioctl__");
1377 if (_stricmp(shareName, "IPC$") == 0 ||
1378 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1379 _stricmp(shareName, "DESKTOP.INI") == 0
1386 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1387 0, KEY_QUERY_VALUE, &parmKey);
1388 if (code == ERROR_SUCCESS) {
1389 len = sizeof(pathName);
1390 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1391 (BYTE *) pathName, &len);
1392 if (code != ERROR_SUCCESS)
1394 RegCloseKey (parmKey);
1399 strcpy(sbmtpath, cm_confDir);
1400 strcat(sbmtpath, "/afsdsbmt.ini");
1401 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1402 pathName, sizeof(pathName), sbmtpath);
1404 if (len != 0 && len != sizeof(pathName) - 1) {
1405 /* We can accept either unix or PC style AFS pathnames. Convert
1406 * Unix-style to PC style here for internal use.
1409 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1410 p += strlen(cm_mountRoot); /* skip mount path */
1413 if (*q == '/') *q = '\\'; /* change to \ */
1419 if (var = smb_stristr(p, VNUserName)) {
1420 if (uidp && uidp->unp)
1421 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1423 smb_subst(p, var, sizeof(VNUserName)," ");
1425 else if (var = smb_stristr(p, VNLCUserName))
1427 if (uidp && uidp->unp)
1428 strcpy(temp, uidp->unp->name);
1432 smb_subst(p, var, sizeof(VNLCUserName), temp);
1434 else if (var = smb_stristr(p, VNComputerName))
1436 sizeTemp = sizeof(temp);
1437 GetComputerName((LPTSTR)temp, &sizeTemp);
1438 smb_subst(p, var, sizeof(VNComputerName), temp);
1440 else if (var = smb_stristr(p, VNLCComputerName))
1442 sizeTemp = sizeof(temp);
1443 GetComputerName((LPTSTR)temp, &sizeTemp);
1445 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1450 *pathNamep = strdup(p);
1455 /* First lookup shareName in root.afs */
1457 smb_findShare_rock_t vrock;
1459 char * p = shareName;
1462 /* attempt to locate a partial match in root.afs. This is because
1463 when using the ANSI RAP calls, the share name is limited to 13 chars
1464 and hence is truncated. Of course we prefer exact matches. */
1466 thyper.HighPart = 0;
1469 vrock.shareName = shareName;
1471 vrock.matchType = 0;
1473 cm_HoldSCache(cm_rootSCachep);
1474 code = cm_ApplyDir(cm_rootSCachep, smb_FindShareProc, &vrock, &thyper,
1475 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1476 cm_ReleaseSCache(cm_rootSCachep);
1478 if (vrock.matchType) {
1479 sprintf(pathName,"/%s/",vrock.match);
1480 *pathNamep = strdup(strlwr(pathName));
1485 /* if we get here, there was no match for the share in root.afs */
1486 /* so try to create \\<netbiosName>\<cellname> */
1491 /* Get the full name for this cell */
1492 code = cm_SearchCellFile(p, temp, 0, 0);
1493 #ifdef AFS_AFSDB_ENV
1494 if (code && cm_dnsEnabled) {
1496 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1499 /* construct the path */
1501 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1502 *pathNamep = strdup(strlwr(pathName));
1511 /* Client-side offline caching policy types */
1512 #define CSC_POLICY_MANUAL 0
1513 #define CSC_POLICY_DOCUMENTS 1
1514 #define CSC_POLICY_PROGRAMS 2
1515 #define CSC_POLICY_DISABLE 3
1517 int smb_FindShareCSCPolicy(char *shareName)
1523 int retval = CSC_POLICY_MANUAL;
1525 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1526 "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
1529 REG_OPTION_NON_VOLATILE,
1535 len = sizeof(policy);
1536 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1538 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1540 else if (stricmp(policy, "documents") == 0)
1542 retval = CSC_POLICY_DOCUMENTS;
1544 else if (stricmp(policy, "programs") == 0)
1546 retval = CSC_POLICY_PROGRAMS;
1548 else if (stricmp(policy, "disable") == 0)
1550 retval = CSC_POLICY_DISABLE;
1553 RegCloseKey(hkCSCPolicy);
1557 /* find a dir search structure by cookie value, and return it held.
1558 * Must be called with smb_globalLock held.
1560 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1562 smb_dirSearch_t *dsp;
1564 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1565 if (dsp->cookie == cookie) {
1566 if (dsp != smb_firstDirSearchp) {
1567 /* move to head of LRU queue, too, if we're not already there */
1568 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1569 smb_lastDirSearchp = (smb_dirSearch_t *)
1571 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1572 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1573 if (!smb_lastDirSearchp)
1574 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1576 lock_ObtainMutex(&dsp->mx);
1578 lock_ReleaseMutex(&dsp->mx);
1585 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1587 lock_ObtainWrite(&smb_globalLock);
1588 lock_ObtainMutex(&dsp->mx);
1589 dsp->flags |= SMB_DIRSEARCH_DELETE;
1590 if (dsp->scp != NULL) {
1591 lock_ObtainMutex(&dsp->scp->mx);
1592 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1593 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1594 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1595 dsp->scp->bulkStatProgress = hones;
1597 lock_ReleaseMutex(&dsp->scp->mx);
1599 lock_ReleaseMutex(&dsp->mx);
1600 lock_ReleaseWrite(&smb_globalLock);
1603 /* Must be called with the smb_globalLock held */
1604 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1610 lock_ObtainMutex(&dsp->mx);
1611 osi_assert(dsp->refCount-- > 0);
1612 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1613 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1614 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1615 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1616 lock_ReleaseMutex(&dsp->mx);
1617 lock_FinalizeMutex(&dsp->mx);
1621 lock_ReleaseMutex(&dsp->mx);
1623 /* do this now to avoid spurious locking hierarchy creation */
1624 if (scp) cm_ReleaseSCache(scp);
1627 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1629 lock_ObtainWrite(&smb_globalLock);
1630 smb_ReleaseDirSearchNoLock(dsp);
1631 lock_ReleaseWrite(&smb_globalLock);
1634 /* find a dir search structure by cookie value, and return it held */
1635 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1637 smb_dirSearch_t *dsp;
1639 lock_ObtainWrite(&smb_globalLock);
1640 dsp = smb_FindDirSearchNoLock(cookie);
1641 lock_ReleaseWrite(&smb_globalLock);
1645 /* GC some dir search entries, in the address space expected by the specific protocol.
1646 * Must be called with smb_globalLock held; release the lock temporarily.
1648 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1649 void smb_GCDirSearches(int isV3)
1651 smb_dirSearch_t *prevp;
1652 smb_dirSearch_t *tp;
1653 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1657 victimCount = 0; /* how many have we got so far */
1658 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1659 /* we'll move tp from queue, so
1662 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1663 /* if no one is using this guy, and we're either in the new protocol,
1664 * or we're in the old one and this is a small enough ID to be useful
1665 * to the old protocol, GC this guy.
1667 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1668 /* hold and delete */
1669 tp->flags |= SMB_DIRSEARCH_DELETE;
1670 victimsp[victimCount++] = tp;
1674 /* don't do more than this */
1675 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1679 /* now release them */
1680 for (i = 0; i < victimCount; i++) {
1681 smb_ReleaseDirSearchNoLock(victimsp[i]);
1685 /* function for allocating a dir search entry. We need these to remember enough context
1686 * since we don't get passed the path from call to call during a directory search.
1688 * Returns a held dir search structure, and bumps the reference count on the vnode,
1689 * since it saves a pointer to the vnode.
1691 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1693 smb_dirSearch_t *dsp;
1697 lock_ObtainWrite(&smb_globalLock);
1700 /* what's the biggest ID allowed in this version of the protocol */
1701 maxAllowed = isV3 ? 65535 : 255;
1704 /* twice so we have enough tries to find guys we GC after one pass;
1705 * 10 extra is just in case I mis-counted.
1707 if (++counter > 2*maxAllowed+10)
1708 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1710 if (smb_dirSearchCounter > maxAllowed) {
1711 smb_dirSearchCounter = 1;
1712 smb_GCDirSearches(isV3); /* GC some */
1714 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1716 /* don't need to watch for refcount zero and deleted, since
1717 * we haven't dropped the global lock.
1719 lock_ObtainMutex(&dsp->mx);
1721 lock_ReleaseMutex(&dsp->mx);
1722 ++smb_dirSearchCounter;
1726 dsp = malloc(sizeof(*dsp));
1727 memset(dsp, 0, sizeof(*dsp));
1728 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1729 if (!smb_lastDirSearchp)
1730 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1731 dsp->cookie = smb_dirSearchCounter;
1732 ++smb_dirSearchCounter;
1734 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1735 dsp->lastTime = osi_Time();
1738 lock_ReleaseWrite(&smb_globalLock);
1742 static smb_packet_t *GetPacket(void)
1746 unsigned int npar, seg, tb_sel;
1749 lock_ObtainWrite(&smb_globalLock);
1750 tbp = smb_packetFreeListp;
1752 smb_packetFreeListp = tbp->nextp;
1753 lock_ReleaseWrite(&smb_globalLock);
1756 tbp = calloc(65540,1);
1758 tbp = malloc(sizeof(smb_packet_t));
1760 tbp->magic = SMB_PACKETMAGIC;
1763 tbp->resumeCode = 0;
1769 tbp->ncb_length = 0;
1774 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1777 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1779 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1781 osi_panic("",__FILE__,__LINE__);
1784 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1789 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1790 tbp->dos_pkt_sel = tb_sel;
1793 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1798 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1802 memcpy(tbp, pkt, sizeof(smb_packet_t));
1803 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1807 static NCB *GetNCB(void)
1812 unsigned int npar, seg, tb_sel;
1815 lock_ObtainWrite(&smb_globalLock);
1816 tbp = smb_ncbFreeListp;
1818 smb_ncbFreeListp = tbp->nextp;
1819 lock_ReleaseWrite(&smb_globalLock);
1822 tbp = calloc(sizeof(*tbp),1);
1824 tbp = malloc(sizeof(*tbp));
1825 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1828 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1830 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1832 osi_panic("",__FILE__,__LINE__);
1834 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1839 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1840 tbp->dos_ncb_sel = tb_sel;
1842 tbp->magic = SMB_NCBMAGIC;
1845 osi_assert(tbp->magic == SMB_NCBMAGIC);
1847 memset(&tbp->ncb, 0, sizeof(NCB));
1850 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1855 void smb_FreePacket(smb_packet_t *tbp)
1857 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1859 lock_ObtainWrite(&smb_globalLock);
1860 tbp->nextp = smb_packetFreeListp;
1861 smb_packetFreeListp = tbp;
1862 tbp->magic = SMB_PACKETMAGIC;
1865 tbp->resumeCode = 0;
1871 tbp->ncb_length = 0;
1873 lock_ReleaseWrite(&smb_globalLock);
1876 static void FreeNCB(NCB *bufferp)
1880 tbp = (smb_ncb_t *) bufferp;
1881 osi_assert(tbp->magic == SMB_NCBMAGIC);
1883 lock_ObtainWrite(&smb_globalLock);
1884 tbp->nextp = smb_ncbFreeListp;
1885 smb_ncbFreeListp = tbp;
1886 lock_ReleaseWrite(&smb_globalLock);
1889 /* get a ptr to the data part of a packet, and its count */
1890 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1894 unsigned char *afterParmsp;
1896 parmBytes = *smbp->wctp << 1;
1897 afterParmsp = smbp->wctp + parmBytes + 1;
1899 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1900 if (nbytesp) *nbytesp = dataBytes;
1902 /* don't forget to skip the data byte count, since it follows
1903 * the parameters; that's where the "2" comes from below.
1905 return (unsigned char *) (afterParmsp + 2);
1908 /* must set all the returned parameters before playing around with the
1909 * data region, since the data region is located past the end of the
1910 * variable number of parameters.
1912 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1914 unsigned char *afterParmsp;
1916 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1918 *afterParmsp++ = dsize & 0xff;
1919 *afterParmsp = (dsize>>8) & 0xff;
1922 /* return the parm'th parameter in the smbp packet */
1923 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1926 unsigned char *parmDatap;
1928 parmCount = *smbp->wctp;
1930 if (parm >= parmCount) {
1935 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1937 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1938 parm, parmCount, smbp->ncb_length);
1941 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1942 1, smbp->ncb_length, ptbuf, smbp);
1943 DeregisterEventSource(h);
1945 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1946 osi_panic(s, __FILE__, __LINE__);
1948 parmDatap = smbp->wctp + (2*parm) + 1;
1950 return parmDatap[0] + (parmDatap[1] << 8);
1953 /* return the parm'th parameter in the smbp packet */
1954 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1957 unsigned char *parmDatap;
1959 parmCount = *smbp->wctp;
1961 if (parm * 2 + offset >= parmCount * 2) {
1966 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1968 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1969 parm, offset, parmCount, smbp->ncb_length);
1972 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1973 1, smbp->ncb_length, ptbuf, smbp);
1974 DeregisterEventSource(h);
1976 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
1977 osi_panic(s, __FILE__, __LINE__);
1979 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1981 return parmDatap[0] + (parmDatap[1] << 8);
1984 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1988 /* make sure we have enough slots */
1989 if (*smbp->wctp <= slot)
1990 *smbp->wctp = slot+1;
1992 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1993 *parmDatap++ = parmValue & 0xff;
1994 *parmDatap = (parmValue>>8) & 0xff;
1997 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2001 /* make sure we have enough slots */
2002 if (*smbp->wctp <= slot)
2003 *smbp->wctp = slot+2;
2005 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2006 *parmDatap++ = parmValue & 0xff;
2007 *parmDatap++ = (parmValue>>8) & 0xff;
2008 *parmDatap++ = (parmValue>>16) & 0xff;
2009 *parmDatap++ = (parmValue>>24) & 0xff;
2012 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2017 /* make sure we have enough slots */
2018 if (*smbp->wctp <= slot)
2019 *smbp->wctp = slot+4;
2021 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2023 *parmDatap++ = *parmValuep++;
2026 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2030 /* make sure we have enough slots */
2031 if (*smbp->wctp <= slot) {
2032 if (smbp->oddByte) {
2034 *smbp->wctp = slot+1;
2039 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2040 *parmDatap++ = parmValue & 0xff;
2043 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2047 lastSlashp = strrchr(inPathp, '\\');
2049 *lastComponentp = lastSlashp;
2052 if (inPathp == lastSlashp)
2054 *outPathp++ = *inPathp++;
2063 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2068 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2073 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2079 tlen = inp[0] + (inp[1]<<8);
2080 inp += 2; /* skip length field */
2083 *chainpp = inp + tlen;
2092 /* format a packet as a response */
2093 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2098 outp = (smb_t *) op;
2100 /* zero the basic structure through the smb_wct field, and zero the data
2101 * size field, assuming that wct stays zero; otherwise, you have to
2102 * explicitly set the data size field, too.
2104 inSmbp = (smb_t *) inp;
2105 memset(outp, 0, sizeof(smb_t)+2);
2111 outp->com = inSmbp->com;
2112 outp->tid = inSmbp->tid;
2113 outp->pid = inSmbp->pid;
2114 outp->uid = inSmbp->uid;
2115 outp->mid = inSmbp->mid;
2116 outp->res[0] = inSmbp->res[0];
2117 outp->res[1] = inSmbp->res[1];
2118 op->inCom = inSmbp->com;
2120 outp->reb = 0x80; /* SERVER_RESP */
2121 outp->flg2 = 0x1; /* KNOWS_LONG_NAMES */
2123 /* copy fields in generic packet area */
2124 op->wctp = &outp->wct;
2127 /* send a (probably response) packet; vcp tells us to whom to send it.
2128 * we compute the length by looking at wct and bcc fields.
2130 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2147 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2150 memset((char *)ncbp, 0, sizeof(NCB));
2152 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2153 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2154 extra += tp[0] + (tp[1]<<8);
2155 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2156 extra += 3; /* wct and length fields */
2158 ncbp->ncb_length = extra; /* bytes to send */
2159 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2160 ncbp->ncb_lana_num = vcp->lana;
2161 ncbp->ncb_command = NCBSEND; /* op means send data */
2163 ncbp->ncb_buffer = (char *) inp;/* packet */
2164 code = Netbios(ncbp);
2166 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2167 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2169 /* copy header information from virtual to DOS address space */
2170 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2171 code = Netbios(ncbp, dos_ncb);
2175 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2181 void smb_MapNTError(long code, unsigned long *NTStatusp)
2183 unsigned long NTStatus;
2185 /* map CM_ERROR_* errors to NT 32-bit status codes */
2186 /* NT Status codes are listed in ntstatus.h not winerror.h */
2187 if (code == CM_ERROR_NOSUCHCELL) {
2188 NTStatus = 0xC000000FL; /* No such file */
2190 else if (code == CM_ERROR_NOSUCHVOLUME) {
2191 NTStatus = 0xC000000FL; /* No such file */
2193 else if (code == CM_ERROR_TIMEDOUT) {
2194 NTStatus = 0xC00000CFL; /* Sharing Paused */
2196 else if (code == CM_ERROR_RETRY) {
2197 NTStatus = 0xC000022DL; /* Retry */
2199 else if (code == CM_ERROR_NOACCESS) {
2200 NTStatus = 0xC0000022L; /* Access denied */
2202 else if (code == CM_ERROR_READONLY) {
2203 NTStatus = 0xC00000A2L; /* Write protected */
2205 else if (code == CM_ERROR_NOSUCHFILE) {
2206 NTStatus = 0xC000000FL; /* No such file */
2208 else if (code == CM_ERROR_NOSUCHPATH) {
2209 NTStatus = 0xC000003AL; /* Object path not found */
2211 else if (code == CM_ERROR_TOOBIG) {
2212 NTStatus = 0xC000007BL; /* Invalid image format */
2214 else if (code == CM_ERROR_INVAL) {
2215 NTStatus = 0xC000000DL; /* Invalid parameter */
2217 else if (code == CM_ERROR_BADFD) {
2218 NTStatus = 0xC0000008L; /* Invalid handle */
2220 else if (code == CM_ERROR_BADFDOP) {
2221 NTStatus = 0xC0000022L; /* Access denied */
2223 else if (code == CM_ERROR_EXISTS) {
2224 NTStatus = 0xC0000035L; /* Object name collision */
2226 else if (code == CM_ERROR_NOTEMPTY) {
2227 NTStatus = 0xC0000101L; /* Directory not empty */
2229 else if (code == CM_ERROR_CROSSDEVLINK) {
2230 NTStatus = 0xC00000D4L; /* Not same device */
2232 else if (code == CM_ERROR_NOTDIR) {
2233 NTStatus = 0xC0000103L; /* Not a directory */
2235 else if (code == CM_ERROR_ISDIR) {
2236 NTStatus = 0xC00000BAL; /* File is a directory */
2238 else if (code == CM_ERROR_BADOP) {
2240 /* I have no idea where this comes from */
2241 NTStatus = 0xC09820FFL; /* SMB no support */
2243 NTStatus = 0xC00000BBL; /* Not supported */
2244 #endif /* COMMENT */
2246 else if (code == CM_ERROR_BADSHARENAME) {
2247 NTStatus = 0xC00000CCL; /* Bad network name */
2249 else if (code == CM_ERROR_NOIPC) {
2251 NTStatus = 0xC0000022L; /* Access Denied */
2253 NTStatus = 0xC000013DL; /* Remote Resources */
2256 else if (code == CM_ERROR_CLOCKSKEW) {
2257 NTStatus = 0xC0000133L; /* Time difference at DC */
2259 else if (code == CM_ERROR_BADTID) {
2260 NTStatus = 0xC0982005L; /* SMB bad TID */
2262 else if (code == CM_ERROR_USESTD) {
2263 NTStatus = 0xC09820FBL; /* SMB use standard */
2265 else if (code == CM_ERROR_QUOTA) {
2267 NTStatus = 0xC0000044L; /* Quota exceeded */
2269 NTStatus = 0xC000007FL; /* Disk full */
2272 else if (code == CM_ERROR_SPACE) {
2273 NTStatus = 0xC000007FL; /* Disk full */
2275 else if (code == CM_ERROR_ATSYS) {
2276 NTStatus = 0xC0000033L; /* Object name invalid */
2278 else if (code == CM_ERROR_BADNTFILENAME) {
2279 NTStatus = 0xC0000033L; /* Object name invalid */
2281 else if (code == CM_ERROR_WOULDBLOCK) {
2282 NTStatus = 0xC0000055L; /* Lock not granted */
2284 else if (code == CM_ERROR_PARTIALWRITE) {
2285 NTStatus = 0xC000007FL; /* Disk full */
2287 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2288 NTStatus = 0xC0000023L; /* Buffer too small */
2290 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2291 NTStatus = 0xC0000035L; /* Object name collision */
2293 else if (code == CM_ERROR_BADPASSWORD) {
2294 NTStatus = 0xC000006DL; /* unknown username or bad password */
2296 else if (code == CM_ERROR_BADLOGONTYPE) {
2297 NTStatus = 0xC000015BL; /* logon type not granted */
2299 else if (code == CM_ERROR_GSSCONTINUE) {
2300 NTStatus = 0xC0000016L; /* more processing required */
2302 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2304 NTStatus = 0xC0000280L; /* reparse point not resolved */
2306 NTStatus = 0xC0000022L; /* Access Denied */
2310 NTStatus = 0xC0982001L; /* SMB non-specific error */
2313 *NTStatusp = NTStatus;
2314 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2317 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2318 unsigned char *classp)
2320 unsigned char class;
2321 unsigned short error;
2323 /* map CM_ERROR_* errors to SMB errors */
2324 if (code == CM_ERROR_NOSUCHCELL) {
2326 error = 3; /* bad path */
2328 else if (code == CM_ERROR_NOSUCHVOLUME) {
2330 error = 3; /* bad path */
2332 else if (code == CM_ERROR_TIMEDOUT) {
2334 error = 81; /* server is paused */
2336 else if (code == CM_ERROR_RETRY) {
2337 class = 2; /* shouldn't happen */
2340 else if (code == CM_ERROR_NOACCESS) {
2342 error = 4; /* bad access */
2344 else if (code == CM_ERROR_READONLY) {
2346 error = 19; /* read only */
2348 else if (code == CM_ERROR_NOSUCHFILE) {
2350 error = 2; /* ENOENT! */
2352 else if (code == CM_ERROR_NOSUCHPATH) {
2354 error = 3; /* Bad path */
2356 else if (code == CM_ERROR_TOOBIG) {
2358 error = 11; /* bad format */
2360 else if (code == CM_ERROR_INVAL) {
2361 class = 2; /* server non-specific error code */
2364 else if (code == CM_ERROR_BADFD) {
2366 error = 6; /* invalid file handle */
2368 else if (code == CM_ERROR_BADFDOP) {
2369 class = 1; /* invalid op on FD */
2372 else if (code == CM_ERROR_EXISTS) {
2374 error = 80; /* file already exists */
2376 else if (code == CM_ERROR_NOTEMPTY) {
2378 error = 5; /* delete directory not empty */
2380 else if (code == CM_ERROR_CROSSDEVLINK) {
2382 error = 17; /* EXDEV */
2384 else if (code == CM_ERROR_NOTDIR) {
2385 class = 1; /* bad path */
2388 else if (code == CM_ERROR_ISDIR) {
2389 class = 1; /* access denied; DOS doesn't have a good match */
2392 else if (code == CM_ERROR_BADOP) {
2396 else if (code == CM_ERROR_BADSHARENAME) {
2400 else if (code == CM_ERROR_NOIPC) {
2402 error = 4; /* bad access */
2404 else if (code == CM_ERROR_CLOCKSKEW) {
2405 class = 1; /* invalid function */
2408 else if (code == CM_ERROR_BADTID) {
2412 else if (code == CM_ERROR_USESTD) {
2416 else if (code == CM_ERROR_REMOTECONN) {
2420 else if (code == CM_ERROR_QUOTA) {
2421 if (vcp->flags & SMB_VCFLAG_USEV3) {
2423 error = 39; /* disk full */
2427 error = 5; /* access denied */
2430 else if (code == CM_ERROR_SPACE) {
2431 if (vcp->flags & SMB_VCFLAG_USEV3) {
2433 error = 39; /* disk full */
2437 error = 5; /* access denied */
2440 else if (code == CM_ERROR_PARTIALWRITE) {
2442 error = 39; /* disk full */
2444 else if (code == CM_ERROR_ATSYS) {
2446 error = 2; /* ENOENT */
2448 else if (code == CM_ERROR_WOULDBLOCK) {
2450 error = 33; /* lock conflict */
2452 else if (code == CM_ERROR_NOFILES) {
2454 error = 18; /* no files in search */
2456 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2458 error = 183; /* Samba uses this */
2460 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2461 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2463 error = 2; /* bad password */
2472 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2475 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2477 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2478 return CM_ERROR_BADOP;
2481 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2483 unsigned short EchoCount, i;
2484 char *data, *outdata;
2487 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2489 for (i=1; i<=EchoCount; i++) {
2490 data = smb_GetSMBData(inp, &dataSize);
2491 smb_SetSMBParm(outp, 0, i);
2492 smb_SetSMBDataLength(outp, dataSize);
2493 outdata = smb_GetSMBData(outp, NULL);
2494 memcpy(outdata, data, dataSize);
2495 smb_SendPacket(vcp, outp);
2501 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2504 long count, minCount, finalCount;
2508 cm_user_t *userp = NULL;
2512 char *rawBuf = NULL;
2514 dos_ptr rawBuf = NULL;
2521 fd = smb_GetSMBParm(inp, 0);
2522 count = smb_GetSMBParm(inp, 3);
2523 minCount = smb_GetSMBParm(inp, 4);
2524 offset.HighPart = 0; /* too bad */
2525 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2527 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2528 fd, offset.LowPart, count);
2530 fidp = smb_FindFID(vcp, fd, 0);
2534 lock_ObtainMutex(&smb_RawBufLock);
2536 /* Get a raw buf, from head of list */
2537 rawBuf = smb_RawBufs;
2539 smb_RawBufs = *(char **)smb_RawBufs;
2541 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2544 lock_ReleaseMutex(&smb_RawBufLock);
2548 if (fidp->flags & SMB_FID_IOCTL)
2551 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2553 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2556 /* Give back raw buffer */
2557 lock_ObtainMutex(&smb_RawBufLock);
2559 *((char **) rawBuf) = smb_RawBufs;
2561 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2564 smb_RawBufs = rawBuf;
2565 lock_ReleaseMutex(&smb_RawBufLock);
2568 smb_ReleaseFID(fidp);
2572 userp = smb_GetUser(vcp, inp);
2575 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2577 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2578 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2579 userp, &finalCount, TRUE /* rawFlag */);
2586 cm_ReleaseUser(userp);
2589 smb_ReleaseFID(fidp);
2594 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2596 memset((char *)ncbp, 0, sizeof(NCB));
2598 ncbp->ncb_length = (unsigned short) finalCount;
2599 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2600 ncbp->ncb_lana_num = vcp->lana;
2601 ncbp->ncb_command = NCBSEND;
2602 ncbp->ncb_buffer = rawBuf;
2605 code = Netbios(ncbp);
2607 code = Netbios(ncbp, dos_ncb);
2610 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2613 /* Give back raw buffer */
2614 lock_ObtainMutex(&smb_RawBufLock);
2616 *((char **) rawBuf) = smb_RawBufs;
2618 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2621 smb_RawBufs = rawBuf;
2622 lock_ReleaseMutex(&smb_RawBufLock);
2628 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2630 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2635 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2637 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2642 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2649 int protoIndex; /* index we're using */
2654 char protocol_array[10][1024]; /* protocol signature of the client */
2655 int caps; /* capabilities */
2658 TIME_ZONE_INFORMATION tzi;
2660 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2664 DWORD now = GetCurrentTime();
2665 if (now - last_msg_time >= 30000
2666 && now - last_msg_time <= 90000) {
2668 "Setting dead_vcp %x", active_vcp);
2670 smb_ReleaseVC(dead_vcp);
2672 "Previous dead_vcp %x", dead_vcp);
2674 smb_HoldVC(active_vcp);
2675 dead_vcp = active_vcp;
2676 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2681 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2683 namep = smb_GetSMBData(inp, &dbytes);
2686 coreProtoIndex = -1; /* not found */
2689 while(namex < dbytes) {
2690 osi_Log1(smb_logp, "Protocol %s",
2691 osi_LogSaveString(smb_logp, namep+1));
2692 strcpy(protocol_array[tcounter], namep+1);
2694 /* namep points at the first protocol, or really, a 0x02
2695 * byte preceding the null-terminated ASCII name.
2697 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2698 coreProtoIndex = tcounter;
2700 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2701 v3ProtoIndex = tcounter;
2703 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2704 NTProtoIndex = tcounter;
2707 /* compute size of protocol entry */
2708 entryLength = strlen(namep+1);
2709 entryLength += 2; /* 0x02 bytes and null termination */
2711 /* advance over this protocol entry */
2712 namex += entryLength;
2713 namep += entryLength;
2714 tcounter++; /* which proto entry we're looking at */
2717 if (NTProtoIndex != -1) {
2718 protoIndex = NTProtoIndex;
2719 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2721 else if (v3ProtoIndex != -1) {
2722 protoIndex = v3ProtoIndex;
2723 vcp->flags |= SMB_VCFLAG_USEV3;
2725 else if (coreProtoIndex != -1) {
2726 protoIndex = coreProtoIndex;
2727 vcp->flags |= SMB_VCFLAG_USECORE;
2729 else protoIndex = -1;
2731 if (protoIndex == -1)
2732 return CM_ERROR_INVAL;
2733 else if (NTProtoIndex != -1) {
2734 smb_SetSMBParm(outp, 0, protoIndex);
2735 if (smb_authType != SMB_AUTH_NONE) {
2736 smb_SetSMBParmByte(outp, 1,
2737 NEGOTIATE_SECURITY_USER_LEVEL |
2738 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2740 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2742 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2743 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2744 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2745 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2746 /* The session key is not a well documented field however most clients
2747 * will echo back the session key to the server. Currently we are using
2748 * the same value for all sessions. We should generate a random value
2749 * and store it into the vcp
2751 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2752 smb_SetSMBParm(outp, 8, 1);
2754 * Tried changing the capabilities to support for W2K - defect 117695
2755 * Maybe something else needs to be changed here?
2759 smb_SetSMBParmLong(outp, 9, 0x43fd);
2761 smb_SetSMBParmLong(outp, 9, 0x251);
2764 * 32-bit error codes *
2768 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2769 NTNEGOTIATE_CAPABILITY_NTFIND |
2770 NTNEGOTIATE_CAPABILITY_RAWMODE |
2771 NTNEGOTIATE_CAPABILITY_NTSMB;
2773 if ( smb_authType == SMB_AUTH_EXTENDED )
2774 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2776 smb_SetSMBParmLong(outp, 9, caps);
2778 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2779 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2780 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2782 GetTimeZoneInformation(&tzi);
2783 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2785 if (smb_authType == SMB_AUTH_NTLM) {
2786 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2787 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2788 /* paste in encryption key */
2789 datap = smb_GetSMBData(outp, NULL);
2790 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2791 /* and the faux domain name */
2792 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2793 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2797 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2799 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2801 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2803 datap = smb_GetSMBData(outp, NULL);
2804 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2807 datap += sizeof(smb_ServerGUID);
2808 memcpy(datap, secBlob, secBlobLength);
2812 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2813 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2816 else if (v3ProtoIndex != -1) {
2817 smb_SetSMBParm(outp, 0, protoIndex);
2819 /* NOTE: Extended authentication cannot be negotiated with v3
2820 * therefore we fail over to NTLM
2822 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2823 smb_SetSMBParm(outp, 1,
2824 NEGOTIATE_SECURITY_USER_LEVEL |
2825 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2827 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2829 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2830 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2831 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2832 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2833 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2834 smb_SetSMBParm(outp, 7, 1);
2836 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2837 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2838 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2840 GetTimeZoneInformation(&tzi);
2841 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2843 /* NOTE: Extended authentication cannot be negotiated with v3
2844 * therefore we fail over to NTLM
2846 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2847 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2848 smb_SetSMBParm(outp, 12, 0); /* resvd */
2849 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2850 datap = smb_GetSMBData(outp, NULL);
2851 /* paste in a new encryption key */
2852 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2853 /* and the faux domain name */
2854 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2856 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2857 smb_SetSMBParm(outp, 12, 0); /* resvd */
2858 smb_SetSMBDataLength(outp, 0);
2861 else if (coreProtoIndex != -1) { /* not really supported anymore */
2862 smb_SetSMBParm(outp, 0, protoIndex);
2863 smb_SetSMBDataLength(outp, 0);
2868 void smb_Daemon(void *parmp)
2870 afs_uint32 count = 0;
2872 while(smbShutdownFlag == 0) {
2876 if (smbShutdownFlag == 1)
2879 if ((count % 72) == 0) { /* every five minutes */
2881 time_t old_localZero = smb_localZero;
2883 /* Initialize smb_localZero */
2884 myTime.tm_isdst = -1; /* compute whether on DST or not */
2885 myTime.tm_year = 70;
2891 smb_localZero = mktime(&myTime);
2893 smb_CalculateNowTZ();
2895 #ifdef AFS_FREELANCE
2896 if ( smb_localZero != old_localZero )
2897 cm_noteLocalMountPointChange();
2900 /* XXX GC dir search entries */
2904 void smb_WaitingLocksDaemon()
2906 smb_waitingLock_t *wL, *nwL;
2909 smb_packet_t *inp, *outp;
2914 lock_ObtainWrite(&smb_globalLock);
2915 nwL = smb_allWaitingLocks;
2917 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2926 lock_ObtainWrite(&smb_globalLock);
2928 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2929 lock_ReleaseWrite(&smb_globalLock);
2930 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2931 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2932 if (code == CM_ERROR_WOULDBLOCK) {
2934 if (wL->timeRemaining != 0xffffffff
2935 && (wL->timeRemaining -= 1000) < 0)
2944 ncbp->ncb_length = inp->ncb_length;
2945 inp->spacep = cm_GetSpace();
2947 /* Remove waitingLock from list */
2948 lock_ObtainWrite(&smb_globalLock);
2949 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2951 lock_ReleaseWrite(&smb_globalLock);
2953 /* Resume packet processing */
2955 smb_SetSMBDataLength(outp, 0);
2956 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2957 outp->resumeCode = code;
2959 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2962 cm_FreeSpace(inp->spacep);
2963 smb_FreePacket(inp);
2964 smb_FreePacket(outp);
2972 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2974 osi_Log0(smb_logp, "SMB receive get disk attributes");
2976 smb_SetSMBParm(outp, 0, 32000);
2977 smb_SetSMBParm(outp, 1, 64);
2978 smb_SetSMBParm(outp, 2, 1024);
2979 smb_SetSMBParm(outp, 3, 30000);
2980 smb_SetSMBParm(outp, 4, 0);
2981 smb_SetSMBDataLength(outp, 0);
2985 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2989 unsigned short newTid;
2990 char shareName[256];
2998 osi_Log0(smb_logp, "SMB receive tree connect");
3000 /* parse input parameters */
3001 tp = smb_GetSMBData(inp, NULL);
3002 pathp = smb_ParseASCIIBlock(tp, &tp);
3003 if (smb_StoreAnsiFilenames)
3004 OemToChar(pathp,pathp);
3005 passwordp = smb_ParseASCIIBlock(tp, &tp);
3006 tp = strrchr(pathp, '\\');
3008 return CM_ERROR_BADSMB;
3009 strcpy(shareName, tp+1);
3011 userp = smb_GetUser(vcp, inp);
3013 lock_ObtainMutex(&vcp->mx);
3014 newTid = vcp->tidCounter++;
3015 lock_ReleaseMutex(&vcp->mx);
3017 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3018 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3019 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3021 smb_ReleaseUID(uidp);
3023 smb_ReleaseTID(tidp);
3024 return CM_ERROR_BADSHARENAME;
3026 lock_ObtainMutex(&tidp->mx);
3027 tidp->userp = userp;
3028 tidp->pathname = sharePath;
3029 lock_ReleaseMutex(&tidp->mx);
3030 smb_ReleaseTID(tidp);
3032 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3033 smb_SetSMBParm(rsp, 1, newTid);
3034 smb_SetSMBDataLength(rsp, 0);
3036 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3040 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3044 if (*inp++ != 0x1) return NULL;
3045 tlen = inp[0] + (inp[1]<<8);
3046 inp += 2; /* skip length field */
3049 *chainpp = inp + tlen;
3052 if (lengthp) *lengthp = tlen;
3057 /* set maskp to the mask part of the incoming path.
3058 * Mask is 11 bytes long (8.3 with the dot elided).
3059 * Returns true if succeeds with a valid name, otherwise it does
3060 * its best, but returns false.
3062 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3070 /* starts off valid */
3073 /* mask starts out all blanks */
3074 memset(maskp, ' ', 11);
3076 /* find last backslash, or use whole thing if there is none */
3077 tp = strrchr(pathp, '\\');
3078 if (!tp) tp = pathp;
3079 else tp++; /* skip slash */
3083 /* names starting with a dot are illegal */
3084 if (*tp == '.') valid8Dot3 = 0;
3088 if (tc == 0) return valid8Dot3;
3089 if (tc == '.' || tc == '"') break;
3090 if (i < 8) *up++ = tc;
3091 else valid8Dot3 = 0;
3094 /* if we get here, tp point after the dot */
3095 up = maskp+8; /* ext goes here */
3102 if (tc == '.' || tc == '"')
3105 /* copy extension if not too long */
3115 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3125 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3127 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3131 /* otherwise, we have a valid 8.3 name; see if we have a match,
3132 * treating '?' as a wildcard in maskp (but not in the file name).
3134 tp1 = umask; /* real name, in mask format */
3135 tp2 = maskp; /* mask, in mask format */
3136 for(i=0; i<11; i++) {
3137 tc1 = *tp1++; /* char from real name */
3138 tc2 = *tp2++; /* char from mask */
3139 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3140 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3143 if (tc2 == '?' && tc1 != ' ')
3150 /* we got a match */
3154 char *smb_FindMask(char *pathp)
3158 tp = strrchr(pathp, '\\'); /* find last slash */
3161 return tp+1; /* skip the slash */
3163 return pathp; /* no slash, return the entire path */
3166 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3168 unsigned char *pathp;
3170 unsigned char mask[11];
3171 unsigned char *statBlockp;
3172 unsigned char initStatBlock[21];
3175 osi_Log0(smb_logp, "SMB receive search volume");
3177 /* pull pathname and stat block out of request */
3178 tp = smb_GetSMBData(inp, NULL);
3179 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3180 osi_assert(pathp != NULL);
3181 if (smb_StoreAnsiFilenames)
3182 OemToChar(pathp,pathp);
3183 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3184 osi_assert(statBlockp != NULL);
3186 statBlockp = initStatBlock;
3190 /* for returning to caller */
3191 smb_Get8Dot3MaskFromPath(mask, pathp);
3193 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3194 tp = smb_GetSMBData(outp, NULL);
3196 *tp++ = 43; /* bytes in a dir entry */
3197 *tp++ = 0; /* high byte in counter */
3199 /* now marshall the dir entry, starting with the search status */
3200 *tp++ = statBlockp[0]; /* Reserved */
3201 memcpy(tp, mask, 11); tp += 11; /* FileName */
3203 /* now pass back server use info, with 1st byte non-zero */
3205 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3207 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3209 *tp++ = 0x8; /* attribute: volume */
3219 /* 4 byte file size */
3225 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3226 memset(tp, ' ', 13);
3229 /* set the length of the data part of the packet to 43 + 3, for the dir
3230 * entry plus the 5 and the length fields.
3232 smb_SetSMBDataLength(outp, 46);
3236 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3237 cm_user_t *userp, cm_req_t *reqp)
3245 smb_dirListPatch_t *patchp;
3246 smb_dirListPatch_t *npatchp;
3248 for (patchp = *dirPatchespp; patchp; patchp =
3249 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3251 dptr = patchp->dptr;
3253 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3255 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3256 *dptr++ = SMB_ATTR_HIDDEN;
3259 lock_ObtainMutex(&scp->mx);
3260 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3261 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3263 lock_ReleaseMutex(&scp->mx);
3264 cm_ReleaseSCache(scp);
3265 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3266 *dptr++ = SMB_ATTR_HIDDEN;
3270 attr = smb_Attributes(scp);
3271 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3272 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3273 attr |= SMB_ATTR_HIDDEN;
3277 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3280 shortTemp = (unsigned short) (dosTime & 0xffff);
3281 *((u_short *)dptr) = shortTemp;
3284 /* and copy out date */
3285 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3286 *((u_short *)dptr) = shortTemp;
3289 /* copy out file length */
3290 *((u_long *)dptr) = scp->length.LowPart;
3292 lock_ReleaseMutex(&scp->mx);
3293 cm_ReleaseSCache(scp);
3296 /* now free the patches */
3297 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3298 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3302 /* and mark the list as empty */
3303 *dirPatchespp = NULL;
3308 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3317 smb_dirListPatch_t *dirListPatchesp;
3318 smb_dirListPatch_t *curPatchp;
3322 osi_hyper_t dirLength;
3323 osi_hyper_t bufferOffset;
3324 osi_hyper_t curOffset;
3326 unsigned char *inCookiep;
3327 smb_dirSearch_t *dsp;
3331 unsigned long clientCookie;
3332 cm_pageHeader_t *pageHeaderp;
3333 cm_user_t *userp = NULL;
3340 long nextEntryCookie;
3341 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3342 char resByte; /* reserved byte from the cookie */
3343 char *op; /* output data ptr */
3344 char *origOp; /* original value of op */
3345 cm_space_t *spacep; /* for pathname buffer */
3356 maxCount = smb_GetSMBParm(inp, 0);
3358 dirListPatchesp = NULL;
3360 caseFold = CM_FLAG_CASEFOLD;
3362 tp = smb_GetSMBData(inp, NULL);
3363 pathp = smb_ParseASCIIBlock(tp, &tp);
3364 if (smb_StoreAnsiFilenames)
3365 OemToChar(pathp,pathp);
3366 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3368 /* bail out if request looks bad */
3369 if (!tp || !pathp) {
3370 return CM_ERROR_BADSMB;
3373 /* We can handle long names */
3374 if (vcp->flags & SMB_VCFLAG_USENT)
3375 ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
3377 /* make sure we got a whole search status */
3378 if (dataLength < 21) {
3379 nextCookie = 0; /* start at the beginning of the dir */
3382 attribute = smb_GetSMBParm(inp, 1);
3384 /* handle volume info in another function */
3385 if (attribute & 0x8)
3386 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3388 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3389 maxCount, osi_LogSaveString(smb_logp, pathp));
3391 if (*pathp == 0) { /* null pathp, treat as root dir */
3392 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3393 return CM_ERROR_NOFILES;
3397 dsp = smb_NewDirSearch(0);
3398 dsp->attribute = attribute;
3399 smb_Get8Dot3MaskFromPath(mask, pathp);
3400 memcpy(dsp->mask, mask, 11);
3402 /* track if this is likely to match a lot of entries */
3403 if (smb_IsStarMask(mask)) starPattern = 1;
3404 else starPattern = 0;
3407 /* pull the next cookie value out of the search status block */
3408 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3409 + (inCookiep[16]<<24);
3410 dsp = smb_FindDirSearch(inCookiep[12]);
3412 /* can't find dir search status; fatal error */
3413 return CM_ERROR_BADFD;
3415 attribute = dsp->attribute;
3416 resByte = inCookiep[0];
3418 /* copy out client cookie, in host byte order. Don't bother
3419 * interpreting it, since we're just passing it through, anyway.
3421 memcpy(&clientCookie, &inCookiep[17], 4);
3423 memcpy(mask, dsp->mask, 11);
3425 /* assume we're doing a star match if it has continued for more
3431 osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3432 nextCookie, dsp->cookie, attribute);
3434 userp = smb_GetUser(vcp, inp);
3436 /* try to get the vnode for the path name next */
3437 lock_ObtainMutex(&dsp->mx);
3444 spacep = inp->spacep;
3445 smb_StripLastComponent(spacep->data, NULL, pathp);
3446 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3448 lock_ReleaseMutex(&dsp->mx);
3449 cm_ReleaseUser(userp);
3450 smb_DeleteDirSearch(dsp);
3451 smb_ReleaseDirSearch(dsp);
3452 return CM_ERROR_NOFILES;
3454 code = cm_NameI(cm_rootSCachep, spacep->data,
3455 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3458 cm_ReleaseSCache(dsp->scp);
3460 /* we need one hold for the entry we just stored into,
3461 * and one for our own processing. When we're done with this
3462 * function, we'll drop the one for our own processing.
3463 * We held it once from the namei call, and so we do another hold
3467 lock_ObtainMutex(&scp->mx);
3468 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3469 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3470 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3471 dsp->flags |= SMB_DIRSEARCH_BULKST;
3473 lock_ReleaseMutex(&scp->mx);
3476 lock_ReleaseMutex(&dsp->mx);
3478 cm_ReleaseUser(userp);
3479 smb_DeleteDirSearch(dsp);
3480 smb_ReleaseDirSearch(dsp);
3484 /* reserves space for parameter; we'll adjust it again later to the
3485 * real count of the # of entries we returned once we've actually
3486 * assembled the directory listing.
3488 smb_SetSMBParm(outp, 0, 0);
3490 /* get the directory size */
3491 lock_ObtainMutex(&scp->mx);
3492 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3493 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3495 lock_ReleaseMutex(&scp->mx);
3496 cm_ReleaseSCache(scp);
3497 cm_ReleaseUser(userp);
3498 smb_DeleteDirSearch(dsp);
3499 smb_ReleaseDirSearch(dsp);
3503 dirLength = scp->length;
3505 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3506 curOffset.HighPart = 0;
3507 curOffset.LowPart = nextCookie;
3508 origOp = op = smb_GetSMBData(outp, NULL);
3509 /* and write out the basic header */
3510 *op++ = 5; /* variable block */
3511 op += 2; /* skip vbl block length; we'll fill it in later */
3515 /* make sure that curOffset.LowPart doesn't point to the first
3516 * 32 bytes in the 2nd through last dir page, and that it doesn't
3517 * point at the first 13 32-byte chunks in the first dir page,
3518 * since those are dir and page headers, and don't contain useful
3521 temp = curOffset.LowPart & (2048-1);
3522 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3523 /* we're in the first page */
3524 if (temp < 13*32) temp = 13*32;
3527 /* we're in a later dir page */
3528 if (temp < 32) temp = 32;
3531 /* make sure the low order 5 bits are zero */
3534 /* now put temp bits back ito curOffset.LowPart */
3535 curOffset.LowPart &= ~(2048-1);
3536 curOffset.LowPart |= temp;
3538 /* check if we've returned all the names that will fit in the
3541 if (returnedNames >= maxCount)
3544 /* check if we've passed the dir's EOF */
3545 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3547 /* see if we can use the bufferp we have now; compute in which page
3548 * the current offset would be, and check whether that's the offset
3549 * of the buffer we have. If not, get the buffer.
3551 thyper.HighPart = curOffset.HighPart;
3552 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3553 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3556 buf_Release(bufferp);
3559 lock_ReleaseMutex(&scp->mx);
3560 lock_ObtainRead(&scp->bufCreateLock);
3561 code = buf_Get(scp, &thyper, &bufferp);
3562 lock_ReleaseRead(&scp->bufCreateLock);
3563 lock_ObtainMutex(&dsp->mx);
3565 /* now, if we're doing a star match, do bulk fetching of all of
3566 * the status info for files in the dir.
3569 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3570 lock_ObtainMutex(&scp->mx);
3571 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3572 LargeIntegerGreaterThanOrEqualTo(thyper,
3573 scp->bulkStatProgress)) {
3574 /* Don't bulk stat if risking timeout */
3575 int now = GetCurrentTime();
3576 if (now - req.startTime > 5000) {
3577 scp->bulkStatProgress = thyper;
3578 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3579 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3581 cm_TryBulkStat(scp, &thyper, userp, &req);
3584 lock_ObtainMutex(&scp->mx);
3586 lock_ReleaseMutex(&dsp->mx);
3590 bufferOffset = thyper;
3592 /* now get the data in the cache */
3594 code = cm_SyncOp(scp, bufferp, userp, &req,
3596 CM_SCACHESYNC_NEEDCALLBACK |
3597 CM_SCACHESYNC_READ);
3600 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3602 /* otherwise, load the buffer and try again */
3603 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3607 buf_Release(bufferp);
3611 } /* if (wrong buffer) ... */
3613 /* now we have the buffer containing the entry we're interested in; copy
3614 * it out if it represents a non-deleted entry.
3616 entryInDir = curOffset.LowPart & (2048-1);
3617 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3619 /* page header will help tell us which entries are free. Page header
3620 * can change more often than once per buffer, since AFS 3 dir page size
3621 * may be less than (but not more than a buffer package buffer.
3623 temp = curOffset.LowPart & (buf_bufferSize - 1); /* only look intra-buffer */
3624 temp &= ~(2048 - 1); /* turn off intra-page bits */
3625 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3627 /* now determine which entry we're looking at in the page. If it is
3628 * free (there's a free bitmap at the start of the dir), we should
3629 * skip these 32 bytes.
3631 slotInPage = (entryInDir & 0x7e0) >> 5;
3632 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3633 /* this entry is free */
3634 numDirChunks = 1; /* only skip this guy */
3638 tp = bufferp->datap + entryInBuffer;
3639 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3641 /* while we're here, compute the next entry's location, too,
3642 * since we'll need it when writing out the cookie into the dir
3645 * XXXX Probably should do more sanity checking.
3647 numDirChunks = cm_NameEntries(dep->name, NULL);
3649 /* compute the offset of the cookie representing the next entry */
3650 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3652 /* Compute 8.3 name if necessary */
3653 actualName = dep->name;
3654 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3655 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3656 actualName = shortName;
3659 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3660 /* this is one of the entries to use: it is not deleted
3661 * and it matches the star pattern we're looking for.
3664 /* Eliminate entries that don't match requested
3667 /* no hidden files */
3668 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3671 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3673 /* We have already done the cm_TryBulkStat above */
3674 fid.cell = scp->fid.cell;
3675 fid.volume = scp->fid.volume;
3676 fid.vnode = ntohl(dep->fid.vnode);
3677 fid.unique = ntohl(dep->fid.unique);
3678 fileType = cm_FindFileType(&fid);
3679 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3680 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3682 if (fileType == CM_SCACHETYPE_DIRECTORY)
3687 memcpy(op, mask, 11); op += 11;
3688 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3689 *op++ = nextEntryCookie & 0xff;
3690 *op++ = (nextEntryCookie>>8) & 0xff;
3691 *op++ = (nextEntryCookie>>16) & 0xff;
3692 *op++ = (nextEntryCookie>>24) & 0xff;
3693 memcpy(op, &clientCookie, 4); op += 4;
3695 /* now we emit the attribute. This is sort of tricky,
3696 * since we need to really stat the file to find out
3697 * what type of entry we've got. Right now, we're
3698 * copying out data from a buffer, while holding the
3699 * scp locked, so it isn't really convenient to stat
3700 * something now. We'll put in a place holder now,
3701 * and make a second pass before returning this to get
3702 * the real attributes. So, we just skip the data for
3703 * now, and adjust it later. We allocate a patch
3704 * record to make it easy to find this point later.
3705 * The replay will happen at a time when it is safe to
3706 * unlock the directory.
3708 curPatchp = malloc(sizeof(*curPatchp));
3709 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3710 curPatchp->dptr = op;
3711 curPatchp->fid.cell = scp->fid.cell;
3712 curPatchp->fid.volume = scp->fid.volume;
3713 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3714 curPatchp->fid.unique = ntohl(dep->fid.unique);
3716 /* do hidden attribute here since name won't be around when applying
3720 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3721 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3723 curPatchp->flags = 0;
3725 op += 9; /* skip attr, time, date and size */
3727 /* zero out name area. The spec says to pad with
3728 * spaces, but Samba doesn't, and neither do we.
3732 /* finally, we get to copy out the name; we know that
3733 * it fits in 8.3 or the pattern wouldn't match, but it
3734 * never hurts to be sure.
3736 strncpy(op, actualName, 13);
3737 if (smb_StoreAnsiFilenames)
3740 /* Uppercase if requested by client */
3741 if ((((smb_t *)inp)->flg2 & 1) == 0)
3746 /* now, adjust the # of entries copied */
3748 } /* if we're including this name */
3751 /* and adjust curOffset to be where the new cookie is */
3752 thyper.HighPart = 0;
3753 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3754 curOffset = LargeIntegerAdd(thyper, curOffset);
3755 } /* while copying data for dir listing */
3757 /* release the mutex */
3758 lock_ReleaseMutex(&scp->mx);
3759 if (bufferp) buf_Release(bufferp);
3761 /* apply and free last set of patches; if not doing a star match, this
3762 * will be empty, but better safe (and freeing everything) than sorry.
3764 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3766 /* special return code for unsuccessful search */
3767 if (code == 0 && dataLength < 21 && returnedNames == 0)
3768 code = CM_ERROR_NOFILES;
3770 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3771 returnedNames, code);
3774 smb_DeleteDirSearch(dsp);
3775 smb_ReleaseDirSearch(dsp);
3776 cm_ReleaseSCache(scp);
3777 cm_ReleaseUser(userp);
3781 /* finalize the output buffer */
3782 smb_SetSMBParm(outp, 0, returnedNames);
3783 temp = (long) (op - origOp);
3784 smb_SetSMBDataLength(outp, temp);
3786 /* the data area is a variable block, which has a 5 (already there)
3787 * followed by the length of the # of data bytes. We now know this to
3788 * be "temp," although that includes the 3 bytes of vbl block header.
3789 * Deduct for them and fill in the length field.
3791 temp -= 3; /* deduct vbl block info */
3792 osi_assert(temp == (43 * returnedNames));
3793 origOp[1] = temp & 0xff;
3794 origOp[2] = (temp>>8) & 0xff;
3795 if (returnedNames == 0)
3796 smb_DeleteDirSearch(dsp);
3797 smb_ReleaseDirSearch(dsp);
3798 cm_ReleaseSCache(scp);
3799 cm_ReleaseUser(userp);
3803 /* verify that this is a valid path to a directory. I don't know why they
3804 * don't use the get file attributes call.
3806 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3810 cm_scache_t *rootScp;
3811 cm_scache_t *newScp;
3820 pathp = smb_GetSMBData(inp, NULL);
3821 pathp = smb_ParseASCIIBlock(pathp, NULL);
3823 return CM_ERROR_BADFD;
3824 if (smb_StoreAnsiFilenames)
3825 OemToChar(pathp,pathp);
3826 osi_Log1(smb_logp, "SMB receive check path %s",
3827 osi_LogSaveString(smb_logp, pathp));
3829 rootScp = cm_rootSCachep;
3831 userp = smb_GetUser(vcp, inp);
3833 caseFold = CM_FLAG_CASEFOLD;
3835 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3837 cm_ReleaseUser(userp);
3838 return CM_ERROR_NOSUCHPATH;
3840 code = cm_NameI(rootScp, pathp,
3841 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3842 userp, tidPathp, &req, &newScp);
3845 cm_ReleaseUser(userp);
3849 /* now lock the vnode with a callback; returns with newScp locked */
3850 lock_ObtainMutex(&newScp->mx);
3851 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3852 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3853 if (code && code != CM_ERROR_NOACCESS) {
3854 lock_ReleaseMutex(&newScp->mx);
3855 cm_ReleaseSCache(newScp);
3856 cm_ReleaseUser(userp);
3860 attrs = smb_Attributes(newScp);
3862 if (!(attrs & 0x10))
3863 code = CM_ERROR_NOTDIR;
3865 lock_ReleaseMutex(&newScp->mx);
3867 cm_ReleaseSCache(newScp);
3868 cm_ReleaseUser(userp);
3872 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3876 cm_scache_t *rootScp;
3877 unsigned short attribute;
3879 cm_scache_t *newScp;
3888 /* decode basic attributes we're passed */
3889 attribute = smb_GetSMBParm(inp, 0);
3890 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3892 pathp = smb_GetSMBData(inp, NULL);
3893 pathp = smb_ParseASCIIBlock(pathp, NULL);
3895 return CM_ERROR_BADSMB;
3896 if (smb_StoreAnsiFilenames)
3897 OemToChar(pathp,pathp);
3899 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3900 dosTime, attribute);
3902 rootScp = cm_rootSCachep;
3904 userp = smb_GetUser(vcp, inp);
3906 caseFold = CM_FLAG_CASEFOLD;
3908 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3910 cm_ReleaseUser(userp);
3911 return CM_ERROR_NOSUCHFILE;
3913 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3914 tidPathp, &req, &newScp);
3917 cm_ReleaseUser(userp);
3921 /* now lock the vnode with a callback; returns with newScp locked; we
3922 * need the current status to determine what the new status is, in some
3925 lock_ObtainMutex(&newScp->mx);
3926 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3927 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3929 lock_ReleaseMutex(&newScp->mx);
3930 cm_ReleaseSCache(newScp);
3931 cm_ReleaseUser(userp);
3935 /* Check for RO volume */
3936 if (newScp->flags & CM_SCACHEFLAG_RO) {
3937 lock_ReleaseMutex(&newScp->mx);
3938 cm_ReleaseSCache(newScp);
3939 cm_ReleaseUser(userp);
3940 return CM_ERROR_READONLY;
3943 /* prepare for setattr call */
3946 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3947 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3949 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3950 /* we're told to make a writable file read-only */
3951 attr.unixModeBits = newScp->unixModeBits & ~0222;
3952 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3954 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3955 /* we're told to make a read-only file writable */
3956 attr.unixModeBits = newScp->unixModeBits | 0222;
3957 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3959 lock_ReleaseMutex(&newScp->mx);
3961 /* now call setattr */
3963 code = cm_SetAttr(newScp, &attr, userp, &req);
3967 cm_ReleaseSCache(newScp);
3968 cm_ReleaseUser(userp);
3973 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3977 cm_scache_t *rootScp;
3978 cm_scache_t *newScp, *dscp;
3990 pathp = smb_GetSMBData(inp, NULL);
3991 pathp = smb_ParseASCIIBlock(pathp, NULL);
3993 return CM_ERROR_BADSMB;
3995 if (*pathp == 0) /* null path */
3998 if (smb_StoreAnsiFilenames)
3999 OemToChar(pathp,pathp);
4001 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4002 osi_LogSaveString(smb_logp, pathp));
4004 rootScp = cm_rootSCachep;
4006 userp = smb_GetUser(vcp, inp);
4008 /* we shouldn't need this for V3 requests, but we seem to */
4009 caseFold = CM_FLAG_CASEFOLD;
4011 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4013 cm_ReleaseUser(userp);
4014 return CM_ERROR_NOSUCHFILE;
4018 * XXX Strange hack XXX
4020 * As of Patch 5 (16 July 97), we are having the following problem:
4021 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4022 * requests to look up "desktop.ini" in all the subdirectories.
4023 * This can cause zillions of timeouts looking up non-existent cells
4024 * and volumes, especially in the top-level directory.
4026 * We have not found any way to avoid this or work around it except
4027 * to explicitly ignore the requests for mount points that haven't
4028 * yet been evaluated and for directories that haven't yet been
4031 * We should modify this hack to provide a fake desktop.ini file
4032 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4034 spacep = inp->spacep;
4035 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4036 #ifndef SPECIAL_FOLDERS
4037 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4038 code = cm_NameI(rootScp, spacep->data,
4039 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4040 userp, tidPathp, &req, &dscp);
4042 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT &&
4043 !dscp->mountRootFidp)
4044 code = CM_ERROR_NOSUCHFILE;
4045 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4046 cm_buf_t *bp = buf_Find(dscp, &hzero);
4050 code = CM_ERROR_NOSUCHFILE;
4052 cm_ReleaseSCache(dscp);
4054 cm_ReleaseUser(userp);
4059 #endif /* SPECIAL_FOLDERS */
4061 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4062 tidPathp, &req, &newScp);
4064 cm_ReleaseUser(userp);
4068 /* now lock the vnode with a callback; returns with newScp locked */
4069 lock_ObtainMutex(&newScp->mx);
4070 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4071 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4073 lock_ReleaseMutex(&newScp->mx);
4074 cm_ReleaseSCache(newScp);
4075 cm_ReleaseUser(userp);
4080 /* use smb_Attributes instead. Also the fact that a file is
4081 * in a readonly volume doesn't mean it shojuld be marked as RO
4083 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4084 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4085 attrs = SMB_ATTR_DIRECTORY;
4088 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4089 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4091 attrs = smb_Attributes(newScp);
4094 smb_SetSMBParm(outp, 0, attrs);
4096 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4097 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4098 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4099 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4100 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4101 smb_SetSMBParm(outp, 5, 0);
4102 smb_SetSMBParm(outp, 6, 0);
4103 smb_SetSMBParm(outp, 7, 0);
4104 smb_SetSMBParm(outp, 8, 0);
4105 smb_SetSMBParm(outp, 9, 0);
4106 smb_SetSMBDataLength(outp, 0);
4107 lock_ReleaseMutex(&newScp->mx);
4109 cm_ReleaseSCache(newScp);
4110 cm_ReleaseUser(userp);
4115 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4119 osi_Log0(smb_logp, "SMB receive tree disconnect");
4121 /* find the tree and free it */
4122 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4124 lock_ObtainMutex(&tidp->mx);
4125 tidp->flags |= SMB_TIDFLAG_DELETE;
4126 lock_ReleaseMutex(&tidp->mx);
4127 smb_ReleaseTID(tidp);
4133 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4151 pathp = smb_GetSMBData(inp, NULL);
4152 pathp = smb_ParseASCIIBlock(pathp, NULL);
4153 if (smb_StoreAnsiFilenames)
4154 OemToChar(pathp,pathp);
4156 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4158 #ifdef DEBUG_VERBOSE
4162 hexpath = osi_HexifyString( pathp );
4163 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4168 share = smb_GetSMBParm(inp, 0);
4169 attribute = smb_GetSMBParm(inp, 1);
4171 spacep = inp->spacep;
4172 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4173 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4174 /* special case magic file name for receiving IOCTL requests
4175 * (since IOCTL calls themselves aren't getting through).
4177 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4178 smb_SetupIoctlFid(fidp, spacep);
4179 smb_SetSMBParm(outp, 0, fidp->fid);
4180 smb_SetSMBParm(outp, 1, 0); /* attrs */
4181 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4182 smb_SetSMBParm(outp, 3, 0);
4183 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4184 smb_SetSMBParm(outp, 5, 0x7fff);
4185 /* pass the open mode back */
4186 smb_SetSMBParm(outp, 6, (share & 0xf));
4187 smb_SetSMBDataLength(outp, 0);
4188 smb_ReleaseFID(fidp);
4192 userp = smb_GetUser(vcp, inp);
4194 caseFold = CM_FLAG_CASEFOLD;
4196 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4198 cm_ReleaseUser(userp);
4199 return CM_ERROR_NOSUCHPATH;
4201 code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4202 tidPathp, &req, &scp);
4205 cm_ReleaseUser(userp);
4209 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4211 cm_ReleaseSCache(scp);
4212 cm_ReleaseUser(userp);
4216 /* don't need callback to check file type, since file types never
4217 * change, and namei and cm_Lookup all stat the object at least once on
4218 * a successful return.
4220 if (scp->fileType != CM_SCACHETYPE_FILE) {
4221 cm_ReleaseSCache(scp);
4222 cm_ReleaseUser(userp);
4223 return CM_ERROR_ISDIR;
4226 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4229 /* save a pointer to the vnode */
4232 if ((share & 0xf) == 0)
4233 fidp->flags |= SMB_FID_OPENREAD;
4234 else if ((share & 0xf) == 1)
4235 fidp->flags |= SMB_FID_OPENWRITE;
4237 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4239 lock_ObtainMutex(&scp->mx);
4240 smb_SetSMBParm(outp, 0, fidp->fid);
4241 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4242 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4243 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4244 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4245 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4246 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4247 /* pass the open mode back; XXXX add access checks */
4248 smb_SetSMBParm(outp, 6, (share & 0xf));
4249 smb_SetSMBDataLength(outp, 0);
4250 lock_ReleaseMutex(&scp->mx);
4253 cm_Open(scp, 0, userp);
4255 /* send and free packet */
4256 smb_ReleaseFID(fidp);
4257 cm_ReleaseUser(userp);
4258 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4262 typedef struct smb_unlinkRock {
4267 char *maskp; /* pointer to the star pattern */
4272 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4275 smb_unlinkRock_t *rockp;
4283 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4284 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4285 caseFold |= CM_FLAG_8DOT3;
4287 matchName = dep->name;
4288 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4290 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4291 !cm_Is8Dot3(dep->name)) {
4292 cm_Gen8Dot3Name(dep, shortName, NULL);
4293 matchName = shortName;
4294 /* 8.3 matches are always case insensitive */
4295 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4298 osi_Log1(smb_logp, "Unlinking %s",
4299 osi_LogSaveString(smb_logp, matchName));
4300 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4301 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4302 smb_NotifyChange(FILE_ACTION_REMOVED,
4303 FILE_NOTIFY_CHANGE_FILE_NAME,
4304 dscp, dep->name, NULL, TRUE);
4308 /* If we made a case sensitive exact match, we might as well quit now. */
4309 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4310 code = CM_ERROR_STOPNOW;
4318 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4327 smb_unlinkRock_t rock;
4336 attribute = smb_GetSMBParm(inp, 0);
4338 tp = smb_GetSMBData(inp, NULL);
4339 pathp = smb_ParseASCIIBlock(tp, &tp);
4340 if (smb_StoreAnsiFilenames)
4341 OemToChar(pathp,pathp);
4343 osi_Log1(smb_logp, "SMB receive unlink %s",
4344 osi_LogSaveString(smb_logp, pathp));
4346 spacep = inp->spacep;
4347 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4349 userp = smb_GetUser(vcp, inp);
4351 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4353 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4355 cm_ReleaseUser(userp);
4356 return CM_ERROR_NOSUCHPATH;
4358 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
4362 cm_ReleaseUser(userp);
4366 /* otherwise, scp points to the parent directory. */
4373 rock.maskp = smb_FindMask(pathp);
4374 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4377 thyper.HighPart = 0;
4383 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4384 * match. If that fails, we do a case insensitve match.
4386 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4387 !smb_IsStarMask(rock.maskp)) {
4388 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4391 thyper.HighPart = 0;
4392 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4397 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4399 if (code == CM_ERROR_STOPNOW)
4402 cm_ReleaseUser(userp);
4404 cm_ReleaseSCache(dscp);
4406 if (code == 0 && !rock.any)
4407 code = CM_ERROR_NOSUCHFILE;
4411 typedef struct smb_renameRock {
4412 cm_scache_t *odscp; /* old dir */
4413 cm_scache_t *ndscp; /* new dir */
4414 cm_user_t *userp; /* user */
4415 cm_req_t *reqp; /* request struct */
4416 smb_vc_t *vcp; /* virtual circuit */
4417 char *maskp; /* pointer to star pattern of old file name */
4418 int flags; /* tilde, casefold, etc */
4419 char *newNamep; /* ptr to the new file's name */
4422 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4425 smb_renameRock_t *rockp;
4430 rockp = (smb_renameRock_t *) vrockp;
4432 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4433 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4434 caseFold |= CM_FLAG_8DOT3;
4436 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4438 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4439 !cm_Is8Dot3(dep->name)) {
4440 cm_Gen8Dot3Name(dep, shortName, NULL);
4441 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4444 code = cm_Rename(rockp->odscp, dep->name,
4445 rockp->ndscp, rockp->newNamep, rockp->userp,
4447 /* if the call worked, stop doing the search now, since we
4448 * really only want to rename one file.
4451 code = CM_ERROR_STOPNOW;
4460 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4463 cm_space_t *spacep = NULL;
4464 smb_renameRock_t rock;
4465 cm_scache_t *oldDscp = NULL;
4466 cm_scache_t *newDscp = NULL;
4467 cm_scache_t *tmpscp= NULL;
4468 cm_scache_t *tmpscp2 = NULL;
4478 userp = smb_GetUser(vcp, inp);
4479 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4481 cm_ReleaseUser(userp);
4482 return CM_ERROR_NOSUCHPATH;
4486 spacep = inp->spacep;
4487 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4490 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4491 * what actually exists is foo/baz. I don't know why the code used to be
4492 * the way it was. 1/29/96
4494 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4496 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4498 * caseFold = CM_FLAG_CASEFOLD;
4500 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4501 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4502 userp, tidPathp, &req, &oldDscp);
4505 cm_ReleaseUser(userp);
4509 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4510 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4511 userp, tidPathp, &req, &newDscp);
4514 cm_ReleaseSCache(oldDscp);
4515 cm_ReleaseUser(userp);
4519 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4520 * next, get the component names, and lower case them.
4523 /* handle the old name first */
4525 oldLastNamep = oldPathp;
4529 /* and handle the new name, too */
4531 newLastNamep = newPathp;
4535 /* TODO: The old name could be a wildcard. The new name must not be */
4537 /* do the vnode call */
4538 rock.odscp = oldDscp;
4539 rock.ndscp = newDscp;
4543 rock.maskp = oldLastNamep;
4544 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4545 rock.newNamep = newLastNamep;
4547 /* Check if the file already exists; if so return error */
4548 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4549 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4550 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4551 osi_LogSaveString(afsd_logp, newLastNamep));
4553 /* Check if the old and the new names differ only in case. If so return
4554 * success, else return CM_ERROR_EXISTS
4556 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4558 /* This would be a success only if the old file is *as same as* the new file */
4559 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4561 if (tmpscp == tmpscp2)
4564 code = CM_ERROR_EXISTS;
4565 cm_ReleaseSCache(tmpscp2);
4568 code = CM_ERROR_NOSUCHFILE;
4571 /* file exist, do not rename, also fixes move */
4572 osi_Log0(smb_logp, "Can't rename. Target already exists");
4573 code = CM_ERROR_EXISTS;
4577 cm_ReleaseSCache(tmpscp);
4578 cm_ReleaseSCache(newDscp);
4579 cm_ReleaseSCache(oldDscp);
4580 cm_ReleaseUser(userp);
4584 /* Now search the directory for the pattern, and do the appropriate rename when found */
4585 thyper.LowPart = 0; /* search dir from here */
4586 thyper.HighPart = 0;
4588 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4590 if (code == CM_ERROR_STOPNOW)
4593 code = CM_ERROR_NOSUCHFILE;
4595 /* Handle Change Notification */
4597 * Being lazy, not distinguishing between files and dirs in this
4598 * filter, since we'd have to do a lookup.
4600 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4601 if (oldDscp == newDscp) {
4602 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4603 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4604 filter, oldDscp, oldLastNamep,
4605 newLastNamep, TRUE);
4607 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4608 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4609 filter, oldDscp, oldLastNamep,
4611 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4612 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4613 filter, newDscp, newLastNamep,
4618 cm_ReleaseSCache(tmpscp);
4619 cm_ReleaseUser(userp);
4620 cm_ReleaseSCache(oldDscp);
4621 cm_ReleaseSCache(newDscp);
4626 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4629 cm_space_t *spacep = NULL;
4630 cm_scache_t *oldDscp = NULL;
4631 cm_scache_t *newDscp = NULL;
4632 cm_scache_t *tmpscp= NULL;
4633 cm_scache_t *tmpscp2 = NULL;
4634 cm_scache_t *sscp = NULL;
4643 userp = smb_GetUser(vcp, inp);
4645 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4647 cm_ReleaseUser(userp);
4648 return CM_ERROR_NOSUCHPATH;
4653 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4655 spacep = inp->spacep;
4656 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4658 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4659 userp, tidPathp, &req, &oldDscp);
4661 cm_ReleaseUser(userp);
4665 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4666 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4667 userp, tidPathp, &req, &newDscp);
4669 cm_ReleaseSCache(oldDscp);
4670 cm_ReleaseUser(userp);
4674 /* Now, although we did two lookups for the two directories (because the same
4675 * directory can be referenced through different paths), we only allow hard links
4676 * within the same directory. */
4677 if (oldDscp != newDscp) {
4678 cm_ReleaseSCache(oldDscp);
4679 cm_ReleaseSCache(newDscp);
4680 cm_ReleaseUser(userp);
4681 return CM_ERROR_CROSSDEVLINK;
4684 /* handle the old name first */
4686 oldLastNamep = oldPathp;
4690 /* and handle the new name, too */
4692 newLastNamep = newPathp;
4696 /* now lookup the old name */
4697 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4698 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4700 cm_ReleaseSCache(oldDscp);
4701 cm_ReleaseSCache(newDscp);
4702 cm_ReleaseUser(userp);
4706 /* Check if the file already exists; if so return error */
4707 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4708 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4709 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4710 osi_LogSaveString(afsd_logp, newLastNamep));
4712 /* if the existing link is to the same file, then we return success */
4714 if(sscp == tmpscp) {
4717 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
4718 code = CM_ERROR_EXISTS;
4723 cm_ReleaseSCache(tmpscp);
4724 cm_ReleaseSCache(sscp);
4725 cm_ReleaseSCache(newDscp);
4726 cm_ReleaseSCache(oldDscp);
4727 cm_ReleaseUser(userp);
4731 /* now create the hardlink */
4732 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
4733 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
4734 osi_Log1(smb_logp," Link returns %d", code);
4736 /* Handle Change Notification */
4738 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
4739 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4740 smb_NotifyChange(FILE_ACTION_ADDED,
4741 filter, newDscp, newLastNamep,
4746 cm_ReleaseSCache(tmpscp);
4747 cm_ReleaseUser(userp);
4748 cm_ReleaseSCache(sscp);
4749 cm_ReleaseSCache(oldDscp);
4750 cm_ReleaseSCache(newDscp);
4755 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4761 tp = smb_GetSMBData(inp, NULL);
4762 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4763 if (smb_StoreAnsiFilenames)
4764 OemToChar(oldPathp,oldPathp);
4765 newPathp = smb_ParseASCIIBlock(tp, &tp);
4766 if (smb_StoreAnsiFilenames)
4767 OemToChar(newPathp,newPathp);
4769 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4770 osi_LogSaveString(smb_logp, oldPathp),
4771 osi_LogSaveString(smb_logp, newPathp));
4773 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
4778 typedef struct smb_rmdirRock {
4782 char *maskp; /* pointer to the star pattern */
4787 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4790 smb_rmdirRock_t *rockp;
4795 rockp = (smb_rmdirRock_t *) vrockp;
4797 matchName = dep->name;
4798 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4799 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4801 match = (strcmp(matchName, rockp->maskp) == 0);
4803 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4804 !cm_Is8Dot3(dep->name)) {
4805 cm_Gen8Dot3Name(dep, shortName, NULL);
4806 matchName = shortName;
4807 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4810 osi_Log1(smb_logp, "Removing directory %s",
4811 osi_LogSaveString(smb_logp, matchName));
4812 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4813 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4814 smb_NotifyChange(FILE_ACTION_REMOVED,
4815 FILE_NOTIFY_CHANGE_DIR_NAME,
4816 dscp, dep->name, NULL, TRUE);
4825 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4833 smb_rmdirRock_t rock;
4842 tp = smb_GetSMBData(inp, NULL);
4843 pathp = smb_ParseASCIIBlock(tp, &tp);
4844 if (smb_StoreAnsiFilenames)
4845 OemToChar(pathp,pathp);
4847 spacep = inp->spacep;
4848 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4850 userp = smb_GetUser(vcp, inp);
4852 caseFold = CM_FLAG_CASEFOLD;
4854 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4856 cm_ReleaseUser(userp);
4857 return CM_ERROR_NOSUCHPATH;
4859 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4860 userp, tidPathp, &req, &dscp);
4863 cm_ReleaseUser(userp);
4867 /* otherwise, scp points to the parent directory. */
4874 rock.maskp = lastNamep;
4875 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4878 thyper.HighPart = 0;
4882 /* First do a case sensitive match, and if that fails, do a case insensitive match */
4883 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4884 if (code == 0 && !rock.any) {
4886 thyper.HighPart = 0;
4887 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4888 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4891 cm_ReleaseUser(userp);
4893 cm_ReleaseSCache(dscp);
4895 if (code == 0 && !rock.any)
4896 code = CM_ERROR_NOSUCHFILE;
4900 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4910 fid = smb_GetSMBParm(inp, 0);
4912 osi_Log1(smb_logp, "SMB flush fid %d", fid);
4914 fid = smb_ChainFID(fid, inp);
4915 fidp = smb_FindFID(vcp, fid, 0);
4916 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4918 smb_ReleaseFID(fidp);
4919 return CM_ERROR_BADFD;
4922 userp = smb_GetUser(vcp, inp);
4924 lock_ObtainMutex(&fidp->mx);
4925 if (fidp->flags & SMB_FID_OPENWRITE)
4926 code = cm_FSync(fidp->scp, userp, &req);
4929 lock_ReleaseMutex(&fidp->mx);
4931 smb_ReleaseFID(fidp);
4933 cm_ReleaseUser(userp);
4938 struct smb_FullNameRock {
4944 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4948 struct smb_FullNameRock *vrockp;
4950 vrockp = (struct smb_FullNameRock *)rockp;
4952 if (!cm_Is8Dot3(dep->name)) {
4953 cm_Gen8Dot3Name(dep, shortName, NULL);
4955 if (cm_stricmp(shortName, vrockp->name) == 0) {
4956 vrockp->fullName = strdup(dep->name);
4957 return CM_ERROR_STOPNOW;
4960 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
4961 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
4962 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4963 vrockp->fullName = strdup(dep->name);
4964 return CM_ERROR_STOPNOW;
4969 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4970 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4972 struct smb_FullNameRock rock;
4978 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
4979 if (code == CM_ERROR_STOPNOW)
4980 *newPathp = rock.fullName;
4982 *newPathp = strdup(pathp);
4985 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4996 fid = smb_GetSMBParm(inp, 0);
4997 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4999 osi_Log1(smb_logp, "SMB close fid %d", fid);
5001 fid = smb_ChainFID(fid, inp);
5002 fidp = smb_FindFID(vcp, fid, 0);
5004 return CM_ERROR_BADFD;
5007 userp = smb_GetUser(vcp, inp);
5009 lock_ObtainMutex(&fidp->mx);
5011 /* Don't jump the gun on an async raw write */
5012 while (fidp->raw_writers) {
5013 lock_ReleaseMutex(&fidp->mx);
5014 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5015 lock_ObtainMutex(&fidp->mx);
5018 fidp->flags |= SMB_FID_DELETE;
5020 /* watch for ioctl closes, and read-only opens */
5021 if (fidp->scp != NULL &&
5022 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5023 == SMB_FID_OPENWRITE) {
5024 if (dosTime != 0 && dosTime != -1) {
5025 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5026 /* This fixes defect 10958 */
5027 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5028 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5030 code = cm_FSync(fidp->scp, userp, &req);
5035 if (fidp->flags & SMB_FID_DELONCLOSE) {
5036 cm_scache_t *dscp = fidp->NTopen_dscp;
5037 char *pathp = fidp->NTopen_pathp;
5040 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5041 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5042 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5043 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5044 smb_NotifyChange(FILE_ACTION_REMOVED,
5045 FILE_NOTIFY_CHANGE_DIR_NAME,
5046 dscp, fullPathp, NULL, TRUE);
5050 code = cm_Unlink(dscp, fullPathp, userp, &req);
5051 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5052 smb_NotifyChange(FILE_ACTION_REMOVED,
5053 FILE_NOTIFY_CHANGE_FILE_NAME,
5054 dscp, fullPathp, NULL, TRUE);
5058 lock_ReleaseMutex(&fidp->mx);
5060 if (fidp->flags & SMB_FID_NTOPEN) {
5061 cm_ReleaseSCache(fidp->NTopen_dscp);
5062 free(fidp->NTopen_pathp);
5064 if (fidp->NTopen_wholepathp)
5065 free(fidp->NTopen_wholepathp);
5067 smb_ReleaseFID(fidp);
5068 cm_ReleaseUser(userp);
5073 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5076 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5077 cm_user_t *userp, long *readp)
5079 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5080 cm_user_t *userp, long *readp, int dosflag)
5087 osi_hyper_t fileLength;
5089 osi_hyper_t lastByte;
5090 osi_hyper_t bufferOffset;
5091 long bufIndex, nbytes;
5101 lock_ObtainMutex(&fidp->mx);
5103 lock_ObtainMutex(&scp->mx);
5105 if (offset.HighPart == 0) {
5106 chunk = offset.LowPart >> cm_logChunkSize;
5107 if (chunk != fidp->curr_chunk) {
5108 fidp->prev_chunk = fidp->curr_chunk;
5109 fidp->curr_chunk = chunk;
5111 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5115 /* start by looking up the file's end */
5116 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5117 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5118 if (code) goto done;
5120 /* now we have the entry locked, look up the length */
5121 fileLength = scp->length;
5123 /* adjust count down so that it won't go past EOF */
5124 thyper.LowPart = count;
5125 thyper.HighPart = 0;
5126 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5128 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5129 /* we'd read past EOF, so just stop at fileLength bytes.
5130 * Start by computing how many bytes remain in the file.
5132 thyper = LargeIntegerSubtract(fileLength, offset);
5134 /* if we are past EOF, read 0 bytes */
5135 if (LargeIntegerLessThanZero(thyper))
5138 count = thyper.LowPart;
5143 /* now, copy the data one buffer at a time,
5144 * until we've filled the request packet
5147 /* if we've copied all the data requested, we're done */
5148 if (count <= 0) break;
5150 /* otherwise, load up a buffer of data */
5151 thyper.HighPart = offset.HighPart;
5152 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5153 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5156 buf_Release(bufferp);
5159 lock_ReleaseMutex(&scp->mx);
5161 lock_ObtainRead(&scp->bufCreateLock);
5162 code = buf_Get(scp, &thyper, &bufferp);
5163 lock_ReleaseRead(&scp->bufCreateLock);
5165 lock_ObtainMutex(&scp->mx);
5166 if (code) goto done;
5167 bufferOffset = thyper;
5169 /* now get the data in the cache */
5171 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5172 CM_SCACHESYNC_NEEDCALLBACK |
5173 CM_SCACHESYNC_READ);
5174 if (code) goto done;
5176 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5178 /* otherwise, load the buffer and try again */
5179 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5183 buf_Release(bufferp);
5187 } /* if (wrong buffer) ... */
5189 /* now we have the right buffer loaded. Copy out the
5190 * data from here to the user's buffer.
5192 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5194 /* and figure out how many bytes we want from this buffer */
5195 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5196 if (nbytes > count) nbytes = count; /* don't go past EOF */
5198 /* now copy the data */
5201 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5204 memcpy(op, bufferp->datap + bufIndex, nbytes);
5206 /* adjust counters, pointers, etc. */
5209 thyper.LowPart = nbytes;
5210 thyper.HighPart = 0;
5211 offset = LargeIntegerAdd(thyper, offset);
5215 lock_ReleaseMutex(&scp->mx);
5216 lock_ReleaseMutex(&fidp->mx);
5218 buf_Release(bufferp);
5220 if (code == 0 && sequential)
5221 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5227 * smb_WriteData -- common code for Write and Raw Write
5230 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5231 cm_user_t *userp, long *writtenp)
5233 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5234 cm_user_t *userp, long *writtenp, int dosflag)
5241 osi_hyper_t fileLength; /* file's length at start of write */
5242 osi_hyper_t minLength; /* don't read past this */
5243 long nbytes; /* # of bytes to transfer this iteration */
5245 osi_hyper_t thyper; /* hyper tmp variable */
5246 osi_hyper_t bufferOffset;
5247 long bufIndex; /* index in buffer where our data is */
5249 osi_hyper_t writeBackOffset;/* offset of region to write back when
5254 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5255 fidp->fid, offsetp->LowPart, count);
5265 lock_ObtainMutex(&fidp->mx);
5267 lock_ObtainMutex(&scp->mx);
5269 /* start by looking up the file's end */
5270 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5272 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5273 CM_SCACHESYNC_NEEDCALLBACK
5274 | CM_SCACHESYNC_SETSTATUS
5275 | CM_SCACHESYNC_GETSTATUS);
5276 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5281 /* make sure we have a writable FD */
5282 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5283 code = CM_ERROR_BADFDOP;
5287 /* now we have the entry locked, look up the length */
5288 fileLength = scp->length;
5289 minLength = fileLength;
5290 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5291 minLength = scp->serverLength;
5293 /* adjust file length if we extend past EOF */
5294 thyper.LowPart = count;
5295 thyper.HighPart = 0;
5296 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5297 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5298 /* we'd write past EOF, so extend the file */
5299 scp->mask |= CM_SCACHEMASK_LENGTH;
5300 scp->length = thyper;
5301 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5303 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5305 /* now, if the new position (thyper) and the old (offset) are in
5306 * different storeback windows, remember to store back the previous
5307 * storeback window when we're done with the write.
5309 if ((thyper.LowPart & (-cm_chunkSize)) !=
5310 (offset.LowPart & (-cm_chunkSize))) {
5311 /* they're different */
5313 writeBackOffset.HighPart = offset.HighPart;
5314 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5319 /* now, copy the data one buffer at a time, until we've filled the
5322 /* if we've copied all the data requested, we're done */
5326 /* handle over quota or out of space */
5327 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5328 *writtenp = written;
5329 code = CM_ERROR_QUOTA;
5333 /* otherwise, load up a buffer of data */
5334 thyper.HighPart = offset.HighPart;
5335 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
5336 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5339 lock_ReleaseMutex(&bufferp->mx);
5340 buf_Release(bufferp);
5343 lock_ReleaseMutex(&scp->mx);
5345 lock_ObtainRead(&scp->bufCreateLock);
5346 code = buf_Get(scp, &thyper, &bufferp);
5347 lock_ReleaseRead(&scp->bufCreateLock);
5349 lock_ObtainMutex(&bufferp->mx);
5350 lock_ObtainMutex(&scp->mx);
5351 if (code) goto done;
5353 bufferOffset = thyper;
5355 /* now get the data in the cache */
5357 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5359 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5360 CM_SCACHESYNC_NEEDCALLBACK
5361 | CM_SCACHESYNC_WRITE
5362 | CM_SCACHESYNC_BUFLOCKED);
5363 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5368 /* If we're overwriting the entire buffer, or
5369 * if we're writing at or past EOF, mark the
5370 * buffer as current so we don't call
5371 * cm_GetBuffer. This skips the fetch from the
5372 * server in those cases where we're going to
5373 * obliterate all the data in the buffer anyway,
5374 * or in those cases where there is no useful
5375 * data at the server to start with.
5377 * Use minLength instead of scp->length, since
5378 * the latter has already been updated by this
5381 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5382 || LargeIntegerEqualTo(offset, bufferp->offset)
5383 && (count >= buf_bufferSize
5384 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5385 ConvertLongToLargeInteger(count)),
5387 if (count < buf_bufferSize
5388 && bufferp->dataVersion == -1)
5389 memset(bufferp->datap, 0,
5391 bufferp->dataVersion = scp->dataVersion;
5394 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5396 /* otherwise, load the buffer and try again */
5397 lock_ReleaseMutex(&bufferp->mx);
5398 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5400 lock_ReleaseMutex(&scp->mx);
5401 lock_ObtainMutex(&bufferp->mx);
5402 lock_ObtainMutex(&scp->mx);
5406 lock_ReleaseMutex(&bufferp->mx);
5407 buf_Release(bufferp);
5411 } /* if (wrong buffer) ... */
5413 /* now we have the right buffer loaded. Copy out the
5414 * data from here to the user's buffer.
5416 bufIndex = offset.LowPart & (buf_bufferSize - 1);
5418 /* and figure out how many bytes we want from this buffer */
5419 nbytes = buf_bufferSize - bufIndex; /* what remains in buffer */
5421 nbytes = count; /* don't go past end of request */
5423 /* now copy the data */
5426 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5429 memcpy(bufferp->datap + bufIndex, op, nbytes);
5430 buf_SetDirty(bufferp);
5432 /* and record the last writer */
5433 if (bufferp->userp != userp) {
5436 cm_ReleaseUser(bufferp->userp);
5437 bufferp->userp = userp;
5440 /* adjust counters, pointers, etc. */
5444 thyper.LowPart = nbytes;
5445 thyper.HighPart = 0;
5446 offset = LargeIntegerAdd(thyper, offset);
5450 lock_ReleaseMutex(&scp->mx);
5451 lock_ReleaseMutex(&fidp->mx);
5453 lock_ReleaseMutex(&bufferp->mx);
5454 buf_Release(bufferp);
5457 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5458 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5459 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5460 fidp->NTopen_dscp, fidp->NTopen_pathp,
5464 if (code == 0 && doWriteBack) {
5466 lock_ObtainMutex(&scp->mx);
5467 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5469 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5470 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5472 lock_ReleaseMutex(&scp->mx);
5473 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5474 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5477 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5478 fidp->fid, code, *writtenp);
5482 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5485 long count, written = 0, total_written = 0;
5490 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5492 int inDataBlockCount;
5494 fd = smb_GetSMBParm(inp, 0);
5495 count = smb_GetSMBParm(inp, 1);
5496 offset.HighPart = 0; /* too bad */
5497 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5499 op = smb_GetSMBData(inp, NULL);
5500 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5502 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5503 fd, offset.LowPart, count);
5505 fd = smb_ChainFID(fd, inp);
5506 fidp = smb_FindFID(vcp, fd, 0);
5508 return CM_ERROR_BADFD;
5511 if (fidp->flags & SMB_FID_IOCTL)
5512 return smb_IoctlWrite(fidp, vcp, inp, outp);
5514 userp = smb_GetUser(vcp, inp);
5516 /* special case: 0 bytes transferred means truncate to this position */
5522 truncAttr.mask = CM_ATTRMASK_LENGTH;
5523 truncAttr.length.LowPart = offset.LowPart;
5524 truncAttr.length.HighPart = 0;
5525 lock_ObtainMutex(&fidp->mx);
5526 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5527 lock_ReleaseMutex(&fidp->mx);
5528 smb_SetSMBParm(outp, 0, /* count */ 0);
5529 smb_SetSMBDataLength(outp, 0);
5530 fidp->flags |= SMB_FID_LENGTHSETDONE;
5535 * Work around bug in NT client
5537 * When copying a file, the NT client should first copy the data,
5538 * then copy the last write time. But sometimes the NT client does
5539 * these in the wrong order, so the data copies would inadvertently
5540 * cause the last write time to be overwritten. We try to detect this,
5541 * and don't set client mod time if we think that would go against the
5544 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5545 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5546 fidp->scp->clientModTime = time(NULL);
5550 while ( code == 0 && count > 0 ) {
5552 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5554 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5556 if (code == 0 && written == 0)
5557 code = CM_ERROR_PARTIALWRITE;
5559 offset.LowPart += written;
5561 total_written += written;
5565 /* set the packet data length to 3 bytes for the data block header,
5566 * plus the size of the data.
5568 smb_SetSMBParm(outp, 0, total_written);
5569 smb_SetSMBDataLength(outp, 0);
5572 smb_ReleaseFID(fidp);
5573 cm_ReleaseUser(userp);
5578 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5579 NCB *ncbp, raw_write_cont_t *rwcp)
5592 fd = smb_GetSMBParm(inp, 0);
5593 fidp = smb_FindFID(vcp, fd, 0);
5595 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5596 rwcp->offset.LowPart, rwcp->count);
5598 userp = smb_GetUser(vcp, inp);
5602 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5605 rawBuf = (dos_ptr) rwcp->buf;
5606 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5607 (unsigned char *) rawBuf, userp,
5611 if (rwcp->writeMode & 0x1) { /* synchronous */
5614 smb_FormatResponsePacket(vcp, inp, outp);
5615 op = (smb_t *) outp;
5616 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5617 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5618 smb_SetSMBDataLength(outp, 0);
5619 smb_SendPacket(vcp, outp);
5620 smb_FreePacket(outp);
5622 else { /* asynchronous */
5623 lock_ObtainMutex(&fidp->mx);
5624 fidp->raw_writers--;
5625 if (fidp->raw_writers == 0)
5626 thrd_SetEvent(fidp->raw_write_event);
5627 lock_ReleaseMutex(&fidp->mx);
5630 /* Give back raw buffer */
5631 lock_ObtainMutex(&smb_RawBufLock);
5633 *((char **)rawBuf) = smb_RawBufs;
5635 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5637 smb_RawBufs = rawBuf;
5638 lock_ReleaseMutex(&smb_RawBufLock);
5640 smb_ReleaseFID(fidp);
5641 cm_ReleaseUser(userp);
5644 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5649 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5652 long count, written = 0, total_written = 0;
5659 unsigned short writeMode;
5666 fd = smb_GetSMBParm(inp, 0);
5667 totalCount = smb_GetSMBParm(inp, 1);
5668 count = smb_GetSMBParm(inp, 10);
5669 offset.HighPart = 0; /* too bad */
5670 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5671 writeMode = smb_GetSMBParm(inp, 7);
5673 op = (char *) inp->data;
5674 op += smb_GetSMBParm(inp, 11);
5677 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5678 fd, offset.LowPart, count, writeMode);
5680 fd = smb_ChainFID(fd, inp);
5681 fidp = smb_FindFID(vcp, fd, 0);
5683 return CM_ERROR_BADFD;
5686 userp = smb_GetUser(vcp, inp);
5689 * Work around bug in NT client
5691 * When copying a file, the NT client should first copy the data,
5692 * then copy the last write time. But sometimes the NT client does
5693 * these in the wrong order, so the data copies would inadvertently
5694 * cause the last write time to be overwritten. We try to detect this,
5695 * and don't set client mod time if we think that would go against the
5698 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5699 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5700 fidp->scp->clientModTime = time(NULL);
5704 while ( code == 0 && count > 0 ) {
5706 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5708 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5710 if (code == 0 && written == 0)
5711 code = CM_ERROR_PARTIALWRITE;
5713 offset.LowPart += written;
5715 total_written += written;
5719 /* Get a raw buffer */
5722 lock_ObtainMutex(&smb_RawBufLock);
5724 /* Get a raw buf, from head of list */
5725 rawBuf = smb_RawBufs;
5727 smb_RawBufs = *(char **)smb_RawBufs;
5729 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5733 code = CM_ERROR_USESTD;
5735 lock_ReleaseMutex(&smb_RawBufLock);
5738 /* Don't allow a premature Close */
5739 if (code == 0 && (writeMode & 1) == 0) {
5740 lock_ObtainMutex(&fidp->mx);
5741 fidp->raw_writers++;
5742 thrd_ResetEvent(fidp->raw_write_event);
5743 lock_ReleaseMutex(&fidp->mx);
5746 smb_ReleaseFID(fidp);
5747 cm_ReleaseUser(userp);
5750 smb_SetSMBParm(outp, 0, total_written);
5751 smb_SetSMBDataLength(outp, 0);
5752 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5759 rwcp->offset.HighPart = 0;
5760 rwcp->offset.LowPart = offset.LowPart + count;
5761 rwcp->count = totalCount - count;
5762 rwcp->writeMode = writeMode;
5763 rwcp->alreadyWritten = total_written;
5765 /* set the packet data length to 3 bytes for the data block header,
5766 * plus the size of the data.
5768 smb_SetSMBParm(outp, 0, 0xffff);
5769 smb_SetSMBDataLength(outp, 0);
5774 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5777 long count, finalCount;
5784 fd = smb_GetSMBParm(inp, 0);
5785 count = smb_GetSMBParm(inp, 1);
5786 offset.HighPart = 0; /* too bad */
5787 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5789 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5790 fd, offset.LowPart, count);
5792 fd = smb_ChainFID(fd, inp);
5793 fidp = smb_FindFID(vcp, fd, 0);
5795 return CM_ERROR_BADFD;
5798 if (fidp->flags & SMB_FID_IOCTL) {
5799 return smb_IoctlRead(fidp, vcp, inp, outp);
5802 userp = smb_GetUser(vcp, inp);
5804 /* remember this for final results */
5805 smb_SetSMBParm(outp, 0, count);
5806 smb_SetSMBParm(outp, 1, 0);
5807 smb_SetSMBParm(outp, 2, 0);
5808 smb_SetSMBParm(outp, 3, 0);
5809 smb_SetSMBParm(outp, 4, 0);
5811 /* set the packet data length to 3 bytes for the data block header,
5812 * plus the size of the data.
5814 smb_SetSMBDataLength(outp, count+3);
5816 /* get op ptr after putting in the parms, since otherwise we don't
5817 * know where the data really is.
5819 op = smb_GetSMBData(outp, NULL);
5821 /* now emit the data block header: 1 byte of type and 2 bytes of length */
5822 *op++ = 1; /* data block marker */
5823 *op++ = (unsigned char) (count & 0xff);
5824 *op++ = (unsigned char) ((count >> 8) & 0xff);
5827 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5829 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5832 /* fix some things up */
5833 smb_SetSMBParm(outp, 0, finalCount);
5834 smb_SetSMBDataLength(outp, finalCount+3);
5836 smb_ReleaseFID(fidp);
5838 cm_ReleaseUser(userp);
5842 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5849 cm_scache_t *dscp; /* dir we're dealing with */
5850 cm_scache_t *scp; /* file we're creating */
5852 int initialModeBits;
5862 /* compute initial mode bits based on read-only flag in attributes */
5863 initialModeBits = 0777;
5865 tp = smb_GetSMBData(inp, NULL);
5866 pathp = smb_ParseASCIIBlock(tp, &tp);
5867 if (smb_StoreAnsiFilenames)
5868 OemToChar(pathp,pathp);
5870 if (strcmp(pathp, "\\") == 0)
5871 return CM_ERROR_EXISTS;
5873 spacep = inp->spacep;
5874 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5876 userp = smb_GetUser(vcp, inp);
5878 caseFold = CM_FLAG_CASEFOLD;
5880 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5882 cm_ReleaseUser(userp);
5883 return CM_ERROR_NOSUCHPATH;
5886 code = cm_NameI(cm_rootSCachep, spacep->data,
5887 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5888 userp, tidPathp, &req, &dscp);
5891 cm_ReleaseUser(userp);
5895 /* otherwise, scp points to the parent directory. Do a lookup, and
5896 * fail if we find it. Otherwise, we do the create.
5902 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
5903 if (scp) cm_ReleaseSCache(scp);
5904 if (code != CM_ERROR_NOSUCHFILE) {
5905 if (code == 0) code = CM_ERROR_EXISTS;
5906 cm_ReleaseSCache(dscp);
5907 cm_ReleaseUser(userp);
5911 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5912 setAttr.clientModTime = time(NULL);
5913 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5914 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5915 smb_NotifyChange(FILE_ACTION_ADDED,
5916 FILE_NOTIFY_CHANGE_DIR_NAME,
5917 dscp, lastNamep, NULL, TRUE);
5919 /* we don't need this any longer */
5920 cm_ReleaseSCache(dscp);
5923 /* something went wrong creating or truncating the file */
5924 cm_ReleaseUser(userp);
5928 /* otherwise we succeeded */
5929 smb_SetSMBDataLength(outp, 0);
5930 cm_ReleaseUser(userp);
5935 BOOL smb_IsLegalFilename(char *filename)
5938 * Find the longest substring of filename that does not contain
5939 * any of the chars in illegalChars. If that substring is less
5940 * than the length of the whole string, then one or more of the
5941 * illegal chars is in filename.
5943 if (strcspn(filename, illegalChars) < strlen(filename))
5949 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5957 cm_scache_t *dscp; /* dir we're dealing with */
5958 cm_scache_t *scp; /* file we're creating */
5960 int initialModeBits;
5972 excl = (inp->inCom == 0x03)? 0 : 1;
5974 attributes = smb_GetSMBParm(inp, 0);
5975 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5977 /* compute initial mode bits based on read-only flag in attributes */
5978 initialModeBits = 0666;
5979 if (attributes & 1) initialModeBits &= ~0222;
5981 tp = smb_GetSMBData(inp, NULL);
5982 pathp = smb_ParseASCIIBlock(tp, &tp);
5983 if (smb_StoreAnsiFilenames)
5984 OemToChar(pathp,pathp);
5986 spacep = inp->spacep;
5987 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5989 userp = smb_GetUser(vcp, inp);
5991 caseFold = CM_FLAG_CASEFOLD;
5993 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5995 cm_ReleaseUser(userp);
5996 return CM_ERROR_NOSUCHPATH;
5998 code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5999 userp, tidPathp, &req, &dscp);
6002 cm_ReleaseUser(userp);
6006 /* otherwise, scp points to the parent directory. Do a lookup, and
6007 * truncate the file if we find it, otherwise we create the file.
6014 if (!smb_IsLegalFilename(lastNamep))
6015 return CM_ERROR_BADNTFILENAME;
6017 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6018 #ifdef DEBUG_VERBOSE
6021 hexp = osi_HexifyString( lastNamep );
6022 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6027 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6028 if (code && code != CM_ERROR_NOSUCHFILE) {
6029 cm_ReleaseSCache(dscp);
6030 cm_ReleaseUser(userp);
6034 /* if we get here, if code is 0, the file exists and is represented by
6035 * scp. Otherwise, we have to create it.
6039 /* oops, file shouldn't be there */
6040 cm_ReleaseSCache(dscp);
6041 cm_ReleaseSCache(scp);
6042 cm_ReleaseUser(userp);
6043 return CM_ERROR_EXISTS;
6046 setAttr.mask = CM_ATTRMASK_LENGTH;
6047 setAttr.length.LowPart = 0;
6048 setAttr.length.HighPart = 0;
6049 code = cm_SetAttr(scp, &setAttr, userp, &req);
6052 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6053 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6054 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6056 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6057 smb_NotifyChange(FILE_ACTION_ADDED,
6058 FILE_NOTIFY_CHANGE_FILE_NAME,
6059 dscp, lastNamep, NULL, TRUE);
6060 if (!excl && code == CM_ERROR_EXISTS) {
6061 /* not an exclusive create, and someone else tried
6062 * creating it already, then we open it anyway. We
6063 * don't bother retrying after this, since if this next
6064 * fails, that means that the file was deleted after
6065 * we started this call.
6067 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6070 setAttr.mask = CM_ATTRMASK_LENGTH;
6071 setAttr.length.LowPart = 0;
6072 setAttr.length.HighPart = 0;
6073 code = cm_SetAttr(scp, &setAttr, userp, &req);
6078 /* we don't need this any longer */
6079 cm_ReleaseSCache(dscp);
6082 /* something went wrong creating or truncating the file */
6083 if (scp) cm_ReleaseSCache(scp);
6084 cm_ReleaseUser(userp);
6088 /* make sure we only open files */
6089 if (scp->fileType != CM_SCACHETYPE_FILE) {
6090 cm_ReleaseSCache(scp);
6091 cm_ReleaseUser(userp);
6092 return CM_ERROR_ISDIR;
6095 /* now all we have to do is open the file itself */
6096 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6099 /* save a pointer to the vnode */
6102 /* always create it open for read/write */
6103 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6105 smb_ReleaseFID(fidp);
6107 smb_SetSMBParm(outp, 0, fidp->fid);
6108 smb_SetSMBDataLength(outp, 0);
6110 cm_Open(scp, 0, userp);
6112 cm_ReleaseUser(userp);
6113 /* leave scp held since we put it in fidp->scp */
6117 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6130 fd = smb_GetSMBParm(inp, 0);
6131 whence = smb_GetSMBParm(inp, 1);
6132 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6134 /* try to find the file descriptor */
6135 fd = smb_ChainFID(fd, inp);
6136 fidp = smb_FindFID(vcp, fd, 0);
6137 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6138 return CM_ERROR_BADFD;
6141 userp = smb_GetUser(vcp, inp);
6143 lock_ObtainMutex(&fidp->mx);
6145 lock_ObtainMutex(&scp->mx);
6146 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6147 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6150 /* offset from current offset */
6151 offset += fidp->offset;
6153 else if (whence == 2) {
6154 /* offset from current EOF */
6155 offset += scp->length.LowPart;
6157 fidp->offset = offset;
6158 smb_SetSMBParm(outp, 0, offset & 0xffff);
6159 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6160 smb_SetSMBDataLength(outp, 0);
6162 lock_ReleaseMutex(&scp->mx);
6163 lock_ReleaseMutex(&fidp->mx);
6164 smb_ReleaseFID(fidp);
6165 cm_ReleaseUser(userp);
6169 /* dispatch all of the requests received in a packet. Due to chaining, this may
6170 * be more than one request.
6172 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6173 NCB *ncbp, raw_write_cont_t *rwcp)
6177 unsigned long code = 0;
6178 unsigned char *outWctp;
6179 int nparms; /* # of bytes of parameters */
6181 int nbytes; /* bytes of data, excluding count */
6184 unsigned short errCode;
6185 unsigned long NTStatus;
6187 unsigned char errClass;
6188 unsigned int oldGen;
6189 DWORD oldTime, newTime;
6191 /* get easy pointer to the data */
6192 smbp = (smb_t *) inp->data;
6194 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6195 /* setup the basic parms for the initial request in the packet */
6196 inp->inCom = smbp->com;
6197 inp->wctp = &smbp->wct;
6199 inp->ncb_length = ncbp->ncb_length;
6204 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6205 /* log it and discard it */
6210 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6211 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6213 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6214 1, ncbp->ncb_length, ptbuf, inp);
6215 DeregisterEventSource(h);
6217 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6222 /* We are an ongoing op */
6223 thrd_Increment(&ongoingOps);
6225 /* set up response packet for receiving output */
6226 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6227 smb_FormatResponsePacket(vcp, inp, outp);
6228 outWctp = outp->wctp;
6230 /* Remember session generation number and time */
6231 oldGen = sessionGen;
6232 oldTime = GetCurrentTime();
6234 while (inp->inCom != 0xff) {
6235 dp = &smb_dispatchTable[inp->inCom];
6237 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6238 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6239 code = outp->resumeCode;
6243 /* process each request in the packet; inCom, wctp and inCount
6244 * are already set up.
6246 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6249 /* now do the dispatch */
6250 /* start by formatting the response record a little, as a default */
6251 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6253 outWctp[1] = 0xff; /* no operation */
6254 outWctp[2] = 0; /* padding */
6259 /* not a chained request, this is a more reasonable default */
6260 outWctp[0] = 0; /* wct of zero */
6261 outWctp[1] = 0; /* and bcc (word) of zero */
6265 /* once set, stays set. Doesn't matter, since we never chain
6266 * "no response" calls.
6268 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6272 /* we have a recognized operation */
6274 if (inp->inCom == 0x1d)
6276 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6279 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
6280 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
6281 code = (*(dp->procp)) (vcp, inp, outp);
6282 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6283 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6285 if ( code == CM_ERROR_BADSMB ||
6286 code == CM_ERROR_BADOP )
6288 #endif /* LOG_PACKET */
6291 if (oldGen != sessionGen) {
6296 newTime = GetCurrentTime();
6297 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6298 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6299 newTime - oldTime, ncbp->ncb_length);
6301 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6302 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6303 DeregisterEventSource(h);
6305 osi_Log1(smb_logp, "Pkt straddled session startup, "
6306 "ncb length %d", ncbp->ncb_length);
6310 /* bad opcode, fail the request, after displaying it */
6311 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6314 #endif /* LOG_PACKET */
6318 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6319 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6320 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6321 if (code == IDCANCEL)
6325 code = CM_ERROR_BADOP;
6328 /* catastrophic failure: log as much as possible */
6329 if (code == CM_ERROR_BADSMB) {
6336 "Invalid SMB, ncb_length %d",
6339 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6340 sprintf(s, "Invalid SMB message, length %d",
6343 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6344 1, ncbp->ncb_length, ptbuf, smbp);
6345 DeregisterEventSource(h);
6348 #endif /* LOG_PACKET */
6350 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6353 code = CM_ERROR_INVAL;
6356 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6357 thrd_Decrement(&ongoingOps);
6362 /* now, if we failed, turn the current response into an empty
6363 * one, and fill in the response packet's error code.
6366 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6367 smb_MapNTError(code, &NTStatus);
6368 outWctp = outp->wctp;
6369 smbp = (smb_t *) &outp->data;
6370 if (code != CM_ERROR_PARTIALWRITE
6371 && code != CM_ERROR_BUFFERTOOSMALL
6372 && code != CM_ERROR_GSSCONTINUE) {
6373 /* nuke wct and bcc. For a partial
6374 * write or an in-process authentication handshake,
6375 * assume they're OK.
6381 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6382 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6383 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6384 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6385 smbp->flg2 |= 0x4000;
6389 smb_MapCoreError(code, vcp, &errCode, &errClass);
6390 outWctp = outp->wctp;
6391 smbp = (smb_t *) &outp->data;
6392 if (code != CM_ERROR_PARTIALWRITE) {
6393 /* nuke wct and bcc. For a partial
6394 * write, assume they're OK.
6400 smbp->errLow = (unsigned char) (errCode & 0xff);
6401 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6402 smbp->rcls = errClass;
6405 } /* error occurred */
6407 /* if we're here, we've finished one request. Look to see if
6408 * this is a chained opcode. If it is, setup things to process
6409 * the chained request, and setup the output buffer to hold the
6410 * chained response. Start by finding the next input record.
6412 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6413 break; /* not a chained req */
6414 tp = inp->wctp; /* points to start of last request */
6415 /* in a chained request, the first two
6416 * parm fields are required, and are
6417 * AndXCommand/AndXReserved and
6419 if (tp[0] < 2) break;
6420 if (tp[1] == 0xff) break; /* no more chained opcodes */
6422 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6425 /* and now append the next output request to the end of this
6426 * last request. Begin by finding out where the last response
6427 * ends, since that's where we'll put our new response.
6429 outWctp = outp->wctp; /* ptr to out parameters */
6430 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6431 nparms = outWctp[0] << 1;
6432 tp = outWctp + nparms + 1; /* now points to bcc field */
6433 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6434 tp += 2 /* for the count itself */ + nbytes;
6435 /* tp now points to the new output record; go back and patch the
6436 * second parameter (off2) to point to the new record.
6438 temp = (unsigned int)tp - ((unsigned int) outp->data);
6439 outWctp[3] = (unsigned char) (temp & 0xff);
6440 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6441 outWctp[2] = 0; /* padding */
6442 outWctp[1] = inp->inCom; /* next opcode */
6444 /* finally, setup for the next iteration */
6447 } /* while loop over all requests in the packet */
6449 /* done logging out, turn off logging-out flag */
6450 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6451 vcp->justLoggedOut = NULL;
6454 free(loggedOutName);
6455 loggedOutName = NULL;
6456 smb_ReleaseUID(loggedOutUserp);
6457 loggedOutUserp = NULL;
6461 /* now send the output packet, and return */
6463 smb_SendPacket(vcp, outp);
6464 thrd_Decrement(&ongoingOps);
6466 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6468 smb_ReleaseVC(active_vcp);
6470 "Replacing active_vcp %x with %x", active_vcp, vcp);
6474 last_msg_time = GetCurrentTime();
6476 else if (active_vcp == vcp) {
6477 smb_ReleaseVC(active_vcp);
6485 /* Wait for Netbios() calls to return, and make the results available to server
6486 * threads. Note that server threads can't wait on the NCBevents array
6487 * themselves, because NCB events are manual-reset, and the servers would race
6488 * each other to reset them.
6490 void smb_ClientWaiter(void *parmp)
6496 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6498 if (code == WAIT_OBJECT_0) {
6499 if (smbShutdownFlag == 1)
6505 /* error checking */
6506 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6508 int abandonIdx = code - WAIT_ABANDONED_0;
6509 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6512 if (code == WAIT_IO_COMPLETION)
6514 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6518 if (code == WAIT_TIMEOUT)
6520 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6523 if (code == WAIT_FAILED)
6525 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6528 idx = code - WAIT_OBJECT_0;
6530 /* check idx range! */
6531 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6533 /* this is fatal - log as much as possible */
6534 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6538 thrd_ResetEvent(NCBevents[idx]);
6539 thrd_SetEvent(NCBreturns[0][idx]);
6545 * Try to have one NCBRECV request waiting for every live session. Not more
6546 * than one, because if there is more than one, it's hard to handle Write Raw.
6548 void smb_ServerWaiter(void *parmp)
6551 int idx_session, idx_NCB;
6559 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6561 if (code == WAIT_OBJECT_0) {
6562 if ( smbShutdownFlag == 1 )
6568 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6570 int abandonIdx = code - WAIT_ABANDONED_0;
6571 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6574 if (code == WAIT_IO_COMPLETION)
6576 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6580 if (code == WAIT_TIMEOUT)
6582 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6585 if (code == WAIT_FAILED)
6587 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6590 idx_session = code - WAIT_OBJECT_0;
6592 /* check idx range! */
6593 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6595 /* this is fatal - log as much as possible */
6596 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6602 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6604 if (code == WAIT_OBJECT_0) {
6605 if ( smbShutdownFlag == 1 )
6611 /* error checking */
6612 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6614 int abandonIdx = code - WAIT_ABANDONED_0;
6615 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6618 if (code == WAIT_IO_COMPLETION)
6620 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6624 if (code == WAIT_TIMEOUT)
6626 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6629 if (code == WAIT_FAILED)
6631 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6634 idx_NCB = code - WAIT_OBJECT_0;
6636 /* check idx range! */
6637 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6639 /* this is fatal - log as much as possible */
6640 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6644 /* Link them together */
6645 NCBsessions[idx_NCB] = idx_session;
6648 ncbp = NCBs[idx_NCB];
6649 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6650 ncbp->ncb_command = NCBRECV | ASYNCH;
6651 ncbp->ncb_lana_num = lanas[idx_session];
6653 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6654 ncbp->ncb_event = NCBevents[idx_NCB];
6655 ncbp->ncb_length = SMB_PACKETSIZE;
6658 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6659 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6660 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6661 ncbp->ncb_length = SMB_PACKETSIZE;
6662 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6663 Netbios(ncbp, dos_ncb);
6669 * The top level loop for handling SMB request messages. Each server thread
6670 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6671 * NCB and buffer for the incoming request are loaned to us.
6673 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6674 * to immediately send a request for the rest of the data. This must come
6675 * before any other traffic for that session, so we delay setting the session
6676 * event until that data has come in.
6678 void smb_Server(VOID *parmp)
6680 int myIdx = (int) parmp;
6684 smb_packet_t *outbufp;
6686 int idx_NCB, idx_session;
6688 smb_vc_t *vcp = NULL;
6695 outbufp = GetPacket();
6696 outbufp->ncbp = outncbp;
6699 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6702 /* terminate silently if shutdown flag is set */
6703 if (code == WAIT_OBJECT_0) {
6704 if (smbShutdownFlag == 1) {
6705 thrd_SetEvent(smb_ServerShutdown[myIdx]);
6711 /* error checking */
6712 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6714 int abandonIdx = code - WAIT_ABANDONED_0;
6715 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6718 if (code == WAIT_IO_COMPLETION)
6720 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6724 if (code == WAIT_TIMEOUT)
6726 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6729 if (code == WAIT_FAILED)
6731 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6734 idx_NCB = code - WAIT_OBJECT_0;
6736 /* check idx range! */
6737 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6739 /* this is fatal - log as much as possible */
6740 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6744 ncbp = NCBs[idx_NCB];
6746 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6748 idx_session = NCBsessions[idx_NCB];
6749 rc = ncbp->ncb_retcode;
6751 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6752 osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6755 case NRC_GOODRET: break;
6758 /* Can this happen? Or is it just my
6765 /* Client closed session */
6766 if (reportSessionStartups)
6768 osi_Log1(smb_logp, "session [ %d ] closed", idx_session);
6770 dead_sessions[idx_session] = TRUE;
6773 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6774 /* Should also release vcp. [done] 2004-05-11 jaltman
6776 * sanity check that all TID's are gone.
6778 * TODO: check if we could use LSNs[idx_session] instead,
6779 * also cleanup after dead vcp
6784 "dead_vcp already set, %x",
6786 if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6788 "setting dead_vcp %x, user struct %x",
6792 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6794 if (vcp->justLoggedOut) {
6796 loggedOutTime = vcp->logoffTime;
6797 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
6798 loggedOutUserp = vcp->justLoggedOut;
6799 lock_ObtainWrite(&smb_rctLock);
6800 loggedOutUserp->refCount++;
6801 lock_ReleaseWrite(&smb_rctLock);
6807 /* Treat as transient error */
6814 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6815 sprintf(s, "SMB message incomplete, length %d",
6818 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6820 ncbp->ncb_length, ptbuf,
6822 DeregisterEventSource(h);
6825 "dispatch smb recv failed, message incomplete, ncb_length %d",
6828 "SMB message incomplete, "
6829 "length %d", ncbp->ncb_length);
6832 * We used to discard the packet.
6833 * Instead, try handling it normally.
6841 /* A weird error code. Log it, sleep, and
6843 if (vcp && vcp->errorCount++ > 3) {
6844 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6845 dead_sessions[idx_session] = TRUE;
6849 thrd_SetEvent(SessionEvents[idx_session]);
6854 /* Success, so now dispatch on all the data in the packet */
6856 smb_concurrentCalls++;
6857 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6858 smb_maxObsConcurrentCalls = smb_concurrentCalls;
6862 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6864 * If at this point vcp is NULL (implies that packet was invalid)
6865 * then we are in big trouble. This means either :
6866 * a) we have the wrong NCB.
6867 * b) Netbios screwed up the call.
6868 * Obviously this implies that
6869 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
6870 * lanas[idx_session] != ncbp->ncb_lana_num )
6871 * Either way, we can't do anything with this packet.
6872 * Log, sleep and resume.
6881 "LSNs[idx_session]=[%d],"
6882 "lanas[idx_session]=[%d],"
6883 "ncbp->ncb_lsn=[%d],"
6884 "ncbp->ncb_lana_num=[%d]",
6888 ncbp->ncb_lana_num);
6892 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6894 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6895 DeregisterEventSource(h);
6898 /* Also log in the trace log. */
6899 osi_Log4(smb_logp, "Server: BAD VCP!"
6900 "LSNs[idx_session]=[%d],"
6901 "lanas[idx_session]=[%d],"
6902 "ncbp->ncb_lsn=[%d],"
6903 "ncbp->ncb_lana_num=[%d]",
6907 ncbp->ncb_lana_num);
6909 /* thrd_Sleep(1000); Don't bother sleeping */
6910 thrd_SetEvent(SessionEvents[idx_session]);
6911 smb_concurrentCalls--;
6916 vcp->errorCount = 0;
6917 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6919 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6920 /* copy whole packet to virtual memory */
6921 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6923 bufp->dos_pkt / 16, bufp);*/
6925 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6927 smbp = (smb_t *)bufp->data;
6930 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6934 if (smbp->com == 0x1d) {
6935 /* Special handling for Write Raw */
6936 raw_write_cont_t rwc;
6937 EVENT_HANDLE rwevent;
6938 char eventName[MAX_PATH];
6940 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6941 if (rwc.code == 0) {
6942 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6943 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6944 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
6945 ncbp->ncb_command = NCBRECV | ASYNCH;
6946 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6947 ncbp->ncb_lana_num = vcp->lana;
6948 ncbp->ncb_buffer = rwc.buf;
6949 ncbp->ncb_length = 65535;
6950 ncbp->ncb_event = rwevent;
6954 Netbios(ncbp, dos_ncb);
6956 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6957 thrd_CloseHandle(rwevent);
6959 thrd_SetEvent(SessionEvents[idx_session]);
6961 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6963 else if (smbp->com == 0xa0) {
6965 * Serialize the handling for NT Transact
6968 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6969 thrd_SetEvent(SessionEvents[idx_session]);
6971 thrd_SetEvent(SessionEvents[idx_session]);
6972 /* TODO: what else needs to be serialized? */
6973 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6975 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6977 __except( smb_ServerExceptionFilter() ) {
6981 smb_concurrentCalls--;
6984 thrd_SetEvent(NCBavails[idx_NCB]);
6991 * Exception filter for the server threads. If an exception occurs in the
6992 * dispatch routines, which is where exceptions are most common, then do a
6993 * force trace and give control to upstream exception handlers. Useful for
6996 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6997 DWORD smb_ServerExceptionFilter(void) {
6998 /* While this is not the best time to do a trace, if it succeeds, then
6999 * we have a trace (assuming tracing was enabled). Otherwise, this should
7000 * throw a second exception.
7005 ptbuf[0] = "Unhandled exception forcing trace";
7007 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7009 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7010 DeregisterEventSource(h);
7013 afsd_ForceTrace(TRUE);
7014 buf_ForceTrace(TRUE);
7015 return EXCEPTION_CONTINUE_SEARCH;
7020 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7021 * If the number of server threads is M, and the number of live sessions is
7022 * N, then the number of NCB's in use at any time either waiting for, or
7023 * holding, received messages is M + N, so that is how many NCB's get created.
7025 void InitNCBslot(int idx)
7027 struct smb_packet *bufp;
7028 EVENT_HANDLE retHandle;
7030 char eventName[MAX_PATH];
7032 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7034 NCBs[idx] = GetNCB();
7035 sprintf(eventName,"NCBavails[%d]", idx);
7036 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7037 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7038 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7040 sprintf(eventName,"NCBevents[%d]", idx);
7041 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7042 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7043 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7045 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7046 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7047 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7048 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7049 for (i=0; i<smb_NumServerThreads; i++)
7050 NCBreturns[i][idx] = retHandle;
7052 bufp->spacep = cm_GetSpace();
7056 /* listen for new connections */
7057 void smb_Listener(void *parmp)
7065 char rname[NCBNAMSZ+1];
7066 char cname[MAX_COMPUTERNAME_LENGTH+1];
7067 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7072 int lana = (int) parmp;
7076 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7079 /* retrieve computer name */
7080 GetComputerName(cname, &cnamelen);
7084 memset(ncbp, 0, sizeof(NCB));
7087 ncbp->ncb_command = NCBLISTEN;
7088 ncbp->ncb_rto = 0; /* No receive timeout */
7089 ncbp->ncb_sto = 0; /* No send timeout */
7091 /* pad out with spaces instead of null termination */
7092 len = strlen(smb_localNamep);
7093 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7094 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7096 strcpy(ncbp->ncb_callname, "*");
7097 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7099 ncbp->ncb_lana_num = lana;
7102 code = Netbios(ncbp);
7104 code = Netbios(ncbp, dos_ncb);
7113 /* terminate silently if shutdown flag is set */
7114 if (smbShutdownFlag == 1) {
7123 "NCBLISTEN lana=%d failed with code %d",
7124 ncbp->ncb_lana_num, code);
7126 "Client exiting due to network failure. Please restart client.\n");
7130 "Client exiting due to network failure. Please restart client.\n"
7131 "NCBLISTEN lana=%d failed with code %d",
7132 ncbp->ncb_lana_num, code);
7134 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7135 MB_OK|MB_SERVICE_NOTIFICATION);
7136 osi_assert(tbuffer);
7139 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7140 ncbp->ncb_lana_num, code);
7141 fprintf(stderr, "\nClient exiting due to network failure "
7142 "(possibly due to power-saving mode)\n");
7143 fprintf(stderr, "Please restart client.\n");
7144 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7148 /* check for remote conns */
7149 /* first get remote name and insert null terminator */
7150 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7151 for (i=NCBNAMSZ; i>0; i--) {
7152 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7158 /* compare with local name */
7160 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7161 flags |= SMB_VCFLAG_REMOTECONN;
7163 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7165 lock_ObtainMutex(&smb_ListenerLock);
7167 /* New generation */
7170 /* Log session startup */
7172 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7174 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7175 #endif /* NOTSERVICE */
7176 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7177 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7179 if (reportSessionStartups) {
7185 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7186 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7188 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7190 DeregisterEventSource(h);
7193 fprintf(stderr, "%s: New session %d starting from host %s\n",
7194 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7198 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7199 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7202 /* now ncbp->ncb_lsn is the connection ID */
7203 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7204 vcp->flags |= flags;
7205 strcpy(vcp->rname, rname);
7207 /* Allocate slot in session arrays */
7208 /* Re-use dead session if possible, otherwise add one more */
7209 /* But don't look at session[0], it is reserved */
7210 for (i = 1; i < numSessions; i++) {
7211 if (dead_sessions[i]) {
7212 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7213 dead_sessions[i] = FALSE;
7218 /* assert that we do not exceed the maximum number of sessions or NCBs.
7219 * we should probably want to wait for a session to be freed in case
7223 osi_assert(i < Sessionmax - 1);
7224 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7226 LSNs[i] = ncbp->ncb_lsn;
7227 lanas[i] = ncbp->ncb_lana_num;
7229 if (i == numSessions) {
7230 /* Add new NCB for new session */
7231 char eventName[MAX_PATH];
7233 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7235 InitNCBslot(numNCBs);
7237 thrd_SetEvent(NCBavails[0]);
7238 thrd_SetEvent(NCBevents[0]);
7239 for (j = 0; j < smb_NumServerThreads; j++)
7240 thrd_SetEvent(NCBreturns[j][0]);
7241 /* Also add new session event */
7242 sprintf(eventName, "SessionEvents[%d]", i);
7243 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7244 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7245 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7247 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7248 thrd_SetEvent(SessionEvents[0]);
7250 thrd_SetEvent(SessionEvents[i]);
7253 lock_ReleaseMutex(&smb_ListenerLock);
7255 } /* dispatch while loop */
7258 /* initialize Netbios */
7259 void smb_NetbiosInit()
7265 int i, lana, code, l;
7267 int delname_tried=0;
7270 OSVERSIONINFO Version;
7272 /* AFAIK, this is the default for the ms loopback adapter.*/
7273 unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
7274 /*******************************************************************/
7276 /* Get the version of Windows */
7277 memset(&Version, 0x00, sizeof(Version));
7278 Version.dwOSVersionInfoSize = sizeof(Version);
7279 GetVersionEx(&Version);
7281 /* setup the NCB system */
7284 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7288 if (smb_LANadapter == -1) {
7289 ncbp->ncb_command = NCBENUM;
7290 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7291 ncbp->ncb_length = sizeof(lana_list);
7292 code = Netbios(ncbp);
7294 sprintf(s, "Netbios NCBENUM error code %d", code);
7295 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7296 osi_panic(s, __FILE__, __LINE__);
7300 lana_list.length = 1;
7301 lana_list.lana[0] = smb_LANadapter;
7304 for (i = 0; i < lana_list.length; i++) {
7305 /* reset the adaptor: in Win32, this is required for every process, and
7306 * acts as an init call, not as a real hardware reset.
7308 ncbp->ncb_command = NCBRESET;
7309 ncbp->ncb_callname[0] = 100;
7310 ncbp->ncb_callname[2] = 100;
7311 ncbp->ncb_lana_num = lana_list.lana[i];
7312 code = Netbios(ncbp);
7314 code = ncbp->ncb_retcode;
7316 sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7317 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7318 lana_list.lana[i] = 255; /* invalid lana */
7320 sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7321 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7325 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7326 we will just fake the LANA list */
7327 if (smb_LANadapter == -1) {
7328 for (i = 0; i < 8; i++)
7329 lana_list.lana[i] = i;
7330 lana_list.length = 8;
7333 lana_list.length = 1;
7334 lana_list.lana[0] = smb_LANadapter;
7338 /* and declare our name so we can receive connections */
7339 memset(ncbp, 0, sizeof(*ncbp));
7340 len=lstrlen(smb_localNamep);
7341 memset(smb_sharename,' ',NCBNAMSZ);
7342 memcpy(smb_sharename,smb_localNamep,len);
7343 sprintf(s, "lana_list.length %d", lana_list.length);
7344 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7346 /* Keep the name so we can unregister it later */
7347 for (l = 0; l < lana_list.length; l++) {
7348 lana = lana_list.lana[l];
7350 ncbp->ncb_command = NCBADDNAME;
7351 ncbp->ncb_lana_num = lana;
7352 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7354 code = Netbios(ncbp);
7356 code = Netbios(ncbp, dos_ncb);
7359 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7360 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7362 char name[NCBNAMSZ+1];
7364 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7365 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7368 if (code == 0) code = ncbp->ncb_retcode;
7370 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7372 /* we only use one LANA with djgpp */
7373 lana_list.lana[0] = lana;
7374 lana_list.length = 1;
7378 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7379 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7380 if (code == NRC_BRIDGE) { /* invalid LANA num */
7381 lana_list.lana[l] = 255;
7384 else if (code == NRC_DUPNAME) {
7385 osi_Log0(smb_logp, "Name already exists; try to delete it");
7386 memset(ncbp, 0, sizeof(*ncbp));
7387 ncbp->ncb_command = NCBDELNAME;
7388 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7389 ncbp->ncb_lana_num = lana;
7391 code = Netbios(ncbp);
7393 code = Netbios(ncbp, dos_ncb);
7396 code = ncbp->ncb_retcode;
7398 sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7399 osi_Log0(smb_logp, s);
7401 if (code != 0 || delname_tried) {
7402 lana_list.lana[l] = 255;
7404 else if (code == 0) {
7405 if (!delname_tried) {
7413 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7414 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, s));
7415 lana_list.lana[l] = 255; /* invalid lana */
7416 osi_panic(s, __FILE__, __LINE__);
7420 lana_found = 1; /* at least one worked */
7427 osi_assert(lana_list.length >= 0);
7429 sprintf(s, "No valid LANA numbers found!");
7430 osi_panic(s, __FILE__, __LINE__);
7433 /* we're done with the NCB now */
7437 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7454 EVENT_HANDLE retHandle;
7455 char eventName[MAX_PATH];
7458 smb_MBfunc = aMBfunc;
7462 smb_LANadapter = LANadapt;
7464 /* Initialize smb_localZero */
7465 myTime.tm_isdst = -1; /* compute whether on DST or not */
7466 myTime.tm_year = 70;
7472 smb_localZero = mktime(&myTime);
7474 /* Initialize kludge-GMT */
7475 smb_CalculateNowTZ();
7477 #ifdef AFS_FREELANCE_CLIENT
7478 /* Make sure the root.afs volume has the correct time */
7479 cm_noteLocalMountPointChange();
7482 /* initialize the remote debugging log */
7485 /* remember the name */
7486 len = strlen(snamep);
7487 smb_localNamep = malloc(len+1);
7488 strcpy(smb_localNamep, snamep);
7489 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7491 /* and the global lock */
7492 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7493 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7495 /* Raw I/O data structures */
7496 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7498 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7500 /* 4 Raw I/O buffers */
7502 smb_RawBufs = calloc(65536,1);
7503 *((char **)smb_RawBufs) = NULL;
7504 for (i=0; i<3; i++) {
7505 char *rawBuf = calloc(65536,1);
7506 *((char **)rawBuf) = smb_RawBufs;
7507 smb_RawBufs = rawBuf;
7510 npar = 65536 >> 4; /* number of paragraphs */
7511 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7513 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7515 osi_panic("",__FILE__,__LINE__);
7518 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7521 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7523 _farpokel(_dos_ds, smb_RawBufs, NULL);
7524 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7525 npar = 65536 >> 4; /* number of paragraphs */
7526 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7528 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7530 osi_panic("",__FILE__,__LINE__);
7533 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7536 rawBuf = (seg * 16) + 0; /* DOS physical address */
7537 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7538 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7539 smb_RawBufs = rawBuf;
7543 /* global free lists */
7544 smb_ncbFreeListp = NULL;
7545 smb_packetFreeListp = NULL;
7549 /* Initialize listener and server structures */
7551 memset(dead_sessions, 0, sizeof(dead_sessions));
7552 sprintf(eventName, "SessionEvents[0]");
7553 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7554 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7555 afsi_log("Event Object Already Exists: %s", eventName);
7557 smb_NumServerThreads = nThreads;
7558 sprintf(eventName, "NCBavails[0]");
7559 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7560 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7561 afsi_log("Event Object Already Exists: %s", eventName);
7562 sprintf(eventName, "NCBevents[0]");
7563 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7564 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7565 afsi_log("Event Object Already Exists: %s", eventName);
7566 NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
7567 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7568 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7569 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7570 afsi_log("Event Object Already Exists: %s", eventName);
7571 for (i = 0; i < smb_NumServerThreads; i++) {
7572 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7573 NCBreturns[i][0] = retHandle;
7576 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
7577 for (i = 0; i < smb_NumServerThreads; i++) {
7578 sprintf(eventName, "smb_ServerShutdown[%d]", i);
7579 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7580 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7581 afsi_log("Event Object Already Exists: %s", eventName);
7584 for (i = 1; i <= nThreads; i++)
7586 numNCBs = nThreads + 1;
7588 /* Initialize dispatch table */
7589 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7590 /* Prepare the table for unknown operations */
7591 for(i=0; i<= SMB_NOPCODES; i++) {
7592 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7594 /* Fill in the ones we do know */
7595 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7596 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7597 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7598 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7599 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7600 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7601 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7602 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7603 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7604 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7605 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7606 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7607 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7608 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7609 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7610 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7611 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7612 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7613 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7614 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7615 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7616 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7617 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7618 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7619 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7620 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7621 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7622 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7623 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7624 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7625 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7626 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7627 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7628 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7629 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7630 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7631 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7632 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7633 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7634 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7635 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7636 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7637 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7638 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7639 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7640 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7641 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7642 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7643 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7644 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7645 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7646 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7647 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7648 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7649 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7650 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7651 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
7652 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
7653 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
7654 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7655 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7656 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7657 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7658 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7659 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
7660 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
7661 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
7662 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
7663 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
7664 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
7665 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
7666 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
7668 /* setup tran 2 dispatch table */
7669 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7670 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7671 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7672 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7673 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7674 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7675 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7676 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7677 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
7678 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
7679 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
7680 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
7681 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
7682 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
7683 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
7684 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
7685 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
7687 /* setup the rap dispatch table */
7688 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
7689 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
7690 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
7691 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
7692 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
7696 /* if we are doing SMB authentication we have register outselves as a logon process */
7697 if (smb_authType != SMB_AUTH_NONE) {
7699 LSA_STRING afsProcessName;
7700 LSA_OPERATIONAL_MODE dummy; /*junk*/
7702 afsProcessName.Buffer = "OpenAFSClientDaemon";
7703 afsProcessName.Length = strlen(afsProcessName.Buffer);
7704 afsProcessName.MaximumLength = afsProcessName.Length + 1;
7706 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
7708 if (nts == STATUS_SUCCESS) {
7709 LSA_STRING packageName;
7710 /* we are registered. Find out the security package id */
7711 packageName.Buffer = MSV1_0_PACKAGE_NAME;
7712 packageName.Length = strlen(packageName.Buffer);
7713 packageName.MaximumLength = packageName.Length + 1;
7714 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
7715 if (nts == STATUS_SUCCESS) {
7716 smb_lsaLogonOrigin.Buffer = "OpenAFS";
7717 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
7718 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
7720 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
7723 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
7726 if (nts != STATUS_SUCCESS) {
7727 /* something went wrong. We report the error and revert back to no authentication
7728 because we can't perform any auth requests without a successful lsa handle
7729 or sec package id. */
7730 afsi_log("Reverting to NO SMB AUTH");
7731 smb_authType = SMB_AUTH_NONE;
7734 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
7735 * time prevents the failure of authentication when logged into Windows with an
7736 * external Kerberos principal mapped to a local account.
7738 else if ( smb_authType == SMB_AUTH_EXTENDED) {
7739 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
7740 * then the only option is NTLMSSP anyway; so just fallback.
7745 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
7746 if (secBlobLength == 0) {
7747 smb_authType = SMB_AUTH_NTLM;
7748 afsi_log("Reverting to SMB AUTH NTLM");
7757 /* Now get ourselves a domain name. */
7758 /* For now we are using the local computer name as the domain name.
7759 * It is actually the domain for local logins, and we are acting as
7760 * a local SMB server.
7762 bufsize = sizeof(smb_ServerDomainName) - 1;
7763 GetComputerName(smb_ServerDomainName, &bufsize);
7764 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
7765 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
7768 /* Start listeners, waiters, servers, and daemons */
7770 for (i = 0; i < lana_list.length; i++) {
7771 if (lana_list.lana[i] == 255) continue;
7772 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
7773 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
7774 osi_assert(phandle != NULL);
7775 thrd_CloseHandle(phandle);
7779 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7780 NULL, 0, &lpid, "smb_ClientWaiter");
7781 osi_assert(phandle != NULL);
7782 thrd_CloseHandle(phandle);
7785 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7786 NULL, 0, &lpid, "smb_ServerWaiter");
7787 osi_assert(phandle != NULL);
7788 thrd_CloseHandle(phandle);
7790 for (i=0; i<nThreads; i++) {
7791 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7792 (void *) i, 0, &lpid, "smb_Server");
7793 osi_assert(phandle != NULL);
7794 thrd_CloseHandle(phandle);
7797 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7798 NULL, 0, &lpid, "smb_Daemon");
7799 osi_assert(phandle != NULL);
7800 thrd_CloseHandle(phandle);
7802 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7803 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7804 osi_assert(phandle != NULL);
7805 thrd_CloseHandle(phandle);
7814 void smb_Shutdown(void)
7823 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7825 /* setup the NCB system */
7828 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7831 /* Block new sessions by setting shutdown flag */
7832 smbShutdownFlag = 1;
7834 /* Hang up all sessions */
7835 memset((char *)ncbp, 0, sizeof(NCB));
7836 for (i = 1; i < numSessions; i++)
7838 if (dead_sessions[i])
7841 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7842 ncbp->ncb_command = NCBHANGUP;
7843 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
7844 ncbp->ncb_lsn = LSNs[i];
7846 code = Netbios(ncbp);
7848 code = Netbios(ncbp, dos_ncb);
7850 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7851 if (code == 0) code = ncbp->ncb_retcode;
7853 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7854 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7858 /* Delete Netbios name */
7859 memset((char *)ncbp, 0, sizeof(NCB));
7860 for (i = 0; i < lana_list.length; i++) {
7861 if (lana_list.lana[i] == 255) continue;
7862 ncbp->ncb_command = NCBDELNAME;
7863 ncbp->ncb_lana_num = lana_list.lana[i];
7864 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7866 code = Netbios(ncbp);
7868 code = Netbios(ncbp, dos_ncb);
7871 code = ncbp->ncb_retcode;
7873 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7874 ncbp->ncb_lana_num, code);
7879 /* Trigger the shutdown of all SMB threads */
7880 for (i = 0; i < smb_NumServerThreads; i++)
7881 thrd_SetEvent(NCBreturns[i][0]);
7883 thrd_SetEvent(NCBevents[0]);
7884 thrd_SetEvent(SessionEvents[0]);
7885 thrd_SetEvent(NCBavails[0]);
7887 for (i = 0;i < smb_NumServerThreads; i++) {
7888 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], INFINITE);
7889 if (code == WAIT_OBJECT_0) {
7892 afsi_log("smb_Shutdown[%d] wait error",i);
7897 /* Get the UNC \\<servername>\<sharename> prefix. */
7898 char *smb_GetSharename()
7902 /* Make sure we have been properly initialized. */
7903 if (smb_localNamep == NULL)
7906 /* Allocate space for \\<servername>\<sharename>, plus the
7909 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7910 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7916 void smb_LogPacket(smb_packet_t *packet)
7919 unsigned length, paramlen, datalen, i, j;
7921 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7923 if (!packet) return;
7925 osi_Log0(smb_logp, "*** SMB packet dump ***");
7927 vp = (BYTE *) packet->data;
7929 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7930 length = paramlen + 2 + datalen;
7933 for (i=0;i < length; i+=16)
7935 memset( buf, ' ', 80 );
7940 buf[strlen(buf)] = ' ';
7942 cp = (BYTE*) buf + 7;
7944 for (j=0;j < 16 && (i+j)<length; j++)
7946 *(cp++) = hex[vp[i+j] >> 4];
7947 *(cp++) = hex[vp[i+j] & 0xf];
7957 for (j=0;j < 16 && (i+j)<length;j++)
7959 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7970 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
7973 osi_Log0(smb_logp, "*** End SMB packet dump ***");
7975 #endif /* LOG_PACKET */
7978 int smb_DumpVCP(FILE *outputFile, char *cookie)
7985 lock_ObtainRead(&smb_rctLock);
7987 sprintf(output, "begin dumping vcpsp\n");
7988 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7990 for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
7994 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7995 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7996 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7998 sprintf(output, "begin dumping fidsp\n");
7999 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8001 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8003 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",
8004 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8005 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8006 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8007 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8010 sprintf(output, "done dumping fidsp\n");
8011 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8014 sprintf(output, "done dumping vcpsp\n");
8015 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8017 lock_ReleaseRead(&smb_rctLock);