2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
17 #include <sys/timeb.h>
30 #include <WINNT\afsreg.h>
33 #include "lanahelper.h"
35 /* These characters are illegal in Windows filenames */
36 static char *illegalChars = "\\/:*?\"<>|";
37 BOOL isWindows2000 = FALSE;
39 smb_vc_t *dead_vcp = NULL;
40 smb_vc_t *active_vcp = NULL;
42 /* TODO; logout mechanism needs to be thread-safe */
43 char *loggedOutName = NULL;
44 smb_user_t *loggedOutUserp = NULL;
47 int smbShutdownFlag = 0;
49 int smb_LogoffTokenTransfer;
50 time_t smb_LogoffTransferTimeout;
52 int smb_StoreAnsiFilenames = 0;
54 DWORD last_msg_time = 0;
58 unsigned int sessionGen = 0;
60 extern void afsi_log(char *pattern, ...);
61 extern HANDLE afsi_file;
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t smb_ListenerLock;
72 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
75 long smb_maxObsConcurrentCalls=0;
76 long smb_concurrentCalls=0;
78 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
80 smb_packet_t *smb_packetFreeListp;
81 smb_ncb_t *smb_ncbFreeListp;
83 int smb_NumServerThreads;
85 int numNCBs, numSessions, numVCs;
87 int smb_maxVCPerServer;
88 int smb_maxMpxRequests;
90 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
92 ULONG smb_lsaSecPackage;
93 LSA_STRING smb_lsaLogonOrigin;
95 #define NCBmax MAXIMUM_WAIT_OBJECTS
96 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
97 EVENT_HANDLE **NCBreturns;
98 EVENT_HANDLE **NCBShutdown;
99 EVENT_HANDLE *smb_ServerShutdown;
100 DWORD NCBsessions[NCBmax];
102 struct smb_packet *bufs[NCBmax];
104 #define Sessionmax MAXIMUM_WAIT_OBJECTS - 4
105 EVENT_HANDLE SessionEvents[Sessionmax];
106 unsigned short LSNs[Sessionmax];
107 int lanas[Sessionmax];
108 BOOL dead_sessions[Sessionmax];
112 osi_mutex_t smb_RawBufLock;
114 #define SMB_RAW_BUFS 4
116 int smb_RawBufSel[SMB_RAW_BUFS];
121 #define SMB_MASKFLAG_TILDE 1
122 #define SMB_MASKFLAG_CASEFOLD 2
124 #define RAWTIMEOUT INFINITE
127 typedef struct raw_write_cont {
140 /* dir search stuff */
141 long smb_dirSearchCounter = 1;
142 smb_dirSearch_t *smb_firstDirSearchp;
143 smb_dirSearch_t *smb_lastDirSearchp;
145 /* hide dot files? */
146 int smb_hideDotFiles;
148 /* global state about V3 protocols */
149 int smb_useV3; /* try to negotiate V3 */
152 static showErrors = 1;
153 /* MessageBox or something like it */
154 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
155 extern HANDLE WaitToTerminate;
159 * Time in Unix format of midnight, 1/1/1970 local time.
160 * When added to dosUTime, gives Unix (AFS) time.
162 time_t smb_localZero = 0;
164 /* Time difference for converting to kludge-GMT */
167 char *smb_localNamep = NULL;
169 smb_vc_t *smb_allVCsp;
171 smb_username_t *usernamesp = NULL;
173 smb_waitingLock_t *smb_allWaitingLocks;
176 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
177 NCB *ncbp, raw_write_cont_t *rwcp);
178 void smb_NetbiosInit();
180 #ifndef AFS_WIN95_ENV
181 DWORD smb_ServerExceptionFilter(void);
184 extern char cm_HostName[];
185 extern char cm_confDir[];
189 #define LPTSTR char *
190 #define GetComputerName(str, sizep) \
191 strcpy((str), cm_HostName); \
192 *(sizep) = strlen(cm_HostName)
196 void smb_LogPacket(smb_packet_t *packet);
197 #endif /* LOG_PACKET */
199 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
200 int smb_ServerDomainNameLength = 0;
201 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
202 int smb_ServerOSLength = sizeof(smb_ServerOS);
203 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
204 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
206 /* Faux server GUID. This is never checked. */
207 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
209 char * myCrt_Dispatch(int i)
214 return "(00)ReceiveCoreMakeDir";
216 return "(01)ReceiveCoreRemoveDir";
218 return "(02)ReceiveCoreOpen";
220 return "(03)ReceiveCoreCreate";
222 return "(04)ReceiveCoreClose";
224 return "(05)ReceiveCoreFlush";
226 return "(06)ReceiveCoreUnlink";
228 return "(07)ReceiveCoreRename";
230 return "(08)ReceiveCoreGetFileAttributes";
232 return "(09)ReceiveCoreSetFileAttributes";
234 return "(0a)ReceiveCoreRead";
236 return "(0b)ReceiveCoreWrite";
238 return "(0c)ReceiveCoreLockRecord";
240 return "(0d)ReceiveCoreUnlockRecord";
242 return "(0e)SendCoreBadOp";
244 return "(0f)ReceiveCoreCreate";
246 return "(10)ReceiveCoreCheckPath";
248 return "(11)SendCoreBadOp";
250 return "(12)ReceiveCoreSeek";
252 return "(1a)ReceiveCoreReadRaw";
254 return "(1d)ReceiveCoreWriteRawDummy";
256 return "(22)ReceiveV3SetAttributes";
258 return "(23)ReceiveV3GetAttributes";
260 return "(24)ReceiveV3LockingX";
262 return "(25)ReceiveV3Trans";
264 return "(26)ReceiveV3Trans[aux]";
266 return "(29)SendCoreBadOp";
268 return "(2b)ReceiveCoreEcho";
270 return "(2d)ReceiveV3OpenX";
272 return "(2e)ReceiveV3ReadX";
274 return "(32)ReceiveV3Tran2A";
276 return "(33)ReceiveV3Tran2A[aux]";
278 return "(34)ReceiveV3FindClose";
280 return "(35)ReceiveV3FindNotifyClose";
282 return "(70)ReceiveCoreTreeConnect";
284 return "(71)ReceiveCoreTreeDisconnect";
286 return "(72)ReceiveNegotiate";
288 return "(73)ReceiveV3SessionSetupX";
290 return "(74)ReceiveV3UserLogoffX";
292 return "(75)ReceiveV3TreeConnectX";
294 return "(80)ReceiveCoreGetDiskAttributes";
296 return "(81)ReceiveCoreSearchDir";
300 return "(83)FindUnique";
302 return "(84)FindClose";
304 return "(A0)ReceiveNTTransact";
306 return "(A2)ReceiveNTCreateX";
308 return "(A4)ReceiveNTCancel";
310 return "(A5)ReceiveNTRename";
312 return "(C0)OpenPrintFile";
314 return "(C1)WritePrintFile";
316 return "(C2)ClosePrintFile";
318 return "(C3)GetPrintQueue";
320 return "(D8)ReadBulk";
322 return "(D9)WriteBulk";
324 return "(DA)WriteBulkData";
326 return "unknown SMB op";
330 char * myCrt_2Dispatch(int i)
335 return "unknown SMB op-2";
337 return "S(00)CreateFile";
339 return "S(01)FindFirst";
341 return "S(02)FindNext"; /* FindNext */
343 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
347 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
349 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
351 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
353 return "S(08)??_ReceiveTran2SetFileInfo";
355 return "S(09)??_ReceiveTran2FSCTL";
357 return "S(0a)_ReceiveTran2IOCTL";
359 return "S(0b)_ReceiveTran2FindNotifyFirst";
361 return "S(0c)_ReceiveTran2FindNotifyNext";
363 return "S(0d)_ReceiveTran2CreateDirectory";
365 return "S(0e)_ReceiveTran2SessionSetup";
367 return "S(10)_ReceiveTran2GetDfsReferral";
369 return "S(11)_ReceiveTran2ReportDfsInconsistency";
373 char * myCrt_RapDispatch(int i)
378 return "unknown RAP OP";
380 return "RAP(0)NetShareEnum";
382 return "RAP(1)NetShareGetInfo";
384 return "RAP(13)NetServerGetInfo";
386 return "RAP(63)NetWkStaGetInfo";
390 /* scache must be locked */
391 unsigned int smb_Attributes(cm_scache_t *scp)
395 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
396 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
397 scp->fileType == CM_SCACHETYPE_INVALID)
399 attrs = SMB_ATTR_DIRECTORY;
400 #ifdef SPECIAL_FOLDERS
401 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
402 #endif /* SPECIAL_FOLDERS */
403 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
404 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
409 * We used to mark a file RO if it was in an RO volume, but that
410 * turns out to be impolitic in NT. See defect 10007.
413 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
414 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
416 if ((scp->unixModeBits & 0222) == 0)
417 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
423 /* Check if the named file/dir is a dotfile/dotdir */
424 /* String pointed to by lastComp can have leading slashes, but otherwise should have
425 no other patch components */
426 unsigned int smb_IsDotFile(char *lastComp) {
429 /* skip over slashes */
430 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
435 /* nulls, curdir and parent dir doesn't count */
441 if(*(s+1) == '.' && !*(s + 2))
448 static int ExtractBits(WORD bits, short start, short len)
455 num = bits << (16 - end);
456 num = num >> ((16 - end) + start);
462 void ShowUnixTime(char *FuncName, time_t unixTime)
467 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
469 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
470 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
472 int day, month, year, sec, min, hour;
475 day = ExtractBits(wDate, 0, 5);
476 month = ExtractBits(wDate, 5, 4);
477 year = ExtractBits(wDate, 9, 7) + 1980;
479 sec = ExtractBits(wTime, 0, 5);
480 min = ExtractBits(wTime, 5, 6);
481 hour = ExtractBits(wTime, 11, 5);
483 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
484 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
490 /* Determine if we are observing daylight savings time */
491 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
493 TIME_ZONE_INFORMATION timeZoneInformation;
494 SYSTEMTIME utc, local, localDST;
496 /* Get the time zone info. NT uses this to calc if we are in DST. */
497 GetTimeZoneInformation(&timeZoneInformation);
499 /* Return the daylight bias */
500 *pDstBias = timeZoneInformation.DaylightBias;
502 /* Return the bias */
503 *pBias = timeZoneInformation.Bias;
505 /* Now determine if DST is being observed */
507 /* Get the UTC (GMT) time */
510 /* Convert UTC time to local time using the time zone info. If we are
511 observing DST, the calculated local time will include this.
513 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
515 /* Set the daylight bias to 0. The daylight bias is the amount of change
516 * in time that we use for daylight savings time. By setting this to 0
517 * we cause there to be no change in time during daylight savings time.
519 timeZoneInformation.DaylightBias = 0;
521 /* Convert the utc time to local time again, but this time without any
522 adjustment for daylight savings time.
524 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
526 /* If the two times are different, then it means that the localDST that
527 we calculated includes the daylight bias, and therefore we are
528 observing daylight savings time.
530 *pDST = localDST.wHour != local.wHour;
533 /* Determine if we are observing daylight savings time */
534 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
540 *pDstBias = -60; /* where can this be different? */
546 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
548 BOOL dst; /* Will be TRUE if observing DST */
549 LONG dstBias; /* Offset from local time if observing DST */
550 LONG bias; /* Offset from GMT for local time */
553 * This function will adjust the last write time to compensate
554 * for two bugs in the smb client:
556 * 1) During Daylight Savings Time, the LastWriteTime is ahead
557 * in time by the DaylightBias (ignoring the sign - the
558 * DaylightBias is always stored as a negative number). If
559 * the DaylightBias is -60, then the LastWriteTime will be
560 * ahead by 60 minutes.
562 * 2) If the local time zone is a positive offset from GMT, then
563 * the LastWriteTime will be the correct local time plus the
564 * Bias (ignoring the sign - a positive offset from GMT is
565 * always stored as a negative Bias). If the Bias is -120,
566 * then the LastWriteTime will be ahead by 120 minutes.
568 * These bugs can occur at the same time.
571 GetTimeZoneInfo(&dst, &dstBias, &bias);
573 /* First adjust for DST */
575 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
577 /* Now adjust for a positive offset from GMT (a negative bias). */
579 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
583 * Calculate the difference (in seconds) between local time and GMT.
584 * This enables us to convert file times to kludge-GMT.
590 struct tm gmt_tm, local_tm;
591 int days, hours, minutes, seconds;
594 gmt_tm = *(gmtime(&t));
595 local_tm = *(localtime(&t));
597 days = local_tm.tm_yday - gmt_tm.tm_yday;
598 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
600 /* There is a problem with DST immediately after the time change
601 * which may continue to exist until the machine is rebooted
603 - (local_tm.tm_isdst ? 1 : 0)
606 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
607 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
613 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
618 time_t ersatz_unixTime;
621 * Must use kludge-GMT instead of real GMT.
622 * kludge-GMT is computed by adding time zone difference to localtime.
625 * ltp = gmtime(&unixTime);
627 ersatz_unixTime = unixTime - smb_NowTZ;
628 ltp = localtime(&ersatz_unixTime);
630 /* if we fail, make up something */
633 localJunk.tm_year = 89 - 20;
634 localJunk.tm_mon = 4;
635 localJunk.tm_mday = 12;
636 localJunk.tm_hour = 0;
637 localJunk.tm_min = 0;
638 localJunk.tm_sec = 0;
641 stm.wYear = ltp->tm_year + 1900;
642 stm.wMonth = ltp->tm_mon + 1;
643 stm.wDayOfWeek = ltp->tm_wday;
644 stm.wDay = ltp->tm_mday;
645 stm.wHour = ltp->tm_hour;
646 stm.wMinute = ltp->tm_min;
647 stm.wSecond = ltp->tm_sec;
648 stm.wMilliseconds = 0;
650 SystemTimeToFileTime(&stm, largeTimep);
653 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
655 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
656 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
657 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
659 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
661 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
662 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
664 *ft = LargeIntegerMultiplyByLong(*ft, 60);
665 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
668 ut = ConvertLongToLargeInteger(unixTime);
669 ut = LargeIntegerMultiplyByLong(ut, 10000000);
670 *ft = LargeIntegerAdd(*ft, ut);
675 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
681 FileTimeToSystemTime(largeTimep, &stm);
683 lt.tm_year = stm.wYear - 1900;
684 lt.tm_mon = stm.wMonth - 1;
685 lt.tm_wday = stm.wDayOfWeek;
686 lt.tm_mday = stm.wDay;
687 lt.tm_hour = stm.wHour;
688 lt.tm_min = stm.wMinute;
689 lt.tm_sec = stm.wSecond;
692 save_timezone = _timezone;
693 _timezone += smb_NowTZ;
694 *unixTimep = mktime(<);
695 _timezone = save_timezone;
698 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
700 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
701 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
702 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
706 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
707 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
708 a = LargeIntegerMultiplyByLong(a, 60);
709 a = LargeIntegerMultiplyByLong(a, 10000000);
711 /* subtract it from ft */
712 a = LargeIntegerSubtract(*ft, a);
714 /* divide down to seconds */
715 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
719 void smb_SearchTimeFromUnixTime(time_t *dosTimep, time_t unixTime)
727 ltp = localtime((time_t*) &t);
729 /* if we fail, make up something */
732 localJunk.tm_year = 89 - 20;
733 localJunk.tm_mon = 4;
734 localJunk.tm_mday = 12;
735 localJunk.tm_hour = 0;
736 localJunk.tm_min = 0;
737 localJunk.tm_sec = 0;
740 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
741 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
742 *dosTimep = (dosDate<<16) | dosTime;
745 void smb_UnixTimeFromSearchTime(time_t *unixTimep, time_t searchTime)
747 unsigned short dosDate;
748 unsigned short dosTime;
751 dosDate = (unsigned short) (searchTime & 0xffff);
752 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
754 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
755 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
756 localTm.tm_mday = (dosDate) & 0x1f;
757 localTm.tm_hour = (dosTime>>11) & 0x1f;
758 localTm.tm_min = (dosTime >> 5) & 0x3f;
759 localTm.tm_sec = (dosTime & 0x1f) * 2;
760 localTm.tm_isdst = -1; /* compute whether DST in effect */
762 *unixTimep = mktime(&localTm);
765 void smb_DosUTimeFromUnixTime(time_t *dosUTimep, time_t unixTime)
767 *dosUTimep = unixTime - smb_localZero;
770 void smb_UnixTimeFromDosUTime(time_t *unixTimep, time_t dosTime)
773 *unixTimep = dosTime + smb_localZero;
775 /* dosTime seems to be already adjusted for GMT */
776 *unixTimep = dosTime;
780 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
784 lock_ObtainWrite(&smb_rctLock);
785 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
786 if (lsn == vcp->lsn && lana == vcp->lana) {
787 smb_HoldVCNoLock(vcp);
791 if (!vcp && (flags & SMB_FLAG_CREATE)) {
792 vcp = malloc(sizeof(*vcp));
793 memset(vcp, 0, sizeof(*vcp));
794 vcp->vcID = numVCs++;
798 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
799 vcp->nextp = smb_allVCsp;
801 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
806 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
807 /* We must obtain a challenge for extended auth
808 * in case the client negotiates smb v3
810 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
811 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
812 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
813 ULONG lsaRespSize = 0;
815 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
817 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
824 if (nts != STATUS_SUCCESS)
825 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
826 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
827 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
829 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
830 LsaFreeReturnBuffer(lsaResp);
833 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
835 lock_ReleaseWrite(&smb_rctLock);
839 int smb_IsStarMask(char *maskp)
844 for(i=0; i<11; i++) {
846 if (tc == '?' || tc == '*' || tc == '>') return 1;
851 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
853 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
855 osi_assert(vcp->refCount-- != 0);
861 void smb_ReleaseVC(smb_vc_t *vcp)
863 lock_ObtainWrite(&smb_rctLock);
864 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
866 osi_assert(vcp->refCount-- != 0);
870 lock_ReleaseWrite(&smb_rctLock);
873 void smb_HoldVCNoLock(smb_vc_t *vcp)
876 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
879 void smb_HoldVC(smb_vc_t *vcp)
881 lock_ObtainWrite(&smb_rctLock);
883 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
884 lock_ReleaseWrite(&smb_rctLock);
887 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
891 lock_ObtainWrite(&smb_rctLock);
892 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
893 if (tid == tidp->tid) {
898 if (!tidp && (flags & SMB_FLAG_CREATE)) {
899 tidp = malloc(sizeof(*tidp));
900 memset(tidp, 0, sizeof(*tidp));
901 tidp->nextp = vcp->tidsp;
904 smb_HoldVCNoLock(vcp);
906 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
909 lock_ReleaseWrite(&smb_rctLock);
913 void smb_ReleaseTID(smb_tid_t *tidp)
920 lock_ObtainWrite(&smb_rctLock);
921 osi_assert(tidp->refCount-- > 0);
922 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
923 ltpp = &tidp->vcp->tidsp;
924 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
928 osi_assert(tp != NULL);
930 lock_FinalizeMutex(&tidp->mx);
931 userp = tidp->userp; /* remember to drop ref later */
933 smb_ReleaseVCNoLock(tidp->vcp);
936 lock_ReleaseWrite(&smb_rctLock);
938 cm_ReleaseUser(userp);
941 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
943 smb_user_t *uidp = NULL;
945 lock_ObtainWrite(&smb_rctLock);
946 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
947 if (uid == uidp->userID) {
949 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
950 (int)vcp, uidp->userID,
951 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
955 if (!uidp && (flags & SMB_FLAG_CREATE)) {
956 uidp = malloc(sizeof(*uidp));
957 memset(uidp, 0, sizeof(*uidp));
958 uidp->nextp = vcp->usersp;
961 smb_HoldVCNoLock(vcp);
963 lock_InitializeMutex(&uidp->mx, "user_t mutex");
965 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 : ""));
967 lock_ReleaseWrite(&smb_rctLock);
971 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
973 smb_username_t *unp= NULL;
975 lock_ObtainWrite(&smb_rctLock);
976 for(unp = usernamesp; unp; unp = unp->nextp) {
977 if (stricmp(unp->name, usern) == 0 &&
978 stricmp(unp->machine, machine) == 0) {
983 if (!unp && (flags & SMB_FLAG_CREATE)) {
984 unp = malloc(sizeof(*unp));
985 memset(unp, 0, sizeof(*unp));
987 unp->nextp = usernamesp;
988 unp->name = strdup(usern);
989 unp->machine = strdup(machine);
991 lock_InitializeMutex(&unp->mx, "username_t mutex");
993 lock_ReleaseWrite(&smb_rctLock);
997 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
999 smb_user_t *uidp= NULL;
1001 lock_ObtainWrite(&smb_rctLock);
1002 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1005 if (stricmp(uidp->unp->name, usern) == 0) {
1007 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
1012 lock_ReleaseWrite(&smb_rctLock);
1015 void smb_ReleaseUID(smb_user_t *uidp)
1022 lock_ObtainWrite(&smb_rctLock);
1023 osi_assert(uidp->refCount-- > 0);
1024 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1025 lupp = &uidp->vcp->usersp;
1026 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1030 osi_assert(up != NULL);
1032 lock_FinalizeMutex(&uidp->mx);
1034 userp = uidp->unp->userp; /* avoid deadlock by releasing */
1035 uidp->unp->userp = NULL; /* after releasing the lock */
1037 smb_ReleaseVCNoLock(uidp->vcp);
1040 lock_ReleaseWrite(&smb_rctLock);
1042 cm_ReleaseUserVCRef(userp);
1043 cm_ReleaseUser(userp);
1048 /* retrieve a held reference to a user structure corresponding to an incoming
1050 * corresponding release function is cm_ReleaseUser.
1052 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1058 smbp = (smb_t *) inp;
1059 uidp = smb_FindUID(vcp, smbp->uid, 0);
1060 if ((!uidp) || (!uidp->unp))
1063 lock_ObtainMutex(&uidp->mx);
1064 up = uidp->unp->userp;
1066 lock_ReleaseMutex(&uidp->mx);
1068 smb_ReleaseUID(uidp);
1074 * Return a pointer to a pathname extracted from a TID structure. The
1075 * TID structure is not held; assume it won't go away.
1077 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1082 tidp = smb_FindTID(vcp, tid, 0);
1086 if (tidp->flags & SMB_TIDFLAG_IPC) {
1087 code = CM_ERROR_TIDIPC;
1088 /* tidp->pathname would be NULL, but that's fine */
1090 *treepath = tidp->pathname;
1091 smb_ReleaseTID(tidp);
1096 /* check to see if we have a chained fid, that is, a fid that comes from an
1097 * OpenAndX message that ran earlier in this packet. In this case, the fid
1098 * field in a read, for example, request, isn't set, since the value is
1099 * supposed to be inherited from the openAndX call.
1101 int smb_ChainFID(int fid, smb_packet_t *inp)
1103 if (inp->fid == 0 || inp->inCount == 0)
1109 /* are we a priv'd user? What does this mean on NT? */
1110 int smb_SUser(cm_user_t *userp)
1115 /* find a file ID. If we pass in 0 we select an used File ID.
1116 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1117 * smb_fid_t data structure if desired File ID cannot be found.
1119 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1124 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1127 lock_ObtainWrite(&smb_rctLock);
1128 /* figure out if we need to allocate a new file ID */
1131 fid = vcp->fidCounter;
1135 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1136 if (fid == fidp->fid) {
1147 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1148 char eventName[MAX_PATH];
1150 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1151 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1152 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1153 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1154 thrd_CloseHandle(event);
1161 fidp = malloc(sizeof(*fidp));
1162 memset(fidp, 0, sizeof(*fidp));
1163 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1166 smb_HoldVCNoLock(vcp);
1167 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1169 fidp->curr_chunk = fidp->prev_chunk = -2;
1170 fidp->raw_write_event = event;
1172 vcp->fidCounter = fid+1;
1173 if (vcp->fidCounter == 0)
1174 vcp->fidCounter = 1;
1177 lock_ReleaseWrite(&smb_rctLock);
1181 void smb_ReleaseFID(smb_fid_t *fidp)
1184 smb_vc_t *vcp = NULL;
1185 smb_ioctl_t *ioctlp;
1191 lock_ObtainWrite(&smb_rctLock);
1192 osi_assert(fidp->refCount-- > 0);
1193 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1196 scp = fidp->scp; /* release after lock is released */
1199 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1200 thrd_CloseHandle(fidp->raw_write_event);
1202 /* and see if there is ioctl stuff to free */
1203 ioctlp = fidp->ioctlp;
1206 cm_FreeSpace(ioctlp->prefix);
1207 if (ioctlp->inAllocp)
1208 free(ioctlp->inAllocp);
1209 if (ioctlp->outAllocp)
1210 free(ioctlp->outAllocp);
1216 smb_ReleaseVCNoLock(vcp);
1218 lock_ReleaseWrite(&smb_rctLock);
1220 /* now release the scache structure */
1222 cm_ReleaseSCache(scp);
1226 * Case-insensitive search for one string in another;
1227 * used to find variable names in submount pathnames.
1229 static char *smb_stristr(char *str1, char *str2)
1233 for (cursor = str1; *cursor; cursor++)
1234 if (stricmp(cursor, str2) == 0)
1241 * Substitute a variable value for its name in a submount pathname. Variable
1242 * name has been identified by smb_stristr() and is in substr. Variable name
1243 * length (plus one) is in substr_size. Variable value is in newstr.
1245 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1250 strcpy(temp, substr + substr_size - 1);
1251 strcpy(substr, newstr);
1255 char VNUserName[] = "%USERNAME%";
1256 char VNLCUserName[] = "%LCUSERNAME%";
1257 char VNComputerName[] = "%COMPUTERNAME%";
1258 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1261 /* List available shares */
1262 int smb_ListShares()
1266 char shareBuf[4096];
1274 /*strcpy(shareNameList[num_shares], "all");
1275 strcpy(pathNameList[num_shares++], "/afs");*/
1276 fprintf(stderr, "The following shares are available:\n");
1277 fprintf(stderr, "Share Name (AFS Path)\n");
1278 fprintf(stderr, "---------------------\n");
1279 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1282 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1283 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1285 strcpy(sbmtpath, cm_confDir);
1287 strcat(sbmtpath, "/afsdsbmt.ini");
1288 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1289 shareBuf, sizeof(shareBuf),
1295 this_share = shareBuf;
1299 /*strcpy(shareNameList[num_shares], this_share);*/
1300 len = GetPrivateProfileString("AFS Submounts", this_share,
1307 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1310 if (*p == '\\') *p = '/'; /* change to / */
1314 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1315 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1318 while (*this_share != 0) this_share++; /* find next NUL */
1319 this_share++; /* skip past the NUL */
1320 } while (*this_share != 0); /* stop at final NUL */
1326 typedef struct smb_findShare_rock {
1330 } smb_findShare_rock_t;
1332 #define SMB_FINDSHARE_EXACT_MATCH 1
1333 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1335 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1339 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1340 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1341 if(!stricmp(dep->name, vrock->shareName))
1342 matchType = SMB_FINDSHARE_EXACT_MATCH;
1344 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1345 if(vrock->match) free(vrock->match);
1346 vrock->match = strdup(dep->name);
1347 vrock->matchType = matchType;
1349 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1350 return CM_ERROR_STOPNOW;
1356 /* find a shareName in the table of submounts */
1357 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1361 char pathName[1024];
1366 char sbmtpath[MAX_PATH];
1371 DWORD allSubmount = 1;
1373 /* if allSubmounts == 0, only return the //mountRoot/all share
1374 * if in fact it has been been created in the subMounts table.
1375 * This is to allow sites that want to restrict access to the
1378 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1379 0, KEY_QUERY_VALUE, &parmKey);
1380 if (code == ERROR_SUCCESS) {
1381 len = sizeof(allSubmount);
1382 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1383 (BYTE *) &allSubmount, &len);
1384 if (code != ERROR_SUCCESS) {
1387 RegCloseKey (parmKey);
1390 if (allSubmount && _stricmp(shareName, "all") == 0) {
1395 /* In case, the all share is disabled we need to still be able
1396 * to handle ioctl requests
1398 if (_stricmp(shareName, "ioctl$") == 0) {
1399 *pathNamep = strdup("/.__ioctl__");
1403 if (_stricmp(shareName, "IPC$") == 0 ||
1404 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1405 _stricmp(shareName, "DESKTOP.INI") == 0
1412 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1413 0, KEY_QUERY_VALUE, &parmKey);
1414 if (code == ERROR_SUCCESS) {
1415 len = sizeof(pathName);
1416 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1417 (BYTE *) pathName, &len);
1418 if (code != ERROR_SUCCESS)
1420 RegCloseKey (parmKey);
1425 strcpy(sbmtpath, cm_confDir);
1426 strcat(sbmtpath, "/afsdsbmt.ini");
1427 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1428 pathName, sizeof(pathName), sbmtpath);
1430 if (len != 0 && len != sizeof(pathName) - 1) {
1431 /* We can accept either unix or PC style AFS pathnames. Convert
1432 * Unix-style to PC style here for internal use.
1435 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1436 p += strlen(cm_mountRoot); /* skip mount path */
1439 if (*q == '/') *q = '\\'; /* change to \ */
1445 if (var = smb_stristr(p, VNUserName)) {
1446 if (uidp && uidp->unp)
1447 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1449 smb_subst(p, var, sizeof(VNUserName)," ");
1451 else if (var = smb_stristr(p, VNLCUserName))
1453 if (uidp && uidp->unp)
1454 strcpy(temp, uidp->unp->name);
1458 smb_subst(p, var, sizeof(VNLCUserName), temp);
1460 else if (var = smb_stristr(p, VNComputerName))
1462 sizeTemp = sizeof(temp);
1463 GetComputerName((LPTSTR)temp, &sizeTemp);
1464 smb_subst(p, var, sizeof(VNComputerName), temp);
1466 else if (var = smb_stristr(p, VNLCComputerName))
1468 sizeTemp = sizeof(temp);
1469 GetComputerName((LPTSTR)temp, &sizeTemp);
1471 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1476 *pathNamep = strdup(p);
1481 /* First lookup shareName in root.afs */
1483 smb_findShare_rock_t vrock;
1485 char * p = shareName;
1488 /* attempt to locate a partial match in root.afs. This is because
1489 when using the ANSI RAP calls, the share name is limited to 13 chars
1490 and hence is truncated. Of course we prefer exact matches. */
1492 thyper.HighPart = 0;
1495 vrock.shareName = shareName;
1497 vrock.matchType = 0;
1499 cm_HoldSCache(cm_data.rootSCachep);
1500 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1501 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1502 cm_ReleaseSCache(cm_data.rootSCachep);
1504 if (vrock.matchType) {
1505 sprintf(pathName,"/%s/",vrock.match);
1506 *pathNamep = strdup(strlwr(pathName));
1511 /* if we get here, there was no match for the share in root.afs */
1512 /* so try to create \\<netbiosName>\<cellname> */
1517 /* Get the full name for this cell */
1518 code = cm_SearchCellFile(p, temp, 0, 0);
1519 #ifdef AFS_AFSDB_ENV
1520 if (code && cm_dnsEnabled) {
1522 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1525 /* construct the path */
1527 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1528 *pathNamep = strdup(strlwr(pathName));
1537 /* Client-side offline caching policy types */
1538 #define CSC_POLICY_MANUAL 0
1539 #define CSC_POLICY_DOCUMENTS 1
1540 #define CSC_POLICY_PROGRAMS 2
1541 #define CSC_POLICY_DISABLE 3
1543 int smb_FindShareCSCPolicy(char *shareName)
1549 int retval = CSC_POLICY_MANUAL;
1551 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1552 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1555 REG_OPTION_NON_VOLATILE,
1561 len = sizeof(policy);
1562 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1564 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1566 else if (stricmp(policy, "documents") == 0)
1568 retval = CSC_POLICY_DOCUMENTS;
1570 else if (stricmp(policy, "programs") == 0)
1572 retval = CSC_POLICY_PROGRAMS;
1574 else if (stricmp(policy, "disable") == 0)
1576 retval = CSC_POLICY_DISABLE;
1579 RegCloseKey(hkCSCPolicy);
1583 /* find a dir search structure by cookie value, and return it held.
1584 * Must be called with smb_globalLock held.
1586 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1588 smb_dirSearch_t *dsp;
1590 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1591 if (dsp->cookie == cookie) {
1592 if (dsp != smb_firstDirSearchp) {
1593 /* move to head of LRU queue, too, if we're not already there */
1594 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1595 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1596 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1597 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1598 if (!smb_lastDirSearchp)
1599 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1601 lock_ObtainMutex(&dsp->mx);
1603 lock_ReleaseMutex(&dsp->mx);
1609 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1610 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1611 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1617 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1619 lock_ObtainWrite(&smb_globalLock);
1620 lock_ObtainMutex(&dsp->mx);
1621 dsp->flags |= SMB_DIRSEARCH_DELETE;
1622 if (dsp->scp != NULL) {
1623 lock_ObtainMutex(&dsp->scp->mx);
1624 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1625 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1626 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1627 dsp->scp->bulkStatProgress = hones;
1629 lock_ReleaseMutex(&dsp->scp->mx);
1631 lock_ReleaseMutex(&dsp->mx);
1632 lock_ReleaseWrite(&smb_globalLock);
1635 /* Must be called with the smb_globalLock held */
1636 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1638 cm_scache_t *scp = NULL;
1640 lock_ObtainMutex(&dsp->mx);
1641 osi_assert(dsp->refCount-- > 0);
1642 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1643 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1644 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1645 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1646 lock_ReleaseMutex(&dsp->mx);
1647 lock_FinalizeMutex(&dsp->mx);
1651 lock_ReleaseMutex(&dsp->mx);
1653 /* do this now to avoid spurious locking hierarchy creation */
1654 if (scp) cm_ReleaseSCache(scp);
1657 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1659 lock_ObtainWrite(&smb_globalLock);
1660 smb_ReleaseDirSearchNoLock(dsp);
1661 lock_ReleaseWrite(&smb_globalLock);
1664 /* find a dir search structure by cookie value, and return it held */
1665 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1667 smb_dirSearch_t *dsp;
1669 lock_ObtainWrite(&smb_globalLock);
1670 dsp = smb_FindDirSearchNoLock(cookie);
1671 lock_ReleaseWrite(&smb_globalLock);
1675 /* GC some dir search entries, in the address space expected by the specific protocol.
1676 * Must be called with smb_globalLock held; release the lock temporarily.
1678 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1679 void smb_GCDirSearches(int isV3)
1681 smb_dirSearch_t *prevp;
1682 smb_dirSearch_t *tp;
1683 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1687 victimCount = 0; /* how many have we got so far */
1688 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1689 /* we'll move tp from queue, so
1692 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1693 /* if no one is using this guy, and we're either in the new protocol,
1694 * or we're in the old one and this is a small enough ID to be useful
1695 * to the old protocol, GC this guy.
1697 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1698 /* hold and delete */
1699 tp->flags |= SMB_DIRSEARCH_DELETE;
1700 victimsp[victimCount++] = tp;
1704 /* don't do more than this */
1705 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1709 /* now release them */
1710 for (i = 0; i < victimCount; i++) {
1711 smb_ReleaseDirSearchNoLock(victimsp[i]);
1715 /* function for allocating a dir search entry. We need these to remember enough context
1716 * since we don't get passed the path from call to call during a directory search.
1718 * Returns a held dir search structure, and bumps the reference count on the vnode,
1719 * since it saves a pointer to the vnode.
1721 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1723 smb_dirSearch_t *dsp;
1729 lock_ObtainWrite(&smb_globalLock);
1732 /* what's the biggest ID allowed in this version of the protocol */
1733 maxAllowed = isV3 ? 65535 : 255;
1734 if (smb_dirSearchCounter > maxAllowed)
1735 smb_dirSearchCounter = 1;
1737 start = smb_dirSearchCounter;
1740 /* twice so we have enough tries to find guys we GC after one pass;
1741 * 10 extra is just in case I mis-counted.
1743 if (++counter > 2*maxAllowed+10)
1744 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1746 if (smb_dirSearchCounter > maxAllowed) {
1747 smb_dirSearchCounter = 1;
1749 if (smb_dirSearchCounter == start) {
1751 smb_GCDirSearches(isV3);
1754 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1756 /* don't need to watch for refcount zero and deleted, since
1757 * we haven't dropped the global lock.
1759 lock_ObtainMutex(&dsp->mx);
1761 lock_ReleaseMutex(&dsp->mx);
1762 ++smb_dirSearchCounter;
1766 dsp = malloc(sizeof(*dsp));
1767 memset(dsp, 0, sizeof(*dsp));
1768 dsp->cookie = smb_dirSearchCounter;
1769 ++smb_dirSearchCounter;
1771 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1772 dsp->lastTime = osi_Time();
1773 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1774 if (!smb_lastDirSearchp)
1775 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1778 lock_ReleaseWrite(&smb_globalLock);
1782 static smb_packet_t *GetPacket(void)
1786 unsigned int npar, seg, tb_sel;
1789 lock_ObtainWrite(&smb_globalLock);
1790 tbp = smb_packetFreeListp;
1792 smb_packetFreeListp = tbp->nextp;
1793 lock_ReleaseWrite(&smb_globalLock);
1796 tbp = calloc(65540,1);
1798 tbp = malloc(sizeof(smb_packet_t));
1800 tbp->magic = SMB_PACKETMAGIC;
1803 tbp->resumeCode = 0;
1809 tbp->ncb_length = 0;
1814 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1817 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1819 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1821 osi_panic("",__FILE__,__LINE__);
1824 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1829 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1830 tbp->dos_pkt_sel = tb_sel;
1833 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1838 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1842 memcpy(tbp, pkt, sizeof(smb_packet_t));
1843 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1845 smb_HoldVC(tbp->vcp);
1849 static NCB *GetNCB(void)
1854 unsigned int npar, seg, tb_sel;
1857 lock_ObtainWrite(&smb_globalLock);
1858 tbp = smb_ncbFreeListp;
1860 smb_ncbFreeListp = tbp->nextp;
1861 lock_ReleaseWrite(&smb_globalLock);
1864 tbp = calloc(sizeof(*tbp),1);
1866 tbp = malloc(sizeof(*tbp));
1867 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1870 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1872 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1874 osi_panic("",__FILE__,__LINE__);
1876 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1881 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1882 tbp->dos_ncb_sel = tb_sel;
1884 tbp->magic = SMB_NCBMAGIC;
1887 osi_assert(tbp->magic == SMB_NCBMAGIC);
1889 memset(&tbp->ncb, 0, sizeof(NCB));
1892 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1897 void smb_FreePacket(smb_packet_t *tbp)
1899 smb_vc_t * vcp = NULL;
1900 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1902 lock_ObtainWrite(&smb_globalLock);
1903 tbp->nextp = smb_packetFreeListp;
1904 smb_packetFreeListp = tbp;
1905 tbp->magic = SMB_PACKETMAGIC;
1909 tbp->resumeCode = 0;
1915 tbp->ncb_length = 0;
1917 lock_ReleaseWrite(&smb_globalLock);
1923 static void FreeNCB(NCB *bufferp)
1927 tbp = (smb_ncb_t *) bufferp;
1928 osi_assert(tbp->magic == SMB_NCBMAGIC);
1930 lock_ObtainWrite(&smb_globalLock);
1931 tbp->nextp = smb_ncbFreeListp;
1932 smb_ncbFreeListp = tbp;
1933 lock_ReleaseWrite(&smb_globalLock);
1936 /* get a ptr to the data part of a packet, and its count */
1937 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1941 unsigned char *afterParmsp;
1943 parmBytes = *smbp->wctp << 1;
1944 afterParmsp = smbp->wctp + parmBytes + 1;
1946 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1947 if (nbytesp) *nbytesp = dataBytes;
1949 /* don't forget to skip the data byte count, since it follows
1950 * the parameters; that's where the "2" comes from below.
1952 return (unsigned char *) (afterParmsp + 2);
1955 /* must set all the returned parameters before playing around with the
1956 * data region, since the data region is located past the end of the
1957 * variable number of parameters.
1959 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1961 unsigned char *afterParmsp;
1963 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1965 *afterParmsp++ = dsize & 0xff;
1966 *afterParmsp = (dsize>>8) & 0xff;
1969 /* return the parm'th parameter in the smbp packet */
1970 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1973 unsigned char *parmDatap;
1975 parmCount = *smbp->wctp;
1977 if (parm >= parmCount) {
1982 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1984 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1985 parm, parmCount, smbp->ncb_length);
1988 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1989 1, smbp->ncb_length, ptbuf, smbp);
1990 DeregisterEventSource(h);
1992 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
1993 parm, parmCount, smbp->ncb_length);
1994 osi_panic(s, __FILE__, __LINE__);
1996 parmDatap = smbp->wctp + (2*parm) + 1;
1998 return parmDatap[0] + (parmDatap[1] << 8);
2001 /* return the parm'th parameter in the smbp packet */
2002 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2005 unsigned char *parmDatap;
2007 parmCount = *smbp->wctp;
2009 if (parm * 2 + offset >= parmCount * 2) {
2014 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2016 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2017 parm, offset, parmCount, smbp->ncb_length);
2020 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2021 1, smbp->ncb_length, ptbuf, smbp);
2022 DeregisterEventSource(h);
2024 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2025 parm, offset, parmCount, smbp->ncb_length);
2026 osi_panic(s, __FILE__, __LINE__);
2028 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2030 return parmDatap[0] + (parmDatap[1] << 8);
2033 void smb_SetSMBParm(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+1;
2041 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2042 *parmDatap++ = parmValue & 0xff;
2043 *parmDatap = (parmValue>>8) & 0xff;
2046 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2050 /* make sure we have enough slots */
2051 if (*smbp->wctp <= slot)
2052 *smbp->wctp = slot+2;
2054 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2055 *parmDatap++ = parmValue & 0xff;
2056 *parmDatap++ = (parmValue>>8) & 0xff;
2057 *parmDatap++ = (parmValue>>16) & 0xff;
2058 *parmDatap++ = (parmValue>>24) & 0xff;
2061 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2066 /* make sure we have enough slots */
2067 if (*smbp->wctp <= slot)
2068 *smbp->wctp = slot+4;
2070 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2072 *parmDatap++ = *parmValuep++;
2075 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2079 /* make sure we have enough slots */
2080 if (*smbp->wctp <= slot) {
2081 if (smbp->oddByte) {
2083 *smbp->wctp = slot+1;
2088 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2089 *parmDatap++ = parmValue & 0xff;
2092 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2096 lastSlashp = strrchr(inPathp, '\\');
2098 *lastComponentp = lastSlashp;
2101 if (inPathp == lastSlashp)
2103 *outPathp++ = *inPathp++;
2112 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2117 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2122 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2128 tlen = inp[0] + (inp[1]<<8);
2129 inp += 2; /* skip length field */
2132 *chainpp = inp + tlen;
2141 /* format a packet as a response */
2142 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2147 outp = (smb_t *) op;
2149 /* zero the basic structure through the smb_wct field, and zero the data
2150 * size field, assuming that wct stays zero; otherwise, you have to
2151 * explicitly set the data size field, too.
2153 inSmbp = (smb_t *) inp;
2154 memset(outp, 0, sizeof(smb_t)+2);
2160 outp->com = inSmbp->com;
2161 outp->tid = inSmbp->tid;
2162 outp->pid = inSmbp->pid;
2163 outp->uid = inSmbp->uid;
2164 outp->mid = inSmbp->mid;
2165 outp->res[0] = inSmbp->res[0];
2166 outp->res[1] = inSmbp->res[1];
2167 op->inCom = inSmbp->com;
2169 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2170 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2172 /* copy fields in generic packet area */
2173 op->wctp = &outp->wct;
2176 /* send a (probably response) packet; vcp tells us to whom to send it.
2177 * we compute the length by looking at wct and bcc fields.
2179 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2196 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2199 memset((char *)ncbp, 0, sizeof(NCB));
2201 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2202 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2203 extra += tp[0] + (tp[1]<<8);
2204 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2205 extra += 3; /* wct and length fields */
2207 ncbp->ncb_length = extra; /* bytes to send */
2208 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2209 ncbp->ncb_lana_num = vcp->lana;
2210 ncbp->ncb_command = NCBSEND; /* op means send data */
2212 ncbp->ncb_buffer = (char *) inp;/* packet */
2213 code = Netbios(ncbp);
2215 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2216 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2218 /* copy header information from virtual to DOS address space */
2219 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2220 code = Netbios(ncbp, dos_ncb);
2224 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2230 void smb_MapNTError(long code, unsigned long *NTStatusp)
2232 unsigned long NTStatus;
2234 /* map CM_ERROR_* errors to NT 32-bit status codes */
2235 /* NT Status codes are listed in ntstatus.h not winerror.h */
2236 if (code == CM_ERROR_NOSUCHCELL) {
2237 NTStatus = 0xC000000FL; /* No such file */
2239 else if (code == CM_ERROR_NOSUCHVOLUME) {
2240 NTStatus = 0xC000000FL; /* No such file */
2242 else if (code == CM_ERROR_TIMEDOUT) {
2243 NTStatus = 0xC00000CFL; /* Sharing Paused */
2245 else if (code == CM_ERROR_RETRY) {
2246 NTStatus = 0xC000022DL; /* Retry */
2248 else if (code == CM_ERROR_NOACCESS) {
2249 NTStatus = 0xC0000022L; /* Access denied */
2251 else if (code == CM_ERROR_READONLY) {
2252 NTStatus = 0xC00000A2L; /* Write protected */
2254 else if (code == CM_ERROR_NOSUCHFILE) {
2255 NTStatus = 0xC000000FL; /* No such file */
2257 else if (code == CM_ERROR_NOSUCHPATH) {
2258 NTStatus = 0xC000003AL; /* Object path not found */
2260 else if (code == CM_ERROR_TOOBIG) {
2261 NTStatus = 0xC000007BL; /* Invalid image format */
2263 else if (code == CM_ERROR_INVAL) {
2264 NTStatus = 0xC000000DL; /* Invalid parameter */
2266 else if (code == CM_ERROR_BADFD) {
2267 NTStatus = 0xC0000008L; /* Invalid handle */
2269 else if (code == CM_ERROR_BADFDOP) {
2270 NTStatus = 0xC0000022L; /* Access denied */
2272 else if (code == CM_ERROR_EXISTS) {
2273 NTStatus = 0xC0000035L; /* Object name collision */
2275 else if (code == CM_ERROR_NOTEMPTY) {
2276 NTStatus = 0xC0000101L; /* Directory not empty */
2278 else if (code == CM_ERROR_CROSSDEVLINK) {
2279 NTStatus = 0xC00000D4L; /* Not same device */
2281 else if (code == CM_ERROR_NOTDIR) {
2282 NTStatus = 0xC0000103L; /* Not a directory */
2284 else if (code == CM_ERROR_ISDIR) {
2285 NTStatus = 0xC00000BAL; /* File is a directory */
2287 else if (code == CM_ERROR_BADOP) {
2289 /* I have no idea where this comes from */
2290 NTStatus = 0xC09820FFL; /* SMB no support */
2292 NTStatus = 0xC00000BBL; /* Not supported */
2293 #endif /* COMMENT */
2295 else if (code == CM_ERROR_BADSHARENAME) {
2296 NTStatus = 0xC00000CCL; /* Bad network name */
2298 else if (code == CM_ERROR_NOIPC) {
2300 NTStatus = 0xC0000022L; /* Access Denied */
2302 NTStatus = 0xC000013DL; /* Remote Resources */
2305 else if (code == CM_ERROR_CLOCKSKEW) {
2306 NTStatus = 0xC0000133L; /* Time difference at DC */
2308 else if (code == CM_ERROR_BADTID) {
2309 NTStatus = 0xC0982005L; /* SMB bad TID */
2311 else if (code == CM_ERROR_USESTD) {
2312 NTStatus = 0xC09820FBL; /* SMB use standard */
2314 else if (code == CM_ERROR_QUOTA) {
2316 NTStatus = 0xC0000044L; /* Quota exceeded */
2318 NTStatus = 0xC000007FL; /* Disk full */
2321 else if (code == CM_ERROR_SPACE) {
2322 NTStatus = 0xC000007FL; /* Disk full */
2324 else if (code == CM_ERROR_ATSYS) {
2325 NTStatus = 0xC0000033L; /* Object name invalid */
2327 else if (code == CM_ERROR_BADNTFILENAME) {
2328 NTStatus = 0xC0000033L; /* Object name invalid */
2330 else if (code == CM_ERROR_WOULDBLOCK) {
2331 NTStatus = 0xC0000055L; /* Lock not granted */
2333 else if (code == CM_ERROR_PARTIALWRITE) {
2334 NTStatus = 0xC000007FL; /* Disk full */
2336 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2337 NTStatus = 0xC0000023L; /* Buffer too small */
2339 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2340 NTStatus = 0xC0000035L; /* Object name collision */
2342 else if (code == CM_ERROR_BADPASSWORD) {
2343 NTStatus = 0xC000006DL; /* unknown username or bad password */
2345 else if (code == CM_ERROR_BADLOGONTYPE) {
2346 NTStatus = 0xC000015BL; /* logon type not granted */
2348 else if (code == CM_ERROR_GSSCONTINUE) {
2349 NTStatus = 0xC0000016L; /* more processing required */
2351 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2353 NTStatus = 0xC0000280L; /* reparse point not resolved */
2355 NTStatus = 0xC0000022L; /* Access Denied */
2358 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2359 NTStatus = 0xC0000257L; /* Path Not Covered */
2361 else if (code == CM_ERROR_ALLBUSY) {
2362 NTStatus = 0xC00000BFL; /* Network Busy */
2364 NTStatus = 0xC0982001L; /* SMB non-specific error */
2367 *NTStatusp = NTStatus;
2368 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2371 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2372 unsigned char *classp)
2374 unsigned char class;
2375 unsigned short error;
2377 /* map CM_ERROR_* errors to SMB errors */
2378 if (code == CM_ERROR_NOSUCHCELL) {
2380 error = 3; /* bad path */
2382 else if (code == CM_ERROR_NOSUCHVOLUME) {
2384 error = 3; /* bad path */
2386 else if (code == CM_ERROR_TIMEDOUT) {
2388 error = 81; /* server is paused */
2390 else if (code == CM_ERROR_RETRY) {
2391 class = 2; /* shouldn't happen */
2394 else if (code == CM_ERROR_NOACCESS) {
2396 error = 4; /* bad access */
2398 else if (code == CM_ERROR_READONLY) {
2400 error = 19; /* read only */
2402 else if (code == CM_ERROR_NOSUCHFILE) {
2404 error = 2; /* ENOENT! */
2406 else if (code == CM_ERROR_NOSUCHPATH) {
2408 error = 3; /* Bad path */
2410 else if (code == CM_ERROR_TOOBIG) {
2412 error = 11; /* bad format */
2414 else if (code == CM_ERROR_INVAL) {
2415 class = 2; /* server non-specific error code */
2418 else if (code == CM_ERROR_BADFD) {
2420 error = 6; /* invalid file handle */
2422 else if (code == CM_ERROR_BADFDOP) {
2423 class = 1; /* invalid op on FD */
2426 else if (code == CM_ERROR_EXISTS) {
2428 error = 80; /* file already exists */
2430 else if (code == CM_ERROR_NOTEMPTY) {
2432 error = 5; /* delete directory not empty */
2434 else if (code == CM_ERROR_CROSSDEVLINK) {
2436 error = 17; /* EXDEV */
2438 else if (code == CM_ERROR_NOTDIR) {
2439 class = 1; /* bad path */
2442 else if (code == CM_ERROR_ISDIR) {
2443 class = 1; /* access denied; DOS doesn't have a good match */
2446 else if (code == CM_ERROR_BADOP) {
2450 else if (code == CM_ERROR_BADSHARENAME) {
2454 else if (code == CM_ERROR_NOIPC) {
2456 error = 4; /* bad access */
2458 else if (code == CM_ERROR_CLOCKSKEW) {
2459 class = 1; /* invalid function */
2462 else if (code == CM_ERROR_BADTID) {
2466 else if (code == CM_ERROR_USESTD) {
2470 else if (code == CM_ERROR_REMOTECONN) {
2474 else if (code == CM_ERROR_QUOTA) {
2475 if (vcp->flags & SMB_VCFLAG_USEV3) {
2477 error = 39; /* disk full */
2481 error = 5; /* access denied */
2484 else if (code == CM_ERROR_SPACE) {
2485 if (vcp->flags & SMB_VCFLAG_USEV3) {
2487 error = 39; /* disk full */
2491 error = 5; /* access denied */
2494 else if (code == CM_ERROR_PARTIALWRITE) {
2496 error = 39; /* disk full */
2498 else if (code == CM_ERROR_ATSYS) {
2500 error = 2; /* ENOENT */
2502 else if (code == CM_ERROR_WOULDBLOCK) {
2504 error = 33; /* lock conflict */
2506 else if (code == CM_ERROR_NOFILES) {
2508 error = 18; /* no files in search */
2510 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2512 error = 183; /* Samba uses this */
2514 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2515 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2517 error = 2; /* bad password */
2519 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2521 error = 3; /* bad path */
2530 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2533 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2535 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2536 return CM_ERROR_BADOP;
2539 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2541 unsigned short EchoCount, i;
2542 char *data, *outdata;
2545 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2547 for (i=1; i<=EchoCount; i++) {
2548 data = smb_GetSMBData(inp, &dataSize);
2549 smb_SetSMBParm(outp, 0, i);
2550 smb_SetSMBDataLength(outp, dataSize);
2551 outdata = smb_GetSMBData(outp, NULL);
2552 memcpy(outdata, data, dataSize);
2553 smb_SendPacket(vcp, outp);
2559 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2562 long count, minCount, finalCount;
2566 cm_user_t *userp = NULL;
2570 char *rawBuf = NULL;
2572 dos_ptr rawBuf = NULL;
2579 fd = smb_GetSMBParm(inp, 0);
2580 count = smb_GetSMBParm(inp, 3);
2581 minCount = smb_GetSMBParm(inp, 4);
2582 offset.HighPart = 0; /* too bad */
2583 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2585 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2586 fd, offset.LowPart, count);
2588 fidp = smb_FindFID(vcp, fd, 0);
2592 lock_ObtainMutex(&smb_RawBufLock);
2594 /* Get a raw buf, from head of list */
2595 rawBuf = smb_RawBufs;
2597 smb_RawBufs = *(char **)smb_RawBufs;
2599 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2602 lock_ReleaseMutex(&smb_RawBufLock);
2606 if (fidp->flags & SMB_FID_IOCTL)
2609 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2611 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2614 /* Give back raw buffer */
2615 lock_ObtainMutex(&smb_RawBufLock);
2617 *((char **) rawBuf) = smb_RawBufs;
2619 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2622 smb_RawBufs = rawBuf;
2623 lock_ReleaseMutex(&smb_RawBufLock);
2626 smb_ReleaseFID(fidp);
2630 userp = smb_GetUser(vcp, inp);
2633 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2635 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2636 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2637 userp, &finalCount, TRUE /* rawFlag */);
2644 cm_ReleaseUser(userp);
2647 smb_ReleaseFID(fidp);
2652 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2654 memset((char *)ncbp, 0, sizeof(NCB));
2656 ncbp->ncb_length = (unsigned short) finalCount;
2657 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2658 ncbp->ncb_lana_num = vcp->lana;
2659 ncbp->ncb_command = NCBSEND;
2660 ncbp->ncb_buffer = rawBuf;
2663 code = Netbios(ncbp);
2665 code = Netbios(ncbp, dos_ncb);
2668 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2671 /* Give back raw buffer */
2672 lock_ObtainMutex(&smb_RawBufLock);
2674 *((char **) rawBuf) = smb_RawBufs;
2676 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2679 smb_RawBufs = rawBuf;
2680 lock_ReleaseMutex(&smb_RawBufLock);
2686 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2688 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2693 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2695 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2700 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2707 int protoIndex; /* index we're using */
2712 char protocol_array[10][1024]; /* protocol signature of the client */
2713 int caps; /* capabilities */
2716 TIME_ZONE_INFORMATION tzi;
2718 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2722 DWORD now = GetCurrentTime();
2723 if (now - last_msg_time >= 30000
2724 && now - last_msg_time <= 90000) {
2726 "Setting dead_vcp %x", active_vcp);
2728 smb_ReleaseVC(dead_vcp);
2730 "Previous dead_vcp %x", dead_vcp);
2732 smb_HoldVC(active_vcp);
2733 dead_vcp = active_vcp;
2734 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2739 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2741 namep = smb_GetSMBData(inp, &dbytes);
2744 coreProtoIndex = -1; /* not found */
2747 while(namex < dbytes) {
2748 osi_Log1(smb_logp, "Protocol %s",
2749 osi_LogSaveString(smb_logp, namep+1));
2750 strcpy(protocol_array[tcounter], namep+1);
2752 /* namep points at the first protocol, or really, a 0x02
2753 * byte preceding the null-terminated ASCII name.
2755 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2756 coreProtoIndex = tcounter;
2758 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2759 v3ProtoIndex = tcounter;
2761 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2762 NTProtoIndex = tcounter;
2765 /* compute size of protocol entry */
2766 entryLength = strlen(namep+1);
2767 entryLength += 2; /* 0x02 bytes and null termination */
2769 /* advance over this protocol entry */
2770 namex += entryLength;
2771 namep += entryLength;
2772 tcounter++; /* which proto entry we're looking at */
2775 if (NTProtoIndex != -1) {
2776 protoIndex = NTProtoIndex;
2777 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2779 else if (v3ProtoIndex != -1) {
2780 protoIndex = v3ProtoIndex;
2781 vcp->flags |= SMB_VCFLAG_USEV3;
2783 else if (coreProtoIndex != -1) {
2784 protoIndex = coreProtoIndex;
2785 vcp->flags |= SMB_VCFLAG_USECORE;
2787 else protoIndex = -1;
2789 if (protoIndex == -1)
2790 return CM_ERROR_INVAL;
2791 else if (NTProtoIndex != -1) {
2792 smb_SetSMBParm(outp, 0, protoIndex);
2793 if (smb_authType != SMB_AUTH_NONE) {
2794 smb_SetSMBParmByte(outp, 1,
2795 NEGOTIATE_SECURITY_USER_LEVEL |
2796 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2798 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2800 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2801 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2802 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2803 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2804 /* The session key is not a well documented field however most clients
2805 * will echo back the session key to the server. Currently we are using
2806 * the same value for all sessions. We should generate a random value
2807 * and store it into the vcp
2809 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2810 smb_SetSMBParm(outp, 8, 1);
2812 * Tried changing the capabilities to support for W2K - defect 117695
2813 * Maybe something else needs to be changed here?
2817 smb_SetSMBParmLong(outp, 9, 0x43fd);
2819 smb_SetSMBParmLong(outp, 9, 0x251);
2822 * 32-bit error codes *
2827 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2829 NTNEGOTIATE_CAPABILITY_DFS |
2831 NTNEGOTIATE_CAPABILITY_NTFIND |
2832 NTNEGOTIATE_CAPABILITY_RAWMODE |
2833 NTNEGOTIATE_CAPABILITY_NTSMB;
2835 if ( smb_authType == SMB_AUTH_EXTENDED )
2836 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2838 smb_SetSMBParmLong(outp, 9, caps);
2840 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2841 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2842 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2844 GetTimeZoneInformation(&tzi);
2845 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2847 if (smb_authType == SMB_AUTH_NTLM) {
2848 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2849 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2850 /* paste in encryption key */
2851 datap = smb_GetSMBData(outp, NULL);
2852 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2853 /* and the faux domain name */
2854 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2855 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2859 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2861 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2863 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2865 datap = smb_GetSMBData(outp, NULL);
2866 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2869 datap += sizeof(smb_ServerGUID);
2870 memcpy(datap, secBlob, secBlobLength);
2874 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2875 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2878 else if (v3ProtoIndex != -1) {
2879 smb_SetSMBParm(outp, 0, protoIndex);
2881 /* NOTE: Extended authentication cannot be negotiated with v3
2882 * therefore we fail over to NTLM
2884 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2885 smb_SetSMBParm(outp, 1,
2886 NEGOTIATE_SECURITY_USER_LEVEL |
2887 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2889 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2891 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2892 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2893 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2894 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2895 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2896 smb_SetSMBParm(outp, 7, 1);
2898 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2899 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2900 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2902 GetTimeZoneInformation(&tzi);
2903 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2905 /* NOTE: Extended authentication cannot be negotiated with v3
2906 * therefore we fail over to NTLM
2908 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2909 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2910 smb_SetSMBParm(outp, 12, 0); /* resvd */
2911 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2912 datap = smb_GetSMBData(outp, NULL);
2913 /* paste in a new encryption key */
2914 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2915 /* and the faux domain name */
2916 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2918 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2919 smb_SetSMBParm(outp, 12, 0); /* resvd */
2920 smb_SetSMBDataLength(outp, 0);
2923 else if (coreProtoIndex != -1) { /* not really supported anymore */
2924 smb_SetSMBParm(outp, 0, protoIndex);
2925 smb_SetSMBDataLength(outp, 0);
2930 void smb_Daemon(void *parmp)
2932 afs_uint32 count = 0;
2934 while(smbShutdownFlag == 0) {
2938 if (smbShutdownFlag == 1)
2941 if ((count % 72) == 0) { /* every five minutes */
2943 time_t old_localZero = smb_localZero;
2945 /* Initialize smb_localZero */
2946 myTime.tm_isdst = -1; /* compute whether on DST or not */
2947 myTime.tm_year = 70;
2953 smb_localZero = mktime(&myTime);
2955 smb_CalculateNowTZ();
2957 #ifdef AFS_FREELANCE
2958 if ( smb_localZero != old_localZero )
2959 cm_noteLocalMountPointChange();
2962 /* XXX GC dir search entries */
2966 void smb_WaitingLocksDaemon()
2968 smb_waitingLock_t *wL, *nwL;
2971 smb_packet_t *inp, *outp;
2975 while (smbShutdownFlag == 0) {
2976 lock_ObtainWrite(&smb_globalLock);
2977 nwL = smb_allWaitingLocks;
2979 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2989 lock_ObtainWrite(&smb_globalLock);
2991 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2992 lock_ReleaseWrite(&smb_globalLock);
2993 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2994 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2995 if (code == CM_ERROR_WOULDBLOCK) {
2997 if (wL->timeRemaining != 0xffffffff
2998 && (wL->timeRemaining -= 1000) < 0)
3008 ncbp->ncb_length = inp->ncb_length;
3009 inp->spacep = cm_GetSpace();
3011 /* Remove waitingLock from list */
3012 lock_ObtainWrite(&smb_globalLock);
3013 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3015 lock_ReleaseWrite(&smb_globalLock);
3017 /* Resume packet processing */
3019 smb_SetSMBDataLength(outp, 0);
3020 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3021 outp->resumeCode = code;
3023 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3026 cm_FreeSpace(inp->spacep);
3027 smb_FreePacket(inp);
3028 smb_FreePacket(outp);
3032 } while (nwL && smbShutdownFlag == 0);
3037 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3039 osi_Log0(smb_logp, "SMB receive get disk attributes");
3041 smb_SetSMBParm(outp, 0, 32000);
3042 smb_SetSMBParm(outp, 1, 64);
3043 smb_SetSMBParm(outp, 2, 1024);
3044 smb_SetSMBParm(outp, 3, 30000);
3045 smb_SetSMBParm(outp, 4, 0);
3046 smb_SetSMBDataLength(outp, 0);
3050 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3054 unsigned short newTid;
3055 char shareName[256];
3063 osi_Log0(smb_logp, "SMB receive tree connect");
3065 /* parse input parameters */
3066 tp = smb_GetSMBData(inp, NULL);
3067 pathp = smb_ParseASCIIBlock(tp, &tp);
3068 if (smb_StoreAnsiFilenames)
3069 OemToChar(pathp,pathp);
3070 passwordp = smb_ParseASCIIBlock(tp, &tp);
3071 tp = strrchr(pathp, '\\');
3073 return CM_ERROR_BADSMB;
3074 strcpy(shareName, tp+1);
3076 userp = smb_GetUser(vcp, inp);
3078 lock_ObtainMutex(&vcp->mx);
3079 newTid = vcp->tidCounter++;
3080 lock_ReleaseMutex(&vcp->mx);
3082 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3083 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3084 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3086 smb_ReleaseUID(uidp);
3088 smb_ReleaseTID(tidp);
3089 return CM_ERROR_BADSHARENAME;
3091 lock_ObtainMutex(&tidp->mx);
3092 tidp->userp = userp;
3093 tidp->pathname = sharePath;
3094 lock_ReleaseMutex(&tidp->mx);
3095 smb_ReleaseTID(tidp);
3097 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3098 smb_SetSMBParm(rsp, 1, newTid);
3099 smb_SetSMBDataLength(rsp, 0);
3101 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3105 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3109 if (*inp++ != 0x1) return NULL;
3110 tlen = inp[0] + (inp[1]<<8);
3111 inp += 2; /* skip length field */
3114 *chainpp = inp + tlen;
3117 if (lengthp) *lengthp = tlen;
3122 /* set maskp to the mask part of the incoming path.
3123 * Mask is 11 bytes long (8.3 with the dot elided).
3124 * Returns true if succeeds with a valid name, otherwise it does
3125 * its best, but returns false.
3127 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3135 /* starts off valid */
3138 /* mask starts out all blanks */
3139 memset(maskp, ' ', 11);
3141 /* find last backslash, or use whole thing if there is none */
3142 tp = strrchr(pathp, '\\');
3143 if (!tp) tp = pathp;
3144 else tp++; /* skip slash */
3148 /* names starting with a dot are illegal */
3149 if (*tp == '.') valid8Dot3 = 0;
3153 if (tc == 0) return valid8Dot3;
3154 if (tc == '.' || tc == '"') break;
3155 if (i < 8) *up++ = tc;
3156 else valid8Dot3 = 0;
3159 /* if we get here, tp point after the dot */
3160 up = maskp+8; /* ext goes here */
3167 if (tc == '.' || tc == '"')
3170 /* copy extension if not too long */
3180 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3190 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3192 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3196 /* otherwise, we have a valid 8.3 name; see if we have a match,
3197 * treating '?' as a wildcard in maskp (but not in the file name).
3199 tp1 = umask; /* real name, in mask format */
3200 tp2 = maskp; /* mask, in mask format */
3201 for(i=0; i<11; i++) {
3202 tc1 = *tp1++; /* char from real name */
3203 tc2 = *tp2++; /* char from mask */
3204 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3205 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3208 if (tc2 == '?' && tc1 != ' ')
3215 /* we got a match */
3219 char *smb_FindMask(char *pathp)
3223 tp = strrchr(pathp, '\\'); /* find last slash */
3226 return tp+1; /* skip the slash */
3228 return pathp; /* no slash, return the entire path */
3231 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3233 unsigned char *pathp;
3235 unsigned char mask[11];
3236 unsigned char *statBlockp;
3237 unsigned char initStatBlock[21];
3240 osi_Log0(smb_logp, "SMB receive search volume");
3242 /* pull pathname and stat block out of request */
3243 tp = smb_GetSMBData(inp, NULL);
3244 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3245 osi_assert(pathp != NULL);
3246 if (smb_StoreAnsiFilenames)
3247 OemToChar(pathp,pathp);
3248 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3249 osi_assert(statBlockp != NULL);
3251 statBlockp = initStatBlock;
3255 /* for returning to caller */
3256 smb_Get8Dot3MaskFromPath(mask, pathp);
3258 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3259 tp = smb_GetSMBData(outp, NULL);
3261 *tp++ = 43; /* bytes in a dir entry */
3262 *tp++ = 0; /* high byte in counter */
3264 /* now marshall the dir entry, starting with the search status */
3265 *tp++ = statBlockp[0]; /* Reserved */
3266 memcpy(tp, mask, 11); tp += 11; /* FileName */
3268 /* now pass back server use info, with 1st byte non-zero */
3270 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3272 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3274 *tp++ = 0x8; /* attribute: volume */
3284 /* 4 byte file size */
3290 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3291 memset(tp, ' ', 13);
3294 /* set the length of the data part of the packet to 43 + 3, for the dir
3295 * entry plus the 5 and the length fields.
3297 smb_SetSMBDataLength(outp, 46);
3301 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3302 cm_user_t *userp, cm_req_t *reqp)
3310 smb_dirListPatch_t *patchp;
3311 smb_dirListPatch_t *npatchp;
3313 for (patchp = *dirPatchespp; patchp; patchp =
3314 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3316 dptr = patchp->dptr;
3318 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3320 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3321 *dptr++ = SMB_ATTR_HIDDEN;
3324 lock_ObtainMutex(&scp->mx);
3325 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3326 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3328 lock_ReleaseMutex(&scp->mx);
3329 cm_ReleaseSCache(scp);
3330 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3331 *dptr++ = SMB_ATTR_HIDDEN;
3335 attr = smb_Attributes(scp);
3336 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3337 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3338 attr |= SMB_ATTR_HIDDEN;
3342 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3345 shortTemp = (unsigned short) (dosTime & 0xffff);
3346 *((u_short *)dptr) = shortTemp;
3349 /* and copy out date */
3350 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3351 *((u_short *)dptr) = shortTemp;
3354 /* copy out file length */
3355 *((u_long *)dptr) = scp->length.LowPart;
3357 lock_ReleaseMutex(&scp->mx);
3358 cm_ReleaseSCache(scp);
3361 /* now free the patches */
3362 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3363 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3367 /* and mark the list as empty */
3368 *dirPatchespp = NULL;
3373 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3382 smb_dirListPatch_t *dirListPatchesp;
3383 smb_dirListPatch_t *curPatchp;
3387 osi_hyper_t dirLength;
3388 osi_hyper_t bufferOffset;
3389 osi_hyper_t curOffset;
3391 unsigned char *inCookiep;
3392 smb_dirSearch_t *dsp;
3396 unsigned long clientCookie;
3397 cm_pageHeader_t *pageHeaderp;
3398 cm_user_t *userp = NULL;
3405 long nextEntryCookie;
3406 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3407 char resByte; /* reserved byte from the cookie */
3408 char *op; /* output data ptr */
3409 char *origOp; /* original value of op */
3410 cm_space_t *spacep; /* for pathname buffer */
3421 maxCount = smb_GetSMBParm(inp, 0);
3423 dirListPatchesp = NULL;
3425 caseFold = CM_FLAG_CASEFOLD;
3427 tp = smb_GetSMBData(inp, NULL);
3428 pathp = smb_ParseASCIIBlock(tp, &tp);
3429 if (smb_StoreAnsiFilenames)
3430 OemToChar(pathp,pathp);
3431 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3433 /* bail out if request looks bad */
3434 if (!tp || !pathp) {
3435 return CM_ERROR_BADSMB;
3438 /* We can handle long names */
3439 if (vcp->flags & SMB_VCFLAG_USENT)
3440 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3442 /* make sure we got a whole search status */
3443 if (dataLength < 21) {
3444 nextCookie = 0; /* start at the beginning of the dir */
3447 attribute = smb_GetSMBParm(inp, 1);
3449 /* handle volume info in another function */
3450 if (attribute & 0x8)
3451 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3453 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3454 maxCount, osi_LogSaveString(smb_logp, pathp));
3456 if (*pathp == 0) { /* null pathp, treat as root dir */
3457 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3458 return CM_ERROR_NOFILES;
3462 dsp = smb_NewDirSearch(0);
3463 dsp->attribute = attribute;
3464 smb_Get8Dot3MaskFromPath(mask, pathp);
3465 memcpy(dsp->mask, mask, 11);
3467 /* track if this is likely to match a lot of entries */
3468 if (smb_IsStarMask(mask))
3473 /* pull the next cookie value out of the search status block */
3474 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3475 + (inCookiep[16]<<24);
3476 dsp = smb_FindDirSearch(inCookiep[12]);
3478 /* can't find dir search status; fatal error */
3479 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3480 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3481 return CM_ERROR_BADFD;
3483 attribute = dsp->attribute;
3484 resByte = inCookiep[0];
3486 /* copy out client cookie, in host byte order. Don't bother
3487 * interpreting it, since we're just passing it through, anyway.
3489 memcpy(&clientCookie, &inCookiep[17], 4);
3491 memcpy(mask, dsp->mask, 11);
3493 /* assume we're doing a star match if it has continued for more
3499 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3500 nextCookie, dsp->cookie, attribute);
3502 userp = smb_GetUser(vcp, inp);
3504 /* try to get the vnode for the path name next */
3505 lock_ObtainMutex(&dsp->mx);
3511 spacep = inp->spacep;
3512 smb_StripLastComponent(spacep->data, NULL, pathp);
3513 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3515 lock_ReleaseMutex(&dsp->mx);
3516 cm_ReleaseUser(userp);
3517 smb_DeleteDirSearch(dsp);
3518 smb_ReleaseDirSearch(dsp);
3519 return CM_ERROR_NOFILES;
3521 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3522 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3525 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3526 cm_ReleaseSCache(scp);
3527 lock_ReleaseMutex(&dsp->mx);
3528 cm_ReleaseUser(userp);
3529 smb_DeleteDirSearch(dsp);
3530 smb_ReleaseDirSearch(dsp);
3531 if ( WANTS_DFS_PATHNAMES(inp) )
3532 return CM_ERROR_PATH_NOT_COVERED;
3534 return CM_ERROR_BADSHARENAME;
3536 #endif /* DFS_SUPPORT */
3539 /* we need one hold for the entry we just stored into,
3540 * and one for our own processing. When we're done with this
3541 * function, we'll drop the one for our own processing.
3542 * We held it once from the namei call, and so we do another hold
3546 lock_ObtainMutex(&scp->mx);
3547 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3548 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3549 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3550 dsp->flags |= SMB_DIRSEARCH_BULKST;
3552 lock_ReleaseMutex(&scp->mx);
3555 lock_ReleaseMutex(&dsp->mx);
3557 cm_ReleaseUser(userp);
3558 smb_DeleteDirSearch(dsp);
3559 smb_ReleaseDirSearch(dsp);
3563 /* reserves space for parameter; we'll adjust it again later to the
3564 * real count of the # of entries we returned once we've actually
3565 * assembled the directory listing.
3567 smb_SetSMBParm(outp, 0, 0);
3569 /* get the directory size */
3570 lock_ObtainMutex(&scp->mx);
3571 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3572 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3574 lock_ReleaseMutex(&scp->mx);
3575 cm_ReleaseSCache(scp);
3576 cm_ReleaseUser(userp);
3577 smb_DeleteDirSearch(dsp);
3578 smb_ReleaseDirSearch(dsp);
3582 dirLength = scp->length;
3584 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3585 curOffset.HighPart = 0;
3586 curOffset.LowPart = nextCookie;
3587 origOp = op = smb_GetSMBData(outp, NULL);
3588 /* and write out the basic header */
3589 *op++ = 5; /* variable block */
3590 op += 2; /* skip vbl block length; we'll fill it in later */
3594 /* make sure that curOffset.LowPart doesn't point to the first
3595 * 32 bytes in the 2nd through last dir page, and that it doesn't
3596 * point at the first 13 32-byte chunks in the first dir page,
3597 * since those are dir and page headers, and don't contain useful
3600 temp = curOffset.LowPart & (2048-1);
3601 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3602 /* we're in the first page */
3603 if (temp < 13*32) temp = 13*32;
3606 /* we're in a later dir page */
3607 if (temp < 32) temp = 32;
3610 /* make sure the low order 5 bits are zero */
3613 /* now put temp bits back ito curOffset.LowPart */
3614 curOffset.LowPart &= ~(2048-1);
3615 curOffset.LowPart |= temp;
3617 /* check if we've returned all the names that will fit in the
3620 if (returnedNames >= maxCount) {
3621 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3622 returnedNames, maxCount);
3626 /* check if we've passed the dir's EOF */
3627 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3629 /* see if we can use the bufferp we have now; compute in which page
3630 * the current offset would be, and check whether that's the offset
3631 * of the buffer we have. If not, get the buffer.
3633 thyper.HighPart = curOffset.HighPart;
3634 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3635 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3638 buf_Release(bufferp);
3641 lock_ReleaseMutex(&scp->mx);
3642 lock_ObtainRead(&scp->bufCreateLock);
3643 code = buf_Get(scp, &thyper, &bufferp);
3644 lock_ReleaseRead(&scp->bufCreateLock);
3645 lock_ObtainMutex(&dsp->mx);
3647 /* now, if we're doing a star match, do bulk fetching of all of
3648 * the status info for files in the dir.
3651 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3652 lock_ObtainMutex(&scp->mx);
3653 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3654 LargeIntegerGreaterThanOrEqualTo(thyper,
3655 scp->bulkStatProgress)) {
3656 /* Don't bulk stat if risking timeout */
3657 int now = GetCurrentTime();
3658 if (now - req.startTime > 5000) {
3659 scp->bulkStatProgress = thyper;
3660 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3661 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3663 cm_TryBulkStat(scp, &thyper, userp, &req);
3666 lock_ObtainMutex(&scp->mx);
3668 lock_ReleaseMutex(&dsp->mx);
3670 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3674 bufferOffset = thyper;
3676 /* now get the data in the cache */
3678 code = cm_SyncOp(scp, bufferp, userp, &req,
3680 CM_SCACHESYNC_NEEDCALLBACK |
3681 CM_SCACHESYNC_READ);
3683 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3687 if (cm_HaveBuffer(scp, bufferp, 0)) {
3688 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3692 /* otherwise, load the buffer and try again */
3693 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3695 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3696 scp, bufferp, code);
3701 buf_Release(bufferp);
3705 } /* if (wrong buffer) ... */
3707 /* now we have the buffer containing the entry we're interested in; copy
3708 * it out if it represents a non-deleted entry.
3710 entryInDir = curOffset.LowPart & (2048-1);
3711 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3713 /* page header will help tell us which entries are free. Page header
3714 * can change more often than once per buffer, since AFS 3 dir page size
3715 * may be less than (but not more than a buffer package buffer.
3717 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3718 temp &= ~(2048 - 1); /* turn off intra-page bits */
3719 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3721 /* now determine which entry we're looking at in the page. If it is
3722 * free (there's a free bitmap at the start of the dir), we should
3723 * skip these 32 bytes.
3725 slotInPage = (entryInDir & 0x7e0) >> 5;
3726 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3727 /* this entry is free */
3728 numDirChunks = 1; /* only skip this guy */
3732 tp = bufferp->datap + entryInBuffer;
3733 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3735 /* while we're here, compute the next entry's location, too,
3736 * since we'll need it when writing out the cookie into the dir
3739 * XXXX Probably should do more sanity checking.
3741 numDirChunks = cm_NameEntries(dep->name, NULL);
3743 /* compute the offset of the cookie representing the next entry */
3744 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3746 /* Compute 8.3 name if necessary */
3747 actualName = dep->name;
3748 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3749 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3750 actualName = shortName;
3753 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3754 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3755 osi_LogSaveString(smb_logp, actualName));
3757 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3758 /* this is one of the entries to use: it is not deleted
3759 * and it matches the star pattern we're looking for.
3762 /* Eliminate entries that don't match requested
3765 /* no hidden files */
3766 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3767 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3771 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3773 /* We have already done the cm_TryBulkStat above */
3774 fid.cell = scp->fid.cell;
3775 fid.volume = scp->fid.volume;
3776 fid.vnode = ntohl(dep->fid.vnode);
3777 fid.unique = ntohl(dep->fid.unique);
3778 fileType = cm_FindFileType(&fid);
3779 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3780 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3782 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3783 fileType == CM_SCACHETYPE_DFSLINK ||
3784 fileType == CM_SCACHETYPE_INVALID)
3785 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3790 memcpy(op, mask, 11); op += 11;
3791 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3792 *op++ = nextEntryCookie & 0xff;
3793 *op++ = (nextEntryCookie>>8) & 0xff;
3794 *op++ = (nextEntryCookie>>16) & 0xff;
3795 *op++ = (nextEntryCookie>>24) & 0xff;
3796 memcpy(op, &clientCookie, 4); op += 4;
3798 /* now we emit the attribute. This is sort of tricky,
3799 * since we need to really stat the file to find out
3800 * what type of entry we've got. Right now, we're
3801 * copying out data from a buffer, while holding the
3802 * scp locked, so it isn't really convenient to stat
3803 * something now. We'll put in a place holder now,
3804 * and make a second pass before returning this to get
3805 * the real attributes. So, we just skip the data for
3806 * now, and adjust it later. We allocate a patch
3807 * record to make it easy to find this point later.
3808 * The replay will happen at a time when it is safe to
3809 * unlock the directory.
3811 curPatchp = malloc(sizeof(*curPatchp));
3812 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3813 curPatchp->dptr = op;
3814 curPatchp->fid.cell = scp->fid.cell;
3815 curPatchp->fid.volume = scp->fid.volume;
3816 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3817 curPatchp->fid.unique = ntohl(dep->fid.unique);
3819 /* do hidden attribute here since name won't be around when applying
3823 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3824 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3826 curPatchp->flags = 0;
3828 op += 9; /* skip attr, time, date and size */
3830 /* zero out name area. The spec says to pad with
3831 * spaces, but Samba doesn't, and neither do we.
3835 /* finally, we get to copy out the name; we know that
3836 * it fits in 8.3 or the pattern wouldn't match, but it
3837 * never hurts to be sure.
3839 strncpy(op, actualName, 13);
3840 if (smb_StoreAnsiFilenames)
3843 /* Uppercase if requested by client */
3844 if (!KNOWS_LONG_NAMES(inp))
3849 /* now, adjust the # of entries copied */
3851 } /* if we're including this name */
3854 /* and adjust curOffset to be where the new cookie is */
3855 thyper.HighPart = 0;
3856 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3857 curOffset = LargeIntegerAdd(thyper, curOffset);
3858 } /* while copying data for dir listing */
3860 /* release the mutex */
3861 lock_ReleaseMutex(&scp->mx);
3862 if (bufferp) buf_Release(bufferp);
3864 /* apply and free last set of patches; if not doing a star match, this
3865 * will be empty, but better safe (and freeing everything) than sorry.
3867 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3869 /* special return code for unsuccessful search */
3870 if (code == 0 && dataLength < 21 && returnedNames == 0)
3871 code = CM_ERROR_NOFILES;
3873 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3874 returnedNames, code);
3877 smb_DeleteDirSearch(dsp);
3878 smb_ReleaseDirSearch(dsp);
3879 cm_ReleaseSCache(scp);
3880 cm_ReleaseUser(userp);
3884 /* finalize the output buffer */
3885 smb_SetSMBParm(outp, 0, returnedNames);
3886 temp = (long) (op - origOp);
3887 smb_SetSMBDataLength(outp, temp);
3889 /* the data area is a variable block, which has a 5 (already there)
3890 * followed by the length of the # of data bytes. We now know this to
3891 * be "temp," although that includes the 3 bytes of vbl block header.
3892 * Deduct for them and fill in the length field.
3894 temp -= 3; /* deduct vbl block info */
3895 osi_assert(temp == (43 * returnedNames));
3896 origOp[1] = temp & 0xff;
3897 origOp[2] = (temp>>8) & 0xff;
3898 if (returnedNames == 0)
3899 smb_DeleteDirSearch(dsp);
3900 smb_ReleaseDirSearch(dsp);
3901 cm_ReleaseSCache(scp);
3902 cm_ReleaseUser(userp);
3906 /* verify that this is a valid path to a directory. I don't know why they
3907 * don't use the get file attributes call.
3909 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3913 cm_scache_t *rootScp;
3914 cm_scache_t *newScp;
3923 pathp = smb_GetSMBData(inp, NULL);
3924 pathp = smb_ParseASCIIBlock(pathp, NULL);
3926 return CM_ERROR_BADFD;
3927 if (smb_StoreAnsiFilenames)
3928 OemToChar(pathp,pathp);
3929 osi_Log1(smb_logp, "SMB receive check path %s",
3930 osi_LogSaveString(smb_logp, pathp));
3932 rootScp = cm_data.rootSCachep;
3934 userp = smb_GetUser(vcp, inp);
3936 caseFold = CM_FLAG_CASEFOLD;
3938 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3940 cm_ReleaseUser(userp);
3941 return CM_ERROR_NOSUCHPATH;
3943 code = cm_NameI(rootScp, pathp,
3944 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3945 userp, tidPathp, &req, &newScp);
3948 cm_ReleaseUser(userp);
3953 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
3954 cm_ReleaseSCache(newScp);
3955 cm_ReleaseUser(userp);
3956 if ( WANTS_DFS_PATHNAMES(inp) )
3957 return CM_ERROR_PATH_NOT_COVERED;
3959 return CM_ERROR_BADSHARENAME;
3961 #endif /* DFS_SUPPORT */
3963 /* now lock the vnode with a callback; returns with newScp locked */
3964 lock_ObtainMutex(&newScp->mx);
3965 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3966 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3967 if (code && code != CM_ERROR_NOACCESS) {
3968 lock_ReleaseMutex(&newScp->mx);
3969 cm_ReleaseSCache(newScp);
3970 cm_ReleaseUser(userp);
3974 attrs = smb_Attributes(newScp);
3976 if (!(attrs & SMB_ATTR_DIRECTORY))
3977 code = CM_ERROR_NOTDIR;
3979 lock_ReleaseMutex(&newScp->mx);
3981 cm_ReleaseSCache(newScp);
3982 cm_ReleaseUser(userp);
3986 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3990 cm_scache_t *rootScp;
3991 unsigned short attribute;
3993 cm_scache_t *newScp;
4002 /* decode basic attributes we're passed */
4003 attribute = smb_GetSMBParm(inp, 0);
4004 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4006 pathp = smb_GetSMBData(inp, NULL);
4007 pathp = smb_ParseASCIIBlock(pathp, NULL);
4009 return CM_ERROR_BADSMB;
4010 if (smb_StoreAnsiFilenames)
4011 OemToChar(pathp,pathp);
4013 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4014 dosTime, attribute);
4016 rootScp = cm_data.rootSCachep;
4018 userp = smb_GetUser(vcp, inp);
4020 caseFold = CM_FLAG_CASEFOLD;
4022 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4024 cm_ReleaseUser(userp);
4025 return CM_ERROR_NOSUCHFILE;
4027 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4028 tidPathp, &req, &newScp);
4031 cm_ReleaseUser(userp);
4036 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4037 cm_ReleaseSCache(newScp);
4038 cm_ReleaseUser(userp);
4039 if ( WANTS_DFS_PATHNAMES(inp) )
4040 return CM_ERROR_PATH_NOT_COVERED;
4042 return CM_ERROR_BADSHARENAME;
4044 #endif /* DFS_SUPPORT */
4046 /* now lock the vnode with a callback; returns with newScp locked; we
4047 * need the current status to determine what the new status is, in some
4050 lock_ObtainMutex(&newScp->mx);
4051 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4052 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4054 lock_ReleaseMutex(&newScp->mx);
4055 cm_ReleaseSCache(newScp);
4056 cm_ReleaseUser(userp);
4060 /* Check for RO volume */
4061 if (newScp->flags & CM_SCACHEFLAG_RO) {
4062 lock_ReleaseMutex(&newScp->mx);
4063 cm_ReleaseSCache(newScp);
4064 cm_ReleaseUser(userp);
4065 return CM_ERROR_READONLY;
4068 /* prepare for setattr call */
4071 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4072 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4074 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4075 /* we're told to make a writable file read-only */
4076 attr.unixModeBits = newScp->unixModeBits & ~0222;
4077 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4079 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4080 /* we're told to make a read-only file writable */
4081 attr.unixModeBits = newScp->unixModeBits | 0222;
4082 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4084 lock_ReleaseMutex(&newScp->mx);
4086 /* now call setattr */
4088 code = cm_SetAttr(newScp, &attr, userp, &req);
4092 cm_ReleaseSCache(newScp);
4093 cm_ReleaseUser(userp);
4098 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4102 cm_scache_t *rootScp;
4103 cm_scache_t *newScp, *dscp;
4115 pathp = smb_GetSMBData(inp, NULL);
4116 pathp = smb_ParseASCIIBlock(pathp, NULL);
4118 return CM_ERROR_BADSMB;
4120 if (*pathp == 0) /* null path */
4123 if (smb_StoreAnsiFilenames)
4124 OemToChar(pathp,pathp);
4126 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4127 osi_LogSaveString(smb_logp, pathp));
4129 rootScp = cm_data.rootSCachep;
4131 userp = smb_GetUser(vcp, inp);
4133 /* we shouldn't need this for V3 requests, but we seem to */
4134 caseFold = CM_FLAG_CASEFOLD;
4136 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4138 cm_ReleaseUser(userp);
4139 return CM_ERROR_NOSUCHFILE;
4143 * XXX Strange hack XXX
4145 * As of Patch 5 (16 July 97), we are having the following problem:
4146 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4147 * requests to look up "desktop.ini" in all the subdirectories.
4148 * This can cause zillions of timeouts looking up non-existent cells
4149 * and volumes, especially in the top-level directory.
4151 * We have not found any way to avoid this or work around it except
4152 * to explicitly ignore the requests for mount points that haven't
4153 * yet been evaluated and for directories that haven't yet been
4156 * We should modify this hack to provide a fake desktop.ini file
4157 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4159 spacep = inp->spacep;
4160 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4161 #ifndef SPECIAL_FOLDERS
4162 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4163 code = cm_NameI(rootScp, spacep->data,
4164 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4165 userp, tidPathp, &req, &dscp);
4168 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4169 if ( WANTS_DFS_PATHNAMES(inp) )
4170 return CM_ERROR_PATH_NOT_COVERED;
4172 return CM_ERROR_BADSHARENAME;
4174 #endif /* DFS_SUPPORT */
4175 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4176 code = CM_ERROR_NOSUCHFILE;
4177 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4178 cm_buf_t *bp = buf_Find(dscp, &hzero);
4182 code = CM_ERROR_NOSUCHFILE;
4184 cm_ReleaseSCache(dscp);
4186 cm_ReleaseUser(userp);
4191 #endif /* SPECIAL_FOLDERS */
4193 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4194 tidPathp, &req, &newScp);
4196 cm_ReleaseUser(userp);
4201 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4202 cm_ReleaseSCache(newScp);
4203 cm_ReleaseUser(userp);
4204 if ( WANTS_DFS_PATHNAMES(inp) )
4205 return CM_ERROR_PATH_NOT_COVERED;
4207 return CM_ERROR_BADSHARENAME;
4209 #endif /* DFS_SUPPORT */
4211 /* now lock the vnode with a callback; returns with newScp locked */
4212 lock_ObtainMutex(&newScp->mx);
4213 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4214 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4216 lock_ReleaseMutex(&newScp->mx);
4217 cm_ReleaseSCache(newScp);
4218 cm_ReleaseUser(userp);
4223 /* use smb_Attributes instead. Also the fact that a file is
4224 * in a readonly volume doesn't mean it shojuld be marked as RO
4226 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4227 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4228 attrs = SMB_ATTR_DIRECTORY;
4231 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4232 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4234 attrs = smb_Attributes(newScp);
4237 smb_SetSMBParm(outp, 0, attrs);
4239 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4240 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4241 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4242 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4243 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4244 smb_SetSMBParm(outp, 5, 0);
4245 smb_SetSMBParm(outp, 6, 0);
4246 smb_SetSMBParm(outp, 7, 0);
4247 smb_SetSMBParm(outp, 8, 0);
4248 smb_SetSMBParm(outp, 9, 0);
4249 smb_SetSMBDataLength(outp, 0);
4250 lock_ReleaseMutex(&newScp->mx);
4252 cm_ReleaseSCache(newScp);
4253 cm_ReleaseUser(userp);
4258 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4262 osi_Log0(smb_logp, "SMB receive tree disconnect");
4264 /* find the tree and free it */
4265 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4267 lock_ObtainMutex(&tidp->mx);
4268 tidp->flags |= SMB_TIDFLAG_DELETE;
4269 lock_ReleaseMutex(&tidp->mx);
4270 smb_ReleaseTID(tidp);
4276 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4294 pathp = smb_GetSMBData(inp, NULL);
4295 pathp = smb_ParseASCIIBlock(pathp, NULL);
4296 if (smb_StoreAnsiFilenames)
4297 OemToChar(pathp,pathp);
4299 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4301 #ifdef DEBUG_VERBOSE
4305 hexpath = osi_HexifyString( pathp );
4306 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4311 share = smb_GetSMBParm(inp, 0);
4312 attribute = smb_GetSMBParm(inp, 1);
4314 spacep = inp->spacep;
4315 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4316 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4317 /* special case magic file name for receiving IOCTL requests
4318 * (since IOCTL calls themselves aren't getting through).
4320 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4321 smb_SetupIoctlFid(fidp, spacep);
4322 smb_SetSMBParm(outp, 0, fidp->fid);
4323 smb_SetSMBParm(outp, 1, 0); /* attrs */
4324 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4325 smb_SetSMBParm(outp, 3, 0);
4326 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4327 smb_SetSMBParm(outp, 5, 0x7fff);
4328 /* pass the open mode back */
4329 smb_SetSMBParm(outp, 6, (share & 0xf));
4330 smb_SetSMBDataLength(outp, 0);
4331 smb_ReleaseFID(fidp);
4335 userp = smb_GetUser(vcp, inp);
4337 caseFold = CM_FLAG_CASEFOLD;
4339 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4341 cm_ReleaseUser(userp);
4342 return CM_ERROR_NOSUCHPATH;
4344 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4345 tidPathp, &req, &scp);
4348 cm_ReleaseUser(userp);
4353 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4354 cm_ReleaseSCache(scp);
4355 cm_ReleaseUser(userp);
4356 if ( WANTS_DFS_PATHNAMES(inp) )
4357 return CM_ERROR_PATH_NOT_COVERED;
4359 return CM_ERROR_BADSHARENAME;
4361 #endif /* DFS_SUPPORT */
4363 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4365 cm_ReleaseSCache(scp);
4366 cm_ReleaseUser(userp);
4370 /* don't need callback to check file type, since file types never
4371 * change, and namei and cm_Lookup all stat the object at least once on
4372 * a successful return.
4374 if (scp->fileType != CM_SCACHETYPE_FILE) {
4375 cm_ReleaseSCache(scp);
4376 cm_ReleaseUser(userp);
4377 return CM_ERROR_ISDIR;
4380 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4383 /* save a pointer to the vnode */
4386 if ((share & 0xf) == 0)
4387 fidp->flags |= SMB_FID_OPENREAD;
4388 else if ((share & 0xf) == 1)
4389 fidp->flags |= SMB_FID_OPENWRITE;
4391 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4393 lock_ObtainMutex(&scp->mx);
4394 smb_SetSMBParm(outp, 0, fidp->fid);
4395 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4396 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4397 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4398 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4399 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4400 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4401 /* pass the open mode back; XXXX add access checks */
4402 smb_SetSMBParm(outp, 6, (share & 0xf));
4403 smb_SetSMBDataLength(outp, 0);
4404 lock_ReleaseMutex(&scp->mx);
4407 cm_Open(scp, 0, userp);
4409 /* send and free packet */
4410 smb_ReleaseFID(fidp);
4411 cm_ReleaseUser(userp);
4412 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4416 typedef struct smb_unlinkRock {
4421 char *maskp; /* pointer to the star pattern */
4426 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4429 smb_unlinkRock_t *rockp;
4437 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4438 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4439 caseFold |= CM_FLAG_8DOT3;
4441 matchName = dep->name;
4442 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4444 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4445 !cm_Is8Dot3(dep->name)) {
4446 cm_Gen8Dot3Name(dep, shortName, NULL);
4447 matchName = shortName;
4448 /* 8.3 matches are always case insensitive */
4449 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4452 osi_Log1(smb_logp, "Unlinking %s",
4453 osi_LogSaveString(smb_logp, matchName));
4454 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4455 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4456 smb_NotifyChange(FILE_ACTION_REMOVED,
4457 FILE_NOTIFY_CHANGE_FILE_NAME,
4458 dscp, dep->name, NULL, TRUE);
4462 /* If we made a case sensitive exact match, we might as well quit now. */
4463 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4464 code = CM_ERROR_STOPNOW;
4472 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4481 smb_unlinkRock_t rock;
4490 attribute = smb_GetSMBParm(inp, 0);
4492 tp = smb_GetSMBData(inp, NULL);
4493 pathp = smb_ParseASCIIBlock(tp, &tp);
4494 if (smb_StoreAnsiFilenames)
4495 OemToChar(pathp,pathp);
4497 osi_Log1(smb_logp, "SMB receive unlink %s",
4498 osi_LogSaveString(smb_logp, pathp));
4500 spacep = inp->spacep;
4501 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4503 userp = smb_GetUser(vcp, inp);
4505 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4507 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4509 cm_ReleaseUser(userp);
4510 return CM_ERROR_NOSUCHPATH;
4512 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4515 cm_ReleaseUser(userp);
4520 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4521 cm_ReleaseSCache(dscp);
4522 cm_ReleaseUser(userp);
4523 if ( WANTS_DFS_PATHNAMES(inp) )
4524 return CM_ERROR_PATH_NOT_COVERED;
4526 return CM_ERROR_BADSHARENAME;
4528 #endif /* DFS_SUPPORT */
4530 /* otherwise, scp points to the parent directory. */
4537 rock.maskp = smb_FindMask(pathp);
4538 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4541 thyper.HighPart = 0;
4547 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4548 * match. If that fails, we do a case insensitve match.
4550 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4551 !smb_IsStarMask(rock.maskp)) {
4552 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4555 thyper.HighPart = 0;
4556 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4561 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4563 if (code == CM_ERROR_STOPNOW)
4566 cm_ReleaseUser(userp);
4568 cm_ReleaseSCache(dscp);
4570 if (code == 0 && !rock.any)
4571 code = CM_ERROR_NOSUCHFILE;
4575 typedef struct smb_renameRock {
4576 cm_scache_t *odscp; /* old dir */
4577 cm_scache_t *ndscp; /* new dir */
4578 cm_user_t *userp; /* user */
4579 cm_req_t *reqp; /* request struct */
4580 smb_vc_t *vcp; /* virtual circuit */
4581 char *maskp; /* pointer to star pattern of old file name */
4582 int flags; /* tilde, casefold, etc */
4583 char *newNamep; /* ptr to the new file's name */
4586 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4589 smb_renameRock_t *rockp;
4594 rockp = (smb_renameRock_t *) vrockp;
4596 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4597 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4598 caseFold |= CM_FLAG_8DOT3;
4600 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4602 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4603 !cm_Is8Dot3(dep->name)) {
4604 cm_Gen8Dot3Name(dep, shortName, NULL);
4605 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4608 code = cm_Rename(rockp->odscp, dep->name,
4609 rockp->ndscp, rockp->newNamep, rockp->userp,
4611 /* if the call worked, stop doing the search now, since we
4612 * really only want to rename one file.
4615 code = CM_ERROR_STOPNOW;
4624 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4627 cm_space_t *spacep = NULL;
4628 smb_renameRock_t rock;
4629 cm_scache_t *oldDscp = NULL;
4630 cm_scache_t *newDscp = NULL;
4631 cm_scache_t *tmpscp= NULL;
4632 cm_scache_t *tmpscp2 = NULL;
4642 userp = smb_GetUser(vcp, inp);
4643 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4645 cm_ReleaseUser(userp);
4646 return CM_ERROR_NOSUCHPATH;
4650 spacep = inp->spacep;
4651 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4654 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4655 * what actually exists is foo/baz. I don't know why the code used to be
4656 * the way it was. 1/29/96
4658 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4660 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4662 * caseFold = CM_FLAG_CASEFOLD;
4664 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4665 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4666 userp, tidPathp, &req, &oldDscp);
4668 cm_ReleaseUser(userp);
4673 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4674 cm_ReleaseSCache(oldDscp);
4675 cm_ReleaseUser(userp);
4676 if ( WANTS_DFS_PATHNAMES(inp) )
4677 return CM_ERROR_PATH_NOT_COVERED;
4679 return CM_ERROR_BADSHARENAME;
4681 #endif /* DFS_SUPPORT */
4683 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4684 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4685 userp, tidPathp, &req, &newDscp);
4688 cm_ReleaseSCache(oldDscp);
4689 cm_ReleaseUser(userp);
4694 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4695 cm_ReleaseSCache(oldDscp);
4696 cm_ReleaseSCache(newDscp);
4697 cm_ReleaseUser(userp);
4698 if ( WANTS_DFS_PATHNAMES(inp) )
4699 return CM_ERROR_PATH_NOT_COVERED;
4701 return CM_ERROR_BADSHARENAME;
4703 #endif /* DFS_SUPPORT */
4706 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4707 * next, get the component names, and lower case them.
4710 /* handle the old name first */
4712 oldLastNamep = oldPathp;
4716 /* and handle the new name, too */
4718 newLastNamep = newPathp;
4722 /* TODO: The old name could be a wildcard. The new name must not be */
4724 /* do the vnode call */
4725 rock.odscp = oldDscp;
4726 rock.ndscp = newDscp;
4730 rock.maskp = oldLastNamep;
4731 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4732 rock.newNamep = newLastNamep;
4734 /* Check if the file already exists; if so return error */
4735 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4736 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4737 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4738 osi_LogSaveString(afsd_logp, newLastNamep));
4740 /* Check if the old and the new names differ only in case. If so return
4741 * success, else return CM_ERROR_EXISTS
4743 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4745 /* This would be a success only if the old file is *as same as* the new file */
4746 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4748 if (tmpscp == tmpscp2)
4751 code = CM_ERROR_EXISTS;
4752 cm_ReleaseSCache(tmpscp2);
4755 code = CM_ERROR_NOSUCHFILE;
4758 /* file exist, do not rename, also fixes move */
4759 osi_Log0(smb_logp, "Can't rename. Target already exists");
4760 code = CM_ERROR_EXISTS;
4764 cm_ReleaseSCache(tmpscp);
4765 cm_ReleaseSCache(newDscp);
4766 cm_ReleaseSCache(oldDscp);
4767 cm_ReleaseUser(userp);
4771 /* Now search the directory for the pattern, and do the appropriate rename when found */
4772 thyper.LowPart = 0; /* search dir from here */
4773 thyper.HighPart = 0;
4775 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4777 if (code == CM_ERROR_STOPNOW)
4780 code = CM_ERROR_NOSUCHFILE;
4782 /* Handle Change Notification */
4784 * Being lazy, not distinguishing between files and dirs in this
4785 * filter, since we'd have to do a lookup.
4787 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4788 if (oldDscp == newDscp) {
4789 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4790 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4791 filter, oldDscp, oldLastNamep,
4792 newLastNamep, TRUE);
4794 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4795 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4796 filter, oldDscp, oldLastNamep,
4798 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4799 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4800 filter, newDscp, newLastNamep,
4805 cm_ReleaseSCache(tmpscp);
4806 cm_ReleaseUser(userp);
4807 cm_ReleaseSCache(oldDscp);
4808 cm_ReleaseSCache(newDscp);
4813 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4816 cm_space_t *spacep = NULL;
4817 cm_scache_t *oldDscp = NULL;
4818 cm_scache_t *newDscp = NULL;
4819 cm_scache_t *tmpscp= NULL;
4820 cm_scache_t *tmpscp2 = NULL;
4821 cm_scache_t *sscp = NULL;
4830 userp = smb_GetUser(vcp, inp);
4832 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4834 cm_ReleaseUser(userp);
4835 return CM_ERROR_NOSUCHPATH;
4840 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4842 spacep = inp->spacep;
4843 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4845 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4846 userp, tidPathp, &req, &oldDscp);
4848 cm_ReleaseUser(userp);
4853 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4854 cm_ReleaseSCache(oldDscp);
4855 cm_ReleaseUser(userp);
4856 if ( WANTS_DFS_PATHNAMES(inp) )
4857 return CM_ERROR_PATH_NOT_COVERED;
4859 return CM_ERROR_BADSHARENAME;
4861 #endif /* DFS_SUPPORT */
4863 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4864 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4865 userp, tidPathp, &req, &newDscp);
4867 cm_ReleaseSCache(oldDscp);
4868 cm_ReleaseUser(userp);
4873 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4874 cm_ReleaseSCache(newDscp);
4875 cm_ReleaseSCache(oldDscp);
4876 cm_ReleaseUser(userp);
4877 if ( WANTS_DFS_PATHNAMES(inp) )
4878 return CM_ERROR_PATH_NOT_COVERED;
4880 return CM_ERROR_BADSHARENAME;
4882 #endif /* DFS_SUPPORT */
4884 /* Now, although we did two lookups for the two directories (because the same
4885 * directory can be referenced through different paths), we only allow hard links
4886 * within the same directory. */
4887 if (oldDscp != newDscp) {
4888 cm_ReleaseSCache(oldDscp);
4889 cm_ReleaseSCache(newDscp);
4890 cm_ReleaseUser(userp);
4891 return CM_ERROR_CROSSDEVLINK;
4894 /* handle the old name first */
4896 oldLastNamep = oldPathp;
4900 /* and handle the new name, too */
4902 newLastNamep = newPathp;
4906 /* now lookup the old name */
4907 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4908 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4910 cm_ReleaseSCache(oldDscp);
4911 cm_ReleaseSCache(newDscp);
4912 cm_ReleaseUser(userp);
4916 /* Check if the file already exists; if so return error */
4917 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4918 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4919 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4920 osi_LogSaveString(afsd_logp, newLastNamep));
4922 /* if the existing link is to the same file, then we return success */
4924 if(sscp == tmpscp) {
4927 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
4928 code = CM_ERROR_EXISTS;
4933 cm_ReleaseSCache(tmpscp);
4934 cm_ReleaseSCache(sscp);
4935 cm_ReleaseSCache(newDscp);
4936 cm_ReleaseSCache(oldDscp);
4937 cm_ReleaseUser(userp);
4941 /* now create the hardlink */
4942 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
4943 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
4944 osi_Log1(smb_logp," Link returns %d", code);
4946 /* Handle Change Notification */
4948 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
4949 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4950 smb_NotifyChange(FILE_ACTION_ADDED,
4951 filter, newDscp, newLastNamep,
4956 cm_ReleaseSCache(tmpscp);
4957 cm_ReleaseUser(userp);
4958 cm_ReleaseSCache(sscp);
4959 cm_ReleaseSCache(oldDscp);
4960 cm_ReleaseSCache(newDscp);
4965 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4971 tp = smb_GetSMBData(inp, NULL);
4972 oldPathp = smb_ParseASCIIBlock(tp, &tp);
4973 if (smb_StoreAnsiFilenames)
4974 OemToChar(oldPathp,oldPathp);
4975 newPathp = smb_ParseASCIIBlock(tp, &tp);
4976 if (smb_StoreAnsiFilenames)
4977 OemToChar(newPathp,newPathp);
4979 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
4980 osi_LogSaveString(smb_logp, oldPathp),
4981 osi_LogSaveString(smb_logp, newPathp));
4983 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
4988 typedef struct smb_rmdirRock {
4992 char *maskp; /* pointer to the star pattern */
4997 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5000 smb_rmdirRock_t *rockp;
5005 rockp = (smb_rmdirRock_t *) vrockp;
5007 matchName = dep->name;
5008 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5009 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5011 match = (strcmp(matchName, rockp->maskp) == 0);
5013 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5014 !cm_Is8Dot3(dep->name)) {
5015 cm_Gen8Dot3Name(dep, shortName, NULL);
5016 matchName = shortName;
5017 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5020 osi_Log1(smb_logp, "Removing directory %s",
5021 osi_LogSaveString(smb_logp, matchName));
5022 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5023 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5024 smb_NotifyChange(FILE_ACTION_REMOVED,
5025 FILE_NOTIFY_CHANGE_DIR_NAME,
5026 dscp, dep->name, NULL, TRUE);
5035 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5043 smb_rmdirRock_t rock;
5052 tp = smb_GetSMBData(inp, NULL);
5053 pathp = smb_ParseASCIIBlock(tp, &tp);
5054 if (smb_StoreAnsiFilenames)
5055 OemToChar(pathp,pathp);
5057 spacep = inp->spacep;
5058 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5060 userp = smb_GetUser(vcp, inp);
5062 caseFold = CM_FLAG_CASEFOLD;
5064 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5066 cm_ReleaseUser(userp);
5067 return CM_ERROR_NOSUCHPATH;
5069 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5070 userp, tidPathp, &req, &dscp);
5073 cm_ReleaseUser(userp);
5078 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5079 cm_ReleaseSCache(dscp);
5080 cm_ReleaseUser(userp);
5081 if ( WANTS_DFS_PATHNAMES(inp) )
5082 return CM_ERROR_PATH_NOT_COVERED;
5084 return CM_ERROR_BADSHARENAME;
5086 #endif /* DFS_SUPPORT */
5088 /* otherwise, scp points to the parent directory. */
5095 rock.maskp = lastNamep;
5096 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5099 thyper.HighPart = 0;
5103 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5104 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5105 if (code == 0 && !rock.any) {
5107 thyper.HighPart = 0;
5108 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5109 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5112 cm_ReleaseUser(userp);
5114 cm_ReleaseSCache(dscp);
5116 if (code == 0 && !rock.any)
5117 code = CM_ERROR_NOSUCHFILE;
5121 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5131 fid = smb_GetSMBParm(inp, 0);
5133 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5135 fid = smb_ChainFID(fid, inp);
5136 fidp = smb_FindFID(vcp, fid, 0);
5137 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5139 smb_ReleaseFID(fidp);
5140 return CM_ERROR_BADFD;
5143 userp = smb_GetUser(vcp, inp);
5145 lock_ObtainMutex(&fidp->mx);
5146 if (fidp->flags & SMB_FID_OPENWRITE)
5147 code = cm_FSync(fidp->scp, userp, &req);
5150 lock_ReleaseMutex(&fidp->mx);
5152 smb_ReleaseFID(fidp);
5154 cm_ReleaseUser(userp);
5159 struct smb_FullNameRock {
5165 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5169 struct smb_FullNameRock *vrockp;
5171 vrockp = (struct smb_FullNameRock *)rockp;
5173 if (!cm_Is8Dot3(dep->name)) {
5174 cm_Gen8Dot3Name(dep, shortName, NULL);
5176 if (cm_stricmp(shortName, vrockp->name) == 0) {
5177 vrockp->fullName = strdup(dep->name);
5178 return CM_ERROR_STOPNOW;
5181 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5182 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5183 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5184 vrockp->fullName = strdup(dep->name);
5185 return CM_ERROR_STOPNOW;
5190 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5191 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5193 struct smb_FullNameRock rock;
5199 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5200 if (code == CM_ERROR_STOPNOW)
5201 *newPathp = rock.fullName;
5203 *newPathp = strdup(pathp);
5206 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5217 fid = smb_GetSMBParm(inp, 0);
5218 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5220 osi_Log1(smb_logp, "SMB close fid %d", fid);
5222 fid = smb_ChainFID(fid, inp);
5223 fidp = smb_FindFID(vcp, fid, 0);
5225 return CM_ERROR_BADFD;
5228 userp = smb_GetUser(vcp, inp);
5230 lock_ObtainMutex(&fidp->mx);
5232 /* Don't jump the gun on an async raw write */
5233 while (fidp->raw_writers) {
5234 lock_ReleaseMutex(&fidp->mx);
5235 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5236 lock_ObtainMutex(&fidp->mx);
5239 fidp->flags |= SMB_FID_DELETE;
5241 /* watch for ioctl closes, and read-only opens */
5242 if (fidp->scp != NULL &&
5243 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5244 == SMB_FID_OPENWRITE) {
5245 if (dosTime != 0 && dosTime != -1) {
5246 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5247 /* This fixes defect 10958 */
5248 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5249 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5251 code = cm_FSync(fidp->scp, userp, &req);
5256 if (fidp->flags & SMB_FID_DELONCLOSE) {
5257 cm_scache_t *dscp = fidp->NTopen_dscp;
5258 char *pathp = fidp->NTopen_pathp;
5261 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5262 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5263 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5264 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5265 smb_NotifyChange(FILE_ACTION_REMOVED,
5266 FILE_NOTIFY_CHANGE_DIR_NAME,
5267 dscp, fullPathp, NULL, TRUE);
5271 code = cm_Unlink(dscp, fullPathp, userp, &req);
5272 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5273 smb_NotifyChange(FILE_ACTION_REMOVED,
5274 FILE_NOTIFY_CHANGE_FILE_NAME,
5275 dscp, fullPathp, NULL, TRUE);
5279 lock_ReleaseMutex(&fidp->mx);
5281 if (fidp->flags & SMB_FID_NTOPEN) {
5282 cm_ReleaseSCache(fidp->NTopen_dscp);
5283 free(fidp->NTopen_pathp);
5285 if (fidp->NTopen_wholepathp)
5286 free(fidp->NTopen_wholepathp);
5288 smb_ReleaseFID(fidp);
5289 cm_ReleaseUser(userp);
5294 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5297 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5298 cm_user_t *userp, long *readp)
5300 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5301 cm_user_t *userp, long *readp, int dosflag)
5308 osi_hyper_t fileLength;
5310 osi_hyper_t lastByte;
5311 osi_hyper_t bufferOffset;
5312 long bufIndex, nbytes;
5322 lock_ObtainMutex(&fidp->mx);
5324 lock_ObtainMutex(&scp->mx);
5326 if (offset.HighPart == 0) {
5327 chunk = offset.LowPart >> cm_logChunkSize;
5328 if (chunk != fidp->curr_chunk) {
5329 fidp->prev_chunk = fidp->curr_chunk;
5330 fidp->curr_chunk = chunk;
5332 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5336 /* start by looking up the file's end */
5337 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5338 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5339 if (code) goto done;
5341 /* now we have the entry locked, look up the length */
5342 fileLength = scp->length;
5344 /* adjust count down so that it won't go past EOF */
5345 thyper.LowPart = count;
5346 thyper.HighPart = 0;
5347 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5349 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5350 /* we'd read past EOF, so just stop at fileLength bytes.
5351 * Start by computing how many bytes remain in the file.
5353 thyper = LargeIntegerSubtract(fileLength, offset);
5355 /* if we are past EOF, read 0 bytes */
5356 if (LargeIntegerLessThanZero(thyper))
5359 count = thyper.LowPart;
5364 /* now, copy the data one buffer at a time,
5365 * until we've filled the request packet
5368 /* if we've copied all the data requested, we're done */
5369 if (count <= 0) break;
5371 /* otherwise, load up a buffer of data */
5372 thyper.HighPart = offset.HighPart;
5373 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5374 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5377 buf_Release(bufferp);
5380 lock_ReleaseMutex(&scp->mx);
5382 lock_ObtainRead(&scp->bufCreateLock);
5383 code = buf_Get(scp, &thyper, &bufferp);
5384 lock_ReleaseRead(&scp->bufCreateLock);
5386 lock_ObtainMutex(&scp->mx);
5387 if (code) goto done;
5388 bufferOffset = thyper;
5390 /* now get the data in the cache */
5392 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5393 CM_SCACHESYNC_NEEDCALLBACK |
5394 CM_SCACHESYNC_READ);
5395 if (code) goto done;
5397 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5399 /* otherwise, load the buffer and try again */
5400 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5404 buf_Release(bufferp);
5408 } /* if (wrong buffer) ... */
5410 /* now we have the right buffer loaded. Copy out the
5411 * data from here to the user's buffer.
5413 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5415 /* and figure out how many bytes we want from this buffer */
5416 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5417 if (nbytes > count) nbytes = count; /* don't go past EOF */
5419 /* now copy the data */
5422 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5425 memcpy(op, bufferp->datap + bufIndex, nbytes);
5427 /* adjust counters, pointers, etc. */
5430 thyper.LowPart = nbytes;
5431 thyper.HighPart = 0;
5432 offset = LargeIntegerAdd(thyper, offset);
5436 lock_ReleaseMutex(&scp->mx);
5437 lock_ReleaseMutex(&fidp->mx);
5439 buf_Release(bufferp);
5441 if (code == 0 && sequential)
5442 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5448 * smb_WriteData -- common code for Write and Raw Write
5451 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5452 cm_user_t *userp, long *writtenp)
5454 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5455 cm_user_t *userp, long *writtenp, int dosflag)
5462 osi_hyper_t fileLength; /* file's length at start of write */
5463 osi_hyper_t minLength; /* don't read past this */
5464 long nbytes; /* # of bytes to transfer this iteration */
5466 osi_hyper_t thyper; /* hyper tmp variable */
5467 osi_hyper_t bufferOffset;
5468 long bufIndex; /* index in buffer where our data is */
5470 osi_hyper_t writeBackOffset;/* offset of region to write back when
5475 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5476 fidp->fid, offsetp->LowPart, count);
5486 lock_ObtainMutex(&fidp->mx);
5488 lock_ObtainMutex(&scp->mx);
5490 /* start by looking up the file's end */
5491 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5493 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5494 CM_SCACHESYNC_NEEDCALLBACK
5495 | CM_SCACHESYNC_SETSTATUS
5496 | CM_SCACHESYNC_GETSTATUS);
5497 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5502 /* make sure we have a writable FD */
5503 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5504 code = CM_ERROR_BADFDOP;
5508 /* now we have the entry locked, look up the length */
5509 fileLength = scp->length;
5510 minLength = fileLength;
5511 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5512 minLength = scp->serverLength;
5514 /* adjust file length if we extend past EOF */
5515 thyper.LowPart = count;
5516 thyper.HighPart = 0;
5517 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5518 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5519 /* we'd write past EOF, so extend the file */
5520 scp->mask |= CM_SCACHEMASK_LENGTH;
5521 scp->length = thyper;
5522 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5524 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5526 /* now, if the new position (thyper) and the old (offset) are in
5527 * different storeback windows, remember to store back the previous
5528 * storeback window when we're done with the write.
5530 if ((thyper.LowPart & (-cm_chunkSize)) !=
5531 (offset.LowPart & (-cm_chunkSize))) {
5532 /* they're different */
5534 writeBackOffset.HighPart = offset.HighPart;
5535 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5540 /* now, copy the data one buffer at a time, until we've filled the
5543 /* if we've copied all the data requested, we're done */
5547 /* handle over quota or out of space */
5548 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5549 *writtenp = written;
5550 code = CM_ERROR_QUOTA;
5554 /* otherwise, load up a buffer of data */
5555 thyper.HighPart = offset.HighPart;
5556 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5557 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5560 lock_ReleaseMutex(&bufferp->mx);
5561 buf_Release(bufferp);
5564 lock_ReleaseMutex(&scp->mx);
5566 lock_ObtainRead(&scp->bufCreateLock);
5567 code = buf_Get(scp, &thyper, &bufferp);
5568 lock_ReleaseRead(&scp->bufCreateLock);
5570 lock_ObtainMutex(&bufferp->mx);
5571 lock_ObtainMutex(&scp->mx);
5572 if (code) goto done;
5574 bufferOffset = thyper;
5576 /* now get the data in the cache */
5578 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5580 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5581 CM_SCACHESYNC_NEEDCALLBACK
5582 | CM_SCACHESYNC_WRITE
5583 | CM_SCACHESYNC_BUFLOCKED);
5584 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5589 /* If we're overwriting the entire buffer, or
5590 * if we're writing at or past EOF, mark the
5591 * buffer as current so we don't call
5592 * cm_GetBuffer. This skips the fetch from the
5593 * server in those cases where we're going to
5594 * obliterate all the data in the buffer anyway,
5595 * or in those cases where there is no useful
5596 * data at the server to start with.
5598 * Use minLength instead of scp->length, since
5599 * the latter has already been updated by this
5602 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5603 || LargeIntegerEqualTo(offset, bufferp->offset)
5604 && (count >= cm_data.buf_blockSize
5605 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5606 ConvertLongToLargeInteger(count)),
5608 if (count < cm_data.buf_blockSize
5609 && bufferp->dataVersion == -1)
5610 memset(bufferp->datap, 0,
5611 cm_data.buf_blockSize);
5612 bufferp->dataVersion = scp->dataVersion;
5615 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5617 /* otherwise, load the buffer and try again */
5618 lock_ReleaseMutex(&bufferp->mx);
5619 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5621 lock_ReleaseMutex(&scp->mx);
5622 lock_ObtainMutex(&bufferp->mx);
5623 lock_ObtainMutex(&scp->mx);
5627 lock_ReleaseMutex(&bufferp->mx);
5628 buf_Release(bufferp);
5632 } /* if (wrong buffer) ... */
5634 /* now we have the right buffer loaded. Copy out the
5635 * data from here to the user's buffer.
5637 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5639 /* and figure out how many bytes we want from this buffer */
5640 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5642 nbytes = count; /* don't go past end of request */
5644 /* now copy the data */
5647 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5650 memcpy(bufferp->datap + bufIndex, op, nbytes);
5651 buf_SetDirty(bufferp);
5653 /* and record the last writer */
5654 if (bufferp->userp != userp) {
5657 cm_ReleaseUser(bufferp->userp);
5658 bufferp->userp = userp;
5661 /* adjust counters, pointers, etc. */
5665 thyper.LowPart = nbytes;
5666 thyper.HighPart = 0;
5667 offset = LargeIntegerAdd(thyper, offset);
5671 lock_ReleaseMutex(&scp->mx);
5672 lock_ReleaseMutex(&fidp->mx);
5674 lock_ReleaseMutex(&bufferp->mx);
5675 buf_Release(bufferp);
5678 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5679 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5680 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5681 fidp->NTopen_dscp, fidp->NTopen_pathp,
5685 if (code == 0 && doWriteBack) {
5687 lock_ObtainMutex(&scp->mx);
5688 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5690 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5691 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5693 lock_ReleaseMutex(&scp->mx);
5694 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5695 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5698 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5699 fidp->fid, code, *writtenp);
5703 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5706 long count, written = 0, total_written = 0;
5711 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5713 int inDataBlockCount;
5715 fd = smb_GetSMBParm(inp, 0);
5716 count = smb_GetSMBParm(inp, 1);
5717 offset.HighPart = 0; /* too bad */
5718 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5720 op = smb_GetSMBData(inp, NULL);
5721 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5723 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5724 fd, offset.LowPart, count);
5726 fd = smb_ChainFID(fd, inp);
5727 fidp = smb_FindFID(vcp, fd, 0);
5729 return CM_ERROR_BADFD;
5732 if (fidp->flags & SMB_FID_IOCTL)
5733 return smb_IoctlWrite(fidp, vcp, inp, outp);
5735 userp = smb_GetUser(vcp, inp);
5737 /* special case: 0 bytes transferred means truncate to this position */
5743 truncAttr.mask = CM_ATTRMASK_LENGTH;
5744 truncAttr.length.LowPart = offset.LowPart;
5745 truncAttr.length.HighPart = 0;
5746 lock_ObtainMutex(&fidp->mx);
5747 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5748 lock_ReleaseMutex(&fidp->mx);
5749 smb_SetSMBParm(outp, 0, /* count */ 0);
5750 smb_SetSMBDataLength(outp, 0);
5751 fidp->flags |= SMB_FID_LENGTHSETDONE;
5756 * Work around bug in NT client
5758 * When copying a file, the NT client should first copy the data,
5759 * then copy the last write time. But sometimes the NT client does
5760 * these in the wrong order, so the data copies would inadvertently
5761 * cause the last write time to be overwritten. We try to detect this,
5762 * and don't set client mod time if we think that would go against the
5765 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5766 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5767 fidp->scp->clientModTime = time(NULL);
5771 while ( code == 0 && count > 0 ) {
5773 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5775 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5777 if (code == 0 && written == 0)
5778 code = CM_ERROR_PARTIALWRITE;
5780 offset.LowPart += written;
5782 total_written += written;
5786 /* set the packet data length to 3 bytes for the data block header,
5787 * plus the size of the data.
5789 smb_SetSMBParm(outp, 0, total_written);
5790 smb_SetSMBDataLength(outp, 0);
5793 smb_ReleaseFID(fidp);
5794 cm_ReleaseUser(userp);
5799 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5800 NCB *ncbp, raw_write_cont_t *rwcp)
5813 fd = smb_GetSMBParm(inp, 0);
5814 fidp = smb_FindFID(vcp, fd, 0);
5816 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5817 rwcp->offset.LowPart, rwcp->count);
5819 userp = smb_GetUser(vcp, inp);
5823 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5826 rawBuf = (dos_ptr) rwcp->buf;
5827 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5828 (unsigned char *) rawBuf, userp,
5832 if (rwcp->writeMode & 0x1) { /* synchronous */
5835 smb_FormatResponsePacket(vcp, inp, outp);
5836 op = (smb_t *) outp;
5837 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5838 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5839 smb_SetSMBDataLength(outp, 0);
5840 smb_SendPacket(vcp, outp);
5841 smb_FreePacket(outp);
5843 else { /* asynchronous */
5844 lock_ObtainMutex(&fidp->mx);
5845 fidp->raw_writers--;
5846 if (fidp->raw_writers == 0)
5847 thrd_SetEvent(fidp->raw_write_event);
5848 lock_ReleaseMutex(&fidp->mx);
5851 /* Give back raw buffer */
5852 lock_ObtainMutex(&smb_RawBufLock);
5854 *((char **)rawBuf) = smb_RawBufs;
5856 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5858 smb_RawBufs = rawBuf;
5859 lock_ReleaseMutex(&smb_RawBufLock);
5861 smb_ReleaseFID(fidp);
5862 cm_ReleaseUser(userp);
5865 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5870 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5873 long count, written = 0, total_written = 0;
5880 unsigned short writeMode;
5887 fd = smb_GetSMBParm(inp, 0);
5888 totalCount = smb_GetSMBParm(inp, 1);
5889 count = smb_GetSMBParm(inp, 10);
5890 offset.HighPart = 0; /* too bad */
5891 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5892 writeMode = smb_GetSMBParm(inp, 7);
5894 op = (char *) inp->data;
5895 op += smb_GetSMBParm(inp, 11);
5898 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5899 fd, offset.LowPart, count, writeMode);
5901 fd = smb_ChainFID(fd, inp);
5902 fidp = smb_FindFID(vcp, fd, 0);
5904 return CM_ERROR_BADFD;
5907 userp = smb_GetUser(vcp, inp);
5910 * Work around bug in NT client
5912 * When copying a file, the NT client should first copy the data,
5913 * then copy the last write time. But sometimes the NT client does
5914 * these in the wrong order, so the data copies would inadvertently
5915 * cause the last write time to be overwritten. We try to detect this,
5916 * and don't set client mod time if we think that would go against the
5919 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5920 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5921 fidp->scp->clientModTime = time(NULL);
5925 while ( code == 0 && count > 0 ) {
5927 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5929 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5931 if (code == 0 && written == 0)
5932 code = CM_ERROR_PARTIALWRITE;
5934 offset.LowPart += written;
5936 total_written += written;
5940 /* Get a raw buffer */
5943 lock_ObtainMutex(&smb_RawBufLock);
5945 /* Get a raw buf, from head of list */
5946 rawBuf = smb_RawBufs;
5948 smb_RawBufs = *(char **)smb_RawBufs;
5950 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5954 code = CM_ERROR_USESTD;
5956 lock_ReleaseMutex(&smb_RawBufLock);
5959 /* Don't allow a premature Close */
5960 if (code == 0 && (writeMode & 1) == 0) {
5961 lock_ObtainMutex(&fidp->mx);
5962 fidp->raw_writers++;
5963 thrd_ResetEvent(fidp->raw_write_event);
5964 lock_ReleaseMutex(&fidp->mx);
5967 smb_ReleaseFID(fidp);
5968 cm_ReleaseUser(userp);
5971 smb_SetSMBParm(outp, 0, total_written);
5972 smb_SetSMBDataLength(outp, 0);
5973 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5980 rwcp->offset.HighPart = 0;
5981 rwcp->offset.LowPart = offset.LowPart + count;
5982 rwcp->count = totalCount - count;
5983 rwcp->writeMode = writeMode;
5984 rwcp->alreadyWritten = total_written;
5986 /* set the packet data length to 3 bytes for the data block header,
5987 * plus the size of the data.
5989 smb_SetSMBParm(outp, 0, 0xffff);
5990 smb_SetSMBDataLength(outp, 0);
5995 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5998 long count, finalCount;
6005 fd = smb_GetSMBParm(inp, 0);
6006 count = smb_GetSMBParm(inp, 1);
6007 offset.HighPart = 0; /* too bad */
6008 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6010 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6011 fd, offset.LowPart, count);
6013 fd = smb_ChainFID(fd, inp);
6014 fidp = smb_FindFID(vcp, fd, 0);
6016 return CM_ERROR_BADFD;
6019 if (fidp->flags & SMB_FID_IOCTL) {
6020 return smb_IoctlRead(fidp, vcp, inp, outp);
6023 userp = smb_GetUser(vcp, inp);
6025 /* remember this for final results */
6026 smb_SetSMBParm(outp, 0, count);
6027 smb_SetSMBParm(outp, 1, 0);
6028 smb_SetSMBParm(outp, 2, 0);
6029 smb_SetSMBParm(outp, 3, 0);
6030 smb_SetSMBParm(outp, 4, 0);
6032 /* set the packet data length to 3 bytes for the data block header,
6033 * plus the size of the data.
6035 smb_SetSMBDataLength(outp, count+3);
6037 /* get op ptr after putting in the parms, since otherwise we don't
6038 * know where the data really is.
6040 op = smb_GetSMBData(outp, NULL);
6042 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6043 *op++ = 1; /* data block marker */
6044 *op++ = (unsigned char) (count & 0xff);
6045 *op++ = (unsigned char) ((count >> 8) & 0xff);
6048 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6050 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6053 /* fix some things up */
6054 smb_SetSMBParm(outp, 0, finalCount);
6055 smb_SetSMBDataLength(outp, finalCount+3);
6057 smb_ReleaseFID(fidp);
6059 cm_ReleaseUser(userp);
6063 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6070 cm_scache_t *dscp; /* dir we're dealing with */
6071 cm_scache_t *scp; /* file we're creating */
6073 int initialModeBits;
6083 /* compute initial mode bits based on read-only flag in attributes */
6084 initialModeBits = 0777;
6086 tp = smb_GetSMBData(inp, NULL);
6087 pathp = smb_ParseASCIIBlock(tp, &tp);
6088 if (smb_StoreAnsiFilenames)
6089 OemToChar(pathp,pathp);
6091 if (strcmp(pathp, "\\") == 0)
6092 return CM_ERROR_EXISTS;
6094 spacep = inp->spacep;
6095 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6097 userp = smb_GetUser(vcp, inp);
6099 caseFold = CM_FLAG_CASEFOLD;
6101 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6103 cm_ReleaseUser(userp);
6104 return CM_ERROR_NOSUCHPATH;
6107 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6108 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6109 userp, tidPathp, &req, &dscp);
6112 cm_ReleaseUser(userp);
6117 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6118 cm_ReleaseSCache(dscp);
6119 cm_ReleaseUser(userp);
6120 if ( WANTS_DFS_PATHNAMES(inp) )
6121 return CM_ERROR_PATH_NOT_COVERED;
6123 return CM_ERROR_BADSHARENAME;
6125 #endif /* DFS_SUPPORT */
6127 /* otherwise, scp points to the parent directory. Do a lookup, and
6128 * fail if we find it. Otherwise, we do the create.
6134 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6135 if (scp) cm_ReleaseSCache(scp);
6136 if (code != CM_ERROR_NOSUCHFILE) {
6137 if (code == 0) code = CM_ERROR_EXISTS;
6138 cm_ReleaseSCache(dscp);
6139 cm_ReleaseUser(userp);
6143 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6144 setAttr.clientModTime = time(NULL);
6145 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6146 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6147 smb_NotifyChange(FILE_ACTION_ADDED,
6148 FILE_NOTIFY_CHANGE_DIR_NAME,
6149 dscp, lastNamep, NULL, TRUE);
6151 /* we don't need this any longer */
6152 cm_ReleaseSCache(dscp);
6155 /* something went wrong creating or truncating the file */
6156 cm_ReleaseUser(userp);
6160 /* otherwise we succeeded */
6161 smb_SetSMBDataLength(outp, 0);
6162 cm_ReleaseUser(userp);
6167 BOOL smb_IsLegalFilename(char *filename)
6170 * Find the longest substring of filename that does not contain
6171 * any of the chars in illegalChars. If that substring is less
6172 * than the length of the whole string, then one or more of the
6173 * illegal chars is in filename.
6175 if (strcspn(filename, illegalChars) < strlen(filename))
6181 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6189 cm_scache_t *dscp; /* dir we're dealing with */
6190 cm_scache_t *scp; /* file we're creating */
6192 int initialModeBits;
6204 excl = (inp->inCom == 0x03)? 0 : 1;
6206 attributes = smb_GetSMBParm(inp, 0);
6207 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6209 /* compute initial mode bits based on read-only flag in attributes */
6210 initialModeBits = 0666;
6211 if (attributes & 1) initialModeBits &= ~0222;
6213 tp = smb_GetSMBData(inp, NULL);
6214 pathp = smb_ParseASCIIBlock(tp, &tp);
6215 if (smb_StoreAnsiFilenames)
6216 OemToChar(pathp,pathp);
6218 spacep = inp->spacep;
6219 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6221 userp = smb_GetUser(vcp, inp);
6223 caseFold = CM_FLAG_CASEFOLD;
6225 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6227 cm_ReleaseUser(userp);
6228 return CM_ERROR_NOSUCHPATH;
6230 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6231 userp, tidPathp, &req, &dscp);
6234 cm_ReleaseUser(userp);
6239 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6240 cm_ReleaseSCache(dscp);
6241 cm_ReleaseUser(userp);
6242 if ( WANTS_DFS_PATHNAMES(inp) )
6243 return CM_ERROR_PATH_NOT_COVERED;
6245 return CM_ERROR_BADSHARENAME;
6247 #endif /* DFS_SUPPORT */
6249 /* otherwise, scp points to the parent directory. Do a lookup, and
6250 * truncate the file if we find it, otherwise we create the file.
6257 if (!smb_IsLegalFilename(lastNamep))
6258 return CM_ERROR_BADNTFILENAME;
6260 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6261 #ifdef DEBUG_VERBOSE
6264 hexp = osi_HexifyString( lastNamep );
6265 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6270 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6271 if (code && code != CM_ERROR_NOSUCHFILE) {
6272 cm_ReleaseSCache(dscp);
6273 cm_ReleaseUser(userp);
6277 /* if we get here, if code is 0, the file exists and is represented by
6278 * scp. Otherwise, we have to create it.
6282 /* oops, file shouldn't be there */
6283 cm_ReleaseSCache(dscp);
6284 cm_ReleaseSCache(scp);
6285 cm_ReleaseUser(userp);
6286 return CM_ERROR_EXISTS;
6289 setAttr.mask = CM_ATTRMASK_LENGTH;
6290 setAttr.length.LowPart = 0;
6291 setAttr.length.HighPart = 0;
6292 code = cm_SetAttr(scp, &setAttr, userp, &req);
6295 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6296 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6297 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6299 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6300 smb_NotifyChange(FILE_ACTION_ADDED,
6301 FILE_NOTIFY_CHANGE_FILE_NAME,
6302 dscp, lastNamep, NULL, TRUE);
6303 if (!excl && code == CM_ERROR_EXISTS) {
6304 /* not an exclusive create, and someone else tried
6305 * creating it already, then we open it anyway. We
6306 * don't bother retrying after this, since if this next
6307 * fails, that means that the file was deleted after
6308 * we started this call.
6310 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6313 setAttr.mask = CM_ATTRMASK_LENGTH;
6314 setAttr.length.LowPart = 0;
6315 setAttr.length.HighPart = 0;
6316 code = cm_SetAttr(scp, &setAttr, userp, &req);
6321 /* we don't need this any longer */
6322 cm_ReleaseSCache(dscp);
6325 /* something went wrong creating or truncating the file */
6326 if (scp) cm_ReleaseSCache(scp);
6327 cm_ReleaseUser(userp);
6331 /* make sure we only open files */
6332 if (scp->fileType != CM_SCACHETYPE_FILE) {
6333 cm_ReleaseSCache(scp);
6334 cm_ReleaseUser(userp);
6335 return CM_ERROR_ISDIR;
6338 /* now all we have to do is open the file itself */
6339 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6342 /* save a pointer to the vnode */
6345 /* always create it open for read/write */
6346 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6348 smb_ReleaseFID(fidp);
6350 smb_SetSMBParm(outp, 0, fidp->fid);
6351 smb_SetSMBDataLength(outp, 0);
6353 cm_Open(scp, 0, userp);
6355 cm_ReleaseUser(userp);
6356 /* leave scp held since we put it in fidp->scp */
6360 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6373 fd = smb_GetSMBParm(inp, 0);
6374 whence = smb_GetSMBParm(inp, 1);
6375 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6377 /* try to find the file descriptor */
6378 fd = smb_ChainFID(fd, inp);
6379 fidp = smb_FindFID(vcp, fd, 0);
6380 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6381 return CM_ERROR_BADFD;
6384 userp = smb_GetUser(vcp, inp);
6386 lock_ObtainMutex(&fidp->mx);
6388 lock_ObtainMutex(&scp->mx);
6389 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6390 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6393 /* offset from current offset */
6394 offset += fidp->offset;
6396 else if (whence == 2) {
6397 /* offset from current EOF */
6398 offset += scp->length.LowPart;
6400 fidp->offset = offset;
6401 smb_SetSMBParm(outp, 0, offset & 0xffff);
6402 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6403 smb_SetSMBDataLength(outp, 0);
6405 lock_ReleaseMutex(&scp->mx);
6406 lock_ReleaseMutex(&fidp->mx);
6407 smb_ReleaseFID(fidp);
6408 cm_ReleaseUser(userp);
6412 /* dispatch all of the requests received in a packet. Due to chaining, this may
6413 * be more than one request.
6415 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6416 NCB *ncbp, raw_write_cont_t *rwcp)
6420 unsigned long code = 0;
6421 unsigned char *outWctp;
6422 int nparms; /* # of bytes of parameters */
6424 int nbytes; /* bytes of data, excluding count */
6427 unsigned short errCode;
6428 unsigned long NTStatus;
6430 unsigned char errClass;
6431 unsigned int oldGen;
6432 DWORD oldTime, newTime;
6434 /* get easy pointer to the data */
6435 smbp = (smb_t *) inp->data;
6437 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6438 /* setup the basic parms for the initial request in the packet */
6439 inp->inCom = smbp->com;
6440 inp->wctp = &smbp->wct;
6442 inp->ncb_length = ncbp->ncb_length;
6447 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6448 /* log it and discard it */
6453 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6454 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6456 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6457 1, ncbp->ncb_length, ptbuf, inp);
6458 DeregisterEventSource(h);
6460 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6465 /* We are an ongoing op */
6466 thrd_Increment(&ongoingOps);
6468 /* set up response packet for receiving output */
6469 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6470 smb_FormatResponsePacket(vcp, inp, outp);
6471 outWctp = outp->wctp;
6473 /* Remember session generation number and time */
6474 oldGen = sessionGen;
6475 oldTime = GetCurrentTime();
6477 while (inp->inCom != 0xff) {
6478 dp = &smb_dispatchTable[inp->inCom];
6480 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6481 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6482 code = outp->resumeCode;
6486 /* process each request in the packet; inCom, wctp and inCount
6487 * are already set up.
6489 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6492 /* now do the dispatch */
6493 /* start by formatting the response record a little, as a default */
6494 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6496 outWctp[1] = 0xff; /* no operation */
6497 outWctp[2] = 0; /* padding */
6502 /* not a chained request, this is a more reasonable default */
6503 outWctp[0] = 0; /* wct of zero */
6504 outWctp[1] = 0; /* and bcc (word) of zero */
6508 /* once set, stays set. Doesn't matter, since we never chain
6509 * "no response" calls.
6511 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6515 /* we have a recognized operation */
6517 if (inp->inCom == 0x1d)
6519 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6522 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp 0x%x lana %d lsn %d",(int)vcp,vcp->lana,vcp->lsn);
6523 osi_Log4(smb_logp,"Dispatch %s vcp 0x%x lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6524 code = (*(dp->procp)) (vcp, inp, outp);
6525 osi_LogEvent("AFS Dispatch return",NULL,"Code 0x%x",(code==0)?0:code-CM_ERROR_BASE);
6526 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%x lana %d lsn %d",(code==0)?0:code-CM_ERROR_BASE,vcp,vcp->lana,vcp->lsn);
6528 if ( code == CM_ERROR_BADSMB ||
6529 code == CM_ERROR_BADOP )
6531 #endif /* LOG_PACKET */
6534 if (oldGen != sessionGen) {
6539 newTime = GetCurrentTime();
6540 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6541 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6542 newTime - oldTime, ncbp->ncb_length);
6544 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6545 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6546 DeregisterEventSource(h);
6548 osi_Log1(smb_logp, "Pkt straddled session startup, "
6549 "ncb length %d", ncbp->ncb_length);
6553 /* bad opcode, fail the request, after displaying it */
6554 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6557 #endif /* LOG_PACKET */
6561 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6562 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6563 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6564 if (code == IDCANCEL)
6568 code = CM_ERROR_BADOP;
6571 /* catastrophic failure: log as much as possible */
6572 if (code == CM_ERROR_BADSMB) {
6579 "Invalid SMB, ncb_length %d",
6582 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6583 sprintf(s, "Invalid SMB message, length %d",
6586 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6587 1, ncbp->ncb_length, ptbuf, smbp);
6588 DeregisterEventSource(h);
6591 #endif /* LOG_PACKET */
6593 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6596 code = CM_ERROR_INVAL;
6599 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6600 thrd_Decrement(&ongoingOps);
6605 /* now, if we failed, turn the current response into an empty
6606 * one, and fill in the response packet's error code.
6609 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6610 smb_MapNTError(code, &NTStatus);
6611 outWctp = outp->wctp;
6612 smbp = (smb_t *) &outp->data;
6613 if (code != CM_ERROR_PARTIALWRITE
6614 && code != CM_ERROR_BUFFERTOOSMALL
6615 && code != CM_ERROR_GSSCONTINUE) {
6616 /* nuke wct and bcc. For a partial
6617 * write or an in-process authentication handshake,
6618 * assume they're OK.
6624 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6625 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6626 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6627 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6628 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6632 smb_MapCoreError(code, vcp, &errCode, &errClass);
6633 outWctp = outp->wctp;
6634 smbp = (smb_t *) &outp->data;
6635 if (code != CM_ERROR_PARTIALWRITE) {
6636 /* nuke wct and bcc. For a partial
6637 * write, assume they're OK.
6643 smbp->errLow = (unsigned char) (errCode & 0xff);
6644 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6645 smbp->rcls = errClass;
6648 } /* error occurred */
6650 /* if we're here, we've finished one request. Look to see if
6651 * this is a chained opcode. If it is, setup things to process
6652 * the chained request, and setup the output buffer to hold the
6653 * chained response. Start by finding the next input record.
6655 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6656 break; /* not a chained req */
6657 tp = inp->wctp; /* points to start of last request */
6658 /* in a chained request, the first two
6659 * parm fields are required, and are
6660 * AndXCommand/AndXReserved and
6662 if (tp[0] < 2) break;
6663 if (tp[1] == 0xff) break; /* no more chained opcodes */
6665 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6668 /* and now append the next output request to the end of this
6669 * last request. Begin by finding out where the last response
6670 * ends, since that's where we'll put our new response.
6672 outWctp = outp->wctp; /* ptr to out parameters */
6673 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6674 nparms = outWctp[0] << 1;
6675 tp = outWctp + nparms + 1; /* now points to bcc field */
6676 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6677 tp += 2 /* for the count itself */ + nbytes;
6678 /* tp now points to the new output record; go back and patch the
6679 * second parameter (off2) to point to the new record.
6681 temp = (unsigned int)tp - ((unsigned int) outp->data);
6682 outWctp[3] = (unsigned char) (temp & 0xff);
6683 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6684 outWctp[2] = 0; /* padding */
6685 outWctp[1] = inp->inCom; /* next opcode */
6687 /* finally, setup for the next iteration */
6690 } /* while loop over all requests in the packet */
6692 /* done logging out, turn off logging-out flag */
6693 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6694 vcp->justLoggedOut = NULL;
6697 free(loggedOutName);
6698 loggedOutName = NULL;
6699 smb_ReleaseUID(loggedOutUserp);
6700 loggedOutUserp = NULL;
6704 /* now send the output packet, and return */
6706 smb_SendPacket(vcp, outp);
6707 thrd_Decrement(&ongoingOps);
6709 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6710 if (active_vcp != vcp) {
6712 smb_ReleaseVC(active_vcp);
6714 "Replacing active_vcp %x with %x", active_vcp, vcp);
6719 last_msg_time = GetCurrentTime();
6720 } else if (active_vcp == vcp) {
6721 smb_ReleaseVC(active_vcp);
6729 /* Wait for Netbios() calls to return, and make the results available to server
6730 * threads. Note that server threads can't wait on the NCBevents array
6731 * themselves, because NCB events are manual-reset, and the servers would race
6732 * each other to reset them.
6734 void smb_ClientWaiter(void *parmp)
6739 while (smbShutdownFlag == 0) {
6740 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6742 if (code == WAIT_OBJECT_0)
6745 /* error checking */
6746 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6748 int abandonIdx = code - WAIT_ABANDONED_0;
6749 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6752 if (code == WAIT_IO_COMPLETION)
6754 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6758 if (code == WAIT_TIMEOUT)
6760 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6763 if (code == WAIT_FAILED)
6765 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6768 idx = code - WAIT_OBJECT_0;
6770 /* check idx range! */
6771 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6773 /* this is fatal - log as much as possible */
6774 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6778 thrd_ResetEvent(NCBevents[idx]);
6779 thrd_SetEvent(NCBreturns[0][idx]);
6785 * Try to have one NCBRECV request waiting for every live session. Not more
6786 * than one, because if there is more than one, it's hard to handle Write Raw.
6788 void smb_ServerWaiter(void *parmp)
6791 int idx_session, idx_NCB;
6797 while (smbShutdownFlag == 0) {
6799 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6801 if (code == WAIT_OBJECT_0)
6804 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6806 int abandonIdx = code - WAIT_ABANDONED_0;
6807 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6810 if (code == WAIT_IO_COMPLETION)
6812 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6816 if (code == WAIT_TIMEOUT)
6818 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6821 if (code == WAIT_FAILED)
6823 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6826 idx_session = code - WAIT_OBJECT_0;
6828 /* check idx range! */
6829 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6831 /* this is fatal - log as much as possible */
6832 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6838 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6840 if (code == WAIT_OBJECT_0) {
6841 if (smbShutdownFlag == 1)
6847 /* error checking */
6848 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6850 int abandonIdx = code - WAIT_ABANDONED_0;
6851 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6854 if (code == WAIT_IO_COMPLETION)
6856 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6860 if (code == WAIT_TIMEOUT)
6862 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6865 if (code == WAIT_FAILED)
6867 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6870 idx_NCB = code - WAIT_OBJECT_0;
6872 /* check idx range! */
6873 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6875 /* this is fatal - log as much as possible */
6876 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6880 /* Link them together */
6881 NCBsessions[idx_NCB] = idx_session;
6884 ncbp = NCBs[idx_NCB];
6885 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6886 ncbp->ncb_command = NCBRECV | ASYNCH;
6887 ncbp->ncb_lana_num = lanas[idx_session];
6889 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6890 ncbp->ncb_event = NCBevents[idx_NCB];
6891 ncbp->ncb_length = SMB_PACKETSIZE;
6894 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6895 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6896 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6897 ncbp->ncb_length = SMB_PACKETSIZE;
6898 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6899 Netbios(ncbp, dos_ncb);
6905 * The top level loop for handling SMB request messages. Each server thread
6906 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6907 * NCB and buffer for the incoming request are loaned to us.
6909 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6910 * to immediately send a request for the rest of the data. This must come
6911 * before any other traffic for that session, so we delay setting the session
6912 * event until that data has come in.
6914 void smb_Server(VOID *parmp)
6916 int myIdx = (int) parmp;
6920 smb_packet_t *outbufp;
6922 int idx_NCB, idx_session;
6924 smb_vc_t *vcp = NULL;
6931 outbufp = GetPacket();
6932 outbufp->ncbp = outncbp;
6935 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6938 /* terminate silently if shutdown flag is set */
6939 if (code == WAIT_OBJECT_0) {
6940 if (smbShutdownFlag == 1) {
6941 thrd_SetEvent(smb_ServerShutdown[myIdx]);
6947 /* error checking */
6948 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6950 int abandonIdx = code - WAIT_ABANDONED_0;
6951 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6954 if (code == WAIT_IO_COMPLETION)
6956 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6960 if (code == WAIT_TIMEOUT)
6962 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6965 if (code == WAIT_FAILED)
6967 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6970 idx_NCB = code - WAIT_OBJECT_0;
6972 /* check idx range! */
6973 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6975 /* this is fatal - log as much as possible */
6976 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
6980 ncbp = NCBs[idx_NCB];
6982 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6984 idx_session = NCBsessions[idx_NCB];
6985 rc = ncbp->ncb_retcode;
6987 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
6990 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
6993 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
6996 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
6999 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
7002 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
7005 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session number out of range", ncbp->ncb_lsn, idx_session);
7008 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
7011 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session closed", ncbp->ncb_lsn, idx_session);
7014 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7017 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7020 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7023 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7026 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local session table full", ncbp->ncb_lsn, idx_session);
7029 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote session table full", ncbp->ncb_lsn, idx_session);
7032 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7035 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7038 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7041 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7044 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7047 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session ended abnormally", ncbp->ncb_lsn, idx_session);
7050 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7053 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7056 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7059 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7062 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7065 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7068 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7071 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7074 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7077 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7080 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7083 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7086 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7089 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7092 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7095 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7098 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7101 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7111 /* Can this happen? Or is it just my UNIX paranoia? */
7112 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7117 /* Client closed session */
7118 dead_sessions[idx_session] = TRUE;
7121 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7122 /* Should also release vcp. [done] 2004-05-11 jaltman
7124 * sanity check that all TID's are gone.
7126 * TODO: check if we could use LSNs[idx_session] instead,
7127 * also cleanup after dead vcp
7130 if (dead_vcp == vcp)
7131 osi_Log1(smb_logp, "dead_vcp already set, 0x%x", dead_vcp);
7132 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7133 osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
7137 smb_ReleaseVC(dead_vcp);
7139 "Previous dead_vcp %x", dead_vcp);
7142 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7144 if (vcp->justLoggedOut) {
7146 loggedOutTime = vcp->logoffTime;
7147 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7148 loggedOutUserp = vcp->justLoggedOut;
7149 lock_ObtainWrite(&smb_rctLock);
7150 loggedOutUserp->refCount++;
7151 lock_ReleaseWrite(&smb_rctLock);
7157 /* Treat as transient error */
7164 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7165 sprintf(s, "SMB message incomplete, length %d",
7168 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
7170 ncbp->ncb_length, ptbuf,
7172 DeregisterEventSource(h);
7175 "dispatch smb recv failed, message incomplete, ncb_length %d",
7178 "SMB message incomplete, "
7179 "length %d", ncbp->ncb_length);
7182 * We used to discard the packet.
7183 * Instead, try handling it normally.
7191 /* A weird error code. Log it, sleep, and
7193 if (vcp && vcp->errorCount++ > 3) {
7194 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7195 dead_sessions[idx_session] = TRUE;
7199 thrd_SetEvent(SessionEvents[idx_session]);
7204 /* Success, so now dispatch on all the data in the packet */
7206 smb_concurrentCalls++;
7207 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7208 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7212 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7214 * If at this point vcp is NULL (implies that packet was invalid)
7215 * then we are in big trouble. This means either :
7216 * a) we have the wrong NCB.
7217 * b) Netbios screwed up the call.
7218 * Obviously this implies that
7219 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7220 * lanas[idx_session] != ncbp->ncb_lana_num )
7221 * Either way, we can't do anything with this packet.
7222 * Log, sleep and resume.
7231 "LSNs[idx_session]=[%d],"
7232 "lanas[idx_session]=[%d],"
7233 "ncbp->ncb_lsn=[%d],"
7234 "ncbp->ncb_lana_num=[%d]",
7238 ncbp->ncb_lana_num);
7242 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7244 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
7245 DeregisterEventSource(h);
7248 /* Also log in the trace log. */
7249 osi_Log4(smb_logp, "Server: BAD VCP!"
7250 "LSNs[idx_session]=[%d],"
7251 "lanas[idx_session]=[%d],"
7252 "ncbp->ncb_lsn=[%d],"
7253 "ncbp->ncb_lana_num=[%d]",
7257 ncbp->ncb_lana_num);
7259 /* thrd_Sleep(1000); Don't bother sleeping */
7260 thrd_SetEvent(SessionEvents[idx_session]);
7261 smb_concurrentCalls--;
7266 vcp->errorCount = 0;
7267 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7269 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7270 /* copy whole packet to virtual memory */
7271 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7273 bufp->dos_pkt / 16, bufp);*/
7275 dosmemget(bufp->dos_pkt, ncbp-d>ncb_length, bufp->data);
7277 smbp = (smb_t *)bufp->data;
7280 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7284 if (smbp->com == 0x1d) {
7285 /* Special handling for Write Raw */
7286 raw_write_cont_t rwc;
7287 EVENT_HANDLE rwevent;
7288 char eventName[MAX_PATH];
7290 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7291 if (rwc.code == 0) {
7292 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7293 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7294 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7295 ncbp->ncb_command = NCBRECV | ASYNCH;
7296 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7297 ncbp->ncb_lana_num = vcp->lana;
7298 ncbp->ncb_buffer = rwc.buf;
7299 ncbp->ncb_length = 65535;
7300 ncbp->ncb_event = rwevent;
7304 Netbios(ncbp, dos_ncb);
7306 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7307 thrd_CloseHandle(rwevent);
7309 thrd_SetEvent(SessionEvents[idx_session]);
7311 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7313 else if (smbp->com == 0xa0) {
7315 * Serialize the handling for NT Transact
7318 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7319 thrd_SetEvent(SessionEvents[idx_session]);
7321 thrd_SetEvent(SessionEvents[idx_session]);
7322 /* TODO: what else needs to be serialized? */
7323 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7325 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7327 __except( smb_ServerExceptionFilter() ) {
7331 smb_concurrentCalls--;
7334 thrd_SetEvent(NCBavails[idx_NCB]);
7341 * Exception filter for the server threads. If an exception occurs in the
7342 * dispatch routines, which is where exceptions are most common, then do a
7343 * force trace and give control to upstream exception handlers. Useful for
7346 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7347 DWORD smb_ServerExceptionFilter(void) {
7348 /* While this is not the best time to do a trace, if it succeeds, then
7349 * we have a trace (assuming tracing was enabled). Otherwise, this should
7350 * throw a second exception.
7355 ptbuf[0] = "Unhandled exception forcing trace";
7357 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7359 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7360 DeregisterEventSource(h);
7363 afsd_ForceTrace(TRUE);
7364 buf_ForceTrace(TRUE);
7365 return EXCEPTION_CONTINUE_SEARCH;
7370 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7371 * If the number of server threads is M, and the number of live sessions is
7372 * N, then the number of NCB's in use at any time either waiting for, or
7373 * holding, received messages is M + N, so that is how many NCB's get created.
7375 void InitNCBslot(int idx)
7377 struct smb_packet *bufp;
7378 EVENT_HANDLE retHandle;
7380 char eventName[MAX_PATH];
7382 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7384 NCBs[idx] = GetNCB();
7385 sprintf(eventName,"NCBavails[%d]", idx);
7386 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7387 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7388 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7390 sprintf(eventName,"NCBevents[%d]", idx);
7391 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7392 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7393 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7395 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7396 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7397 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7398 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7399 for (i=0; i<smb_NumServerThreads; i++)
7400 NCBreturns[i][idx] = retHandle;
7402 bufp->spacep = cm_GetSpace();
7406 /* listen for new connections */
7407 void smb_Listener(void *parmp)
7415 char rname[NCBNAMSZ+1];
7416 char cname[MAX_COMPUTERNAME_LENGTH+1];
7417 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7422 int lana = (int) parmp;
7426 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7429 /* retrieve computer name */
7430 GetComputerName(cname, &cnamelen);
7434 memset(ncbp, 0, sizeof(NCB));
7437 ncbp->ncb_command = NCBLISTEN;
7438 ncbp->ncb_rto = 0; /* No receive timeout */
7439 ncbp->ncb_sto = 0; /* No send timeout */
7441 /* pad out with spaces instead of null termination */
7442 len = strlen(smb_localNamep);
7443 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7444 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7446 strcpy(ncbp->ncb_callname, "*");
7447 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7449 ncbp->ncb_lana_num = lana;
7452 code = Netbios(ncbp);
7454 code = Netbios(ncbp, dos_ncb);
7463 /* terminate silently if shutdown flag is set */
7464 if (smbShutdownFlag == 1) {
7473 "NCBLISTEN lana=%d failed with code %d",
7474 ncbp->ncb_lana_num, code);
7476 "Client exiting due to network failure. Please restart client.\n");
7480 "Client exiting due to network failure. Please restart client.\n"
7481 "NCBLISTEN lana=%d failed with code %d",
7482 ncbp->ncb_lana_num, code);
7484 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7485 MB_OK|MB_SERVICE_NOTIFICATION);
7486 osi_assert(tbuffer);
7489 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7490 ncbp->ncb_lana_num, code);
7491 fprintf(stderr, "\nClient exiting due to network failure "
7492 "(possibly due to power-saving mode)\n");
7493 fprintf(stderr, "Please restart client.\n");
7494 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7498 /* check for remote conns */
7499 /* first get remote name and insert null terminator */
7500 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7501 for (i=NCBNAMSZ; i>0; i--) {
7502 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7508 /* compare with local name */
7510 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7511 flags |= SMB_VCFLAG_REMOTECONN;
7513 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7515 lock_ObtainMutex(&smb_ListenerLock);
7517 /* New generation */
7520 /* Log session startup */
7522 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7524 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7525 #endif /* NOTSERVICE */
7526 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7527 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7529 if (reportSessionStartups) {
7535 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7536 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7538 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7540 DeregisterEventSource(h);
7543 fprintf(stderr, "%s: New session %d starting from host %s\n",
7544 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7548 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7549 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7552 /* now ncbp->ncb_lsn is the connection ID */
7553 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7554 vcp->flags |= flags;
7555 strcpy(vcp->rname, rname);
7557 /* Allocate slot in session arrays */
7558 /* Re-use dead session if possible, otherwise add one more */
7559 /* But don't look at session[0], it is reserved */
7560 for (i = 1; i < numSessions; i++) {
7561 if (dead_sessions[i]) {
7562 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7563 dead_sessions[i] = FALSE;
7568 if (i >= Sessionmax - 1 || numNCBs >= NCBmax - 1) {
7569 unsigned long code = CM_ERROR_ALLBUSY;
7570 smb_packet_t * outp = GetPacket();
7571 unsigned char *outWctp;
7576 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7577 unsigned long NTStatus;
7578 smb_MapNTError(code, &NTStatus);
7579 outWctp = outp->wctp;
7580 smbp = (smb_t *) &outp->data;
7584 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7585 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7586 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7587 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7588 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7590 unsigned short errCode;
7591 unsigned char errClass;
7592 smb_MapCoreError(code, vcp, &errCode, &errClass);
7593 outWctp = outp->wctp;
7594 smbp = (smb_t *) &outp->data;
7598 smbp->errLow = (unsigned char) (errCode & 0xff);
7599 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7600 smbp->rcls = errClass;
7602 smb_SendPacket(vcp, outp);
7603 smb_FreePacket(outp);
7605 /* assert that we do not exceed the maximum number of sessions or NCBs.
7606 * we should probably want to wait for a session to be freed in case
7609 osi_assert(i < Sessionmax - 1);
7610 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7612 LSNs[i] = ncbp->ncb_lsn;
7613 lanas[i] = ncbp->ncb_lana_num;
7615 if (i == numSessions) {
7616 /* Add new NCB for new session */
7617 char eventName[MAX_PATH];
7619 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7621 InitNCBslot(numNCBs);
7623 thrd_SetEvent(NCBavails[0]);
7624 thrd_SetEvent(NCBevents[0]);
7625 for (j = 0; j < smb_NumServerThreads; j++)
7626 thrd_SetEvent(NCBreturns[j][0]);
7627 /* Also add new session event */
7628 sprintf(eventName, "SessionEvents[%d]", i);
7629 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7630 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7631 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7633 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7634 thrd_SetEvent(SessionEvents[0]);
7636 thrd_SetEvent(SessionEvents[i]);
7643 lock_ReleaseMutex(&smb_ListenerLock);
7644 } /* dispatch while loop */
7647 /* initialize Netbios */
7648 void smb_NetbiosInit()
7654 int i, lana, code, l;
7656 int delname_tried=0;
7659 OSVERSIONINFO Version;
7661 /* Get the version of Windows */
7662 memset(&Version, 0x00, sizeof(Version));
7663 Version.dwOSVersionInfoSize = sizeof(Version);
7664 GetVersionEx(&Version);
7666 /* setup the NCB system */
7669 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7673 if (smb_LANadapter == -1) {
7674 ncbp->ncb_command = NCBENUM;
7675 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7676 ncbp->ncb_length = sizeof(lana_list);
7677 code = Netbios(ncbp);
7679 osi_Log1(smb_logp, "Netbios NCBENUM error code %d", code);
7680 osi_panic(s, __FILE__, __LINE__);
7684 lana_list.length = 1;
7685 lana_list.lana[0] = smb_LANadapter;
7688 for (i = 0; i < lana_list.length; i++) {
7689 /* reset the adaptor: in Win32, this is required for every process, and
7690 * acts as an init call, not as a real hardware reset.
7692 ncbp->ncb_command = NCBRESET;
7693 ncbp->ncb_callname[0] = 100;
7694 ncbp->ncb_callname[2] = 100;
7695 ncbp->ncb_lana_num = lana_list.lana[i];
7696 code = Netbios(ncbp);
7698 code = ncbp->ncb_retcode;
7700 osi_Log2(smb_logp, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7701 lana_list.lana[i] = 255; /* invalid lana */
7703 osi_Log1(smb_logp, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7707 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7708 we will just fake the LANA list */
7709 if (smb_LANadapter == -1) {
7710 for (i = 0; i < 8; i++)
7711 lana_list.lana[i] = i;
7712 lana_list.length = 8;
7715 lana_list.length = 1;
7716 lana_list.lana[0] = smb_LANadapter;
7720 /* and declare our name so we can receive connections */
7721 memset(ncbp, 0, sizeof(*ncbp));
7722 len=lstrlen(smb_localNamep);
7723 memset(smb_sharename,' ',NCBNAMSZ);
7724 memcpy(smb_sharename,smb_localNamep,len);
7725 osi_Log1(smb_logp, "lana_list.length %d", lana_list.length);
7727 /* Keep the name so we can unregister it later */
7728 for (l = 0; l < lana_list.length; l++) {
7729 lana = lana_list.lana[l];
7731 ncbp->ncb_command = NCBADDNAME;
7732 ncbp->ncb_lana_num = lana;
7733 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7735 code = Netbios(ncbp);
7737 code = Netbios(ncbp, dos_ncb);
7740 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7741 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7743 char name[NCBNAMSZ+1];
7745 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7746 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7749 if (code == 0) code = ncbp->ncb_retcode;
7751 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7753 /* we only use one LANA with djgpp */
7754 lana_list.lana[0] = lana;
7755 lana_list.length = 1;
7759 osi_Log2(smb_logp, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7760 if (code == NRC_BRIDGE) { /* invalid LANA num */
7761 lana_list.lana[l] = 255;
7764 else if (code == NRC_DUPNAME) {
7765 osi_Log0(smb_logp, "Name already exists; try to delete it");
7766 memset(ncbp, 0, sizeof(*ncbp));
7767 ncbp->ncb_command = NCBDELNAME;
7768 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7769 ncbp->ncb_lana_num = lana;
7771 code = Netbios(ncbp);
7773 code = Netbios(ncbp, dos_ncb);
7776 code = ncbp->ncb_retcode;
7778 osi_Log2(smb_logp, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7780 if (code != 0 || delname_tried) {
7781 lana_list.lana[l] = 255;
7783 else if (code == 0) {
7784 if (!delname_tried) {
7792 osi_Log2(smb_logp, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7793 lana_list.lana[l] = 255; /* invalid lana */
7794 osi_panic(s, __FILE__, __LINE__);
7798 lana_found = 1; /* at least one worked */
7805 osi_assert(lana_list.length >= 0);
7807 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
7810 /* we're done with the NCB now */
7814 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7831 EVENT_HANDLE retHandle;
7832 char eventName[MAX_PATH];
7835 smb_MBfunc = aMBfunc;
7839 smb_LANadapter = LANadapt;
7841 /* Initialize smb_localZero */
7842 myTime.tm_isdst = -1; /* compute whether on DST or not */
7843 myTime.tm_year = 70;
7849 smb_localZero = mktime(&myTime);
7851 /* Initialize kludge-GMT */
7852 smb_CalculateNowTZ();
7854 #ifdef AFS_FREELANCE_CLIENT
7855 /* Make sure the root.afs volume has the correct time */
7856 cm_noteLocalMountPointChange();
7859 /* initialize the remote debugging log */
7862 /* remember the name */
7863 len = strlen(snamep);
7864 smb_localNamep = malloc(len+1);
7865 strcpy(smb_localNamep, snamep);
7866 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7868 /* and the global lock */
7869 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7870 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7872 /* Raw I/O data structures */
7873 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7875 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7877 /* 4 Raw I/O buffers */
7879 smb_RawBufs = calloc(65536,1);
7880 *((char **)smb_RawBufs) = NULL;
7881 for (i=0; i<3; i++) {
7882 char *rawBuf = calloc(65536,1);
7883 *((char **)rawBuf) = smb_RawBufs;
7884 smb_RawBufs = rawBuf;
7887 npar = 65536 >> 4; /* number of paragraphs */
7888 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7890 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7892 osi_panic("",__FILE__,__LINE__);
7895 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7898 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7900 _farpokel(_dos_ds, smb_RawBufs, NULL);
7901 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7902 npar = 65536 >> 4; /* number of paragraphs */
7903 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7905 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7907 osi_panic("",__FILE__,__LINE__);
7910 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7913 rawBuf = (seg * 16) + 0; /* DOS physical address */
7914 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7915 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7916 smb_RawBufs = rawBuf;
7920 /* global free lists */
7921 smb_ncbFreeListp = NULL;
7922 smb_packetFreeListp = NULL;
7926 /* Initialize listener and server structures */
7928 memset(dead_sessions, 0, sizeof(dead_sessions));
7929 sprintf(eventName, "SessionEvents[0]");
7930 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7931 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7932 afsi_log("Event Object Already Exists: %s", eventName);
7934 smb_NumServerThreads = nThreads;
7935 sprintf(eventName, "NCBavails[0]");
7936 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7937 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7938 afsi_log("Event Object Already Exists: %s", eventName);
7939 sprintf(eventName, "NCBevents[0]");
7940 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7941 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7942 afsi_log("Event Object Already Exists: %s", eventName);
7943 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
7944 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7945 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7946 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7947 afsi_log("Event Object Already Exists: %s", eventName);
7948 for (i = 0; i < smb_NumServerThreads; i++) {
7949 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7950 NCBreturns[i][0] = retHandle;
7953 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
7954 for (i = 0; i < smb_NumServerThreads; i++) {
7955 sprintf(eventName, "smb_ServerShutdown[%d]", i);
7956 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7957 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7958 afsi_log("Event Object Already Exists: %s", eventName);
7961 numNCBs = smb_NumServerThreads + 1;
7963 /* Initialize dispatch table */
7964 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7965 /* Prepare the table for unknown operations */
7966 for(i=0; i<= SMB_NOPCODES; i++) {
7967 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7969 /* Fill in the ones we do know */
7970 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
7971 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
7972 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
7973 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
7974 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
7975 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
7976 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
7977 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
7978 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
7979 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
7980 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
7981 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
7982 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
7983 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
7984 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
7985 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
7986 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
7987 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
7988 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
7989 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
7990 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
7991 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7992 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
7993 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
7994 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
7995 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
7996 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
7997 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
7998 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
7999 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8000 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8001 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8002 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8003 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8004 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8005 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8006 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8007 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8008 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8009 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8010 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8011 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8012 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8013 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8014 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8015 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8016 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8017 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8018 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8019 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8020 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8021 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8022 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8023 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8024 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8025 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8026 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8027 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8028 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8029 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8030 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8031 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8032 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8033 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8034 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8035 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8036 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8037 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8038 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8039 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8040 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8041 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8043 /* setup tran 2 dispatch table */
8044 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8045 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8046 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8047 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8048 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8049 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8050 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8051 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8052 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8053 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8054 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8055 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8056 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8057 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8058 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8059 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8060 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8062 /* setup the rap dispatch table */
8063 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8064 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8065 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8066 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8067 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8071 /* if we are doing SMB authentication we have register outselves as a logon process */
8072 if (smb_authType != SMB_AUTH_NONE) {
8073 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8074 LSA_STRING afsProcessName;
8075 LSA_OPERATIONAL_MODE dummy; /*junk*/
8077 afsProcessName.Buffer = "OpenAFSClientDaemon";
8078 afsProcessName.Length = strlen(afsProcessName.Buffer);
8079 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8081 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8083 if (nts == STATUS_SUCCESS) {
8084 LSA_STRING packageName;
8085 /* we are registered. Find out the security package id */
8086 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8087 packageName.Length = strlen(packageName.Buffer);
8088 packageName.MaximumLength = packageName.Length + 1;
8089 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8090 if (nts == STATUS_SUCCESS) {
8092 * This code forces Windows to authenticate against the Logon Cache
8093 * first instead of attempting to authenticate against the Domain
8094 * Controller. When the Windows logon cache is enabled this improves
8095 * performance by removing the network access and works around a bug
8096 * seen at sites which are using a MIT Kerberos principal to login
8097 * to machines joined to a non-root domain in a multi-domain forest.
8099 PVOID pResponse = NULL;
8100 ULONG cbResponse = 0;
8101 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8103 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8104 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8105 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8106 OptionsRequest.DisableOptions = FALSE;
8108 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8111 sizeof(OptionsRequest),
8117 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8119 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8121 OutputDebugString(message);
8122 osi_Log2(smb_logp,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8125 OutputDebugString("MsV1_0SetProcessOption success");
8126 osi_Log0(smb_logp,"MsV1_0SetProcessOption success");
8128 /* END - code from Larry */
8130 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8131 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
8132 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8134 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
8136 /* something went wrong. We report the error and revert back to no authentication
8137 because we can't perform any auth requests without a successful lsa handle
8138 or sec package id. */
8139 afsi_log("Reverting to NO SMB AUTH");
8140 smb_authType = SMB_AUTH_NONE;
8143 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
8145 /* something went wrong. We report the error and revert back to no authentication
8146 because we can't perform any auth requests without a successful lsa handle
8147 or sec package id. */
8148 afsi_log("Reverting to NO SMB AUTH");
8149 smb_authType = SMB_AUTH_NONE;
8153 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8154 * time prevents the failure of authentication when logged into Windows with an
8155 * external Kerberos principal mapped to a local account.
8157 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8158 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8159 * then the only option is NTLMSSP anyway; so just fallback.
8164 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8165 if (secBlobLength == 0) {
8166 smb_authType = SMB_AUTH_NTLM;
8167 afsi_log("Reverting to SMB AUTH NTLM");
8176 /* Now get ourselves a domain name. */
8177 /* For now we are using the local computer name as the domain name.
8178 * It is actually the domain for local logins, and we are acting as
8179 * a local SMB server.
8181 bufsize = sizeof(smb_ServerDomainName) - 1;
8182 GetComputerName(smb_ServerDomainName, &bufsize);
8183 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8184 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8187 /* Start listeners, waiters, servers, and daemons */
8189 for (i = 0; i < lana_list.length; i++) {
8190 if (lana_list.lana[i] == 255)
8192 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8193 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8194 osi_assert(phandle != NULL);
8195 thrd_CloseHandle(phandle);
8199 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8200 NULL, 0, &lpid, "smb_ClientWaiter");
8201 osi_assert(phandle != NULL);
8202 thrd_CloseHandle(phandle);
8205 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8206 NULL, 0, &lpid, "smb_ServerWaiter");
8207 osi_assert(phandle != NULL);
8208 thrd_CloseHandle(phandle);
8210 for (i=0; i<smb_NumServerThreads; i++) {
8211 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8212 (void *) i, 0, &lpid, "smb_Server");
8213 osi_assert(phandle != NULL);
8214 thrd_CloseHandle(phandle);
8217 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8218 NULL, 0, &lpid, "smb_Daemon");
8219 osi_assert(phandle != NULL);
8220 thrd_CloseHandle(phandle);
8222 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8223 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8224 osi_assert(phandle != NULL);
8225 thrd_CloseHandle(phandle);
8234 void smb_Shutdown(void)
8244 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8246 /* setup the NCB system */
8249 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8252 /* Block new sessions by setting shutdown flag */
8253 smbShutdownFlag = 1;
8255 /* Hang up all sessions */
8256 memset((char *)ncbp, 0, sizeof(NCB));
8257 for (i = 1; i < numSessions; i++)
8259 if (dead_sessions[i])
8262 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8263 ncbp->ncb_command = NCBHANGUP;
8264 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8265 ncbp->ncb_lsn = LSNs[i];
8267 code = Netbios(ncbp);
8269 code = Netbios(ncbp, dos_ncb);
8271 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8272 if (code == 0) code = ncbp->ncb_retcode;
8274 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8275 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8279 /* Trigger the shutdown of all SMB threads */
8280 for (i = 0; i < smb_NumServerThreads; i++)
8281 thrd_SetEvent(NCBreturns[i][0]);
8283 thrd_SetEvent(NCBevents[0]);
8284 thrd_SetEvent(SessionEvents[0]);
8285 thrd_SetEvent(NCBavails[0]);
8287 for (i = 0;i < smb_NumServerThreads; i++) {
8288 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8289 if (code == WAIT_OBJECT_0) {
8292 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8293 thrd_SetEvent(NCBreturns[i--][0]);
8297 /* Delete Netbios name */
8298 memset((char *)ncbp, 0, sizeof(NCB));
8299 for (i = 0; i < lana_list.length; i++) {
8300 if (lana_list.lana[i] == 255) continue;
8301 ncbp->ncb_command = NCBDELNAME;
8302 ncbp->ncb_lana_num = lana_list.lana[i];
8303 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8305 code = Netbios(ncbp);
8307 code = Netbios(ncbp, dos_ncb);
8310 code = ncbp->ncb_retcode;
8312 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8313 ncbp->ncb_lana_num, code);
8318 /* Release the reference counts held by the VCs */
8319 lock_ObtainWrite(&smb_rctLock);
8320 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8325 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8327 if (fidp->scp != NULL) {
8330 lock_ObtainMutex(&fidp->mx);
8331 if (fidp->scp != NULL) {
8334 cm_ReleaseSCache(scp);
8336 lock_ReleaseMutex(&fidp->mx);
8340 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8342 smb_ReleaseVCNoLock(tidp->vcp);
8344 cm_user_t *userp = tidp->userp;
8346 lock_ReleaseWrite(&smb_rctLock);
8347 cm_ReleaseUser(userp);
8348 lock_ObtainWrite(&smb_rctLock);
8352 lock_ReleaseWrite(&smb_rctLock);
8355 /* Get the UNC \\<servername>\<sharename> prefix. */
8356 char *smb_GetSharename()
8360 /* Make sure we have been properly initialized. */
8361 if (smb_localNamep == NULL)
8364 /* Allocate space for \\<servername>\<sharename>, plus the
8367 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8368 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8374 void smb_LogPacket(smb_packet_t *packet)
8377 unsigned length, paramlen, datalen, i, j;
8379 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8381 if (!packet) return;
8383 osi_Log0(smb_logp, "*** SMB packet dump ***");
8385 vp = (BYTE *) packet->data;
8387 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8388 length = paramlen + 2 + datalen;
8391 for (i=0;i < length; i+=16)
8393 memset( buf, ' ', 80 );
8398 buf[strlen(buf)] = ' ';
8400 cp = (BYTE*) buf + 7;
8402 for (j=0;j < 16 && (i+j)<length; j++)
8404 *(cp++) = hex[vp[i+j] >> 4];
8405 *(cp++) = hex[vp[i+j] & 0xf];
8415 for (j=0;j < 16 && (i+j)<length;j++)
8417 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8428 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8431 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8433 #endif /* LOG_PACKET */
8436 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8444 lock_ObtainRead(&smb_rctLock);
8446 sprintf(output, "begin dumping smb_vc_t\n");
8447 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8449 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8453 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8454 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8455 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8457 sprintf(output, "begin dumping smb_fid_t\n");
8458 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8460 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8462 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",
8463 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8464 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8465 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8466 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8469 sprintf(output, "done dumping smb_fid_t\n");
8470 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8473 sprintf(output, "done dumping smb_vc_t\n");
8474 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8477 lock_ReleaseRead(&smb_rctLock);