3 * Copyright 2000, International Business Machines Corporation and others.
6 * This software has been released under the terms of the IBM Public
7 * License. For details, see the LICENSE file in the top-level source
8 * directory or online at http://www.openafs.org/dl/license10.html
11 #include <afs/param.h>
18 #include <sys/timeb.h>
31 #include <WINNT\afsreg.h>
34 #include "lanahelper.h"
36 /* These characters are illegal in Windows filenames */
37 static char *illegalChars = "\\/:*?\"<>|";
38 BOOL isWindows2000 = FALSE;
40 smb_vc_t *dead_vcp = NULL;
41 smb_vc_t *active_vcp = NULL;
43 /* TODO; logout mechanism needs to be thread-safe */
44 char *loggedOutName = NULL;
45 smb_user_t *loggedOutUserp = NULL;
48 int smbShutdownFlag = 0;
50 int smb_LogoffTokenTransfer;
51 time_t smb_LogoffTransferTimeout;
53 int smb_StoreAnsiFilenames = 0;
55 DWORD last_msg_time = 0;
59 unsigned int sessionGen = 0;
61 extern void afsi_log(char *pattern, ...);
62 extern HANDLE afsi_file;
64 osi_hyper_t hzero = {0, 0};
65 osi_hyper_t hones = {0xFFFFFFFF, -1};
68 osi_rwlock_t smb_globalLock;
69 osi_rwlock_t smb_rctLock;
70 osi_mutex_t smb_ListenerLock;
73 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
76 long smb_maxObsConcurrentCalls=0;
77 long smb_concurrentCalls=0;
79 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
81 smb_packet_t *smb_packetFreeListp;
82 smb_ncb_t *smb_ncbFreeListp;
84 int smb_NumServerThreads;
86 int numNCBs, numSessions, numVCs;
88 int smb_maxVCPerServer;
89 int smb_maxMpxRequests;
91 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
93 ULONG smb_lsaSecPackage;
94 LSA_STRING smb_lsaLogonOrigin;
96 #define NCBmax MAXIMUM_WAIT_OBJECTS
97 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
98 EVENT_HANDLE **NCBreturns;
99 EVENT_HANDLE **NCBShutdown;
100 EVENT_HANDLE *smb_ServerShutdown;
101 DWORD NCBsessions[NCBmax];
103 struct smb_packet *bufs[NCBmax];
105 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
106 EVENT_HANDLE SessionEvents[Sessionmax];
107 unsigned short LSNs[Sessionmax];
108 int lanas[Sessionmax];
109 BOOL dead_sessions[Sessionmax];
113 osi_mutex_t smb_RawBufLock;
115 #define SMB_RAW_BUFS 4
117 int smb_RawBufSel[SMB_RAW_BUFS];
122 #define SMB_MASKFLAG_TILDE 1
123 #define SMB_MASKFLAG_CASEFOLD 2
125 #define RAWTIMEOUT INFINITE
128 typedef struct raw_write_cont {
141 /* dir search stuff */
142 long smb_dirSearchCounter = 1;
143 smb_dirSearch_t *smb_firstDirSearchp;
144 smb_dirSearch_t *smb_lastDirSearchp;
146 /* hide dot files? */
147 int smb_hideDotFiles;
149 /* global state about V3 protocols */
150 int smb_useV3; /* try to negotiate V3 */
153 static showErrors = 1;
154 /* MessageBox or something like it */
155 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
156 extern HANDLE WaitToTerminate;
160 * Time in Unix format of midnight, 1/1/1970 local time.
161 * When added to dosUTime, gives Unix (AFS) time.
163 time_t smb_localZero = 0;
165 /* Time difference for converting to kludge-GMT */
168 char *smb_localNamep = NULL;
170 smb_vc_t *smb_allVCsp;
172 smb_username_t *usernamesp = NULL;
174 smb_waitingLock_t *smb_allWaitingLocks;
177 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
178 NCB *ncbp, raw_write_cont_t *rwcp);
179 void smb_NetbiosInit();
181 #ifndef AFS_WIN95_ENV
182 DWORD smb_ServerExceptionFilter(void);
185 extern char cm_HostName[];
186 extern char cm_confDir[];
190 #define LPTSTR char *
191 #define GetComputerName(str, sizep) \
192 strcpy((str), cm_HostName); \
193 *(sizep) = strlen(cm_HostName)
197 void smb_LogPacket(smb_packet_t *packet);
198 #endif /* LOG_PACKET */
200 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
201 int smb_ServerDomainNameLength = 0;
202 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
203 int smb_ServerOSLength = sizeof(smb_ServerOS);
204 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
205 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
207 /* Faux server GUID. This is never checked. */
208 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
210 char * myCrt_Dispatch(int i)
215 return "(00)ReceiveCoreMakeDir";
217 return "(01)ReceiveCoreRemoveDir";
219 return "(02)ReceiveCoreOpen";
221 return "(03)ReceiveCoreCreate";
223 return "(04)ReceiveCoreClose";
225 return "(05)ReceiveCoreFlush";
227 return "(06)ReceiveCoreUnlink";
229 return "(07)ReceiveCoreRename";
231 return "(08)ReceiveCoreGetFileAttributes";
233 return "(09)ReceiveCoreSetFileAttributes";
235 return "(0a)ReceiveCoreRead";
237 return "(0b)ReceiveCoreWrite";
239 return "(0c)ReceiveCoreLockRecord";
241 return "(0d)ReceiveCoreUnlockRecord";
243 return "(0e)SendCoreBadOp";
245 return "(0f)ReceiveCoreCreate";
247 return "(10)ReceiveCoreCheckPath";
249 return "(11)SendCoreBadOp";
251 return "(12)ReceiveCoreSeek";
253 return "(1a)ReceiveCoreReadRaw";
255 return "(1d)ReceiveCoreWriteRawDummy";
257 return "(22)ReceiveV3SetAttributes";
259 return "(23)ReceiveV3GetAttributes";
261 return "(24)ReceiveV3LockingX";
263 return "(25)ReceiveV3Trans";
265 return "(26)ReceiveV3Trans[aux]";
267 return "(29)SendCoreBadOp";
269 return "(2b)ReceiveCoreEcho";
271 return "(2d)ReceiveV3OpenX";
273 return "(2e)ReceiveV3ReadX";
275 return "(32)ReceiveV3Tran2A";
277 return "(33)ReceiveV3Tran2A[aux]";
279 return "(34)ReceiveV3FindClose";
281 return "(35)ReceiveV3FindNotifyClose";
283 return "(70)ReceiveCoreTreeConnect";
285 return "(71)ReceiveCoreTreeDisconnect";
287 return "(72)ReceiveNegotiate";
289 return "(73)ReceiveV3SessionSetupX";
291 return "(74)ReceiveV3UserLogoffX";
293 return "(75)ReceiveV3TreeConnectX";
295 return "(80)ReceiveCoreGetDiskAttributes";
297 return "(81)ReceiveCoreSearchDir";
301 return "(83)FindUnique";
303 return "(84)FindClose";
305 return "(A0)ReceiveNTTransact";
307 return "(A2)ReceiveNTCreateX";
309 return "(A4)ReceiveNTCancel";
311 return "(A5)ReceiveNTRename";
313 return "(C0)OpenPrintFile";
315 return "(C1)WritePrintFile";
317 return "(C2)ClosePrintFile";
319 return "(C3)GetPrintQueue";
321 return "(D8)ReadBulk";
323 return "(D9)WriteBulk";
325 return "(DA)WriteBulkData";
327 return "unknown SMB op";
331 char * myCrt_2Dispatch(int i)
336 return "unknown SMB op-2";
338 return "S(00)CreateFile";
340 return "S(01)FindFirst";
342 return "S(02)FindNext"; /* FindNext */
344 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
348 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
350 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
352 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
354 return "S(08)??_ReceiveTran2SetFileInfo";
356 return "S(09)??_ReceiveTran2FSCTL";
358 return "S(0a)_ReceiveTran2IOCTL";
360 return "S(0b)_ReceiveTran2FindNotifyFirst";
362 return "S(0c)_ReceiveTran2FindNotifyNext";
364 return "S(0d)_ReceiveTran2CreateDirectory";
366 return "S(0e)_ReceiveTran2SessionSetup";
368 return "S(10)_ReceiveTran2GetDfsReferral";
370 return "S(11)_ReceiveTran2ReportDfsInconsistency";
374 char * myCrt_RapDispatch(int i)
379 return "unknown RAP OP";
381 return "RAP(0)NetShareEnum";
383 return "RAP(1)NetShareGetInfo";
385 return "RAP(13)NetServerGetInfo";
387 return "RAP(63)NetWkStaGetInfo";
391 /* scache must be locked */
392 unsigned int smb_Attributes(cm_scache_t *scp)
396 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
397 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
398 scp->fileType == CM_SCACHETYPE_INVALID)
400 attrs = SMB_ATTR_DIRECTORY;
401 #ifdef SPECIAL_FOLDERS
402 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
403 #endif /* SPECIAL_FOLDERS */
404 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
405 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
410 * We used to mark a file RO if it was in an RO volume, but that
411 * turns out to be impolitic in NT. See defect 10007.
414 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
415 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
417 if ((scp->unixModeBits & 0222) == 0)
418 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
424 /* Check if the named file/dir is a dotfile/dotdir */
425 /* String pointed to by lastComp can have leading slashes, but otherwise should have
426 no other patch components */
427 unsigned int smb_IsDotFile(char *lastComp) {
430 /* skip over slashes */
431 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
436 /* nulls, curdir and parent dir doesn't count */
442 if(*(s+1) == '.' && !*(s + 2))
449 static int ExtractBits(WORD bits, short start, short len)
456 num = bits << (16 - end);
457 num = num >> ((16 - end) + start);
463 void ShowUnixTime(char *FuncName, time_t unixTime)
468 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
470 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
471 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
473 int day, month, year, sec, min, hour;
476 day = ExtractBits(wDate, 0, 5);
477 month = ExtractBits(wDate, 5, 4);
478 year = ExtractBits(wDate, 9, 7) + 1980;
480 sec = ExtractBits(wTime, 0, 5);
481 min = ExtractBits(wTime, 5, 6);
482 hour = ExtractBits(wTime, 11, 5);
484 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
485 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
491 /* Determine if we are observing daylight savings time */
492 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
494 TIME_ZONE_INFORMATION timeZoneInformation;
495 SYSTEMTIME utc, local, localDST;
497 /* Get the time zone info. NT uses this to calc if we are in DST. */
498 GetTimeZoneInformation(&timeZoneInformation);
500 /* Return the daylight bias */
501 *pDstBias = timeZoneInformation.DaylightBias;
503 /* Return the bias */
504 *pBias = timeZoneInformation.Bias;
506 /* Now determine if DST is being observed */
508 /* Get the UTC (GMT) time */
511 /* Convert UTC time to local time using the time zone info. If we are
512 observing DST, the calculated local time will include this.
514 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
516 /* Set the daylight bias to 0. The daylight bias is the amount of change
517 * in time that we use for daylight savings time. By setting this to 0
518 * we cause there to be no change in time during daylight savings time.
520 timeZoneInformation.DaylightBias = 0;
522 /* Convert the utc time to local time again, but this time without any
523 adjustment for daylight savings time.
525 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
527 /* If the two times are different, then it means that the localDST that
528 we calculated includes the daylight bias, and therefore we are
529 observing daylight savings time.
531 *pDST = localDST.wHour != local.wHour;
534 /* Determine if we are observing daylight savings time */
535 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
541 *pDstBias = -60; /* where can this be different? */
547 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
549 BOOL dst; /* Will be TRUE if observing DST */
550 LONG dstBias; /* Offset from local time if observing DST */
551 LONG bias; /* Offset from GMT for local time */
554 * This function will adjust the last write time to compensate
555 * for two bugs in the smb client:
557 * 1) During Daylight Savings Time, the LastWriteTime is ahead
558 * in time by the DaylightBias (ignoring the sign - the
559 * DaylightBias is always stored as a negative number). If
560 * the DaylightBias is -60, then the LastWriteTime will be
561 * ahead by 60 minutes.
563 * 2) If the local time zone is a positive offset from GMT, then
564 * the LastWriteTime will be the correct local time plus the
565 * Bias (ignoring the sign - a positive offset from GMT is
566 * always stored as a negative Bias). If the Bias is -120,
567 * then the LastWriteTime will be ahead by 120 minutes.
569 * These bugs can occur at the same time.
572 GetTimeZoneInfo(&dst, &dstBias, &bias);
574 /* First adjust for DST */
576 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
578 /* Now adjust for a positive offset from GMT (a negative bias). */
580 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
584 * Calculate the difference (in seconds) between local time and GMT.
585 * This enables us to convert file times to kludge-GMT.
591 struct tm gmt_tm, local_tm;
592 int days, hours, minutes, seconds;
595 gmt_tm = *(gmtime(&t));
596 local_tm = *(localtime(&t));
598 days = local_tm.tm_yday - gmt_tm.tm_yday;
599 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
601 /* There is a problem with DST immediately after the time change
602 * which may continue to exist until the machine is rebooted
604 - (local_tm.tm_isdst ? 1 : 0)
607 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
608 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
614 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
619 time_t ersatz_unixTime;
622 * Must use kludge-GMT instead of real GMT.
623 * kludge-GMT is computed by adding time zone difference to localtime.
626 * ltp = gmtime(&unixTime);
628 ersatz_unixTime = unixTime - smb_NowTZ;
629 ltp = localtime(&ersatz_unixTime);
631 /* if we fail, make up something */
634 localJunk.tm_year = 89 - 20;
635 localJunk.tm_mon = 4;
636 localJunk.tm_mday = 12;
637 localJunk.tm_hour = 0;
638 localJunk.tm_min = 0;
639 localJunk.tm_sec = 0;
642 stm.wYear = ltp->tm_year + 1900;
643 stm.wMonth = ltp->tm_mon + 1;
644 stm.wDayOfWeek = ltp->tm_wday;
645 stm.wDay = ltp->tm_mday;
646 stm.wHour = ltp->tm_hour;
647 stm.wMinute = ltp->tm_min;
648 stm.wSecond = ltp->tm_sec;
649 stm.wMilliseconds = 0;
651 SystemTimeToFileTime(&stm, largeTimep);
654 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
656 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
657 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
658 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
660 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
662 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
663 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
665 *ft = LargeIntegerMultiplyByLong(*ft, 60);
666 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
669 ut = ConvertLongToLargeInteger(unixTime);
670 ut = LargeIntegerMultiplyByLong(ut, 10000000);
671 *ft = LargeIntegerAdd(*ft, ut);
676 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
682 FileTimeToSystemTime(largeTimep, &stm);
684 lt.tm_year = stm.wYear - 1900;
685 lt.tm_mon = stm.wMonth - 1;
686 lt.tm_wday = stm.wDayOfWeek;
687 lt.tm_mday = stm.wDay;
688 lt.tm_hour = stm.wHour;
689 lt.tm_min = stm.wMinute;
690 lt.tm_sec = stm.wSecond;
693 save_timezone = _timezone;
694 _timezone += smb_NowTZ;
695 *unixTimep = mktime(<);
696 _timezone = save_timezone;
699 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
701 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
702 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
703 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
707 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
708 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
709 a = LargeIntegerMultiplyByLong(a, 60);
710 a = LargeIntegerMultiplyByLong(a, 10000000);
712 /* subtract it from ft */
713 a = LargeIntegerSubtract(*ft, a);
715 /* divide down to seconds */
716 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
720 void smb_SearchTimeFromUnixTime(time_t *dosTimep, time_t unixTime)
728 ltp = localtime((time_t*) &t);
730 /* if we fail, make up something */
733 localJunk.tm_year = 89 - 20;
734 localJunk.tm_mon = 4;
735 localJunk.tm_mday = 12;
736 localJunk.tm_hour = 0;
737 localJunk.tm_min = 0;
738 localJunk.tm_sec = 0;
741 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
742 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
743 *dosTimep = (dosDate<<16) | dosTime;
746 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
748 unsigned short dosDate;
749 unsigned short dosTime;
752 dosDate = (unsigned short) (searchTime & 0xffff);
753 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
755 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
756 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
757 localTm.tm_mday = (dosDate) & 0x1f;
758 localTm.tm_hour = (dosTime>>11) & 0x1f;
759 localTm.tm_min = (dosTime >> 5) & 0x3f;
760 localTm.tm_sec = (dosTime & 0x1f) * 2;
761 localTm.tm_isdst = -1; /* compute whether DST in effect */
763 *unixTimep = mktime(&localTm);
766 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
768 *dosUTimep = unixTime - smb_localZero;
771 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
774 *unixTimep = dosTime + smb_localZero;
776 /* dosTime seems to be already adjusted for GMT */
777 *unixTimep = dosTime;
781 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
785 lock_ObtainWrite(&smb_rctLock);
786 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
787 if (lsn == vcp->lsn && lana == vcp->lana) {
788 smb_HoldVCNoLock(vcp);
792 if (!vcp && (flags & SMB_FLAG_CREATE)) {
793 vcp = malloc(sizeof(*vcp));
794 memset(vcp, 0, sizeof(*vcp));
795 vcp->vcID = numVCs++;
799 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
800 vcp->nextp = smb_allVCsp;
802 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
807 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
808 /* We must obtain a challenge for extended auth
809 * in case the client negotiates smb v3
811 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
812 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
813 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
814 ULONG lsaRespSize = 0;
816 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
818 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
825 if (nts != STATUS_SUCCESS)
826 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
827 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
828 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
830 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
831 LsaFreeReturnBuffer(lsaResp);
834 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
836 lock_ReleaseWrite(&smb_rctLock);
840 int smb_IsStarMask(char *maskp)
845 for(i=0; i<11; i++) {
847 if (tc == '?' || tc == '*' || tc == '>') return 1;
852 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
854 osi_assert(vcp->refCount-- != 0);
857 void smb_ReleaseVC(smb_vc_t *vcp)
859 lock_ObtainWrite(&smb_rctLock);
860 osi_assert(vcp->refCount-- != 0);
861 lock_ReleaseWrite(&smb_rctLock);
864 void smb_HoldVCNoLock(smb_vc_t *vcp)
869 void smb_HoldVC(smb_vc_t *vcp)
871 lock_ObtainWrite(&smb_rctLock);
873 lock_ReleaseWrite(&smb_rctLock);
876 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
880 lock_ObtainWrite(&smb_rctLock);
881 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
882 if (tid == tidp->tid) {
887 if (!tidp && (flags & SMB_FLAG_CREATE)) {
888 tidp = malloc(sizeof(*tidp));
889 memset(tidp, 0, sizeof(*tidp));
890 tidp->nextp = vcp->tidsp;
893 smb_HoldVCNoLock(vcp);
895 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
898 lock_ReleaseWrite(&smb_rctLock);
902 void smb_ReleaseTID(smb_tid_t *tidp)
909 lock_ObtainWrite(&smb_rctLock);
910 osi_assert(tidp->refCount-- > 0);
911 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
912 ltpp = &tidp->vcp->tidsp;
913 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
917 osi_assert(tp != NULL);
919 lock_FinalizeMutex(&tidp->mx);
920 userp = tidp->userp; /* remember to drop ref later */
922 smb_ReleaseVCNoLock(tidp->vcp);
925 lock_ReleaseWrite(&smb_rctLock);
927 cm_ReleaseUser(userp);
930 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
932 smb_user_t *uidp = NULL;
934 lock_ObtainWrite(&smb_rctLock);
935 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
936 if (uid == uidp->userID) {
938 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
939 (int)vcp, uidp->userID,
940 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
944 if (!uidp && (flags & SMB_FLAG_CREATE)) {
945 uidp = malloc(sizeof(*uidp));
946 memset(uidp, 0, sizeof(*uidp));
947 uidp->nextp = vcp->usersp;
950 smb_HoldVCNoLock(vcp);
952 lock_InitializeMutex(&uidp->mx, "user_t mutex");
954 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 : ""));
956 lock_ReleaseWrite(&smb_rctLock);
960 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
962 smb_username_t *unp= NULL;
964 lock_ObtainWrite(&smb_rctLock);
965 for(unp = usernamesp; unp; unp = unp->nextp) {
966 if (stricmp(unp->name, usern) == 0 &&
967 stricmp(unp->machine, machine) == 0) {
972 if (!unp && (flags & SMB_FLAG_CREATE)) {
973 unp = malloc(sizeof(*unp));
974 memset(unp, 0, sizeof(*unp));
976 unp->nextp = usernamesp;
977 unp->name = strdup(usern);
978 unp->machine = strdup(machine);
980 lock_InitializeMutex(&unp->mx, "username_t mutex");
982 lock_ReleaseWrite(&smb_rctLock);
986 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
988 smb_user_t *uidp= NULL;
990 lock_ObtainWrite(&smb_rctLock);
991 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
994 if (stricmp(uidp->unp->name, usern) == 0) {
996 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
1001 lock_ReleaseWrite(&smb_rctLock);
1004 void smb_ReleaseUID(smb_user_t *uidp)
1011 lock_ObtainWrite(&smb_rctLock);
1012 osi_assert(uidp->refCount-- > 0);
1013 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1014 lupp = &uidp->vcp->usersp;
1015 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1019 osi_assert(up != NULL);
1021 lock_FinalizeMutex(&uidp->mx);
1023 userp = uidp->unp->userp; /* avoid deadlock by releasing */
1024 uidp->unp->userp = NULL; /* after releasing the lock */
1026 smb_ReleaseVCNoLock(uidp->vcp);
1029 lock_ReleaseWrite(&smb_rctLock);
1031 cm_ReleaseUserVCRef(userp);
1032 cm_ReleaseUser(userp);
1037 /* retrieve a held reference to a user structure corresponding to an incoming
1039 * corresponding release function is cm_ReleaseUser.
1041 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1047 smbp = (smb_t *) inp;
1048 uidp = smb_FindUID(vcp, smbp->uid, 0);
1049 if ((!uidp) || (!uidp->unp))
1052 lock_ObtainMutex(&uidp->mx);
1053 up = uidp->unp->userp;
1055 lock_ReleaseMutex(&uidp->mx);
1057 smb_ReleaseUID(uidp);
1063 * Return a pointer to a pathname extracted from a TID structure. The
1064 * TID structure is not held; assume it won't go away.
1066 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1071 tidp = smb_FindTID(vcp, tid, 0);
1075 if (tidp->flags & SMB_TIDFLAG_IPC) {
1076 code = CM_ERROR_TIDIPC;
1077 /* tidp->pathname would be NULL, but that's fine */
1079 *treepath = tidp->pathname;
1080 smb_ReleaseTID(tidp);
1085 /* check to see if we have a chained fid, that is, a fid that comes from an
1086 * OpenAndX message that ran earlier in this packet. In this case, the fid
1087 * field in a read, for example, request, isn't set, since the value is
1088 * supposed to be inherited from the openAndX call.
1090 int smb_ChainFID(int fid, smb_packet_t *inp)
1092 if (inp->fid == 0 || inp->inCount == 0)
1098 /* are we a priv'd user? What does this mean on NT? */
1099 int smb_SUser(cm_user_t *userp)
1104 /* find a file ID. If we pass in 0 we select an used File ID.
1105 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1106 * smb_fid_t data structure if desired File ID cannot be found.
1108 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1113 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1116 lock_ObtainWrite(&smb_rctLock);
1117 /* figure out if we need to allocate a new file ID */
1120 fid = vcp->fidCounter;
1124 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1125 if (fid == fidp->fid) {
1136 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1137 char eventName[MAX_PATH];
1139 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1140 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1141 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1142 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1143 thrd_CloseHandle(event);
1150 fidp = malloc(sizeof(*fidp));
1151 memset(fidp, 0, sizeof(*fidp));
1152 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1155 smb_HoldVCNoLock(vcp);
1156 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1158 fidp->curr_chunk = fidp->prev_chunk = -2;
1159 fidp->raw_write_event = event;
1161 vcp->fidCounter = fid+1;
1162 if (vcp->fidCounter == 0)
1163 vcp->fidCounter = 1;
1166 lock_ReleaseWrite(&smb_rctLock);
1170 void smb_ReleaseFID(smb_fid_t *fidp)
1173 smb_vc_t *vcp = NULL;
1174 smb_ioctl_t *ioctlp;
1180 lock_ObtainWrite(&smb_rctLock);
1181 osi_assert(fidp->refCount-- > 0);
1182 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1185 scp = fidp->scp; /* release after lock is released */
1188 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1189 thrd_CloseHandle(fidp->raw_write_event);
1191 /* and see if there is ioctl stuff to free */
1192 ioctlp = fidp->ioctlp;
1195 cm_FreeSpace(ioctlp->prefix);
1196 if (ioctlp->inAllocp)
1197 free(ioctlp->inAllocp);
1198 if (ioctlp->outAllocp)
1199 free(ioctlp->outAllocp);
1205 smb_ReleaseVCNoLock(vcp);
1207 lock_ReleaseWrite(&smb_rctLock);
1209 /* now release the scache structure */
1211 cm_ReleaseSCache(scp);
1215 * Case-insensitive search for one string in another;
1216 * used to find variable names in submount pathnames.
1218 static char *smb_stristr(char *str1, char *str2)
1222 for (cursor = str1; *cursor; cursor++)
1223 if (stricmp(cursor, str2) == 0)
1230 * Substitute a variable value for its name in a submount pathname. Variable
1231 * name has been identified by smb_stristr() and is in substr. Variable name
1232 * length (plus one) is in substr_size. Variable value is in newstr.
1234 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1239 strcpy(temp, substr + substr_size - 1);
1240 strcpy(substr, newstr);
1244 char VNUserName[] = "%USERNAME%";
1245 char VNLCUserName[] = "%LCUSERNAME%";
1246 char VNComputerName[] = "%COMPUTERNAME%";
1247 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1250 /* List available shares */
1251 int smb_ListShares()
1255 char shareBuf[4096];
1263 /*strcpy(shareNameList[num_shares], "all");
1264 strcpy(pathNameList[num_shares++], "/afs");*/
1265 fprintf(stderr, "The following shares are available:\n");
1266 fprintf(stderr, "Share Name (AFS Path)\n");
1267 fprintf(stderr, "---------------------\n");
1268 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1271 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1272 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1274 strcpy(sbmtpath, cm_confDir);
1276 strcat(sbmtpath, "/afsdsbmt.ini");
1277 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1278 shareBuf, sizeof(shareBuf),
1284 this_share = shareBuf;
1288 /*strcpy(shareNameList[num_shares], this_share);*/
1289 len = GetPrivateProfileString("AFS Submounts", this_share,
1296 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1299 if (*p == '\\') *p = '/'; /* change to / */
1303 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1304 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1307 while (*this_share != 0) this_share++; /* find next NUL */
1308 this_share++; /* skip past the NUL */
1309 } while (*this_share != 0); /* stop at final NUL */
1315 typedef struct smb_findShare_rock {
1319 } smb_findShare_rock_t;
1321 #define SMB_FINDSHARE_EXACT_MATCH 1
1322 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1324 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1328 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1329 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1330 if(!stricmp(dep->name, vrock->shareName))
1331 matchType = SMB_FINDSHARE_EXACT_MATCH;
1333 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1334 if(vrock->match) free(vrock->match);
1335 vrock->match = strdup(dep->name);
1336 vrock->matchType = matchType;
1338 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1339 return CM_ERROR_STOPNOW;
1345 /* find a shareName in the table of submounts */
1346 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1350 char pathName[1024];
1355 char sbmtpath[MAX_PATH];
1360 DWORD allSubmount = 1;
1362 /* if allSubmounts == 0, only return the //mountRoot/all share
1363 * if in fact it has been been created in the subMounts table.
1364 * This is to allow sites that want to restrict access to the
1367 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1368 0, KEY_QUERY_VALUE, &parmKey);
1369 if (code == ERROR_SUCCESS) {
1370 len = sizeof(allSubmount);
1371 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1372 (BYTE *) &allSubmount, &len);
1373 if (code != ERROR_SUCCESS) {
1376 RegCloseKey (parmKey);
1379 if (allSubmount && _stricmp(shareName, "all") == 0) {
1384 /* In case, the all share is disabled we need to still be able
1385 * to handle ioctl requests
1387 if (_stricmp(shareName, "ioctl$") == 0) {
1388 *pathNamep = strdup("/.__ioctl__");
1392 if (_stricmp(shareName, "IPC$") == 0 ||
1393 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1394 _stricmp(shareName, "DESKTOP.INI") == 0
1401 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1402 0, KEY_QUERY_VALUE, &parmKey);
1403 if (code == ERROR_SUCCESS) {
1404 len = sizeof(pathName);
1405 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1406 (BYTE *) pathName, &len);
1407 if (code != ERROR_SUCCESS)
1409 RegCloseKey (parmKey);
1414 strcpy(sbmtpath, cm_confDir);
1415 strcat(sbmtpath, "/afsdsbmt.ini");
1416 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1417 pathName, sizeof(pathName), sbmtpath);
1419 if (len != 0 && len != sizeof(pathName) - 1) {
1420 /* We can accept either unix or PC style AFS pathnames. Convert
1421 * Unix-style to PC style here for internal use.
1424 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1425 p += strlen(cm_mountRoot); /* skip mount path */
1428 if (*q == '/') *q = '\\'; /* change to \ */
1434 if (var = smb_stristr(p, VNUserName)) {
1435 if (uidp && uidp->unp)
1436 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1438 smb_subst(p, var, sizeof(VNUserName)," ");
1440 else if (var = smb_stristr(p, VNLCUserName))
1442 if (uidp && uidp->unp)
1443 strcpy(temp, uidp->unp->name);
1447 smb_subst(p, var, sizeof(VNLCUserName), temp);
1449 else if (var = smb_stristr(p, VNComputerName))
1451 sizeTemp = sizeof(temp);
1452 GetComputerName((LPTSTR)temp, &sizeTemp);
1453 smb_subst(p, var, sizeof(VNComputerName), temp);
1455 else if (var = smb_stristr(p, VNLCComputerName))
1457 sizeTemp = sizeof(temp);
1458 GetComputerName((LPTSTR)temp, &sizeTemp);
1460 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1465 *pathNamep = strdup(p);
1470 /* First lookup shareName in root.afs */
1472 smb_findShare_rock_t vrock;
1474 char * p = shareName;
1477 /* attempt to locate a partial match in root.afs. This is because
1478 when using the ANSI RAP calls, the share name is limited to 13 chars
1479 and hence is truncated. Of course we prefer exact matches. */
1481 thyper.HighPart = 0;
1484 vrock.shareName = shareName;
1486 vrock.matchType = 0;
1488 cm_HoldSCache(cm_data.rootSCachep);
1489 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1490 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1491 cm_ReleaseSCache(cm_data.rootSCachep);
1493 if (vrock.matchType) {
1494 sprintf(pathName,"/%s/",vrock.match);
1495 *pathNamep = strdup(strlwr(pathName));
1500 /* if we get here, there was no match for the share in root.afs */
1501 /* so try to create \\<netbiosName>\<cellname> */
1506 /* Get the full name for this cell */
1507 code = cm_SearchCellFile(p, temp, 0, 0);
1508 #ifdef AFS_AFSDB_ENV
1509 if (code && cm_dnsEnabled) {
1511 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1514 /* construct the path */
1516 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1517 *pathNamep = strdup(strlwr(pathName));
1526 /* Client-side offline caching policy types */
1527 #define CSC_POLICY_MANUAL 0
1528 #define CSC_POLICY_DOCUMENTS 1
1529 #define CSC_POLICY_PROGRAMS 2
1530 #define CSC_POLICY_DISABLE 3
1532 int smb_FindShareCSCPolicy(char *shareName)
1538 int retval = CSC_POLICY_MANUAL;
1540 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1541 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1544 REG_OPTION_NON_VOLATILE,
1550 len = sizeof(policy);
1551 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1553 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1555 else if (stricmp(policy, "documents") == 0)
1557 retval = CSC_POLICY_DOCUMENTS;
1559 else if (stricmp(policy, "programs") == 0)
1561 retval = CSC_POLICY_PROGRAMS;
1563 else if (stricmp(policy, "disable") == 0)
1565 retval = CSC_POLICY_DISABLE;
1568 RegCloseKey(hkCSCPolicy);
1572 /* find a dir search structure by cookie value, and return it held.
1573 * Must be called with smb_globalLock held.
1575 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1577 smb_dirSearch_t *dsp;
1579 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1580 if (dsp->cookie == cookie) {
1581 if (dsp != smb_firstDirSearchp) {
1582 /* move to head of LRU queue, too, if we're not already there */
1583 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1584 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1585 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1586 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1587 if (!smb_lastDirSearchp)
1588 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1590 lock_ObtainMutex(&dsp->mx);
1592 lock_ReleaseMutex(&dsp->mx);
1598 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1599 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1600 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1606 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1608 lock_ObtainWrite(&smb_globalLock);
1609 lock_ObtainMutex(&dsp->mx);
1610 dsp->flags |= SMB_DIRSEARCH_DELETE;
1611 if (dsp->scp != NULL) {
1612 lock_ObtainMutex(&dsp->scp->mx);
1613 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1614 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1615 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1616 dsp->scp->bulkStatProgress = hones;
1618 lock_ReleaseMutex(&dsp->scp->mx);
1620 lock_ReleaseMutex(&dsp->mx);
1621 lock_ReleaseWrite(&smb_globalLock);
1624 /* Must be called with the smb_globalLock held */
1625 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1627 cm_scache_t *scp = NULL;
1629 lock_ObtainMutex(&dsp->mx);
1630 osi_assert(dsp->refCount-- > 0);
1631 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1632 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1633 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1634 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1635 lock_ReleaseMutex(&dsp->mx);
1636 lock_FinalizeMutex(&dsp->mx);
1640 lock_ReleaseMutex(&dsp->mx);
1642 /* do this now to avoid spurious locking hierarchy creation */
1643 if (scp) cm_ReleaseSCache(scp);
1646 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1648 lock_ObtainWrite(&smb_globalLock);
1649 smb_ReleaseDirSearchNoLock(dsp);
1650 lock_ReleaseWrite(&smb_globalLock);
1653 /* find a dir search structure by cookie value, and return it held */
1654 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1656 smb_dirSearch_t *dsp;
1658 lock_ObtainWrite(&smb_globalLock);
1659 dsp = smb_FindDirSearchNoLock(cookie);
1660 lock_ReleaseWrite(&smb_globalLock);
1664 /* GC some dir search entries, in the address space expected by the specific protocol.
1665 * Must be called with smb_globalLock held; release the lock temporarily.
1667 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1668 void smb_GCDirSearches(int isV3)
1670 smb_dirSearch_t *prevp;
1671 smb_dirSearch_t *tp;
1672 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1676 victimCount = 0; /* how many have we got so far */
1677 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1678 /* we'll move tp from queue, so
1681 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1682 /* if no one is using this guy, and we're either in the new protocol,
1683 * or we're in the old one and this is a small enough ID to be useful
1684 * to the old protocol, GC this guy.
1686 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1687 /* hold and delete */
1688 tp->flags |= SMB_DIRSEARCH_DELETE;
1689 victimsp[victimCount++] = tp;
1693 /* don't do more than this */
1694 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1698 /* now release them */
1699 for (i = 0; i < victimCount; i++) {
1700 smb_ReleaseDirSearchNoLock(victimsp[i]);
1704 /* function for allocating a dir search entry. We need these to remember enough context
1705 * since we don't get passed the path from call to call during a directory search.
1707 * Returns a held dir search structure, and bumps the reference count on the vnode,
1708 * since it saves a pointer to the vnode.
1710 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1712 smb_dirSearch_t *dsp;
1718 lock_ObtainWrite(&smb_globalLock);
1721 /* what's the biggest ID allowed in this version of the protocol */
1722 maxAllowed = isV3 ? 65535 : 255;
1723 if (smb_dirSearchCounter > maxAllowed)
1724 smb_dirSearchCounter = 1;
1726 start = smb_dirSearchCounter;
1729 /* twice so we have enough tries to find guys we GC after one pass;
1730 * 10 extra is just in case I mis-counted.
1732 if (++counter > 2*maxAllowed+10)
1733 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1735 if (smb_dirSearchCounter > maxAllowed) {
1736 smb_dirSearchCounter = 1;
1738 if (smb_dirSearchCounter == start) {
1740 smb_GCDirSearches(isV3);
1743 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1745 /* don't need to watch for refcount zero and deleted, since
1746 * we haven't dropped the global lock.
1748 lock_ObtainMutex(&dsp->mx);
1750 lock_ReleaseMutex(&dsp->mx);
1751 ++smb_dirSearchCounter;
1755 dsp = malloc(sizeof(*dsp));
1756 memset(dsp, 0, sizeof(*dsp));
1757 dsp->cookie = smb_dirSearchCounter;
1758 ++smb_dirSearchCounter;
1760 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1761 dsp->lastTime = osi_Time();
1762 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1763 if (!smb_lastDirSearchp)
1764 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1767 lock_ReleaseWrite(&smb_globalLock);
1771 static smb_packet_t *GetPacket(void)
1775 unsigned int npar, seg, tb_sel;
1778 lock_ObtainWrite(&smb_globalLock);
1779 tbp = smb_packetFreeListp;
1781 smb_packetFreeListp = tbp->nextp;
1782 lock_ReleaseWrite(&smb_globalLock);
1785 tbp = calloc(65540,1);
1787 tbp = malloc(sizeof(smb_packet_t));
1789 tbp->magic = SMB_PACKETMAGIC;
1792 tbp->resumeCode = 0;
1798 tbp->ncb_length = 0;
1803 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1806 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1808 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1810 osi_panic("",__FILE__,__LINE__);
1813 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1818 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1819 tbp->dos_pkt_sel = tb_sel;
1822 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1827 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1831 memcpy(tbp, pkt, sizeof(smb_packet_t));
1832 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1836 static NCB *GetNCB(void)
1841 unsigned int npar, seg, tb_sel;
1844 lock_ObtainWrite(&smb_globalLock);
1845 tbp = smb_ncbFreeListp;
1847 smb_ncbFreeListp = tbp->nextp;
1848 lock_ReleaseWrite(&smb_globalLock);
1851 tbp = calloc(sizeof(*tbp),1);
1853 tbp = malloc(sizeof(*tbp));
1854 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1857 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1859 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1861 osi_panic("",__FILE__,__LINE__);
1863 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1868 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1869 tbp->dos_ncb_sel = tb_sel;
1871 tbp->magic = SMB_NCBMAGIC;
1874 osi_assert(tbp->magic == SMB_NCBMAGIC);
1876 memset(&tbp->ncb, 0, sizeof(NCB));
1879 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1884 void smb_FreePacket(smb_packet_t *tbp)
1886 smb_vc_t * vcp = NULL;
1887 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1889 lock_ObtainWrite(&smb_globalLock);
1890 tbp->nextp = smb_packetFreeListp;
1891 smb_packetFreeListp = tbp;
1892 tbp->magic = SMB_PACKETMAGIC;
1896 tbp->resumeCode = 0;
1902 tbp->ncb_length = 0;
1904 lock_ReleaseWrite(&smb_globalLock);
1910 static void FreeNCB(NCB *bufferp)
1914 tbp = (smb_ncb_t *) bufferp;
1915 osi_assert(tbp->magic == SMB_NCBMAGIC);
1917 lock_ObtainWrite(&smb_globalLock);
1918 tbp->nextp = smb_ncbFreeListp;
1919 smb_ncbFreeListp = tbp;
1920 lock_ReleaseWrite(&smb_globalLock);
1923 /* get a ptr to the data part of a packet, and its count */
1924 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1928 unsigned char *afterParmsp;
1930 parmBytes = *smbp->wctp << 1;
1931 afterParmsp = smbp->wctp + parmBytes + 1;
1933 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1934 if (nbytesp) *nbytesp = dataBytes;
1936 /* don't forget to skip the data byte count, since it follows
1937 * the parameters; that's where the "2" comes from below.
1939 return (unsigned char *) (afterParmsp + 2);
1942 /* must set all the returned parameters before playing around with the
1943 * data region, since the data region is located past the end of the
1944 * variable number of parameters.
1946 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1948 unsigned char *afterParmsp;
1950 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1952 *afterParmsp++ = dsize & 0xff;
1953 *afterParmsp = (dsize>>8) & 0xff;
1956 /* return the parm'th parameter in the smbp packet */
1957 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1960 unsigned char *parmDatap;
1962 parmCount = *smbp->wctp;
1964 if (parm >= parmCount) {
1969 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1971 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1972 parm, parmCount, smbp->ncb_length);
1975 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1976 1, smbp->ncb_length, ptbuf, smbp);
1977 DeregisterEventSource(h);
1979 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
1980 parm, parmCount, smbp->ncb_length);
1981 osi_panic(s, __FILE__, __LINE__);
1983 parmDatap = smbp->wctp + (2*parm) + 1;
1985 return parmDatap[0] + (parmDatap[1] << 8);
1988 /* return the parm'th parameter in the smbp packet */
1989 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1992 unsigned char *parmDatap;
1994 parmCount = *smbp->wctp;
1996 if (parm * 2 + offset >= parmCount * 2) {
2001 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2003 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2004 parm, offset, parmCount, smbp->ncb_length);
2007 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2008 1, smbp->ncb_length, ptbuf, smbp);
2009 DeregisterEventSource(h);
2011 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2012 parm, offset, parmCount, smbp->ncb_length);
2013 osi_panic(s, __FILE__, __LINE__);
2015 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2017 return parmDatap[0] + (parmDatap[1] << 8);
2020 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2024 /* make sure we have enough slots */
2025 if (*smbp->wctp <= slot)
2026 *smbp->wctp = slot+1;
2028 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2029 *parmDatap++ = parmValue & 0xff;
2030 *parmDatap = (parmValue>>8) & 0xff;
2033 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2037 /* make sure we have enough slots */
2038 if (*smbp->wctp <= slot)
2039 *smbp->wctp = slot+2;
2041 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2042 *parmDatap++ = parmValue & 0xff;
2043 *parmDatap++ = (parmValue>>8) & 0xff;
2044 *parmDatap++ = (parmValue>>16) & 0xff;
2045 *parmDatap++ = (parmValue>>24) & 0xff;
2048 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2053 /* make sure we have enough slots */
2054 if (*smbp->wctp <= slot)
2055 *smbp->wctp = slot+4;
2057 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2059 *parmDatap++ = *parmValuep++;
2062 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2066 /* make sure we have enough slots */
2067 if (*smbp->wctp <= slot) {
2068 if (smbp->oddByte) {
2070 *smbp->wctp = slot+1;
2075 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2076 *parmDatap++ = parmValue & 0xff;
2079 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2083 lastSlashp = strrchr(inPathp, '\\');
2085 *lastComponentp = lastSlashp;
2088 if (inPathp == lastSlashp)
2090 *outPathp++ = *inPathp++;
2099 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2104 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2109 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2115 tlen = inp[0] + (inp[1]<<8);
2116 inp += 2; /* skip length field */
2119 *chainpp = inp + tlen;
2128 /* format a packet as a response */
2129 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2134 outp = (smb_t *) op;
2136 /* zero the basic structure through the smb_wct field, and zero the data
2137 * size field, assuming that wct stays zero; otherwise, you have to
2138 * explicitly set the data size field, too.
2140 inSmbp = (smb_t *) inp;
2141 memset(outp, 0, sizeof(smb_t)+2);
2147 outp->com = inSmbp->com;
2148 outp->tid = inSmbp->tid;
2149 outp->pid = inSmbp->pid;
2150 outp->uid = inSmbp->uid;
2151 outp->mid = inSmbp->mid;
2152 outp->res[0] = inSmbp->res[0];
2153 outp->res[1] = inSmbp->res[1];
2154 op->inCom = inSmbp->com;
2156 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2157 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2159 /* copy fields in generic packet area */
2160 op->wctp = &outp->wct;
2163 /* send a (probably response) packet; vcp tells us to whom to send it.
2164 * we compute the length by looking at wct and bcc fields.
2166 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2183 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2186 memset((char *)ncbp, 0, sizeof(NCB));
2188 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2189 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2190 extra += tp[0] + (tp[1]<<8);
2191 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2192 extra += 3; /* wct and length fields */
2194 ncbp->ncb_length = extra; /* bytes to send */
2195 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2196 ncbp->ncb_lana_num = vcp->lana;
2197 ncbp->ncb_command = NCBSEND; /* op means send data */
2199 ncbp->ncb_buffer = (char *) inp;/* packet */
2200 code = Netbios(ncbp);
2202 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2203 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2205 /* copy header information from virtual to DOS address space */
2206 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2207 code = Netbios(ncbp, dos_ncb);
2211 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2217 void smb_MapNTError(long code, unsigned long *NTStatusp)
2219 unsigned long NTStatus;
2221 /* map CM_ERROR_* errors to NT 32-bit status codes */
2222 /* NT Status codes are listed in ntstatus.h not winerror.h */
2223 if (code == CM_ERROR_NOSUCHCELL) {
2224 NTStatus = 0xC000000FL; /* No such file */
2226 else if (code == CM_ERROR_NOSUCHVOLUME) {
2227 NTStatus = 0xC000000FL; /* No such file */
2229 else if (code == CM_ERROR_TIMEDOUT) {
2230 NTStatus = 0xC00000CFL; /* Sharing Paused */
2232 else if (code == CM_ERROR_RETRY) {
2233 NTStatus = 0xC000022DL; /* Retry */
2235 else if (code == CM_ERROR_NOACCESS) {
2236 NTStatus = 0xC0000022L; /* Access denied */
2238 else if (code == CM_ERROR_READONLY) {
2239 NTStatus = 0xC00000A2L; /* Write protected */
2241 else if (code == CM_ERROR_NOSUCHFILE) {
2242 NTStatus = 0xC000000FL; /* No such file */
2244 else if (code == CM_ERROR_NOSUCHPATH) {
2245 NTStatus = 0xC000003AL; /* Object path not found */
2247 else if (code == CM_ERROR_TOOBIG) {
2248 NTStatus = 0xC000007BL; /* Invalid image format */
2250 else if (code == CM_ERROR_INVAL) {
2251 NTStatus = 0xC000000DL; /* Invalid parameter */
2253 else if (code == CM_ERROR_BADFD) {
2254 NTStatus = 0xC0000008L; /* Invalid handle */
2256 else if (code == CM_ERROR_BADFDOP) {
2257 NTStatus = 0xC0000022L; /* Access denied */
2259 else if (code == CM_ERROR_EXISTS) {
2260 NTStatus = 0xC0000035L; /* Object name collision */
2262 else if (code == CM_ERROR_NOTEMPTY) {
2263 NTStatus = 0xC0000101L; /* Directory not empty */
2265 else if (code == CM_ERROR_CROSSDEVLINK) {
2266 NTStatus = 0xC00000D4L; /* Not same device */
2268 else if (code == CM_ERROR_NOTDIR) {
2269 NTStatus = 0xC0000103L; /* Not a directory */
2271 else if (code == CM_ERROR_ISDIR) {
2272 NTStatus = 0xC00000BAL; /* File is a directory */
2274 else if (code == CM_ERROR_BADOP) {
2276 /* I have no idea where this comes from */
2277 NTStatus = 0xC09820FFL; /* SMB no support */
2279 NTStatus = 0xC00000BBL; /* Not supported */
2280 #endif /* COMMENT */
2282 else if (code == CM_ERROR_BADSHARENAME) {
2283 NTStatus = 0xC00000CCL; /* Bad network name */
2285 else if (code == CM_ERROR_NOIPC) {
2287 NTStatus = 0xC0000022L; /* Access Denied */
2289 NTStatus = 0xC000013DL; /* Remote Resources */
2292 else if (code == CM_ERROR_CLOCKSKEW) {
2293 NTStatus = 0xC0000133L; /* Time difference at DC */
2295 else if (code == CM_ERROR_BADTID) {
2296 NTStatus = 0xC0982005L; /* SMB bad TID */
2298 else if (code == CM_ERROR_USESTD) {
2299 NTStatus = 0xC09820FBL; /* SMB use standard */
2301 else if (code == CM_ERROR_QUOTA) {
2303 NTStatus = 0xC0000044L; /* Quota exceeded */
2305 NTStatus = 0xC000007FL; /* Disk full */
2308 else if (code == CM_ERROR_SPACE) {
2309 NTStatus = 0xC000007FL; /* Disk full */
2311 else if (code == CM_ERROR_ATSYS) {
2312 NTStatus = 0xC0000033L; /* Object name invalid */
2314 else if (code == CM_ERROR_BADNTFILENAME) {
2315 NTStatus = 0xC0000033L; /* Object name invalid */
2317 else if (code == CM_ERROR_WOULDBLOCK) {
2318 NTStatus = 0xC0000055L; /* Lock not granted */
2320 else if (code == CM_ERROR_PARTIALWRITE) {
2321 NTStatus = 0xC000007FL; /* Disk full */
2323 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2324 NTStatus = 0xC0000023L; /* Buffer too small */
2326 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2327 NTStatus = 0xC0000035L; /* Object name collision */
2329 else if (code == CM_ERROR_BADPASSWORD) {
2330 NTStatus = 0xC000006DL; /* unknown username or bad password */
2332 else if (code == CM_ERROR_BADLOGONTYPE) {
2333 NTStatus = 0xC000015BL; /* logon type not granted */
2335 else if (code == CM_ERROR_GSSCONTINUE) {
2336 NTStatus = 0xC0000016L; /* more processing required */
2338 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2340 NTStatus = 0xC0000280L; /* reparse point not resolved */
2342 NTStatus = 0xC0000022L; /* Access Denied */
2345 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2346 NTStatus = 0xC0000257L; /* Path Not Covered */
2348 else if (code == CM_ERROR_ALLBUSY) {
2349 NTStatus = 0xC00000BFL; /* Network Busy */
2351 NTStatus = 0xC0982001L; /* SMB non-specific error */
2354 *NTStatusp = NTStatus;
2355 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2358 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2359 unsigned char *classp)
2361 unsigned char class;
2362 unsigned short error;
2364 /* map CM_ERROR_* errors to SMB errors */
2365 if (code == CM_ERROR_NOSUCHCELL) {
2367 error = 3; /* bad path */
2369 else if (code == CM_ERROR_NOSUCHVOLUME) {
2371 error = 3; /* bad path */
2373 else if (code == CM_ERROR_TIMEDOUT) {
2375 error = 81; /* server is paused */
2377 else if (code == CM_ERROR_RETRY) {
2378 class = 2; /* shouldn't happen */
2381 else if (code == CM_ERROR_NOACCESS) {
2383 error = 4; /* bad access */
2385 else if (code == CM_ERROR_READONLY) {
2387 error = 19; /* read only */
2389 else if (code == CM_ERROR_NOSUCHFILE) {
2391 error = 2; /* ENOENT! */
2393 else if (code == CM_ERROR_NOSUCHPATH) {
2395 error = 3; /* Bad path */
2397 else if (code == CM_ERROR_TOOBIG) {
2399 error = 11; /* bad format */
2401 else if (code == CM_ERROR_INVAL) {
2402 class = 2; /* server non-specific error code */
2405 else if (code == CM_ERROR_BADFD) {
2407 error = 6; /* invalid file handle */
2409 else if (code == CM_ERROR_BADFDOP) {
2410 class = 1; /* invalid op on FD */
2413 else if (code == CM_ERROR_EXISTS) {
2415 error = 80; /* file already exists */
2417 else if (code == CM_ERROR_NOTEMPTY) {
2419 error = 5; /* delete directory not empty */
2421 else if (code == CM_ERROR_CROSSDEVLINK) {
2423 error = 17; /* EXDEV */
2425 else if (code == CM_ERROR_NOTDIR) {
2426 class = 1; /* bad path */
2429 else if (code == CM_ERROR_ISDIR) {
2430 class = 1; /* access denied; DOS doesn't have a good match */
2433 else if (code == CM_ERROR_BADOP) {
2437 else if (code == CM_ERROR_BADSHARENAME) {
2441 else if (code == CM_ERROR_NOIPC) {
2443 error = 4; /* bad access */
2445 else if (code == CM_ERROR_CLOCKSKEW) {
2446 class = 1; /* invalid function */
2449 else if (code == CM_ERROR_BADTID) {
2453 else if (code == CM_ERROR_USESTD) {
2457 else if (code == CM_ERROR_REMOTECONN) {
2461 else if (code == CM_ERROR_QUOTA) {
2462 if (vcp->flags & SMB_VCFLAG_USEV3) {
2464 error = 39; /* disk full */
2468 error = 5; /* access denied */
2471 else if (code == CM_ERROR_SPACE) {
2472 if (vcp->flags & SMB_VCFLAG_USEV3) {
2474 error = 39; /* disk full */
2478 error = 5; /* access denied */
2481 else if (code == CM_ERROR_PARTIALWRITE) {
2483 error = 39; /* disk full */
2485 else if (code == CM_ERROR_ATSYS) {
2487 error = 2; /* ENOENT */
2489 else if (code == CM_ERROR_WOULDBLOCK) {
2491 error = 33; /* lock conflict */
2493 else if (code == CM_ERROR_NOFILES) {
2495 error = 18; /* no files in search */
2497 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2499 error = 183; /* Samba uses this */
2501 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2502 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2504 error = 2; /* bad password */
2506 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2508 error = 3; /* bad path */
2517 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2520 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2522 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2523 return CM_ERROR_BADOP;
2526 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2528 unsigned short EchoCount, i;
2529 char *data, *outdata;
2532 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2534 for (i=1; i<=EchoCount; i++) {
2535 data = smb_GetSMBData(inp, &dataSize);
2536 smb_SetSMBParm(outp, 0, i);
2537 smb_SetSMBDataLength(outp, dataSize);
2538 outdata = smb_GetSMBData(outp, NULL);
2539 memcpy(outdata, data, dataSize);
2540 smb_SendPacket(vcp, outp);
2546 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2549 long count, minCount, finalCount;
2553 cm_user_t *userp = NULL;
2557 char *rawBuf = NULL;
2559 dos_ptr rawBuf = NULL;
2566 fd = smb_GetSMBParm(inp, 0);
2567 count = smb_GetSMBParm(inp, 3);
2568 minCount = smb_GetSMBParm(inp, 4);
2569 offset.HighPart = 0; /* too bad */
2570 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2572 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2573 fd, offset.LowPart, count);
2575 fidp = smb_FindFID(vcp, fd, 0);
2579 lock_ObtainMutex(&smb_RawBufLock);
2581 /* Get a raw buf, from head of list */
2582 rawBuf = smb_RawBufs;
2584 smb_RawBufs = *(char **)smb_RawBufs;
2586 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2589 lock_ReleaseMutex(&smb_RawBufLock);
2593 if (fidp->flags & SMB_FID_IOCTL)
2596 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2598 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2601 /* Give back raw buffer */
2602 lock_ObtainMutex(&smb_RawBufLock);
2604 *((char **) rawBuf) = smb_RawBufs;
2606 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2609 smb_RawBufs = rawBuf;
2610 lock_ReleaseMutex(&smb_RawBufLock);
2613 smb_ReleaseFID(fidp);
2617 userp = smb_GetUser(vcp, inp);
2620 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2622 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2623 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2624 userp, &finalCount, TRUE /* rawFlag */);
2631 cm_ReleaseUser(userp);
2634 smb_ReleaseFID(fidp);
2639 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2641 memset((char *)ncbp, 0, sizeof(NCB));
2643 ncbp->ncb_length = (unsigned short) finalCount;
2644 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2645 ncbp->ncb_lana_num = vcp->lana;
2646 ncbp->ncb_command = NCBSEND;
2647 ncbp->ncb_buffer = rawBuf;
2650 code = Netbios(ncbp);
2652 code = Netbios(ncbp, dos_ncb);
2655 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2658 /* Give back raw buffer */
2659 lock_ObtainMutex(&smb_RawBufLock);
2661 *((char **) rawBuf) = smb_RawBufs;
2663 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2666 smb_RawBufs = rawBuf;
2667 lock_ReleaseMutex(&smb_RawBufLock);
2673 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2675 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2680 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2682 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2687 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2694 int protoIndex; /* index we're using */
2699 char protocol_array[10][1024]; /* protocol signature of the client */
2700 int caps; /* capabilities */
2703 TIME_ZONE_INFORMATION tzi;
2705 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2709 DWORD now = GetCurrentTime();
2710 if (now - last_msg_time >= 30000
2711 && now - last_msg_time <= 90000) {
2713 "Setting dead_vcp %x", active_vcp);
2715 smb_ReleaseVC(dead_vcp);
2717 "Previous dead_vcp %x", dead_vcp);
2719 smb_HoldVC(active_vcp);
2720 dead_vcp = active_vcp;
2721 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2726 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2728 namep = smb_GetSMBData(inp, &dbytes);
2731 coreProtoIndex = -1; /* not found */
2734 while(namex < dbytes) {
2735 osi_Log1(smb_logp, "Protocol %s",
2736 osi_LogSaveString(smb_logp, namep+1));
2737 strcpy(protocol_array[tcounter], namep+1);
2739 /* namep points at the first protocol, or really, a 0x02
2740 * byte preceding the null-terminated ASCII name.
2742 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2743 coreProtoIndex = tcounter;
2745 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2746 v3ProtoIndex = tcounter;
2748 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2749 NTProtoIndex = tcounter;
2752 /* compute size of protocol entry */
2753 entryLength = strlen(namep+1);
2754 entryLength += 2; /* 0x02 bytes and null termination */
2756 /* advance over this protocol entry */
2757 namex += entryLength;
2758 namep += entryLength;
2759 tcounter++; /* which proto entry we're looking at */
2762 if (NTProtoIndex != -1) {
2763 protoIndex = NTProtoIndex;
2764 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2766 else if (v3ProtoIndex != -1) {
2767 protoIndex = v3ProtoIndex;
2768 vcp->flags |= SMB_VCFLAG_USEV3;
2770 else if (coreProtoIndex != -1) {
2771 protoIndex = coreProtoIndex;
2772 vcp->flags |= SMB_VCFLAG_USECORE;
2774 else protoIndex = -1;
2776 if (protoIndex == -1)
2777 return CM_ERROR_INVAL;
2778 else if (NTProtoIndex != -1) {
2779 smb_SetSMBParm(outp, 0, protoIndex);
2780 if (smb_authType != SMB_AUTH_NONE) {
2781 smb_SetSMBParmByte(outp, 1,
2782 NEGOTIATE_SECURITY_USER_LEVEL |
2783 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2785 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2787 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2788 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2789 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2790 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2791 /* The session key is not a well documented field however most clients
2792 * will echo back the session key to the server. Currently we are using
2793 * the same value for all sessions. We should generate a random value
2794 * and store it into the vcp
2796 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2797 smb_SetSMBParm(outp, 8, 1);
2799 * Tried changing the capabilities to support for W2K - defect 117695
2800 * Maybe something else needs to be changed here?
2804 smb_SetSMBParmLong(outp, 9, 0x43fd);
2806 smb_SetSMBParmLong(outp, 9, 0x251);
2809 * 32-bit error codes *
2814 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2816 NTNEGOTIATE_CAPABILITY_DFS |
2818 NTNEGOTIATE_CAPABILITY_NTFIND |
2819 NTNEGOTIATE_CAPABILITY_RAWMODE |
2820 NTNEGOTIATE_CAPABILITY_NTSMB;
2822 if ( smb_authType == SMB_AUTH_EXTENDED )
2823 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2825 smb_SetSMBParmLong(outp, 9, caps);
2827 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2828 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2829 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2831 GetTimeZoneInformation(&tzi);
2832 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2834 if (smb_authType == SMB_AUTH_NTLM) {
2835 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2836 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2837 /* paste in encryption key */
2838 datap = smb_GetSMBData(outp, NULL);
2839 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2840 /* and the faux domain name */
2841 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2842 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2846 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2848 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2850 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2852 datap = smb_GetSMBData(outp, NULL);
2853 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2856 datap += sizeof(smb_ServerGUID);
2857 memcpy(datap, secBlob, secBlobLength);
2861 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2862 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2865 else if (v3ProtoIndex != -1) {
2866 smb_SetSMBParm(outp, 0, protoIndex);
2868 /* NOTE: Extended authentication cannot be negotiated with v3
2869 * therefore we fail over to NTLM
2871 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2872 smb_SetSMBParm(outp, 1,
2873 NEGOTIATE_SECURITY_USER_LEVEL |
2874 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2876 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2878 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2879 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2880 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2881 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2882 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2883 smb_SetSMBParm(outp, 7, 1);
2885 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2886 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2887 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2889 GetTimeZoneInformation(&tzi);
2890 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2892 /* NOTE: Extended authentication cannot be negotiated with v3
2893 * therefore we fail over to NTLM
2895 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2896 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2897 smb_SetSMBParm(outp, 12, 0); /* resvd */
2898 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2899 datap = smb_GetSMBData(outp, NULL);
2900 /* paste in a new encryption key */
2901 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2902 /* and the faux domain name */
2903 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2905 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2906 smb_SetSMBParm(outp, 12, 0); /* resvd */
2907 smb_SetSMBDataLength(outp, 0);
2910 else if (coreProtoIndex != -1) { /* not really supported anymore */
2911 smb_SetSMBParm(outp, 0, protoIndex);
2912 smb_SetSMBDataLength(outp, 0);
2917 void smb_Daemon(void *parmp)
2919 afs_uint32 count = 0;
2921 while(smbShutdownFlag == 0) {
2925 if (smbShutdownFlag == 1)
2928 if ((count % 72) == 0) { /* every five minutes */
2930 time_t old_localZero = smb_localZero;
2932 /* Initialize smb_localZero */
2933 myTime.tm_isdst = -1; /* compute whether on DST or not */
2934 myTime.tm_year = 70;
2940 smb_localZero = mktime(&myTime);
2942 smb_CalculateNowTZ();
2944 #ifdef AFS_FREELANCE
2945 if ( smb_localZero != old_localZero )
2946 cm_noteLocalMountPointChange();
2949 /* XXX GC dir search entries */
2953 void smb_WaitingLocksDaemon()
2955 smb_waitingLock_t *wL, *nwL;
2958 smb_packet_t *inp, *outp;
2962 while (smbShutdownFlag == 0) {
2963 lock_ObtainWrite(&smb_globalLock);
2964 nwL = smb_allWaitingLocks;
2966 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2976 lock_ObtainWrite(&smb_globalLock);
2978 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2979 lock_ReleaseWrite(&smb_globalLock);
2980 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2981 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2982 if (code == CM_ERROR_WOULDBLOCK) {
2984 if (wL->timeRemaining != 0xffffffff
2985 && (wL->timeRemaining -= 1000) < 0)
2995 ncbp->ncb_length = inp->ncb_length;
2996 inp->spacep = cm_GetSpace();
2998 /* Remove waitingLock from list */
2999 lock_ObtainWrite(&smb_globalLock);
3000 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3002 lock_ReleaseWrite(&smb_globalLock);
3004 /* Resume packet processing */
3006 smb_SetSMBDataLength(outp, 0);
3007 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3008 outp->resumeCode = code;
3010 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3013 cm_FreeSpace(inp->spacep);
3014 smb_FreePacket(inp);
3015 smb_FreePacket(outp);
3019 } while (nwL && smbShutdownFlag == 0);
3024 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3026 osi_Log0(smb_logp, "SMB receive get disk attributes");
3028 smb_SetSMBParm(outp, 0, 32000);
3029 smb_SetSMBParm(outp, 1, 64);
3030 smb_SetSMBParm(outp, 2, 1024);
3031 smb_SetSMBParm(outp, 3, 30000);
3032 smb_SetSMBParm(outp, 4, 0);
3033 smb_SetSMBDataLength(outp, 0);
3037 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3041 unsigned short newTid;
3042 char shareName[256];
3050 osi_Log0(smb_logp, "SMB receive tree connect");
3052 /* parse input parameters */
3053 tp = smb_GetSMBData(inp, NULL);
3054 pathp = smb_ParseASCIIBlock(tp, &tp);
3055 if (smb_StoreAnsiFilenames)
3056 OemToChar(pathp,pathp);
3057 passwordp = smb_ParseASCIIBlock(tp, &tp);
3058 tp = strrchr(pathp, '\\');
3060 return CM_ERROR_BADSMB;
3061 strcpy(shareName, tp+1);
3063 userp = smb_GetUser(vcp, inp);
3065 lock_ObtainMutex(&vcp->mx);
3066 newTid = vcp->tidCounter++;
3067 lock_ReleaseMutex(&vcp->mx);
3069 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3070 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3071 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3073 smb_ReleaseUID(uidp);
3075 smb_ReleaseTID(tidp);
3076 return CM_ERROR_BADSHARENAME;
3078 lock_ObtainMutex(&tidp->mx);
3079 tidp->userp = userp;
3080 tidp->pathname = sharePath;
3081 lock_ReleaseMutex(&tidp->mx);
3082 smb_ReleaseTID(tidp);
3084 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3085 smb_SetSMBParm(rsp, 1, newTid);
3086 smb_SetSMBDataLength(rsp, 0);
3088 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3092 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3096 if (*inp++ != 0x1) return NULL;
3097 tlen = inp[0] + (inp[1]<<8);
3098 inp += 2; /* skip length field */
3101 *chainpp = inp + tlen;
3104 if (lengthp) *lengthp = tlen;
3109 /* set maskp to the mask part of the incoming path.
3110 * Mask is 11 bytes long (8.3 with the dot elided).
3111 * Returns true if succeeds with a valid name, otherwise it does
3112 * its best, but returns false.
3114 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3122 /* starts off valid */
3125 /* mask starts out all blanks */
3126 memset(maskp, ' ', 11);
3128 /* find last backslash, or use whole thing if there is none */
3129 tp = strrchr(pathp, '\\');
3130 if (!tp) tp = pathp;
3131 else tp++; /* skip slash */
3135 /* names starting with a dot are illegal */
3136 if (*tp == '.') valid8Dot3 = 0;
3140 if (tc == 0) return valid8Dot3;
3141 if (tc == '.' || tc == '"') break;
3142 if (i < 8) *up++ = tc;
3143 else valid8Dot3 = 0;
3146 /* if we get here, tp point after the dot */
3147 up = maskp+8; /* ext goes here */
3154 if (tc == '.' || tc == '"')
3157 /* copy extension if not too long */
3167 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3177 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3179 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3183 /* otherwise, we have a valid 8.3 name; see if we have a match,
3184 * treating '?' as a wildcard in maskp (but not in the file name).
3186 tp1 = umask; /* real name, in mask format */
3187 tp2 = maskp; /* mask, in mask format */
3188 for(i=0; i<11; i++) {
3189 tc1 = *tp1++; /* char from real name */
3190 tc2 = *tp2++; /* char from mask */
3191 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3192 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3195 if (tc2 == '?' && tc1 != ' ')
3202 /* we got a match */
3206 char *smb_FindMask(char *pathp)
3210 tp = strrchr(pathp, '\\'); /* find last slash */
3213 return tp+1; /* skip the slash */
3215 return pathp; /* no slash, return the entire path */
3218 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3220 unsigned char *pathp;
3222 unsigned char mask[11];
3223 unsigned char *statBlockp;
3224 unsigned char initStatBlock[21];
3227 osi_Log0(smb_logp, "SMB receive search volume");
3229 /* pull pathname and stat block out of request */
3230 tp = smb_GetSMBData(inp, NULL);
3231 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3232 osi_assert(pathp != NULL);
3233 if (smb_StoreAnsiFilenames)
3234 OemToChar(pathp,pathp);
3235 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3236 osi_assert(statBlockp != NULL);
3238 statBlockp = initStatBlock;
3242 /* for returning to caller */
3243 smb_Get8Dot3MaskFromPath(mask, pathp);
3245 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3246 tp = smb_GetSMBData(outp, NULL);
3248 *tp++ = 43; /* bytes in a dir entry */
3249 *tp++ = 0; /* high byte in counter */
3251 /* now marshall the dir entry, starting with the search status */
3252 *tp++ = statBlockp[0]; /* Reserved */
3253 memcpy(tp, mask, 11); tp += 11; /* FileName */
3255 /* now pass back server use info, with 1st byte non-zero */
3257 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3259 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3261 *tp++ = 0x8; /* attribute: volume */
3271 /* 4 byte file size */
3277 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3278 memset(tp, ' ', 13);
3281 /* set the length of the data part of the packet to 43 + 3, for the dir
3282 * entry plus the 5 and the length fields.
3284 smb_SetSMBDataLength(outp, 46);
3288 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3289 cm_user_t *userp, cm_req_t *reqp)
3297 smb_dirListPatch_t *patchp;
3298 smb_dirListPatch_t *npatchp;
3300 for (patchp = *dirPatchespp; patchp; patchp =
3301 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3303 dptr = patchp->dptr;
3305 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3307 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3308 *dptr++ = SMB_ATTR_HIDDEN;
3311 lock_ObtainMutex(&scp->mx);
3312 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3313 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3315 lock_ReleaseMutex(&scp->mx);
3316 cm_ReleaseSCache(scp);
3317 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3318 *dptr++ = SMB_ATTR_HIDDEN;
3322 attr = smb_Attributes(scp);
3323 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3324 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3325 attr |= SMB_ATTR_HIDDEN;
3329 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3332 shortTemp = (unsigned short) (dosTime & 0xffff);
3333 *((u_short *)dptr) = shortTemp;
3336 /* and copy out date */
3337 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3338 *((u_short *)dptr) = shortTemp;
3341 /* copy out file length */
3342 *((u_long *)dptr) = scp->length.LowPart;
3344 lock_ReleaseMutex(&scp->mx);
3345 cm_ReleaseSCache(scp);
3348 /* now free the patches */
3349 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3350 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3354 /* and mark the list as empty */
3355 *dirPatchespp = NULL;
3360 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3369 smb_dirListPatch_t *dirListPatchesp;
3370 smb_dirListPatch_t *curPatchp;
3374 osi_hyper_t dirLength;
3375 osi_hyper_t bufferOffset;
3376 osi_hyper_t curOffset;
3378 unsigned char *inCookiep;
3379 smb_dirSearch_t *dsp;
3383 unsigned long clientCookie;
3384 cm_pageHeader_t *pageHeaderp;
3385 cm_user_t *userp = NULL;
3392 long nextEntryCookie;
3393 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3394 char resByte; /* reserved byte from the cookie */
3395 char *op; /* output data ptr */
3396 char *origOp; /* original value of op */
3397 cm_space_t *spacep; /* for pathname buffer */
3408 maxCount = smb_GetSMBParm(inp, 0);
3410 dirListPatchesp = NULL;
3412 caseFold = CM_FLAG_CASEFOLD;
3414 tp = smb_GetSMBData(inp, NULL);
3415 pathp = smb_ParseASCIIBlock(tp, &tp);
3416 if (smb_StoreAnsiFilenames)
3417 OemToChar(pathp,pathp);
3418 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3420 /* bail out if request looks bad */
3421 if (!tp || !pathp) {
3422 return CM_ERROR_BADSMB;
3425 /* We can handle long names */
3426 if (vcp->flags & SMB_VCFLAG_USENT)
3427 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3429 /* make sure we got a whole search status */
3430 if (dataLength < 21) {
3431 nextCookie = 0; /* start at the beginning of the dir */
3434 attribute = smb_GetSMBParm(inp, 1);
3436 /* handle volume info in another function */
3437 if (attribute & 0x8)
3438 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3440 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3441 maxCount, osi_LogSaveString(smb_logp, pathp));
3443 if (*pathp == 0) { /* null pathp, treat as root dir */
3444 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3445 return CM_ERROR_NOFILES;
3449 dsp = smb_NewDirSearch(0);
3450 dsp->attribute = attribute;
3451 smb_Get8Dot3MaskFromPath(mask, pathp);
3452 memcpy(dsp->mask, mask, 11);
3454 /* track if this is likely to match a lot of entries */
3455 if (smb_IsStarMask(mask))
3460 /* pull the next cookie value out of the search status block */
3461 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3462 + (inCookiep[16]<<24);
3463 dsp = smb_FindDirSearch(inCookiep[12]);
3465 /* can't find dir search status; fatal error */
3466 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3467 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3468 return CM_ERROR_BADFD;
3470 attribute = dsp->attribute;
3471 resByte = inCookiep[0];
3473 /* copy out client cookie, in host byte order. Don't bother
3474 * interpreting it, since we're just passing it through, anyway.
3476 memcpy(&clientCookie, &inCookiep[17], 4);
3478 memcpy(mask, dsp->mask, 11);
3480 /* assume we're doing a star match if it has continued for more
3486 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3487 nextCookie, dsp->cookie, attribute);
3489 userp = smb_GetUser(vcp, inp);
3491 /* try to get the vnode for the path name next */
3492 lock_ObtainMutex(&dsp->mx);
3498 spacep = inp->spacep;
3499 smb_StripLastComponent(spacep->data, NULL, pathp);
3500 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3502 lock_ReleaseMutex(&dsp->mx);
3503 cm_ReleaseUser(userp);
3504 smb_DeleteDirSearch(dsp);
3505 smb_ReleaseDirSearch(dsp);
3506 return CM_ERROR_NOFILES;
3508 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3509 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3512 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3513 cm_ReleaseSCache(scp);
3514 lock_ReleaseMutex(&dsp->mx);
3515 cm_ReleaseUser(userp);
3516 smb_DeleteDirSearch(dsp);
3517 smb_ReleaseDirSearch(dsp);
3518 if ( WANTS_DFS_PATHNAMES(inp) )
3519 return CM_ERROR_PATH_NOT_COVERED;
3521 return CM_ERROR_BADSHARENAME;
3523 #endif /* DFS_SUPPORT */
3526 /* we need one hold for the entry we just stored into,
3527 * and one for our own processing. When we're done with this
3528 * function, we'll drop the one for our own processing.
3529 * We held it once from the namei call, and so we do another hold
3533 lock_ObtainMutex(&scp->mx);
3534 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3535 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3536 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3537 dsp->flags |= SMB_DIRSEARCH_BULKST;
3539 lock_ReleaseMutex(&scp->mx);
3542 lock_ReleaseMutex(&dsp->mx);
3544 cm_ReleaseUser(userp);
3545 smb_DeleteDirSearch(dsp);
3546 smb_ReleaseDirSearch(dsp);
3550 /* reserves space for parameter; we'll adjust it again later to the
3551 * real count of the # of entries we returned once we've actually
3552 * assembled the directory listing.
3554 smb_SetSMBParm(outp, 0, 0);
3556 /* get the directory size */
3557 lock_ObtainMutex(&scp->mx);
3558 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3559 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3561 lock_ReleaseMutex(&scp->mx);
3562 cm_ReleaseSCache(scp);
3563 cm_ReleaseUser(userp);
3564 smb_DeleteDirSearch(dsp);
3565 smb_ReleaseDirSearch(dsp);
3569 dirLength = scp->length;
3571 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3572 curOffset.HighPart = 0;
3573 curOffset.LowPart = nextCookie;
3574 origOp = op = smb_GetSMBData(outp, NULL);
3575 /* and write out the basic header */
3576 *op++ = 5; /* variable block */
3577 op += 2; /* skip vbl block length; we'll fill it in later */
3581 /* make sure that curOffset.LowPart doesn't point to the first
3582 * 32 bytes in the 2nd through last dir page, and that it doesn't
3583 * point at the first 13 32-byte chunks in the first dir page,
3584 * since those are dir and page headers, and don't contain useful
3587 temp = curOffset.LowPart & (2048-1);
3588 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3589 /* we're in the first page */
3590 if (temp < 13*32) temp = 13*32;
3593 /* we're in a later dir page */
3594 if (temp < 32) temp = 32;
3597 /* make sure the low order 5 bits are zero */
3600 /* now put temp bits back ito curOffset.LowPart */
3601 curOffset.LowPart &= ~(2048-1);
3602 curOffset.LowPart |= temp;
3604 /* check if we've returned all the names that will fit in the
3607 if (returnedNames >= maxCount) {
3608 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3609 returnedNames, maxCount);
3613 /* check if we've passed the dir's EOF */
3614 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3616 /* see if we can use the bufferp we have now; compute in which page
3617 * the current offset would be, and check whether that's the offset
3618 * of the buffer we have. If not, get the buffer.
3620 thyper.HighPart = curOffset.HighPart;
3621 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3622 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3625 buf_Release(bufferp);
3628 lock_ReleaseMutex(&scp->mx);
3629 lock_ObtainRead(&scp->bufCreateLock);
3630 code = buf_Get(scp, &thyper, &bufferp);
3631 lock_ReleaseRead(&scp->bufCreateLock);
3632 lock_ObtainMutex(&dsp->mx);
3634 /* now, if we're doing a star match, do bulk fetching of all of
3635 * the status info for files in the dir.
3638 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3639 lock_ObtainMutex(&scp->mx);
3640 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3641 LargeIntegerGreaterThanOrEqualTo(thyper,
3642 scp->bulkStatProgress)) {
3643 /* Don't bulk stat if risking timeout */
3644 int now = GetCurrentTime();
3645 if (now - req.startTime > 5000) {
3646 scp->bulkStatProgress = thyper;
3647 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3648 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3650 cm_TryBulkStat(scp, &thyper, userp, &req);
3653 lock_ObtainMutex(&scp->mx);
3655 lock_ReleaseMutex(&dsp->mx);
3657 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3661 bufferOffset = thyper;
3663 /* now get the data in the cache */
3665 code = cm_SyncOp(scp, bufferp, userp, &req,
3667 CM_SCACHESYNC_NEEDCALLBACK |
3668 CM_SCACHESYNC_READ);
3670 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3674 if (cm_HaveBuffer(scp, bufferp, 0)) {
3675 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3679 /* otherwise, load the buffer and try again */
3680 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3682 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3683 scp, bufferp, code);
3688 buf_Release(bufferp);
3692 } /* if (wrong buffer) ... */
3694 /* now we have the buffer containing the entry we're interested in; copy
3695 * it out if it represents a non-deleted entry.
3697 entryInDir = curOffset.LowPart & (2048-1);
3698 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3700 /* page header will help tell us which entries are free. Page header
3701 * can change more often than once per buffer, since AFS 3 dir page size
3702 * may be less than (but not more than a buffer package buffer.
3704 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3705 temp &= ~(2048 - 1); /* turn off intra-page bits */
3706 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3708 /* now determine which entry we're looking at in the page. If it is
3709 * free (there's a free bitmap at the start of the dir), we should
3710 * skip these 32 bytes.
3712 slotInPage = (entryInDir & 0x7e0) >> 5;
3713 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3714 /* this entry is free */
3715 numDirChunks = 1; /* only skip this guy */
3719 tp = bufferp->datap + entryInBuffer;
3720 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3722 /* while we're here, compute the next entry's location, too,
3723 * since we'll need it when writing out the cookie into the dir
3726 * XXXX Probably should do more sanity checking.
3728 numDirChunks = cm_NameEntries(dep->name, NULL);
3730 /* compute the offset of the cookie representing the next entry */
3731 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3733 /* Compute 8.3 name if necessary */
3734 actualName = dep->name;
3735 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3736 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3737 actualName = shortName;
3740 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3741 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3742 osi_LogSaveString(smb_logp, actualName));
3744 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3745 /* this is one of the entries to use: it is not deleted
3746 * and it matches the star pattern we're looking for.
3749 /* Eliminate entries that don't match requested
3752 /* no hidden files */
3753 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3754 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3758 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3760 /* We have already done the cm_TryBulkStat above */
3761 fid.cell = scp->fid.cell;
3762 fid.volume = scp->fid.volume;
3763 fid.vnode = ntohl(dep->fid.vnode);
3764 fid.unique = ntohl(dep->fid.unique);
3765 fileType = cm_FindFileType(&fid);
3766 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3767 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3769 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3770 fileType == CM_SCACHETYPE_DFSLINK ||
3771 fileType == CM_SCACHETYPE_INVALID)
3772 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3777 memcpy(op, mask, 11); op += 11;
3778 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3779 *op++ = nextEntryCookie & 0xff;
3780 *op++ = (nextEntryCookie>>8) & 0xff;
3781 *op++ = (nextEntryCookie>>16) & 0xff;
3782 *op++ = (nextEntryCookie>>24) & 0xff;
3783 memcpy(op, &clientCookie, 4); op += 4;
3785 /* now we emit the attribute. This is sort of tricky,
3786 * since we need to really stat the file to find out
3787 * what type of entry we've got. Right now, we're
3788 * copying out data from a buffer, while holding the
3789 * scp locked, so it isn't really convenient to stat
3790 * something now. We'll put in a place holder now,
3791 * and make a second pass before returning this to get
3792 * the real attributes. So, we just skip the data for
3793 * now, and adjust it later. We allocate a patch
3794 * record to make it easy to find this point later.
3795 * The replay will happen at a time when it is safe to
3796 * unlock the directory.
3798 curPatchp = malloc(sizeof(*curPatchp));
3799 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3800 curPatchp->dptr = op;
3801 curPatchp->fid.cell = scp->fid.cell;
3802 curPatchp->fid.volume = scp->fid.volume;
3803 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3804 curPatchp->fid.unique = ntohl(dep->fid.unique);
3806 /* do hidden attribute here since name won't be around when applying
3810 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3811 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3813 curPatchp->flags = 0;
3815 op += 9; /* skip attr, time, date and size */
3817 /* zero out name area. The spec says to pad with
3818 * spaces, but Samba doesn't, and neither do we.
3822 /* finally, we get to copy out the name; we know that
3823 * it fits in 8.3 or the pattern wouldn't match, but it
3824 * never hurts to be sure.
3826 strncpy(op, actualName, 13);
3827 if (smb_StoreAnsiFilenames)
3830 /* Uppercase if requested by client */
3831 if (!KNOWS_LONG_NAMES(inp))
3836 /* now, adjust the # of entries copied */
3838 } /* if we're including this name */
3841 /* and adjust curOffset to be where the new cookie is */
3842 thyper.HighPart = 0;
3843 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3844 curOffset = LargeIntegerAdd(thyper, curOffset);
3845 } /* while copying data for dir listing */
3847 /* release the mutex */
3848 lock_ReleaseMutex(&scp->mx);
3849 if (bufferp) buf_Release(bufferp);
3851 /* apply and free last set of patches; if not doing a star match, this
3852 * will be empty, but better safe (and freeing everything) than sorry.
3854 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3856 /* special return code for unsuccessful search */
3857 if (code == 0 && dataLength < 21 && returnedNames == 0)
3858 code = CM_ERROR_NOFILES;
3860 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3861 returnedNames, code);
3864 smb_DeleteDirSearch(dsp);
3865 smb_ReleaseDirSearch(dsp);
3866 cm_ReleaseSCache(scp);
3867 cm_ReleaseUser(userp);
3871 /* finalize the output buffer */
3872 smb_SetSMBParm(outp, 0, returnedNames);
3873 temp = (long) (op - origOp);
3874 smb_SetSMBDataLength(outp, temp);
3876 /* the data area is a variable block, which has a 5 (already there)
3877 * followed by the length of the # of data bytes. We now know this to
3878 * be "temp," although that includes the 3 bytes of vbl block header.
3879 * Deduct for them and fill in the length field.
3881 temp -= 3; /* deduct vbl block info */
3882 osi_assert(temp == (43 * returnedNames));
3883 origOp[1] = temp & 0xff;
3884 origOp[2] = (temp>>8) & 0xff;
3885 if (returnedNames == 0)
3886 smb_DeleteDirSearch(dsp);
3887 smb_ReleaseDirSearch(dsp);
3888 cm_ReleaseSCache(scp);
3889 cm_ReleaseUser(userp);
3893 /* verify that this is a valid path to a directory. I don't know why they
3894 * don't use the get file attributes call.
3896 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3900 cm_scache_t *rootScp;
3901 cm_scache_t *newScp;
3910 pathp = smb_GetSMBData(inp, NULL);
3911 pathp = smb_ParseASCIIBlock(pathp, NULL);
3913 return CM_ERROR_BADFD;
3914 if (smb_StoreAnsiFilenames)
3915 OemToChar(pathp,pathp);
3916 osi_Log1(smb_logp, "SMB receive check path %s",
3917 osi_LogSaveString(smb_logp, pathp));
3919 rootScp = cm_data.rootSCachep;
3921 userp = smb_GetUser(vcp, inp);
3923 caseFold = CM_FLAG_CASEFOLD;
3925 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3927 cm_ReleaseUser(userp);
3928 return CM_ERROR_NOSUCHPATH;
3930 code = cm_NameI(rootScp, pathp,
3931 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3932 userp, tidPathp, &req, &newScp);
3935 cm_ReleaseUser(userp);
3940 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
3941 cm_ReleaseSCache(newScp);
3942 cm_ReleaseUser(userp);
3943 if ( WANTS_DFS_PATHNAMES(inp) )
3944 return CM_ERROR_PATH_NOT_COVERED;
3946 return CM_ERROR_BADSHARENAME;
3948 #endif /* DFS_SUPPORT */
3950 /* now lock the vnode with a callback; returns with newScp locked */
3951 lock_ObtainMutex(&newScp->mx);
3952 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3953 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3954 if (code && code != CM_ERROR_NOACCESS) {
3955 lock_ReleaseMutex(&newScp->mx);
3956 cm_ReleaseSCache(newScp);
3957 cm_ReleaseUser(userp);
3961 attrs = smb_Attributes(newScp);
3963 if (!(attrs & SMB_ATTR_DIRECTORY))
3964 code = CM_ERROR_NOTDIR;
3966 lock_ReleaseMutex(&newScp->mx);
3968 cm_ReleaseSCache(newScp);
3969 cm_ReleaseUser(userp);
3973 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3977 cm_scache_t *rootScp;
3978 unsigned short attribute;
3980 cm_scache_t *newScp;
3989 /* decode basic attributes we're passed */
3990 attribute = smb_GetSMBParm(inp, 0);
3991 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3993 pathp = smb_GetSMBData(inp, NULL);
3994 pathp = smb_ParseASCIIBlock(pathp, NULL);
3996 return CM_ERROR_BADSMB;
3997 if (smb_StoreAnsiFilenames)
3998 OemToChar(pathp,pathp);
4000 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4001 dosTime, attribute);
4003 rootScp = cm_data.rootSCachep;
4005 userp = smb_GetUser(vcp, inp);
4007 caseFold = CM_FLAG_CASEFOLD;
4009 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4011 cm_ReleaseUser(userp);
4012 return CM_ERROR_NOSUCHFILE;
4014 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4015 tidPathp, &req, &newScp);
4018 cm_ReleaseUser(userp);
4023 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4024 cm_ReleaseSCache(newScp);
4025 cm_ReleaseUser(userp);
4026 if ( WANTS_DFS_PATHNAMES(inp) )
4027 return CM_ERROR_PATH_NOT_COVERED;
4029 return CM_ERROR_BADSHARENAME;
4031 #endif /* DFS_SUPPORT */
4033 /* now lock the vnode with a callback; returns with newScp locked; we
4034 * need the current status to determine what the new status is, in some
4037 lock_ObtainMutex(&newScp->mx);
4038 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4039 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4041 lock_ReleaseMutex(&newScp->mx);
4042 cm_ReleaseSCache(newScp);
4043 cm_ReleaseUser(userp);
4047 /* Check for RO volume */
4048 if (newScp->flags & CM_SCACHEFLAG_RO) {
4049 lock_ReleaseMutex(&newScp->mx);
4050 cm_ReleaseSCache(newScp);
4051 cm_ReleaseUser(userp);
4052 return CM_ERROR_READONLY;
4055 /* prepare for setattr call */
4058 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4059 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4061 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4062 /* we're told to make a writable file read-only */
4063 attr.unixModeBits = newScp->unixModeBits & ~0222;
4064 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4066 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4067 /* we're told to make a read-only file writable */
4068 attr.unixModeBits = newScp->unixModeBits | 0222;
4069 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4071 lock_ReleaseMutex(&newScp->mx);
4073 /* now call setattr */
4075 code = cm_SetAttr(newScp, &attr, userp, &req);
4079 cm_ReleaseSCache(newScp);
4080 cm_ReleaseUser(userp);
4085 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4089 cm_scache_t *rootScp;
4090 cm_scache_t *newScp, *dscp;
4102 pathp = smb_GetSMBData(inp, NULL);
4103 pathp = smb_ParseASCIIBlock(pathp, NULL);
4105 return CM_ERROR_BADSMB;
4107 if (*pathp == 0) /* null path */
4110 if (smb_StoreAnsiFilenames)
4111 OemToChar(pathp,pathp);
4113 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4114 osi_LogSaveString(smb_logp, pathp));
4116 rootScp = cm_data.rootSCachep;
4118 userp = smb_GetUser(vcp, inp);
4120 /* we shouldn't need this for V3 requests, but we seem to */
4121 caseFold = CM_FLAG_CASEFOLD;
4123 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4125 cm_ReleaseUser(userp);
4126 return CM_ERROR_NOSUCHFILE;
4130 * XXX Strange hack XXX
4132 * As of Patch 5 (16 July 97), we are having the following problem:
4133 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4134 * requests to look up "desktop.ini" in all the subdirectories.
4135 * This can cause zillions of timeouts looking up non-existent cells
4136 * and volumes, especially in the top-level directory.
4138 * We have not found any way to avoid this or work around it except
4139 * to explicitly ignore the requests for mount points that haven't
4140 * yet been evaluated and for directories that haven't yet been
4143 * We should modify this hack to provide a fake desktop.ini file
4144 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4146 spacep = inp->spacep;
4147 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4148 #ifndef SPECIAL_FOLDERS
4149 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4150 code = cm_NameI(rootScp, spacep->data,
4151 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4152 userp, tidPathp, &req, &dscp);
4155 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4156 if ( WANTS_DFS_PATHNAMES(inp) )
4157 return CM_ERROR_PATH_NOT_COVERED;
4159 return CM_ERROR_BADSHARENAME;
4161 #endif /* DFS_SUPPORT */
4162 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4163 code = CM_ERROR_NOSUCHFILE;
4164 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4165 cm_buf_t *bp = buf_Find(dscp, &hzero);
4169 code = CM_ERROR_NOSUCHFILE;
4171 cm_ReleaseSCache(dscp);
4173 cm_ReleaseUser(userp);
4178 #endif /* SPECIAL_FOLDERS */
4180 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4181 tidPathp, &req, &newScp);
4183 cm_ReleaseUser(userp);
4188 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4189 cm_ReleaseSCache(newScp);
4190 cm_ReleaseUser(userp);
4191 if ( WANTS_DFS_PATHNAMES(inp) )
4192 return CM_ERROR_PATH_NOT_COVERED;
4194 return CM_ERROR_BADSHARENAME;
4196 #endif /* DFS_SUPPORT */
4198 /* now lock the vnode with a callback; returns with newScp locked */
4199 lock_ObtainMutex(&newScp->mx);
4200 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4201 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4203 lock_ReleaseMutex(&newScp->mx);
4204 cm_ReleaseSCache(newScp);
4205 cm_ReleaseUser(userp);
4210 /* use smb_Attributes instead. Also the fact that a file is
4211 * in a readonly volume doesn't mean it shojuld be marked as RO
4213 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4214 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4215 attrs = SMB_ATTR_DIRECTORY;
4218 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4219 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4221 attrs = smb_Attributes(newScp);
4224 smb_SetSMBParm(outp, 0, attrs);
4226 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4227 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4228 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4229 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4230 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4231 smb_SetSMBParm(outp, 5, 0);
4232 smb_SetSMBParm(outp, 6, 0);
4233 smb_SetSMBParm(outp, 7, 0);
4234 smb_SetSMBParm(outp, 8, 0);
4235 smb_SetSMBParm(outp, 9, 0);
4236 smb_SetSMBDataLength(outp, 0);
4237 lock_ReleaseMutex(&newScp->mx);
4239 cm_ReleaseSCache(newScp);
4240 cm_ReleaseUser(userp);
4245 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4249 osi_Log0(smb_logp, "SMB receive tree disconnect");
4251 /* find the tree and free it */
4252 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4254 lock_ObtainMutex(&tidp->mx);
4255 tidp->flags |= SMB_TIDFLAG_DELETE;
4256 lock_ReleaseMutex(&tidp->mx);
4257 smb_ReleaseTID(tidp);
4263 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4281 pathp = smb_GetSMBData(inp, NULL);
4282 pathp = smb_ParseASCIIBlock(pathp, NULL);
4283 if (smb_StoreAnsiFilenames)
4284 OemToChar(pathp,pathp);
4286 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4288 #ifdef DEBUG_VERBOSE
4292 hexpath = osi_HexifyString( pathp );
4293 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4298 share = smb_GetSMBParm(inp, 0);
4299 attribute = smb_GetSMBParm(inp, 1);
4301 spacep = inp->spacep;
4302 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4303 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4304 /* special case magic file name for receiving IOCTL requests
4305 * (since IOCTL calls themselves aren't getting through).
4307 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4308 smb_SetupIoctlFid(fidp, spacep);
4309 smb_SetSMBParm(outp, 0, fidp->fid);
4310 smb_SetSMBParm(outp, 1, 0); /* attrs */
4311 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4312 smb_SetSMBParm(outp, 3, 0);
4313 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4314 smb_SetSMBParm(outp, 5, 0x7fff);
4315 /* pass the open mode back */
4316 smb_SetSMBParm(outp, 6, (share & 0xf));
4317 smb_SetSMBDataLength(outp, 0);
4318 smb_ReleaseFID(fidp);
4322 userp = smb_GetUser(vcp, inp);
4324 caseFold = CM_FLAG_CASEFOLD;
4326 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4328 cm_ReleaseUser(userp);
4329 return CM_ERROR_NOSUCHPATH;
4331 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4332 tidPathp, &req, &scp);
4335 cm_ReleaseUser(userp);
4340 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4341 cm_ReleaseSCache(scp);
4342 cm_ReleaseUser(userp);
4343 if ( WANTS_DFS_PATHNAMES(inp) )
4344 return CM_ERROR_PATH_NOT_COVERED;
4346 return CM_ERROR_BADSHARENAME;
4348 #endif /* DFS_SUPPORT */
4350 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4352 cm_ReleaseSCache(scp);
4353 cm_ReleaseUser(userp);
4357 /* don't need callback to check file type, since file types never
4358 * change, and namei and cm_Lookup all stat the object at least once on
4359 * a successful return.
4361 if (scp->fileType != CM_SCACHETYPE_FILE) {
4362 cm_ReleaseSCache(scp);
4363 cm_ReleaseUser(userp);
4364 return CM_ERROR_ISDIR;
4367 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4370 /* save a pointer to the vnode */
4373 if ((share & 0xf) == 0)
4374 fidp->flags |= SMB_FID_OPENREAD;
4375 else if ((share & 0xf) == 1)
4376 fidp->flags |= SMB_FID_OPENWRITE;
4378 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4380 lock_ObtainMutex(&scp->mx);
4381 smb_SetSMBParm(outp, 0, fidp->fid);
4382 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4383 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4384 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4385 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4386 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4387 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4388 /* pass the open mode back; XXXX add access checks */
4389 smb_SetSMBParm(outp, 6, (share & 0xf));
4390 smb_SetSMBDataLength(outp, 0);
4391 lock_ReleaseMutex(&scp->mx);
4394 cm_Open(scp, 0, userp);
4396 /* send and free packet */
4397 smb_ReleaseFID(fidp);
4398 cm_ReleaseUser(userp);
4399 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4403 typedef struct smb_unlinkRock {
4408 char *maskp; /* pointer to the star pattern */
4413 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4416 smb_unlinkRock_t *rockp;
4424 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4425 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4426 caseFold |= CM_FLAG_8DOT3;
4428 matchName = dep->name;
4429 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4431 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4432 !cm_Is8Dot3(dep->name)) {
4433 cm_Gen8Dot3Name(dep, shortName, NULL);
4434 matchName = shortName;
4435 /* 8.3 matches are always case insensitive */
4436 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4439 osi_Log1(smb_logp, "Unlinking %s",
4440 osi_LogSaveString(smb_logp, matchName));
4441 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4442 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4443 smb_NotifyChange(FILE_ACTION_REMOVED,
4444 FILE_NOTIFY_CHANGE_FILE_NAME,
4445 dscp, dep->name, NULL, TRUE);
4449 /* If we made a case sensitive exact match, we might as well quit now. */
4450 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4451 code = CM_ERROR_STOPNOW;
4459 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4468 smb_unlinkRock_t rock;
4477 attribute = smb_GetSMBParm(inp, 0);
4479 tp = smb_GetSMBData(inp, NULL);
4480 pathp = smb_ParseASCIIBlock(tp, &tp);
4481 if (smb_StoreAnsiFilenames)
4482 OemToChar(pathp,pathp);
4484 osi_Log1(smb_logp, "SMB receive unlink %s",
4485 osi_LogSaveString(smb_logp, pathp));
4487 spacep = inp->spacep;
4488 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4490 userp = smb_GetUser(vcp, inp);
4492 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4494 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4496 cm_ReleaseUser(userp);
4497 return CM_ERROR_NOSUCHPATH;
4499 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4502 cm_ReleaseUser(userp);
4507 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4508 cm_ReleaseSCache(dscp);
4509 cm_ReleaseUser(userp);
4510 if ( WANTS_DFS_PATHNAMES(inp) )
4511 return CM_ERROR_PATH_NOT_COVERED;
4513 return CM_ERROR_BADSHARENAME;
4515 #endif /* DFS_SUPPORT */
4517 /* otherwise, scp points to the parent directory. */
4524 rock.maskp = smb_FindMask(pathp);
4525 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4528 thyper.HighPart = 0;
4534 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4535 * match. If that fails, we do a case insensitve match.
4537 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4538 !smb_IsStarMask(rock.maskp)) {
4539 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4542 thyper.HighPart = 0;
4543 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4548 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4550 if (code == CM_ERROR_STOPNOW)
4553 cm_ReleaseUser(userp);
4555 cm_ReleaseSCache(dscp);
4557 if (code == 0 && !rock.any)
4558 code = CM_ERROR_NOSUCHFILE;
4562 typedef struct smb_renameRock {
4563 cm_scache_t *odscp; /* old dir */
4564 cm_scache_t *ndscp; /* new dir */
4565 cm_user_t *userp; /* user */
4566 cm_req_t *reqp; /* request struct */
4567 smb_vc_t *vcp; /* virtual circuit */
4568 char *maskp; /* pointer to star pattern of old file name */
4569 int flags; /* tilde, casefold, etc */
4570 char *newNamep; /* ptr to the new file's name */
4573 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4576 smb_renameRock_t *rockp;
4581 rockp = (smb_renameRock_t *) vrockp;
4583 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4584 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4585 caseFold |= CM_FLAG_8DOT3;
4587 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4589 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4590 !cm_Is8Dot3(dep->name)) {
4591 cm_Gen8Dot3Name(dep, shortName, NULL);
4592 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4595 code = cm_Rename(rockp->odscp, dep->name,
4596 rockp->ndscp, rockp->newNamep, rockp->userp,
4598 /* if the call worked, stop doing the search now, since we
4599 * really only want to rename one file.
4602 code = CM_ERROR_STOPNOW;
4611 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4614 cm_space_t *spacep = NULL;
4615 smb_renameRock_t rock;
4616 cm_scache_t *oldDscp = NULL;
4617 cm_scache_t *newDscp = NULL;
4618 cm_scache_t *tmpscp= NULL;
4619 cm_scache_t *tmpscp2 = NULL;
4629 userp = smb_GetUser(vcp, inp);
4630 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4632 cm_ReleaseUser(userp);
4633 return CM_ERROR_NOSUCHPATH;
4637 spacep = inp->spacep;
4638 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4641 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4642 * what actually exists is foo/baz. I don't know why the code used to be
4643 * the way it was. 1/29/96
4645 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4647 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4649 * caseFold = CM_FLAG_CASEFOLD;
4651 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4652 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4653 userp, tidPathp, &req, &oldDscp);
4655 cm_ReleaseUser(userp);
4660 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4661 cm_ReleaseSCache(oldDscp);
4662 cm_ReleaseUser(userp);
4663 if ( WANTS_DFS_PATHNAMES(inp) )
4664 return CM_ERROR_PATH_NOT_COVERED;
4666 return CM_ERROR_BADSHARENAME;
4668 #endif /* DFS_SUPPORT */
4670 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4671 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4672 userp, tidPathp, &req, &newDscp);
4675 cm_ReleaseSCache(oldDscp);
4676 cm_ReleaseUser(userp);
4681 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4682 cm_ReleaseSCache(oldDscp);
4683 cm_ReleaseSCache(newDscp);
4684 cm_ReleaseUser(userp);
4685 if ( WANTS_DFS_PATHNAMES(inp) )
4686 return CM_ERROR_PATH_NOT_COVERED;
4688 return CM_ERROR_BADSHARENAME;
4690 #endif /* DFS_SUPPORT */
4693 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4694 * next, get the component names, and lower case them.
4697 /* handle the old name first */
4699 oldLastNamep = oldPathp;
4703 /* and handle the new name, too */
4705 newLastNamep = newPathp;
4709 /* TODO: The old name could be a wildcard. The new name must not be */
4711 /* do the vnode call */
4712 rock.odscp = oldDscp;
4713 rock.ndscp = newDscp;
4717 rock.maskp = oldLastNamep;
4718 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4719 rock.newNamep = newLastNamep;
4721 /* Check if the file already exists; if so return error */
4722 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4723 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4724 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4725 osi_LogSaveString(afsd_logp, newLastNamep));
4727 /* Check if the old and the new names differ only in case. If so return
4728 * success, else return CM_ERROR_EXISTS
4730 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4732 /* This would be a success only if the old file is *as same as* the new file */
4733 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4735 if (tmpscp == tmpscp2)
4738 code = CM_ERROR_EXISTS;
4739 cm_ReleaseSCache(tmpscp2);
4742 code = CM_ERROR_NOSUCHFILE;
4745 /* file exist, do not rename, also fixes move */
4746 osi_Log0(smb_logp, "Can't rename. Target already exists");
4747 code = CM_ERROR_EXISTS;
4751 cm_ReleaseSCache(tmpscp);
4752 cm_ReleaseSCache(newDscp);
4753 cm_ReleaseSCache(oldDscp);
4754 cm_ReleaseUser(userp);
4758 /* Now search the directory for the pattern, and do the appropriate rename when found */
4759 thyper.LowPart = 0; /* search dir from here */
4760 thyper.HighPart = 0;
4762 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4764 if (code == CM_ERROR_STOPNOW)
4767 code = CM_ERROR_NOSUCHFILE;
4769 /* Handle Change Notification */
4771 * Being lazy, not distinguishing between files and dirs in this
4772 * filter, since we'd have to do a lookup.
4774 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4775 if (oldDscp == newDscp) {
4776 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4777 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4778 filter, oldDscp, oldLastNamep,
4779 newLastNamep, TRUE);
4781 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4782 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4783 filter, oldDscp, oldLastNamep,
4785 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4786 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4787 filter, newDscp, newLastNamep,
4792 cm_ReleaseSCache(tmpscp);
4793 cm_ReleaseUser(userp);
4794 cm_ReleaseSCache(oldDscp);
4795 cm_ReleaseSCache(newDscp);
4800 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4803 cm_space_t *spacep = NULL;
4804 cm_scache_t *oldDscp = NULL;
4805 cm_scache_t *newDscp = NULL;
4806 cm_scache_t *tmpscp= NULL;
4807 cm_scache_t *tmpscp2 = NULL;
4808 cm_scache_t *sscp = NULL;
4817 userp = smb_GetUser(vcp, inp);
4819 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4821 cm_ReleaseUser(userp);
4822 return CM_ERROR_NOSUCHPATH;
4827 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4829 spacep = inp->spacep;
4830 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4832 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4833 userp, tidPathp, &req, &oldDscp);
4835 cm_ReleaseUser(userp);
4840 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4841 cm_ReleaseSCache(oldDscp);
4842 cm_ReleaseUser(userp);
4843 if ( WANTS_DFS_PATHNAMES(inp) )
4844 return CM_ERROR_PATH_NOT_COVERED;
4846 return CM_ERROR_BADSHARENAME;
4848 #endif /* DFS_SUPPORT */
4850 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4851 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4852 userp, tidPathp, &req, &newDscp);
4854 cm_ReleaseSCache(oldDscp);
4855 cm_ReleaseUser(userp);
4860 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4861 cm_ReleaseSCache(newDscp);
4862 cm_ReleaseSCache(oldDscp);
4863 cm_ReleaseUser(userp);
4864 if ( WANTS_DFS_PATHNAMES(inp) )
4865 return CM_ERROR_PATH_NOT_COVERED;
4867 return CM_ERROR_BADSHARENAME;
4869 #endif /* DFS_SUPPORT */
4871 /* Now, although we did two lookups for the two directories (because the same
4872 * directory can be referenced through different paths), we only allow hard links
4873 * within the same directory. */
4874 if (oldDscp != newDscp) {
4875 cm_ReleaseSCache(oldDscp);
4876 cm_ReleaseSCache(newDscp);
4877 cm_ReleaseUser(userp);
4878 return CM_ERROR_CROSSDEVLINK;
4881 /* handle the old name first */
4883 oldLastNamep = oldPathp;
4887 /* and handle the new name, too */
4889 newLastNamep = newPathp;
4893 /* now lookup the old name */
4894 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4895 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4897 cm_ReleaseSCache(oldDscp);
4898 cm_ReleaseSCache(newDscp);
4899 cm_ReleaseUser(userp);
4903 /* Check if the file already exists; if so return error */
4904 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4905 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4906 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4907 osi_LogSaveString(afsd_logp, newLastNamep));
4909 /* if the existing link is to the same file, then we return success */
4911 if(sscp == tmpscp) {
4914 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
4915 code = CM_ERROR_EXISTS;
4920 cm_ReleaseSCache(tmpscp);
4921 cm_ReleaseSCache(sscp);
4922 cm_ReleaseSCache(newDscp);
4923 cm_ReleaseSCache(oldDscp);
4924 cm_ReleaseUser(userp);
4928 /* now create the hardlink */
4929 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
4930 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
4931 osi_Log1(smb_logp," Link returns %d", code);
4933 /* Handle Change Notification */
4935 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
4936 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4937 smb_NotifyChange(FILE_ACTION_ADDED,
4938 filter, newDscp, newLastNamep,
4943 cm_ReleaseSCache(tmpscp);
4944 cm_ReleaseUser(userp);
4945 cm_ReleaseSCache(sscp);
4946 cm_ReleaseSCache(oldDscp);
4947 cm_ReleaseSCache(newDscp);
4952 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4958 tp = smb_GetSMBData(inp, NULL);
4959 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4960 if (smb_StoreAnsiFilenames)
4961 OemToChar(oldPathp,oldPathp);
4962 newPathp = smb_ParseASCIIBlock(tp, &tp);
4963 if (smb_StoreAnsiFilenames)
4964 OemToChar(newPathp,newPathp);
4966 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4967 osi_LogSaveString(smb_logp, oldPathp),
4968 osi_LogSaveString(smb_logp, newPathp));
4970 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
4975 typedef struct smb_rmdirRock {
4979 char *maskp; /* pointer to the star pattern */
4984 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4987 smb_rmdirRock_t *rockp;
4992 rockp = (smb_rmdirRock_t *) vrockp;
4994 matchName = dep->name;
4995 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
4996 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4998 match = (strcmp(matchName, rockp->maskp) == 0);
5000 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5001 !cm_Is8Dot3(dep->name)) {
5002 cm_Gen8Dot3Name(dep, shortName, NULL);
5003 matchName = shortName;
5004 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5007 osi_Log1(smb_logp, "Removing directory %s",
5008 osi_LogSaveString(smb_logp, matchName));
5009 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5010 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5011 smb_NotifyChange(FILE_ACTION_REMOVED,
5012 FILE_NOTIFY_CHANGE_DIR_NAME,
5013 dscp, dep->name, NULL, TRUE);
5022 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5030 smb_rmdirRock_t rock;
5039 tp = smb_GetSMBData(inp, NULL);
5040 pathp = smb_ParseASCIIBlock(tp, &tp);
5041 if (smb_StoreAnsiFilenames)
5042 OemToChar(pathp,pathp);
5044 spacep = inp->spacep;
5045 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5047 userp = smb_GetUser(vcp, inp);
5049 caseFold = CM_FLAG_CASEFOLD;
5051 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5053 cm_ReleaseUser(userp);
5054 return CM_ERROR_NOSUCHPATH;
5056 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5057 userp, tidPathp, &req, &dscp);
5060 cm_ReleaseUser(userp);
5065 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5066 cm_ReleaseSCache(dscp);
5067 cm_ReleaseUser(userp);
5068 if ( WANTS_DFS_PATHNAMES(inp) )
5069 return CM_ERROR_PATH_NOT_COVERED;
5071 return CM_ERROR_BADSHARENAME;
5073 #endif /* DFS_SUPPORT */
5075 /* otherwise, scp points to the parent directory. */
5082 rock.maskp = lastNamep;
5083 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5086 thyper.HighPart = 0;
5090 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5091 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5092 if (code == 0 && !rock.any) {
5094 thyper.HighPart = 0;
5095 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5096 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5099 cm_ReleaseUser(userp);
5101 cm_ReleaseSCache(dscp);
5103 if (code == 0 && !rock.any)
5104 code = CM_ERROR_NOSUCHFILE;
5108 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5118 fid = smb_GetSMBParm(inp, 0);
5120 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5122 fid = smb_ChainFID(fid, inp);
5123 fidp = smb_FindFID(vcp, fid, 0);
5124 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5126 smb_ReleaseFID(fidp);
5127 return CM_ERROR_BADFD;
5130 userp = smb_GetUser(vcp, inp);
5132 lock_ObtainMutex(&fidp->mx);
5133 if (fidp->flags & SMB_FID_OPENWRITE)
5134 code = cm_FSync(fidp->scp, userp, &req);
5137 lock_ReleaseMutex(&fidp->mx);
5139 smb_ReleaseFID(fidp);
5141 cm_ReleaseUser(userp);
5146 struct smb_FullNameRock {
5152 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5156 struct smb_FullNameRock *vrockp;
5158 vrockp = (struct smb_FullNameRock *)rockp;
5160 if (!cm_Is8Dot3(dep->name)) {
5161 cm_Gen8Dot3Name(dep, shortName, NULL);
5163 if (cm_stricmp(shortName, vrockp->name) == 0) {
5164 vrockp->fullName = strdup(dep->name);
5165 return CM_ERROR_STOPNOW;
5168 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5169 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5170 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5171 vrockp->fullName = strdup(dep->name);
5172 return CM_ERROR_STOPNOW;
5177 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5178 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5180 struct smb_FullNameRock rock;
5186 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5187 if (code == CM_ERROR_STOPNOW)
5188 *newPathp = rock.fullName;
5190 *newPathp = strdup(pathp);
5193 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5204 fid = smb_GetSMBParm(inp, 0);
5205 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5207 osi_Log1(smb_logp, "SMB close fid %d", fid);
5209 fid = smb_ChainFID(fid, inp);
5210 fidp = smb_FindFID(vcp, fid, 0);
5212 return CM_ERROR_BADFD;
5215 userp = smb_GetUser(vcp, inp);
5217 lock_ObtainMutex(&fidp->mx);
5219 /* Don't jump the gun on an async raw write */
5220 while (fidp->raw_writers) {
5221 lock_ReleaseMutex(&fidp->mx);
5222 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5223 lock_ObtainMutex(&fidp->mx);
5226 fidp->flags |= SMB_FID_DELETE;
5228 /* watch for ioctl closes, and read-only opens */
5229 if (fidp->scp != NULL &&
5230 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5231 == SMB_FID_OPENWRITE) {
5232 if (dosTime != 0 && dosTime != -1) {
5233 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5234 /* This fixes defect 10958 */
5235 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5236 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5238 code = cm_FSync(fidp->scp, userp, &req);
5243 if (fidp->flags & SMB_FID_DELONCLOSE) {
5244 cm_scache_t *dscp = fidp->NTopen_dscp;
5245 char *pathp = fidp->NTopen_pathp;
5248 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5249 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5250 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5251 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5252 smb_NotifyChange(FILE_ACTION_REMOVED,
5253 FILE_NOTIFY_CHANGE_DIR_NAME,
5254 dscp, fullPathp, NULL, TRUE);
5258 code = cm_Unlink(dscp, fullPathp, userp, &req);
5259 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5260 smb_NotifyChange(FILE_ACTION_REMOVED,
5261 FILE_NOTIFY_CHANGE_FILE_NAME,
5262 dscp, fullPathp, NULL, TRUE);
5266 lock_ReleaseMutex(&fidp->mx);
5268 if (fidp->flags & SMB_FID_NTOPEN) {
5269 cm_ReleaseSCache(fidp->NTopen_dscp);
5270 free(fidp->NTopen_pathp);
5272 if (fidp->NTopen_wholepathp)
5273 free(fidp->NTopen_wholepathp);
5275 smb_ReleaseFID(fidp);
5276 cm_ReleaseUser(userp);
5281 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5284 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5285 cm_user_t *userp, long *readp)
5287 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5288 cm_user_t *userp, long *readp, int dosflag)
5295 osi_hyper_t fileLength;
5297 osi_hyper_t lastByte;
5298 osi_hyper_t bufferOffset;
5299 long bufIndex, nbytes;
5309 lock_ObtainMutex(&fidp->mx);
5311 lock_ObtainMutex(&scp->mx);
5313 if (offset.HighPart == 0) {
5314 chunk = offset.LowPart >> cm_logChunkSize;
5315 if (chunk != fidp->curr_chunk) {
5316 fidp->prev_chunk = fidp->curr_chunk;
5317 fidp->curr_chunk = chunk;
5319 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5323 /* start by looking up the file's end */
5324 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5325 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5326 if (code) goto done;
5328 /* now we have the entry locked, look up the length */
5329 fileLength = scp->length;
5331 /* adjust count down so that it won't go past EOF */
5332 thyper.LowPart = count;
5333 thyper.HighPart = 0;
5334 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5336 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5337 /* we'd read past EOF, so just stop at fileLength bytes.
5338 * Start by computing how many bytes remain in the file.
5340 thyper = LargeIntegerSubtract(fileLength, offset);
5342 /* if we are past EOF, read 0 bytes */
5343 if (LargeIntegerLessThanZero(thyper))
5346 count = thyper.LowPart;
5351 /* now, copy the data one buffer at a time,
5352 * until we've filled the request packet
5355 /* if we've copied all the data requested, we're done */
5356 if (count <= 0) break;
5358 /* otherwise, load up a buffer of data */
5359 thyper.HighPart = offset.HighPart;
5360 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5361 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5364 buf_Release(bufferp);
5367 lock_ReleaseMutex(&scp->mx);
5369 lock_ObtainRead(&scp->bufCreateLock);
5370 code = buf_Get(scp, &thyper, &bufferp);
5371 lock_ReleaseRead(&scp->bufCreateLock);
5373 lock_ObtainMutex(&scp->mx);
5374 if (code) goto done;
5375 bufferOffset = thyper;
5377 /* now get the data in the cache */
5379 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5380 CM_SCACHESYNC_NEEDCALLBACK |
5381 CM_SCACHESYNC_READ);
5382 if (code) goto done;
5384 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5386 /* otherwise, load the buffer and try again */
5387 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5391 buf_Release(bufferp);
5395 } /* if (wrong buffer) ... */
5397 /* now we have the right buffer loaded. Copy out the
5398 * data from here to the user's buffer.
5400 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5402 /* and figure out how many bytes we want from this buffer */
5403 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5404 if (nbytes > count) nbytes = count; /* don't go past EOF */
5406 /* now copy the data */
5409 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5412 memcpy(op, bufferp->datap + bufIndex, nbytes);
5414 /* adjust counters, pointers, etc. */
5417 thyper.LowPart = nbytes;
5418 thyper.HighPart = 0;
5419 offset = LargeIntegerAdd(thyper, offset);
5423 lock_ReleaseMutex(&scp->mx);
5424 lock_ReleaseMutex(&fidp->mx);
5426 buf_Release(bufferp);
5428 if (code == 0 && sequential)
5429 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5435 * smb_WriteData -- common code for Write and Raw Write
5438 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5439 cm_user_t *userp, long *writtenp)
5441 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5442 cm_user_t *userp, long *writtenp, int dosflag)
5449 osi_hyper_t fileLength; /* file's length at start of write */
5450 osi_hyper_t minLength; /* don't read past this */
5451 long nbytes; /* # of bytes to transfer this iteration */
5453 osi_hyper_t thyper; /* hyper tmp variable */
5454 osi_hyper_t bufferOffset;
5455 long bufIndex; /* index in buffer where our data is */
5457 osi_hyper_t writeBackOffset;/* offset of region to write back when
5462 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5463 fidp->fid, offsetp->LowPart, count);
5473 lock_ObtainMutex(&fidp->mx);
5475 lock_ObtainMutex(&scp->mx);
5477 /* start by looking up the file's end */
5478 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5480 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5481 CM_SCACHESYNC_NEEDCALLBACK
5482 | CM_SCACHESYNC_SETSTATUS
5483 | CM_SCACHESYNC_GETSTATUS);
5484 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5489 /* make sure we have a writable FD */
5490 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5491 code = CM_ERROR_BADFDOP;
5495 /* now we have the entry locked, look up the length */
5496 fileLength = scp->length;
5497 minLength = fileLength;
5498 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5499 minLength = scp->serverLength;
5501 /* adjust file length if we extend past EOF */
5502 thyper.LowPart = count;
5503 thyper.HighPart = 0;
5504 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5505 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5506 /* we'd write past EOF, so extend the file */
5507 scp->mask |= CM_SCACHEMASK_LENGTH;
5508 scp->length = thyper;
5509 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5511 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5513 /* now, if the new position (thyper) and the old (offset) are in
5514 * different storeback windows, remember to store back the previous
5515 * storeback window when we're done with the write.
5517 if ((thyper.LowPart & (-cm_chunkSize)) !=
5518 (offset.LowPart & (-cm_chunkSize))) {
5519 /* they're different */
5521 writeBackOffset.HighPart = offset.HighPart;
5522 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5527 /* now, copy the data one buffer at a time, until we've filled the
5530 /* if we've copied all the data requested, we're done */
5534 /* handle over quota or out of space */
5535 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5536 *writtenp = written;
5537 code = CM_ERROR_QUOTA;
5541 /* otherwise, load up a buffer of data */
5542 thyper.HighPart = offset.HighPart;
5543 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5544 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5547 lock_ReleaseMutex(&bufferp->mx);
5548 buf_Release(bufferp);
5551 lock_ReleaseMutex(&scp->mx);
5553 lock_ObtainRead(&scp->bufCreateLock);
5554 code = buf_Get(scp, &thyper, &bufferp);
5555 lock_ReleaseRead(&scp->bufCreateLock);
5557 lock_ObtainMutex(&bufferp->mx);
5558 lock_ObtainMutex(&scp->mx);
5559 if (code) goto done;
5561 bufferOffset = thyper;
5563 /* now get the data in the cache */
5565 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5567 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5568 CM_SCACHESYNC_NEEDCALLBACK
5569 | CM_SCACHESYNC_WRITE
5570 | CM_SCACHESYNC_BUFLOCKED);
5571 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5576 /* If we're overwriting the entire buffer, or
5577 * if we're writing at or past EOF, mark the
5578 * buffer as current so we don't call
5579 * cm_GetBuffer. This skips the fetch from the
5580 * server in those cases where we're going to
5581 * obliterate all the data in the buffer anyway,
5582 * or in those cases where there is no useful
5583 * data at the server to start with.
5585 * Use minLength instead of scp->length, since
5586 * the latter has already been updated by this
5589 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5590 || LargeIntegerEqualTo(offset, bufferp->offset)
5591 && (count >= cm_data.buf_blockSize
5592 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5593 ConvertLongToLargeInteger(count)),
5595 if (count < cm_data.buf_blockSize
5596 && bufferp->dataVersion == -1)
5597 memset(bufferp->datap, 0,
5598 cm_data.buf_blockSize);
5599 bufferp->dataVersion = scp->dataVersion;
5602 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5604 /* otherwise, load the buffer and try again */
5605 lock_ReleaseMutex(&bufferp->mx);
5606 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5608 lock_ReleaseMutex(&scp->mx);
5609 lock_ObtainMutex(&bufferp->mx);
5610 lock_ObtainMutex(&scp->mx);
5614 lock_ReleaseMutex(&bufferp->mx);
5615 buf_Release(bufferp);
5619 } /* if (wrong buffer) ... */
5621 /* now we have the right buffer loaded. Copy out the
5622 * data from here to the user's buffer.
5624 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5626 /* and figure out how many bytes we want from this buffer */
5627 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5629 nbytes = count; /* don't go past end of request */
5631 /* now copy the data */
5634 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5637 memcpy(bufferp->datap + bufIndex, op, nbytes);
5638 buf_SetDirty(bufferp);
5640 /* and record the last writer */
5641 if (bufferp->userp != userp) {
5644 cm_ReleaseUser(bufferp->userp);
5645 bufferp->userp = userp;
5648 /* adjust counters, pointers, etc. */
5652 thyper.LowPart = nbytes;
5653 thyper.HighPart = 0;
5654 offset = LargeIntegerAdd(thyper, offset);
5658 lock_ReleaseMutex(&scp->mx);
5659 lock_ReleaseMutex(&fidp->mx);
5661 lock_ReleaseMutex(&bufferp->mx);
5662 buf_Release(bufferp);
5665 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5666 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5667 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5668 fidp->NTopen_dscp, fidp->NTopen_pathp,
5672 if (code == 0 && doWriteBack) {
5674 lock_ObtainMutex(&scp->mx);
5675 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5677 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5678 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5680 lock_ReleaseMutex(&scp->mx);
5681 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5682 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5685 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5686 fidp->fid, code, *writtenp);
5690 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5693 long count, written = 0, total_written = 0;
5698 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5700 int inDataBlockCount;
5702 fd = smb_GetSMBParm(inp, 0);
5703 count = smb_GetSMBParm(inp, 1);
5704 offset.HighPart = 0; /* too bad */
5705 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5707 op = smb_GetSMBData(inp, NULL);
5708 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5710 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5711 fd, offset.LowPart, count);
5713 fd = smb_ChainFID(fd, inp);
5714 fidp = smb_FindFID(vcp, fd, 0);
5716 return CM_ERROR_BADFD;
5719 if (fidp->flags & SMB_FID_IOCTL)
5720 return smb_IoctlWrite(fidp, vcp, inp, outp);
5722 userp = smb_GetUser(vcp, inp);
5724 /* special case: 0 bytes transferred means truncate to this position */
5730 truncAttr.mask = CM_ATTRMASK_LENGTH;
5731 truncAttr.length.LowPart = offset.LowPart;
5732 truncAttr.length.HighPart = 0;
5733 lock_ObtainMutex(&fidp->mx);
5734 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5735 lock_ReleaseMutex(&fidp->mx);
5736 smb_SetSMBParm(outp, 0, /* count */ 0);
5737 smb_SetSMBDataLength(outp, 0);
5738 fidp->flags |= SMB_FID_LENGTHSETDONE;
5743 * Work around bug in NT client
5745 * When copying a file, the NT client should first copy the data,
5746 * then copy the last write time. But sometimes the NT client does
5747 * these in the wrong order, so the data copies would inadvertently
5748 * cause the last write time to be overwritten. We try to detect this,
5749 * and don't set client mod time if we think that would go against the
5752 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5753 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5754 fidp->scp->clientModTime = time(NULL);
5758 while ( code == 0 && count > 0 ) {
5760 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5762 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5764 if (code == 0 && written == 0)
5765 code = CM_ERROR_PARTIALWRITE;
5767 offset.LowPart += written;
5769 total_written += written;
5773 /* set the packet data length to 3 bytes for the data block header,
5774 * plus the size of the data.
5776 smb_SetSMBParm(outp, 0, total_written);
5777 smb_SetSMBDataLength(outp, 0);
5780 smb_ReleaseFID(fidp);
5781 cm_ReleaseUser(userp);
5786 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5787 NCB *ncbp, raw_write_cont_t *rwcp)
5800 fd = smb_GetSMBParm(inp, 0);
5801 fidp = smb_FindFID(vcp, fd, 0);
5803 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5804 rwcp->offset.LowPart, rwcp->count);
5806 userp = smb_GetUser(vcp, inp);
5810 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5813 rawBuf = (dos_ptr) rwcp->buf;
5814 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5815 (unsigned char *) rawBuf, userp,
5819 if (rwcp->writeMode & 0x1) { /* synchronous */
5822 smb_FormatResponsePacket(vcp, inp, outp);
5823 op = (smb_t *) outp;
5824 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5825 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5826 smb_SetSMBDataLength(outp, 0);
5827 smb_SendPacket(vcp, outp);
5828 smb_FreePacket(outp);
5830 else { /* asynchronous */
5831 lock_ObtainMutex(&fidp->mx);
5832 fidp->raw_writers--;
5833 if (fidp->raw_writers == 0)
5834 thrd_SetEvent(fidp->raw_write_event);
5835 lock_ReleaseMutex(&fidp->mx);
5838 /* Give back raw buffer */
5839 lock_ObtainMutex(&smb_RawBufLock);
5841 *((char **)rawBuf) = smb_RawBufs;
5843 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5845 smb_RawBufs = rawBuf;
5846 lock_ReleaseMutex(&smb_RawBufLock);
5848 smb_ReleaseFID(fidp);
5849 cm_ReleaseUser(userp);
5852 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5857 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5860 long count, written = 0, total_written = 0;
5867 unsigned short writeMode;
5874 fd = smb_GetSMBParm(inp, 0);
5875 totalCount = smb_GetSMBParm(inp, 1);
5876 count = smb_GetSMBParm(inp, 10);
5877 offset.HighPart = 0; /* too bad */
5878 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5879 writeMode = smb_GetSMBParm(inp, 7);
5881 op = (char *) inp->data;
5882 op += smb_GetSMBParm(inp, 11);
5885 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5886 fd, offset.LowPart, count, writeMode);
5888 fd = smb_ChainFID(fd, inp);
5889 fidp = smb_FindFID(vcp, fd, 0);
5891 return CM_ERROR_BADFD;
5894 userp = smb_GetUser(vcp, inp);
5897 * Work around bug in NT client
5899 * When copying a file, the NT client should first copy the data,
5900 * then copy the last write time. But sometimes the NT client does
5901 * these in the wrong order, so the data copies would inadvertently
5902 * cause the last write time to be overwritten. We try to detect this,
5903 * and don't set client mod time if we think that would go against the
5906 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5907 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5908 fidp->scp->clientModTime = time(NULL);
5912 while ( code == 0 && count > 0 ) {
5914 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5916 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5918 if (code == 0 && written == 0)
5919 code = CM_ERROR_PARTIALWRITE;
5921 offset.LowPart += written;
5923 total_written += written;
5927 /* Get a raw buffer */
5930 lock_ObtainMutex(&smb_RawBufLock);
5932 /* Get a raw buf, from head of list */
5933 rawBuf = smb_RawBufs;
5935 smb_RawBufs = *(char **)smb_RawBufs;
5937 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5941 code = CM_ERROR_USESTD;
5943 lock_ReleaseMutex(&smb_RawBufLock);
5946 /* Don't allow a premature Close */
5947 if (code == 0 && (writeMode & 1) == 0) {
5948 lock_ObtainMutex(&fidp->mx);
5949 fidp->raw_writers++;
5950 thrd_ResetEvent(fidp->raw_write_event);
5951 lock_ReleaseMutex(&fidp->mx);
5954 smb_ReleaseFID(fidp);
5955 cm_ReleaseUser(userp);
5958 smb_SetSMBParm(outp, 0, total_written);
5959 smb_SetSMBDataLength(outp, 0);
5960 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5967 rwcp->offset.HighPart = 0;
5968 rwcp->offset.LowPart = offset.LowPart + count;
5969 rwcp->count = totalCount - count;
5970 rwcp->writeMode = writeMode;
5971 rwcp->alreadyWritten = total_written;
5973 /* set the packet data length to 3 bytes for the data block header,
5974 * plus the size of the data.
5976 smb_SetSMBParm(outp, 0, 0xffff);
5977 smb_SetSMBDataLength(outp, 0);
5982 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5985 long count, finalCount;
5992 fd = smb_GetSMBParm(inp, 0);
5993 count = smb_GetSMBParm(inp, 1);
5994 offset.HighPart = 0; /* too bad */
5995 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5997 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5998 fd, offset.LowPart, count);
6000 fd = smb_ChainFID(fd, inp);
6001 fidp = smb_FindFID(vcp, fd, 0);
6003 return CM_ERROR_BADFD;
6006 if (fidp->flags & SMB_FID_IOCTL) {
6007 return smb_IoctlRead(fidp, vcp, inp, outp);
6010 userp = smb_GetUser(vcp, inp);
6012 /* remember this for final results */
6013 smb_SetSMBParm(outp, 0, count);
6014 smb_SetSMBParm(outp, 1, 0);
6015 smb_SetSMBParm(outp, 2, 0);
6016 smb_SetSMBParm(outp, 3, 0);
6017 smb_SetSMBParm(outp, 4, 0);
6019 /* set the packet data length to 3 bytes for the data block header,
6020 * plus the size of the data.
6022 smb_SetSMBDataLength(outp, count+3);
6024 /* get op ptr after putting in the parms, since otherwise we don't
6025 * know where the data really is.
6027 op = smb_GetSMBData(outp, NULL);
6029 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6030 *op++ = 1; /* data block marker */
6031 *op++ = (unsigned char) (count & 0xff);
6032 *op++ = (unsigned char) ((count >> 8) & 0xff);
6035 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6037 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6040 /* fix some things up */
6041 smb_SetSMBParm(outp, 0, finalCount);
6042 smb_SetSMBDataLength(outp, finalCount+3);
6044 smb_ReleaseFID(fidp);
6046 cm_ReleaseUser(userp);
6050 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6057 cm_scache_t *dscp; /* dir we're dealing with */
6058 cm_scache_t *scp; /* file we're creating */
6060 int initialModeBits;
6070 /* compute initial mode bits based on read-only flag in attributes */
6071 initialModeBits = 0777;
6073 tp = smb_GetSMBData(inp, NULL);
6074 pathp = smb_ParseASCIIBlock(tp, &tp);
6075 if (smb_StoreAnsiFilenames)
6076 OemToChar(pathp,pathp);
6078 if (strcmp(pathp, "\\") == 0)
6079 return CM_ERROR_EXISTS;
6081 spacep = inp->spacep;
6082 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6084 userp = smb_GetUser(vcp, inp);
6086 caseFold = CM_FLAG_CASEFOLD;
6088 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6090 cm_ReleaseUser(userp);
6091 return CM_ERROR_NOSUCHPATH;
6094 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6095 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6096 userp, tidPathp, &req, &dscp);
6099 cm_ReleaseUser(userp);
6104 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6105 cm_ReleaseSCache(dscp);
6106 cm_ReleaseUser(userp);
6107 if ( WANTS_DFS_PATHNAMES(inp) )
6108 return CM_ERROR_PATH_NOT_COVERED;
6110 return CM_ERROR_BADSHARENAME;
6112 #endif /* DFS_SUPPORT */
6114 /* otherwise, scp points to the parent directory. Do a lookup, and
6115 * fail if we find it. Otherwise, we do the create.
6121 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6122 if (scp) cm_ReleaseSCache(scp);
6123 if (code != CM_ERROR_NOSUCHFILE) {
6124 if (code == 0) code = CM_ERROR_EXISTS;
6125 cm_ReleaseSCache(dscp);
6126 cm_ReleaseUser(userp);
6130 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6131 setAttr.clientModTime = time(NULL);
6132 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6133 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6134 smb_NotifyChange(FILE_ACTION_ADDED,
6135 FILE_NOTIFY_CHANGE_DIR_NAME,
6136 dscp, lastNamep, NULL, TRUE);
6138 /* we don't need this any longer */
6139 cm_ReleaseSCache(dscp);
6142 /* something went wrong creating or truncating the file */
6143 cm_ReleaseUser(userp);
6147 /* otherwise we succeeded */
6148 smb_SetSMBDataLength(outp, 0);
6149 cm_ReleaseUser(userp);
6154 BOOL smb_IsLegalFilename(char *filename)
6157 * Find the longest substring of filename that does not contain
6158 * any of the chars in illegalChars. If that substring is less
6159 * than the length of the whole string, then one or more of the
6160 * illegal chars is in filename.
6162 if (strcspn(filename, illegalChars) < strlen(filename))
6168 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6176 cm_scache_t *dscp; /* dir we're dealing with */
6177 cm_scache_t *scp; /* file we're creating */
6179 int initialModeBits;
6191 excl = (inp->inCom == 0x03)? 0 : 1;
6193 attributes = smb_GetSMBParm(inp, 0);
6194 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6196 /* compute initial mode bits based on read-only flag in attributes */
6197 initialModeBits = 0666;
6198 if (attributes & 1) initialModeBits &= ~0222;
6200 tp = smb_GetSMBData(inp, NULL);
6201 pathp = smb_ParseASCIIBlock(tp, &tp);
6202 if (smb_StoreAnsiFilenames)
6203 OemToChar(pathp,pathp);
6205 spacep = inp->spacep;
6206 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6208 userp = smb_GetUser(vcp, inp);
6210 caseFold = CM_FLAG_CASEFOLD;
6212 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6214 cm_ReleaseUser(userp);
6215 return CM_ERROR_NOSUCHPATH;
6217 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6218 userp, tidPathp, &req, &dscp);
6221 cm_ReleaseUser(userp);
6226 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6227 cm_ReleaseSCache(dscp);
6228 cm_ReleaseUser(userp);
6229 if ( WANTS_DFS_PATHNAMES(inp) )
6230 return CM_ERROR_PATH_NOT_COVERED;
6232 return CM_ERROR_BADSHARENAME;
6234 #endif /* DFS_SUPPORT */
6236 /* otherwise, scp points to the parent directory. Do a lookup, and
6237 * truncate the file if we find it, otherwise we create the file.
6244 if (!smb_IsLegalFilename(lastNamep))
6245 return CM_ERROR_BADNTFILENAME;
6247 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6248 #ifdef DEBUG_VERBOSE
6251 hexp = osi_HexifyString( lastNamep );
6252 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6257 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6258 if (code && code != CM_ERROR_NOSUCHFILE) {
6259 cm_ReleaseSCache(dscp);
6260 cm_ReleaseUser(userp);
6264 /* if we get here, if code is 0, the file exists and is represented by
6265 * scp. Otherwise, we have to create it.
6269 /* oops, file shouldn't be there */
6270 cm_ReleaseSCache(dscp);
6271 cm_ReleaseSCache(scp);
6272 cm_ReleaseUser(userp);
6273 return CM_ERROR_EXISTS;
6276 setAttr.mask = CM_ATTRMASK_LENGTH;
6277 setAttr.length.LowPart = 0;
6278 setAttr.length.HighPart = 0;
6279 code = cm_SetAttr(scp, &setAttr, userp, &req);
6282 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6283 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6284 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6286 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6287 smb_NotifyChange(FILE_ACTION_ADDED,
6288 FILE_NOTIFY_CHANGE_FILE_NAME,
6289 dscp, lastNamep, NULL, TRUE);
6290 if (!excl && code == CM_ERROR_EXISTS) {
6291 /* not an exclusive create, and someone else tried
6292 * creating it already, then we open it anyway. We
6293 * don't bother retrying after this, since if this next
6294 * fails, that means that the file was deleted after
6295 * we started this call.
6297 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6300 setAttr.mask = CM_ATTRMASK_LENGTH;
6301 setAttr.length.LowPart = 0;
6302 setAttr.length.HighPart = 0;
6303 code = cm_SetAttr(scp, &setAttr, userp, &req);
6308 /* we don't need this any longer */
6309 cm_ReleaseSCache(dscp);
6312 /* something went wrong creating or truncating the file */
6313 if (scp) cm_ReleaseSCache(scp);
6314 cm_ReleaseUser(userp);
6318 /* make sure we only open files */
6319 if (scp->fileType != CM_SCACHETYPE_FILE) {
6320 cm_ReleaseSCache(scp);
6321 cm_ReleaseUser(userp);
6322 return CM_ERROR_ISDIR;
6325 /* now all we have to do is open the file itself */
6326 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6329 /* save a pointer to the vnode */
6332 /* always create it open for read/write */
6333 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6335 smb_ReleaseFID(fidp);
6337 smb_SetSMBParm(outp, 0, fidp->fid);
6338 smb_SetSMBDataLength(outp, 0);
6340 cm_Open(scp, 0, userp);
6342 cm_ReleaseUser(userp);
6343 /* leave scp held since we put it in fidp->scp */
6347 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6360 fd = smb_GetSMBParm(inp, 0);
6361 whence = smb_GetSMBParm(inp, 1);
6362 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6364 /* try to find the file descriptor */
6365 fd = smb_ChainFID(fd, inp);
6366 fidp = smb_FindFID(vcp, fd, 0);
6367 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6368 return CM_ERROR_BADFD;
6371 userp = smb_GetUser(vcp, inp);
6373 lock_ObtainMutex(&fidp->mx);
6375 lock_ObtainMutex(&scp->mx);
6376 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6377 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6380 /* offset from current offset */
6381 offset += fidp->offset;
6383 else if (whence == 2) {
6384 /* offset from current EOF */
6385 offset += scp->length.LowPart;
6387 fidp->offset = offset;
6388 smb_SetSMBParm(outp, 0, offset & 0xffff);
6389 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6390 smb_SetSMBDataLength(outp, 0);
6392 lock_ReleaseMutex(&scp->mx);
6393 lock_ReleaseMutex(&fidp->mx);
6394 smb_ReleaseFID(fidp);
6395 cm_ReleaseUser(userp);
6399 /* dispatch all of the requests received in a packet. Due to chaining, this may
6400 * be more than one request.
6402 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6403 NCB *ncbp, raw_write_cont_t *rwcp)
6407 unsigned long code = 0;
6408 unsigned char *outWctp;
6409 int nparms; /* # of bytes of parameters */
6411 int nbytes; /* bytes of data, excluding count */
6414 unsigned short errCode;
6415 unsigned long NTStatus;
6417 unsigned char errClass;
6418 unsigned int oldGen;
6419 DWORD oldTime, newTime;
6421 /* get easy pointer to the data */
6422 smbp = (smb_t *) inp->data;
6424 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6425 /* setup the basic parms for the initial request in the packet */
6426 inp->inCom = smbp->com;
6427 inp->wctp = &smbp->wct;
6429 inp->ncb_length = ncbp->ncb_length;
6434 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6435 /* log it and discard it */
6440 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6441 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6443 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6444 1, ncbp->ncb_length, ptbuf, inp);
6445 DeregisterEventSource(h);
6447 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6452 /* We are an ongoing op */
6453 thrd_Increment(&ongoingOps);
6455 /* set up response packet for receiving output */
6456 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6457 smb_FormatResponsePacket(vcp, inp, outp);
6458 outWctp = outp->wctp;
6460 /* Remember session generation number and time */
6461 oldGen = sessionGen;
6462 oldTime = GetCurrentTime();
6464 while (inp->inCom != 0xff) {
6465 dp = &smb_dispatchTable[inp->inCom];
6467 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6468 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6469 code = outp->resumeCode;
6473 /* process each request in the packet; inCom, wctp and inCount
6474 * are already set up.
6476 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6479 /* now do the dispatch */
6480 /* start by formatting the response record a little, as a default */
6481 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6483 outWctp[1] = 0xff; /* no operation */
6484 outWctp[2] = 0; /* padding */
6489 /* not a chained request, this is a more reasonable default */
6490 outWctp[0] = 0; /* wct of zero */
6491 outWctp[1] = 0; /* and bcc (word) of zero */
6495 /* once set, stays set. Doesn't matter, since we never chain
6496 * "no response" calls.
6498 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6502 /* we have a recognized operation */
6504 if (inp->inCom == 0x1d)
6506 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6509 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
6510 osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6511 code = (*(dp->procp)) (vcp, inp, outp);
6512 osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6513 osi_Log1(smb_logp,"Dispatch return code[%d]",(code==0)?0:code-CM_ERROR_BASE);
6515 if ( code == CM_ERROR_BADSMB ||
6516 code == CM_ERROR_BADOP )
6518 #endif /* LOG_PACKET */
6521 if (oldGen != sessionGen) {
6526 newTime = GetCurrentTime();
6527 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6528 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6529 newTime - oldTime, ncbp->ncb_length);
6531 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6532 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6533 DeregisterEventSource(h);
6535 osi_Log1(smb_logp, "Pkt straddled session startup, "
6536 "ncb length %d", ncbp->ncb_length);
6540 /* bad opcode, fail the request, after displaying it */
6541 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6544 #endif /* LOG_PACKET */
6548 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6549 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6550 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6551 if (code == IDCANCEL)
6555 code = CM_ERROR_BADOP;
6558 /* catastrophic failure: log as much as possible */
6559 if (code == CM_ERROR_BADSMB) {
6566 "Invalid SMB, ncb_length %d",
6569 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6570 sprintf(s, "Invalid SMB message, length %d",
6573 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6574 1, ncbp->ncb_length, ptbuf, smbp);
6575 DeregisterEventSource(h);
6578 #endif /* LOG_PACKET */
6580 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6583 code = CM_ERROR_INVAL;
6586 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6587 thrd_Decrement(&ongoingOps);
6592 /* now, if we failed, turn the current response into an empty
6593 * one, and fill in the response packet's error code.
6596 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6597 smb_MapNTError(code, &NTStatus);
6598 outWctp = outp->wctp;
6599 smbp = (smb_t *) &outp->data;
6600 if (code != CM_ERROR_PARTIALWRITE
6601 && code != CM_ERROR_BUFFERTOOSMALL
6602 && code != CM_ERROR_GSSCONTINUE) {
6603 /* nuke wct and bcc. For a partial
6604 * write or an in-process authentication handshake,
6605 * assume they're OK.
6611 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6612 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6613 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6614 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6615 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6619 smb_MapCoreError(code, vcp, &errCode, &errClass);
6620 outWctp = outp->wctp;
6621 smbp = (smb_t *) &outp->data;
6622 if (code != CM_ERROR_PARTIALWRITE) {
6623 /* nuke wct and bcc. For a partial
6624 * write, assume they're OK.
6630 smbp->errLow = (unsigned char) (errCode & 0xff);
6631 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6632 smbp->rcls = errClass;
6635 } /* error occurred */
6637 /* if we're here, we've finished one request. Look to see if
6638 * this is a chained opcode. If it is, setup things to process
6639 * the chained request, and setup the output buffer to hold the
6640 * chained response. Start by finding the next input record.
6642 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6643 break; /* not a chained req */
6644 tp = inp->wctp; /* points to start of last request */
6645 /* in a chained request, the first two
6646 * parm fields are required, and are
6647 * AndXCommand/AndXReserved and
6649 if (tp[0] < 2) break;
6650 if (tp[1] == 0xff) break; /* no more chained opcodes */
6652 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6655 /* and now append the next output request to the end of this
6656 * last request. Begin by finding out where the last response
6657 * ends, since that's where we'll put our new response.
6659 outWctp = outp->wctp; /* ptr to out parameters */
6660 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6661 nparms = outWctp[0] << 1;
6662 tp = outWctp + nparms + 1; /* now points to bcc field */
6663 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6664 tp += 2 /* for the count itself */ + nbytes;
6665 /* tp now points to the new output record; go back and patch the
6666 * second parameter (off2) to point to the new record.
6668 temp = (unsigned int)tp - ((unsigned int) outp->data);
6669 outWctp[3] = (unsigned char) (temp & 0xff);
6670 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6671 outWctp[2] = 0; /* padding */
6672 outWctp[1] = inp->inCom; /* next opcode */
6674 /* finally, setup for the next iteration */
6677 } /* while loop over all requests in the packet */
6679 /* done logging out, turn off logging-out flag */
6680 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6681 vcp->justLoggedOut = NULL;
6684 free(loggedOutName);
6685 loggedOutName = NULL;
6686 smb_ReleaseUID(loggedOutUserp);
6687 loggedOutUserp = NULL;
6691 /* now send the output packet, and return */
6693 smb_SendPacket(vcp, outp);
6694 thrd_Decrement(&ongoingOps);
6696 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6697 if (active_vcp != vcp) {
6699 smb_ReleaseVC(active_vcp);
6701 "Replacing active_vcp %x with %x", active_vcp, vcp);
6706 last_msg_time = GetCurrentTime();
6707 } else if (active_vcp == vcp) {
6708 smb_ReleaseVC(active_vcp);
6716 /* Wait for Netbios() calls to return, and make the results available to server
6717 * threads. Note that server threads can't wait on the NCBevents array
6718 * themselves, because NCB events are manual-reset, and the servers would race
6719 * each other to reset them.
6721 void smb_ClientWaiter(void *parmp)
6726 while (smbShutdownFlag == 0) {
6727 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6729 if (code == WAIT_OBJECT_0)
6732 /* error checking */
6733 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6735 int abandonIdx = code - WAIT_ABANDONED_0;
6736 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6739 if (code == WAIT_IO_COMPLETION)
6741 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6745 if (code == WAIT_TIMEOUT)
6747 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6750 if (code == WAIT_FAILED)
6752 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6755 idx = code - WAIT_OBJECT_0;
6757 /* check idx range! */
6758 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6760 /* this is fatal - log as much as possible */
6761 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6765 thrd_ResetEvent(NCBevents[idx]);
6766 thrd_SetEvent(NCBreturns[0][idx]);
6772 * Try to have one NCBRECV request waiting for every live session. Not more
6773 * than one, because if there is more than one, it's hard to handle Write Raw.
6775 void smb_ServerWaiter(void *parmp)
6778 int idx_session, idx_NCB;
6784 while (smbShutdownFlag == 0) {
6786 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6788 if (code == WAIT_OBJECT_0)
6791 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6793 int abandonIdx = code - WAIT_ABANDONED_0;
6794 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6797 if (code == WAIT_IO_COMPLETION)
6799 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6803 if (code == WAIT_TIMEOUT)
6805 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6808 if (code == WAIT_FAILED)
6810 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6813 idx_session = code - WAIT_OBJECT_0;
6815 /* check idx range! */
6816 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6818 /* this is fatal - log as much as possible */
6819 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6825 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6827 if (code == WAIT_OBJECT_0) {
6828 if (smbShutdownFlag == 1)
6834 /* error checking */
6835 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6837 int abandonIdx = code - WAIT_ABANDONED_0;
6838 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6841 if (code == WAIT_IO_COMPLETION)
6843 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6847 if (code == WAIT_TIMEOUT)
6849 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6852 if (code == WAIT_FAILED)
6854 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6857 idx_NCB = code - WAIT_OBJECT_0;
6859 /* check idx range! */
6860 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6862 /* this is fatal - log as much as possible */
6863 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6867 /* Link them together */
6868 NCBsessions[idx_NCB] = idx_session;
6871 ncbp = NCBs[idx_NCB];
6872 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6873 ncbp->ncb_command = NCBRECV | ASYNCH;
6874 ncbp->ncb_lana_num = lanas[idx_session];
6876 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6877 ncbp->ncb_event = NCBevents[idx_NCB];
6878 ncbp->ncb_length = SMB_PACKETSIZE;
6881 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6882 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6883 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6884 ncbp->ncb_length = SMB_PACKETSIZE;
6885 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6886 Netbios(ncbp, dos_ncb);
6892 * The top level loop for handling SMB request messages. Each server thread
6893 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6894 * NCB and buffer for the incoming request are loaned to us.
6896 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6897 * to immediately send a request for the rest of the data. This must come
6898 * before any other traffic for that session, so we delay setting the session
6899 * event until that data has come in.
6901 void smb_Server(VOID *parmp)
6903 int myIdx = (int) parmp;
6907 smb_packet_t *outbufp;
6909 int idx_NCB, idx_session;
6911 smb_vc_t *vcp = NULL;
6918 outbufp = GetPacket();
6919 outbufp->ncbp = outncbp;
6922 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6925 /* terminate silently if shutdown flag is set */
6926 if (code == WAIT_OBJECT_0) {
6927 if (smbShutdownFlag == 1) {
6928 thrd_SetEvent(smb_ServerShutdown[myIdx]);
6934 /* error checking */
6935 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6937 int abandonIdx = code - WAIT_ABANDONED_0;
6938 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6941 if (code == WAIT_IO_COMPLETION)
6943 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6947 if (code == WAIT_TIMEOUT)
6949 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6952 if (code == WAIT_FAILED)
6954 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6957 idx_NCB = code - WAIT_OBJECT_0;
6959 /* check idx range! */
6960 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6962 /* this is fatal - log as much as possible */
6963 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6967 ncbp = NCBs[idx_NCB];
6969 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6971 idx_session = NCBsessions[idx_NCB];
6972 rc = ncbp->ncb_retcode;
6974 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
6977 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
6980 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
6983 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
6986 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
6989 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
6992 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lsn %d session number out of range", ncbp->ncb_lsn, idx_session);
6995 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
6998 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lsn %d session closed", ncbp->ncb_lsn, idx_session);
7001 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7004 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7007 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7010 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7013 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local lsn %d session table full", ncbp->ncb_lsn, idx_session);
7016 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote lsn %d session table full", ncbp->ncb_lsn, idx_session);
7019 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7022 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7025 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7028 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7031 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7034 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lsn %d session ended abnormally", ncbp->ncb_lsn, idx_session);
7037 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7040 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7043 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7046 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7049 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7052 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7055 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7058 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7061 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7064 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7067 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7070 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7073 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7076 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7079 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7082 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7085 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7088 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7098 /* Can this happen? Or is it just my
7105 /* Client closed session */
7106 dead_sessions[idx_session] = TRUE;
7109 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7110 /* Should also release vcp. [done] 2004-05-11 jaltman
7112 * sanity check that all TID's are gone.
7114 * TODO: check if we could use LSNs[idx_session] instead,
7115 * also cleanup after dead vcp
7120 "dead_vcp already set, %x",
7122 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7124 "setting dead_vcp %x, user struct %x",
7128 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7130 if (vcp->justLoggedOut) {
7132 loggedOutTime = vcp->logoffTime;
7133 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7134 loggedOutUserp = vcp->justLoggedOut;
7135 lock_ObtainWrite(&smb_rctLock);
7136 loggedOutUserp->refCount++;
7137 lock_ReleaseWrite(&smb_rctLock);
7143 /* Treat as transient error */
7150 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7151 sprintf(s, "SMB message incomplete, length %d",
7154 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
7156 ncbp->ncb_length, ptbuf,
7158 DeregisterEventSource(h);
7161 "dispatch smb recv failed, message incomplete, ncb_length %d",
7164 "SMB message incomplete, "
7165 "length %d", ncbp->ncb_length);
7168 * We used to discard the packet.
7169 * Instead, try handling it normally.
7177 /* A weird error code. Log it, sleep, and
7179 if (vcp && vcp->errorCount++ > 3) {
7180 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7181 dead_sessions[idx_session] = TRUE;
7185 thrd_SetEvent(SessionEvents[idx_session]);
7190 /* Success, so now dispatch on all the data in the packet */
7192 smb_concurrentCalls++;
7193 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7194 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7198 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7200 * If at this point vcp is NULL (implies that packet was invalid)
7201 * then we are in big trouble. This means either :
7202 * a) we have the wrong NCB.
7203 * b) Netbios screwed up the call.
7204 * Obviously this implies that
7205 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7206 * lanas[idx_session] != ncbp->ncb_lana_num )
7207 * Either way, we can't do anything with this packet.
7208 * Log, sleep and resume.
7217 "LSNs[idx_session]=[%d],"
7218 "lanas[idx_session]=[%d],"
7219 "ncbp->ncb_lsn=[%d],"
7220 "ncbp->ncb_lana_num=[%d]",
7224 ncbp->ncb_lana_num);
7228 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7230 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
7231 DeregisterEventSource(h);
7234 /* Also log in the trace log. */
7235 osi_Log4(smb_logp, "Server: BAD VCP!"
7236 "LSNs[idx_session]=[%d],"
7237 "lanas[idx_session]=[%d],"
7238 "ncbp->ncb_lsn=[%d],"
7239 "ncbp->ncb_lana_num=[%d]",
7243 ncbp->ncb_lana_num);
7245 /* thrd_Sleep(1000); Don't bother sleeping */
7246 thrd_SetEvent(SessionEvents[idx_session]);
7247 smb_concurrentCalls--;
7252 vcp->errorCount = 0;
7253 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7255 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7256 /* copy whole packet to virtual memory */
7257 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7259 bufp->dos_pkt / 16, bufp);*/
7261 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7263 smbp = (smb_t *)bufp->data;
7266 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7270 if (smbp->com == 0x1d) {
7271 /* Special handling for Write Raw */
7272 raw_write_cont_t rwc;
7273 EVENT_HANDLE rwevent;
7274 char eventName[MAX_PATH];
7276 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7277 if (rwc.code == 0) {
7278 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7279 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7280 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7281 ncbp->ncb_command = NCBRECV | ASYNCH;
7282 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7283 ncbp->ncb_lana_num = vcp->lana;
7284 ncbp->ncb_buffer = rwc.buf;
7285 ncbp->ncb_length = 65535;
7286 ncbp->ncb_event = rwevent;
7290 Netbios(ncbp, dos_ncb);
7292 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7293 thrd_CloseHandle(rwevent);
7295 thrd_SetEvent(SessionEvents[idx_session]);
7297 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7299 else if (smbp->com == 0xa0) {
7301 * Serialize the handling for NT Transact
7304 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7305 thrd_SetEvent(SessionEvents[idx_session]);
7307 thrd_SetEvent(SessionEvents[idx_session]);
7308 /* TODO: what else needs to be serialized? */
7309 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7311 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7313 __except( smb_ServerExceptionFilter() ) {
7317 smb_concurrentCalls--;
7320 thrd_SetEvent(NCBavails[idx_NCB]);
7327 * Exception filter for the server threads. If an exception occurs in the
7328 * dispatch routines, which is where exceptions are most common, then do a
7329 * force trace and give control to upstream exception handlers. Useful for
7332 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7333 DWORD smb_ServerExceptionFilter(void) {
7334 /* While this is not the best time to do a trace, if it succeeds, then
7335 * we have a trace (assuming tracing was enabled). Otherwise, this should
7336 * throw a second exception.
7341 ptbuf[0] = "Unhandled exception forcing trace";
7343 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7345 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7346 DeregisterEventSource(h);
7349 afsd_ForceTrace(TRUE);
7350 buf_ForceTrace(TRUE);
7351 return EXCEPTION_CONTINUE_SEARCH;
7356 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7357 * If the number of server threads is M, and the number of live sessions is
7358 * N, then the number of NCB's in use at any time either waiting for, or
7359 * holding, received messages is M + N, so that is how many NCB's get created.
7361 void InitNCBslot(int idx)
7363 struct smb_packet *bufp;
7364 EVENT_HANDLE retHandle;
7366 char eventName[MAX_PATH];
7368 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7370 NCBs[idx] = GetNCB();
7371 sprintf(eventName,"NCBavails[%d]", idx);
7372 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7373 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7374 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7376 sprintf(eventName,"NCBevents[%d]", idx);
7377 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7378 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7379 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7381 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7382 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7383 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7384 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7385 for (i=0; i<smb_NumServerThreads; i++)
7386 NCBreturns[i][idx] = retHandle;
7388 bufp->spacep = cm_GetSpace();
7392 /* listen for new connections */
7393 void smb_Listener(void *parmp)
7401 char rname[NCBNAMSZ+1];
7402 char cname[MAX_COMPUTERNAME_LENGTH+1];
7403 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7408 int lana = (int) parmp;
7412 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7415 /* retrieve computer name */
7416 GetComputerName(cname, &cnamelen);
7420 memset(ncbp, 0, sizeof(NCB));
7423 ncbp->ncb_command = NCBLISTEN;
7424 ncbp->ncb_rto = 0; /* No receive timeout */
7425 ncbp->ncb_sto = 0; /* No send timeout */
7427 /* pad out with spaces instead of null termination */
7428 len = strlen(smb_localNamep);
7429 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7430 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7432 strcpy(ncbp->ncb_callname, "*");
7433 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7435 ncbp->ncb_lana_num = lana;
7438 code = Netbios(ncbp);
7440 code = Netbios(ncbp, dos_ncb);
7449 /* terminate silently if shutdown flag is set */
7450 if (smbShutdownFlag == 1) {
7459 "NCBLISTEN lana=%d failed with code %d",
7460 ncbp->ncb_lana_num, code);
7462 "Client exiting due to network failure. Please restart client.\n");
7466 "Client exiting due to network failure. Please restart client.\n"
7467 "NCBLISTEN lana=%d failed with code %d",
7468 ncbp->ncb_lana_num, code);
7470 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7471 MB_OK|MB_SERVICE_NOTIFICATION);
7472 osi_assert(tbuffer);
7475 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7476 ncbp->ncb_lana_num, code);
7477 fprintf(stderr, "\nClient exiting due to network failure "
7478 "(possibly due to power-saving mode)\n");
7479 fprintf(stderr, "Please restart client.\n");
7480 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7484 /* check for remote conns */
7485 /* first get remote name and insert null terminator */
7486 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7487 for (i=NCBNAMSZ; i>0; i--) {
7488 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7494 /* compare with local name */
7496 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7497 flags |= SMB_VCFLAG_REMOTECONN;
7499 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7501 lock_ObtainMutex(&smb_ListenerLock);
7503 /* New generation */
7506 /* Log session startup */
7508 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7510 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7511 #endif /* NOTSERVICE */
7512 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7513 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7515 if (reportSessionStartups) {
7521 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7522 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7524 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7526 DeregisterEventSource(h);
7529 fprintf(stderr, "%s: New session %d starting from host %s\n",
7530 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7534 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7535 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7538 /* now ncbp->ncb_lsn is the connection ID */
7539 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7540 vcp->flags |= flags;
7541 strcpy(vcp->rname, rname);
7544 /* Allocate slot in session arrays */
7545 /* Re-use dead session if possible, otherwise add one more */
7546 /* But don't look at session[0], it is reserved */
7547 for (i = 1; i < numSessions; i++) {
7548 if (dead_sessions[i]) {
7549 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7550 dead_sessions[i] = FALSE;
7555 /* assert that we do not exceed the maximum number of sessions or NCBs.
7556 * we should probably want to wait for a session to be freed in case
7560 osi_assert(i < Sessionmax - 1);
7561 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7563 LSNs[i] = ncbp->ncb_lsn;
7564 lanas[i] = ncbp->ncb_lana_num;
7566 if (i == numSessions) {
7567 /* Add new NCB for new session */
7568 char eventName[MAX_PATH];
7570 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7572 InitNCBslot(numNCBs);
7574 thrd_SetEvent(NCBavails[0]);
7575 thrd_SetEvent(NCBevents[0]);
7576 for (j = 0; j < smb_NumServerThreads; j++)
7577 thrd_SetEvent(NCBreturns[j][0]);
7578 /* Also add new session event */
7579 sprintf(eventName, "SessionEvents[%d]", i);
7580 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7581 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7582 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7584 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7585 thrd_SetEvent(SessionEvents[0]);
7587 thrd_SetEvent(SessionEvents[i]);
7590 lock_ReleaseMutex(&smb_ListenerLock);
7592 } /* dispatch while loop */
7595 /* initialize Netbios */
7596 void smb_NetbiosInit()
7602 int i, lana, code, l;
7604 int delname_tried=0;
7607 OSVERSIONINFO Version;
7609 /* Get the version of Windows */
7610 memset(&Version, 0x00, sizeof(Version));
7611 Version.dwOSVersionInfoSize = sizeof(Version);
7612 GetVersionEx(&Version);
7614 /* setup the NCB system */
7617 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7621 if (smb_LANadapter == -1) {
7622 ncbp->ncb_command = NCBENUM;
7623 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7624 ncbp->ncb_length = sizeof(lana_list);
7625 code = Netbios(ncbp);
7627 osi_Log1(smb_logp, "Netbios NCBENUM error code %d", code);
7628 osi_panic(s, __FILE__, __LINE__);
7632 lana_list.length = 1;
7633 lana_list.lana[0] = smb_LANadapter;
7636 for (i = 0; i < lana_list.length; i++) {
7637 /* reset the adaptor: in Win32, this is required for every process, and
7638 * acts as an init call, not as a real hardware reset.
7640 ncbp->ncb_command = NCBRESET;
7641 ncbp->ncb_callname[0] = 100;
7642 ncbp->ncb_callname[2] = 100;
7643 ncbp->ncb_lana_num = lana_list.lana[i];
7644 code = Netbios(ncbp);
7646 code = ncbp->ncb_retcode;
7648 osi_Log2(smb_logp, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7649 lana_list.lana[i] = 255; /* invalid lana */
7651 osi_Log1(smb_logp, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7655 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7656 we will just fake the LANA list */
7657 if (smb_LANadapter == -1) {
7658 for (i = 0; i < 8; i++)
7659 lana_list.lana[i] = i;
7660 lana_list.length = 8;
7663 lana_list.length = 1;
7664 lana_list.lana[0] = smb_LANadapter;
7668 /* and declare our name so we can receive connections */
7669 memset(ncbp, 0, sizeof(*ncbp));
7670 len=lstrlen(smb_localNamep);
7671 memset(smb_sharename,' ',NCBNAMSZ);
7672 memcpy(smb_sharename,smb_localNamep,len);
7673 osi_Log1(smb_logp, "lana_list.length %d", lana_list.length);
7675 /* Keep the name so we can unregister it later */
7676 for (l = 0; l < lana_list.length; l++) {
7677 lana = lana_list.lana[l];
7679 ncbp->ncb_command = NCBADDNAME;
7680 ncbp->ncb_lana_num = lana;
7681 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7683 code = Netbios(ncbp);
7685 code = Netbios(ncbp, dos_ncb);
7688 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7689 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7691 char name[NCBNAMSZ+1];
7693 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7694 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7697 if (code == 0) code = ncbp->ncb_retcode;
7699 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7701 /* we only use one LANA with djgpp */
7702 lana_list.lana[0] = lana;
7703 lana_list.length = 1;
7707 osi_Log2(smb_logp, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7708 if (code == NRC_BRIDGE) { /* invalid LANA num */
7709 lana_list.lana[l] = 255;
7712 else if (code == NRC_DUPNAME) {
7713 osi_Log0(smb_logp, "Name already exists; try to delete it");
7714 memset(ncbp, 0, sizeof(*ncbp));
7715 ncbp->ncb_command = NCBDELNAME;
7716 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7717 ncbp->ncb_lana_num = lana;
7719 code = Netbios(ncbp);
7721 code = Netbios(ncbp, dos_ncb);
7724 code = ncbp->ncb_retcode;
7726 osi_Log2(smb_logp, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7728 if (code != 0 || delname_tried) {
7729 lana_list.lana[l] = 255;
7731 else if (code == 0) {
7732 if (!delname_tried) {
7740 osi_Log2(smb_logp, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7741 lana_list.lana[l] = 255; /* invalid lana */
7742 osi_panic(s, __FILE__, __LINE__);
7746 lana_found = 1; /* at least one worked */
7753 osi_assert(lana_list.length >= 0);
7755 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
7758 /* we're done with the NCB now */
7762 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7779 EVENT_HANDLE retHandle;
7780 char eventName[MAX_PATH];
7783 smb_MBfunc = aMBfunc;
7787 smb_LANadapter = LANadapt;
7789 /* Initialize smb_localZero */
7790 myTime.tm_isdst = -1; /* compute whether on DST or not */
7791 myTime.tm_year = 70;
7797 smb_localZero = mktime(&myTime);
7799 /* Initialize kludge-GMT */
7800 smb_CalculateNowTZ();
7802 #ifdef AFS_FREELANCE_CLIENT
7803 /* Make sure the root.afs volume has the correct time */
7804 cm_noteLocalMountPointChange();
7807 /* initialize the remote debugging log */
7810 /* remember the name */
7811 len = strlen(snamep);
7812 smb_localNamep = malloc(len+1);
7813 strcpy(smb_localNamep, snamep);
7814 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7816 /* and the global lock */
7817 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7818 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7820 /* Raw I/O data structures */
7821 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7823 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7825 /* 4 Raw I/O buffers */
7827 smb_RawBufs = calloc(65536,1);
7828 *((char **)smb_RawBufs) = NULL;
7829 for (i=0; i<3; i++) {
7830 char *rawBuf = calloc(65536,1);
7831 *((char **)rawBuf) = smb_RawBufs;
7832 smb_RawBufs = rawBuf;
7835 npar = 65536 >> 4; /* number of paragraphs */
7836 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7838 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7840 osi_panic("",__FILE__,__LINE__);
7843 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7846 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7848 _farpokel(_dos_ds, smb_RawBufs, NULL);
7849 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7850 npar = 65536 >> 4; /* number of paragraphs */
7851 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7853 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7855 osi_panic("",__FILE__,__LINE__);
7858 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7861 rawBuf = (seg * 16) + 0; /* DOS physical address */
7862 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7863 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7864 smb_RawBufs = rawBuf;
7868 /* global free lists */
7869 smb_ncbFreeListp = NULL;
7870 smb_packetFreeListp = NULL;
7874 /* Initialize listener and server structures */
7876 memset(dead_sessions, 0, sizeof(dead_sessions));
7877 sprintf(eventName, "SessionEvents[0]");
7878 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7879 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7880 afsi_log("Event Object Already Exists: %s", eventName);
7882 smb_NumServerThreads = nThreads;
7883 sprintf(eventName, "NCBavails[0]");
7884 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7885 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7886 afsi_log("Event Object Already Exists: %s", eventName);
7887 sprintf(eventName, "NCBevents[0]");
7888 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7889 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7890 afsi_log("Event Object Already Exists: %s", eventName);
7891 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
7892 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7893 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7894 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7895 afsi_log("Event Object Already Exists: %s", eventName);
7896 for (i = 0; i < smb_NumServerThreads; i++) {
7897 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7898 NCBreturns[i][0] = retHandle;
7901 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
7902 for (i = 0; i < smb_NumServerThreads; i++) {
7903 sprintf(eventName, "smb_ServerShutdown[%d]", i);
7904 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7905 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7906 afsi_log("Event Object Already Exists: %s", eventName);
7909 numNCBs = smb_NumServerThreads + 1;
7911 /* Initialize dispatch table */
7912 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7913 /* Prepare the table for unknown operations */
7914 for(i=0; i<= SMB_NOPCODES; i++) {
7915 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7917 /* Fill in the ones we do know */
7918 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7919 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7920 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7921 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7922 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7923 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7924 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7925 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7926 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7927 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7928 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7929 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7930 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7931 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7932 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7933 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7934 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7935 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7936 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7937 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7938 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7939 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7940 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7941 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7942 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7943 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7944 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7945 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7946 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7947 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
7948 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7949 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
7950 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
7951 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
7952 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7953 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
7954 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
7955 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
7956 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
7957 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
7958 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7959 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
7960 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7961 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
7962 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
7963 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
7964 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
7965 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
7966 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
7967 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
7968 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
7969 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
7970 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
7971 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
7972 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
7973 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
7974 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
7975 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
7976 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
7977 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
7978 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
7979 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
7980 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
7981 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7982 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
7983 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
7984 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
7985 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
7986 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
7987 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
7988 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
7989 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
7991 /* setup tran 2 dispatch table */
7992 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
7993 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
7994 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
7995 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
7996 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
7997 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
7998 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
7999 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8000 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8001 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8002 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8003 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8004 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8005 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8006 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8007 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8008 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8010 /* setup the rap dispatch table */
8011 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8012 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8013 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8014 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8015 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8019 /* if we are doing SMB authentication we have register outselves as a logon process */
8020 if (smb_authType != SMB_AUTH_NONE) {
8021 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8022 LSA_STRING afsProcessName;
8023 LSA_OPERATIONAL_MODE dummy; /*junk*/
8025 afsProcessName.Buffer = "OpenAFSClientDaemon";
8026 afsProcessName.Length = strlen(afsProcessName.Buffer);
8027 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8029 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8031 if (nts == STATUS_SUCCESS) {
8032 LSA_STRING packageName;
8033 /* we are registered. Find out the security package id */
8034 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8035 packageName.Length = strlen(packageName.Buffer);
8036 packageName.MaximumLength = packageName.Length + 1;
8037 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8038 if (nts == STATUS_SUCCESS) {
8040 /* BEGIN - This code is from Larry */
8041 PVOID pResponse = NULL;
8042 ULONG cbResponse = 0;
8043 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8045 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8046 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8047 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8048 OptionsRequest.DisableOptions = FALSE;
8050 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8053 sizeof(OptionsRequest),
8059 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8060 osi_Log2(smb_logp,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8062 OutputDebugString("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8065 osi_Log0(smb_logp,"MsV1_0SetProcessOption success");
8066 OutputDebugString("MsV1_0SetProcessOption success");
8068 /* END - code from Larry */
8069 #endif /* LARRY_HACK */
8071 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8072 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
8073 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8075 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
8078 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
8081 if (nts != STATUS_SUCCESS) {
8082 /* something went wrong. We report the error and revert back to no authentication
8083 because we can't perform any auth requests without a successful lsa handle
8084 or sec package id. */
8085 afsi_log("Reverting to NO SMB AUTH");
8086 smb_authType = SMB_AUTH_NONE;
8089 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8090 * time prevents the failure of authentication when logged into Windows with an
8091 * external Kerberos principal mapped to a local account.
8093 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8094 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8095 * then the only option is NTLMSSP anyway; so just fallback.
8100 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8101 if (secBlobLength == 0) {
8102 smb_authType = SMB_AUTH_NTLM;
8103 afsi_log("Reverting to SMB AUTH NTLM");
8112 /* Now get ourselves a domain name. */
8113 /* For now we are using the local computer name as the domain name.
8114 * It is actually the domain for local logins, and we are acting as
8115 * a local SMB server.
8117 bufsize = sizeof(smb_ServerDomainName) - 1;
8118 GetComputerName(smb_ServerDomainName, &bufsize);
8119 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8120 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8123 /* Start listeners, waiters, servers, and daemons */
8125 for (i = 0; i < lana_list.length; i++) {
8126 if (lana_list.lana[i] == 255)
8128 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8129 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8130 osi_assert(phandle != NULL);
8131 thrd_CloseHandle(phandle);
8135 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8136 NULL, 0, &lpid, "smb_ClientWaiter");
8137 osi_assert(phandle != NULL);
8138 thrd_CloseHandle(phandle);
8141 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8142 NULL, 0, &lpid, "smb_ServerWaiter");
8143 osi_assert(phandle != NULL);
8144 thrd_CloseHandle(phandle);
8146 for (i=0; i<smb_NumServerThreads; i++) {
8147 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8148 (void *) i, 0, &lpid, "smb_Server");
8149 osi_assert(phandle != NULL);
8150 thrd_CloseHandle(phandle);
8153 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8154 NULL, 0, &lpid, "smb_Daemon");
8155 osi_assert(phandle != NULL);
8156 thrd_CloseHandle(phandle);
8158 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8159 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8160 osi_assert(phandle != NULL);
8161 thrd_CloseHandle(phandle);
8170 void smb_Shutdown(void)
8180 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8182 /* setup the NCB system */
8185 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8188 /* Block new sessions by setting shutdown flag */
8189 smbShutdownFlag = 1;
8191 /* Hang up all sessions */
8192 memset((char *)ncbp, 0, sizeof(NCB));
8193 for (i = 1; i < numSessions; i++)
8195 if (dead_sessions[i])
8198 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8199 ncbp->ncb_command = NCBHANGUP;
8200 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8201 ncbp->ncb_lsn = LSNs[i];
8203 code = Netbios(ncbp);
8205 code = Netbios(ncbp, dos_ncb);
8207 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8208 if (code == 0) code = ncbp->ncb_retcode;
8210 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8211 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8215 /* Trigger the shutdown of all SMB threads */
8216 for (i = 0; i < smb_NumServerThreads; i++)
8217 thrd_SetEvent(NCBreturns[i][0]);
8219 thrd_SetEvent(NCBevents[0]);
8220 thrd_SetEvent(SessionEvents[0]);
8221 thrd_SetEvent(NCBavails[0]);
8223 for (i = 0;i < smb_NumServerThreads; i++) {
8224 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8225 if (code == WAIT_OBJECT_0) {
8228 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8229 thrd_SetEvent(NCBreturns[i--][0]);
8233 /* Delete Netbios name */
8234 memset((char *)ncbp, 0, sizeof(NCB));
8235 for (i = 0; i < lana_list.length; i++) {
8236 if (lana_list.lana[i] == 255) continue;
8237 ncbp->ncb_command = NCBDELNAME;
8238 ncbp->ncb_lana_num = lana_list.lana[i];
8239 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8241 code = Netbios(ncbp);
8243 code = Netbios(ncbp, dos_ncb);
8246 code = ncbp->ncb_retcode;
8248 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8249 ncbp->ncb_lana_num, code);
8254 /* Release the reference counts held by the VCs */
8255 lock_ObtainWrite(&smb_rctLock);
8256 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8261 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8263 if (fidp->scp != NULL) {
8266 lock_ObtainMutex(&fidp->mx);
8267 if (fidp->scp != NULL) {
8270 cm_ReleaseSCache(scp);
8272 lock_ReleaseMutex(&fidp->mx);
8276 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8278 smb_ReleaseVCNoLock(tidp->vcp);
8280 cm_user_t *userp = tidp->userp;
8282 lock_ReleaseWrite(&smb_rctLock);
8283 cm_ReleaseUser(userp);
8284 lock_ObtainWrite(&smb_rctLock);
8288 lock_ReleaseWrite(&smb_rctLock);
8291 /* Get the UNC \\<servername>\<sharename> prefix. */
8292 char *smb_GetSharename()
8296 /* Make sure we have been properly initialized. */
8297 if (smb_localNamep == NULL)
8300 /* Allocate space for \\<servername>\<sharename>, plus the
8303 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8304 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8310 void smb_LogPacket(smb_packet_t *packet)
8313 unsigned length, paramlen, datalen, i, j;
8315 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8317 if (!packet) return;
8319 osi_Log0(smb_logp, "*** SMB packet dump ***");
8321 vp = (BYTE *) packet->data;
8323 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8324 length = paramlen + 2 + datalen;
8327 for (i=0;i < length; i+=16)
8329 memset( buf, ' ', 80 );
8334 buf[strlen(buf)] = ' ';
8336 cp = (BYTE*) buf + 7;
8338 for (j=0;j < 16 && (i+j)<length; j++)
8340 *(cp++) = hex[vp[i+j] >> 4];
8341 *(cp++) = hex[vp[i+j] & 0xf];
8351 for (j=0;j < 16 && (i+j)<length;j++)
8353 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8364 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8367 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8369 #endif /* LOG_PACKET */
8372 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8380 lock_ObtainRead(&smb_rctLock);
8382 sprintf(output, "begin dumping smb_vc_t\n");
8383 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8385 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8389 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8390 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8391 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8393 sprintf(output, "begin dumping smb_fid_t\n");
8394 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8396 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8398 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",
8399 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8400 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8401 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8402 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8405 sprintf(output, "done dumping smb_fid_t\n");
8406 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8409 sprintf(output, "done dumping smb_vc_t\n");
8410 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8413 lock_ReleaseRead(&smb_rctLock);