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 #include <afs/param.h>
17 #include <sys/timeb.h>
30 #include <WINNT\afsreg.h>
33 #include "lanahelper.h"
35 /* These characters are illegal in Windows filenames */
36 static char *illegalChars = "\\/:*?\"<>|";
37 BOOL isWindows2000 = FALSE;
39 smb_vc_t *dead_vcp = NULL;
40 smb_vc_t *active_vcp = NULL;
42 /* TODO; logout mechanism needs to be thread-safe */
43 char *loggedOutName = NULL;
44 smb_user_t *loggedOutUserp = NULL;
47 int smbShutdownFlag = 0;
49 int smb_LogoffTokenTransfer;
50 time_t smb_LogoffTransferTimeout;
52 int smb_StoreAnsiFilenames = 0;
54 DWORD last_msg_time = 0;
58 unsigned int sessionGen = 0;
60 extern void afsi_log(char *pattern, ...);
61 extern HANDLE afsi_file;
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t smb_ListenerLock;
72 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
75 long smb_maxObsConcurrentCalls=0;
76 long smb_concurrentCalls=0;
78 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
80 smb_packet_t *smb_packetFreeListp;
81 smb_ncb_t *smb_ncbFreeListp;
83 int smb_NumServerThreads;
85 int numNCBs, numSessions, numVCs;
87 int smb_maxVCPerServer;
88 int smb_maxMpxRequests;
90 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
92 ULONG smb_lsaSecPackage;
93 LSA_STRING smb_lsaLogonOrigin;
95 #define NCBmax MAXIMUM_WAIT_OBJECTS
96 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
97 EVENT_HANDLE **NCBreturns;
98 EVENT_HANDLE **NCBShutdown;
99 EVENT_HANDLE *smb_ServerShutdown;
100 DWORD NCBsessions[NCBmax];
102 struct smb_packet *bufs[NCBmax];
104 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
105 EVENT_HANDLE SessionEvents[Sessionmax];
106 unsigned short LSNs[Sessionmax];
107 int lanas[Sessionmax];
108 BOOL dead_sessions[Sessionmax];
112 osi_mutex_t smb_RawBufLock;
114 #define SMB_RAW_BUFS 4
116 int smb_RawBufSel[SMB_RAW_BUFS];
121 #define SMB_MASKFLAG_TILDE 1
122 #define SMB_MASKFLAG_CASEFOLD 2
124 #define RAWTIMEOUT INFINITE
127 typedef struct raw_write_cont {
140 /* dir search stuff */
141 long smb_dirSearchCounter = 1;
142 smb_dirSearch_t *smb_firstDirSearchp;
143 smb_dirSearch_t *smb_lastDirSearchp;
145 /* hide dot files? */
146 int smb_hideDotFiles;
148 /* global state about V3 protocols */
149 int smb_useV3; /* try to negotiate V3 */
152 static showErrors = 1;
153 /* MessageBox or something like it */
154 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
155 extern HANDLE WaitToTerminate;
159 * Time in Unix format of midnight, 1/1/1970 local time.
160 * When added to dosUTime, gives Unix (AFS) time.
162 time_t smb_localZero = 0;
164 /* Time difference for converting to kludge-GMT */
167 char *smb_localNamep = NULL;
169 smb_vc_t *smb_allVCsp;
171 smb_username_t *usernamesp = NULL;
173 smb_waitingLock_t *smb_allWaitingLocks;
176 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
177 NCB *ncbp, raw_write_cont_t *rwcp);
178 void smb_NetbiosInit();
180 #ifndef AFS_WIN95_ENV
181 DWORD smb_ServerExceptionFilter(void);
184 extern char cm_HostName[];
185 extern char cm_confDir[];
189 #define LPTSTR char *
190 #define GetComputerName(str, sizep) \
191 strcpy((str), cm_HostName); \
192 *(sizep) = strlen(cm_HostName)
196 void smb_LogPacket(smb_packet_t *packet);
197 #endif /* LOG_PACKET */
199 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
200 int smb_ServerDomainNameLength = 0;
201 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
202 int smb_ServerOSLength = sizeof(smb_ServerOS);
203 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
204 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
206 /* Faux server GUID. This is never checked. */
207 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
209 char * myCrt_Dispatch(int i)
214 return "(00)ReceiveCoreMakeDir";
216 return "(01)ReceiveCoreRemoveDir";
218 return "(02)ReceiveCoreOpen";
220 return "(03)ReceiveCoreCreate";
222 return "(04)ReceiveCoreClose";
224 return "(05)ReceiveCoreFlush";
226 return "(06)ReceiveCoreUnlink";
228 return "(07)ReceiveCoreRename";
230 return "(08)ReceiveCoreGetFileAttributes";
232 return "(09)ReceiveCoreSetFileAttributes";
234 return "(0a)ReceiveCoreRead";
236 return "(0b)ReceiveCoreWrite";
238 return "(0c)ReceiveCoreLockRecord";
240 return "(0d)ReceiveCoreUnlockRecord";
242 return "(0e)SendCoreBadOp";
244 return "(0f)ReceiveCoreCreate";
246 return "(10)ReceiveCoreCheckPath";
248 return "(11)SendCoreBadOp";
250 return "(12)ReceiveCoreSeek";
252 return "(1a)ReceiveCoreReadRaw";
254 return "(1d)ReceiveCoreWriteRawDummy";
256 return "(22)ReceiveV3SetAttributes";
258 return "(23)ReceiveV3GetAttributes";
260 return "(24)ReceiveV3LockingX";
262 return "(25)ReceiveV3Trans";
264 return "(26)ReceiveV3Trans[aux]";
266 return "(29)SendCoreBadOp";
268 return "(2b)ReceiveCoreEcho";
270 return "(2d)ReceiveV3OpenX";
272 return "(2e)ReceiveV3ReadX";
274 return "(32)ReceiveV3Tran2A";
276 return "(33)ReceiveV3Tran2A[aux]";
278 return "(34)ReceiveV3FindClose";
280 return "(35)ReceiveV3FindNotifyClose";
282 return "(70)ReceiveCoreTreeConnect";
284 return "(71)ReceiveCoreTreeDisconnect";
286 return "(72)ReceiveNegotiate";
288 return "(73)ReceiveV3SessionSetupX";
290 return "(74)ReceiveV3UserLogoffX";
292 return "(75)ReceiveV3TreeConnectX";
294 return "(80)ReceiveCoreGetDiskAttributes";
296 return "(81)ReceiveCoreSearchDir";
300 return "(83)FindUnique";
302 return "(84)FindClose";
304 return "(A0)ReceiveNTTransact";
306 return "(A2)ReceiveNTCreateX";
308 return "(A4)ReceiveNTCancel";
310 return "(A5)ReceiveNTRename";
312 return "(C0)OpenPrintFile";
314 return "(C1)WritePrintFile";
316 return "(C2)ClosePrintFile";
318 return "(C3)GetPrintQueue";
320 return "(D8)ReadBulk";
322 return "(D9)WriteBulk";
324 return "(DA)WriteBulkData";
326 return "unknown SMB op";
330 char * myCrt_2Dispatch(int i)
335 return "unknown SMB op-2";
337 return "S(00)CreateFile";
339 return "S(01)FindFirst";
341 return "S(02)FindNext"; /* FindNext */
343 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
347 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
349 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
351 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
353 return "S(08)??_ReceiveTran2SetFileInfo";
355 return "S(09)??_ReceiveTran2FSCTL";
357 return "S(0a)_ReceiveTran2IOCTL";
359 return "S(0b)_ReceiveTran2FindNotifyFirst";
361 return "S(0c)_ReceiveTran2FindNotifyNext";
363 return "S(0d)_ReceiveTran2CreateDirectory";
365 return "S(0e)_ReceiveTran2SessionSetup";
367 return "S(10)_ReceiveTran2GetDfsReferral";
369 return "S(11)_ReceiveTran2ReportDfsInconsistency";
373 char * myCrt_RapDispatch(int i)
378 return "unknown RAP OP";
380 return "RAP(0)NetShareEnum";
382 return "RAP(1)NetShareGetInfo";
384 return "RAP(13)NetServerGetInfo";
386 return "RAP(63)NetWkStaGetInfo";
390 /* scache must be locked */
391 unsigned int smb_Attributes(cm_scache_t *scp)
395 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
396 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
397 scp->fileType == CM_SCACHETYPE_INVALID)
399 attrs = SMB_ATTR_DIRECTORY;
400 #ifdef SPECIAL_FOLDERS
401 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
402 #endif /* SPECIAL_FOLDERS */
403 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
404 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
409 * We used to mark a file RO if it was in an RO volume, but that
410 * turns out to be impolitic in NT. See defect 10007.
413 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
414 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
416 if ((scp->unixModeBits & 0222) == 0)
417 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
423 /* Check if the named file/dir is a dotfile/dotdir */
424 /* String pointed to by lastComp can have leading slashes, but otherwise should have
425 no other patch components */
426 unsigned int smb_IsDotFile(char *lastComp) {
429 /* skip over slashes */
430 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
435 /* nulls, curdir and parent dir doesn't count */
441 if(*(s+1) == '.' && !*(s + 2))
448 static int ExtractBits(WORD bits, short start, short len)
455 num = bits << (16 - end);
456 num = num >> ((16 - end) + start);
462 void ShowUnixTime(char *FuncName, time_t unixTime)
467 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
469 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
470 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
472 int day, month, year, sec, min, hour;
475 day = ExtractBits(wDate, 0, 5);
476 month = ExtractBits(wDate, 5, 4);
477 year = ExtractBits(wDate, 9, 7) + 1980;
479 sec = ExtractBits(wTime, 0, 5);
480 min = ExtractBits(wTime, 5, 6);
481 hour = ExtractBits(wTime, 11, 5);
483 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
484 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
490 /* Determine if we are observing daylight savings time */
491 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
493 TIME_ZONE_INFORMATION timeZoneInformation;
494 SYSTEMTIME utc, local, localDST;
496 /* Get the time zone info. NT uses this to calc if we are in DST. */
497 GetTimeZoneInformation(&timeZoneInformation);
499 /* Return the daylight bias */
500 *pDstBias = timeZoneInformation.DaylightBias;
502 /* Return the bias */
503 *pBias = timeZoneInformation.Bias;
505 /* Now determine if DST is being observed */
507 /* Get the UTC (GMT) time */
510 /* Convert UTC time to local time using the time zone info. If we are
511 observing DST, the calculated local time will include this.
513 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
515 /* Set the daylight bias to 0. The daylight bias is the amount of change
516 * in time that we use for daylight savings time. By setting this to 0
517 * we cause there to be no change in time during daylight savings time.
519 timeZoneInformation.DaylightBias = 0;
521 /* Convert the utc time to local time again, but this time without any
522 adjustment for daylight savings time.
524 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
526 /* If the two times are different, then it means that the localDST that
527 we calculated includes the daylight bias, and therefore we are
528 observing daylight savings time.
530 *pDST = localDST.wHour != local.wHour;
533 /* Determine if we are observing daylight savings time */
534 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
540 *pDstBias = -60; /* where can this be different? */
546 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
548 BOOL dst; /* Will be TRUE if observing DST */
549 LONG dstBias; /* Offset from local time if observing DST */
550 LONG bias; /* Offset from GMT for local time */
553 * This function will adjust the last write time to compensate
554 * for two bugs in the smb client:
556 * 1) During Daylight Savings Time, the LastWriteTime is ahead
557 * in time by the DaylightBias (ignoring the sign - the
558 * DaylightBias is always stored as a negative number). If
559 * the DaylightBias is -60, then the LastWriteTime will be
560 * ahead by 60 minutes.
562 * 2) If the local time zone is a positive offset from GMT, then
563 * the LastWriteTime will be the correct local time plus the
564 * Bias (ignoring the sign - a positive offset from GMT is
565 * always stored as a negative Bias). If the Bias is -120,
566 * then the LastWriteTime will be ahead by 120 minutes.
568 * These bugs can occur at the same time.
571 GetTimeZoneInfo(&dst, &dstBias, &bias);
573 /* First adjust for DST */
575 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
577 /* Now adjust for a positive offset from GMT (a negative bias). */
579 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
583 * Calculate the difference (in seconds) between local time and GMT.
584 * This enables us to convert file times to kludge-GMT.
590 struct tm gmt_tm, local_tm;
591 int days, hours, minutes, seconds;
594 gmt_tm = *(gmtime(&t));
595 local_tm = *(localtime(&t));
597 days = local_tm.tm_yday - gmt_tm.tm_yday;
598 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
600 /* There is a problem with DST immediately after the time change
601 * which may continue to exist until the machine is rebooted
603 - (local_tm.tm_isdst ? 1 : 0)
606 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
607 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
613 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
618 time_t ersatz_unixTime;
621 * Must use kludge-GMT instead of real GMT.
622 * kludge-GMT is computed by adding time zone difference to localtime.
625 * ltp = gmtime(&unixTime);
627 ersatz_unixTime = unixTime - smb_NowTZ;
628 ltp = localtime(&ersatz_unixTime);
630 /* if we fail, make up something */
633 localJunk.tm_year = 89 - 20;
634 localJunk.tm_mon = 4;
635 localJunk.tm_mday = 12;
636 localJunk.tm_hour = 0;
637 localJunk.tm_min = 0;
638 localJunk.tm_sec = 0;
641 stm.wYear = ltp->tm_year + 1900;
642 stm.wMonth = ltp->tm_mon + 1;
643 stm.wDayOfWeek = ltp->tm_wday;
644 stm.wDay = ltp->tm_mday;
645 stm.wHour = ltp->tm_hour;
646 stm.wMinute = ltp->tm_min;
647 stm.wSecond = ltp->tm_sec;
648 stm.wMilliseconds = 0;
650 SystemTimeToFileTime(&stm, largeTimep);
653 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
655 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
656 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
657 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
659 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
661 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
662 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
664 *ft = LargeIntegerMultiplyByLong(*ft, 60);
665 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
668 ut = ConvertLongToLargeInteger(unixTime);
669 ut = LargeIntegerMultiplyByLong(ut, 10000000);
670 *ft = LargeIntegerAdd(*ft, ut);
675 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
681 FileTimeToSystemTime(largeTimep, &stm);
683 lt.tm_year = stm.wYear - 1900;
684 lt.tm_mon = stm.wMonth - 1;
685 lt.tm_wday = stm.wDayOfWeek;
686 lt.tm_mday = stm.wDay;
687 lt.tm_hour = stm.wHour;
688 lt.tm_min = stm.wMinute;
689 lt.tm_sec = stm.wSecond;
692 save_timezone = _timezone;
693 _timezone += smb_NowTZ;
694 *unixTimep = mktime(<);
695 _timezone = save_timezone;
698 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
700 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
701 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
702 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
706 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
707 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
708 a = LargeIntegerMultiplyByLong(a, 60);
709 a = LargeIntegerMultiplyByLong(a, 10000000);
711 /* subtract it from ft */
712 a = LargeIntegerSubtract(*ft, a);
714 /* divide down to seconds */
715 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
719 void smb_SearchTimeFromUnixTime(time_t *dosTimep, time_t unixTime)
727 ltp = localtime((time_t*) &t);
729 /* if we fail, make up something */
732 localJunk.tm_year = 89 - 20;
733 localJunk.tm_mon = 4;
734 localJunk.tm_mday = 12;
735 localJunk.tm_hour = 0;
736 localJunk.tm_min = 0;
737 localJunk.tm_sec = 0;
740 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
741 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
742 *dosTimep = (dosDate<<16) | dosTime;
745 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
747 unsigned short dosDate;
748 unsigned short dosTime;
751 dosDate = (unsigned short) (searchTime & 0xffff);
752 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
754 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
755 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
756 localTm.tm_mday = (dosDate) & 0x1f;
757 localTm.tm_hour = (dosTime>>11) & 0x1f;
758 localTm.tm_min = (dosTime >> 5) & 0x3f;
759 localTm.tm_sec = (dosTime & 0x1f) * 2;
760 localTm.tm_isdst = -1; /* compute whether DST in effect */
762 *unixTimep = mktime(&localTm);
765 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
767 *dosUTimep = unixTime - smb_localZero;
770 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
773 *unixTimep = dosTime + smb_localZero;
775 /* dosTime seems to be already adjusted for GMT */
776 *unixTimep = dosTime;
780 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
784 lock_ObtainWrite(&smb_rctLock);
785 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
786 if (lsn == vcp->lsn && lana == vcp->lana) {
787 smb_HoldVCNoLock(vcp);
791 if (!vcp && (flags & SMB_FLAG_CREATE)) {
792 vcp = malloc(sizeof(*vcp));
793 memset(vcp, 0, sizeof(*vcp));
794 vcp->vcID = numVCs++;
798 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
799 vcp->nextp = smb_allVCsp;
801 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
806 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
807 /* We must obtain a challenge for extended auth
808 * in case the client negotiates smb v3
810 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
811 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
812 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
813 ULONG lsaRespSize = 0;
815 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
817 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
824 if (nts != STATUS_SUCCESS)
825 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
826 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
827 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
829 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
830 LsaFreeReturnBuffer(lsaResp);
833 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
835 lock_ReleaseWrite(&smb_rctLock);
839 int smb_IsStarMask(char *maskp)
844 for(i=0; i<11; i++) {
846 if (tc == '?' || tc == '*' || tc == '>') return 1;
851 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
853 osi_assert(vcp->refCount-- != 0);
856 void smb_ReleaseVC(smb_vc_t *vcp)
858 lock_ObtainWrite(&smb_rctLock);
859 osi_assert(vcp->refCount-- != 0);
860 lock_ReleaseWrite(&smb_rctLock);
863 void smb_HoldVCNoLock(smb_vc_t *vcp)
868 void smb_HoldVC(smb_vc_t *vcp)
870 lock_ObtainWrite(&smb_rctLock);
872 lock_ReleaseWrite(&smb_rctLock);
875 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
879 lock_ObtainWrite(&smb_rctLock);
880 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
881 if (tid == tidp->tid) {
886 if (!tidp && (flags & SMB_FLAG_CREATE)) {
887 tidp = malloc(sizeof(*tidp));
888 memset(tidp, 0, sizeof(*tidp));
889 tidp->nextp = vcp->tidsp;
892 smb_HoldVCNoLock(vcp);
894 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
897 lock_ReleaseWrite(&smb_rctLock);
901 void smb_ReleaseTID(smb_tid_t *tidp)
908 lock_ObtainWrite(&smb_rctLock);
909 osi_assert(tidp->refCount-- > 0);
910 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
911 ltpp = &tidp->vcp->tidsp;
912 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
916 osi_assert(tp != NULL);
918 lock_FinalizeMutex(&tidp->mx);
919 userp = tidp->userp; /* remember to drop ref later */
921 smb_ReleaseVCNoLock(tidp->vcp);
924 lock_ReleaseWrite(&smb_rctLock);
926 cm_ReleaseUser(userp);
929 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
931 smb_user_t *uidp = NULL;
933 lock_ObtainWrite(&smb_rctLock);
934 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
935 if (uid == uidp->userID) {
937 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
938 (int)vcp, uidp->userID,
939 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
943 if (!uidp && (flags & SMB_FLAG_CREATE)) {
944 uidp = malloc(sizeof(*uidp));
945 memset(uidp, 0, sizeof(*uidp));
946 uidp->nextp = vcp->usersp;
949 smb_HoldVCNoLock(vcp);
951 lock_InitializeMutex(&uidp->mx, "user_t mutex");
953 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 : ""));
955 lock_ReleaseWrite(&smb_rctLock);
959 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
961 smb_username_t *unp= NULL;
963 lock_ObtainWrite(&smb_rctLock);
964 for(unp = usernamesp; unp; unp = unp->nextp) {
965 if (stricmp(unp->name, usern) == 0 &&
966 stricmp(unp->machine, machine) == 0) {
971 if (!unp && (flags & SMB_FLAG_CREATE)) {
972 unp = malloc(sizeof(*unp));
973 memset(unp, 0, sizeof(*unp));
975 unp->nextp = usernamesp;
976 unp->name = strdup(usern);
977 unp->machine = strdup(machine);
979 lock_InitializeMutex(&unp->mx, "username_t mutex");
981 lock_ReleaseWrite(&smb_rctLock);
985 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
987 smb_user_t *uidp= NULL;
989 lock_ObtainWrite(&smb_rctLock);
990 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
993 if (stricmp(uidp->unp->name, usern) == 0) {
995 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
1000 lock_ReleaseWrite(&smb_rctLock);
1003 void smb_ReleaseUID(smb_user_t *uidp)
1010 lock_ObtainWrite(&smb_rctLock);
1011 osi_assert(uidp->refCount-- > 0);
1012 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1013 lupp = &uidp->vcp->usersp;
1014 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1018 osi_assert(up != NULL);
1020 lock_FinalizeMutex(&uidp->mx);
1022 userp = uidp->unp->userp; /* avoid deadlock by releasing */
1023 uidp->unp->userp = NULL; /* after releasing the lock */
1025 smb_ReleaseVCNoLock(uidp->vcp);
1028 lock_ReleaseWrite(&smb_rctLock);
1030 cm_ReleaseUserVCRef(userp);
1031 cm_ReleaseUser(userp);
1036 /* retrieve a held reference to a user structure corresponding to an incoming
1038 * corresponding release function is cm_ReleaseUser.
1040 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1046 smbp = (smb_t *) inp;
1047 uidp = smb_FindUID(vcp, smbp->uid, 0);
1048 if ((!uidp) || (!uidp->unp))
1051 lock_ObtainMutex(&uidp->mx);
1052 up = uidp->unp->userp;
1054 lock_ReleaseMutex(&uidp->mx);
1056 smb_ReleaseUID(uidp);
1062 * Return a pointer to a pathname extracted from a TID structure. The
1063 * TID structure is not held; assume it won't go away.
1065 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1070 tidp = smb_FindTID(vcp, tid, 0);
1074 if (tidp->flags & SMB_TIDFLAG_IPC) {
1075 code = CM_ERROR_TIDIPC;
1076 /* tidp->pathname would be NULL, but that's fine */
1078 *treepath = tidp->pathname;
1079 smb_ReleaseTID(tidp);
1084 /* check to see if we have a chained fid, that is, a fid that comes from an
1085 * OpenAndX message that ran earlier in this packet. In this case, the fid
1086 * field in a read, for example, request, isn't set, since the value is
1087 * supposed to be inherited from the openAndX call.
1089 int smb_ChainFID(int fid, smb_packet_t *inp)
1091 if (inp->fid == 0 || inp->inCount == 0)
1097 /* are we a priv'd user? What does this mean on NT? */
1098 int smb_SUser(cm_user_t *userp)
1103 /* find a file ID. If we pass in 0 we select an used File ID.
1104 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1105 * smb_fid_t data structure if desired File ID cannot be found.
1107 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1112 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1115 lock_ObtainWrite(&smb_rctLock);
1116 /* figure out if we need to allocate a new file ID */
1119 fid = vcp->fidCounter;
1123 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1124 if (fid == fidp->fid) {
1135 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1136 char eventName[MAX_PATH];
1138 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1139 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1140 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1141 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1142 thrd_CloseHandle(event);
1149 fidp = malloc(sizeof(*fidp));
1150 memset(fidp, 0, sizeof(*fidp));
1151 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1154 smb_HoldVCNoLock(vcp);
1155 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1157 fidp->curr_chunk = fidp->prev_chunk = -2;
1158 fidp->raw_write_event = event;
1160 vcp->fidCounter = fid+1;
1161 if (vcp->fidCounter == 0)
1162 vcp->fidCounter = 1;
1165 lock_ReleaseWrite(&smb_rctLock);
1169 void smb_ReleaseFID(smb_fid_t *fidp)
1172 smb_vc_t *vcp = NULL;
1173 smb_ioctl_t *ioctlp;
1179 lock_ObtainWrite(&smb_rctLock);
1180 osi_assert(fidp->refCount-- > 0);
1181 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1184 scp = fidp->scp; /* release after lock is released */
1187 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1188 thrd_CloseHandle(fidp->raw_write_event);
1190 /* and see if there is ioctl stuff to free */
1191 ioctlp = fidp->ioctlp;
1194 cm_FreeSpace(ioctlp->prefix);
1195 if (ioctlp->inAllocp)
1196 free(ioctlp->inAllocp);
1197 if (ioctlp->outAllocp)
1198 free(ioctlp->outAllocp);
1204 smb_ReleaseVCNoLock(vcp);
1206 lock_ReleaseWrite(&smb_rctLock);
1208 /* now release the scache structure */
1210 cm_ReleaseSCache(scp);
1214 * Case-insensitive search for one string in another;
1215 * used to find variable names in submount pathnames.
1217 static char *smb_stristr(char *str1, char *str2)
1221 for (cursor = str1; *cursor; cursor++)
1222 if (stricmp(cursor, str2) == 0)
1229 * Substitute a variable value for its name in a submount pathname. Variable
1230 * name has been identified by smb_stristr() and is in substr. Variable name
1231 * length (plus one) is in substr_size. Variable value is in newstr.
1233 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1238 strcpy(temp, substr + substr_size - 1);
1239 strcpy(substr, newstr);
1243 char VNUserName[] = "%USERNAME%";
1244 char VNLCUserName[] = "%LCUSERNAME%";
1245 char VNComputerName[] = "%COMPUTERNAME%";
1246 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1249 /* List available shares */
1250 int smb_ListShares()
1254 char shareBuf[4096];
1262 /*strcpy(shareNameList[num_shares], "all");
1263 strcpy(pathNameList[num_shares++], "/afs");*/
1264 fprintf(stderr, "The following shares are available:\n");
1265 fprintf(stderr, "Share Name (AFS Path)\n");
1266 fprintf(stderr, "---------------------\n");
1267 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1270 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1271 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1273 strcpy(sbmtpath, cm_confDir);
1275 strcat(sbmtpath, "/afsdsbmt.ini");
1276 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1277 shareBuf, sizeof(shareBuf),
1283 this_share = shareBuf;
1287 /*strcpy(shareNameList[num_shares], this_share);*/
1288 len = GetPrivateProfileString("AFS Submounts", this_share,
1295 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1298 if (*p == '\\') *p = '/'; /* change to / */
1302 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1303 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1306 while (*this_share != 0) this_share++; /* find next NUL */
1307 this_share++; /* skip past the NUL */
1308 } while (*this_share != 0); /* stop at final NUL */
1314 typedef struct smb_findShare_rock {
1318 } smb_findShare_rock_t;
1320 #define SMB_FINDSHARE_EXACT_MATCH 1
1321 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1323 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1327 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1328 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1329 if(!stricmp(dep->name, vrock->shareName))
1330 matchType = SMB_FINDSHARE_EXACT_MATCH;
1332 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1333 if(vrock->match) free(vrock->match);
1334 vrock->match = strdup(dep->name);
1335 vrock->matchType = matchType;
1337 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1338 return CM_ERROR_STOPNOW;
1344 /* find a shareName in the table of submounts */
1345 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1349 char pathName[1024];
1354 char sbmtpath[MAX_PATH];
1359 DWORD allSubmount = 1;
1361 /* if allSubmounts == 0, only return the //mountRoot/all share
1362 * if in fact it has been been created in the subMounts table.
1363 * This is to allow sites that want to restrict access to the
1366 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1367 0, KEY_QUERY_VALUE, &parmKey);
1368 if (code == ERROR_SUCCESS) {
1369 len = sizeof(allSubmount);
1370 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1371 (BYTE *) &allSubmount, &len);
1372 if (code != ERROR_SUCCESS) {
1375 RegCloseKey (parmKey);
1378 if (allSubmount && _stricmp(shareName, "all") == 0) {
1383 /* In case, the all share is disabled we need to still be able
1384 * to handle ioctl requests
1386 if (_stricmp(shareName, "ioctl$") == 0) {
1387 *pathNamep = strdup("/.__ioctl__");
1391 if (_stricmp(shareName, "IPC$") == 0 ||
1392 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1393 _stricmp(shareName, "DESKTOP.INI") == 0
1400 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1401 0, KEY_QUERY_VALUE, &parmKey);
1402 if (code == ERROR_SUCCESS) {
1403 len = sizeof(pathName);
1404 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1405 (BYTE *) pathName, &len);
1406 if (code != ERROR_SUCCESS)
1408 RegCloseKey (parmKey);
1413 strcpy(sbmtpath, cm_confDir);
1414 strcat(sbmtpath, "/afsdsbmt.ini");
1415 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1416 pathName, sizeof(pathName), sbmtpath);
1418 if (len != 0 && len != sizeof(pathName) - 1) {
1419 /* We can accept either unix or PC style AFS pathnames. Convert
1420 * Unix-style to PC style here for internal use.
1423 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1424 p += strlen(cm_mountRoot); /* skip mount path */
1427 if (*q == '/') *q = '\\'; /* change to \ */
1433 if (var = smb_stristr(p, VNUserName)) {
1434 if (uidp && uidp->unp)
1435 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1437 smb_subst(p, var, sizeof(VNUserName)," ");
1439 else if (var = smb_stristr(p, VNLCUserName))
1441 if (uidp && uidp->unp)
1442 strcpy(temp, uidp->unp->name);
1446 smb_subst(p, var, sizeof(VNLCUserName), temp);
1448 else if (var = smb_stristr(p, VNComputerName))
1450 sizeTemp = sizeof(temp);
1451 GetComputerName((LPTSTR)temp, &sizeTemp);
1452 smb_subst(p, var, sizeof(VNComputerName), temp);
1454 else if (var = smb_stristr(p, VNLCComputerName))
1456 sizeTemp = sizeof(temp);
1457 GetComputerName((LPTSTR)temp, &sizeTemp);
1459 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1464 *pathNamep = strdup(p);
1469 /* First lookup shareName in root.afs */
1471 smb_findShare_rock_t vrock;
1473 char * p = shareName;
1476 /* attempt to locate a partial match in root.afs. This is because
1477 when using the ANSI RAP calls, the share name is limited to 13 chars
1478 and hence is truncated. Of course we prefer exact matches. */
1480 thyper.HighPart = 0;
1483 vrock.shareName = shareName;
1485 vrock.matchType = 0;
1487 cm_HoldSCache(cm_data.rootSCachep);
1488 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1489 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1490 cm_ReleaseSCache(cm_data.rootSCachep);
1492 if (vrock.matchType) {
1493 sprintf(pathName,"/%s/",vrock.match);
1494 *pathNamep = strdup(strlwr(pathName));
1499 /* if we get here, there was no match for the share in root.afs */
1500 /* so try to create \\<netbiosName>\<cellname> */
1505 /* Get the full name for this cell */
1506 code = cm_SearchCellFile(p, temp, 0, 0);
1507 #ifdef AFS_AFSDB_ENV
1508 if (code && cm_dnsEnabled) {
1510 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1513 /* construct the path */
1515 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1516 *pathNamep = strdup(strlwr(pathName));
1525 /* Client-side offline caching policy types */
1526 #define CSC_POLICY_MANUAL 0
1527 #define CSC_POLICY_DOCUMENTS 1
1528 #define CSC_POLICY_PROGRAMS 2
1529 #define CSC_POLICY_DISABLE 3
1531 int smb_FindShareCSCPolicy(char *shareName)
1537 int retval = CSC_POLICY_MANUAL;
1539 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1540 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1543 REG_OPTION_NON_VOLATILE,
1549 len = sizeof(policy);
1550 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1552 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1554 else if (stricmp(policy, "documents") == 0)
1556 retval = CSC_POLICY_DOCUMENTS;
1558 else if (stricmp(policy, "programs") == 0)
1560 retval = CSC_POLICY_PROGRAMS;
1562 else if (stricmp(policy, "disable") == 0)
1564 retval = CSC_POLICY_DISABLE;
1567 RegCloseKey(hkCSCPolicy);
1571 /* find a dir search structure by cookie value, and return it held.
1572 * Must be called with smb_globalLock held.
1574 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1576 smb_dirSearch_t *dsp;
1578 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1579 if (dsp->cookie == cookie) {
1580 if (dsp != smb_firstDirSearchp) {
1581 /* move to head of LRU queue, too, if we're not already there */
1582 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1583 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1584 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1585 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1586 if (!smb_lastDirSearchp)
1587 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1589 lock_ObtainMutex(&dsp->mx);
1591 lock_ReleaseMutex(&dsp->mx);
1597 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1598 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1599 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1605 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1607 lock_ObtainWrite(&smb_globalLock);
1608 lock_ObtainMutex(&dsp->mx);
1609 dsp->flags |= SMB_DIRSEARCH_DELETE;
1610 if (dsp->scp != NULL) {
1611 lock_ObtainMutex(&dsp->scp->mx);
1612 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1613 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1614 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1615 dsp->scp->bulkStatProgress = hones;
1617 lock_ReleaseMutex(&dsp->scp->mx);
1619 lock_ReleaseMutex(&dsp->mx);
1620 lock_ReleaseWrite(&smb_globalLock);
1623 /* Must be called with the smb_globalLock held */
1624 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1626 cm_scache_t *scp = NULL;
1628 lock_ObtainMutex(&dsp->mx);
1629 osi_assert(dsp->refCount-- > 0);
1630 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1631 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1632 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1633 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1634 lock_ReleaseMutex(&dsp->mx);
1635 lock_FinalizeMutex(&dsp->mx);
1639 lock_ReleaseMutex(&dsp->mx);
1641 /* do this now to avoid spurious locking hierarchy creation */
1642 if (scp) cm_ReleaseSCache(scp);
1645 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1647 lock_ObtainWrite(&smb_globalLock);
1648 smb_ReleaseDirSearchNoLock(dsp);
1649 lock_ReleaseWrite(&smb_globalLock);
1652 /* find a dir search structure by cookie value, and return it held */
1653 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1655 smb_dirSearch_t *dsp;
1657 lock_ObtainWrite(&smb_globalLock);
1658 dsp = smb_FindDirSearchNoLock(cookie);
1659 lock_ReleaseWrite(&smb_globalLock);
1663 /* GC some dir search entries, in the address space expected by the specific protocol.
1664 * Must be called with smb_globalLock held; release the lock temporarily.
1666 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1667 void smb_GCDirSearches(int isV3)
1669 smb_dirSearch_t *prevp;
1670 smb_dirSearch_t *tp;
1671 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1675 victimCount = 0; /* how many have we got so far */
1676 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1677 /* we'll move tp from queue, so
1680 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1681 /* if no one is using this guy, and we're either in the new protocol,
1682 * or we're in the old one and this is a small enough ID to be useful
1683 * to the old protocol, GC this guy.
1685 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1686 /* hold and delete */
1687 tp->flags |= SMB_DIRSEARCH_DELETE;
1688 victimsp[victimCount++] = tp;
1692 /* don't do more than this */
1693 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1697 /* now release them */
1698 for (i = 0; i < victimCount; i++) {
1699 smb_ReleaseDirSearchNoLock(victimsp[i]);
1703 /* function for allocating a dir search entry. We need these to remember enough context
1704 * since we don't get passed the path from call to call during a directory search.
1706 * Returns a held dir search structure, and bumps the reference count on the vnode,
1707 * since it saves a pointer to the vnode.
1709 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1711 smb_dirSearch_t *dsp;
1717 lock_ObtainWrite(&smb_globalLock);
1720 /* what's the biggest ID allowed in this version of the protocol */
1721 maxAllowed = isV3 ? 65535 : 255;
1722 if (smb_dirSearchCounter > maxAllowed)
1723 smb_dirSearchCounter = 1;
1725 start = smb_dirSearchCounter;
1728 /* twice so we have enough tries to find guys we GC after one pass;
1729 * 10 extra is just in case I mis-counted.
1731 if (++counter > 2*maxAllowed+10)
1732 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1734 if (smb_dirSearchCounter > maxAllowed) {
1735 smb_dirSearchCounter = 1;
1737 if (smb_dirSearchCounter == start) {
1739 smb_GCDirSearches(isV3);
1742 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1744 /* don't need to watch for refcount zero and deleted, since
1745 * we haven't dropped the global lock.
1747 lock_ObtainMutex(&dsp->mx);
1749 lock_ReleaseMutex(&dsp->mx);
1750 ++smb_dirSearchCounter;
1754 dsp = malloc(sizeof(*dsp));
1755 memset(dsp, 0, sizeof(*dsp));
1756 dsp->cookie = smb_dirSearchCounter;
1757 ++smb_dirSearchCounter;
1759 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1760 dsp->lastTime = osi_Time();
1761 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1762 if (!smb_lastDirSearchp)
1763 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1766 lock_ReleaseWrite(&smb_globalLock);
1770 static smb_packet_t *GetPacket(void)
1774 unsigned int npar, seg, tb_sel;
1777 lock_ObtainWrite(&smb_globalLock);
1778 tbp = smb_packetFreeListp;
1780 smb_packetFreeListp = tbp->nextp;
1781 lock_ReleaseWrite(&smb_globalLock);
1784 tbp = calloc(65540,1);
1786 tbp = malloc(sizeof(smb_packet_t));
1788 tbp->magic = SMB_PACKETMAGIC;
1791 tbp->resumeCode = 0;
1797 tbp->ncb_length = 0;
1802 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1805 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1807 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1809 osi_panic("",__FILE__,__LINE__);
1812 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1817 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1818 tbp->dos_pkt_sel = tb_sel;
1821 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1826 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1830 memcpy(tbp, pkt, sizeof(smb_packet_t));
1831 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1835 static NCB *GetNCB(void)
1840 unsigned int npar, seg, tb_sel;
1843 lock_ObtainWrite(&smb_globalLock);
1844 tbp = smb_ncbFreeListp;
1846 smb_ncbFreeListp = tbp->nextp;
1847 lock_ReleaseWrite(&smb_globalLock);
1850 tbp = calloc(sizeof(*tbp),1);
1852 tbp = malloc(sizeof(*tbp));
1853 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1856 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1858 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1860 osi_panic("",__FILE__,__LINE__);
1862 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1867 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1868 tbp->dos_ncb_sel = tb_sel;
1870 tbp->magic = SMB_NCBMAGIC;
1873 osi_assert(tbp->magic == SMB_NCBMAGIC);
1875 memset(&tbp->ncb, 0, sizeof(NCB));
1878 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1883 void smb_FreePacket(smb_packet_t *tbp)
1885 smb_vc_t * vcp = NULL;
1886 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1888 lock_ObtainWrite(&smb_globalLock);
1889 tbp->nextp = smb_packetFreeListp;
1890 smb_packetFreeListp = tbp;
1891 tbp->magic = SMB_PACKETMAGIC;
1895 tbp->resumeCode = 0;
1901 tbp->ncb_length = 0;
1903 lock_ReleaseWrite(&smb_globalLock);
1909 static void FreeNCB(NCB *bufferp)
1913 tbp = (smb_ncb_t *) bufferp;
1914 osi_assert(tbp->magic == SMB_NCBMAGIC);
1916 lock_ObtainWrite(&smb_globalLock);
1917 tbp->nextp = smb_ncbFreeListp;
1918 smb_ncbFreeListp = tbp;
1919 lock_ReleaseWrite(&smb_globalLock);
1922 /* get a ptr to the data part of a packet, and its count */
1923 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1927 unsigned char *afterParmsp;
1929 parmBytes = *smbp->wctp << 1;
1930 afterParmsp = smbp->wctp + parmBytes + 1;
1932 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1933 if (nbytesp) *nbytesp = dataBytes;
1935 /* don't forget to skip the data byte count, since it follows
1936 * the parameters; that's where the "2" comes from below.
1938 return (unsigned char *) (afterParmsp + 2);
1941 /* must set all the returned parameters before playing around with the
1942 * data region, since the data region is located past the end of the
1943 * variable number of parameters.
1945 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1947 unsigned char *afterParmsp;
1949 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1951 *afterParmsp++ = dsize & 0xff;
1952 *afterParmsp = (dsize>>8) & 0xff;
1955 /* return the parm'th parameter in the smbp packet */
1956 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1959 unsigned char *parmDatap;
1961 parmCount = *smbp->wctp;
1963 if (parm >= parmCount) {
1968 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1970 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1971 parm, parmCount, smbp->ncb_length);
1974 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1975 1, smbp->ncb_length, ptbuf, smbp);
1976 DeregisterEventSource(h);
1978 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
1979 parm, parmCount, smbp->ncb_length);
1980 osi_panic(s, __FILE__, __LINE__);
1982 parmDatap = smbp->wctp + (2*parm) + 1;
1984 return parmDatap[0] + (parmDatap[1] << 8);
1987 /* return the parm'th parameter in the smbp packet */
1988 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1991 unsigned char *parmDatap;
1993 parmCount = *smbp->wctp;
1995 if (parm * 2 + offset >= parmCount * 2) {
2000 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2002 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2003 parm, offset, parmCount, smbp->ncb_length);
2006 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2007 1, smbp->ncb_length, ptbuf, smbp);
2008 DeregisterEventSource(h);
2010 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2011 parm, offset, parmCount, smbp->ncb_length);
2012 osi_panic(s, __FILE__, __LINE__);
2014 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2016 return parmDatap[0] + (parmDatap[1] << 8);
2019 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2023 /* make sure we have enough slots */
2024 if (*smbp->wctp <= slot)
2025 *smbp->wctp = slot+1;
2027 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2028 *parmDatap++ = parmValue & 0xff;
2029 *parmDatap = (parmValue>>8) & 0xff;
2032 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2036 /* make sure we have enough slots */
2037 if (*smbp->wctp <= slot)
2038 *smbp->wctp = slot+2;
2040 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2041 *parmDatap++ = parmValue & 0xff;
2042 *parmDatap++ = (parmValue>>8) & 0xff;
2043 *parmDatap++ = (parmValue>>16) & 0xff;
2044 *parmDatap++ = (parmValue>>24) & 0xff;
2047 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2052 /* make sure we have enough slots */
2053 if (*smbp->wctp <= slot)
2054 *smbp->wctp = slot+4;
2056 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2058 *parmDatap++ = *parmValuep++;
2061 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2065 /* make sure we have enough slots */
2066 if (*smbp->wctp <= slot) {
2067 if (smbp->oddByte) {
2069 *smbp->wctp = slot+1;
2074 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2075 *parmDatap++ = parmValue & 0xff;
2078 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2082 lastSlashp = strrchr(inPathp, '\\');
2084 *lastComponentp = lastSlashp;
2087 if (inPathp == lastSlashp)
2089 *outPathp++ = *inPathp++;
2098 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2103 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2108 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2114 tlen = inp[0] + (inp[1]<<8);
2115 inp += 2; /* skip length field */
2118 *chainpp = inp + tlen;
2127 /* format a packet as a response */
2128 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2133 outp = (smb_t *) op;
2135 /* zero the basic structure through the smb_wct field, and zero the data
2136 * size field, assuming that wct stays zero; otherwise, you have to
2137 * explicitly set the data size field, too.
2139 inSmbp = (smb_t *) inp;
2140 memset(outp, 0, sizeof(smb_t)+2);
2146 outp->com = inSmbp->com;
2147 outp->tid = inSmbp->tid;
2148 outp->pid = inSmbp->pid;
2149 outp->uid = inSmbp->uid;
2150 outp->mid = inSmbp->mid;
2151 outp->res[0] = inSmbp->res[0];
2152 outp->res[1] = inSmbp->res[1];
2153 op->inCom = inSmbp->com;
2155 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2156 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2158 /* copy fields in generic packet area */
2159 op->wctp = &outp->wct;
2162 /* send a (probably response) packet; vcp tells us to whom to send it.
2163 * we compute the length by looking at wct and bcc fields.
2165 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2182 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2185 memset((char *)ncbp, 0, sizeof(NCB));
2187 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2188 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2189 extra += tp[0] + (tp[1]<<8);
2190 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2191 extra += 3; /* wct and length fields */
2193 ncbp->ncb_length = extra; /* bytes to send */
2194 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2195 ncbp->ncb_lana_num = vcp->lana;
2196 ncbp->ncb_command = NCBSEND; /* op means send data */
2198 ncbp->ncb_buffer = (char *) inp;/* packet */
2199 code = Netbios(ncbp);
2201 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2202 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2204 /* copy header information from virtual to DOS address space */
2205 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2206 code = Netbios(ncbp, dos_ncb);
2210 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2216 void smb_MapNTError(long code, unsigned long *NTStatusp)
2218 unsigned long NTStatus;
2220 /* map CM_ERROR_* errors to NT 32-bit status codes */
2221 /* NT Status codes are listed in ntstatus.h not winerror.h */
2222 if (code == CM_ERROR_NOSUCHCELL) {
2223 NTStatus = 0xC000000FL; /* No such file */
2225 else if (code == CM_ERROR_NOSUCHVOLUME) {
2226 NTStatus = 0xC000000FL; /* No such file */
2228 else if (code == CM_ERROR_TIMEDOUT) {
2229 NTStatus = 0xC00000CFL; /* Sharing Paused */
2231 else if (code == CM_ERROR_RETRY) {
2232 NTStatus = 0xC000022DL; /* Retry */
2234 else if (code == CM_ERROR_NOACCESS) {
2235 NTStatus = 0xC0000022L; /* Access denied */
2237 else if (code == CM_ERROR_READONLY) {
2238 NTStatus = 0xC00000A2L; /* Write protected */
2240 else if (code == CM_ERROR_NOSUCHFILE) {
2241 NTStatus = 0xC000000FL; /* No such file */
2243 else if (code == CM_ERROR_NOSUCHPATH) {
2244 NTStatus = 0xC000003AL; /* Object path not found */
2246 else if (code == CM_ERROR_TOOBIG) {
2247 NTStatus = 0xC000007BL; /* Invalid image format */
2249 else if (code == CM_ERROR_INVAL) {
2250 NTStatus = 0xC000000DL; /* Invalid parameter */
2252 else if (code == CM_ERROR_BADFD) {
2253 NTStatus = 0xC0000008L; /* Invalid handle */
2255 else if (code == CM_ERROR_BADFDOP) {
2256 NTStatus = 0xC0000022L; /* Access denied */
2258 else if (code == CM_ERROR_EXISTS) {
2259 NTStatus = 0xC0000035L; /* Object name collision */
2261 else if (code == CM_ERROR_NOTEMPTY) {
2262 NTStatus = 0xC0000101L; /* Directory not empty */
2264 else if (code == CM_ERROR_CROSSDEVLINK) {
2265 NTStatus = 0xC00000D4L; /* Not same device */
2267 else if (code == CM_ERROR_NOTDIR) {
2268 NTStatus = 0xC0000103L; /* Not a directory */
2270 else if (code == CM_ERROR_ISDIR) {
2271 NTStatus = 0xC00000BAL; /* File is a directory */
2273 else if (code == CM_ERROR_BADOP) {
2275 /* I have no idea where this comes from */
2276 NTStatus = 0xC09820FFL; /* SMB no support */
2278 NTStatus = 0xC00000BBL; /* Not supported */
2279 #endif /* COMMENT */
2281 else if (code == CM_ERROR_BADSHARENAME) {
2282 NTStatus = 0xC00000CCL; /* Bad network name */
2284 else if (code == CM_ERROR_NOIPC) {
2286 NTStatus = 0xC0000022L; /* Access Denied */
2288 NTStatus = 0xC000013DL; /* Remote Resources */
2291 else if (code == CM_ERROR_CLOCKSKEW) {
2292 NTStatus = 0xC0000133L; /* Time difference at DC */
2294 else if (code == CM_ERROR_BADTID) {
2295 NTStatus = 0xC0982005L; /* SMB bad TID */
2297 else if (code == CM_ERROR_USESTD) {
2298 NTStatus = 0xC09820FBL; /* SMB use standard */
2300 else if (code == CM_ERROR_QUOTA) {
2302 NTStatus = 0xC0000044L; /* Quota exceeded */
2304 NTStatus = 0xC000007FL; /* Disk full */
2307 else if (code == CM_ERROR_SPACE) {
2308 NTStatus = 0xC000007FL; /* Disk full */
2310 else if (code == CM_ERROR_ATSYS) {
2311 NTStatus = 0xC0000033L; /* Object name invalid */
2313 else if (code == CM_ERROR_BADNTFILENAME) {
2314 NTStatus = 0xC0000033L; /* Object name invalid */
2316 else if (code == CM_ERROR_WOULDBLOCK) {
2317 NTStatus = 0xC0000055L; /* Lock not granted */
2319 else if (code == CM_ERROR_PARTIALWRITE) {
2320 NTStatus = 0xC000007FL; /* Disk full */
2322 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2323 NTStatus = 0xC0000023L; /* Buffer too small */
2325 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2326 NTStatus = 0xC0000035L; /* Object name collision */
2328 else if (code == CM_ERROR_BADPASSWORD) {
2329 NTStatus = 0xC000006DL; /* unknown username or bad password */
2331 else if (code == CM_ERROR_BADLOGONTYPE) {
2332 NTStatus = 0xC000015BL; /* logon type not granted */
2334 else if (code == CM_ERROR_GSSCONTINUE) {
2335 NTStatus = 0xC0000016L; /* more processing required */
2337 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2339 NTStatus = 0xC0000280L; /* reparse point not resolved */
2341 NTStatus = 0xC0000022L; /* Access Denied */
2344 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2345 NTStatus = 0xC0000257L; /* Path Not Covered */
2347 else if (code == CM_ERROR_ALLBUSY) {
2348 NTStatus = 0xC00000BFL; /* Network Busy */
2350 NTStatus = 0xC0982001L; /* SMB non-specific error */
2353 *NTStatusp = NTStatus;
2354 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2357 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2358 unsigned char *classp)
2360 unsigned char class;
2361 unsigned short error;
2363 /* map CM_ERROR_* errors to SMB errors */
2364 if (code == CM_ERROR_NOSUCHCELL) {
2366 error = 3; /* bad path */
2368 else if (code == CM_ERROR_NOSUCHVOLUME) {
2370 error = 3; /* bad path */
2372 else if (code == CM_ERROR_TIMEDOUT) {
2374 error = 81; /* server is paused */
2376 else if (code == CM_ERROR_RETRY) {
2377 class = 2; /* shouldn't happen */
2380 else if (code == CM_ERROR_NOACCESS) {
2382 error = 4; /* bad access */
2384 else if (code == CM_ERROR_READONLY) {
2386 error = 19; /* read only */
2388 else if (code == CM_ERROR_NOSUCHFILE) {
2390 error = 2; /* ENOENT! */
2392 else if (code == CM_ERROR_NOSUCHPATH) {
2394 error = 3; /* Bad path */
2396 else if (code == CM_ERROR_TOOBIG) {
2398 error = 11; /* bad format */
2400 else if (code == CM_ERROR_INVAL) {
2401 class = 2; /* server non-specific error code */
2404 else if (code == CM_ERROR_BADFD) {
2406 error = 6; /* invalid file handle */
2408 else if (code == CM_ERROR_BADFDOP) {
2409 class = 1; /* invalid op on FD */
2412 else if (code == CM_ERROR_EXISTS) {
2414 error = 80; /* file already exists */
2416 else if (code == CM_ERROR_NOTEMPTY) {
2418 error = 5; /* delete directory not empty */
2420 else if (code == CM_ERROR_CROSSDEVLINK) {
2422 error = 17; /* EXDEV */
2424 else if (code == CM_ERROR_NOTDIR) {
2425 class = 1; /* bad path */
2428 else if (code == CM_ERROR_ISDIR) {
2429 class = 1; /* access denied; DOS doesn't have a good match */
2432 else if (code == CM_ERROR_BADOP) {
2436 else if (code == CM_ERROR_BADSHARENAME) {
2440 else if (code == CM_ERROR_NOIPC) {
2442 error = 4; /* bad access */
2444 else if (code == CM_ERROR_CLOCKSKEW) {
2445 class = 1; /* invalid function */
2448 else if (code == CM_ERROR_BADTID) {
2452 else if (code == CM_ERROR_USESTD) {
2456 else if (code == CM_ERROR_REMOTECONN) {
2460 else if (code == CM_ERROR_QUOTA) {
2461 if (vcp->flags & SMB_VCFLAG_USEV3) {
2463 error = 39; /* disk full */
2467 error = 5; /* access denied */
2470 else if (code == CM_ERROR_SPACE) {
2471 if (vcp->flags & SMB_VCFLAG_USEV3) {
2473 error = 39; /* disk full */
2477 error = 5; /* access denied */
2480 else if (code == CM_ERROR_PARTIALWRITE) {
2482 error = 39; /* disk full */
2484 else if (code == CM_ERROR_ATSYS) {
2486 error = 2; /* ENOENT */
2488 else if (code == CM_ERROR_WOULDBLOCK) {
2490 error = 33; /* lock conflict */
2492 else if (code == CM_ERROR_NOFILES) {
2494 error = 18; /* no files in search */
2496 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2498 error = 183; /* Samba uses this */
2500 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2501 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2503 error = 2; /* bad password */
2505 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2507 error = 3; /* bad path */
2516 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2519 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2521 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2522 return CM_ERROR_BADOP;
2525 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2527 unsigned short EchoCount, i;
2528 char *data, *outdata;
2531 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2533 for (i=1; i<=EchoCount; i++) {
2534 data = smb_GetSMBData(inp, &dataSize);
2535 smb_SetSMBParm(outp, 0, i);
2536 smb_SetSMBDataLength(outp, dataSize);
2537 outdata = smb_GetSMBData(outp, NULL);
2538 memcpy(outdata, data, dataSize);
2539 smb_SendPacket(vcp, outp);
2545 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2548 long count, minCount, finalCount;
2552 cm_user_t *userp = NULL;
2556 char *rawBuf = NULL;
2558 dos_ptr rawBuf = NULL;
2565 fd = smb_GetSMBParm(inp, 0);
2566 count = smb_GetSMBParm(inp, 3);
2567 minCount = smb_GetSMBParm(inp, 4);
2568 offset.HighPart = 0; /* too bad */
2569 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2571 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2572 fd, offset.LowPart, count);
2574 fidp = smb_FindFID(vcp, fd, 0);
2578 lock_ObtainMutex(&smb_RawBufLock);
2580 /* Get a raw buf, from head of list */
2581 rawBuf = smb_RawBufs;
2583 smb_RawBufs = *(char **)smb_RawBufs;
2585 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2588 lock_ReleaseMutex(&smb_RawBufLock);
2592 if (fidp->flags & SMB_FID_IOCTL)
2595 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2597 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2600 /* Give back raw buffer */
2601 lock_ObtainMutex(&smb_RawBufLock);
2603 *((char **) rawBuf) = smb_RawBufs;
2605 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2608 smb_RawBufs = rawBuf;
2609 lock_ReleaseMutex(&smb_RawBufLock);
2612 smb_ReleaseFID(fidp);
2616 userp = smb_GetUser(vcp, inp);
2619 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2621 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2622 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2623 userp, &finalCount, TRUE /* rawFlag */);
2630 cm_ReleaseUser(userp);
2633 smb_ReleaseFID(fidp);
2638 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2640 memset((char *)ncbp, 0, sizeof(NCB));
2642 ncbp->ncb_length = (unsigned short) finalCount;
2643 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2644 ncbp->ncb_lana_num = vcp->lana;
2645 ncbp->ncb_command = NCBSEND;
2646 ncbp->ncb_buffer = rawBuf;
2649 code = Netbios(ncbp);
2651 code = Netbios(ncbp, dos_ncb);
2654 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2657 /* Give back raw buffer */
2658 lock_ObtainMutex(&smb_RawBufLock);
2660 *((char **) rawBuf) = smb_RawBufs;
2662 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2665 smb_RawBufs = rawBuf;
2666 lock_ReleaseMutex(&smb_RawBufLock);
2672 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2674 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2679 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2681 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2686 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2693 int protoIndex; /* index we're using */
2698 char protocol_array[10][1024]; /* protocol signature of the client */
2699 int caps; /* capabilities */
2702 TIME_ZONE_INFORMATION tzi;
2704 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2708 DWORD now = GetCurrentTime();
2709 if (now - last_msg_time >= 30000
2710 && now - last_msg_time <= 90000) {
2712 "Setting dead_vcp %x", active_vcp);
2714 smb_ReleaseVC(dead_vcp);
2716 "Previous dead_vcp %x", dead_vcp);
2718 smb_HoldVC(active_vcp);
2719 dead_vcp = active_vcp;
2720 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2725 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2727 namep = smb_GetSMBData(inp, &dbytes);
2730 coreProtoIndex = -1; /* not found */
2733 while(namex < dbytes) {
2734 osi_Log1(smb_logp, "Protocol %s",
2735 osi_LogSaveString(smb_logp, namep+1));
2736 strcpy(protocol_array[tcounter], namep+1);
2738 /* namep points at the first protocol, or really, a 0x02
2739 * byte preceding the null-terminated ASCII name.
2741 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2742 coreProtoIndex = tcounter;
2744 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2745 v3ProtoIndex = tcounter;
2747 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2748 NTProtoIndex = tcounter;
2751 /* compute size of protocol entry */
2752 entryLength = strlen(namep+1);
2753 entryLength += 2; /* 0x02 bytes and null termination */
2755 /* advance over this protocol entry */
2756 namex += entryLength;
2757 namep += entryLength;
2758 tcounter++; /* which proto entry we're looking at */
2761 if (NTProtoIndex != -1) {
2762 protoIndex = NTProtoIndex;
2763 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2765 else if (v3ProtoIndex != -1) {
2766 protoIndex = v3ProtoIndex;
2767 vcp->flags |= SMB_VCFLAG_USEV3;
2769 else if (coreProtoIndex != -1) {
2770 protoIndex = coreProtoIndex;
2771 vcp->flags |= SMB_VCFLAG_USECORE;
2773 else protoIndex = -1;
2775 if (protoIndex == -1)
2776 return CM_ERROR_INVAL;
2777 else if (NTProtoIndex != -1) {
2778 smb_SetSMBParm(outp, 0, protoIndex);
2779 if (smb_authType != SMB_AUTH_NONE) {
2780 smb_SetSMBParmByte(outp, 1,
2781 NEGOTIATE_SECURITY_USER_LEVEL |
2782 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2784 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2786 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2787 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2788 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2789 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2790 /* The session key is not a well documented field however most clients
2791 * will echo back the session key to the server. Currently we are using
2792 * the same value for all sessions. We should generate a random value
2793 * and store it into the vcp
2795 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2796 smb_SetSMBParm(outp, 8, 1);
2798 * Tried changing the capabilities to support for W2K - defect 117695
2799 * Maybe something else needs to be changed here?
2803 smb_SetSMBParmLong(outp, 9, 0x43fd);
2805 smb_SetSMBParmLong(outp, 9, 0x251);
2808 * 32-bit error codes *
2813 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2815 NTNEGOTIATE_CAPABILITY_DFS |
2817 NTNEGOTIATE_CAPABILITY_NTFIND |
2818 NTNEGOTIATE_CAPABILITY_RAWMODE |
2819 NTNEGOTIATE_CAPABILITY_NTSMB;
2821 if ( smb_authType == SMB_AUTH_EXTENDED )
2822 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2824 smb_SetSMBParmLong(outp, 9, caps);
2826 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2827 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2828 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2830 GetTimeZoneInformation(&tzi);
2831 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2833 if (smb_authType == SMB_AUTH_NTLM) {
2834 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2835 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2836 /* paste in encryption key */
2837 datap = smb_GetSMBData(outp, NULL);
2838 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2839 /* and the faux domain name */
2840 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2841 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2845 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2847 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2849 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2851 datap = smb_GetSMBData(outp, NULL);
2852 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2855 datap += sizeof(smb_ServerGUID);
2856 memcpy(datap, secBlob, secBlobLength);
2860 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2861 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2864 else if (v3ProtoIndex != -1) {
2865 smb_SetSMBParm(outp, 0, protoIndex);
2867 /* NOTE: Extended authentication cannot be negotiated with v3
2868 * therefore we fail over to NTLM
2870 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2871 smb_SetSMBParm(outp, 1,
2872 NEGOTIATE_SECURITY_USER_LEVEL |
2873 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2875 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2877 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2878 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2879 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2880 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2881 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2882 smb_SetSMBParm(outp, 7, 1);
2884 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2885 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2886 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2888 GetTimeZoneInformation(&tzi);
2889 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2891 /* NOTE: Extended authentication cannot be negotiated with v3
2892 * therefore we fail over to NTLM
2894 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2895 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2896 smb_SetSMBParm(outp, 12, 0); /* resvd */
2897 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2898 datap = smb_GetSMBData(outp, NULL);
2899 /* paste in a new encryption key */
2900 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2901 /* and the faux domain name */
2902 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2904 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2905 smb_SetSMBParm(outp, 12, 0); /* resvd */
2906 smb_SetSMBDataLength(outp, 0);
2909 else if (coreProtoIndex != -1) { /* not really supported anymore */
2910 smb_SetSMBParm(outp, 0, protoIndex);
2911 smb_SetSMBDataLength(outp, 0);
2916 void smb_Daemon(void *parmp)
2918 afs_uint32 count = 0;
2920 while(smbShutdownFlag == 0) {
2924 if (smbShutdownFlag == 1)
2927 if ((count % 72) == 0) { /* every five minutes */
2929 time_t old_localZero = smb_localZero;
2931 /* Initialize smb_localZero */
2932 myTime.tm_isdst = -1; /* compute whether on DST or not */
2933 myTime.tm_year = 70;
2939 smb_localZero = mktime(&myTime);
2941 smb_CalculateNowTZ();
2943 #ifdef AFS_FREELANCE
2944 if ( smb_localZero != old_localZero )
2945 cm_noteLocalMountPointChange();
2948 /* XXX GC dir search entries */
2952 void smb_WaitingLocksDaemon()
2954 smb_waitingLock_t *wL, *nwL;
2957 smb_packet_t *inp, *outp;
2961 while (smbShutdownFlag == 0) {
2962 lock_ObtainWrite(&smb_globalLock);
2963 nwL = smb_allWaitingLocks;
2965 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2975 lock_ObtainWrite(&smb_globalLock);
2977 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2978 lock_ReleaseWrite(&smb_globalLock);
2979 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2980 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2981 if (code == CM_ERROR_WOULDBLOCK) {
2983 if (wL->timeRemaining != 0xffffffff
2984 && (wL->timeRemaining -= 1000) < 0)
2994 ncbp->ncb_length = inp->ncb_length;
2995 inp->spacep = cm_GetSpace();
2997 /* Remove waitingLock from list */
2998 lock_ObtainWrite(&smb_globalLock);
2999 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3001 lock_ReleaseWrite(&smb_globalLock);
3003 /* Resume packet processing */
3005 smb_SetSMBDataLength(outp, 0);
3006 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3007 outp->resumeCode = code;
3009 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3012 cm_FreeSpace(inp->spacep);
3013 smb_FreePacket(inp);
3014 smb_FreePacket(outp);
3018 } while (nwL && smbShutdownFlag == 0);
3023 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3025 osi_Log0(smb_logp, "SMB receive get disk attributes");
3027 smb_SetSMBParm(outp, 0, 32000);
3028 smb_SetSMBParm(outp, 1, 64);
3029 smb_SetSMBParm(outp, 2, 1024);
3030 smb_SetSMBParm(outp, 3, 30000);
3031 smb_SetSMBParm(outp, 4, 0);
3032 smb_SetSMBDataLength(outp, 0);
3036 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3040 unsigned short newTid;
3041 char shareName[256];
3049 osi_Log0(smb_logp, "SMB receive tree connect");
3051 /* parse input parameters */
3052 tp = smb_GetSMBData(inp, NULL);
3053 pathp = smb_ParseASCIIBlock(tp, &tp);
3054 if (smb_StoreAnsiFilenames)
3055 OemToChar(pathp,pathp);
3056 passwordp = smb_ParseASCIIBlock(tp, &tp);
3057 tp = strrchr(pathp, '\\');
3059 return CM_ERROR_BADSMB;
3060 strcpy(shareName, tp+1);
3062 userp = smb_GetUser(vcp, inp);
3064 lock_ObtainMutex(&vcp->mx);
3065 newTid = vcp->tidCounter++;
3066 lock_ReleaseMutex(&vcp->mx);
3068 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3069 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3070 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3072 smb_ReleaseUID(uidp);
3074 smb_ReleaseTID(tidp);
3075 return CM_ERROR_BADSHARENAME;
3077 lock_ObtainMutex(&tidp->mx);
3078 tidp->userp = userp;
3079 tidp->pathname = sharePath;
3080 lock_ReleaseMutex(&tidp->mx);
3081 smb_ReleaseTID(tidp);
3083 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3084 smb_SetSMBParm(rsp, 1, newTid);
3085 smb_SetSMBDataLength(rsp, 0);
3087 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3091 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3095 if (*inp++ != 0x1) return NULL;
3096 tlen = inp[0] + (inp[1]<<8);
3097 inp += 2; /* skip length field */
3100 *chainpp = inp + tlen;
3103 if (lengthp) *lengthp = tlen;
3108 /* set maskp to the mask part of the incoming path.
3109 * Mask is 11 bytes long (8.3 with the dot elided).
3110 * Returns true if succeeds with a valid name, otherwise it does
3111 * its best, but returns false.
3113 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3121 /* starts off valid */
3124 /* mask starts out all blanks */
3125 memset(maskp, ' ', 11);
3127 /* find last backslash, or use whole thing if there is none */
3128 tp = strrchr(pathp, '\\');
3129 if (!tp) tp = pathp;
3130 else tp++; /* skip slash */
3134 /* names starting with a dot are illegal */
3135 if (*tp == '.') valid8Dot3 = 0;
3139 if (tc == 0) return valid8Dot3;
3140 if (tc == '.' || tc == '"') break;
3141 if (i < 8) *up++ = tc;
3142 else valid8Dot3 = 0;
3145 /* if we get here, tp point after the dot */
3146 up = maskp+8; /* ext goes here */
3153 if (tc == '.' || tc == '"')
3156 /* copy extension if not too long */
3166 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3176 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3178 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3182 /* otherwise, we have a valid 8.3 name; see if we have a match,
3183 * treating '?' as a wildcard in maskp (but not in the file name).
3185 tp1 = umask; /* real name, in mask format */
3186 tp2 = maskp; /* mask, in mask format */
3187 for(i=0; i<11; i++) {
3188 tc1 = *tp1++; /* char from real name */
3189 tc2 = *tp2++; /* char from mask */
3190 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3191 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3194 if (tc2 == '?' && tc1 != ' ')
3201 /* we got a match */
3205 char *smb_FindMask(char *pathp)
3209 tp = strrchr(pathp, '\\'); /* find last slash */
3212 return tp+1; /* skip the slash */
3214 return pathp; /* no slash, return the entire path */
3217 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3219 unsigned char *pathp;
3221 unsigned char mask[11];
3222 unsigned char *statBlockp;
3223 unsigned char initStatBlock[21];
3226 osi_Log0(smb_logp, "SMB receive search volume");
3228 /* pull pathname and stat block out of request */
3229 tp = smb_GetSMBData(inp, NULL);
3230 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3231 osi_assert(pathp != NULL);
3232 if (smb_StoreAnsiFilenames)
3233 OemToChar(pathp,pathp);
3234 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3235 osi_assert(statBlockp != NULL);
3237 statBlockp = initStatBlock;
3241 /* for returning to caller */
3242 smb_Get8Dot3MaskFromPath(mask, pathp);
3244 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3245 tp = smb_GetSMBData(outp, NULL);
3247 *tp++ = 43; /* bytes in a dir entry */
3248 *tp++ = 0; /* high byte in counter */
3250 /* now marshall the dir entry, starting with the search status */
3251 *tp++ = statBlockp[0]; /* Reserved */
3252 memcpy(tp, mask, 11); tp += 11; /* FileName */
3254 /* now pass back server use info, with 1st byte non-zero */
3256 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3258 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3260 *tp++ = 0x8; /* attribute: volume */
3270 /* 4 byte file size */
3276 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3277 memset(tp, ' ', 13);
3280 /* set the length of the data part of the packet to 43 + 3, for the dir
3281 * entry plus the 5 and the length fields.
3283 smb_SetSMBDataLength(outp, 46);
3287 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3288 cm_user_t *userp, cm_req_t *reqp)
3296 smb_dirListPatch_t *patchp;
3297 smb_dirListPatch_t *npatchp;
3299 for (patchp = *dirPatchespp; patchp; patchp =
3300 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3302 dptr = patchp->dptr;
3304 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3306 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3307 *dptr++ = SMB_ATTR_HIDDEN;
3310 lock_ObtainMutex(&scp->mx);
3311 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3312 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3314 lock_ReleaseMutex(&scp->mx);
3315 cm_ReleaseSCache(scp);
3316 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3317 *dptr++ = SMB_ATTR_HIDDEN;
3321 attr = smb_Attributes(scp);
3322 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3323 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3324 attr |= SMB_ATTR_HIDDEN;
3328 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3331 shortTemp = (unsigned short) (dosTime & 0xffff);
3332 *((u_short *)dptr) = shortTemp;
3335 /* and copy out date */
3336 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3337 *((u_short *)dptr) = shortTemp;
3340 /* copy out file length */
3341 *((u_long *)dptr) = scp->length.LowPart;
3343 lock_ReleaseMutex(&scp->mx);
3344 cm_ReleaseSCache(scp);
3347 /* now free the patches */
3348 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3349 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3353 /* and mark the list as empty */
3354 *dirPatchespp = NULL;
3359 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3368 smb_dirListPatch_t *dirListPatchesp;
3369 smb_dirListPatch_t *curPatchp;
3373 osi_hyper_t dirLength;
3374 osi_hyper_t bufferOffset;
3375 osi_hyper_t curOffset;
3377 unsigned char *inCookiep;
3378 smb_dirSearch_t *dsp;
3382 unsigned long clientCookie;
3383 cm_pageHeader_t *pageHeaderp;
3384 cm_user_t *userp = NULL;
3391 long nextEntryCookie;
3392 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3393 char resByte; /* reserved byte from the cookie */
3394 char *op; /* output data ptr */
3395 char *origOp; /* original value of op */
3396 cm_space_t *spacep; /* for pathname buffer */
3407 maxCount = smb_GetSMBParm(inp, 0);
3409 dirListPatchesp = NULL;
3411 caseFold = CM_FLAG_CASEFOLD;
3413 tp = smb_GetSMBData(inp, NULL);
3414 pathp = smb_ParseASCIIBlock(tp, &tp);
3415 if (smb_StoreAnsiFilenames)
3416 OemToChar(pathp,pathp);
3417 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3419 /* bail out if request looks bad */
3420 if (!tp || !pathp) {
3421 return CM_ERROR_BADSMB;
3424 /* We can handle long names */
3425 if (vcp->flags & SMB_VCFLAG_USENT)
3426 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3428 /* make sure we got a whole search status */
3429 if (dataLength < 21) {
3430 nextCookie = 0; /* start at the beginning of the dir */
3433 attribute = smb_GetSMBParm(inp, 1);
3435 /* handle volume info in another function */
3436 if (attribute & 0x8)
3437 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3439 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3440 maxCount, osi_LogSaveString(smb_logp, pathp));
3442 if (*pathp == 0) { /* null pathp, treat as root dir */
3443 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3444 return CM_ERROR_NOFILES;
3448 dsp = smb_NewDirSearch(0);
3449 dsp->attribute = attribute;
3450 smb_Get8Dot3MaskFromPath(mask, pathp);
3451 memcpy(dsp->mask, mask, 11);
3453 /* track if this is likely to match a lot of entries */
3454 if (smb_IsStarMask(mask))
3459 /* pull the next cookie value out of the search status block */
3460 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3461 + (inCookiep[16]<<24);
3462 dsp = smb_FindDirSearch(inCookiep[12]);
3464 /* can't find dir search status; fatal error */
3465 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3466 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3467 return CM_ERROR_BADFD;
3469 attribute = dsp->attribute;
3470 resByte = inCookiep[0];
3472 /* copy out client cookie, in host byte order. Don't bother
3473 * interpreting it, since we're just passing it through, anyway.
3475 memcpy(&clientCookie, &inCookiep[17], 4);
3477 memcpy(mask, dsp->mask, 11);
3479 /* assume we're doing a star match if it has continued for more
3485 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3486 nextCookie, dsp->cookie, attribute);
3488 userp = smb_GetUser(vcp, inp);
3490 /* try to get the vnode for the path name next */
3491 lock_ObtainMutex(&dsp->mx);
3497 spacep = inp->spacep;
3498 smb_StripLastComponent(spacep->data, NULL, pathp);
3499 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3501 lock_ReleaseMutex(&dsp->mx);
3502 cm_ReleaseUser(userp);
3503 smb_DeleteDirSearch(dsp);
3504 smb_ReleaseDirSearch(dsp);
3505 return CM_ERROR_NOFILES;
3507 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3508 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3511 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3512 cm_ReleaseSCache(scp);
3513 lock_ReleaseMutex(&dsp->mx);
3514 cm_ReleaseUser(userp);
3515 smb_DeleteDirSearch(dsp);
3516 smb_ReleaseDirSearch(dsp);
3517 if ( WANTS_DFS_PATHNAMES(inp) )
3518 return CM_ERROR_PATH_NOT_COVERED;
3520 return CM_ERROR_BADSHARENAME;
3522 #endif /* DFS_SUPPORT */
3525 /* we need one hold for the entry we just stored into,
3526 * and one for our own processing. When we're done with this
3527 * function, we'll drop the one for our own processing.
3528 * We held it once from the namei call, and so we do another hold
3532 lock_ObtainMutex(&scp->mx);
3533 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3534 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3535 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3536 dsp->flags |= SMB_DIRSEARCH_BULKST;
3538 lock_ReleaseMutex(&scp->mx);
3541 lock_ReleaseMutex(&dsp->mx);
3543 cm_ReleaseUser(userp);
3544 smb_DeleteDirSearch(dsp);
3545 smb_ReleaseDirSearch(dsp);
3549 /* reserves space for parameter; we'll adjust it again later to the
3550 * real count of the # of entries we returned once we've actually
3551 * assembled the directory listing.
3553 smb_SetSMBParm(outp, 0, 0);
3555 /* get the directory size */
3556 lock_ObtainMutex(&scp->mx);
3557 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3558 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3560 lock_ReleaseMutex(&scp->mx);
3561 cm_ReleaseSCache(scp);
3562 cm_ReleaseUser(userp);
3563 smb_DeleteDirSearch(dsp);
3564 smb_ReleaseDirSearch(dsp);
3568 dirLength = scp->length;
3570 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3571 curOffset.HighPart = 0;
3572 curOffset.LowPart = nextCookie;
3573 origOp = op = smb_GetSMBData(outp, NULL);
3574 /* and write out the basic header */
3575 *op++ = 5; /* variable block */
3576 op += 2; /* skip vbl block length; we'll fill it in later */
3580 /* make sure that curOffset.LowPart doesn't point to the first
3581 * 32 bytes in the 2nd through last dir page, and that it doesn't
3582 * point at the first 13 32-byte chunks in the first dir page,
3583 * since those are dir and page headers, and don't contain useful
3586 temp = curOffset.LowPart & (2048-1);
3587 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3588 /* we're in the first page */
3589 if (temp < 13*32) temp = 13*32;
3592 /* we're in a later dir page */
3593 if (temp < 32) temp = 32;
3596 /* make sure the low order 5 bits are zero */
3599 /* now put temp bits back ito curOffset.LowPart */
3600 curOffset.LowPart &= ~(2048-1);
3601 curOffset.LowPart |= temp;
3603 /* check if we've returned all the names that will fit in the
3606 if (returnedNames >= maxCount) {
3607 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3608 returnedNames, maxCount);
3612 /* check if we've passed the dir's EOF */
3613 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3615 /* see if we can use the bufferp we have now; compute in which page
3616 * the current offset would be, and check whether that's the offset
3617 * of the buffer we have. If not, get the buffer.
3619 thyper.HighPart = curOffset.HighPart;
3620 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3621 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3624 buf_Release(bufferp);
3627 lock_ReleaseMutex(&scp->mx);
3628 lock_ObtainRead(&scp->bufCreateLock);
3629 code = buf_Get(scp, &thyper, &bufferp);
3630 lock_ReleaseRead(&scp->bufCreateLock);
3631 lock_ObtainMutex(&dsp->mx);
3633 /* now, if we're doing a star match, do bulk fetching of all of
3634 * the status info for files in the dir.
3637 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3638 lock_ObtainMutex(&scp->mx);
3639 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3640 LargeIntegerGreaterThanOrEqualTo(thyper,
3641 scp->bulkStatProgress)) {
3642 /* Don't bulk stat if risking timeout */
3643 int now = GetCurrentTime();
3644 if (now - req.startTime > 5000) {
3645 scp->bulkStatProgress = thyper;
3646 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3647 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3649 cm_TryBulkStat(scp, &thyper, userp, &req);
3652 lock_ObtainMutex(&scp->mx);
3654 lock_ReleaseMutex(&dsp->mx);
3656 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3660 bufferOffset = thyper;
3662 /* now get the data in the cache */
3664 code = cm_SyncOp(scp, bufferp, userp, &req,
3666 CM_SCACHESYNC_NEEDCALLBACK |
3667 CM_SCACHESYNC_READ);
3669 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3673 if (cm_HaveBuffer(scp, bufferp, 0)) {
3674 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3678 /* otherwise, load the buffer and try again */
3679 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3681 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3682 scp, bufferp, code);
3687 buf_Release(bufferp);
3691 } /* if (wrong buffer) ... */
3693 /* now we have the buffer containing the entry we're interested in; copy
3694 * it out if it represents a non-deleted entry.
3696 entryInDir = curOffset.LowPart & (2048-1);
3697 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3699 /* page header will help tell us which entries are free. Page header
3700 * can change more often than once per buffer, since AFS 3 dir page size
3701 * may be less than (but not more than a buffer package buffer.
3703 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3704 temp &= ~(2048 - 1); /* turn off intra-page bits */
3705 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3707 /* now determine which entry we're looking at in the page. If it is
3708 * free (there's a free bitmap at the start of the dir), we should
3709 * skip these 32 bytes.
3711 slotInPage = (entryInDir & 0x7e0) >> 5;
3712 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3713 /* this entry is free */
3714 numDirChunks = 1; /* only skip this guy */
3718 tp = bufferp->datap + entryInBuffer;
3719 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3721 /* while we're here, compute the next entry's location, too,
3722 * since we'll need it when writing out the cookie into the dir
3725 * XXXX Probably should do more sanity checking.
3727 numDirChunks = cm_NameEntries(dep->name, NULL);
3729 /* compute the offset of the cookie representing the next entry */
3730 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3732 /* Compute 8.3 name if necessary */
3733 actualName = dep->name;
3734 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3735 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3736 actualName = shortName;
3739 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3740 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3741 osi_LogSaveString(smb_logp, actualName));
3743 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3744 /* this is one of the entries to use: it is not deleted
3745 * and it matches the star pattern we're looking for.
3748 /* Eliminate entries that don't match requested
3751 /* no hidden files */
3752 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3753 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3757 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3759 /* We have already done the cm_TryBulkStat above */
3760 fid.cell = scp->fid.cell;
3761 fid.volume = scp->fid.volume;
3762 fid.vnode = ntohl(dep->fid.vnode);
3763 fid.unique = ntohl(dep->fid.unique);
3764 fileType = cm_FindFileType(&fid);
3765 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3766 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3768 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3769 fileType == CM_SCACHETYPE_DFSLINK ||
3770 fileType == CM_SCACHETYPE_INVALID)
3771 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3776 memcpy(op, mask, 11); op += 11;
3777 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3778 *op++ = nextEntryCookie & 0xff;
3779 *op++ = (nextEntryCookie>>8) & 0xff;
3780 *op++ = (nextEntryCookie>>16) & 0xff;
3781 *op++ = (nextEntryCookie>>24) & 0xff;
3782 memcpy(op, &clientCookie, 4); op += 4;
3784 /* now we emit the attribute. This is sort of tricky,
3785 * since we need to really stat the file to find out
3786 * what type of entry we've got. Right now, we're
3787 * copying out data from a buffer, while holding the
3788 * scp locked, so it isn't really convenient to stat
3789 * something now. We'll put in a place holder now,
3790 * and make a second pass before returning this to get
3791 * the real attributes. So, we just skip the data for
3792 * now, and adjust it later. We allocate a patch
3793 * record to make it easy to find this point later.
3794 * The replay will happen at a time when it is safe to
3795 * unlock the directory.
3797 curPatchp = malloc(sizeof(*curPatchp));
3798 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3799 curPatchp->dptr = op;
3800 curPatchp->fid.cell = scp->fid.cell;
3801 curPatchp->fid.volume = scp->fid.volume;
3802 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3803 curPatchp->fid.unique = ntohl(dep->fid.unique);
3805 /* do hidden attribute here since name won't be around when applying
3809 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3810 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3812 curPatchp->flags = 0;
3814 op += 9; /* skip attr, time, date and size */
3816 /* zero out name area. The spec says to pad with
3817 * spaces, but Samba doesn't, and neither do we.
3821 /* finally, we get to copy out the name; we know that
3822 * it fits in 8.3 or the pattern wouldn't match, but it
3823 * never hurts to be sure.
3825 strncpy(op, actualName, 13);
3826 if (smb_StoreAnsiFilenames)
3829 /* Uppercase if requested by client */
3830 if (!KNOWS_LONG_NAMES(inp))
3835 /* now, adjust the # of entries copied */
3837 } /* if we're including this name */
3840 /* and adjust curOffset to be where the new cookie is */
3841 thyper.HighPart = 0;
3842 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3843 curOffset = LargeIntegerAdd(thyper, curOffset);
3844 } /* while copying data for dir listing */
3846 /* release the mutex */
3847 lock_ReleaseMutex(&scp->mx);
3848 if (bufferp) buf_Release(bufferp);
3850 /* apply and free last set of patches; if not doing a star match, this
3851 * will be empty, but better safe (and freeing everything) than sorry.
3853 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3855 /* special return code for unsuccessful search */
3856 if (code == 0 && dataLength < 21 && returnedNames == 0)
3857 code = CM_ERROR_NOFILES;
3859 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3860 returnedNames, code);
3863 smb_DeleteDirSearch(dsp);
3864 smb_ReleaseDirSearch(dsp);
3865 cm_ReleaseSCache(scp);
3866 cm_ReleaseUser(userp);
3870 /* finalize the output buffer */
3871 smb_SetSMBParm(outp, 0, returnedNames);
3872 temp = (long) (op - origOp);
3873 smb_SetSMBDataLength(outp, temp);
3875 /* the data area is a variable block, which has a 5 (already there)
3876 * followed by the length of the # of data bytes. We now know this to
3877 * be "temp," although that includes the 3 bytes of vbl block header.
3878 * Deduct for them and fill in the length field.
3880 temp -= 3; /* deduct vbl block info */
3881 osi_assert(temp == (43 * returnedNames));
3882 origOp[1] = temp & 0xff;
3883 origOp[2] = (temp>>8) & 0xff;
3884 if (returnedNames == 0)
3885 smb_DeleteDirSearch(dsp);
3886 smb_ReleaseDirSearch(dsp);
3887 cm_ReleaseSCache(scp);
3888 cm_ReleaseUser(userp);
3892 /* verify that this is a valid path to a directory. I don't know why they
3893 * don't use the get file attributes call.
3895 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3899 cm_scache_t *rootScp;
3900 cm_scache_t *newScp;
3909 pathp = smb_GetSMBData(inp, NULL);
3910 pathp = smb_ParseASCIIBlock(pathp, NULL);
3912 return CM_ERROR_BADFD;
3913 if (smb_StoreAnsiFilenames)
3914 OemToChar(pathp,pathp);
3915 osi_Log1(smb_logp, "SMB receive check path %s",
3916 osi_LogSaveString(smb_logp, pathp));
3918 rootScp = cm_data.rootSCachep;
3920 userp = smb_GetUser(vcp, inp);
3922 caseFold = CM_FLAG_CASEFOLD;
3924 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3926 cm_ReleaseUser(userp);
3927 return CM_ERROR_NOSUCHPATH;
3929 code = cm_NameI(rootScp, pathp,
3930 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3931 userp, tidPathp, &req, &newScp);
3934 cm_ReleaseUser(userp);
3939 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
3940 cm_ReleaseSCache(newScp);
3941 cm_ReleaseUser(userp);
3942 if ( WANTS_DFS_PATHNAMES(inp) )
3943 return CM_ERROR_PATH_NOT_COVERED;
3945 return CM_ERROR_BADSHARENAME;
3947 #endif /* DFS_SUPPORT */
3949 /* now lock the vnode with a callback; returns with newScp locked */
3950 lock_ObtainMutex(&newScp->mx);
3951 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3952 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3953 if (code && code != CM_ERROR_NOACCESS) {
3954 lock_ReleaseMutex(&newScp->mx);
3955 cm_ReleaseSCache(newScp);
3956 cm_ReleaseUser(userp);
3960 attrs = smb_Attributes(newScp);
3962 if (!(attrs & SMB_ATTR_DIRECTORY))
3963 code = CM_ERROR_NOTDIR;
3965 lock_ReleaseMutex(&newScp->mx);
3967 cm_ReleaseSCache(newScp);
3968 cm_ReleaseUser(userp);
3972 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3976 cm_scache_t *rootScp;
3977 unsigned short attribute;
3979 cm_scache_t *newScp;
3988 /* decode basic attributes we're passed */
3989 attribute = smb_GetSMBParm(inp, 0);
3990 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3992 pathp = smb_GetSMBData(inp, NULL);
3993 pathp = smb_ParseASCIIBlock(pathp, NULL);
3995 return CM_ERROR_BADSMB;
3996 if (smb_StoreAnsiFilenames)
3997 OemToChar(pathp,pathp);
3999 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4000 dosTime, attribute);
4002 rootScp = cm_data.rootSCachep;
4004 userp = smb_GetUser(vcp, inp);
4006 caseFold = CM_FLAG_CASEFOLD;
4008 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4010 cm_ReleaseUser(userp);
4011 return CM_ERROR_NOSUCHFILE;
4013 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4014 tidPathp, &req, &newScp);
4017 cm_ReleaseUser(userp);
4022 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4023 cm_ReleaseSCache(newScp);
4024 cm_ReleaseUser(userp);
4025 if ( WANTS_DFS_PATHNAMES(inp) )
4026 return CM_ERROR_PATH_NOT_COVERED;
4028 return CM_ERROR_BADSHARENAME;
4030 #endif /* DFS_SUPPORT */
4032 /* now lock the vnode with a callback; returns with newScp locked; we
4033 * need the current status to determine what the new status is, in some
4036 lock_ObtainMutex(&newScp->mx);
4037 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4038 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4040 lock_ReleaseMutex(&newScp->mx);
4041 cm_ReleaseSCache(newScp);
4042 cm_ReleaseUser(userp);
4046 /* Check for RO volume */
4047 if (newScp->flags & CM_SCACHEFLAG_RO) {
4048 lock_ReleaseMutex(&newScp->mx);
4049 cm_ReleaseSCache(newScp);
4050 cm_ReleaseUser(userp);
4051 return CM_ERROR_READONLY;
4054 /* prepare for setattr call */
4057 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4058 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4060 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4061 /* we're told to make a writable file read-only */
4062 attr.unixModeBits = newScp->unixModeBits & ~0222;
4063 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4065 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4066 /* we're told to make a read-only file writable */
4067 attr.unixModeBits = newScp->unixModeBits | 0222;
4068 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4070 lock_ReleaseMutex(&newScp->mx);
4072 /* now call setattr */
4074 code = cm_SetAttr(newScp, &attr, userp, &req);
4078 cm_ReleaseSCache(newScp);
4079 cm_ReleaseUser(userp);
4084 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4088 cm_scache_t *rootScp;
4089 cm_scache_t *newScp, *dscp;
4101 pathp = smb_GetSMBData(inp, NULL);
4102 pathp = smb_ParseASCIIBlock(pathp, NULL);
4104 return CM_ERROR_BADSMB;
4106 if (*pathp == 0) /* null path */
4109 if (smb_StoreAnsiFilenames)
4110 OemToChar(pathp,pathp);
4112 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4113 osi_LogSaveString(smb_logp, pathp));
4115 rootScp = cm_data.rootSCachep;
4117 userp = smb_GetUser(vcp, inp);
4119 /* we shouldn't need this for V3 requests, but we seem to */
4120 caseFold = CM_FLAG_CASEFOLD;
4122 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4124 cm_ReleaseUser(userp);
4125 return CM_ERROR_NOSUCHFILE;
4129 * XXX Strange hack XXX
4131 * As of Patch 5 (16 July 97), we are having the following problem:
4132 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4133 * requests to look up "desktop.ini" in all the subdirectories.
4134 * This can cause zillions of timeouts looking up non-existent cells
4135 * and volumes, especially in the top-level directory.
4137 * We have not found any way to avoid this or work around it except
4138 * to explicitly ignore the requests for mount points that haven't
4139 * yet been evaluated and for directories that haven't yet been
4142 * We should modify this hack to provide a fake desktop.ini file
4143 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4145 spacep = inp->spacep;
4146 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4147 #ifndef SPECIAL_FOLDERS
4148 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4149 code = cm_NameI(rootScp, spacep->data,
4150 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4151 userp, tidPathp, &req, &dscp);
4154 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4155 if ( WANTS_DFS_PATHNAMES(inp) )
4156 return CM_ERROR_PATH_NOT_COVERED;
4158 return CM_ERROR_BADSHARENAME;
4160 #endif /* DFS_SUPPORT */
4161 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4162 code = CM_ERROR_NOSUCHFILE;
4163 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4164 cm_buf_t *bp = buf_Find(dscp, &hzero);
4168 code = CM_ERROR_NOSUCHFILE;
4170 cm_ReleaseSCache(dscp);
4172 cm_ReleaseUser(userp);
4177 #endif /* SPECIAL_FOLDERS */
4179 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4180 tidPathp, &req, &newScp);
4182 cm_ReleaseUser(userp);
4187 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4188 cm_ReleaseSCache(newScp);
4189 cm_ReleaseUser(userp);
4190 if ( WANTS_DFS_PATHNAMES(inp) )
4191 return CM_ERROR_PATH_NOT_COVERED;
4193 return CM_ERROR_BADSHARENAME;
4195 #endif /* DFS_SUPPORT */
4197 /* now lock the vnode with a callback; returns with newScp locked */
4198 lock_ObtainMutex(&newScp->mx);
4199 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4200 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4202 lock_ReleaseMutex(&newScp->mx);
4203 cm_ReleaseSCache(newScp);
4204 cm_ReleaseUser(userp);
4209 /* use smb_Attributes instead. Also the fact that a file is
4210 * in a readonly volume doesn't mean it shojuld be marked as RO
4212 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4213 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4214 attrs = SMB_ATTR_DIRECTORY;
4217 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4218 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4220 attrs = smb_Attributes(newScp);
4223 smb_SetSMBParm(outp, 0, attrs);
4225 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4226 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4227 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4228 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4229 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4230 smb_SetSMBParm(outp, 5, 0);
4231 smb_SetSMBParm(outp, 6, 0);
4232 smb_SetSMBParm(outp, 7, 0);
4233 smb_SetSMBParm(outp, 8, 0);
4234 smb_SetSMBParm(outp, 9, 0);
4235 smb_SetSMBDataLength(outp, 0);
4236 lock_ReleaseMutex(&newScp->mx);
4238 cm_ReleaseSCache(newScp);
4239 cm_ReleaseUser(userp);
4244 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4248 osi_Log0(smb_logp, "SMB receive tree disconnect");
4250 /* find the tree and free it */
4251 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4253 lock_ObtainMutex(&tidp->mx);
4254 tidp->flags |= SMB_TIDFLAG_DELETE;
4255 lock_ReleaseMutex(&tidp->mx);
4256 smb_ReleaseTID(tidp);
4262 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4280 pathp = smb_GetSMBData(inp, NULL);
4281 pathp = smb_ParseASCIIBlock(pathp, NULL);
4282 if (smb_StoreAnsiFilenames)
4283 OemToChar(pathp,pathp);
4285 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4287 #ifdef DEBUG_VERBOSE
4291 hexpath = osi_HexifyString( pathp );
4292 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4297 share = smb_GetSMBParm(inp, 0);
4298 attribute = smb_GetSMBParm(inp, 1);
4300 spacep = inp->spacep;
4301 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4302 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4303 /* special case magic file name for receiving IOCTL requests
4304 * (since IOCTL calls themselves aren't getting through).
4306 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4307 smb_SetupIoctlFid(fidp, spacep);
4308 smb_SetSMBParm(outp, 0, fidp->fid);
4309 smb_SetSMBParm(outp, 1, 0); /* attrs */
4310 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4311 smb_SetSMBParm(outp, 3, 0);
4312 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4313 smb_SetSMBParm(outp, 5, 0x7fff);
4314 /* pass the open mode back */
4315 smb_SetSMBParm(outp, 6, (share & 0xf));
4316 smb_SetSMBDataLength(outp, 0);
4317 smb_ReleaseFID(fidp);
4321 userp = smb_GetUser(vcp, inp);
4323 caseFold = CM_FLAG_CASEFOLD;
4325 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4327 cm_ReleaseUser(userp);
4328 return CM_ERROR_NOSUCHPATH;
4330 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4331 tidPathp, &req, &scp);
4334 cm_ReleaseUser(userp);
4339 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4340 cm_ReleaseSCache(scp);
4341 cm_ReleaseUser(userp);
4342 if ( WANTS_DFS_PATHNAMES(inp) )
4343 return CM_ERROR_PATH_NOT_COVERED;
4345 return CM_ERROR_BADSHARENAME;
4347 #endif /* DFS_SUPPORT */
4349 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4351 cm_ReleaseSCache(scp);
4352 cm_ReleaseUser(userp);
4356 /* don't need callback to check file type, since file types never
4357 * change, and namei and cm_Lookup all stat the object at least once on
4358 * a successful return.
4360 if (scp->fileType != CM_SCACHETYPE_FILE) {
4361 cm_ReleaseSCache(scp);
4362 cm_ReleaseUser(userp);
4363 return CM_ERROR_ISDIR;
4366 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4369 /* save a pointer to the vnode */
4372 if ((share & 0xf) == 0)
4373 fidp->flags |= SMB_FID_OPENREAD;
4374 else if ((share & 0xf) == 1)
4375 fidp->flags |= SMB_FID_OPENWRITE;
4377 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4379 lock_ObtainMutex(&scp->mx);
4380 smb_SetSMBParm(outp, 0, fidp->fid);
4381 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4382 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4383 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4384 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4385 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4386 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4387 /* pass the open mode back; XXXX add access checks */
4388 smb_SetSMBParm(outp, 6, (share & 0xf));
4389 smb_SetSMBDataLength(outp, 0);
4390 lock_ReleaseMutex(&scp->mx);
4393 cm_Open(scp, 0, userp);
4395 /* send and free packet */
4396 smb_ReleaseFID(fidp);
4397 cm_ReleaseUser(userp);
4398 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4402 typedef struct smb_unlinkRock {
4407 char *maskp; /* pointer to the star pattern */
4412 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4415 smb_unlinkRock_t *rockp;
4423 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4424 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4425 caseFold |= CM_FLAG_8DOT3;
4427 matchName = dep->name;
4428 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4430 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4431 !cm_Is8Dot3(dep->name)) {
4432 cm_Gen8Dot3Name(dep, shortName, NULL);
4433 matchName = shortName;
4434 /* 8.3 matches are always case insensitive */
4435 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4438 osi_Log1(smb_logp, "Unlinking %s",
4439 osi_LogSaveString(smb_logp, matchName));
4440 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4441 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4442 smb_NotifyChange(FILE_ACTION_REMOVED,
4443 FILE_NOTIFY_CHANGE_FILE_NAME,
4444 dscp, dep->name, NULL, TRUE);
4448 /* If we made a case sensitive exact match, we might as well quit now. */
4449 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4450 code = CM_ERROR_STOPNOW;
4458 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4467 smb_unlinkRock_t rock;
4476 attribute = smb_GetSMBParm(inp, 0);
4478 tp = smb_GetSMBData(inp, NULL);
4479 pathp = smb_ParseASCIIBlock(tp, &tp);
4480 if (smb_StoreAnsiFilenames)
4481 OemToChar(pathp,pathp);
4483 osi_Log1(smb_logp, "SMB receive unlink %s",
4484 osi_LogSaveString(smb_logp, pathp));
4486 spacep = inp->spacep;
4487 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4489 userp = smb_GetUser(vcp, inp);
4491 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4493 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4495 cm_ReleaseUser(userp);
4496 return CM_ERROR_NOSUCHPATH;
4498 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4501 cm_ReleaseUser(userp);
4506 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4507 cm_ReleaseSCache(dscp);
4508 cm_ReleaseUser(userp);
4509 if ( WANTS_DFS_PATHNAMES(inp) )
4510 return CM_ERROR_PATH_NOT_COVERED;
4512 return CM_ERROR_BADSHARENAME;
4514 #endif /* DFS_SUPPORT */
4516 /* otherwise, scp points to the parent directory. */
4523 rock.maskp = smb_FindMask(pathp);
4524 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4527 thyper.HighPart = 0;
4533 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4534 * match. If that fails, we do a case insensitve match.
4536 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4537 !smb_IsStarMask(rock.maskp)) {
4538 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4541 thyper.HighPart = 0;
4542 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4547 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4549 if (code == CM_ERROR_STOPNOW)
4552 cm_ReleaseUser(userp);
4554 cm_ReleaseSCache(dscp);
4556 if (code == 0 && !rock.any)
4557 code = CM_ERROR_NOSUCHFILE;
4561 typedef struct smb_renameRock {
4562 cm_scache_t *odscp; /* old dir */
4563 cm_scache_t *ndscp; /* new dir */
4564 cm_user_t *userp; /* user */
4565 cm_req_t *reqp; /* request struct */
4566 smb_vc_t *vcp; /* virtual circuit */
4567 char *maskp; /* pointer to star pattern of old file name */
4568 int flags; /* tilde, casefold, etc */
4569 char *newNamep; /* ptr to the new file's name */
4572 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4575 smb_renameRock_t *rockp;
4580 rockp = (smb_renameRock_t *) vrockp;
4582 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4583 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4584 caseFold |= CM_FLAG_8DOT3;
4586 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4588 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4589 !cm_Is8Dot3(dep->name)) {
4590 cm_Gen8Dot3Name(dep, shortName, NULL);
4591 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4594 code = cm_Rename(rockp->odscp, dep->name,
4595 rockp->ndscp, rockp->newNamep, rockp->userp,
4597 /* if the call worked, stop doing the search now, since we
4598 * really only want to rename one file.
4601 code = CM_ERROR_STOPNOW;
4610 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4613 cm_space_t *spacep = NULL;
4614 smb_renameRock_t rock;
4615 cm_scache_t *oldDscp = NULL;
4616 cm_scache_t *newDscp = NULL;
4617 cm_scache_t *tmpscp= NULL;
4618 cm_scache_t *tmpscp2 = NULL;
4628 userp = smb_GetUser(vcp, inp);
4629 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4631 cm_ReleaseUser(userp);
4632 return CM_ERROR_NOSUCHPATH;
4636 spacep = inp->spacep;
4637 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4640 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4641 * what actually exists is foo/baz. I don't know why the code used to be
4642 * the way it was. 1/29/96
4644 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4646 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4648 * caseFold = CM_FLAG_CASEFOLD;
4650 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4651 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4652 userp, tidPathp, &req, &oldDscp);
4654 cm_ReleaseUser(userp);
4659 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4660 cm_ReleaseSCache(oldDscp);
4661 cm_ReleaseUser(userp);
4662 if ( WANTS_DFS_PATHNAMES(inp) )
4663 return CM_ERROR_PATH_NOT_COVERED;
4665 return CM_ERROR_BADSHARENAME;
4667 #endif /* DFS_SUPPORT */
4669 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4670 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4671 userp, tidPathp, &req, &newDscp);
4674 cm_ReleaseSCache(oldDscp);
4675 cm_ReleaseUser(userp);
4680 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4681 cm_ReleaseSCache(oldDscp);
4682 cm_ReleaseSCache(newDscp);
4683 cm_ReleaseUser(userp);
4684 if ( WANTS_DFS_PATHNAMES(inp) )
4685 return CM_ERROR_PATH_NOT_COVERED;
4687 return CM_ERROR_BADSHARENAME;
4689 #endif /* DFS_SUPPORT */
4692 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4693 * next, get the component names, and lower case them.
4696 /* handle the old name first */
4698 oldLastNamep = oldPathp;
4702 /* and handle the new name, too */
4704 newLastNamep = newPathp;
4708 /* TODO: The old name could be a wildcard. The new name must not be */
4710 /* do the vnode call */
4711 rock.odscp = oldDscp;
4712 rock.ndscp = newDscp;
4716 rock.maskp = oldLastNamep;
4717 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4718 rock.newNamep = newLastNamep;
4720 /* Check if the file already exists; if so return error */
4721 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4722 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4723 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4724 osi_LogSaveString(afsd_logp, newLastNamep));
4726 /* Check if the old and the new names differ only in case. If so return
4727 * success, else return CM_ERROR_EXISTS
4729 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4731 /* This would be a success only if the old file is *as same as* the new file */
4732 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4734 if (tmpscp == tmpscp2)
4737 code = CM_ERROR_EXISTS;
4738 cm_ReleaseSCache(tmpscp2);
4741 code = CM_ERROR_NOSUCHFILE;
4744 /* file exist, do not rename, also fixes move */
4745 osi_Log0(smb_logp, "Can't rename. Target already exists");
4746 code = CM_ERROR_EXISTS;
4750 cm_ReleaseSCache(tmpscp);
4751 cm_ReleaseSCache(newDscp);
4752 cm_ReleaseSCache(oldDscp);
4753 cm_ReleaseUser(userp);
4757 /* Now search the directory for the pattern, and do the appropriate rename when found */
4758 thyper.LowPart = 0; /* search dir from here */
4759 thyper.HighPart = 0;
4761 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4763 if (code == CM_ERROR_STOPNOW)
4766 code = CM_ERROR_NOSUCHFILE;
4768 /* Handle Change Notification */
4770 * Being lazy, not distinguishing between files and dirs in this
4771 * filter, since we'd have to do a lookup.
4773 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4774 if (oldDscp == newDscp) {
4775 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4776 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4777 filter, oldDscp, oldLastNamep,
4778 newLastNamep, TRUE);
4780 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4781 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4782 filter, oldDscp, oldLastNamep,
4784 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4785 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4786 filter, newDscp, newLastNamep,
4791 cm_ReleaseSCache(tmpscp);
4792 cm_ReleaseUser(userp);
4793 cm_ReleaseSCache(oldDscp);
4794 cm_ReleaseSCache(newDscp);
4799 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4802 cm_space_t *spacep = NULL;
4803 cm_scache_t *oldDscp = NULL;
4804 cm_scache_t *newDscp = NULL;
4805 cm_scache_t *tmpscp= NULL;
4806 cm_scache_t *tmpscp2 = NULL;
4807 cm_scache_t *sscp = NULL;
4816 userp = smb_GetUser(vcp, inp);
4818 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4820 cm_ReleaseUser(userp);
4821 return CM_ERROR_NOSUCHPATH;
4826 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4828 spacep = inp->spacep;
4829 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4831 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4832 userp, tidPathp, &req, &oldDscp);
4834 cm_ReleaseUser(userp);
4839 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4840 cm_ReleaseSCache(oldDscp);
4841 cm_ReleaseUser(userp);
4842 if ( WANTS_DFS_PATHNAMES(inp) )
4843 return CM_ERROR_PATH_NOT_COVERED;
4845 return CM_ERROR_BADSHARENAME;
4847 #endif /* DFS_SUPPORT */
4849 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4850 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4851 userp, tidPathp, &req, &newDscp);
4853 cm_ReleaseSCache(oldDscp);
4854 cm_ReleaseUser(userp);
4859 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4860 cm_ReleaseSCache(newDscp);
4861 cm_ReleaseSCache(oldDscp);
4862 cm_ReleaseUser(userp);
4863 if ( WANTS_DFS_PATHNAMES(inp) )
4864 return CM_ERROR_PATH_NOT_COVERED;
4866 return CM_ERROR_BADSHARENAME;
4868 #endif /* DFS_SUPPORT */
4870 /* Now, although we did two lookups for the two directories (because the same
4871 * directory can be referenced through different paths), we only allow hard links
4872 * within the same directory. */
4873 if (oldDscp != newDscp) {
4874 cm_ReleaseSCache(oldDscp);
4875 cm_ReleaseSCache(newDscp);
4876 cm_ReleaseUser(userp);
4877 return CM_ERROR_CROSSDEVLINK;
4880 /* handle the old name first */
4882 oldLastNamep = oldPathp;
4886 /* and handle the new name, too */
4888 newLastNamep = newPathp;
4892 /* now lookup the old name */
4893 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4894 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4896 cm_ReleaseSCache(oldDscp);
4897 cm_ReleaseSCache(newDscp);
4898 cm_ReleaseUser(userp);
4902 /* Check if the file already exists; if so return error */
4903 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4904 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4905 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4906 osi_LogSaveString(afsd_logp, newLastNamep));
4908 /* if the existing link is to the same file, then we return success */
4910 if(sscp == tmpscp) {
4913 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
4914 code = CM_ERROR_EXISTS;
4919 cm_ReleaseSCache(tmpscp);
4920 cm_ReleaseSCache(sscp);
4921 cm_ReleaseSCache(newDscp);
4922 cm_ReleaseSCache(oldDscp);
4923 cm_ReleaseUser(userp);
4927 /* now create the hardlink */
4928 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
4929 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
4930 osi_Log1(smb_logp," Link returns %d", code);
4932 /* Handle Change Notification */
4934 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
4935 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4936 smb_NotifyChange(FILE_ACTION_ADDED,
4937 filter, newDscp, newLastNamep,
4942 cm_ReleaseSCache(tmpscp);
4943 cm_ReleaseUser(userp);
4944 cm_ReleaseSCache(sscp);
4945 cm_ReleaseSCache(oldDscp);
4946 cm_ReleaseSCache(newDscp);
4951 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4957 tp = smb_GetSMBData(inp, NULL);
4958 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4959 if (smb_StoreAnsiFilenames)
4960 OemToChar(oldPathp,oldPathp);
4961 newPathp = smb_ParseASCIIBlock(tp, &tp);
4962 if (smb_StoreAnsiFilenames)
4963 OemToChar(newPathp,newPathp);
4965 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4966 osi_LogSaveString(smb_logp, oldPathp),
4967 osi_LogSaveString(smb_logp, newPathp));
4969 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
4974 typedef struct smb_rmdirRock {
4978 char *maskp; /* pointer to the star pattern */
4983 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4986 smb_rmdirRock_t *rockp;
4991 rockp = (smb_rmdirRock_t *) vrockp;
4993 matchName = dep->name;
4994 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4995 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4997 match = (strcmp(matchName, rockp->maskp) == 0);
4999 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5000 !cm_Is8Dot3(dep->name)) {
5001 cm_Gen8Dot3Name(dep, shortName, NULL);
5002 matchName = shortName;
5003 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5006 osi_Log1(smb_logp, "Removing directory %s",
5007 osi_LogSaveString(smb_logp, matchName));
5008 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5009 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5010 smb_NotifyChange(FILE_ACTION_REMOVED,
5011 FILE_NOTIFY_CHANGE_DIR_NAME,
5012 dscp, dep->name, NULL, TRUE);
5021 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5029 smb_rmdirRock_t rock;
5038 tp = smb_GetSMBData(inp, NULL);
5039 pathp = smb_ParseASCIIBlock(tp, &tp);
5040 if (smb_StoreAnsiFilenames)
5041 OemToChar(pathp,pathp);
5043 spacep = inp->spacep;
5044 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5046 userp = smb_GetUser(vcp, inp);
5048 caseFold = CM_FLAG_CASEFOLD;
5050 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5052 cm_ReleaseUser(userp);
5053 return CM_ERROR_NOSUCHPATH;
5055 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5056 userp, tidPathp, &req, &dscp);
5059 cm_ReleaseUser(userp);
5064 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5065 cm_ReleaseSCache(dscp);
5066 cm_ReleaseUser(userp);
5067 if ( WANTS_DFS_PATHNAMES(inp) )
5068 return CM_ERROR_PATH_NOT_COVERED;
5070 return CM_ERROR_BADSHARENAME;
5072 #endif /* DFS_SUPPORT */
5074 /* otherwise, scp points to the parent directory. */
5081 rock.maskp = lastNamep;
5082 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5085 thyper.HighPart = 0;
5089 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5090 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5091 if (code == 0 && !rock.any) {
5093 thyper.HighPart = 0;
5094 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5095 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5098 cm_ReleaseUser(userp);
5100 cm_ReleaseSCache(dscp);
5102 if (code == 0 && !rock.any)
5103 code = CM_ERROR_NOSUCHFILE;
5107 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5117 fid = smb_GetSMBParm(inp, 0);
5119 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5121 fid = smb_ChainFID(fid, inp);
5122 fidp = smb_FindFID(vcp, fid, 0);
5123 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5125 smb_ReleaseFID(fidp);
5126 return CM_ERROR_BADFD;
5129 userp = smb_GetUser(vcp, inp);
5131 lock_ObtainMutex(&fidp->mx);
5132 if (fidp->flags & SMB_FID_OPENWRITE)
5133 code = cm_FSync(fidp->scp, userp, &req);
5136 lock_ReleaseMutex(&fidp->mx);
5138 smb_ReleaseFID(fidp);
5140 cm_ReleaseUser(userp);
5145 struct smb_FullNameRock {
5151 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5155 struct smb_FullNameRock *vrockp;
5157 vrockp = (struct smb_FullNameRock *)rockp;
5159 if (!cm_Is8Dot3(dep->name)) {
5160 cm_Gen8Dot3Name(dep, shortName, NULL);
5162 if (cm_stricmp(shortName, vrockp->name) == 0) {
5163 vrockp->fullName = strdup(dep->name);
5164 return CM_ERROR_STOPNOW;
5167 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5168 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5169 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5170 vrockp->fullName = strdup(dep->name);
5171 return CM_ERROR_STOPNOW;
5176 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5177 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5179 struct smb_FullNameRock rock;
5185 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5186 if (code == CM_ERROR_STOPNOW)
5187 *newPathp = rock.fullName;
5189 *newPathp = strdup(pathp);
5192 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5203 fid = smb_GetSMBParm(inp, 0);
5204 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5206 osi_Log1(smb_logp, "SMB close fid %d", fid);
5208 fid = smb_ChainFID(fid, inp);
5209 fidp = smb_FindFID(vcp, fid, 0);
5211 return CM_ERROR_BADFD;
5214 userp = smb_GetUser(vcp, inp);
5216 lock_ObtainMutex(&fidp->mx);
5218 /* Don't jump the gun on an async raw write */
5219 while (fidp->raw_writers) {
5220 lock_ReleaseMutex(&fidp->mx);
5221 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5222 lock_ObtainMutex(&fidp->mx);
5225 fidp->flags |= SMB_FID_DELETE;
5227 /* watch for ioctl closes, and read-only opens */
5228 if (fidp->scp != NULL &&
5229 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5230 == SMB_FID_OPENWRITE) {
5231 if (dosTime != 0 && dosTime != -1) {
5232 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5233 /* This fixes defect 10958 */
5234 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5235 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5237 code = cm_FSync(fidp->scp, userp, &req);
5242 if (fidp->flags & SMB_FID_DELONCLOSE) {
5243 cm_scache_t *dscp = fidp->NTopen_dscp;
5244 char *pathp = fidp->NTopen_pathp;
5247 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5248 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5249 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5250 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5251 smb_NotifyChange(FILE_ACTION_REMOVED,
5252 FILE_NOTIFY_CHANGE_DIR_NAME,
5253 dscp, fullPathp, NULL, TRUE);
5257 code = cm_Unlink(dscp, fullPathp, userp, &req);
5258 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5259 smb_NotifyChange(FILE_ACTION_REMOVED,
5260 FILE_NOTIFY_CHANGE_FILE_NAME,
5261 dscp, fullPathp, NULL, TRUE);
5265 lock_ReleaseMutex(&fidp->mx);
5267 if (fidp->flags & SMB_FID_NTOPEN) {
5268 cm_ReleaseSCache(fidp->NTopen_dscp);
5269 free(fidp->NTopen_pathp);
5271 if (fidp->NTopen_wholepathp)
5272 free(fidp->NTopen_wholepathp);
5274 smb_ReleaseFID(fidp);
5275 cm_ReleaseUser(userp);
5280 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5283 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5284 cm_user_t *userp, long *readp)
5286 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5287 cm_user_t *userp, long *readp, int dosflag)
5294 osi_hyper_t fileLength;
5296 osi_hyper_t lastByte;
5297 osi_hyper_t bufferOffset;
5298 long bufIndex, nbytes;
5308 lock_ObtainMutex(&fidp->mx);
5310 lock_ObtainMutex(&scp->mx);
5312 if (offset.HighPart == 0) {
5313 chunk = offset.LowPart >> cm_logChunkSize;
5314 if (chunk != fidp->curr_chunk) {
5315 fidp->prev_chunk = fidp->curr_chunk;
5316 fidp->curr_chunk = chunk;
5318 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5322 /* start by looking up the file's end */
5323 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5324 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5325 if (code) goto done;
5327 /* now we have the entry locked, look up the length */
5328 fileLength = scp->length;
5330 /* adjust count down so that it won't go past EOF */
5331 thyper.LowPart = count;
5332 thyper.HighPart = 0;
5333 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5335 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5336 /* we'd read past EOF, so just stop at fileLength bytes.
5337 * Start by computing how many bytes remain in the file.
5339 thyper = LargeIntegerSubtract(fileLength, offset);
5341 /* if we are past EOF, read 0 bytes */
5342 if (LargeIntegerLessThanZero(thyper))
5345 count = thyper.LowPart;
5350 /* now, copy the data one buffer at a time,
5351 * until we've filled the request packet
5354 /* if we've copied all the data requested, we're done */
5355 if (count <= 0) break;
5357 /* otherwise, load up a buffer of data */
5358 thyper.HighPart = offset.HighPart;
5359 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5360 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5363 buf_Release(bufferp);
5366 lock_ReleaseMutex(&scp->mx);
5368 lock_ObtainRead(&scp->bufCreateLock);
5369 code = buf_Get(scp, &thyper, &bufferp);
5370 lock_ReleaseRead(&scp->bufCreateLock);
5372 lock_ObtainMutex(&scp->mx);
5373 if (code) goto done;
5374 bufferOffset = thyper;
5376 /* now get the data in the cache */
5378 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5379 CM_SCACHESYNC_NEEDCALLBACK |
5380 CM_SCACHESYNC_READ);
5381 if (code) goto done;
5383 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5385 /* otherwise, load the buffer and try again */
5386 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5390 buf_Release(bufferp);
5394 } /* if (wrong buffer) ... */
5396 /* now we have the right buffer loaded. Copy out the
5397 * data from here to the user's buffer.
5399 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5401 /* and figure out how many bytes we want from this buffer */
5402 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5403 if (nbytes > count) nbytes = count; /* don't go past EOF */
5405 /* now copy the data */
5408 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5411 memcpy(op, bufferp->datap + bufIndex, nbytes);
5413 /* adjust counters, pointers, etc. */
5416 thyper.LowPart = nbytes;
5417 thyper.HighPart = 0;
5418 offset = LargeIntegerAdd(thyper, offset);
5422 lock_ReleaseMutex(&scp->mx);
5423 lock_ReleaseMutex(&fidp->mx);
5425 buf_Release(bufferp);
5427 if (code == 0 && sequential)
5428 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5434 * smb_WriteData -- common code for Write and Raw Write
5437 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5438 cm_user_t *userp, long *writtenp)
5440 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5441 cm_user_t *userp, long *writtenp, int dosflag)
5448 osi_hyper_t fileLength; /* file's length at start of write */
5449 osi_hyper_t minLength; /* don't read past this */
5450 long nbytes; /* # of bytes to transfer this iteration */
5452 osi_hyper_t thyper; /* hyper tmp variable */
5453 osi_hyper_t bufferOffset;
5454 long bufIndex; /* index in buffer where our data is */
5456 osi_hyper_t writeBackOffset;/* offset of region to write back when
5461 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5462 fidp->fid, offsetp->LowPart, count);
5472 lock_ObtainMutex(&fidp->mx);
5474 lock_ObtainMutex(&scp->mx);
5476 /* start by looking up the file's end */
5477 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5479 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5480 CM_SCACHESYNC_NEEDCALLBACK
5481 | CM_SCACHESYNC_SETSTATUS
5482 | CM_SCACHESYNC_GETSTATUS);
5483 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5488 /* make sure we have a writable FD */
5489 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5490 code = CM_ERROR_BADFDOP;
5494 /* now we have the entry locked, look up the length */
5495 fileLength = scp->length;
5496 minLength = fileLength;
5497 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5498 minLength = scp->serverLength;
5500 /* adjust file length if we extend past EOF */
5501 thyper.LowPart = count;
5502 thyper.HighPart = 0;
5503 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5504 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5505 /* we'd write past EOF, so extend the file */
5506 scp->mask |= CM_SCACHEMASK_LENGTH;
5507 scp->length = thyper;
5508 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5510 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5512 /* now, if the new position (thyper) and the old (offset) are in
5513 * different storeback windows, remember to store back the previous
5514 * storeback window when we're done with the write.
5516 if ((thyper.LowPart & (-cm_chunkSize)) !=
5517 (offset.LowPart & (-cm_chunkSize))) {
5518 /* they're different */
5520 writeBackOffset.HighPart = offset.HighPart;
5521 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5526 /* now, copy the data one buffer at a time, until we've filled the
5529 /* if we've copied all the data requested, we're done */
5533 /* handle over quota or out of space */
5534 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5535 *writtenp = written;
5536 code = CM_ERROR_QUOTA;
5540 /* otherwise, load up a buffer of data */
5541 thyper.HighPart = offset.HighPart;
5542 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5543 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5546 lock_ReleaseMutex(&bufferp->mx);
5547 buf_Release(bufferp);
5550 lock_ReleaseMutex(&scp->mx);
5552 lock_ObtainRead(&scp->bufCreateLock);
5553 code = buf_Get(scp, &thyper, &bufferp);
5554 lock_ReleaseRead(&scp->bufCreateLock);
5556 lock_ObtainMutex(&bufferp->mx);
5557 lock_ObtainMutex(&scp->mx);
5558 if (code) goto done;
5560 bufferOffset = thyper;
5562 /* now get the data in the cache */
5564 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5566 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5567 CM_SCACHESYNC_NEEDCALLBACK
5568 | CM_SCACHESYNC_WRITE
5569 | CM_SCACHESYNC_BUFLOCKED);
5570 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5575 /* If we're overwriting the entire buffer, or
5576 * if we're writing at or past EOF, mark the
5577 * buffer as current so we don't call
5578 * cm_GetBuffer. This skips the fetch from the
5579 * server in those cases where we're going to
5580 * obliterate all the data in the buffer anyway,
5581 * or in those cases where there is no useful
5582 * data at the server to start with.
5584 * Use minLength instead of scp->length, since
5585 * the latter has already been updated by this
5588 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5589 || LargeIntegerEqualTo(offset, bufferp->offset)
5590 && (count >= cm_data.buf_blockSize
5591 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5592 ConvertLongToLargeInteger(count)),
5594 if (count < cm_data.buf_blockSize
5595 && bufferp->dataVersion == -1)
5596 memset(bufferp->datap, 0,
5597 cm_data.buf_blockSize);
5598 bufferp->dataVersion = scp->dataVersion;
5601 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5603 /* otherwise, load the buffer and try again */
5604 lock_ReleaseMutex(&bufferp->mx);
5605 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5607 lock_ReleaseMutex(&scp->mx);
5608 lock_ObtainMutex(&bufferp->mx);
5609 lock_ObtainMutex(&scp->mx);
5613 lock_ReleaseMutex(&bufferp->mx);
5614 buf_Release(bufferp);
5618 } /* if (wrong buffer) ... */
5620 /* now we have the right buffer loaded. Copy out the
5621 * data from here to the user's buffer.
5623 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5625 /* and figure out how many bytes we want from this buffer */
5626 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5628 nbytes = count; /* don't go past end of request */
5630 /* now copy the data */
5633 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5636 memcpy(bufferp->datap + bufIndex, op, nbytes);
5637 buf_SetDirty(bufferp);
5639 /* and record the last writer */
5640 if (bufferp->userp != userp) {
5643 cm_ReleaseUser(bufferp->userp);
5644 bufferp->userp = userp;
5647 /* adjust counters, pointers, etc. */
5651 thyper.LowPart = nbytes;
5652 thyper.HighPart = 0;
5653 offset = LargeIntegerAdd(thyper, offset);
5657 lock_ReleaseMutex(&scp->mx);
5658 lock_ReleaseMutex(&fidp->mx);
5660 lock_ReleaseMutex(&bufferp->mx);
5661 buf_Release(bufferp);
5664 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5665 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5666 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5667 fidp->NTopen_dscp, fidp->NTopen_pathp,
5671 if (code == 0 && doWriteBack) {
5673 lock_ObtainMutex(&scp->mx);
5674 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5676 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5677 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5679 lock_ReleaseMutex(&scp->mx);
5680 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5681 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5684 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5685 fidp->fid, code, *writtenp);
5689 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5692 long count, written = 0, total_written = 0;
5697 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5699 int inDataBlockCount;
5701 fd = smb_GetSMBParm(inp, 0);
5702 count = smb_GetSMBParm(inp, 1);
5703 offset.HighPart = 0; /* too bad */
5704 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5706 op = smb_GetSMBData(inp, NULL);
5707 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5709 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5710 fd, offset.LowPart, count);
5712 fd = smb_ChainFID(fd, inp);
5713 fidp = smb_FindFID(vcp, fd, 0);
5715 return CM_ERROR_BADFD;
5718 if (fidp->flags & SMB_FID_IOCTL)
5719 return smb_IoctlWrite(fidp, vcp, inp, outp);
5721 userp = smb_GetUser(vcp, inp);
5723 /* special case: 0 bytes transferred means truncate to this position */
5729 truncAttr.mask = CM_ATTRMASK_LENGTH;
5730 truncAttr.length.LowPart = offset.LowPart;
5731 truncAttr.length.HighPart = 0;
5732 lock_ObtainMutex(&fidp->mx);
5733 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5734 lock_ReleaseMutex(&fidp->mx);
5735 smb_SetSMBParm(outp, 0, /* count */ 0);
5736 smb_SetSMBDataLength(outp, 0);
5737 fidp->flags |= SMB_FID_LENGTHSETDONE;
5742 * Work around bug in NT client
5744 * When copying a file, the NT client should first copy the data,
5745 * then copy the last write time. But sometimes the NT client does
5746 * these in the wrong order, so the data copies would inadvertently
5747 * cause the last write time to be overwritten. We try to detect this,
5748 * and don't set client mod time if we think that would go against the
5751 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5752 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5753 fidp->scp->clientModTime = time(NULL);
5757 while ( code == 0 && count > 0 ) {
5759 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5761 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5763 if (code == 0 && written == 0)
5764 code = CM_ERROR_PARTIALWRITE;
5766 offset.LowPart += written;
5768 total_written += written;
5772 /* set the packet data length to 3 bytes for the data block header,
5773 * plus the size of the data.
5775 smb_SetSMBParm(outp, 0, total_written);
5776 smb_SetSMBDataLength(outp, 0);
5779 smb_ReleaseFID(fidp);
5780 cm_ReleaseUser(userp);
5785 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5786 NCB *ncbp, raw_write_cont_t *rwcp)
5799 fd = smb_GetSMBParm(inp, 0);
5800 fidp = smb_FindFID(vcp, fd, 0);
5802 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5803 rwcp->offset.LowPart, rwcp->count);
5805 userp = smb_GetUser(vcp, inp);
5809 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5812 rawBuf = (dos_ptr) rwcp->buf;
5813 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5814 (unsigned char *) rawBuf, userp,
5818 if (rwcp->writeMode & 0x1) { /* synchronous */
5821 smb_FormatResponsePacket(vcp, inp, outp);
5822 op = (smb_t *) outp;
5823 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5824 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5825 smb_SetSMBDataLength(outp, 0);
5826 smb_SendPacket(vcp, outp);
5827 smb_FreePacket(outp);
5829 else { /* asynchronous */
5830 lock_ObtainMutex(&fidp->mx);
5831 fidp->raw_writers--;
5832 if (fidp->raw_writers == 0)
5833 thrd_SetEvent(fidp->raw_write_event);
5834 lock_ReleaseMutex(&fidp->mx);
5837 /* Give back raw buffer */
5838 lock_ObtainMutex(&smb_RawBufLock);
5840 *((char **)rawBuf) = smb_RawBufs;
5842 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5844 smb_RawBufs = rawBuf;
5845 lock_ReleaseMutex(&smb_RawBufLock);
5847 smb_ReleaseFID(fidp);
5848 cm_ReleaseUser(userp);
5851 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5856 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5859 long count, written = 0, total_written = 0;
5866 unsigned short writeMode;
5873 fd = smb_GetSMBParm(inp, 0);
5874 totalCount = smb_GetSMBParm(inp, 1);
5875 count = smb_GetSMBParm(inp, 10);
5876 offset.HighPart = 0; /* too bad */
5877 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5878 writeMode = smb_GetSMBParm(inp, 7);
5880 op = (char *) inp->data;
5881 op += smb_GetSMBParm(inp, 11);
5884 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5885 fd, offset.LowPart, count, writeMode);
5887 fd = smb_ChainFID(fd, inp);
5888 fidp = smb_FindFID(vcp, fd, 0);
5890 return CM_ERROR_BADFD;
5893 userp = smb_GetUser(vcp, inp);
5896 * Work around bug in NT client
5898 * When copying a file, the NT client should first copy the data,
5899 * then copy the last write time. But sometimes the NT client does
5900 * these in the wrong order, so the data copies would inadvertently
5901 * cause the last write time to be overwritten. We try to detect this,
5902 * and don't set client mod time if we think that would go against the
5905 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5906 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5907 fidp->scp->clientModTime = time(NULL);
5911 while ( code == 0 && count > 0 ) {
5913 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5915 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5917 if (code == 0 && written == 0)
5918 code = CM_ERROR_PARTIALWRITE;
5920 offset.LowPart += written;
5922 total_written += written;
5926 /* Get a raw buffer */
5929 lock_ObtainMutex(&smb_RawBufLock);
5931 /* Get a raw buf, from head of list */
5932 rawBuf = smb_RawBufs;
5934 smb_RawBufs = *(char **)smb_RawBufs;
5936 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5940 code = CM_ERROR_USESTD;
5942 lock_ReleaseMutex(&smb_RawBufLock);
5945 /* Don't allow a premature Close */
5946 if (code == 0 && (writeMode & 1) == 0) {
5947 lock_ObtainMutex(&fidp->mx);
5948 fidp->raw_writers++;
5949 thrd_ResetEvent(fidp->raw_write_event);
5950 lock_ReleaseMutex(&fidp->mx);
5953 smb_ReleaseFID(fidp);
5954 cm_ReleaseUser(userp);
5957 smb_SetSMBParm(outp, 0, total_written);
5958 smb_SetSMBDataLength(outp, 0);
5959 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5966 rwcp->offset.HighPart = 0;
5967 rwcp->offset.LowPart = offset.LowPart + count;
5968 rwcp->count = totalCount - count;
5969 rwcp->writeMode = writeMode;
5970 rwcp->alreadyWritten = total_written;
5972 /* set the packet data length to 3 bytes for the data block header,
5973 * plus the size of the data.
5975 smb_SetSMBParm(outp, 0, 0xffff);
5976 smb_SetSMBDataLength(outp, 0);
5981 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5984 long count, finalCount;
5991 fd = smb_GetSMBParm(inp, 0);
5992 count = smb_GetSMBParm(inp, 1);
5993 offset.HighPart = 0; /* too bad */
5994 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5996 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5997 fd, offset.LowPart, count);
5999 fd = smb_ChainFID(fd, inp);
6000 fidp = smb_FindFID(vcp, fd, 0);
6002 return CM_ERROR_BADFD;
6005 if (fidp->flags & SMB_FID_IOCTL) {
6006 return smb_IoctlRead(fidp, vcp, inp, outp);
6009 userp = smb_GetUser(vcp, inp);
6011 /* remember this for final results */
6012 smb_SetSMBParm(outp, 0, count);
6013 smb_SetSMBParm(outp, 1, 0);
6014 smb_SetSMBParm(outp, 2, 0);
6015 smb_SetSMBParm(outp, 3, 0);
6016 smb_SetSMBParm(outp, 4, 0);
6018 /* set the packet data length to 3 bytes for the data block header,
6019 * plus the size of the data.
6021 smb_SetSMBDataLength(outp, count+3);
6023 /* get op ptr after putting in the parms, since otherwise we don't
6024 * know where the data really is.
6026 op = smb_GetSMBData(outp, NULL);
6028 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6029 *op++ = 1; /* data block marker */
6030 *op++ = (unsigned char) (count & 0xff);
6031 *op++ = (unsigned char) ((count >> 8) & 0xff);
6034 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6036 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6039 /* fix some things up */
6040 smb_SetSMBParm(outp, 0, finalCount);
6041 smb_SetSMBDataLength(outp, finalCount+3);
6043 smb_ReleaseFID(fidp);
6045 cm_ReleaseUser(userp);
6049 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6056 cm_scache_t *dscp; /* dir we're dealing with */
6057 cm_scache_t *scp; /* file we're creating */
6059 int initialModeBits;
6069 /* compute initial mode bits based on read-only flag in attributes */
6070 initialModeBits = 0777;
6072 tp = smb_GetSMBData(inp, NULL);
6073 pathp = smb_ParseASCIIBlock(tp, &tp);
6074 if (smb_StoreAnsiFilenames)
6075 OemToChar(pathp,pathp);
6077 if (strcmp(pathp, "\\") == 0)
6078 return CM_ERROR_EXISTS;
6080 spacep = inp->spacep;
6081 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6083 userp = smb_GetUser(vcp, inp);
6085 caseFold = CM_FLAG_CASEFOLD;
6087 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6089 cm_ReleaseUser(userp);
6090 return CM_ERROR_NOSUCHPATH;
6093 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6094 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6095 userp, tidPathp, &req, &dscp);
6098 cm_ReleaseUser(userp);
6103 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6104 cm_ReleaseSCache(dscp);
6105 cm_ReleaseUser(userp);
6106 if ( WANTS_DFS_PATHNAMES(inp) )
6107 return CM_ERROR_PATH_NOT_COVERED;
6109 return CM_ERROR_BADSHARENAME;
6111 #endif /* DFS_SUPPORT */
6113 /* otherwise, scp points to the parent directory. Do a lookup, and
6114 * fail if we find it. Otherwise, we do the create.
6120 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6121 if (scp) cm_ReleaseSCache(scp);
6122 if (code != CM_ERROR_NOSUCHFILE) {
6123 if (code == 0) code = CM_ERROR_EXISTS;
6124 cm_ReleaseSCache(dscp);
6125 cm_ReleaseUser(userp);
6129 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6130 setAttr.clientModTime = time(NULL);
6131 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6132 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6133 smb_NotifyChange(FILE_ACTION_ADDED,
6134 FILE_NOTIFY_CHANGE_DIR_NAME,
6135 dscp, lastNamep, NULL, TRUE);
6137 /* we don't need this any longer */
6138 cm_ReleaseSCache(dscp);
6141 /* something went wrong creating or truncating the file */
6142 cm_ReleaseUser(userp);
6146 /* otherwise we succeeded */
6147 smb_SetSMBDataLength(outp, 0);
6148 cm_ReleaseUser(userp);
6153 BOOL smb_IsLegalFilename(char *filename)
6156 * Find the longest substring of filename that does not contain
6157 * any of the chars in illegalChars. If that substring is less
6158 * than the length of the whole string, then one or more of the
6159 * illegal chars is in filename.
6161 if (strcspn(filename, illegalChars) < strlen(filename))
6167 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6175 cm_scache_t *dscp; /* dir we're dealing with */
6176 cm_scache_t *scp; /* file we're creating */
6178 int initialModeBits;
6190 excl = (inp->inCom == 0x03)? 0 : 1;
6192 attributes = smb_GetSMBParm(inp, 0);
6193 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6195 /* compute initial mode bits based on read-only flag in attributes */
6196 initialModeBits = 0666;
6197 if (attributes & 1) initialModeBits &= ~0222;
6199 tp = smb_GetSMBData(inp, NULL);
6200 pathp = smb_ParseASCIIBlock(tp, &tp);
6201 if (smb_StoreAnsiFilenames)
6202 OemToChar(pathp,pathp);
6204 spacep = inp->spacep;
6205 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6207 userp = smb_GetUser(vcp, inp);
6209 caseFold = CM_FLAG_CASEFOLD;
6211 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6213 cm_ReleaseUser(userp);
6214 return CM_ERROR_NOSUCHPATH;
6216 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6217 userp, tidPathp, &req, &dscp);
6220 cm_ReleaseUser(userp);
6225 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6226 cm_ReleaseSCache(dscp);
6227 cm_ReleaseUser(userp);
6228 if ( WANTS_DFS_PATHNAMES(inp) )
6229 return CM_ERROR_PATH_NOT_COVERED;
6231 return CM_ERROR_BADSHARENAME;
6233 #endif /* DFS_SUPPORT */
6235 /* otherwise, scp points to the parent directory. Do a lookup, and
6236 * truncate the file if we find it, otherwise we create the file.
6243 if (!smb_IsLegalFilename(lastNamep))
6244 return CM_ERROR_BADNTFILENAME;
6246 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6247 #ifdef DEBUG_VERBOSE
6250 hexp = osi_HexifyString( lastNamep );
6251 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6256 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6257 if (code && code != CM_ERROR_NOSUCHFILE) {
6258 cm_ReleaseSCache(dscp);
6259 cm_ReleaseUser(userp);
6263 /* if we get here, if code is 0, the file exists and is represented by
6264 * scp. Otherwise, we have to create it.
6268 /* oops, file shouldn't be there */
6269 cm_ReleaseSCache(dscp);
6270 cm_ReleaseSCache(scp);
6271 cm_ReleaseUser(userp);
6272 return CM_ERROR_EXISTS;
6275 setAttr.mask = CM_ATTRMASK_LENGTH;
6276 setAttr.length.LowPart = 0;
6277 setAttr.length.HighPart = 0;
6278 code = cm_SetAttr(scp, &setAttr, userp, &req);
6281 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6282 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6283 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6285 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6286 smb_NotifyChange(FILE_ACTION_ADDED,
6287 FILE_NOTIFY_CHANGE_FILE_NAME,
6288 dscp, lastNamep, NULL, TRUE);
6289 if (!excl && code == CM_ERROR_EXISTS) {
6290 /* not an exclusive create, and someone else tried
6291 * creating it already, then we open it anyway. We
6292 * don't bother retrying after this, since if this next
6293 * fails, that means that the file was deleted after
6294 * we started this call.
6296 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6299 setAttr.mask = CM_ATTRMASK_LENGTH;
6300 setAttr.length.LowPart = 0;
6301 setAttr.length.HighPart = 0;
6302 code = cm_SetAttr(scp, &setAttr, userp, &req);
6307 /* we don't need this any longer */
6308 cm_ReleaseSCache(dscp);
6311 /* something went wrong creating or truncating the file */
6312 if (scp) cm_ReleaseSCache(scp);
6313 cm_ReleaseUser(userp);
6317 /* make sure we only open files */
6318 if (scp->fileType != CM_SCACHETYPE_FILE) {
6319 cm_ReleaseSCache(scp);
6320 cm_ReleaseUser(userp);
6321 return CM_ERROR_ISDIR;
6324 /* now all we have to do is open the file itself */
6325 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6328 /* save a pointer to the vnode */
6331 /* always create it open for read/write */
6332 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6334 smb_ReleaseFID(fidp);
6336 smb_SetSMBParm(outp, 0, fidp->fid);
6337 smb_SetSMBDataLength(outp, 0);
6339 cm_Open(scp, 0, userp);
6341 cm_ReleaseUser(userp);
6342 /* leave scp held since we put it in fidp->scp */
6346 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6359 fd = smb_GetSMBParm(inp, 0);
6360 whence = smb_GetSMBParm(inp, 1);
6361 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6363 /* try to find the file descriptor */
6364 fd = smb_ChainFID(fd, inp);
6365 fidp = smb_FindFID(vcp, fd, 0);
6366 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6367 return CM_ERROR_BADFD;
6370 userp = smb_GetUser(vcp, inp);
6372 lock_ObtainMutex(&fidp->mx);
6374 lock_ObtainMutex(&scp->mx);
6375 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6376 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6379 /* offset from current offset */
6380 offset += fidp->offset;
6382 else if (whence == 2) {
6383 /* offset from current EOF */
6384 offset += scp->length.LowPart;
6386 fidp->offset = offset;
6387 smb_SetSMBParm(outp, 0, offset & 0xffff);
6388 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6389 smb_SetSMBDataLength(outp, 0);
6391 lock_ReleaseMutex(&scp->mx);
6392 lock_ReleaseMutex(&fidp->mx);
6393 smb_ReleaseFID(fidp);
6394 cm_ReleaseUser(userp);
6398 /* dispatch all of the requests received in a packet. Due to chaining, this may
6399 * be more than one request.
6401 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6402 NCB *ncbp, raw_write_cont_t *rwcp)
6406 unsigned long code = 0;
6407 unsigned char *outWctp;
6408 int nparms; /* # of bytes of parameters */
6410 int nbytes; /* bytes of data, excluding count */
6413 unsigned short errCode;
6414 unsigned long NTStatus;
6416 unsigned char errClass;
6417 unsigned int oldGen;
6418 DWORD oldTime, newTime;
6420 /* get easy pointer to the data */
6421 smbp = (smb_t *) inp->data;
6423 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6424 /* setup the basic parms for the initial request in the packet */
6425 inp->inCom = smbp->com;
6426 inp->wctp = &smbp->wct;
6428 inp->ncb_length = ncbp->ncb_length;
6433 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6434 /* log it and discard it */
6439 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6440 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6442 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6443 1, ncbp->ncb_length, ptbuf, inp);
6444 DeregisterEventSource(h);
6446 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6451 /* We are an ongoing op */
6452 thrd_Increment(&ongoingOps);
6454 /* set up response packet for receiving output */
6455 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6456 smb_FormatResponsePacket(vcp, inp, outp);
6457 outWctp = outp->wctp;
6459 /* Remember session generation number and time */
6460 oldGen = sessionGen;
6461 oldTime = GetCurrentTime();
6463 while (inp->inCom != 0xff) {
6464 dp = &smb_dispatchTable[inp->inCom];
6466 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6467 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6468 code = outp->resumeCode;
6472 /* process each request in the packet; inCom, wctp and inCount
6473 * are already set up.
6475 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6478 /* now do the dispatch */
6479 /* start by formatting the response record a little, as a default */
6480 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6482 outWctp[1] = 0xff; /* no operation */
6483 outWctp[2] = 0; /* padding */
6488 /* not a chained request, this is a more reasonable default */
6489 outWctp[0] = 0; /* wct of zero */
6490 outWctp[1] = 0; /* and bcc (word) of zero */
6494 /* once set, stays set. Doesn't matter, since we never chain
6495 * "no response" calls.
6497 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6501 /* we have a recognized operation */
6503 if (inp->inCom == 0x1d)
6505 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6508 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
6509 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6510 code = (*(dp->procp)) (vcp, inp, outp);
6511 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6512 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6514 if ( code == CM_ERROR_BADSMB ||
6515 code == CM_ERROR_BADOP )
6517 #endif /* LOG_PACKET */
6520 if (oldGen != sessionGen) {
6525 newTime = GetCurrentTime();
6526 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6527 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6528 newTime - oldTime, ncbp->ncb_length);
6530 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6531 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6532 DeregisterEventSource(h);
6534 osi_Log1(smb_logp, "Pkt straddled session startup, "
6535 "ncb length %d", ncbp->ncb_length);
6539 /* bad opcode, fail the request, after displaying it */
6540 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6543 #endif /* LOG_PACKET */
6547 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6548 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6549 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6550 if (code == IDCANCEL)
6554 code = CM_ERROR_BADOP;
6557 /* catastrophic failure: log as much as possible */
6558 if (code == CM_ERROR_BADSMB) {
6565 "Invalid SMB, ncb_length %d",
6568 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6569 sprintf(s, "Invalid SMB message, length %d",
6572 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6573 1, ncbp->ncb_length, ptbuf, smbp);
6574 DeregisterEventSource(h);
6577 #endif /* LOG_PACKET */
6579 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6582 code = CM_ERROR_INVAL;
6585 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6586 thrd_Decrement(&ongoingOps);
6591 /* now, if we failed, turn the current response into an empty
6592 * one, and fill in the response packet's error code.
6595 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6596 smb_MapNTError(code, &NTStatus);
6597 outWctp = outp->wctp;
6598 smbp = (smb_t *) &outp->data;
6599 if (code != CM_ERROR_PARTIALWRITE
6600 && code != CM_ERROR_BUFFERTOOSMALL
6601 && code != CM_ERROR_GSSCONTINUE) {
6602 /* nuke wct and bcc. For a partial
6603 * write or an in-process authentication handshake,
6604 * assume they're OK.
6610 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6611 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6612 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6613 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6614 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6618 smb_MapCoreError(code, vcp, &errCode, &errClass);
6619 outWctp = outp->wctp;
6620 smbp = (smb_t *) &outp->data;
6621 if (code != CM_ERROR_PARTIALWRITE) {
6622 /* nuke wct and bcc. For a partial
6623 * write, assume they're OK.
6629 smbp->errLow = (unsigned char) (errCode & 0xff);
6630 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6631 smbp->rcls = errClass;
6634 } /* error occurred */
6636 /* if we're here, we've finished one request. Look to see if
6637 * this is a chained opcode. If it is, setup things to process
6638 * the chained request, and setup the output buffer to hold the
6639 * chained response. Start by finding the next input record.
6641 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6642 break; /* not a chained req */
6643 tp = inp->wctp; /* points to start of last request */
6644 /* in a chained request, the first two
6645 * parm fields are required, and are
6646 * AndXCommand/AndXReserved and
6648 if (tp[0] < 2) break;
6649 if (tp[1] == 0xff) break; /* no more chained opcodes */
6651 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6654 /* and now append the next output request to the end of this
6655 * last request. Begin by finding out where the last response
6656 * ends, since that's where we'll put our new response.
6658 outWctp = outp->wctp; /* ptr to out parameters */
6659 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6660 nparms = outWctp[0] << 1;
6661 tp = outWctp + nparms + 1; /* now points to bcc field */
6662 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6663 tp += 2 /* for the count itself */ + nbytes;
6664 /* tp now points to the new output record; go back and patch the
6665 * second parameter (off2) to point to the new record.
6667 temp = (unsigned int)tp - ((unsigned int) outp->data);
6668 outWctp[3] = (unsigned char) (temp & 0xff);
6669 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6670 outWctp[2] = 0; /* padding */
6671 outWctp[1] = inp->inCom; /* next opcode */
6673 /* finally, setup for the next iteration */
6676 } /* while loop over all requests in the packet */
6678 /* done logging out, turn off logging-out flag */
6679 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6680 vcp->justLoggedOut = NULL;
6683 free(loggedOutName);
6684 loggedOutName = NULL;
6685 smb_ReleaseUID(loggedOutUserp);
6686 loggedOutUserp = NULL;
6690 /* now send the output packet, and return */
6692 smb_SendPacket(vcp, outp);
6693 thrd_Decrement(&ongoingOps);
6695 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6696 if (active_vcp != vcp) {
6698 smb_ReleaseVC(active_vcp);
6700 "Replacing active_vcp %x with %x", active_vcp, vcp);
6705 last_msg_time = GetCurrentTime();
6706 } else if (active_vcp == vcp) {
6707 smb_ReleaseVC(active_vcp);
6715 /* Wait for Netbios() calls to return, and make the results available to server
6716 * threads. Note that server threads can't wait on the NCBevents array
6717 * themselves, because NCB events are manual-reset, and the servers would race
6718 * each other to reset them.
6720 void smb_ClientWaiter(void *parmp)
6725 while (smbShutdownFlag == 0) {
6726 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6728 if (code == WAIT_OBJECT_0)
6731 /* error checking */
6732 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6734 int abandonIdx = code - WAIT_ABANDONED_0;
6735 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6738 if (code == WAIT_IO_COMPLETION)
6740 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6744 if (code == WAIT_TIMEOUT)
6746 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6749 if (code == WAIT_FAILED)
6751 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6754 idx = code - WAIT_OBJECT_0;
6756 /* check idx range! */
6757 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6759 /* this is fatal - log as much as possible */
6760 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6764 thrd_ResetEvent(NCBevents[idx]);
6765 thrd_SetEvent(NCBreturns[0][idx]);
6771 * Try to have one NCBRECV request waiting for every live session. Not more
6772 * than one, because if there is more than one, it's hard to handle Write Raw.
6774 void smb_ServerWaiter(void *parmp)
6777 int idx_session, idx_NCB;
6783 while (smbShutdownFlag == 0) {
6785 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6787 if (code == WAIT_OBJECT_0)
6790 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6792 int abandonIdx = code - WAIT_ABANDONED_0;
6793 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6796 if (code == WAIT_IO_COMPLETION)
6798 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6802 if (code == WAIT_TIMEOUT)
6804 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6807 if (code == WAIT_FAILED)
6809 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6812 idx_session = code - WAIT_OBJECT_0;
6814 /* check idx range! */
6815 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6817 /* this is fatal - log as much as possible */
6818 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6824 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6826 if (code == WAIT_OBJECT_0) {
6827 if (smbShutdownFlag == 1)
6833 /* error checking */
6834 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6836 int abandonIdx = code - WAIT_ABANDONED_0;
6837 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6840 if (code == WAIT_IO_COMPLETION)
6842 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6846 if (code == WAIT_TIMEOUT)
6848 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6851 if (code == WAIT_FAILED)
6853 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6856 idx_NCB = code - WAIT_OBJECT_0;
6858 /* check idx range! */
6859 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6861 /* this is fatal - log as much as possible */
6862 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6866 /* Link them together */
6867 NCBsessions[idx_NCB] = idx_session;
6870 ncbp = NCBs[idx_NCB];
6871 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6872 ncbp->ncb_command = NCBRECV | ASYNCH;
6873 ncbp->ncb_lana_num = lanas[idx_session];
6875 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6876 ncbp->ncb_event = NCBevents[idx_NCB];
6877 ncbp->ncb_length = SMB_PACKETSIZE;
6880 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6881 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6882 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6883 ncbp->ncb_length = SMB_PACKETSIZE;
6884 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6885 Netbios(ncbp, dos_ncb);
6891 * The top level loop for handling SMB request messages. Each server thread
6892 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6893 * NCB and buffer for the incoming request are loaned to us.
6895 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6896 * to immediately send a request for the rest of the data. This must come
6897 * before any other traffic for that session, so we delay setting the session
6898 * event until that data has come in.
6900 void smb_Server(VOID *parmp)
6902 int myIdx = (int) parmp;
6906 smb_packet_t *outbufp;
6908 int idx_NCB, idx_session;
6910 smb_vc_t *vcp = NULL;
6917 outbufp = GetPacket();
6918 outbufp->ncbp = outncbp;
6921 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6924 /* terminate silently if shutdown flag is set */
6925 if (code == WAIT_OBJECT_0) {
6926 if (smbShutdownFlag == 1) {
6927 thrd_SetEvent(smb_ServerShutdown[myIdx]);
6933 /* error checking */
6934 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6936 int abandonIdx = code - WAIT_ABANDONED_0;
6937 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6940 if (code == WAIT_IO_COMPLETION)
6942 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6946 if (code == WAIT_TIMEOUT)
6948 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6951 if (code == WAIT_FAILED)
6953 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6956 idx_NCB = code - WAIT_OBJECT_0;
6958 /* check idx range! */
6959 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6961 /* this is fatal - log as much as possible */
6962 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6966 ncbp = NCBs[idx_NCB];
6968 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6970 idx_session = NCBsessions[idx_NCB];
6971 rc = ncbp->ncb_retcode;
6973 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
6976 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
6979 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
6982 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
6985 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
6988 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
6991 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lsn %d session number out of range", ncbp->ncb_lsn, idx_session);
6994 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
6997 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lsn %d session closed", ncbp->ncb_lsn, idx_session);
7000 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7003 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7006 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7009 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7012 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local lsn %d session table full", ncbp->ncb_lsn, idx_session);
7015 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote lsn %d session table full", ncbp->ncb_lsn, idx_session);
7018 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7021 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7024 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7027 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7030 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7033 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lsn %d session ended abnormally", ncbp->ncb_lsn, idx_session);
7036 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7039 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7042 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7045 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7048 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7051 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7054 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7057 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7060 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7063 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7066 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7069 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7072 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7075 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7078 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7081 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7084 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7087 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7097 /* Can this happen? Or is it just my
7104 /* Client closed session */
7105 dead_sessions[idx_session] = TRUE;
7108 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7109 /* Should also release vcp. [done] 2004-05-11 jaltman
7111 * sanity check that all TID's are gone.
7113 * TODO: check if we could use LSNs[idx_session] instead,
7114 * also cleanup after dead vcp
7119 "dead_vcp already set, %x",
7121 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7123 "setting dead_vcp %x, user struct %x",
7127 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7129 if (vcp->justLoggedOut) {
7131 loggedOutTime = vcp->logoffTime;
7132 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7133 loggedOutUserp = vcp->justLoggedOut;
7134 lock_ObtainWrite(&smb_rctLock);
7135 loggedOutUserp->refCount++;
7136 lock_ReleaseWrite(&smb_rctLock);
7142 /* Treat as transient error */
7149 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7150 sprintf(s, "SMB message incomplete, length %d",
7153 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
7155 ncbp->ncb_length, ptbuf,
7157 DeregisterEventSource(h);
7160 "dispatch smb recv failed, message incomplete, ncb_length %d",
7163 "SMB message incomplete, "
7164 "length %d", ncbp->ncb_length);
7167 * We used to discard the packet.
7168 * Instead, try handling it normally.
7176 /* A weird error code. Log it, sleep, and
7178 if (vcp && vcp->errorCount++ > 3) {
7179 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7180 dead_sessions[idx_session] = TRUE;
7184 thrd_SetEvent(SessionEvents[idx_session]);
7189 /* Success, so now dispatch on all the data in the packet */
7191 smb_concurrentCalls++;
7192 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7193 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7197 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7199 * If at this point vcp is NULL (implies that packet was invalid)
7200 * then we are in big trouble. This means either :
7201 * a) we have the wrong NCB.
7202 * b) Netbios screwed up the call.
7203 * Obviously this implies that
7204 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7205 * lanas[idx_session] != ncbp->ncb_lana_num )
7206 * Either way, we can't do anything with this packet.
7207 * Log, sleep and resume.
7216 "LSNs[idx_session]=[%d],"
7217 "lanas[idx_session]=[%d],"
7218 "ncbp->ncb_lsn=[%d],"
7219 "ncbp->ncb_lana_num=[%d]",
7223 ncbp->ncb_lana_num);
7227 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7229 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
7230 DeregisterEventSource(h);
7233 /* Also log in the trace log. */
7234 osi_Log4(smb_logp, "Server: BAD VCP!"
7235 "LSNs[idx_session]=[%d],"
7236 "lanas[idx_session]=[%d],"
7237 "ncbp->ncb_lsn=[%d],"
7238 "ncbp->ncb_lana_num=[%d]",
7242 ncbp->ncb_lana_num);
7244 /* thrd_Sleep(1000); Don't bother sleeping */
7245 thrd_SetEvent(SessionEvents[idx_session]);
7246 smb_concurrentCalls--;
7251 vcp->errorCount = 0;
7252 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7254 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7255 /* copy whole packet to virtual memory */
7256 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7258 bufp->dos_pkt / 16, bufp);*/
7260 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7262 smbp = (smb_t *)bufp->data;
7265 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7269 if (smbp->com == 0x1d) {
7270 /* Special handling for Write Raw */
7271 raw_write_cont_t rwc;
7272 EVENT_HANDLE rwevent;
7273 char eventName[MAX_PATH];
7275 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7276 if (rwc.code == 0) {
7277 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7278 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7279 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7280 ncbp->ncb_command = NCBRECV | ASYNCH;
7281 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7282 ncbp->ncb_lana_num = vcp->lana;
7283 ncbp->ncb_buffer = rwc.buf;
7284 ncbp->ncb_length = 65535;
7285 ncbp->ncb_event = rwevent;
7289 Netbios(ncbp, dos_ncb);
7291 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7292 thrd_CloseHandle(rwevent);
7294 thrd_SetEvent(SessionEvents[idx_session]);
7296 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7298 else if (smbp->com == 0xa0) {
7300 * Serialize the handling for NT Transact
7303 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7304 thrd_SetEvent(SessionEvents[idx_session]);
7306 thrd_SetEvent(SessionEvents[idx_session]);
7307 /* TODO: what else needs to be serialized? */
7308 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7310 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7312 __except( smb_ServerExceptionFilter() ) {
7316 smb_concurrentCalls--;
7319 thrd_SetEvent(NCBavails[idx_NCB]);
7326 * Exception filter for the server threads. If an exception occurs in the
7327 * dispatch routines, which is where exceptions are most common, then do a
7328 * force trace and give control to upstream exception handlers. Useful for
7331 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7332 DWORD smb_ServerExceptionFilter(void) {
7333 /* While this is not the best time to do a trace, if it succeeds, then
7334 * we have a trace (assuming tracing was enabled). Otherwise, this should
7335 * throw a second exception.
7340 ptbuf[0] = "Unhandled exception forcing trace";
7342 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7344 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7345 DeregisterEventSource(h);
7348 afsd_ForceTrace(TRUE);
7349 buf_ForceTrace(TRUE);
7350 return EXCEPTION_CONTINUE_SEARCH;
7355 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7356 * If the number of server threads is M, and the number of live sessions is
7357 * N, then the number of NCB's in use at any time either waiting for, or
7358 * holding, received messages is M + N, so that is how many NCB's get created.
7360 void InitNCBslot(int idx)
7362 struct smb_packet *bufp;
7363 EVENT_HANDLE retHandle;
7365 char eventName[MAX_PATH];
7367 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7369 NCBs[idx] = GetNCB();
7370 sprintf(eventName,"NCBavails[%d]", idx);
7371 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7372 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7373 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7375 sprintf(eventName,"NCBevents[%d]", idx);
7376 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7377 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7378 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7380 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7381 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7382 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7383 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7384 for (i=0; i<smb_NumServerThreads; i++)
7385 NCBreturns[i][idx] = retHandle;
7387 bufp->spacep = cm_GetSpace();
7391 /* listen for new connections */
7392 void smb_Listener(void *parmp)
7400 char rname[NCBNAMSZ+1];
7401 char cname[MAX_COMPUTERNAME_LENGTH+1];
7402 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7407 int lana = (int) parmp;
7411 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7414 /* retrieve computer name */
7415 GetComputerName(cname, &cnamelen);
7419 memset(ncbp, 0, sizeof(NCB));
7422 ncbp->ncb_command = NCBLISTEN;
7423 ncbp->ncb_rto = 0; /* No receive timeout */
7424 ncbp->ncb_sto = 0; /* No send timeout */
7426 /* pad out with spaces instead of null termination */
7427 len = strlen(smb_localNamep);
7428 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7429 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7431 strcpy(ncbp->ncb_callname, "*");
7432 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7434 ncbp->ncb_lana_num = lana;
7437 code = Netbios(ncbp);
7439 code = Netbios(ncbp, dos_ncb);
7448 /* terminate silently if shutdown flag is set */
7449 if (smbShutdownFlag == 1) {
7458 "NCBLISTEN lana=%d failed with code %d",
7459 ncbp->ncb_lana_num, code);
7461 "Client exiting due to network failure. Please restart client.\n");
7465 "Client exiting due to network failure. Please restart client.\n"
7466 "NCBLISTEN lana=%d failed with code %d",
7467 ncbp->ncb_lana_num, code);
7469 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7470 MB_OK|MB_SERVICE_NOTIFICATION);
7471 osi_assert(tbuffer);
7474 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7475 ncbp->ncb_lana_num, code);
7476 fprintf(stderr, "\nClient exiting due to network failure "
7477 "(possibly due to power-saving mode)\n");
7478 fprintf(stderr, "Please restart client.\n");
7479 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7483 /* check for remote conns */
7484 /* first get remote name and insert null terminator */
7485 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7486 for (i=NCBNAMSZ; i>0; i--) {
7487 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7493 /* compare with local name */
7495 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7496 flags |= SMB_VCFLAG_REMOTECONN;
7498 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7500 lock_ObtainMutex(&smb_ListenerLock);
7502 /* New generation */
7505 /* Log session startup */
7507 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7509 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7510 #endif /* NOTSERVICE */
7511 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7512 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7514 if (reportSessionStartups) {
7520 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7521 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7523 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7525 DeregisterEventSource(h);
7528 fprintf(stderr, "%s: New session %d starting from host %s\n",
7529 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7533 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7534 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7537 /* now ncbp->ncb_lsn is the connection ID */
7538 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7539 vcp->flags |= flags;
7540 strcpy(vcp->rname, rname);
7543 /* Allocate slot in session arrays */
7544 /* Re-use dead session if possible, otherwise add one more */
7545 /* But don't look at session[0], it is reserved */
7546 for (i = 1; i < numSessions; i++) {
7547 if (dead_sessions[i]) {
7548 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7549 dead_sessions[i] = FALSE;
7554 /* assert that we do not exceed the maximum number of sessions or NCBs.
7555 * we should probably want to wait for a session to be freed in case
7559 osi_assert(i < Sessionmax - 1);
7560 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7562 LSNs[i] = ncbp->ncb_lsn;
7563 lanas[i] = ncbp->ncb_lana_num;
7565 if (i == numSessions) {
7566 /* Add new NCB for new session */
7567 char eventName[MAX_PATH];
7569 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7571 InitNCBslot(numNCBs);
7573 thrd_SetEvent(NCBavails[0]);
7574 thrd_SetEvent(NCBevents[0]);
7575 for (j = 0; j < smb_NumServerThreads; j++)
7576 thrd_SetEvent(NCBreturns[j][0]);
7577 /* Also add new session event */
7578 sprintf(eventName, "SessionEvents[%d]", i);
7579 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7580 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7581 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7583 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7584 thrd_SetEvent(SessionEvents[0]);
7586 thrd_SetEvent(SessionEvents[i]);
7589 lock_ReleaseMutex(&smb_ListenerLock);
7591 } /* dispatch while loop */
7594 /* initialize Netbios */
7595 void smb_NetbiosInit()
7601 int i, lana, code, l;
7603 int delname_tried=0;
7606 OSVERSIONINFO Version;
7608 /* Get the version of Windows */
7609 memset(&Version, 0x00, sizeof(Version));
7610 Version.dwOSVersionInfoSize = sizeof(Version);
7611 GetVersionEx(&Version);
7613 /* setup the NCB system */
7616 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7620 if (smb_LANadapter == -1) {
7621 ncbp->ncb_command = NCBENUM;
7622 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7623 ncbp->ncb_length = sizeof(lana_list);
7624 code = Netbios(ncbp);
7626 osi_Log1(smb_logp, "Netbios NCBENUM error code %d", code);
7627 osi_panic(s, __FILE__, __LINE__);
7631 lana_list.length = 1;
7632 lana_list.lana[0] = smb_LANadapter;
7635 for (i = 0; i < lana_list.length; i++) {
7636 /* reset the adaptor: in Win32, this is required for every process, and
7637 * acts as an init call, not as a real hardware reset.
7639 ncbp->ncb_command = NCBRESET;
7640 ncbp->ncb_callname[0] = 100;
7641 ncbp->ncb_callname[2] = 100;
7642 ncbp->ncb_lana_num = lana_list.lana[i];
7643 code = Netbios(ncbp);
7645 code = ncbp->ncb_retcode;
7647 osi_Log2(smb_logp, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7648 lana_list.lana[i] = 255; /* invalid lana */
7650 osi_Log1(smb_logp, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7654 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7655 we will just fake the LANA list */
7656 if (smb_LANadapter == -1) {
7657 for (i = 0; i < 8; i++)
7658 lana_list.lana[i] = i;
7659 lana_list.length = 8;
7662 lana_list.length = 1;
7663 lana_list.lana[0] = smb_LANadapter;
7667 /* and declare our name so we can receive connections */
7668 memset(ncbp, 0, sizeof(*ncbp));
7669 len=lstrlen(smb_localNamep);
7670 memset(smb_sharename,' ',NCBNAMSZ);
7671 memcpy(smb_sharename,smb_localNamep,len);
7672 osi_Log1(smb_logp, "lana_list.length %d", lana_list.length);
7674 /* Keep the name so we can unregister it later */
7675 for (l = 0; l < lana_list.length; l++) {
7676 lana = lana_list.lana[l];
7678 ncbp->ncb_command = NCBADDNAME;
7679 ncbp->ncb_lana_num = lana;
7680 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7682 code = Netbios(ncbp);
7684 code = Netbios(ncbp, dos_ncb);
7687 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7688 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7690 char name[NCBNAMSZ+1];
7692 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7693 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7696 if (code == 0) code = ncbp->ncb_retcode;
7698 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7700 /* we only use one LANA with djgpp */
7701 lana_list.lana[0] = lana;
7702 lana_list.length = 1;
7706 osi_Log2(smb_logp, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7707 if (code == NRC_BRIDGE) { /* invalid LANA num */
7708 lana_list.lana[l] = 255;
7711 else if (code == NRC_DUPNAME) {
7712 osi_Log0(smb_logp, "Name already exists; try to delete it");
7713 memset(ncbp, 0, sizeof(*ncbp));
7714 ncbp->ncb_command = NCBDELNAME;
7715 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7716 ncbp->ncb_lana_num = lana;
7718 code = Netbios(ncbp);
7720 code = Netbios(ncbp, dos_ncb);
7723 code = ncbp->ncb_retcode;
7725 osi_Log2(smb_logp, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7727 if (code != 0 || delname_tried) {
7728 lana_list.lana[l] = 255;
7730 else if (code == 0) {
7731 if (!delname_tried) {
7739 osi_Log2(smb_logp, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7740 lana_list.lana[l] = 255; /* invalid lana */
7741 osi_panic(s, __FILE__, __LINE__);
7745 lana_found = 1; /* at least one worked */
7752 osi_assert(lana_list.length >= 0);
7754 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
7757 /* we're done with the NCB now */
7761 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7778 EVENT_HANDLE retHandle;
7779 char eventName[MAX_PATH];
7782 smb_MBfunc = aMBfunc;
7786 smb_LANadapter = LANadapt;
7788 /* Initialize smb_localZero */
7789 myTime.tm_isdst = -1; /* compute whether on DST or not */
7790 myTime.tm_year = 70;
7796 smb_localZero = mktime(&myTime);
7798 /* Initialize kludge-GMT */
7799 smb_CalculateNowTZ();
7801 #ifdef AFS_FREELANCE_CLIENT
7802 /* Make sure the root.afs volume has the correct time */
7803 cm_noteLocalMountPointChange();
7806 /* initialize the remote debugging log */
7809 /* remember the name */
7810 len = strlen(snamep);
7811 smb_localNamep = malloc(len+1);
7812 strcpy(smb_localNamep, snamep);
7813 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7815 /* and the global lock */
7816 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7817 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7819 /* Raw I/O data structures */
7820 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7822 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7824 /* 4 Raw I/O buffers */
7826 smb_RawBufs = calloc(65536,1);
7827 *((char **)smb_RawBufs) = NULL;
7828 for (i=0; i<3; i++) {
7829 char *rawBuf = calloc(65536,1);
7830 *((char **)rawBuf) = smb_RawBufs;
7831 smb_RawBufs = rawBuf;
7834 npar = 65536 >> 4; /* number of paragraphs */
7835 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7837 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7839 osi_panic("",__FILE__,__LINE__);
7842 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7845 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7847 _farpokel(_dos_ds, smb_RawBufs, NULL);
7848 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7849 npar = 65536 >> 4; /* number of paragraphs */
7850 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7852 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7854 osi_panic("",__FILE__,__LINE__);
7857 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7860 rawBuf = (seg * 16) + 0; /* DOS physical address */
7861 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7862 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7863 smb_RawBufs = rawBuf;
7867 /* global free lists */
7868 smb_ncbFreeListp = NULL;
7869 smb_packetFreeListp = NULL;
7873 /* Initialize listener and server structures */
7875 memset(dead_sessions, 0, sizeof(dead_sessions));
7876 sprintf(eventName, "SessionEvents[0]");
7877 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7878 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7879 afsi_log("Event Object Already Exists: %s", eventName);
7881 smb_NumServerThreads = nThreads;
7882 sprintf(eventName, "NCBavails[0]");
7883 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7884 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7885 afsi_log("Event Object Already Exists: %s", eventName);
7886 sprintf(eventName, "NCBevents[0]");
7887 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7888 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7889 afsi_log("Event Object Already Exists: %s", eventName);
7890 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
7891 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7892 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7893 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7894 afsi_log("Event Object Already Exists: %s", eventName);
7895 for (i = 0; i < smb_NumServerThreads; i++) {
7896 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7897 NCBreturns[i][0] = retHandle;
7900 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
7901 for (i = 0; i < smb_NumServerThreads; i++) {
7902 sprintf(eventName, "smb_ServerShutdown[%d]", i);
7903 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7904 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7905 afsi_log("Event Object Already Exists: %s", eventName);
7908 numNCBs = smb_NumServerThreads + 1;
7910 /* Initialize dispatch table */
7911 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7912 /* Prepare the table for unknown operations */
7913 for(i=0; i<= SMB_NOPCODES; i++) {
7914 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7916 /* Fill in the ones we do know */
7917 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7918 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7919 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7920 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7921 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7922 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7923 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7924 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7925 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7926 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7927 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7928 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7929 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7930 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7931 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7932 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7933 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7934 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7935 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7936 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7937 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7938 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7939 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7940 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7941 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7942 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7943 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7944 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7945 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7946 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7947 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7948 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7949 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7950 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7951 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7952 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7953 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7954 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7955 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7956 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7957 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7958 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7959 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7960 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7961 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7962 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7963 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7964 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7965 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7966 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7967 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7968 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7969 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7970 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7971 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7972 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7973 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
7974 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
7975 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
7976 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7977 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7978 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7979 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7980 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7981 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
7982 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
7983 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
7984 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
7985 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
7986 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
7987 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
7988 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
7990 /* setup tran 2 dispatch table */
7991 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7992 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7993 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7994 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7995 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7996 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7997 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7998 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
7999 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8000 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8001 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8002 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8003 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8004 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8005 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8006 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8007 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8009 /* setup the rap dispatch table */
8010 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8011 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8012 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8013 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8014 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8018 /* if we are doing SMB authentication we have register outselves as a logon process */
8019 if (smb_authType != SMB_AUTH_NONE) {
8020 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8021 LSA_STRING afsProcessName;
8022 LSA_OPERATIONAL_MODE dummy; /*junk*/
8024 afsProcessName.Buffer = "OpenAFSClientDaemon";
8025 afsProcessName.Length = strlen(afsProcessName.Buffer);
8026 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8028 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8030 if (nts == STATUS_SUCCESS) {
8031 LSA_STRING packageName;
8032 /* we are registered. Find out the security package id */
8033 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8034 packageName.Length = strlen(packageName.Buffer);
8035 packageName.MaximumLength = packageName.Length + 1;
8036 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8037 if (nts == STATUS_SUCCESS) {
8039 * This code forces Windows to authenticate against the Logon Cache
8040 * first instead of attempting to authenticate against the Domain
8041 * Controller. When the Windows logon cache is enabled this improves
8042 * performance by removing the network access and works around a bug
8043 * seen at sites which are using a MIT Kerberos principal to login
8044 * to machines joined to a non-root domain in a multi-domain forest.
8046 PVOID pResponse = NULL;
8047 ULONG cbResponse = 0;
8048 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8050 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8051 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8052 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8053 OptionsRequest.DisableOptions = FALSE;
8055 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8058 sizeof(OptionsRequest),
8064 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8065 osi_Log2(smb_logp,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8067 OutputDebugString("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8070 osi_Log0(smb_logp,"MsV1_0SetProcessOption success");
8071 OutputDebugString("MsV1_0SetProcessOption success");
8073 /* END - code from Larry */
8075 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8076 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
8077 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8079 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
8082 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
8085 if (nts != STATUS_SUCCESS) {
8086 /* something went wrong. We report the error and revert back to no authentication
8087 because we can't perform any auth requests without a successful lsa handle
8088 or sec package id. */
8089 afsi_log("Reverting to NO SMB AUTH");
8090 smb_authType = SMB_AUTH_NONE;
8093 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8094 * time prevents the failure of authentication when logged into Windows with an
8095 * external Kerberos principal mapped to a local account.
8097 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8098 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8099 * then the only option is NTLMSSP anyway; so just fallback.
8104 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8105 if (secBlobLength == 0) {
8106 smb_authType = SMB_AUTH_NTLM;
8107 afsi_log("Reverting to SMB AUTH NTLM");
8116 /* Now get ourselves a domain name. */
8117 /* For now we are using the local computer name as the domain name.
8118 * It is actually the domain for local logins, and we are acting as
8119 * a local SMB server.
8121 bufsize = sizeof(smb_ServerDomainName) - 1;
8122 GetComputerName(smb_ServerDomainName, &bufsize);
8123 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8124 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8127 /* Start listeners, waiters, servers, and daemons */
8129 for (i = 0; i < lana_list.length; i++) {
8130 if (lana_list.lana[i] == 255)
8132 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8133 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8134 osi_assert(phandle != NULL);
8135 thrd_CloseHandle(phandle);
8139 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8140 NULL, 0, &lpid, "smb_ClientWaiter");
8141 osi_assert(phandle != NULL);
8142 thrd_CloseHandle(phandle);
8145 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8146 NULL, 0, &lpid, "smb_ServerWaiter");
8147 osi_assert(phandle != NULL);
8148 thrd_CloseHandle(phandle);
8150 for (i=0; i<smb_NumServerThreads; i++) {
8151 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8152 (void *) i, 0, &lpid, "smb_Server");
8153 osi_assert(phandle != NULL);
8154 thrd_CloseHandle(phandle);
8157 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8158 NULL, 0, &lpid, "smb_Daemon");
8159 osi_assert(phandle != NULL);
8160 thrd_CloseHandle(phandle);
8162 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8163 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8164 osi_assert(phandle != NULL);
8165 thrd_CloseHandle(phandle);
8174 void smb_Shutdown(void)
8184 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8186 /* setup the NCB system */
8189 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8192 /* Block new sessions by setting shutdown flag */
8193 smbShutdownFlag = 1;
8195 /* Hang up all sessions */
8196 memset((char *)ncbp, 0, sizeof(NCB));
8197 for (i = 1; i < numSessions; i++)
8199 if (dead_sessions[i])
8202 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8203 ncbp->ncb_command = NCBHANGUP;
8204 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8205 ncbp->ncb_lsn = LSNs[i];
8207 code = Netbios(ncbp);
8209 code = Netbios(ncbp, dos_ncb);
8211 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8212 if (code == 0) code = ncbp->ncb_retcode;
8214 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8215 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8219 /* Trigger the shutdown of all SMB threads */
8220 for (i = 0; i < smb_NumServerThreads; i++)
8221 thrd_SetEvent(NCBreturns[i][0]);
8223 thrd_SetEvent(NCBevents[0]);
8224 thrd_SetEvent(SessionEvents[0]);
8225 thrd_SetEvent(NCBavails[0]);
8227 for (i = 0;i < smb_NumServerThreads; i++) {
8228 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8229 if (code == WAIT_OBJECT_0) {
8232 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8233 thrd_SetEvent(NCBreturns[i--][0]);
8237 /* Delete Netbios name */
8238 memset((char *)ncbp, 0, sizeof(NCB));
8239 for (i = 0; i < lana_list.length; i++) {
8240 if (lana_list.lana[i] == 255) continue;
8241 ncbp->ncb_command = NCBDELNAME;
8242 ncbp->ncb_lana_num = lana_list.lana[i];
8243 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8245 code = Netbios(ncbp);
8247 code = Netbios(ncbp, dos_ncb);
8250 code = ncbp->ncb_retcode;
8252 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8253 ncbp->ncb_lana_num, code);
8258 /* Release the reference counts held by the VCs */
8259 lock_ObtainWrite(&smb_rctLock);
8260 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8265 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8267 if (fidp->scp != NULL) {
8270 lock_ObtainMutex(&fidp->mx);
8271 if (fidp->scp != NULL) {
8274 cm_ReleaseSCache(scp);
8276 lock_ReleaseMutex(&fidp->mx);
8280 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8282 smb_ReleaseVCNoLock(tidp->vcp);
8284 cm_user_t *userp = tidp->userp;
8286 lock_ReleaseWrite(&smb_rctLock);
8287 cm_ReleaseUser(userp);
8288 lock_ObtainWrite(&smb_rctLock);
8292 lock_ReleaseWrite(&smb_rctLock);
8295 /* Get the UNC \\<servername>\<sharename> prefix. */
8296 char *smb_GetSharename()
8300 /* Make sure we have been properly initialized. */
8301 if (smb_localNamep == NULL)
8304 /* Allocate space for \\<servername>\<sharename>, plus the
8307 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8308 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8314 void smb_LogPacket(smb_packet_t *packet)
8317 unsigned length, paramlen, datalen, i, j;
8319 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8321 if (!packet) return;
8323 osi_Log0(smb_logp, "*** SMB packet dump ***");
8325 vp = (BYTE *) packet->data;
8327 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8328 length = paramlen + 2 + datalen;
8331 for (i=0;i < length; i+=16)
8333 memset( buf, ' ', 80 );
8338 buf[strlen(buf)] = ' ';
8340 cp = (BYTE*) buf + 7;
8342 for (j=0;j < 16 && (i+j)<length; j++)
8344 *(cp++) = hex[vp[i+j] >> 4];
8345 *(cp++) = hex[vp[i+j] & 0xf];
8355 for (j=0;j < 16 && (i+j)<length;j++)
8357 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8368 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8371 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8373 #endif /* LOG_PACKET */
8376 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8384 lock_ObtainRead(&smb_rctLock);
8386 sprintf(output, "begin dumping smb_vc_t\n");
8387 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8389 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8393 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8394 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8395 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8397 sprintf(output, "begin dumping smb_fid_t\n");
8398 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8400 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8402 sprintf(output, "%s -- smb_fidp=0x%08X, refCount=%d, fid=%d, vcp=0x%08X, scp=0x%08X, ioctlp=0x%08X, NTopen_pathp=%s, NTopen_wholepathp=%s\n",
8403 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8404 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8405 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8406 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8409 sprintf(output, "done dumping smb_fid_t\n");
8410 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8413 sprintf(output, "done dumping smb_vc_t\n");
8414 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8417 lock_ReleaseRead(&smb_rctLock);