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 #define USE_NUMERIC_TIME_CONV 1
166 #ifndef USE_NUMERIC_TIME_CONV
167 /* Time difference for converting to kludge-GMT */
168 afs_uint32 smb_NowTZ;
169 #endif /* USE_NUMERIC_TIME_CONV */
171 char *smb_localNamep = NULL;
173 smb_vc_t *smb_allVCsp;
175 smb_username_t *usernamesp = NULL;
177 smb_waitingLock_t *smb_allWaitingLocks;
180 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
181 NCB *ncbp, raw_write_cont_t *rwcp);
182 void smb_NetbiosInit();
184 #ifndef AFS_WIN95_ENV
185 DWORD smb_ServerExceptionFilter(void);
188 extern char cm_HostName[];
189 extern char cm_confDir[];
193 #define LPTSTR char *
194 #define GetComputerName(str, sizep) \
195 strcpy((str), cm_HostName); \
196 *(sizep) = strlen(cm_HostName)
200 void smb_LogPacket(smb_packet_t *packet);
201 #endif /* LOG_PACKET */
203 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
204 int smb_ServerDomainNameLength = 0;
205 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
206 int smb_ServerOSLength = sizeof(smb_ServerOS);
207 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
208 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
210 /* Faux server GUID. This is never checked. */
211 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
213 char * myCrt_Dispatch(int i)
218 return "(00)ReceiveCoreMakeDir";
220 return "(01)ReceiveCoreRemoveDir";
222 return "(02)ReceiveCoreOpen";
224 return "(03)ReceiveCoreCreate";
226 return "(04)ReceiveCoreClose";
228 return "(05)ReceiveCoreFlush";
230 return "(06)ReceiveCoreUnlink";
232 return "(07)ReceiveCoreRename";
234 return "(08)ReceiveCoreGetFileAttributes";
236 return "(09)ReceiveCoreSetFileAttributes";
238 return "(0a)ReceiveCoreRead";
240 return "(0b)ReceiveCoreWrite";
242 return "(0c)ReceiveCoreLockRecord";
244 return "(0d)ReceiveCoreUnlockRecord";
246 return "(0e)SendCoreBadOp";
248 return "(0f)ReceiveCoreCreate";
250 return "(10)ReceiveCoreCheckPath";
252 return "(11)SendCoreBadOp";
254 return "(12)ReceiveCoreSeek";
256 return "(1a)ReceiveCoreReadRaw";
258 return "(1d)ReceiveCoreWriteRawDummy";
260 return "(22)ReceiveV3SetAttributes";
262 return "(23)ReceiveV3GetAttributes";
264 return "(24)ReceiveV3LockingX";
266 return "(25)ReceiveV3Trans";
268 return "(26)ReceiveV3Trans[aux]";
270 return "(29)SendCoreBadOp";
272 return "(2b)ReceiveCoreEcho";
274 return "(2d)ReceiveV3OpenX";
276 return "(2e)ReceiveV3ReadX";
278 return "(32)ReceiveV3Tran2A";
280 return "(33)ReceiveV3Tran2A[aux]";
282 return "(34)ReceiveV3FindClose";
284 return "(35)ReceiveV3FindNotifyClose";
286 return "(70)ReceiveCoreTreeConnect";
288 return "(71)ReceiveCoreTreeDisconnect";
290 return "(72)ReceiveNegotiate";
292 return "(73)ReceiveV3SessionSetupX";
294 return "(74)ReceiveV3UserLogoffX";
296 return "(75)ReceiveV3TreeConnectX";
298 return "(80)ReceiveCoreGetDiskAttributes";
300 return "(81)ReceiveCoreSearchDir";
304 return "(83)FindUnique";
306 return "(84)FindClose";
308 return "(A0)ReceiveNTTransact";
310 return "(A2)ReceiveNTCreateX";
312 return "(A4)ReceiveNTCancel";
314 return "(A5)ReceiveNTRename";
316 return "(C0)OpenPrintFile";
318 return "(C1)WritePrintFile";
320 return "(C2)ClosePrintFile";
322 return "(C3)GetPrintQueue";
324 return "(D8)ReadBulk";
326 return "(D9)WriteBulk";
328 return "(DA)WriteBulkData";
330 return "unknown SMB op";
334 char * myCrt_2Dispatch(int i)
339 return "unknown SMB op-2";
341 return "S(00)CreateFile";
343 return "S(01)FindFirst";
345 return "S(02)FindNext"; /* FindNext */
347 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
351 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
353 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
355 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
357 return "S(08)??_ReceiveTran2SetFileInfo";
359 return "S(09)??_ReceiveTran2FSCTL";
361 return "S(0a)_ReceiveTran2IOCTL";
363 return "S(0b)_ReceiveTran2FindNotifyFirst";
365 return "S(0c)_ReceiveTran2FindNotifyNext";
367 return "S(0d)_ReceiveTran2CreateDirectory";
369 return "S(0e)_ReceiveTran2SessionSetup";
371 return "S(10)_ReceiveTran2GetDfsReferral";
373 return "S(11)_ReceiveTran2ReportDfsInconsistency";
377 char * myCrt_RapDispatch(int i)
382 return "unknown RAP OP";
384 return "RAP(0)NetShareEnum";
386 return "RAP(1)NetShareGetInfo";
388 return "RAP(13)NetServerGetInfo";
390 return "RAP(63)NetWkStaGetInfo";
394 /* scache must be locked */
395 unsigned int smb_Attributes(cm_scache_t *scp)
399 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
400 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
401 scp->fileType == CM_SCACHETYPE_INVALID)
403 attrs = SMB_ATTR_DIRECTORY;
404 #ifdef SPECIAL_FOLDERS
405 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
406 #endif /* SPECIAL_FOLDERS */
407 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
408 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
413 * We used to mark a file RO if it was in an RO volume, but that
414 * turns out to be impolitic in NT. See defect 10007.
417 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
418 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
420 if ((scp->unixModeBits & 0222) == 0)
421 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
427 /* Check if the named file/dir is a dotfile/dotdir */
428 /* String pointed to by lastComp can have leading slashes, but otherwise should have
429 no other patch components */
430 unsigned int smb_IsDotFile(char *lastComp) {
433 /* skip over slashes */
434 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
439 /* nulls, curdir and parent dir doesn't count */
445 if(*(s+1) == '.' && !*(s + 2))
452 static int ExtractBits(WORD bits, short start, short len)
459 num = bits << (16 - end);
460 num = num >> ((16 - end) + start);
466 void ShowUnixTime(char *FuncName, time_t unixTime)
471 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
473 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
474 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
476 int day, month, year, sec, min, hour;
479 day = ExtractBits(wDate, 0, 5);
480 month = ExtractBits(wDate, 5, 4);
481 year = ExtractBits(wDate, 9, 7) + 1980;
483 sec = ExtractBits(wTime, 0, 5);
484 min = ExtractBits(wTime, 5, 6);
485 hour = ExtractBits(wTime, 11, 5);
487 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
488 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
494 /* Determine if we are observing daylight savings time */
495 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
497 TIME_ZONE_INFORMATION timeZoneInformation;
498 SYSTEMTIME utc, local, localDST;
500 /* Get the time zone info. NT uses this to calc if we are in DST. */
501 GetTimeZoneInformation(&timeZoneInformation);
503 /* Return the daylight bias */
504 *pDstBias = timeZoneInformation.DaylightBias;
506 /* Return the bias */
507 *pBias = timeZoneInformation.Bias;
509 /* Now determine if DST is being observed */
511 /* Get the UTC (GMT) time */
514 /* Convert UTC time to local time using the time zone info. If we are
515 observing DST, the calculated local time will include this.
517 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
519 /* Set the daylight bias to 0. The daylight bias is the amount of change
520 * in time that we use for daylight savings time. By setting this to 0
521 * we cause there to be no change in time during daylight savings time.
523 timeZoneInformation.DaylightBias = 0;
525 /* Convert the utc time to local time again, but this time without any
526 adjustment for daylight savings time.
528 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
530 /* If the two times are different, then it means that the localDST that
531 we calculated includes the daylight bias, and therefore we are
532 observing daylight savings time.
534 *pDST = localDST.wHour != local.wHour;
537 /* Determine if we are observing daylight savings time */
538 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
544 *pDstBias = -60; /* where can this be different? */
550 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
552 BOOL dst; /* Will be TRUE if observing DST */
553 LONG dstBias; /* Offset from local time if observing DST */
554 LONG bias; /* Offset from GMT for local time */
557 * This function will adjust the last write time to compensate
558 * for two bugs in the smb client:
560 * 1) During Daylight Savings Time, the LastWriteTime is ahead
561 * in time by the DaylightBias (ignoring the sign - the
562 * DaylightBias is always stored as a negative number). If
563 * the DaylightBias is -60, then the LastWriteTime will be
564 * ahead by 60 minutes.
566 * 2) If the local time zone is a positive offset from GMT, then
567 * the LastWriteTime will be the correct local time plus the
568 * Bias (ignoring the sign - a positive offset from GMT is
569 * always stored as a negative Bias). If the Bias is -120,
570 * then the LastWriteTime will be ahead by 120 minutes.
572 * These bugs can occur at the same time.
575 GetTimeZoneInfo(&dst, &dstBias, &bias);
577 /* First adjust for DST */
579 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
581 /* Now adjust for a positive offset from GMT (a negative bias). */
583 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
586 #ifndef USE_NUMERIC_TIME_CONV
588 * Calculate the difference (in seconds) between local time and GMT.
589 * This enables us to convert file times to kludge-GMT.
595 struct tm gmt_tm, local_tm;
596 int days, hours, minutes, seconds;
599 gmt_tm = *(gmtime(&t));
600 local_tm = *(localtime(&t));
602 days = local_tm.tm_yday - gmt_tm.tm_yday;
603 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
604 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
605 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
609 #endif /* USE_NUMERIC_TIME_CONV */
612 #ifdef USE_NUMERIC_TIME_CONV
613 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
615 // Note that LONGLONG is a 64-bit value
618 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
619 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
620 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
623 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
628 time_t ersatz_unixTime;
631 * Must use kludge-GMT instead of real GMT.
632 * kludge-GMT is computed by adding time zone difference to localtime.
635 * ltp = gmtime(&unixTime);
637 ersatz_unixTime = unixTime - smb_NowTZ;
638 ltp = localtime(&ersatz_unixTime);
640 /* if we fail, make up something */
643 localJunk.tm_year = 89 - 20;
644 localJunk.tm_mon = 4;
645 localJunk.tm_mday = 12;
646 localJunk.tm_hour = 0;
647 localJunk.tm_min = 0;
648 localJunk.tm_sec = 0;
651 stm.wYear = ltp->tm_year + 1900;
652 stm.wMonth = ltp->tm_mon + 1;
653 stm.wDayOfWeek = ltp->tm_wday;
654 stm.wDay = ltp->tm_mday;
655 stm.wHour = ltp->tm_hour;
656 stm.wMinute = ltp->tm_min;
657 stm.wSecond = ltp->tm_sec;
658 stm.wMilliseconds = 0;
660 SystemTimeToFileTime(&stm, largeTimep);
662 #endif /* USE_NUMERIC_TIME_CONV */
664 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
666 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
667 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
668 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
670 int leap_years = 89; /* leap years betw 1/1/1601 and 1/1/1970 */
672 /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
673 *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
675 *ft = LargeIntegerMultiplyByLong(*ft, 60);
676 *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
679 ut = ConvertLongToLargeInteger(unixTime);
680 ut = LargeIntegerMultiplyByLong(ut, 10000000);
681 *ft = LargeIntegerAdd(*ft, ut);
686 #ifdef USE_NUMERIC_TIME_CONV
687 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
689 // Note that LONGLONG is a 64-bit value
692 ll = largeTimep->dwHighDateTime;
694 ll += largeTimep->dwLowDateTime;
696 ll -= 116444736000000000;
699 *unixTimep = (DWORD)ll;
701 #else /* USE_NUMERIC_TIME_CONV */
702 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
708 FileTimeToSystemTime(largeTimep, &stm);
710 lt.tm_year = stm.wYear - 1900;
711 lt.tm_mon = stm.wMonth - 1;
712 lt.tm_wday = stm.wDayOfWeek;
713 lt.tm_mday = stm.wDay;
714 lt.tm_hour = stm.wHour;
715 lt.tm_min = stm.wMinute;
716 lt.tm_sec = stm.wSecond;
719 save_timezone = _timezone;
720 _timezone += smb_NowTZ;
721 *unixTimep = mktime(<);
722 _timezone = save_timezone;
724 #endif /* USE_NUMERIC_TIME_CONV */
726 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
728 /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
729 /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
730 LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
734 /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
735 a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
736 a = LargeIntegerMultiplyByLong(a, 60);
737 a = LargeIntegerMultiplyByLong(a, 10000000);
739 /* subtract it from ft */
740 a = LargeIntegerSubtract(*ft, a);
742 /* divide down to seconds */
743 *unixTimep = LargeIntegerDivideByLong(a, 10000000);
747 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
755 ltp = localtime((time_t*) &t);
757 /* if we fail, make up something */
760 localJunk.tm_year = 89 - 20;
761 localJunk.tm_mon = 4;
762 localJunk.tm_mday = 12;
763 localJunk.tm_hour = 0;
764 localJunk.tm_min = 0;
765 localJunk.tm_sec = 0;
768 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
769 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
770 *searchTimep = (dosDate<<16) | dosTime;
773 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
775 unsigned short dosDate;
776 unsigned short dosTime;
779 dosDate = (unsigned short) (searchTime & 0xffff);
780 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
782 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
783 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
784 localTm.tm_mday = (dosDate) & 0x1f;
785 localTm.tm_hour = (dosTime>>11) & 0x1f;
786 localTm.tm_min = (dosTime >> 5) & 0x3f;
787 localTm.tm_sec = (dosTime & 0x1f) * 2;
788 localTm.tm_isdst = -1; /* compute whether DST in effect */
790 *unixTimep = mktime(&localTm);
793 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
795 *dosUTimep = unixTime - smb_localZero;
798 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
801 *unixTimep = dosTime + smb_localZero;
803 /* dosTime seems to be already adjusted for GMT */
804 *unixTimep = dosTime;
808 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
812 lock_ObtainWrite(&smb_rctLock);
813 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
814 if (lsn == vcp->lsn && lana == vcp->lana) {
815 smb_HoldVCNoLock(vcp);
819 if (!vcp && (flags & SMB_FLAG_CREATE)) {
820 vcp = malloc(sizeof(*vcp));
821 memset(vcp, 0, sizeof(*vcp));
822 vcp->vcID = numVCs++;
826 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
827 vcp->nextp = smb_allVCsp;
829 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
834 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
835 /* We must obtain a challenge for extended auth
836 * in case the client negotiates smb v3
838 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
839 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
840 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
841 ULONG lsaRespSize = 0;
843 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
845 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
852 if (nts != STATUS_SUCCESS)
853 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
854 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
855 osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
857 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
858 LsaFreeReturnBuffer(lsaResp);
861 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
863 lock_ReleaseWrite(&smb_rctLock);
867 int smb_IsStarMask(char *maskp)
872 for(i=0; i<11; i++) {
874 if (tc == '?' || tc == '*' || tc == '>') return 1;
879 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
881 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
883 osi_assert(vcp->refCount-- != 0);
889 void smb_ReleaseVC(smb_vc_t *vcp)
891 lock_ObtainWrite(&smb_rctLock);
892 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
894 osi_assert(vcp->refCount-- != 0);
898 lock_ReleaseWrite(&smb_rctLock);
901 void smb_HoldVCNoLock(smb_vc_t *vcp)
904 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
907 void smb_HoldVC(smb_vc_t *vcp)
909 lock_ObtainWrite(&smb_rctLock);
911 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
912 lock_ReleaseWrite(&smb_rctLock);
915 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
919 lock_ObtainWrite(&smb_rctLock);
920 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
921 if (tid == tidp->tid) {
926 if (!tidp && (flags & SMB_FLAG_CREATE)) {
927 tidp = malloc(sizeof(*tidp));
928 memset(tidp, 0, sizeof(*tidp));
929 tidp->nextp = vcp->tidsp;
932 smb_HoldVCNoLock(vcp);
934 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
937 lock_ReleaseWrite(&smb_rctLock);
941 void smb_ReleaseTID(smb_tid_t *tidp)
948 lock_ObtainWrite(&smb_rctLock);
949 osi_assert(tidp->refCount-- > 0);
950 if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
951 ltpp = &tidp->vcp->tidsp;
952 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
956 osi_assert(tp != NULL);
958 lock_FinalizeMutex(&tidp->mx);
959 userp = tidp->userp; /* remember to drop ref later */
961 smb_ReleaseVCNoLock(tidp->vcp);
964 lock_ReleaseWrite(&smb_rctLock);
966 cm_ReleaseUser(userp);
969 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
971 smb_user_t *uidp = NULL;
973 lock_ObtainWrite(&smb_rctLock);
974 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
975 if (uid == uidp->userID) {
977 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",
978 (int)vcp, uidp->userID,
979 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
983 if (!uidp && (flags & SMB_FLAG_CREATE)) {
984 uidp = malloc(sizeof(*uidp));
985 memset(uidp, 0, sizeof(*uidp));
986 uidp->nextp = vcp->usersp;
989 smb_HoldVCNoLock(vcp);
991 lock_InitializeMutex(&uidp->mx, "user_t mutex");
993 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 : ""));
995 lock_ReleaseWrite(&smb_rctLock);
999 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
1001 smb_username_t *unp= NULL;
1003 lock_ObtainWrite(&smb_rctLock);
1004 for(unp = usernamesp; unp; unp = unp->nextp) {
1005 if (stricmp(unp->name, usern) == 0 &&
1006 stricmp(unp->machine, machine) == 0) {
1011 if (!unp && (flags & SMB_FLAG_CREATE)) {
1012 unp = malloc(sizeof(*unp));
1013 memset(unp, 0, sizeof(*unp));
1015 unp->nextp = usernamesp;
1016 unp->name = strdup(usern);
1017 unp->machine = strdup(machine);
1019 lock_InitializeMutex(&unp->mx, "username_t mutex");
1021 lock_ReleaseWrite(&smb_rctLock);
1025 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1027 smb_user_t *uidp= NULL;
1029 lock_ObtainWrite(&smb_rctLock);
1030 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1033 if (stricmp(uidp->unp->name, usern) == 0) {
1035 osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
1040 lock_ReleaseWrite(&smb_rctLock);
1043 void smb_ReleaseUID(smb_user_t *uidp)
1050 lock_ObtainWrite(&smb_rctLock);
1051 osi_assert(uidp->refCount-- > 0);
1052 if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
1053 lupp = &uidp->vcp->usersp;
1054 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1058 osi_assert(up != NULL);
1060 lock_FinalizeMutex(&uidp->mx);
1062 userp = uidp->unp->userp; /* avoid deadlock by releasing */
1063 uidp->unp->userp = NULL; /* after releasing the lock */
1065 smb_ReleaseVCNoLock(uidp->vcp);
1068 lock_ReleaseWrite(&smb_rctLock);
1070 cm_ReleaseUserVCRef(userp);
1071 cm_ReleaseUser(userp);
1076 /* retrieve a held reference to a user structure corresponding to an incoming
1078 * corresponding release function is cm_ReleaseUser.
1080 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
1086 smbp = (smb_t *) inp;
1087 uidp = smb_FindUID(vcp, smbp->uid, 0);
1088 if ((!uidp) || (!uidp->unp))
1091 lock_ObtainMutex(&uidp->mx);
1092 up = uidp->unp->userp;
1094 lock_ReleaseMutex(&uidp->mx);
1096 smb_ReleaseUID(uidp);
1102 * Return a pointer to a pathname extracted from a TID structure. The
1103 * TID structure is not held; assume it won't go away.
1105 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1110 tidp = smb_FindTID(vcp, tid, 0);
1114 if (tidp->flags & SMB_TIDFLAG_IPC) {
1115 code = CM_ERROR_TIDIPC;
1116 /* tidp->pathname would be NULL, but that's fine */
1118 *treepath = tidp->pathname;
1119 smb_ReleaseTID(tidp);
1124 /* check to see if we have a chained fid, that is, a fid that comes from an
1125 * OpenAndX message that ran earlier in this packet. In this case, the fid
1126 * field in a read, for example, request, isn't set, since the value is
1127 * supposed to be inherited from the openAndX call.
1129 int smb_ChainFID(int fid, smb_packet_t *inp)
1131 if (inp->fid == 0 || inp->inCount == 0)
1137 /* are we a priv'd user? What does this mean on NT? */
1138 int smb_SUser(cm_user_t *userp)
1143 /* find a file ID. If we pass in 0 we select an used File ID.
1144 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1145 * smb_fid_t data structure if desired File ID cannot be found.
1147 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1152 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1155 lock_ObtainWrite(&smb_rctLock);
1156 /* figure out if we need to allocate a new file ID */
1159 fid = vcp->fidCounter;
1163 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1164 if (fid == fidp->fid) {
1175 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1176 char eventName[MAX_PATH];
1178 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1179 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1180 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1181 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1182 thrd_CloseHandle(event);
1189 fidp = malloc(sizeof(*fidp));
1190 memset(fidp, 0, sizeof(*fidp));
1191 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1194 smb_HoldVCNoLock(vcp);
1195 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1197 fidp->curr_chunk = fidp->prev_chunk = -2;
1198 fidp->raw_write_event = event;
1200 vcp->fidCounter = fid+1;
1201 if (vcp->fidCounter == 0)
1202 vcp->fidCounter = 1;
1205 lock_ReleaseWrite(&smb_rctLock);
1209 void smb_ReleaseFID(smb_fid_t *fidp)
1212 smb_vc_t *vcp = NULL;
1213 smb_ioctl_t *ioctlp;
1219 lock_ObtainWrite(&smb_rctLock);
1220 osi_assert(fidp->refCount-- > 0);
1221 if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1224 scp = fidp->scp; /* release after lock is released */
1227 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1228 thrd_CloseHandle(fidp->raw_write_event);
1230 /* and see if there is ioctl stuff to free */
1231 ioctlp = fidp->ioctlp;
1234 cm_FreeSpace(ioctlp->prefix);
1235 if (ioctlp->inAllocp)
1236 free(ioctlp->inAllocp);
1237 if (ioctlp->outAllocp)
1238 free(ioctlp->outAllocp);
1244 smb_ReleaseVCNoLock(vcp);
1246 lock_ReleaseWrite(&smb_rctLock);
1248 /* now release the scache structure */
1250 cm_ReleaseSCache(scp);
1254 * Case-insensitive search for one string in another;
1255 * used to find variable names in submount pathnames.
1257 static char *smb_stristr(char *str1, char *str2)
1261 for (cursor = str1; *cursor; cursor++)
1262 if (stricmp(cursor, str2) == 0)
1269 * Substitute a variable value for its name in a submount pathname. Variable
1270 * name has been identified by smb_stristr() and is in substr. Variable name
1271 * length (plus one) is in substr_size. Variable value is in newstr.
1273 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1278 strcpy(temp, substr + substr_size - 1);
1279 strcpy(substr, newstr);
1283 char VNUserName[] = "%USERNAME%";
1284 char VNLCUserName[] = "%LCUSERNAME%";
1285 char VNComputerName[] = "%COMPUTERNAME%";
1286 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1289 /* List available shares */
1290 int smb_ListShares()
1294 char shareBuf[4096];
1302 /*strcpy(shareNameList[num_shares], "all");
1303 strcpy(pathNameList[num_shares++], "/afs");*/
1304 fprintf(stderr, "The following shares are available:\n");
1305 fprintf(stderr, "Share Name (AFS Path)\n");
1306 fprintf(stderr, "---------------------\n");
1307 fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1310 code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1311 if (code == 0 || code > sizeof(sbmtpath)) return -1;
1313 strcpy(sbmtpath, cm_confDir);
1315 strcat(sbmtpath, "/afsdsbmt.ini");
1316 len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1317 shareBuf, sizeof(shareBuf),
1323 this_share = shareBuf;
1327 /*strcpy(shareNameList[num_shares], this_share);*/
1328 len = GetPrivateProfileString("AFS Submounts", this_share,
1335 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1338 if (*p == '\\') *p = '/'; /* change to / */
1342 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1343 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1346 while (*this_share != 0) this_share++; /* find next NUL */
1347 this_share++; /* skip past the NUL */
1348 } while (*this_share != 0); /* stop at final NUL */
1354 typedef struct smb_findShare_rock {
1358 } smb_findShare_rock_t;
1360 #define SMB_FINDSHARE_EXACT_MATCH 1
1361 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1363 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1367 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1368 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1369 if(!stricmp(dep->name, vrock->shareName))
1370 matchType = SMB_FINDSHARE_EXACT_MATCH;
1372 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1373 if(vrock->match) free(vrock->match);
1374 vrock->match = strdup(dep->name);
1375 vrock->matchType = matchType;
1377 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1378 return CM_ERROR_STOPNOW;
1384 /* find a shareName in the table of submounts */
1385 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1389 char pathName[1024];
1394 char sbmtpath[MAX_PATH];
1399 DWORD allSubmount = 1;
1401 /* if allSubmounts == 0, only return the //mountRoot/all share
1402 * if in fact it has been been created in the subMounts table.
1403 * This is to allow sites that want to restrict access to the
1406 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1407 0, KEY_QUERY_VALUE, &parmKey);
1408 if (code == ERROR_SUCCESS) {
1409 len = sizeof(allSubmount);
1410 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1411 (BYTE *) &allSubmount, &len);
1412 if (code != ERROR_SUCCESS) {
1415 RegCloseKey (parmKey);
1418 if (allSubmount && _stricmp(shareName, "all") == 0) {
1423 /* In case, the all share is disabled we need to still be able
1424 * to handle ioctl requests
1426 if (_stricmp(shareName, "ioctl$") == 0) {
1427 *pathNamep = strdup("/.__ioctl__");
1431 if (_stricmp(shareName, "IPC$") == 0 ||
1432 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1433 _stricmp(shareName, "DESKTOP.INI") == 0
1440 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1441 0, KEY_QUERY_VALUE, &parmKey);
1442 if (code == ERROR_SUCCESS) {
1443 len = sizeof(pathName);
1444 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1445 (BYTE *) pathName, &len);
1446 if (code != ERROR_SUCCESS)
1448 RegCloseKey (parmKey);
1453 strcpy(sbmtpath, cm_confDir);
1454 strcat(sbmtpath, "/afsdsbmt.ini");
1455 len = GetPrivateProfileString("AFS Submounts", shareName, "",
1456 pathName, sizeof(pathName), sbmtpath);
1458 if (len != 0 && len != sizeof(pathName) - 1) {
1459 /* We can accept either unix or PC style AFS pathnames. Convert
1460 * Unix-style to PC style here for internal use.
1463 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1464 p += strlen(cm_mountRoot); /* skip mount path */
1467 if (*q == '/') *q = '\\'; /* change to \ */
1473 if (var = smb_stristr(p, VNUserName)) {
1474 if (uidp && uidp->unp)
1475 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1477 smb_subst(p, var, sizeof(VNUserName)," ");
1479 else if (var = smb_stristr(p, VNLCUserName))
1481 if (uidp && uidp->unp)
1482 strcpy(temp, uidp->unp->name);
1486 smb_subst(p, var, sizeof(VNLCUserName), temp);
1488 else if (var = smb_stristr(p, VNComputerName))
1490 sizeTemp = sizeof(temp);
1491 GetComputerName((LPTSTR)temp, &sizeTemp);
1492 smb_subst(p, var, sizeof(VNComputerName), temp);
1494 else if (var = smb_stristr(p, VNLCComputerName))
1496 sizeTemp = sizeof(temp);
1497 GetComputerName((LPTSTR)temp, &sizeTemp);
1499 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1504 *pathNamep = strdup(p);
1509 /* First lookup shareName in root.afs */
1511 smb_findShare_rock_t vrock;
1513 char * p = shareName;
1516 /* attempt to locate a partial match in root.afs. This is because
1517 when using the ANSI RAP calls, the share name is limited to 13 chars
1518 and hence is truncated. Of course we prefer exact matches. */
1520 thyper.HighPart = 0;
1523 vrock.shareName = shareName;
1525 vrock.matchType = 0;
1527 cm_HoldSCache(cm_data.rootSCachep);
1528 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1529 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1530 cm_ReleaseSCache(cm_data.rootSCachep);
1532 if (vrock.matchType) {
1533 sprintf(pathName,"/%s/",vrock.match);
1534 *pathNamep = strdup(strlwr(pathName));
1539 /* if we get here, there was no match for the share in root.afs */
1540 /* so try to create \\<netbiosName>\<cellname> */
1545 /* Get the full name for this cell */
1546 code = cm_SearchCellFile(p, temp, 0, 0);
1547 #ifdef AFS_AFSDB_ENV
1548 if (code && cm_dnsEnabled) {
1550 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1553 /* construct the path */
1555 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1556 *pathNamep = strdup(strlwr(pathName));
1565 /* Client-side offline caching policy types */
1566 #define CSC_POLICY_MANUAL 0
1567 #define CSC_POLICY_DOCUMENTS 1
1568 #define CSC_POLICY_PROGRAMS 2
1569 #define CSC_POLICY_DISABLE 3
1571 int smb_FindShareCSCPolicy(char *shareName)
1577 int retval = CSC_POLICY_MANUAL;
1579 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1580 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1583 REG_OPTION_NON_VOLATILE,
1589 len = sizeof(policy);
1590 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1592 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1594 else if (stricmp(policy, "documents") == 0)
1596 retval = CSC_POLICY_DOCUMENTS;
1598 else if (stricmp(policy, "programs") == 0)
1600 retval = CSC_POLICY_PROGRAMS;
1602 else if (stricmp(policy, "disable") == 0)
1604 retval = CSC_POLICY_DISABLE;
1607 RegCloseKey(hkCSCPolicy);
1611 /* find a dir search structure by cookie value, and return it held.
1612 * Must be called with smb_globalLock held.
1614 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1616 smb_dirSearch_t *dsp;
1618 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1619 if (dsp->cookie == cookie) {
1620 if (dsp != smb_firstDirSearchp) {
1621 /* move to head of LRU queue, too, if we're not already there */
1622 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1623 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1624 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1625 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1626 if (!smb_lastDirSearchp)
1627 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1629 lock_ObtainMutex(&dsp->mx);
1631 lock_ReleaseMutex(&dsp->mx);
1637 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1638 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1639 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1645 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1647 lock_ObtainWrite(&smb_globalLock);
1648 lock_ObtainMutex(&dsp->mx);
1649 dsp->flags |= SMB_DIRSEARCH_DELETE;
1650 if (dsp->scp != NULL) {
1651 lock_ObtainMutex(&dsp->scp->mx);
1652 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1653 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1654 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1655 dsp->scp->bulkStatProgress = hones;
1657 lock_ReleaseMutex(&dsp->scp->mx);
1659 lock_ReleaseMutex(&dsp->mx);
1660 lock_ReleaseWrite(&smb_globalLock);
1663 /* Must be called with the smb_globalLock held */
1664 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1666 cm_scache_t *scp = NULL;
1668 lock_ObtainMutex(&dsp->mx);
1669 osi_assert(dsp->refCount-- > 0);
1670 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1671 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1672 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1673 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1674 lock_ReleaseMutex(&dsp->mx);
1675 lock_FinalizeMutex(&dsp->mx);
1679 lock_ReleaseMutex(&dsp->mx);
1681 /* do this now to avoid spurious locking hierarchy creation */
1682 if (scp) cm_ReleaseSCache(scp);
1685 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1687 lock_ObtainWrite(&smb_globalLock);
1688 smb_ReleaseDirSearchNoLock(dsp);
1689 lock_ReleaseWrite(&smb_globalLock);
1692 /* find a dir search structure by cookie value, and return it held */
1693 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1695 smb_dirSearch_t *dsp;
1697 lock_ObtainWrite(&smb_globalLock);
1698 dsp = smb_FindDirSearchNoLock(cookie);
1699 lock_ReleaseWrite(&smb_globalLock);
1703 /* GC some dir search entries, in the address space expected by the specific protocol.
1704 * Must be called with smb_globalLock held; release the lock temporarily.
1706 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1707 void smb_GCDirSearches(int isV3)
1709 smb_dirSearch_t *prevp;
1710 smb_dirSearch_t *tp;
1711 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1715 victimCount = 0; /* how many have we got so far */
1716 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1717 /* we'll move tp from queue, so
1720 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1721 /* if no one is using this guy, and we're either in the new protocol,
1722 * or we're in the old one and this is a small enough ID to be useful
1723 * to the old protocol, GC this guy.
1725 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1726 /* hold and delete */
1727 tp->flags |= SMB_DIRSEARCH_DELETE;
1728 victimsp[victimCount++] = tp;
1732 /* don't do more than this */
1733 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1737 /* now release them */
1738 for (i = 0; i < victimCount; i++) {
1739 smb_ReleaseDirSearchNoLock(victimsp[i]);
1743 /* function for allocating a dir search entry. We need these to remember enough context
1744 * since we don't get passed the path from call to call during a directory search.
1746 * Returns a held dir search structure, and bumps the reference count on the vnode,
1747 * since it saves a pointer to the vnode.
1749 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1751 smb_dirSearch_t *dsp;
1757 lock_ObtainWrite(&smb_globalLock);
1760 /* what's the biggest ID allowed in this version of the protocol */
1761 maxAllowed = isV3 ? 65535 : 255;
1762 if (smb_dirSearchCounter > maxAllowed)
1763 smb_dirSearchCounter = 1;
1765 start = smb_dirSearchCounter;
1768 /* twice so we have enough tries to find guys we GC after one pass;
1769 * 10 extra is just in case I mis-counted.
1771 if (++counter > 2*maxAllowed+10)
1772 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
1774 if (smb_dirSearchCounter > maxAllowed) {
1775 smb_dirSearchCounter = 1;
1777 if (smb_dirSearchCounter == start) {
1779 smb_GCDirSearches(isV3);
1782 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
1784 /* don't need to watch for refcount zero and deleted, since
1785 * we haven't dropped the global lock.
1787 lock_ObtainMutex(&dsp->mx);
1789 lock_ReleaseMutex(&dsp->mx);
1790 ++smb_dirSearchCounter;
1794 dsp = malloc(sizeof(*dsp));
1795 memset(dsp, 0, sizeof(*dsp));
1796 dsp->cookie = smb_dirSearchCounter;
1797 ++smb_dirSearchCounter;
1799 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1800 dsp->lastTime = osi_Time();
1801 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1802 if (!smb_lastDirSearchp)
1803 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1806 lock_ReleaseWrite(&smb_globalLock);
1810 static smb_packet_t *GetPacket(void)
1814 unsigned int npar, seg, tb_sel;
1817 lock_ObtainWrite(&smb_globalLock);
1818 tbp = smb_packetFreeListp;
1820 smb_packetFreeListp = tbp->nextp;
1821 lock_ReleaseWrite(&smb_globalLock);
1824 tbp = calloc(65540,1);
1826 tbp = malloc(sizeof(smb_packet_t));
1828 tbp->magic = SMB_PACKETMAGIC;
1831 tbp->resumeCode = 0;
1837 tbp->ncb_length = 0;
1842 npar = SMB_PACKETSIZE >> 4; /* number of paragraphs */
1845 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1847 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
1849 osi_panic("",__FILE__,__LINE__);
1852 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
1857 tbp->dos_pkt = (seg * 16) + 0; /* DOS physical address */
1858 tbp->dos_pkt_sel = tb_sel;
1861 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1866 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1870 memcpy(tbp, pkt, sizeof(smb_packet_t));
1871 tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1873 smb_HoldVC(tbp->vcp);
1877 static NCB *GetNCB(void)
1882 unsigned int npar, seg, tb_sel;
1885 lock_ObtainWrite(&smb_globalLock);
1886 tbp = smb_ncbFreeListp;
1888 smb_ncbFreeListp = tbp->nextp;
1889 lock_ReleaseWrite(&smb_globalLock);
1892 tbp = calloc(sizeof(*tbp),1);
1894 tbp = malloc(sizeof(*tbp));
1895 npar = (sizeof(NCB)+15) >> 4; /* number of paragraphs */
1898 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1900 osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
1902 osi_panic("",__FILE__,__LINE__);
1904 osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1909 tbp->dos_ncb = (seg * 16) + 0; /* DOS physical address */
1910 tbp->dos_ncb_sel = tb_sel;
1912 tbp->magic = SMB_NCBMAGIC;
1915 osi_assert(tbp->magic == SMB_NCBMAGIC);
1917 memset(&tbp->ncb, 0, sizeof(NCB));
1920 dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1925 void smb_FreePacket(smb_packet_t *tbp)
1927 smb_vc_t * vcp = NULL;
1928 osi_assert(tbp->magic == SMB_PACKETMAGIC);
1930 lock_ObtainWrite(&smb_globalLock);
1931 tbp->nextp = smb_packetFreeListp;
1932 smb_packetFreeListp = tbp;
1933 tbp->magic = SMB_PACKETMAGIC;
1937 tbp->resumeCode = 0;
1943 tbp->ncb_length = 0;
1945 lock_ReleaseWrite(&smb_globalLock);
1951 static void FreeNCB(NCB *bufferp)
1955 tbp = (smb_ncb_t *) bufferp;
1956 osi_assert(tbp->magic == SMB_NCBMAGIC);
1958 lock_ObtainWrite(&smb_globalLock);
1959 tbp->nextp = smb_ncbFreeListp;
1960 smb_ncbFreeListp = tbp;
1961 lock_ReleaseWrite(&smb_globalLock);
1964 /* get a ptr to the data part of a packet, and its count */
1965 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1969 unsigned char *afterParmsp;
1971 parmBytes = *smbp->wctp << 1;
1972 afterParmsp = smbp->wctp + parmBytes + 1;
1974 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1975 if (nbytesp) *nbytesp = dataBytes;
1977 /* don't forget to skip the data byte count, since it follows
1978 * the parameters; that's where the "2" comes from below.
1980 return (unsigned char *) (afterParmsp + 2);
1983 /* must set all the returned parameters before playing around with the
1984 * data region, since the data region is located past the end of the
1985 * variable number of parameters.
1987 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1989 unsigned char *afterParmsp;
1991 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1993 *afterParmsp++ = dsize & 0xff;
1994 *afterParmsp = (dsize>>8) & 0xff;
1997 /* return the parm'th parameter in the smbp packet */
1998 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
2001 unsigned char *parmDatap;
2003 parmCount = *smbp->wctp;
2005 if (parm >= parmCount) {
2010 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2012 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2013 parm, parmCount, smbp->ncb_length);
2016 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2017 1, smbp->ncb_length, ptbuf, smbp);
2018 DeregisterEventSource(h);
2020 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2021 parm, parmCount, smbp->ncb_length);
2022 osi_panic(s, __FILE__, __LINE__);
2024 parmDatap = smbp->wctp + (2*parm) + 1;
2026 return parmDatap[0] + (parmDatap[1] << 8);
2029 /* return the parm'th parameter in the smbp packet */
2030 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2033 unsigned char *parmDatap;
2035 parmCount = *smbp->wctp;
2037 if (parm * 2 + offset >= parmCount * 2) {
2042 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
2044 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2045 parm, offset, parmCount, smbp->ncb_length);
2048 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
2049 1, smbp->ncb_length, ptbuf, smbp);
2050 DeregisterEventSource(h);
2052 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2053 parm, offset, parmCount, smbp->ncb_length);
2054 osi_panic(s, __FILE__, __LINE__);
2056 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2058 return parmDatap[0] + (parmDatap[1] << 8);
2061 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2065 /* make sure we have enough slots */
2066 if (*smbp->wctp <= slot)
2067 *smbp->wctp = slot+1;
2069 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2070 *parmDatap++ = parmValue & 0xff;
2071 *parmDatap = (parmValue>>8) & 0xff;
2074 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2078 /* make sure we have enough slots */
2079 if (*smbp->wctp <= slot)
2080 *smbp->wctp = slot+2;
2082 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2083 *parmDatap++ = parmValue & 0xff;
2084 *parmDatap++ = (parmValue>>8) & 0xff;
2085 *parmDatap++ = (parmValue>>16) & 0xff;
2086 *parmDatap++ = (parmValue>>24) & 0xff;
2089 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2094 /* make sure we have enough slots */
2095 if (*smbp->wctp <= slot)
2096 *smbp->wctp = slot+4;
2098 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2100 *parmDatap++ = *parmValuep++;
2103 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2107 /* make sure we have enough slots */
2108 if (*smbp->wctp <= slot) {
2109 if (smbp->oddByte) {
2111 *smbp->wctp = slot+1;
2116 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2117 *parmDatap++ = parmValue & 0xff;
2120 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2124 lastSlashp = strrchr(inPathp, '\\');
2126 *lastComponentp = lastSlashp;
2129 if (inPathp == lastSlashp)
2131 *outPathp++ = *inPathp++;
2140 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2145 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2150 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2156 tlen = inp[0] + (inp[1]<<8);
2157 inp += 2; /* skip length field */
2160 *chainpp = inp + tlen;
2169 /* format a packet as a response */
2170 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2175 outp = (smb_t *) op;
2177 /* zero the basic structure through the smb_wct field, and zero the data
2178 * size field, assuming that wct stays zero; otherwise, you have to
2179 * explicitly set the data size field, too.
2181 inSmbp = (smb_t *) inp;
2182 memset(outp, 0, sizeof(smb_t)+2);
2188 outp->com = inSmbp->com;
2189 outp->tid = inSmbp->tid;
2190 outp->pid = inSmbp->pid;
2191 outp->uid = inSmbp->uid;
2192 outp->mid = inSmbp->mid;
2193 outp->res[0] = inSmbp->res[0];
2194 outp->res[1] = inSmbp->res[1];
2195 op->inCom = inSmbp->com;
2197 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
2198 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2200 /* copy fields in generic packet area */
2201 op->wctp = &outp->wct;
2204 /* send a (probably response) packet; vcp tells us to whom to send it.
2205 * we compute the length by looking at wct and bcc fields.
2207 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2224 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2227 memset((char *)ncbp, 0, sizeof(NCB));
2229 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2230 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2231 extra += tp[0] + (tp[1]<<8);
2232 extra += ((unsigned int)inp->wctp - (unsigned int)inp->data); /* distance to last wct field */
2233 extra += 3; /* wct and length fields */
2235 ncbp->ncb_length = extra; /* bytes to send */
2236 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2237 ncbp->ncb_lana_num = vcp->lana;
2238 ncbp->ncb_command = NCBSEND; /* op means send data */
2240 ncbp->ncb_buffer = (char *) inp;/* packet */
2241 code = Netbios(ncbp);
2243 ncbp->ncb_buffer = inp->dos_pkt;/* packet */
2244 ((smb_ncb_t*)ncbp)->orig_pkt = inp;
2246 /* copy header information from virtual to DOS address space */
2247 dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
2248 code = Netbios(ncbp, dos_ncb);
2252 osi_Log1(smb_logp, "SendPacket failure code %d", code);
2258 void smb_MapNTError(long code, unsigned long *NTStatusp)
2260 unsigned long NTStatus;
2262 /* map CM_ERROR_* errors to NT 32-bit status codes */
2263 /* NT Status codes are listed in ntstatus.h not winerror.h */
2264 if (code == CM_ERROR_NOSUCHCELL) {
2265 NTStatus = 0xC000000FL; /* No such file */
2267 else if (code == CM_ERROR_NOSUCHVOLUME) {
2268 NTStatus = 0xC000000FL; /* No such file */
2270 else if (code == CM_ERROR_TIMEDOUT) {
2271 NTStatus = 0xC00000CFL; /* Sharing Paused */
2273 else if (code == CM_ERROR_RETRY) {
2274 NTStatus = 0xC000022DL; /* Retry */
2276 else if (code == CM_ERROR_NOACCESS) {
2277 NTStatus = 0xC0000022L; /* Access denied */
2279 else if (code == CM_ERROR_READONLY) {
2280 NTStatus = 0xC00000A2L; /* Write protected */
2282 else if (code == CM_ERROR_NOSUCHFILE) {
2283 NTStatus = 0xC000000FL; /* No such file */
2285 else if (code == CM_ERROR_NOSUCHPATH) {
2286 NTStatus = 0xC000003AL; /* Object path not found */
2288 else if (code == CM_ERROR_TOOBIG) {
2289 NTStatus = 0xC000007BL; /* Invalid image format */
2291 else if (code == CM_ERROR_INVAL) {
2292 NTStatus = 0xC000000DL; /* Invalid parameter */
2294 else if (code == CM_ERROR_BADFD) {
2295 NTStatus = 0xC0000008L; /* Invalid handle */
2297 else if (code == CM_ERROR_BADFDOP) {
2298 NTStatus = 0xC0000022L; /* Access denied */
2300 else if (code == CM_ERROR_EXISTS) {
2301 NTStatus = 0xC0000035L; /* Object name collision */
2303 else if (code == CM_ERROR_NOTEMPTY) {
2304 NTStatus = 0xC0000101L; /* Directory not empty */
2306 else if (code == CM_ERROR_CROSSDEVLINK) {
2307 NTStatus = 0xC00000D4L; /* Not same device */
2309 else if (code == CM_ERROR_NOTDIR) {
2310 NTStatus = 0xC0000103L; /* Not a directory */
2312 else if (code == CM_ERROR_ISDIR) {
2313 NTStatus = 0xC00000BAL; /* File is a directory */
2315 else if (code == CM_ERROR_BADOP) {
2317 /* I have no idea where this comes from */
2318 NTStatus = 0xC09820FFL; /* SMB no support */
2320 NTStatus = 0xC00000BBL; /* Not supported */
2321 #endif /* COMMENT */
2323 else if (code == CM_ERROR_BADSHARENAME) {
2324 NTStatus = 0xC00000CCL; /* Bad network name */
2326 else if (code == CM_ERROR_NOIPC) {
2328 NTStatus = 0xC0000022L; /* Access Denied */
2330 NTStatus = 0xC000013DL; /* Remote Resources */
2333 else if (code == CM_ERROR_CLOCKSKEW) {
2334 NTStatus = 0xC0000133L; /* Time difference at DC */
2336 else if (code == CM_ERROR_BADTID) {
2337 NTStatus = 0xC0982005L; /* SMB bad TID */
2339 else if (code == CM_ERROR_USESTD) {
2340 NTStatus = 0xC09820FBL; /* SMB use standard */
2342 else if (code == CM_ERROR_QUOTA) {
2344 NTStatus = 0xC0000044L; /* Quota exceeded */
2346 NTStatus = 0xC000007FL; /* Disk full */
2349 else if (code == CM_ERROR_SPACE) {
2350 NTStatus = 0xC000007FL; /* Disk full */
2352 else if (code == CM_ERROR_ATSYS) {
2353 NTStatus = 0xC0000033L; /* Object name invalid */
2355 else if (code == CM_ERROR_BADNTFILENAME) {
2356 NTStatus = 0xC0000033L; /* Object name invalid */
2358 else if (code == CM_ERROR_WOULDBLOCK) {
2359 NTStatus = 0xC0000055L; /* Lock not granted */
2361 else if (code == CM_ERROR_PARTIALWRITE) {
2362 NTStatus = 0xC000007FL; /* Disk full */
2364 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2365 NTStatus = 0xC0000023L; /* Buffer too small */
2367 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2368 NTStatus = 0xC0000035L; /* Object name collision */
2370 else if (code == CM_ERROR_BADPASSWORD) {
2371 NTStatus = 0xC000006DL; /* unknown username or bad password */
2373 else if (code == CM_ERROR_BADLOGONTYPE) {
2374 NTStatus = 0xC000015BL; /* logon type not granted */
2376 else if (code == CM_ERROR_GSSCONTINUE) {
2377 NTStatus = 0xC0000016L; /* more processing required */
2379 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2381 NTStatus = 0xC0000280L; /* reparse point not resolved */
2383 NTStatus = 0xC0000022L; /* Access Denied */
2386 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2387 NTStatus = 0xC0000257L; /* Path Not Covered */
2389 else if (code == CM_ERROR_ALLBUSY) {
2390 NTStatus = 0xC00000BFL; /* Network Busy */
2392 NTStatus = 0xC0982001L; /* SMB non-specific error */
2395 *NTStatusp = NTStatus;
2396 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2399 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2400 unsigned char *classp)
2402 unsigned char class;
2403 unsigned short error;
2405 /* map CM_ERROR_* errors to SMB errors */
2406 if (code == CM_ERROR_NOSUCHCELL) {
2408 error = 3; /* bad path */
2410 else if (code == CM_ERROR_NOSUCHVOLUME) {
2412 error = 3; /* bad path */
2414 else if (code == CM_ERROR_TIMEDOUT) {
2416 error = 81; /* server is paused */
2418 else if (code == CM_ERROR_RETRY) {
2419 class = 2; /* shouldn't happen */
2422 else if (code == CM_ERROR_NOACCESS) {
2424 error = 4; /* bad access */
2426 else if (code == CM_ERROR_READONLY) {
2428 error = 19; /* read only */
2430 else if (code == CM_ERROR_NOSUCHFILE) {
2432 error = 2; /* ENOENT! */
2434 else if (code == CM_ERROR_NOSUCHPATH) {
2436 error = 3; /* Bad path */
2438 else if (code == CM_ERROR_TOOBIG) {
2440 error = 11; /* bad format */
2442 else if (code == CM_ERROR_INVAL) {
2443 class = 2; /* server non-specific error code */
2446 else if (code == CM_ERROR_BADFD) {
2448 error = 6; /* invalid file handle */
2450 else if (code == CM_ERROR_BADFDOP) {
2451 class = 1; /* invalid op on FD */
2454 else if (code == CM_ERROR_EXISTS) {
2456 error = 80; /* file already exists */
2458 else if (code == CM_ERROR_NOTEMPTY) {
2460 error = 5; /* delete directory not empty */
2462 else if (code == CM_ERROR_CROSSDEVLINK) {
2464 error = 17; /* EXDEV */
2466 else if (code == CM_ERROR_NOTDIR) {
2467 class = 1; /* bad path */
2470 else if (code == CM_ERROR_ISDIR) {
2471 class = 1; /* access denied; DOS doesn't have a good match */
2474 else if (code == CM_ERROR_BADOP) {
2478 else if (code == CM_ERROR_BADSHARENAME) {
2482 else if (code == CM_ERROR_NOIPC) {
2484 error = 4; /* bad access */
2486 else if (code == CM_ERROR_CLOCKSKEW) {
2487 class = 1; /* invalid function */
2490 else if (code == CM_ERROR_BADTID) {
2494 else if (code == CM_ERROR_USESTD) {
2498 else if (code == CM_ERROR_REMOTECONN) {
2502 else if (code == CM_ERROR_QUOTA) {
2503 if (vcp->flags & SMB_VCFLAG_USEV3) {
2505 error = 39; /* disk full */
2509 error = 5; /* access denied */
2512 else if (code == CM_ERROR_SPACE) {
2513 if (vcp->flags & SMB_VCFLAG_USEV3) {
2515 error = 39; /* disk full */
2519 error = 5; /* access denied */
2522 else if (code == CM_ERROR_PARTIALWRITE) {
2524 error = 39; /* disk full */
2526 else if (code == CM_ERROR_ATSYS) {
2528 error = 2; /* ENOENT */
2530 else if (code == CM_ERROR_WOULDBLOCK) {
2532 error = 33; /* lock conflict */
2534 else if (code == CM_ERROR_NOFILES) {
2536 error = 18; /* no files in search */
2538 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2540 error = 183; /* Samba uses this */
2542 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2543 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2545 error = 2; /* bad password */
2547 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2549 error = 3; /* bad path */
2558 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2561 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2563 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2564 return CM_ERROR_BADOP;
2567 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2569 unsigned short EchoCount, i;
2570 char *data, *outdata;
2573 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2575 for (i=1; i<=EchoCount; i++) {
2576 data = smb_GetSMBData(inp, &dataSize);
2577 smb_SetSMBParm(outp, 0, i);
2578 smb_SetSMBDataLength(outp, dataSize);
2579 outdata = smb_GetSMBData(outp, NULL);
2580 memcpy(outdata, data, dataSize);
2581 smb_SendPacket(vcp, outp);
2587 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2590 long count, minCount, finalCount;
2594 cm_user_t *userp = NULL;
2598 char *rawBuf = NULL;
2600 dos_ptr rawBuf = NULL;
2607 fd = smb_GetSMBParm(inp, 0);
2608 count = smb_GetSMBParm(inp, 3);
2609 minCount = smb_GetSMBParm(inp, 4);
2610 offset.HighPart = 0; /* too bad */
2611 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2613 osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2614 fd, offset.LowPart, count);
2616 fidp = smb_FindFID(vcp, fd, 0);
2620 lock_ObtainMutex(&smb_RawBufLock);
2622 /* Get a raw buf, from head of list */
2623 rawBuf = smb_RawBufs;
2625 smb_RawBufs = *(char **)smb_RawBufs;
2627 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2630 lock_ReleaseMutex(&smb_RawBufLock);
2634 if (fidp->flags & SMB_FID_IOCTL)
2637 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2639 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2642 /* Give back raw buffer */
2643 lock_ObtainMutex(&smb_RawBufLock);
2645 *((char **) rawBuf) = smb_RawBufs;
2647 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2650 smb_RawBufs = rawBuf;
2651 lock_ReleaseMutex(&smb_RawBufLock);
2654 smb_ReleaseFID(fidp);
2658 userp = smb_GetUser(vcp, inp);
2661 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2663 /* have to give ReadData flag so it will treat buffer as DOS mem. */
2664 code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2665 userp, &finalCount, TRUE /* rawFlag */);
2672 cm_ReleaseUser(userp);
2675 smb_ReleaseFID(fidp);
2680 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2682 memset((char *)ncbp, 0, sizeof(NCB));
2684 ncbp->ncb_length = (unsigned short) finalCount;
2685 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2686 ncbp->ncb_lana_num = vcp->lana;
2687 ncbp->ncb_command = NCBSEND;
2688 ncbp->ncb_buffer = rawBuf;
2691 code = Netbios(ncbp);
2693 code = Netbios(ncbp, dos_ncb);
2696 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2699 /* Give back raw buffer */
2700 lock_ObtainMutex(&smb_RawBufLock);
2702 *((char **) rawBuf) = smb_RawBufs;
2704 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2707 smb_RawBufs = rawBuf;
2708 lock_ReleaseMutex(&smb_RawBufLock);
2714 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2716 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
2721 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2723 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
2728 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2735 int protoIndex; /* index we're using */
2740 char protocol_array[10][1024]; /* protocol signature of the client */
2741 int caps; /* capabilities */
2744 TIME_ZONE_INFORMATION tzi;
2746 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2750 DWORD now = GetCurrentTime();
2751 if (now - last_msg_time >= 30000
2752 && now - last_msg_time <= 90000) {
2754 "Setting dead_vcp %x", active_vcp);
2756 smb_ReleaseVC(dead_vcp);
2758 "Previous dead_vcp %x", dead_vcp);
2760 smb_HoldVC(active_vcp);
2761 dead_vcp = active_vcp;
2762 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2767 inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2769 namep = smb_GetSMBData(inp, &dbytes);
2772 coreProtoIndex = -1; /* not found */
2775 while(namex < dbytes) {
2776 osi_Log1(smb_logp, "Protocol %s",
2777 osi_LogSaveString(smb_logp, namep+1));
2778 strcpy(protocol_array[tcounter], namep+1);
2780 /* namep points at the first protocol, or really, a 0x02
2781 * byte preceding the null-terminated ASCII name.
2783 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2784 coreProtoIndex = tcounter;
2786 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2787 v3ProtoIndex = tcounter;
2789 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2790 NTProtoIndex = tcounter;
2793 /* compute size of protocol entry */
2794 entryLength = strlen(namep+1);
2795 entryLength += 2; /* 0x02 bytes and null termination */
2797 /* advance over this protocol entry */
2798 namex += entryLength;
2799 namep += entryLength;
2800 tcounter++; /* which proto entry we're looking at */
2803 if (NTProtoIndex != -1) {
2804 protoIndex = NTProtoIndex;
2805 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2807 else if (v3ProtoIndex != -1) {
2808 protoIndex = v3ProtoIndex;
2809 vcp->flags |= SMB_VCFLAG_USEV3;
2811 else if (coreProtoIndex != -1) {
2812 protoIndex = coreProtoIndex;
2813 vcp->flags |= SMB_VCFLAG_USECORE;
2815 else protoIndex = -1;
2817 if (protoIndex == -1)
2818 return CM_ERROR_INVAL;
2819 else if (NTProtoIndex != -1) {
2820 smb_SetSMBParm(outp, 0, protoIndex);
2821 if (smb_authType != SMB_AUTH_NONE) {
2822 smb_SetSMBParmByte(outp, 1,
2823 NEGOTIATE_SECURITY_USER_LEVEL |
2824 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2826 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
2828 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
2829 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2830 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2831 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
2832 /* The session key is not a well documented field however most clients
2833 * will echo back the session key to the server. Currently we are using
2834 * the same value for all sessions. We should generate a random value
2835 * and store it into the vcp
2837 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
2838 smb_SetSMBParm(outp, 8, 1);
2840 * Tried changing the capabilities to support for W2K - defect 117695
2841 * Maybe something else needs to be changed here?
2845 smb_SetSMBParmLong(outp, 9, 0x43fd);
2847 smb_SetSMBParmLong(outp, 9, 0x251);
2850 * 32-bit error codes *
2855 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
2857 NTNEGOTIATE_CAPABILITY_DFS |
2859 NTNEGOTIATE_CAPABILITY_NTFIND |
2860 NTNEGOTIATE_CAPABILITY_RAWMODE |
2861 NTNEGOTIATE_CAPABILITY_NTSMB;
2863 if ( smb_authType == SMB_AUTH_EXTENDED )
2864 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
2866 smb_SetSMBParmLong(outp, 9, caps);
2868 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2869 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
2870 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
2872 GetTimeZoneInformation(&tzi);
2873 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
2875 if (smb_authType == SMB_AUTH_NTLM) {
2876 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
2877 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
2878 /* paste in encryption key */
2879 datap = smb_GetSMBData(outp, NULL);
2880 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
2881 /* and the faux domain name */
2882 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
2883 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
2887 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2889 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
2891 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
2893 datap = smb_GetSMBData(outp, NULL);
2894 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
2897 datap += sizeof(smb_ServerGUID);
2898 memcpy(datap, secBlob, secBlobLength);
2902 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
2903 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
2906 else if (v3ProtoIndex != -1) {
2907 smb_SetSMBParm(outp, 0, protoIndex);
2909 /* NOTE: Extended authentication cannot be negotiated with v3
2910 * therefore we fail over to NTLM
2912 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2913 smb_SetSMBParm(outp, 1,
2914 NEGOTIATE_SECURITY_USER_LEVEL |
2915 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
2917 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
2919 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2920 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
2921 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
2922 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
2923 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
2924 smb_SetSMBParm(outp, 7, 1);
2926 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
2927 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
2928 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
2930 GetTimeZoneInformation(&tzi);
2931 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
2933 /* NOTE: Extended authentication cannot be negotiated with v3
2934 * therefore we fail over to NTLM
2936 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
2937 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
2938 smb_SetSMBParm(outp, 12, 0); /* resvd */
2939 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
2940 datap = smb_GetSMBData(outp, NULL);
2941 /* paste in a new encryption key */
2942 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
2943 /* and the faux domain name */
2944 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
2946 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
2947 smb_SetSMBParm(outp, 12, 0); /* resvd */
2948 smb_SetSMBDataLength(outp, 0);
2951 else if (coreProtoIndex != -1) { /* not really supported anymore */
2952 smb_SetSMBParm(outp, 0, protoIndex);
2953 smb_SetSMBDataLength(outp, 0);
2958 void smb_Daemon(void *parmp)
2960 afs_uint32 count = 0;
2962 while(smbShutdownFlag == 0) {
2966 if (smbShutdownFlag == 1)
2969 if ((count % 72) == 0) { /* every five minutes */
2971 time_t old_localZero = smb_localZero;
2973 /* Initialize smb_localZero */
2974 myTime.tm_isdst = -1; /* compute whether on DST or not */
2975 myTime.tm_year = 70;
2981 smb_localZero = mktime(&myTime);
2983 #ifndef USE_NUMERIC_TIME_CONV
2984 smb_CalculateNowTZ();
2985 #endif /* USE_NUMERIC_TIME_CONV */
2986 #ifdef AFS_FREELANCE
2987 if ( smb_localZero != old_localZero )
2988 cm_noteLocalMountPointChange();
2991 /* XXX GC dir search entries */
2995 void smb_WaitingLocksDaemon()
2997 smb_waitingLock_t *wL, *nwL;
3000 smb_packet_t *inp, *outp;
3004 while (smbShutdownFlag == 0) {
3005 lock_ObtainWrite(&smb_globalLock);
3006 nwL = smb_allWaitingLocks;
3008 osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
3018 lock_ObtainWrite(&smb_globalLock);
3020 nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
3021 lock_ReleaseWrite(&smb_globalLock);
3022 code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
3023 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
3024 if (code == CM_ERROR_WOULDBLOCK) {
3026 if (wL->timeRemaining != 0xffffffff
3027 && (wL->timeRemaining -= 1000) < 0)
3037 ncbp->ncb_length = inp->ncb_length;
3038 inp->spacep = cm_GetSpace();
3040 /* Remove waitingLock from list */
3041 lock_ObtainWrite(&smb_globalLock);
3042 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3044 lock_ReleaseWrite(&smb_globalLock);
3046 /* Resume packet processing */
3048 smb_SetSMBDataLength(outp, 0);
3049 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3050 outp->resumeCode = code;
3052 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3055 cm_FreeSpace(inp->spacep);
3056 smb_FreePacket(inp);
3057 smb_FreePacket(outp);
3061 } while (nwL && smbShutdownFlag == 0);
3066 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3068 osi_Log0(smb_logp, "SMB receive get disk attributes");
3070 smb_SetSMBParm(outp, 0, 32000);
3071 smb_SetSMBParm(outp, 1, 64);
3072 smb_SetSMBParm(outp, 2, 1024);
3073 smb_SetSMBParm(outp, 3, 30000);
3074 smb_SetSMBParm(outp, 4, 0);
3075 smb_SetSMBDataLength(outp, 0);
3079 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3083 unsigned short newTid;
3084 char shareName[256];
3092 osi_Log0(smb_logp, "SMB receive tree connect");
3094 /* parse input parameters */
3095 tp = smb_GetSMBData(inp, NULL);
3096 pathp = smb_ParseASCIIBlock(tp, &tp);
3097 if (smb_StoreAnsiFilenames)
3098 OemToChar(pathp,pathp);
3099 passwordp = smb_ParseASCIIBlock(tp, &tp);
3100 tp = strrchr(pathp, '\\');
3102 return CM_ERROR_BADSMB;
3103 strcpy(shareName, tp+1);
3105 userp = smb_GetUser(vcp, inp);
3107 lock_ObtainMutex(&vcp->mx);
3108 newTid = vcp->tidCounter++;
3109 lock_ReleaseMutex(&vcp->mx);
3111 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3112 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3113 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3115 smb_ReleaseUID(uidp);
3117 smb_ReleaseTID(tidp);
3118 return CM_ERROR_BADSHARENAME;
3120 lock_ObtainMutex(&tidp->mx);
3121 tidp->userp = userp;
3122 tidp->pathname = sharePath;
3123 lock_ReleaseMutex(&tidp->mx);
3124 smb_ReleaseTID(tidp);
3126 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3127 smb_SetSMBParm(rsp, 1, newTid);
3128 smb_SetSMBDataLength(rsp, 0);
3130 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3134 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3138 if (*inp++ != 0x1) return NULL;
3139 tlen = inp[0] + (inp[1]<<8);
3140 inp += 2; /* skip length field */
3143 *chainpp = inp + tlen;
3146 if (lengthp) *lengthp = tlen;
3151 /* set maskp to the mask part of the incoming path.
3152 * Mask is 11 bytes long (8.3 with the dot elided).
3153 * Returns true if succeeds with a valid name, otherwise it does
3154 * its best, but returns false.
3156 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3164 /* starts off valid */
3167 /* mask starts out all blanks */
3168 memset(maskp, ' ', 11);
3170 /* find last backslash, or use whole thing if there is none */
3171 tp = strrchr(pathp, '\\');
3172 if (!tp) tp = pathp;
3173 else tp++; /* skip slash */
3177 /* names starting with a dot are illegal */
3178 if (*tp == '.') valid8Dot3 = 0;
3182 if (tc == 0) return valid8Dot3;
3183 if (tc == '.' || tc == '"') break;
3184 if (i < 8) *up++ = tc;
3185 else valid8Dot3 = 0;
3188 /* if we get here, tp point after the dot */
3189 up = maskp+8; /* ext goes here */
3196 if (tc == '.' || tc == '"')
3199 /* copy extension if not too long */
3209 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3219 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3221 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3225 /* otherwise, we have a valid 8.3 name; see if we have a match,
3226 * treating '?' as a wildcard in maskp (but not in the file name).
3228 tp1 = umask; /* real name, in mask format */
3229 tp2 = maskp; /* mask, in mask format */
3230 for(i=0; i<11; i++) {
3231 tc1 = *tp1++; /* char from real name */
3232 tc2 = *tp2++; /* char from mask */
3233 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3234 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3237 if (tc2 == '?' && tc1 != ' ')
3244 /* we got a match */
3248 char *smb_FindMask(char *pathp)
3252 tp = strrchr(pathp, '\\'); /* find last slash */
3255 return tp+1; /* skip the slash */
3257 return pathp; /* no slash, return the entire path */
3260 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3262 unsigned char *pathp;
3264 unsigned char mask[11];
3265 unsigned char *statBlockp;
3266 unsigned char initStatBlock[21];
3269 osi_Log0(smb_logp, "SMB receive search volume");
3271 /* pull pathname and stat block out of request */
3272 tp = smb_GetSMBData(inp, NULL);
3273 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3274 osi_assert(pathp != NULL);
3275 if (smb_StoreAnsiFilenames)
3276 OemToChar(pathp,pathp);
3277 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3278 osi_assert(statBlockp != NULL);
3280 statBlockp = initStatBlock;
3284 /* for returning to caller */
3285 smb_Get8Dot3MaskFromPath(mask, pathp);
3287 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3288 tp = smb_GetSMBData(outp, NULL);
3290 *tp++ = 43; /* bytes in a dir entry */
3291 *tp++ = 0; /* high byte in counter */
3293 /* now marshall the dir entry, starting with the search status */
3294 *tp++ = statBlockp[0]; /* Reserved */
3295 memcpy(tp, mask, 11); tp += 11; /* FileName */
3297 /* now pass back server use info, with 1st byte non-zero */
3299 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3301 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3303 *tp++ = 0x8; /* attribute: volume */
3313 /* 4 byte file size */
3319 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3320 memset(tp, ' ', 13);
3323 /* set the length of the data part of the packet to 43 + 3, for the dir
3324 * entry plus the 5 and the length fields.
3326 smb_SetSMBDataLength(outp, 46);
3330 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3331 cm_user_t *userp, cm_req_t *reqp)
3339 smb_dirListPatch_t *patchp;
3340 smb_dirListPatch_t *npatchp;
3342 for (patchp = *dirPatchespp; patchp; patchp =
3343 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3345 dptr = patchp->dptr;
3347 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3349 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3350 *dptr++ = SMB_ATTR_HIDDEN;
3353 lock_ObtainMutex(&scp->mx);
3354 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3355 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3357 lock_ReleaseMutex(&scp->mx);
3358 cm_ReleaseSCache(scp);
3359 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3360 *dptr++ = SMB_ATTR_HIDDEN;
3364 attr = smb_Attributes(scp);
3365 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3366 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3367 attr |= SMB_ATTR_HIDDEN;
3371 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3374 shortTemp = (unsigned short) (dosTime & 0xffff);
3375 *((u_short *)dptr) = shortTemp;
3378 /* and copy out date */
3379 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3380 *((u_short *)dptr) = shortTemp;
3383 /* copy out file length */
3384 *((u_long *)dptr) = scp->length.LowPart;
3386 lock_ReleaseMutex(&scp->mx);
3387 cm_ReleaseSCache(scp);
3390 /* now free the patches */
3391 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3392 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3396 /* and mark the list as empty */
3397 *dirPatchespp = NULL;
3402 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3411 smb_dirListPatch_t *dirListPatchesp;
3412 smb_dirListPatch_t *curPatchp;
3416 osi_hyper_t dirLength;
3417 osi_hyper_t bufferOffset;
3418 osi_hyper_t curOffset;
3420 unsigned char *inCookiep;
3421 smb_dirSearch_t *dsp;
3425 unsigned long clientCookie;
3426 cm_pageHeader_t *pageHeaderp;
3427 cm_user_t *userp = NULL;
3434 long nextEntryCookie;
3435 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3436 char resByte; /* reserved byte from the cookie */
3437 char *op; /* output data ptr */
3438 char *origOp; /* original value of op */
3439 cm_space_t *spacep; /* for pathname buffer */
3450 maxCount = smb_GetSMBParm(inp, 0);
3452 dirListPatchesp = NULL;
3454 caseFold = CM_FLAG_CASEFOLD;
3456 tp = smb_GetSMBData(inp, NULL);
3457 pathp = smb_ParseASCIIBlock(tp, &tp);
3458 if (smb_StoreAnsiFilenames)
3459 OemToChar(pathp,pathp);
3460 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3462 /* bail out if request looks bad */
3463 if (!tp || !pathp) {
3464 return CM_ERROR_BADSMB;
3467 /* We can handle long names */
3468 if (vcp->flags & SMB_VCFLAG_USENT)
3469 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3471 /* make sure we got a whole search status */
3472 if (dataLength < 21) {
3473 nextCookie = 0; /* start at the beginning of the dir */
3476 attribute = smb_GetSMBParm(inp, 1);
3478 /* handle volume info in another function */
3479 if (attribute & 0x8)
3480 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3482 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3483 maxCount, osi_LogSaveString(smb_logp, pathp));
3485 if (*pathp == 0) { /* null pathp, treat as root dir */
3486 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3487 return CM_ERROR_NOFILES;
3491 dsp = smb_NewDirSearch(0);
3492 dsp->attribute = attribute;
3493 smb_Get8Dot3MaskFromPath(mask, pathp);
3494 memcpy(dsp->mask, mask, 11);
3496 /* track if this is likely to match a lot of entries */
3497 if (smb_IsStarMask(mask))
3502 /* pull the next cookie value out of the search status block */
3503 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3504 + (inCookiep[16]<<24);
3505 dsp = smb_FindDirSearch(inCookiep[12]);
3507 /* can't find dir search status; fatal error */
3508 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3509 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3510 return CM_ERROR_BADFD;
3512 attribute = dsp->attribute;
3513 resByte = inCookiep[0];
3515 /* copy out client cookie, in host byte order. Don't bother
3516 * interpreting it, since we're just passing it through, anyway.
3518 memcpy(&clientCookie, &inCookiep[17], 4);
3520 memcpy(mask, dsp->mask, 11);
3522 /* assume we're doing a star match if it has continued for more
3528 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3529 nextCookie, dsp->cookie, attribute);
3531 userp = smb_GetUser(vcp, inp);
3533 /* try to get the vnode for the path name next */
3534 lock_ObtainMutex(&dsp->mx);
3540 spacep = inp->spacep;
3541 smb_StripLastComponent(spacep->data, NULL, pathp);
3542 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3544 lock_ReleaseMutex(&dsp->mx);
3545 cm_ReleaseUser(userp);
3546 smb_DeleteDirSearch(dsp);
3547 smb_ReleaseDirSearch(dsp);
3548 return CM_ERROR_NOFILES;
3550 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3551 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3554 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3555 cm_ReleaseSCache(scp);
3556 lock_ReleaseMutex(&dsp->mx);
3557 cm_ReleaseUser(userp);
3558 smb_DeleteDirSearch(dsp);
3559 smb_ReleaseDirSearch(dsp);
3560 if ( WANTS_DFS_PATHNAMES(inp) )
3561 return CM_ERROR_PATH_NOT_COVERED;
3563 return CM_ERROR_BADSHARENAME;
3565 #endif /* DFS_SUPPORT */
3568 /* we need one hold for the entry we just stored into,
3569 * and one for our own processing. When we're done with this
3570 * function, we'll drop the one for our own processing.
3571 * We held it once from the namei call, and so we do another hold
3575 lock_ObtainMutex(&scp->mx);
3576 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3577 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3578 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3579 dsp->flags |= SMB_DIRSEARCH_BULKST;
3581 lock_ReleaseMutex(&scp->mx);
3584 lock_ReleaseMutex(&dsp->mx);
3586 cm_ReleaseUser(userp);
3587 smb_DeleteDirSearch(dsp);
3588 smb_ReleaseDirSearch(dsp);
3592 /* reserves space for parameter; we'll adjust it again later to the
3593 * real count of the # of entries we returned once we've actually
3594 * assembled the directory listing.
3596 smb_SetSMBParm(outp, 0, 0);
3598 /* get the directory size */
3599 lock_ObtainMutex(&scp->mx);
3600 code = cm_SyncOp(scp, NULL, userp, &req, 0,
3601 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3603 lock_ReleaseMutex(&scp->mx);
3604 cm_ReleaseSCache(scp);
3605 cm_ReleaseUser(userp);
3606 smb_DeleteDirSearch(dsp);
3607 smb_ReleaseDirSearch(dsp);
3611 dirLength = scp->length;
3613 bufferOffset.LowPart = bufferOffset.HighPart = 0;
3614 curOffset.HighPart = 0;
3615 curOffset.LowPart = nextCookie;
3616 origOp = op = smb_GetSMBData(outp, NULL);
3617 /* and write out the basic header */
3618 *op++ = 5; /* variable block */
3619 op += 2; /* skip vbl block length; we'll fill it in later */
3623 /* make sure that curOffset.LowPart doesn't point to the first
3624 * 32 bytes in the 2nd through last dir page, and that it doesn't
3625 * point at the first 13 32-byte chunks in the first dir page,
3626 * since those are dir and page headers, and don't contain useful
3629 temp = curOffset.LowPart & (2048-1);
3630 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3631 /* we're in the first page */
3632 if (temp < 13*32) temp = 13*32;
3635 /* we're in a later dir page */
3636 if (temp < 32) temp = 32;
3639 /* make sure the low order 5 bits are zero */
3642 /* now put temp bits back ito curOffset.LowPart */
3643 curOffset.LowPart &= ~(2048-1);
3644 curOffset.LowPart |= temp;
3646 /* check if we've returned all the names that will fit in the
3649 if (returnedNames >= maxCount) {
3650 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
3651 returnedNames, maxCount);
3655 /* check if we've passed the dir's EOF */
3656 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3658 /* see if we can use the bufferp we have now; compute in which page
3659 * the current offset would be, and check whether that's the offset
3660 * of the buffer we have. If not, get the buffer.
3662 thyper.HighPart = curOffset.HighPart;
3663 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
3664 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3667 buf_Release(bufferp);
3670 lock_ReleaseMutex(&scp->mx);
3671 lock_ObtainRead(&scp->bufCreateLock);
3672 code = buf_Get(scp, &thyper, &bufferp);
3673 lock_ReleaseRead(&scp->bufCreateLock);
3674 lock_ObtainMutex(&dsp->mx);
3676 /* now, if we're doing a star match, do bulk fetching of all of
3677 * the status info for files in the dir.
3680 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3681 lock_ObtainMutex(&scp->mx);
3682 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3683 LargeIntegerGreaterThanOrEqualTo(thyper,
3684 scp->bulkStatProgress)) {
3685 /* Don't bulk stat if risking timeout */
3686 int now = GetCurrentTime();
3687 if (now - req.startTime > 5000) {
3688 scp->bulkStatProgress = thyper;
3689 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3690 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3692 cm_TryBulkStat(scp, &thyper, userp, &req);
3695 lock_ObtainMutex(&scp->mx);
3697 lock_ReleaseMutex(&dsp->mx);
3699 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
3703 bufferOffset = thyper;
3705 /* now get the data in the cache */
3707 code = cm_SyncOp(scp, bufferp, userp, &req,
3709 CM_SCACHESYNC_NEEDCALLBACK |
3710 CM_SCACHESYNC_READ);
3712 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
3716 if (cm_HaveBuffer(scp, bufferp, 0)) {
3717 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
3721 /* otherwise, load the buffer and try again */
3722 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3724 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
3725 scp, bufferp, code);
3730 buf_Release(bufferp);
3734 } /* if (wrong buffer) ... */
3736 /* now we have the buffer containing the entry we're interested in; copy
3737 * it out if it represents a non-deleted entry.
3739 entryInDir = curOffset.LowPart & (2048-1);
3740 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
3742 /* page header will help tell us which entries are free. Page header
3743 * can change more often than once per buffer, since AFS 3 dir page size
3744 * may be less than (but not more than a buffer package buffer.
3746 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
3747 temp &= ~(2048 - 1); /* turn off intra-page bits */
3748 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3750 /* now determine which entry we're looking at in the page. If it is
3751 * free (there's a free bitmap at the start of the dir), we should
3752 * skip these 32 bytes.
3754 slotInPage = (entryInDir & 0x7e0) >> 5;
3755 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3756 /* this entry is free */
3757 numDirChunks = 1; /* only skip this guy */
3761 tp = bufferp->datap + entryInBuffer;
3762 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
3764 /* while we're here, compute the next entry's location, too,
3765 * since we'll need it when writing out the cookie into the dir
3768 * XXXX Probably should do more sanity checking.
3770 numDirChunks = cm_NameEntries(dep->name, NULL);
3772 /* compute the offset of the cookie representing the next entry */
3773 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3775 /* Compute 8.3 name if necessary */
3776 actualName = dep->name;
3777 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3778 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3779 actualName = shortName;
3782 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
3783 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
3784 osi_LogSaveString(smb_logp, actualName));
3786 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3787 /* this is one of the entries to use: it is not deleted
3788 * and it matches the star pattern we're looking for.
3791 /* Eliminate entries that don't match requested
3794 /* no hidden files */
3795 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
3796 osi_Log0(smb_logp, "SMB search dir skipping hidden");
3800 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
3802 /* We have already done the cm_TryBulkStat above */
3803 fid.cell = scp->fid.cell;
3804 fid.volume = scp->fid.volume;
3805 fid.vnode = ntohl(dep->fid.vnode);
3806 fid.unique = ntohl(dep->fid.unique);
3807 fileType = cm_FindFileType(&fid);
3808 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3809 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
3811 if (fileType == CM_SCACHETYPE_DIRECTORY ||
3812 fileType == CM_SCACHETYPE_DFSLINK ||
3813 fileType == CM_SCACHETYPE_INVALID)
3814 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
3819 memcpy(op, mask, 11); op += 11;
3820 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
3821 *op++ = nextEntryCookie & 0xff;
3822 *op++ = (nextEntryCookie>>8) & 0xff;
3823 *op++ = (nextEntryCookie>>16) & 0xff;
3824 *op++ = (nextEntryCookie>>24) & 0xff;
3825 memcpy(op, &clientCookie, 4); op += 4;
3827 /* now we emit the attribute. This is sort of tricky,
3828 * since we need to really stat the file to find out
3829 * what type of entry we've got. Right now, we're
3830 * copying out data from a buffer, while holding the
3831 * scp locked, so it isn't really convenient to stat
3832 * something now. We'll put in a place holder now,
3833 * and make a second pass before returning this to get
3834 * the real attributes. So, we just skip the data for
3835 * now, and adjust it later. We allocate a patch
3836 * record to make it easy to find this point later.
3837 * The replay will happen at a time when it is safe to
3838 * unlock the directory.
3840 curPatchp = malloc(sizeof(*curPatchp));
3841 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3842 curPatchp->dptr = op;
3843 curPatchp->fid.cell = scp->fid.cell;
3844 curPatchp->fid.volume = scp->fid.volume;
3845 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3846 curPatchp->fid.unique = ntohl(dep->fid.unique);
3848 /* do hidden attribute here since name won't be around when applying
3852 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3853 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3855 curPatchp->flags = 0;
3857 op += 9; /* skip attr, time, date and size */
3859 /* zero out name area. The spec says to pad with
3860 * spaces, but Samba doesn't, and neither do we.
3864 /* finally, we get to copy out the name; we know that
3865 * it fits in 8.3 or the pattern wouldn't match, but it
3866 * never hurts to be sure.
3868 strncpy(op, actualName, 13);
3869 if (smb_StoreAnsiFilenames)
3872 /* Uppercase if requested by client */
3873 if (!KNOWS_LONG_NAMES(inp))
3878 /* now, adjust the # of entries copied */
3880 } /* if we're including this name */
3883 /* and adjust curOffset to be where the new cookie is */
3884 thyper.HighPart = 0;
3885 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3886 curOffset = LargeIntegerAdd(thyper, curOffset);
3887 } /* while copying data for dir listing */
3889 /* release the mutex */
3890 lock_ReleaseMutex(&scp->mx);
3891 if (bufferp) buf_Release(bufferp);
3893 /* apply and free last set of patches; if not doing a star match, this
3894 * will be empty, but better safe (and freeing everything) than sorry.
3896 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3898 /* special return code for unsuccessful search */
3899 if (code == 0 && dataLength < 21 && returnedNames == 0)
3900 code = CM_ERROR_NOFILES;
3902 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3903 returnedNames, code);
3906 smb_DeleteDirSearch(dsp);
3907 smb_ReleaseDirSearch(dsp);
3908 cm_ReleaseSCache(scp);
3909 cm_ReleaseUser(userp);
3913 /* finalize the output buffer */
3914 smb_SetSMBParm(outp, 0, returnedNames);
3915 temp = (long) (op - origOp);
3916 smb_SetSMBDataLength(outp, temp);
3918 /* the data area is a variable block, which has a 5 (already there)
3919 * followed by the length of the # of data bytes. We now know this to
3920 * be "temp," although that includes the 3 bytes of vbl block header.
3921 * Deduct for them and fill in the length field.
3923 temp -= 3; /* deduct vbl block info */
3924 osi_assert(temp == (43 * returnedNames));
3925 origOp[1] = temp & 0xff;
3926 origOp[2] = (temp>>8) & 0xff;
3927 if (returnedNames == 0)
3928 smb_DeleteDirSearch(dsp);
3929 smb_ReleaseDirSearch(dsp);
3930 cm_ReleaseSCache(scp);
3931 cm_ReleaseUser(userp);
3935 /* verify that this is a valid path to a directory. I don't know why they
3936 * don't use the get file attributes call.
3938 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3942 cm_scache_t *rootScp;
3943 cm_scache_t *newScp;
3952 pathp = smb_GetSMBData(inp, NULL);
3953 pathp = smb_ParseASCIIBlock(pathp, NULL);
3955 return CM_ERROR_BADFD;
3956 if (smb_StoreAnsiFilenames)
3957 OemToChar(pathp,pathp);
3958 osi_Log1(smb_logp, "SMB receive check path %s",
3959 osi_LogSaveString(smb_logp, pathp));
3961 rootScp = cm_data.rootSCachep;
3963 userp = smb_GetUser(vcp, inp);
3965 caseFold = CM_FLAG_CASEFOLD;
3967 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3969 cm_ReleaseUser(userp);
3970 return CM_ERROR_NOSUCHPATH;
3972 code = cm_NameI(rootScp, pathp,
3973 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3974 userp, tidPathp, &req, &newScp);
3977 cm_ReleaseUser(userp);
3982 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
3983 cm_ReleaseSCache(newScp);
3984 cm_ReleaseUser(userp);
3985 if ( WANTS_DFS_PATHNAMES(inp) )
3986 return CM_ERROR_PATH_NOT_COVERED;
3988 return CM_ERROR_BADSHARENAME;
3990 #endif /* DFS_SUPPORT */
3992 /* now lock the vnode with a callback; returns with newScp locked */
3993 lock_ObtainMutex(&newScp->mx);
3994 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3995 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3996 if (code && code != CM_ERROR_NOACCESS) {
3997 lock_ReleaseMutex(&newScp->mx);
3998 cm_ReleaseSCache(newScp);
3999 cm_ReleaseUser(userp);
4003 attrs = smb_Attributes(newScp);
4005 if (!(attrs & SMB_ATTR_DIRECTORY))
4006 code = CM_ERROR_NOTDIR;
4008 lock_ReleaseMutex(&newScp->mx);
4010 cm_ReleaseSCache(newScp);
4011 cm_ReleaseUser(userp);
4015 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4019 cm_scache_t *rootScp;
4020 unsigned short attribute;
4022 cm_scache_t *newScp;
4031 /* decode basic attributes we're passed */
4032 attribute = smb_GetSMBParm(inp, 0);
4033 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4035 pathp = smb_GetSMBData(inp, NULL);
4036 pathp = smb_ParseASCIIBlock(pathp, NULL);
4038 return CM_ERROR_BADSMB;
4039 if (smb_StoreAnsiFilenames)
4040 OemToChar(pathp,pathp);
4042 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4043 dosTime, attribute);
4045 rootScp = cm_data.rootSCachep;
4047 userp = smb_GetUser(vcp, inp);
4049 caseFold = CM_FLAG_CASEFOLD;
4051 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4053 cm_ReleaseUser(userp);
4054 return CM_ERROR_NOSUCHFILE;
4056 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4057 tidPathp, &req, &newScp);
4060 cm_ReleaseUser(userp);
4065 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4066 cm_ReleaseSCache(newScp);
4067 cm_ReleaseUser(userp);
4068 if ( WANTS_DFS_PATHNAMES(inp) )
4069 return CM_ERROR_PATH_NOT_COVERED;
4071 return CM_ERROR_BADSHARENAME;
4073 #endif /* DFS_SUPPORT */
4075 /* now lock the vnode with a callback; returns with newScp locked; we
4076 * need the current status to determine what the new status is, in some
4079 lock_ObtainMutex(&newScp->mx);
4080 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4081 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4083 lock_ReleaseMutex(&newScp->mx);
4084 cm_ReleaseSCache(newScp);
4085 cm_ReleaseUser(userp);
4089 /* Check for RO volume */
4090 if (newScp->flags & CM_SCACHEFLAG_RO) {
4091 lock_ReleaseMutex(&newScp->mx);
4092 cm_ReleaseSCache(newScp);
4093 cm_ReleaseUser(userp);
4094 return CM_ERROR_READONLY;
4097 /* prepare for setattr call */
4100 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4101 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4103 if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
4104 /* we're told to make a writable file read-only */
4105 attr.unixModeBits = newScp->unixModeBits & ~0222;
4106 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4108 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
4109 /* we're told to make a read-only file writable */
4110 attr.unixModeBits = newScp->unixModeBits | 0222;
4111 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4113 lock_ReleaseMutex(&newScp->mx);
4115 /* now call setattr */
4117 code = cm_SetAttr(newScp, &attr, userp, &req);
4121 cm_ReleaseSCache(newScp);
4122 cm_ReleaseUser(userp);
4127 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4131 cm_scache_t *rootScp;
4132 cm_scache_t *newScp, *dscp;
4144 pathp = smb_GetSMBData(inp, NULL);
4145 pathp = smb_ParseASCIIBlock(pathp, NULL);
4147 return CM_ERROR_BADSMB;
4149 if (*pathp == 0) /* null path */
4152 if (smb_StoreAnsiFilenames)
4153 OemToChar(pathp,pathp);
4155 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4156 osi_LogSaveString(smb_logp, pathp));
4158 rootScp = cm_data.rootSCachep;
4160 userp = smb_GetUser(vcp, inp);
4162 /* we shouldn't need this for V3 requests, but we seem to */
4163 caseFold = CM_FLAG_CASEFOLD;
4165 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4167 cm_ReleaseUser(userp);
4168 return CM_ERROR_NOSUCHFILE;
4172 * XXX Strange hack XXX
4174 * As of Patch 5 (16 July 97), we are having the following problem:
4175 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4176 * requests to look up "desktop.ini" in all the subdirectories.
4177 * This can cause zillions of timeouts looking up non-existent cells
4178 * and volumes, especially in the top-level directory.
4180 * We have not found any way to avoid this or work around it except
4181 * to explicitly ignore the requests for mount points that haven't
4182 * yet been evaluated and for directories that haven't yet been
4185 * We should modify this hack to provide a fake desktop.ini file
4186 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4188 spacep = inp->spacep;
4189 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4190 #ifndef SPECIAL_FOLDERS
4191 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4192 code = cm_NameI(rootScp, spacep->data,
4193 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4194 userp, tidPathp, &req, &dscp);
4197 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4198 if ( WANTS_DFS_PATHNAMES(inp) )
4199 return CM_ERROR_PATH_NOT_COVERED;
4201 return CM_ERROR_BADSHARENAME;
4203 #endif /* DFS_SUPPORT */
4204 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4205 code = CM_ERROR_NOSUCHFILE;
4206 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4207 cm_buf_t *bp = buf_Find(dscp, &hzero);
4211 code = CM_ERROR_NOSUCHFILE;
4213 cm_ReleaseSCache(dscp);
4215 cm_ReleaseUser(userp);
4220 #endif /* SPECIAL_FOLDERS */
4222 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4223 tidPathp, &req, &newScp);
4225 cm_ReleaseUser(userp);
4230 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4231 cm_ReleaseSCache(newScp);
4232 cm_ReleaseUser(userp);
4233 if ( WANTS_DFS_PATHNAMES(inp) )
4234 return CM_ERROR_PATH_NOT_COVERED;
4236 return CM_ERROR_BADSHARENAME;
4238 #endif /* DFS_SUPPORT */
4240 /* now lock the vnode with a callback; returns with newScp locked */
4241 lock_ObtainMutex(&newScp->mx);
4242 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4243 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4245 lock_ReleaseMutex(&newScp->mx);
4246 cm_ReleaseSCache(newScp);
4247 cm_ReleaseUser(userp);
4252 /* use smb_Attributes instead. Also the fact that a file is
4253 * in a readonly volume doesn't mean it shojuld be marked as RO
4255 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4256 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
4257 attrs = SMB_ATTR_DIRECTORY;
4260 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4261 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4263 attrs = smb_Attributes(newScp);
4266 smb_SetSMBParm(outp, 0, attrs);
4268 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4269 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4270 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4271 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4272 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4273 smb_SetSMBParm(outp, 5, 0);
4274 smb_SetSMBParm(outp, 6, 0);
4275 smb_SetSMBParm(outp, 7, 0);
4276 smb_SetSMBParm(outp, 8, 0);
4277 smb_SetSMBParm(outp, 9, 0);
4278 smb_SetSMBDataLength(outp, 0);
4279 lock_ReleaseMutex(&newScp->mx);
4281 cm_ReleaseSCache(newScp);
4282 cm_ReleaseUser(userp);
4287 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4291 osi_Log0(smb_logp, "SMB receive tree disconnect");
4293 /* find the tree and free it */
4294 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4296 lock_ObtainMutex(&tidp->mx);
4297 tidp->flags |= SMB_TIDFLAG_DELETE;
4298 lock_ReleaseMutex(&tidp->mx);
4299 smb_ReleaseTID(tidp);
4305 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4323 pathp = smb_GetSMBData(inp, NULL);
4324 pathp = smb_ParseASCIIBlock(pathp, NULL);
4325 if (smb_StoreAnsiFilenames)
4326 OemToChar(pathp,pathp);
4328 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4330 #ifdef DEBUG_VERBOSE
4334 hexpath = osi_HexifyString( pathp );
4335 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4340 share = smb_GetSMBParm(inp, 0);
4341 attribute = smb_GetSMBParm(inp, 1);
4343 spacep = inp->spacep;
4344 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4345 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4346 /* special case magic file name for receiving IOCTL requests
4347 * (since IOCTL calls themselves aren't getting through).
4349 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4350 smb_SetupIoctlFid(fidp, spacep);
4351 smb_SetSMBParm(outp, 0, fidp->fid);
4352 smb_SetSMBParm(outp, 1, 0); /* attrs */
4353 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4354 smb_SetSMBParm(outp, 3, 0);
4355 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4356 smb_SetSMBParm(outp, 5, 0x7fff);
4357 /* pass the open mode back */
4358 smb_SetSMBParm(outp, 6, (share & 0xf));
4359 smb_SetSMBDataLength(outp, 0);
4360 smb_ReleaseFID(fidp);
4364 userp = smb_GetUser(vcp, inp);
4366 caseFold = CM_FLAG_CASEFOLD;
4368 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4370 cm_ReleaseUser(userp);
4371 return CM_ERROR_NOSUCHPATH;
4373 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4374 tidPathp, &req, &scp);
4377 cm_ReleaseUser(userp);
4382 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4383 cm_ReleaseSCache(scp);
4384 cm_ReleaseUser(userp);
4385 if ( WANTS_DFS_PATHNAMES(inp) )
4386 return CM_ERROR_PATH_NOT_COVERED;
4388 return CM_ERROR_BADSHARENAME;
4390 #endif /* DFS_SUPPORT */
4392 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4394 cm_ReleaseSCache(scp);
4395 cm_ReleaseUser(userp);
4399 /* don't need callback to check file type, since file types never
4400 * change, and namei and cm_Lookup all stat the object at least once on
4401 * a successful return.
4403 if (scp->fileType != CM_SCACHETYPE_FILE) {
4404 cm_ReleaseSCache(scp);
4405 cm_ReleaseUser(userp);
4406 return CM_ERROR_ISDIR;
4409 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4412 /* save a pointer to the vnode */
4415 if ((share & 0xf) == 0)
4416 fidp->flags |= SMB_FID_OPENREAD;
4417 else if ((share & 0xf) == 1)
4418 fidp->flags |= SMB_FID_OPENWRITE;
4420 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
4422 lock_ObtainMutex(&scp->mx);
4423 smb_SetSMBParm(outp, 0, fidp->fid);
4424 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4425 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4426 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4427 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4428 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4429 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4430 /* pass the open mode back; XXXX add access checks */
4431 smb_SetSMBParm(outp, 6, (share & 0xf));
4432 smb_SetSMBDataLength(outp, 0);
4433 lock_ReleaseMutex(&scp->mx);
4436 cm_Open(scp, 0, userp);
4438 /* send and free packet */
4439 smb_ReleaseFID(fidp);
4440 cm_ReleaseUser(userp);
4441 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4445 typedef struct smb_unlinkRock {
4450 char *maskp; /* pointer to the star pattern */
4455 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4458 smb_unlinkRock_t *rockp;
4466 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4467 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4468 caseFold |= CM_FLAG_8DOT3;
4470 matchName = dep->name;
4471 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4473 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4474 !cm_Is8Dot3(dep->name)) {
4475 cm_Gen8Dot3Name(dep, shortName, NULL);
4476 matchName = shortName;
4477 /* 8.3 matches are always case insensitive */
4478 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4481 osi_Log1(smb_logp, "Unlinking %s",
4482 osi_LogSaveString(smb_logp, matchName));
4483 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
4484 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4485 smb_NotifyChange(FILE_ACTION_REMOVED,
4486 FILE_NOTIFY_CHANGE_FILE_NAME,
4487 dscp, dep->name, NULL, TRUE);
4491 /* If we made a case sensitive exact match, we might as well quit now. */
4492 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4493 code = CM_ERROR_STOPNOW;
4501 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4510 smb_unlinkRock_t rock;
4519 attribute = smb_GetSMBParm(inp, 0);
4521 tp = smb_GetSMBData(inp, NULL);
4522 pathp = smb_ParseASCIIBlock(tp, &tp);
4523 if (smb_StoreAnsiFilenames)
4524 OemToChar(pathp,pathp);
4526 osi_Log1(smb_logp, "SMB receive unlink %s",
4527 osi_LogSaveString(smb_logp, pathp));
4529 spacep = inp->spacep;
4530 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4532 userp = smb_GetUser(vcp, inp);
4534 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4536 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4538 cm_ReleaseUser(userp);
4539 return CM_ERROR_NOSUCHPATH;
4541 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
4544 cm_ReleaseUser(userp);
4549 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4550 cm_ReleaseSCache(dscp);
4551 cm_ReleaseUser(userp);
4552 if ( WANTS_DFS_PATHNAMES(inp) )
4553 return CM_ERROR_PATH_NOT_COVERED;
4555 return CM_ERROR_BADSHARENAME;
4557 #endif /* DFS_SUPPORT */
4559 /* otherwise, scp points to the parent directory. */
4566 rock.maskp = smb_FindMask(pathp);
4567 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4570 thyper.HighPart = 0;
4576 /* Now, if we aren't dealing with a wildcard match, we first try an exact
4577 * match. If that fails, we do a case insensitve match.
4579 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
4580 !smb_IsStarMask(rock.maskp)) {
4581 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4584 thyper.HighPart = 0;
4585 rock.flags |= SMB_MASKFLAG_CASEFOLD;
4590 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
4592 if (code == CM_ERROR_STOPNOW)
4595 cm_ReleaseUser(userp);
4597 cm_ReleaseSCache(dscp);
4599 if (code == 0 && !rock.any)
4600 code = CM_ERROR_NOSUCHFILE;
4604 typedef struct smb_renameRock {
4605 cm_scache_t *odscp; /* old dir */
4606 cm_scache_t *ndscp; /* new dir */
4607 cm_user_t *userp; /* user */
4608 cm_req_t *reqp; /* request struct */
4609 smb_vc_t *vcp; /* virtual circuit */
4610 char *maskp; /* pointer to star pattern of old file name */
4611 int flags; /* tilde, casefold, etc */
4612 char *newNamep; /* ptr to the new file's name */
4615 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4618 smb_renameRock_t *rockp;
4623 rockp = (smb_renameRock_t *) vrockp;
4625 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4626 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4627 caseFold |= CM_FLAG_8DOT3;
4629 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
4631 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4632 !cm_Is8Dot3(dep->name)) {
4633 cm_Gen8Dot3Name(dep, shortName, NULL);
4634 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
4637 code = cm_Rename(rockp->odscp, dep->name,
4638 rockp->ndscp, rockp->newNamep, rockp->userp,
4640 /* if the call worked, stop doing the search now, since we
4641 * really only want to rename one file.
4644 code = CM_ERROR_STOPNOW;
4653 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
4656 cm_space_t *spacep = NULL;
4657 smb_renameRock_t rock;
4658 cm_scache_t *oldDscp = NULL;
4659 cm_scache_t *newDscp = NULL;
4660 cm_scache_t *tmpscp= NULL;
4661 cm_scache_t *tmpscp2 = NULL;
4671 userp = smb_GetUser(vcp, inp);
4672 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4674 cm_ReleaseUser(userp);
4675 return CM_ERROR_NOSUCHPATH;
4679 spacep = inp->spacep;
4680 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4683 * Changed to use CASEFOLD always. This enables us to rename Foo/baz when
4684 * what actually exists is foo/baz. I don't know why the code used to be
4685 * the way it was. 1/29/96
4687 * caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4689 * Changed to use CM_FLAG_FOLLOW. 7/24/96
4691 * caseFold = CM_FLAG_CASEFOLD;
4693 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4694 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4695 userp, tidPathp, &req, &oldDscp);
4697 cm_ReleaseUser(userp);
4702 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4703 cm_ReleaseSCache(oldDscp);
4704 cm_ReleaseUser(userp);
4705 if ( WANTS_DFS_PATHNAMES(inp) )
4706 return CM_ERROR_PATH_NOT_COVERED;
4708 return CM_ERROR_BADSHARENAME;
4710 #endif /* DFS_SUPPORT */
4712 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4713 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4714 userp, tidPathp, &req, &newDscp);
4717 cm_ReleaseSCache(oldDscp);
4718 cm_ReleaseUser(userp);
4723 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4724 cm_ReleaseSCache(oldDscp);
4725 cm_ReleaseSCache(newDscp);
4726 cm_ReleaseUser(userp);
4727 if ( WANTS_DFS_PATHNAMES(inp) )
4728 return CM_ERROR_PATH_NOT_COVERED;
4730 return CM_ERROR_BADSHARENAME;
4732 #endif /* DFS_SUPPORT */
4735 /* otherwise, oldDscp and newDscp point to the corresponding directories.
4736 * next, get the component names, and lower case them.
4739 /* handle the old name first */
4741 oldLastNamep = oldPathp;
4745 /* and handle the new name, too */
4747 newLastNamep = newPathp;
4751 /* TODO: The old name could be a wildcard. The new name must not be */
4753 /* do the vnode call */
4754 rock.odscp = oldDscp;
4755 rock.ndscp = newDscp;
4759 rock.maskp = oldLastNamep;
4760 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
4761 rock.newNamep = newLastNamep;
4763 /* Check if the file already exists; if so return error */
4764 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4765 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4766 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4767 osi_LogSaveString(afsd_logp, newLastNamep));
4769 /* Check if the old and the new names differ only in case. If so return
4770 * success, else return CM_ERROR_EXISTS
4772 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4774 /* This would be a success only if the old file is *as same as* the new file */
4775 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
4777 if (tmpscp == tmpscp2)
4780 code = CM_ERROR_EXISTS;
4781 cm_ReleaseSCache(tmpscp2);
4784 code = CM_ERROR_NOSUCHFILE;
4787 /* file exist, do not rename, also fixes move */
4788 osi_Log0(smb_logp, "Can't rename. Target already exists");
4789 code = CM_ERROR_EXISTS;
4793 cm_ReleaseSCache(tmpscp);
4794 cm_ReleaseSCache(newDscp);
4795 cm_ReleaseSCache(oldDscp);
4796 cm_ReleaseUser(userp);
4800 /* Now search the directory for the pattern, and do the appropriate rename when found */
4801 thyper.LowPart = 0; /* search dir from here */
4802 thyper.HighPart = 0;
4804 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4806 if (code == CM_ERROR_STOPNOW)
4809 code = CM_ERROR_NOSUCHFILE;
4811 /* Handle Change Notification */
4813 * Being lazy, not distinguishing between files and dirs in this
4814 * filter, since we'd have to do a lookup.
4816 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4817 if (oldDscp == newDscp) {
4818 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4819 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4820 filter, oldDscp, oldLastNamep,
4821 newLastNamep, TRUE);
4823 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4824 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4825 filter, oldDscp, oldLastNamep,
4827 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4828 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4829 filter, newDscp, newLastNamep,
4834 cm_ReleaseSCache(tmpscp);
4835 cm_ReleaseUser(userp);
4836 cm_ReleaseSCache(oldDscp);
4837 cm_ReleaseSCache(newDscp);
4842 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
4845 cm_space_t *spacep = NULL;
4846 cm_scache_t *oldDscp = NULL;
4847 cm_scache_t *newDscp = NULL;
4848 cm_scache_t *tmpscp= NULL;
4849 cm_scache_t *tmpscp2 = NULL;
4850 cm_scache_t *sscp = NULL;
4859 userp = smb_GetUser(vcp, inp);
4861 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4863 cm_ReleaseUser(userp);
4864 return CM_ERROR_NOSUCHPATH;
4869 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4871 spacep = inp->spacep;
4872 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4874 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4875 userp, tidPathp, &req, &oldDscp);
4877 cm_ReleaseUser(userp);
4882 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4883 cm_ReleaseSCache(oldDscp);
4884 cm_ReleaseUser(userp);
4885 if ( WANTS_DFS_PATHNAMES(inp) )
4886 return CM_ERROR_PATH_NOT_COVERED;
4888 return CM_ERROR_BADSHARENAME;
4890 #endif /* DFS_SUPPORT */
4892 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4893 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
4894 userp, tidPathp, &req, &newDscp);
4896 cm_ReleaseSCache(oldDscp);
4897 cm_ReleaseUser(userp);
4902 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
4903 cm_ReleaseSCache(newDscp);
4904 cm_ReleaseSCache(oldDscp);
4905 cm_ReleaseUser(userp);
4906 if ( WANTS_DFS_PATHNAMES(inp) )
4907 return CM_ERROR_PATH_NOT_COVERED;
4909 return CM_ERROR_BADSHARENAME;
4911 #endif /* DFS_SUPPORT */
4913 /* Now, although we did two lookups for the two directories (because the same
4914 * directory can be referenced through different paths), we only allow hard links
4915 * within the same directory. */
4916 if (oldDscp != newDscp) {
4917 cm_ReleaseSCache(oldDscp);
4918 cm_ReleaseSCache(newDscp);
4919 cm_ReleaseUser(userp);
4920 return CM_ERROR_CROSSDEVLINK;
4923 /* handle the old name first */
4925 oldLastNamep = oldPathp;
4929 /* and handle the new name, too */
4931 newLastNamep = newPathp;
4935 /* now lookup the old name */
4936 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
4937 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
4939 cm_ReleaseSCache(oldDscp);
4940 cm_ReleaseSCache(newDscp);
4941 cm_ReleaseUser(userp);
4945 /* Check if the file already exists; if so return error */
4946 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4947 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4948 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
4949 osi_LogSaveString(afsd_logp, newLastNamep));
4951 /* if the existing link is to the same file, then we return success */
4953 if(sscp == tmpscp) {
4956 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
4957 code = CM_ERROR_EXISTS;
4962 cm_ReleaseSCache(tmpscp);
4963 cm_ReleaseSCache(sscp);
4964 cm_ReleaseSCache(newDscp);
4965 cm_ReleaseSCache(oldDscp);
4966 cm_ReleaseUser(userp);
4970 /* now create the hardlink */
4971 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
4972 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
4973 osi_Log1(smb_logp," Link returns %d", code);
4975 /* Handle Change Notification */
4977 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
4978 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4979 smb_NotifyChange(FILE_ACTION_ADDED,
4980 filter, newDscp, newLastNamep,
4985 cm_ReleaseSCache(tmpscp);
4986 cm_ReleaseUser(userp);
4987 cm_ReleaseSCache(sscp);
4988 cm_ReleaseSCache(oldDscp);
4989 cm_ReleaseSCache(newDscp);
4994 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5000 tp = smb_GetSMBData(inp, NULL);
5001 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5002 if (smb_StoreAnsiFilenames)
5003 OemToChar(oldPathp,oldPathp);
5004 newPathp = smb_ParseASCIIBlock(tp, &tp);
5005 if (smb_StoreAnsiFilenames)
5006 OemToChar(newPathp,newPathp);
5008 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5009 osi_LogSaveString(smb_logp, oldPathp),
5010 osi_LogSaveString(smb_logp, newPathp));
5012 return smb_Rename(vcp,inp,oldPathp,newPathp,0);
5017 typedef struct smb_rmdirRock {
5021 char *maskp; /* pointer to the star pattern */
5026 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5029 smb_rmdirRock_t *rockp;
5034 rockp = (smb_rmdirRock_t *) vrockp;
5036 matchName = dep->name;
5037 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5038 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5040 match = (strcmp(matchName, rockp->maskp) == 0);
5042 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5043 !cm_Is8Dot3(dep->name)) {
5044 cm_Gen8Dot3Name(dep, shortName, NULL);
5045 matchName = shortName;
5046 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5049 osi_Log1(smb_logp, "Removing directory %s",
5050 osi_LogSaveString(smb_logp, matchName));
5051 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
5052 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5053 smb_NotifyChange(FILE_ACTION_REMOVED,
5054 FILE_NOTIFY_CHANGE_DIR_NAME,
5055 dscp, dep->name, NULL, TRUE);
5064 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5072 smb_rmdirRock_t rock;
5081 tp = smb_GetSMBData(inp, NULL);
5082 pathp = smb_ParseASCIIBlock(tp, &tp);
5083 if (smb_StoreAnsiFilenames)
5084 OemToChar(pathp,pathp);
5086 spacep = inp->spacep;
5087 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5089 userp = smb_GetUser(vcp, inp);
5091 caseFold = CM_FLAG_CASEFOLD;
5093 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5095 cm_ReleaseUser(userp);
5096 return CM_ERROR_NOSUCHPATH;
5098 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5099 userp, tidPathp, &req, &dscp);
5102 cm_ReleaseUser(userp);
5107 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5108 cm_ReleaseSCache(dscp);
5109 cm_ReleaseUser(userp);
5110 if ( WANTS_DFS_PATHNAMES(inp) )
5111 return CM_ERROR_PATH_NOT_COVERED;
5113 return CM_ERROR_BADSHARENAME;
5115 #endif /* DFS_SUPPORT */
5117 /* otherwise, scp points to the parent directory. */
5124 rock.maskp = lastNamep;
5125 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5128 thyper.HighPart = 0;
5132 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5133 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5134 if (code == 0 && !rock.any) {
5136 thyper.HighPart = 0;
5137 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5138 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5141 cm_ReleaseUser(userp);
5143 cm_ReleaseSCache(dscp);
5145 if (code == 0 && !rock.any)
5146 code = CM_ERROR_NOSUCHFILE;
5150 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5160 fid = smb_GetSMBParm(inp, 0);
5162 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5164 fid = smb_ChainFID(fid, inp);
5165 fidp = smb_FindFID(vcp, fid, 0);
5166 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5168 smb_ReleaseFID(fidp);
5169 return CM_ERROR_BADFD;
5172 userp = smb_GetUser(vcp, inp);
5174 lock_ObtainMutex(&fidp->mx);
5175 if (fidp->flags & SMB_FID_OPENWRITE)
5176 code = cm_FSync(fidp->scp, userp, &req);
5179 lock_ReleaseMutex(&fidp->mx);
5181 smb_ReleaseFID(fidp);
5183 cm_ReleaseUser(userp);
5188 struct smb_FullNameRock {
5194 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5198 struct smb_FullNameRock *vrockp;
5200 vrockp = (struct smb_FullNameRock *)rockp;
5202 if (!cm_Is8Dot3(dep->name)) {
5203 cm_Gen8Dot3Name(dep, shortName, NULL);
5205 if (cm_stricmp(shortName, vrockp->name) == 0) {
5206 vrockp->fullName = strdup(dep->name);
5207 return CM_ERROR_STOPNOW;
5210 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5211 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5212 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5213 vrockp->fullName = strdup(dep->name);
5214 return CM_ERROR_STOPNOW;
5219 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5220 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5222 struct smb_FullNameRock rock;
5228 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5229 if (code == CM_ERROR_STOPNOW)
5230 *newPathp = rock.fullName;
5232 *newPathp = strdup(pathp);
5235 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5246 fid = smb_GetSMBParm(inp, 0);
5247 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5249 osi_Log1(smb_logp, "SMB close fid %d", fid);
5251 fid = smb_ChainFID(fid, inp);
5252 fidp = smb_FindFID(vcp, fid, 0);
5254 return CM_ERROR_BADFD;
5257 userp = smb_GetUser(vcp, inp);
5259 lock_ObtainMutex(&fidp->mx);
5261 /* Don't jump the gun on an async raw write */
5262 while (fidp->raw_writers) {
5263 lock_ReleaseMutex(&fidp->mx);
5264 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5265 lock_ObtainMutex(&fidp->mx);
5268 fidp->flags |= SMB_FID_DELETE;
5270 /* watch for ioctl closes, and read-only opens */
5271 if (fidp->scp != NULL &&
5272 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5273 == SMB_FID_OPENWRITE) {
5274 if (dosTime != 0 && dosTime != -1) {
5275 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5276 /* This fixes defect 10958 */
5277 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5278 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5280 code = cm_FSync(fidp->scp, userp, &req);
5285 if (fidp->flags & SMB_FID_DELONCLOSE) {
5286 cm_scache_t *dscp = fidp->NTopen_dscp;
5287 char *pathp = fidp->NTopen_pathp;
5290 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
5291 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
5292 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5293 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5294 smb_NotifyChange(FILE_ACTION_REMOVED,
5295 FILE_NOTIFY_CHANGE_DIR_NAME,
5296 dscp, fullPathp, NULL, TRUE);
5300 code = cm_Unlink(dscp, fullPathp, userp, &req);
5301 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5302 smb_NotifyChange(FILE_ACTION_REMOVED,
5303 FILE_NOTIFY_CHANGE_FILE_NAME,
5304 dscp, fullPathp, NULL, TRUE);
5308 lock_ReleaseMutex(&fidp->mx);
5310 if (fidp->flags & SMB_FID_NTOPEN) {
5311 cm_ReleaseSCache(fidp->NTopen_dscp);
5312 free(fidp->NTopen_pathp);
5314 if (fidp->NTopen_wholepathp)
5315 free(fidp->NTopen_wholepathp);
5317 smb_ReleaseFID(fidp);
5318 cm_ReleaseUser(userp);
5323 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5326 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5327 cm_user_t *userp, long *readp)
5329 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5330 cm_user_t *userp, long *readp, int dosflag)
5337 osi_hyper_t fileLength;
5339 osi_hyper_t lastByte;
5340 osi_hyper_t bufferOffset;
5341 long bufIndex, nbytes;
5351 lock_ObtainMutex(&fidp->mx);
5353 lock_ObtainMutex(&scp->mx);
5355 if (offset.HighPart == 0) {
5356 chunk = offset.LowPart >> cm_logChunkSize;
5357 if (chunk != fidp->curr_chunk) {
5358 fidp->prev_chunk = fidp->curr_chunk;
5359 fidp->curr_chunk = chunk;
5361 if (fidp->curr_chunk == fidp->prev_chunk + 1)
5365 /* start by looking up the file's end */
5366 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5367 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5368 if (code) goto done;
5370 /* now we have the entry locked, look up the length */
5371 fileLength = scp->length;
5373 /* adjust count down so that it won't go past EOF */
5374 thyper.LowPart = count;
5375 thyper.HighPart = 0;
5376 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
5378 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5379 /* we'd read past EOF, so just stop at fileLength bytes.
5380 * Start by computing how many bytes remain in the file.
5382 thyper = LargeIntegerSubtract(fileLength, offset);
5384 /* if we are past EOF, read 0 bytes */
5385 if (LargeIntegerLessThanZero(thyper))
5388 count = thyper.LowPart;
5393 /* now, copy the data one buffer at a time,
5394 * until we've filled the request packet
5397 /* if we've copied all the data requested, we're done */
5398 if (count <= 0) break;
5400 /* otherwise, load up a buffer of data */
5401 thyper.HighPart = offset.HighPart;
5402 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5403 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5406 buf_Release(bufferp);
5409 lock_ReleaseMutex(&scp->mx);
5411 lock_ObtainRead(&scp->bufCreateLock);
5412 code = buf_Get(scp, &thyper, &bufferp);
5413 lock_ReleaseRead(&scp->bufCreateLock);
5415 lock_ObtainMutex(&scp->mx);
5416 if (code) goto done;
5417 bufferOffset = thyper;
5419 /* now get the data in the cache */
5421 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5422 CM_SCACHESYNC_NEEDCALLBACK |
5423 CM_SCACHESYNC_READ);
5424 if (code) goto done;
5426 if (cm_HaveBuffer(scp, bufferp, 0)) break;
5428 /* otherwise, load the buffer and try again */
5429 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5433 buf_Release(bufferp);
5437 } /* if (wrong buffer) ... */
5439 /* now we have the right buffer loaded. Copy out the
5440 * data from here to the user's buffer.
5442 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5444 /* and figure out how many bytes we want from this buffer */
5445 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5446 if (nbytes > count) nbytes = count; /* don't go past EOF */
5448 /* now copy the data */
5451 dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
5454 memcpy(op, bufferp->datap + bufIndex, nbytes);
5456 /* adjust counters, pointers, etc. */
5459 thyper.LowPart = nbytes;
5460 thyper.HighPart = 0;
5461 offset = LargeIntegerAdd(thyper, offset);
5465 lock_ReleaseMutex(&scp->mx);
5466 lock_ReleaseMutex(&fidp->mx);
5468 buf_Release(bufferp);
5470 if (code == 0 && sequential)
5471 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
5477 * smb_WriteData -- common code for Write and Raw Write
5480 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5481 cm_user_t *userp, long *writtenp)
5483 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
5484 cm_user_t *userp, long *writtenp, int dosflag)
5491 osi_hyper_t fileLength; /* file's length at start of write */
5492 osi_hyper_t minLength; /* don't read past this */
5493 long nbytes; /* # of bytes to transfer this iteration */
5495 osi_hyper_t thyper; /* hyper tmp variable */
5496 osi_hyper_t bufferOffset;
5497 long bufIndex; /* index in buffer where our data is */
5499 osi_hyper_t writeBackOffset;/* offset of region to write back when
5504 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
5505 fidp->fid, offsetp->LowPart, count);
5515 lock_ObtainMutex(&fidp->mx);
5517 lock_ObtainMutex(&scp->mx);
5519 /* start by looking up the file's end */
5520 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS",
5522 code = cm_SyncOp(scp, NULL, userp, &req, 0,
5523 CM_SCACHESYNC_NEEDCALLBACK
5524 | CM_SCACHESYNC_SETSTATUS
5525 | CM_SCACHESYNC_GETSTATUS);
5526 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|SETSTATUS|GETSTATUS returns %d",
5531 /* make sure we have a writable FD */
5532 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
5533 code = CM_ERROR_BADFDOP;
5537 /* now we have the entry locked, look up the length */
5538 fileLength = scp->length;
5539 minLength = fileLength;
5540 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
5541 minLength = scp->serverLength;
5543 /* adjust file length if we extend past EOF */
5544 thyper.LowPart = count;
5545 thyper.HighPart = 0;
5546 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
5547 if (LargeIntegerGreaterThan(thyper, fileLength)) {
5548 /* we'd write past EOF, so extend the file */
5549 scp->mask |= CM_SCACHEMASK_LENGTH;
5550 scp->length = thyper;
5551 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
5553 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
5555 /* now, if the new position (thyper) and the old (offset) are in
5556 * different storeback windows, remember to store back the previous
5557 * storeback window when we're done with the write.
5559 if ((thyper.LowPart & (-cm_chunkSize)) !=
5560 (offset.LowPart & (-cm_chunkSize))) {
5561 /* they're different */
5563 writeBackOffset.HighPart = offset.HighPart;
5564 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
5569 /* now, copy the data one buffer at a time, until we've filled the
5572 /* if we've copied all the data requested, we're done */
5576 /* handle over quota or out of space */
5577 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
5578 *writtenp = written;
5579 code = CM_ERROR_QUOTA;
5583 /* otherwise, load up a buffer of data */
5584 thyper.HighPart = offset.HighPart;
5585 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
5586 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5589 lock_ReleaseMutex(&bufferp->mx);
5590 buf_Release(bufferp);
5593 lock_ReleaseMutex(&scp->mx);
5595 lock_ObtainRead(&scp->bufCreateLock);
5596 code = buf_Get(scp, &thyper, &bufferp);
5597 lock_ReleaseRead(&scp->bufCreateLock);
5599 lock_ObtainMutex(&bufferp->mx);
5600 lock_ObtainMutex(&scp->mx);
5601 if (code) goto done;
5603 bufferOffset = thyper;
5605 /* now get the data in the cache */
5607 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED",
5609 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
5610 CM_SCACHESYNC_NEEDCALLBACK
5611 | CM_SCACHESYNC_WRITE
5612 | CM_SCACHESYNC_BUFLOCKED);
5613 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp NEEDCALLBACK|WRITE|BUFLOCKED returns %d",
5618 /* If we're overwriting the entire buffer, or
5619 * if we're writing at or past EOF, mark the
5620 * buffer as current so we don't call
5621 * cm_GetBuffer. This skips the fetch from the
5622 * server in those cases where we're going to
5623 * obliterate all the data in the buffer anyway,
5624 * or in those cases where there is no useful
5625 * data at the server to start with.
5627 * Use minLength instead of scp->length, since
5628 * the latter has already been updated by this
5631 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
5632 || LargeIntegerEqualTo(offset, bufferp->offset)
5633 && (count >= cm_data.buf_blockSize
5634 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
5635 ConvertLongToLargeInteger(count)),
5637 if (count < cm_data.buf_blockSize
5638 && bufferp->dataVersion == -1)
5639 memset(bufferp->datap, 0,
5640 cm_data.buf_blockSize);
5641 bufferp->dataVersion = scp->dataVersion;
5644 if (cm_HaveBuffer(scp, bufferp, 1)) break;
5646 /* otherwise, load the buffer and try again */
5647 lock_ReleaseMutex(&bufferp->mx);
5648 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5650 lock_ReleaseMutex(&scp->mx);
5651 lock_ObtainMutex(&bufferp->mx);
5652 lock_ObtainMutex(&scp->mx);
5656 lock_ReleaseMutex(&bufferp->mx);
5657 buf_Release(bufferp);
5661 } /* if (wrong buffer) ... */
5663 /* now we have the right buffer loaded. Copy out the
5664 * data from here to the user's buffer.
5666 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
5668 /* and figure out how many bytes we want from this buffer */
5669 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
5671 nbytes = count; /* don't go past end of request */
5673 /* now copy the data */
5676 dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
5679 memcpy(bufferp->datap + bufIndex, op, nbytes);
5680 buf_SetDirty(bufferp);
5682 /* and record the last writer */
5683 if (bufferp->userp != userp) {
5686 cm_ReleaseUser(bufferp->userp);
5687 bufferp->userp = userp;
5690 /* adjust counters, pointers, etc. */
5694 thyper.LowPart = nbytes;
5695 thyper.HighPart = 0;
5696 offset = LargeIntegerAdd(thyper, offset);
5700 lock_ReleaseMutex(&scp->mx);
5701 lock_ReleaseMutex(&fidp->mx);
5703 lock_ReleaseMutex(&bufferp->mx);
5704 buf_Release(bufferp);
5707 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
5708 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
5709 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
5710 fidp->NTopen_dscp, fidp->NTopen_pathp,
5714 if (code == 0 && doWriteBack) {
5716 lock_ObtainMutex(&scp->mx);
5717 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
5719 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
5720 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
5722 lock_ReleaseMutex(&scp->mx);
5723 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
5724 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
5727 osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
5728 fidp->fid, code, *writtenp);
5732 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5735 long count, written = 0, total_written = 0;
5740 cm_attr_t truncAttr; /* attribute struct used for truncating file */
5742 int inDataBlockCount;
5744 fd = smb_GetSMBParm(inp, 0);
5745 count = smb_GetSMBParm(inp, 1);
5746 offset.HighPart = 0; /* too bad */
5747 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5749 op = smb_GetSMBData(inp, NULL);
5750 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
5752 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
5753 fd, offset.LowPart, count);
5755 fd = smb_ChainFID(fd, inp);
5756 fidp = smb_FindFID(vcp, fd, 0);
5758 return CM_ERROR_BADFD;
5761 if (fidp->flags & SMB_FID_IOCTL)
5762 return smb_IoctlWrite(fidp, vcp, inp, outp);
5764 userp = smb_GetUser(vcp, inp);
5766 /* special case: 0 bytes transferred means truncate to this position */
5772 truncAttr.mask = CM_ATTRMASK_LENGTH;
5773 truncAttr.length.LowPart = offset.LowPart;
5774 truncAttr.length.HighPart = 0;
5775 lock_ObtainMutex(&fidp->mx);
5776 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
5777 lock_ReleaseMutex(&fidp->mx);
5778 smb_SetSMBParm(outp, 0, /* count */ 0);
5779 smb_SetSMBDataLength(outp, 0);
5780 fidp->flags |= SMB_FID_LENGTHSETDONE;
5785 * Work around bug in NT client
5787 * When copying a file, the NT client should first copy the data,
5788 * then copy the last write time. But sometimes the NT client does
5789 * these in the wrong order, so the data copies would inadvertently
5790 * cause the last write time to be overwritten. We try to detect this,
5791 * and don't set client mod time if we think that would go against the
5794 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5795 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5796 fidp->scp->clientModTime = time(NULL);
5800 while ( code == 0 && count > 0 ) {
5802 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5804 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5806 if (code == 0 && written == 0)
5807 code = CM_ERROR_PARTIALWRITE;
5809 offset.LowPart += written;
5811 total_written += written;
5815 /* set the packet data length to 3 bytes for the data block header,
5816 * plus the size of the data.
5818 smb_SetSMBParm(outp, 0, total_written);
5819 smb_SetSMBDataLength(outp, 0);
5822 smb_ReleaseFID(fidp);
5823 cm_ReleaseUser(userp);
5828 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5829 NCB *ncbp, raw_write_cont_t *rwcp)
5842 fd = smb_GetSMBParm(inp, 0);
5843 fidp = smb_FindFID(vcp, fd, 0);
5845 osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
5846 rwcp->offset.LowPart, rwcp->count);
5848 userp = smb_GetUser(vcp, inp);
5852 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
5855 rawBuf = (dos_ptr) rwcp->buf;
5856 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
5857 (unsigned char *) rawBuf, userp,
5861 if (rwcp->writeMode & 0x1) { /* synchronous */
5864 smb_FormatResponsePacket(vcp, inp, outp);
5865 op = (smb_t *) outp;
5866 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
5867 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
5868 smb_SetSMBDataLength(outp, 0);
5869 smb_SendPacket(vcp, outp);
5870 smb_FreePacket(outp);
5872 else { /* asynchronous */
5873 lock_ObtainMutex(&fidp->mx);
5874 fidp->raw_writers--;
5875 if (fidp->raw_writers == 0)
5876 thrd_SetEvent(fidp->raw_write_event);
5877 lock_ReleaseMutex(&fidp->mx);
5880 /* Give back raw buffer */
5881 lock_ObtainMutex(&smb_RawBufLock);
5883 *((char **)rawBuf) = smb_RawBufs;
5885 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
5887 smb_RawBufs = rawBuf;
5888 lock_ReleaseMutex(&smb_RawBufLock);
5890 smb_ReleaseFID(fidp);
5891 cm_ReleaseUser(userp);
5894 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5899 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
5902 long count, written = 0, total_written = 0;
5909 unsigned short writeMode;
5916 fd = smb_GetSMBParm(inp, 0);
5917 totalCount = smb_GetSMBParm(inp, 1);
5918 count = smb_GetSMBParm(inp, 10);
5919 offset.HighPart = 0; /* too bad */
5920 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5921 writeMode = smb_GetSMBParm(inp, 7);
5923 op = (char *) inp->data;
5924 op += smb_GetSMBParm(inp, 11);
5927 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5928 fd, offset.LowPart, count, writeMode);
5930 fd = smb_ChainFID(fd, inp);
5931 fidp = smb_FindFID(vcp, fd, 0);
5933 return CM_ERROR_BADFD;
5936 userp = smb_GetUser(vcp, inp);
5939 * Work around bug in NT client
5941 * When copying a file, the NT client should first copy the data,
5942 * then copy the last write time. But sometimes the NT client does
5943 * these in the wrong order, so the data copies would inadvertently
5944 * cause the last write time to be overwritten. We try to detect this,
5945 * and don't set client mod time if we think that would go against the
5948 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5949 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5950 fidp->scp->clientModTime = time(NULL);
5954 while ( code == 0 && count > 0 ) {
5956 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5958 code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5960 if (code == 0 && written == 0)
5961 code = CM_ERROR_PARTIALWRITE;
5963 offset.LowPart += written;
5965 total_written += written;
5969 /* Get a raw buffer */
5972 lock_ObtainMutex(&smb_RawBufLock);
5974 /* Get a raw buf, from head of list */
5975 rawBuf = smb_RawBufs;
5977 smb_RawBufs = *(char **)smb_RawBufs;
5979 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5983 code = CM_ERROR_USESTD;
5985 lock_ReleaseMutex(&smb_RawBufLock);
5988 /* Don't allow a premature Close */
5989 if (code == 0 && (writeMode & 1) == 0) {
5990 lock_ObtainMutex(&fidp->mx);
5991 fidp->raw_writers++;
5992 thrd_ResetEvent(fidp->raw_write_event);
5993 lock_ReleaseMutex(&fidp->mx);
5996 smb_ReleaseFID(fidp);
5997 cm_ReleaseUser(userp);
6000 smb_SetSMBParm(outp, 0, total_written);
6001 smb_SetSMBDataLength(outp, 0);
6002 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6009 rwcp->offset.HighPart = 0;
6010 rwcp->offset.LowPart = offset.LowPart + count;
6011 rwcp->count = totalCount - count;
6012 rwcp->writeMode = writeMode;
6013 rwcp->alreadyWritten = total_written;
6015 /* set the packet data length to 3 bytes for the data block header,
6016 * plus the size of the data.
6018 smb_SetSMBParm(outp, 0, 0xffff);
6019 smb_SetSMBDataLength(outp, 0);
6024 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6027 long count, finalCount;
6034 fd = smb_GetSMBParm(inp, 0);
6035 count = smb_GetSMBParm(inp, 1);
6036 offset.HighPart = 0; /* too bad */
6037 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6039 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6040 fd, offset.LowPart, count);
6042 fd = smb_ChainFID(fd, inp);
6043 fidp = smb_FindFID(vcp, fd, 0);
6045 return CM_ERROR_BADFD;
6048 if (fidp->flags & SMB_FID_IOCTL) {
6049 return smb_IoctlRead(fidp, vcp, inp, outp);
6052 userp = smb_GetUser(vcp, inp);
6054 /* remember this for final results */
6055 smb_SetSMBParm(outp, 0, count);
6056 smb_SetSMBParm(outp, 1, 0);
6057 smb_SetSMBParm(outp, 2, 0);
6058 smb_SetSMBParm(outp, 3, 0);
6059 smb_SetSMBParm(outp, 4, 0);
6061 /* set the packet data length to 3 bytes for the data block header,
6062 * plus the size of the data.
6064 smb_SetSMBDataLength(outp, count+3);
6066 /* get op ptr after putting in the parms, since otherwise we don't
6067 * know where the data really is.
6069 op = smb_GetSMBData(outp, NULL);
6071 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6072 *op++ = 1; /* data block marker */
6073 *op++ = (unsigned char) (count & 0xff);
6074 *op++ = (unsigned char) ((count >> 8) & 0xff);
6077 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6079 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6082 /* fix some things up */
6083 smb_SetSMBParm(outp, 0, finalCount);
6084 smb_SetSMBDataLength(outp, finalCount+3);
6086 smb_ReleaseFID(fidp);
6088 cm_ReleaseUser(userp);
6092 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6099 cm_scache_t *dscp; /* dir we're dealing with */
6100 cm_scache_t *scp; /* file we're creating */
6102 int initialModeBits;
6112 /* compute initial mode bits based on read-only flag in attributes */
6113 initialModeBits = 0777;
6115 tp = smb_GetSMBData(inp, NULL);
6116 pathp = smb_ParseASCIIBlock(tp, &tp);
6117 if (smb_StoreAnsiFilenames)
6118 OemToChar(pathp,pathp);
6120 if (strcmp(pathp, "\\") == 0)
6121 return CM_ERROR_EXISTS;
6123 spacep = inp->spacep;
6124 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6126 userp = smb_GetUser(vcp, inp);
6128 caseFold = CM_FLAG_CASEFOLD;
6130 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6132 cm_ReleaseUser(userp);
6133 return CM_ERROR_NOSUCHPATH;
6136 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6137 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6138 userp, tidPathp, &req, &dscp);
6141 cm_ReleaseUser(userp);
6146 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6147 cm_ReleaseSCache(dscp);
6148 cm_ReleaseUser(userp);
6149 if ( WANTS_DFS_PATHNAMES(inp) )
6150 return CM_ERROR_PATH_NOT_COVERED;
6152 return CM_ERROR_BADSHARENAME;
6154 #endif /* DFS_SUPPORT */
6156 /* otherwise, scp points to the parent directory. Do a lookup, and
6157 * fail if we find it. Otherwise, we do the create.
6163 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6164 if (scp) cm_ReleaseSCache(scp);
6165 if (code != CM_ERROR_NOSUCHFILE) {
6166 if (code == 0) code = CM_ERROR_EXISTS;
6167 cm_ReleaseSCache(dscp);
6168 cm_ReleaseUser(userp);
6172 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6173 setAttr.clientModTime = time(NULL);
6174 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6175 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6176 smb_NotifyChange(FILE_ACTION_ADDED,
6177 FILE_NOTIFY_CHANGE_DIR_NAME,
6178 dscp, lastNamep, NULL, TRUE);
6180 /* we don't need this any longer */
6181 cm_ReleaseSCache(dscp);
6184 /* something went wrong creating or truncating the file */
6185 cm_ReleaseUser(userp);
6189 /* otherwise we succeeded */
6190 smb_SetSMBDataLength(outp, 0);
6191 cm_ReleaseUser(userp);
6196 BOOL smb_IsLegalFilename(char *filename)
6199 * Find the longest substring of filename that does not contain
6200 * any of the chars in illegalChars. If that substring is less
6201 * than the length of the whole string, then one or more of the
6202 * illegal chars is in filename.
6204 if (strcspn(filename, illegalChars) < strlen(filename))
6210 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6218 cm_scache_t *dscp; /* dir we're dealing with */
6219 cm_scache_t *scp; /* file we're creating */
6221 int initialModeBits;
6233 excl = (inp->inCom == 0x03)? 0 : 1;
6235 attributes = smb_GetSMBParm(inp, 0);
6236 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6238 /* compute initial mode bits based on read-only flag in attributes */
6239 initialModeBits = 0666;
6240 if (attributes & 1) initialModeBits &= ~0222;
6242 tp = smb_GetSMBData(inp, NULL);
6243 pathp = smb_ParseASCIIBlock(tp, &tp);
6244 if (smb_StoreAnsiFilenames)
6245 OemToChar(pathp,pathp);
6247 spacep = inp->spacep;
6248 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6250 userp = smb_GetUser(vcp, inp);
6252 caseFold = CM_FLAG_CASEFOLD;
6254 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6256 cm_ReleaseUser(userp);
6257 return CM_ERROR_NOSUCHPATH;
6259 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
6260 userp, tidPathp, &req, &dscp);
6263 cm_ReleaseUser(userp);
6268 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6269 cm_ReleaseSCache(dscp);
6270 cm_ReleaseUser(userp);
6271 if ( WANTS_DFS_PATHNAMES(inp) )
6272 return CM_ERROR_PATH_NOT_COVERED;
6274 return CM_ERROR_BADSHARENAME;
6276 #endif /* DFS_SUPPORT */
6278 /* otherwise, scp points to the parent directory. Do a lookup, and
6279 * truncate the file if we find it, otherwise we create the file.
6286 if (!smb_IsLegalFilename(lastNamep))
6287 return CM_ERROR_BADNTFILENAME;
6289 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
6290 #ifdef DEBUG_VERBOSE
6293 hexp = osi_HexifyString( lastNamep );
6294 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
6299 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6300 if (code && code != CM_ERROR_NOSUCHFILE) {
6301 cm_ReleaseSCache(dscp);
6302 cm_ReleaseUser(userp);
6306 /* if we get here, if code is 0, the file exists and is represented by
6307 * scp. Otherwise, we have to create it.
6311 /* oops, file shouldn't be there */
6312 cm_ReleaseSCache(dscp);
6313 cm_ReleaseSCache(scp);
6314 cm_ReleaseUser(userp);
6315 return CM_ERROR_EXISTS;
6318 setAttr.mask = CM_ATTRMASK_LENGTH;
6319 setAttr.length.LowPart = 0;
6320 setAttr.length.HighPart = 0;
6321 code = cm_SetAttr(scp, &setAttr, userp, &req);
6324 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6325 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6326 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6328 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6329 smb_NotifyChange(FILE_ACTION_ADDED,
6330 FILE_NOTIFY_CHANGE_FILE_NAME,
6331 dscp, lastNamep, NULL, TRUE);
6332 if (!excl && code == CM_ERROR_EXISTS) {
6333 /* not an exclusive create, and someone else tried
6334 * creating it already, then we open it anyway. We
6335 * don't bother retrying after this, since if this next
6336 * fails, that means that the file was deleted after
6337 * we started this call.
6339 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
6342 setAttr.mask = CM_ATTRMASK_LENGTH;
6343 setAttr.length.LowPart = 0;
6344 setAttr.length.HighPart = 0;
6345 code = cm_SetAttr(scp, &setAttr, userp, &req);
6350 /* we don't need this any longer */
6351 cm_ReleaseSCache(dscp);
6354 /* something went wrong creating or truncating the file */
6355 if (scp) cm_ReleaseSCache(scp);
6356 cm_ReleaseUser(userp);
6360 /* make sure we only open files */
6361 if (scp->fileType != CM_SCACHETYPE_FILE) {
6362 cm_ReleaseSCache(scp);
6363 cm_ReleaseUser(userp);
6364 return CM_ERROR_ISDIR;
6367 /* now all we have to do is open the file itself */
6368 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6371 /* save a pointer to the vnode */
6374 /* always create it open for read/write */
6375 fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
6377 smb_ReleaseFID(fidp);
6379 smb_SetSMBParm(outp, 0, fidp->fid);
6380 smb_SetSMBDataLength(outp, 0);
6382 cm_Open(scp, 0, userp);
6384 cm_ReleaseUser(userp);
6385 /* leave scp held since we put it in fidp->scp */
6389 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6402 fd = smb_GetSMBParm(inp, 0);
6403 whence = smb_GetSMBParm(inp, 1);
6404 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6406 /* try to find the file descriptor */
6407 fd = smb_ChainFID(fd, inp);
6408 fidp = smb_FindFID(vcp, fd, 0);
6409 if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
6410 return CM_ERROR_BADFD;
6413 userp = smb_GetUser(vcp, inp);
6415 lock_ObtainMutex(&fidp->mx);
6417 lock_ObtainMutex(&scp->mx);
6418 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6419 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6422 /* offset from current offset */
6423 offset += fidp->offset;
6425 else if (whence == 2) {
6426 /* offset from current EOF */
6427 offset += scp->length.LowPart;
6429 fidp->offset = offset;
6430 smb_SetSMBParm(outp, 0, offset & 0xffff);
6431 smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
6432 smb_SetSMBDataLength(outp, 0);
6434 lock_ReleaseMutex(&scp->mx);
6435 lock_ReleaseMutex(&fidp->mx);
6436 smb_ReleaseFID(fidp);
6437 cm_ReleaseUser(userp);
6441 /* dispatch all of the requests received in a packet. Due to chaining, this may
6442 * be more than one request.
6444 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6445 NCB *ncbp, raw_write_cont_t *rwcp)
6449 unsigned long code = 0;
6450 unsigned char *outWctp;
6451 int nparms; /* # of bytes of parameters */
6453 int nbytes; /* bytes of data, excluding count */
6456 unsigned short errCode;
6457 unsigned long NTStatus;
6459 unsigned char errClass;
6460 unsigned int oldGen;
6461 DWORD oldTime, newTime;
6463 /* get easy pointer to the data */
6464 smbp = (smb_t *) inp->data;
6466 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
6467 /* setup the basic parms for the initial request in the packet */
6468 inp->inCom = smbp->com;
6469 inp->wctp = &smbp->wct;
6471 inp->ncb_length = ncbp->ncb_length;
6476 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
6477 /* log it and discard it */
6482 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6483 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
6485 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
6486 1, ncbp->ncb_length, ptbuf, inp);
6487 DeregisterEventSource(h);
6489 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
6494 /* We are an ongoing op */
6495 thrd_Increment(&ongoingOps);
6497 /* set up response packet for receiving output */
6498 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
6499 smb_FormatResponsePacket(vcp, inp, outp);
6500 outWctp = outp->wctp;
6502 /* Remember session generation number and time */
6503 oldGen = sessionGen;
6504 oldTime = GetCurrentTime();
6506 while (inp->inCom != 0xff) {
6507 dp = &smb_dispatchTable[inp->inCom];
6509 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
6510 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
6511 code = outp->resumeCode;
6515 /* process each request in the packet; inCom, wctp and inCount
6516 * are already set up.
6518 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
6521 /* now do the dispatch */
6522 /* start by formatting the response record a little, as a default */
6523 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
6525 outWctp[1] = 0xff; /* no operation */
6526 outWctp[2] = 0; /* padding */
6531 /* not a chained request, this is a more reasonable default */
6532 outWctp[0] = 0; /* wct of zero */
6533 outWctp[1] = 0; /* and bcc (word) of zero */
6537 /* once set, stays set. Doesn't matter, since we never chain
6538 * "no response" calls.
6540 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
6544 /* we have a recognized operation */
6546 if (inp->inCom == 0x1d)
6548 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
6551 osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp 0x%x lana %d lsn %d",(int)vcp,vcp->lana,vcp->lsn);
6552 osi_Log4(smb_logp,"Dispatch %s vcp 0x%x lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
6553 code = (*(dp->procp)) (vcp, inp, outp);
6554 osi_LogEvent("AFS Dispatch return",NULL,"Code 0x%x",(code==0)?0:code-CM_ERROR_BASE);
6555 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);
6557 if ( code == CM_ERROR_BADSMB ||
6558 code == CM_ERROR_BADOP )
6560 #endif /* LOG_PACKET */
6563 if (oldGen != sessionGen) {
6568 newTime = GetCurrentTime();
6569 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6570 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
6571 newTime - oldTime, ncbp->ncb_length);
6573 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6574 1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
6575 DeregisterEventSource(h);
6577 osi_Log1(smb_logp, "Pkt straddled session startup, "
6578 "ncb length %d", ncbp->ncb_length);
6582 /* bad opcode, fail the request, after displaying it */
6583 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
6586 #endif /* LOG_PACKET */
6590 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
6591 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
6592 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
6593 if (code == IDCANCEL)
6597 code = CM_ERROR_BADOP;
6600 /* catastrophic failure: log as much as possible */
6601 if (code == CM_ERROR_BADSMB) {
6608 "Invalid SMB, ncb_length %d",
6611 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6612 sprintf(s, "Invalid SMB message, length %d",
6615 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
6616 1, ncbp->ncb_length, ptbuf, smbp);
6617 DeregisterEventSource(h);
6620 #endif /* LOG_PACKET */
6622 osi_Log1(smb_logp, "Invalid SMB message, length %d",
6625 code = CM_ERROR_INVAL;
6628 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
6629 thrd_Decrement(&ongoingOps);
6634 /* now, if we failed, turn the current response into an empty
6635 * one, and fill in the response packet's error code.
6638 if (vcp->flags & SMB_VCFLAG_STATUS32) {
6639 smb_MapNTError(code, &NTStatus);
6640 outWctp = outp->wctp;
6641 smbp = (smb_t *) &outp->data;
6642 if (code != CM_ERROR_PARTIALWRITE
6643 && code != CM_ERROR_BUFFERTOOSMALL
6644 && code != CM_ERROR_GSSCONTINUE) {
6645 /* nuke wct and bcc. For a partial
6646 * write or an in-process authentication handshake,
6647 * assume they're OK.
6653 smbp->rcls = (unsigned char) (NTStatus & 0xff);
6654 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
6655 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
6656 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
6657 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6661 smb_MapCoreError(code, vcp, &errCode, &errClass);
6662 outWctp = outp->wctp;
6663 smbp = (smb_t *) &outp->data;
6664 if (code != CM_ERROR_PARTIALWRITE) {
6665 /* nuke wct and bcc. For a partial
6666 * write, assume they're OK.
6672 smbp->errLow = (unsigned char) (errCode & 0xff);
6673 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
6674 smbp->rcls = errClass;
6677 } /* error occurred */
6679 /* if we're here, we've finished one request. Look to see if
6680 * this is a chained opcode. If it is, setup things to process
6681 * the chained request, and setup the output buffer to hold the
6682 * chained response. Start by finding the next input record.
6684 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
6685 break; /* not a chained req */
6686 tp = inp->wctp; /* points to start of last request */
6687 /* in a chained request, the first two
6688 * parm fields are required, and are
6689 * AndXCommand/AndXReserved and
6691 if (tp[0] < 2) break;
6692 if (tp[1] == 0xff) break; /* no more chained opcodes */
6694 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
6697 /* and now append the next output request to the end of this
6698 * last request. Begin by finding out where the last response
6699 * ends, since that's where we'll put our new response.
6701 outWctp = outp->wctp; /* ptr to out parameters */
6702 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
6703 nparms = outWctp[0] << 1;
6704 tp = outWctp + nparms + 1; /* now points to bcc field */
6705 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
6706 tp += 2 /* for the count itself */ + nbytes;
6707 /* tp now points to the new output record; go back and patch the
6708 * second parameter (off2) to point to the new record.
6710 temp = (unsigned int)tp - ((unsigned int) outp->data);
6711 outWctp[3] = (unsigned char) (temp & 0xff);
6712 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
6713 outWctp[2] = 0; /* padding */
6714 outWctp[1] = inp->inCom; /* next opcode */
6716 /* finally, setup for the next iteration */
6719 } /* while loop over all requests in the packet */
6721 /* done logging out, turn off logging-out flag */
6722 if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
6723 vcp->justLoggedOut = NULL;
6726 free(loggedOutName);
6727 loggedOutName = NULL;
6728 smb_ReleaseUID(loggedOutUserp);
6729 loggedOutUserp = NULL;
6733 /* now send the output packet, and return */
6735 smb_SendPacket(vcp, outp);
6736 thrd_Decrement(&ongoingOps);
6738 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6739 if (active_vcp != vcp) {
6741 smb_ReleaseVC(active_vcp);
6743 "Replacing active_vcp %x with %x", active_vcp, vcp);
6748 last_msg_time = GetCurrentTime();
6749 } else if (active_vcp == vcp) {
6750 smb_ReleaseVC(active_vcp);
6758 /* Wait for Netbios() calls to return, and make the results available to server
6759 * threads. Note that server threads can't wait on the NCBevents array
6760 * themselves, because NCB events are manual-reset, and the servers would race
6761 * each other to reset them.
6763 void smb_ClientWaiter(void *parmp)
6768 while (smbShutdownFlag == 0) {
6769 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
6771 if (code == WAIT_OBJECT_0)
6774 /* error checking */
6775 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6777 int abandonIdx = code - WAIT_ABANDONED_0;
6778 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6781 if (code == WAIT_IO_COMPLETION)
6783 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
6787 if (code == WAIT_TIMEOUT)
6789 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
6792 if (code == WAIT_FAILED)
6794 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
6797 idx = code - WAIT_OBJECT_0;
6799 /* check idx range! */
6800 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
6802 /* this is fatal - log as much as possible */
6803 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
6807 thrd_ResetEvent(NCBevents[idx]);
6808 thrd_SetEvent(NCBreturns[0][idx]);
6814 * Try to have one NCBRECV request waiting for every live session. Not more
6815 * than one, because if there is more than one, it's hard to handle Write Raw.
6817 void smb_ServerWaiter(void *parmp)
6820 int idx_session, idx_NCB;
6826 while (smbShutdownFlag == 0) {
6828 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
6830 if (code == WAIT_OBJECT_0)
6833 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
6835 int abandonIdx = code - WAIT_ABANDONED_0;
6836 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6839 if (code == WAIT_IO_COMPLETION)
6841 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
6845 if (code == WAIT_TIMEOUT)
6847 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
6850 if (code == WAIT_FAILED)
6852 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
6855 idx_session = code - WAIT_OBJECT_0;
6857 /* check idx range! */
6858 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
6860 /* this is fatal - log as much as possible */
6861 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
6867 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
6869 if (code == WAIT_OBJECT_0) {
6870 if (smbShutdownFlag == 1)
6876 /* error checking */
6877 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6879 int abandonIdx = code - WAIT_ABANDONED_0;
6880 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
6883 if (code == WAIT_IO_COMPLETION)
6885 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
6889 if (code == WAIT_TIMEOUT)
6891 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
6894 if (code == WAIT_FAILED)
6896 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
6899 idx_NCB = code - WAIT_OBJECT_0;
6901 /* check idx range! */
6902 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
6904 /* this is fatal - log as much as possible */
6905 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6909 /* Link them together */
6910 NCBsessions[idx_NCB] = idx_session;
6913 ncbp = NCBs[idx_NCB];
6914 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
6915 ncbp->ncb_command = NCBRECV | ASYNCH;
6916 ncbp->ncb_lana_num = lanas[idx_session];
6918 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
6919 ncbp->ncb_event = NCBevents[idx_NCB];
6920 ncbp->ncb_length = SMB_PACKETSIZE;
6923 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
6924 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
6925 ncbp->ncb_event = NCBreturns[0][idx_NCB];
6926 ncbp->ncb_length = SMB_PACKETSIZE;
6927 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6928 Netbios(ncbp, dos_ncb);
6934 * The top level loop for handling SMB request messages. Each server thread
6935 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
6936 * NCB and buffer for the incoming request are loaned to us.
6938 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
6939 * to immediately send a request for the rest of the data. This must come
6940 * before any other traffic for that session, so we delay setting the session
6941 * event until that data has come in.
6943 void smb_Server(VOID *parmp)
6945 int myIdx = (int) parmp;
6949 smb_packet_t *outbufp;
6951 int idx_NCB, idx_session;
6953 smb_vc_t *vcp = NULL;
6960 outbufp = GetPacket();
6961 outbufp->ncbp = outncbp;
6964 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6967 /* terminate silently if shutdown flag is set */
6968 if (code == WAIT_OBJECT_0) {
6969 if (smbShutdownFlag == 1) {
6970 thrd_SetEvent(smb_ServerShutdown[myIdx]);
6976 /* error checking */
6977 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6979 int abandonIdx = code - WAIT_ABANDONED_0;
6980 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6983 if (code == WAIT_IO_COMPLETION)
6985 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6989 if (code == WAIT_TIMEOUT)
6991 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6994 if (code == WAIT_FAILED)
6996 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6999 idx_NCB = code - WAIT_OBJECT_0;
7001 /* check idx range! */
7002 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7004 /* this is fatal - log as much as possible */
7005 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7009 ncbp = NCBs[idx_NCB];
7011 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7013 idx_session = NCBsessions[idx_NCB];
7014 rc = ncbp->ncb_retcode;
7016 if (rc != NRC_PENDING && rc != NRC_GOODRET) {
7019 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer length", ncbp->ncb_lsn, idx_session);
7022 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal command", ncbp->ncb_lsn, idx_session);
7025 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command timed out", ncbp->ncb_lsn, idx_session);
7028 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: message incomplete, issue another command", ncbp->ncb_lsn, idx_session);
7031 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal buffer address", ncbp->ncb_lsn, idx_session);
7034 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session number out of range", ncbp->ncb_lsn, idx_session);
7037 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no resource available", ncbp->ncb_lsn, idx_session);
7040 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session closed", ncbp->ncb_lsn, idx_session);
7043 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command cancelled", ncbp->ncb_lsn, idx_session);
7046 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: duplicate name", ncbp->ncb_lsn, idx_session);
7049 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name table full", ncbp->ncb_lsn, idx_session);
7052 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no deletions, name has active lsn %d sessions", ncbp->ncb_lsn, idx_session);
7055 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: local session table full", ncbp->ncb_lsn, idx_session);
7058 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: remote session table full", ncbp->ncb_lsn, idx_session);
7061 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: illegal name number", ncbp->ncb_lsn, idx_session);
7064 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no callname", ncbp->ncb_lsn, idx_session);
7067 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: cannot put * in NCB_NAME", ncbp->ncb_lsn, idx_session);
7070 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name in use on remote adapter", ncbp->ncb_lsn, idx_session);
7073 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name deleted", ncbp->ncb_lsn, idx_session);
7076 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: session ended abnormally", ncbp->ncb_lsn, idx_session);
7079 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name conflict detected", ncbp->ncb_lsn, idx_session);
7082 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: interface busy, IRET before retrying", ncbp->ncb_lsn, idx_session);
7085 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: too many commands outstanding, retry later", ncbp->ncb_lsn, idx_session);
7088 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: ncb_lana_num field invalid", ncbp->ncb_lsn, idx_session);
7091 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command completed while cancel occurring", ncbp->ncb_lsn, idx_session);
7094 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: command not valid to cancel", ncbp->ncb_lsn, idx_session);
7097 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: name defined by anther local process", ncbp->ncb_lsn, idx_session);
7100 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: environment undefined. RESET required", ncbp->ncb_lsn, idx_session);
7103 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: required OS resources exhausted", ncbp->ncb_lsn, idx_session);
7106 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: max number of applications exceeded", ncbp->ncb_lsn, idx_session);
7109 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: no saps available for netbios", ncbp->ncb_lsn, idx_session);
7112 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: requested resources are not available", ncbp->ncb_lsn, idx_session);
7115 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid ncb address or length > segment", ncbp->ncb_lsn, idx_session);
7118 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: invalid NCB DDID", ncbp->ncb_lsn, idx_session);
7121 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: lock of user area failed", ncbp->ncb_lsn, idx_session);
7124 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: NETBIOS not loaded", ncbp->ncb_lsn, idx_session);
7127 osi_Log2(smb_logp, "NCBRECV failure lsn %d session %d: system error", ncbp->ncb_lsn, idx_session);
7130 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d code %d", ncbp->ncb_lsn, idx_session, rc);
7140 /* Can this happen? Or is it just my UNIX paranoia? */
7141 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7146 /* Client closed session */
7147 dead_sessions[idx_session] = TRUE;
7150 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7151 /* Should also release vcp. [done] 2004-05-11 jaltman
7153 * sanity check that all TID's are gone.
7155 * TODO: check if we could use LSNs[idx_session] instead,
7156 * also cleanup after dead vcp
7159 if (dead_vcp == vcp)
7160 osi_Log1(smb_logp, "dead_vcp already set, 0x%x", dead_vcp);
7161 else if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7162 osi_Log2(smb_logp, "setting dead_vcp 0x%x, user struct 0x%x",
7166 smb_ReleaseVC(dead_vcp);
7168 "Previous dead_vcp %x", dead_vcp);
7171 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7173 if (vcp->justLoggedOut) {
7175 loggedOutTime = vcp->logoffTime;
7176 loggedOutName = strdup(vcp->justLoggedOut->unp->name);
7177 loggedOutUserp = vcp->justLoggedOut;
7178 lock_ObtainWrite(&smb_rctLock);
7179 loggedOutUserp->refCount++;
7180 lock_ReleaseWrite(&smb_rctLock);
7186 /* Treat as transient error */
7193 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7194 sprintf(s, "SMB message incomplete, length %d",
7197 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
7199 ncbp->ncb_length, ptbuf,
7201 DeregisterEventSource(h);
7204 "dispatch smb recv failed, message incomplete, ncb_length %d",
7207 "SMB message incomplete, "
7208 "length %d", ncbp->ncb_length);
7211 * We used to discard the packet.
7212 * Instead, try handling it normally.
7220 /* A weird error code. Log it, sleep, and
7222 if (vcp && vcp->errorCount++ > 3) {
7223 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7224 dead_sessions[idx_session] = TRUE;
7228 thrd_SetEvent(SessionEvents[idx_session]);
7233 /* Success, so now dispatch on all the data in the packet */
7235 smb_concurrentCalls++;
7236 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7237 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7241 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
7243 * If at this point vcp is NULL (implies that packet was invalid)
7244 * then we are in big trouble. This means either :
7245 * a) we have the wrong NCB.
7246 * b) Netbios screwed up the call.
7247 * Obviously this implies that
7248 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7249 * lanas[idx_session] != ncbp->ncb_lana_num )
7250 * Either way, we can't do anything with this packet.
7251 * Log, sleep and resume.
7260 "LSNs[idx_session]=[%d],"
7261 "lanas[idx_session]=[%d],"
7262 "ncbp->ncb_lsn=[%d],"
7263 "ncbp->ncb_lana_num=[%d]",
7267 ncbp->ncb_lana_num);
7271 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7273 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
7274 DeregisterEventSource(h);
7277 /* Also log in the trace log. */
7278 osi_Log4(smb_logp, "Server: BAD VCP!"
7279 "LSNs[idx_session]=[%d],"
7280 "lanas[idx_session]=[%d],"
7281 "ncbp->ncb_lsn=[%d],"
7282 "ncbp->ncb_lana_num=[%d]",
7286 ncbp->ncb_lana_num);
7288 /* thrd_Sleep(1000); Don't bother sleeping */
7289 thrd_SetEvent(SessionEvents[idx_session]);
7290 smb_concurrentCalls--;
7295 vcp->errorCount = 0;
7296 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7298 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
7299 /* copy whole packet to virtual memory */
7300 /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
7302 bufp->dos_pkt / 16, bufp);*/
7304 dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
7306 smbp = (smb_t *)bufp->data;
7309 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
7313 if (smbp->com == 0x1d) {
7314 /* Special handling for Write Raw */
7315 raw_write_cont_t rwc;
7316 EVENT_HANDLE rwevent;
7317 char eventName[MAX_PATH];
7319 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7320 if (rwc.code == 0) {
7321 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7322 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7323 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7324 ncbp->ncb_command = NCBRECV | ASYNCH;
7325 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7326 ncbp->ncb_lana_num = vcp->lana;
7327 ncbp->ncb_buffer = rwc.buf;
7328 ncbp->ncb_length = 65535;
7329 ncbp->ncb_event = rwevent;
7333 Netbios(ncbp, dos_ncb);
7335 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7336 thrd_CloseHandle(rwevent);
7338 thrd_SetEvent(SessionEvents[idx_session]);
7340 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7342 else if (smbp->com == 0xa0) {
7344 * Serialize the handling for NT Transact
7347 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7348 thrd_SetEvent(SessionEvents[idx_session]);
7350 thrd_SetEvent(SessionEvents[idx_session]);
7351 /* TODO: what else needs to be serialized? */
7352 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7354 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7356 __except( smb_ServerExceptionFilter() ) {
7360 smb_concurrentCalls--;
7363 thrd_SetEvent(NCBavails[idx_NCB]);
7370 * Exception filter for the server threads. If an exception occurs in the
7371 * dispatch routines, which is where exceptions are most common, then do a
7372 * force trace and give control to upstream exception handlers. Useful for
7375 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
7376 DWORD smb_ServerExceptionFilter(void) {
7377 /* While this is not the best time to do a trace, if it succeeds, then
7378 * we have a trace (assuming tracing was enabled). Otherwise, this should
7379 * throw a second exception.
7384 ptbuf[0] = "Unhandled exception forcing trace";
7386 h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
7388 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
7389 DeregisterEventSource(h);
7392 afsd_ForceTrace(TRUE);
7393 buf_ForceTrace(TRUE);
7394 return EXCEPTION_CONTINUE_SEARCH;
7399 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7400 * If the number of server threads is M, and the number of live sessions is
7401 * N, then the number of NCB's in use at any time either waiting for, or
7402 * holding, received messages is M + N, so that is how many NCB's get created.
7404 void InitNCBslot(int idx)
7406 struct smb_packet *bufp;
7407 EVENT_HANDLE retHandle;
7409 char eventName[MAX_PATH];
7411 osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
7413 NCBs[idx] = GetNCB();
7414 sprintf(eventName,"NCBavails[%d]", idx);
7415 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7416 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7417 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7419 sprintf(eventName,"NCBevents[%d]", idx);
7420 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7421 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7422 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7424 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
7425 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7426 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7427 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7428 for (i=0; i<smb_NumServerThreads; i++)
7429 NCBreturns[i][idx] = retHandle;
7431 bufp->spacep = cm_GetSpace();
7435 /* listen for new connections */
7436 void smb_Listener(void *parmp)
7444 char rname[NCBNAMSZ+1];
7445 char cname[MAX_COMPUTERNAME_LENGTH+1];
7446 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
7451 int lana = (int) parmp;
7455 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7458 /* retrieve computer name */
7459 GetComputerName(cname, &cnamelen);
7463 memset(ncbp, 0, sizeof(NCB));
7466 ncbp->ncb_command = NCBLISTEN;
7467 ncbp->ncb_rto = 0; /* No receive timeout */
7468 ncbp->ncb_sto = 0; /* No send timeout */
7470 /* pad out with spaces instead of null termination */
7471 len = strlen(smb_localNamep);
7472 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
7473 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
7475 strcpy(ncbp->ncb_callname, "*");
7476 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
7478 ncbp->ncb_lana_num = lana;
7481 code = Netbios(ncbp);
7483 code = Netbios(ncbp, dos_ncb);
7492 /* terminate silently if shutdown flag is set */
7493 if (smbShutdownFlag == 1) {
7502 "NCBLISTEN lana=%d failed with code %d",
7503 ncbp->ncb_lana_num, code);
7505 "Client exiting due to network failure. Please restart client.\n");
7509 "Client exiting due to network failure. Please restart client.\n"
7510 "NCBLISTEN lana=%d failed with code %d",
7511 ncbp->ncb_lana_num, code);
7513 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
7514 MB_OK|MB_SERVICE_NOTIFICATION);
7515 osi_assert(tbuffer);
7518 fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
7519 ncbp->ncb_lana_num, code);
7520 fprintf(stderr, "\nClient exiting due to network failure "
7521 "(possibly due to power-saving mode)\n");
7522 fprintf(stderr, "Please restart client.\n");
7523 afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
7527 /* check for remote conns */
7528 /* first get remote name and insert null terminator */
7529 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
7530 for (i=NCBNAMSZ; i>0; i--) {
7531 if (rname[i-1] != ' ' && rname[i-1] != 0) {
7537 /* compare with local name */
7539 if (strncmp(rname, cname, NCBNAMSZ) != 0)
7540 flags |= SMB_VCFLAG_REMOTECONN;
7542 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
7544 lock_ObtainMutex(&smb_ListenerLock);
7546 /* New generation */
7549 /* Log session startup */
7551 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
7553 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
7554 #endif /* NOTSERVICE */
7555 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
7556 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
7558 if (reportSessionStartups) {
7564 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
7565 sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
7567 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
7569 DeregisterEventSource(h);
7572 fprintf(stderr, "%s: New session %d starting from host %s\n",
7573 asctime(localtime(&now)), ncbp->ncb_lsn, rname);
7577 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
7578 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
7581 /* now ncbp->ncb_lsn is the connection ID */
7582 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
7583 vcp->flags |= flags;
7584 strcpy(vcp->rname, rname);
7586 /* Allocate slot in session arrays */
7587 /* Re-use dead session if possible, otherwise add one more */
7588 /* But don't look at session[0], it is reserved */
7589 for (i = 1; i < numSessions; i++) {
7590 if (dead_sessions[i]) {
7591 osi_Log1(smb_logp, "connecting to dead session [ %d ]", i);
7592 dead_sessions[i] = FALSE;
7597 if (i >= Sessionmax - 1 || numNCBs >= NCBmax - 1) {
7598 unsigned long code = CM_ERROR_ALLBUSY;
7599 smb_packet_t * outp = GetPacket();
7600 unsigned char *outWctp;
7605 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7606 unsigned long NTStatus;
7607 smb_MapNTError(code, &NTStatus);
7608 outWctp = outp->wctp;
7609 smbp = (smb_t *) &outp->data;
7613 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7614 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7615 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7616 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7617 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7619 unsigned short errCode;
7620 unsigned char errClass;
7621 smb_MapCoreError(code, vcp, &errCode, &errClass);
7622 outWctp = outp->wctp;
7623 smbp = (smb_t *) &outp->data;
7627 smbp->errLow = (unsigned char) (errCode & 0xff);
7628 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7629 smbp->rcls = errClass;
7631 smb_SendPacket(vcp, outp);
7632 smb_FreePacket(outp);
7634 /* assert that we do not exceed the maximum number of sessions or NCBs.
7635 * we should probably want to wait for a session to be freed in case
7638 osi_assert(i < Sessionmax - 1);
7639 osi_assert(numNCBs < NCBmax - 1); /* if we pass this test we can allocate one more */
7641 LSNs[i] = ncbp->ncb_lsn;
7642 lanas[i] = ncbp->ncb_lana_num;
7644 if (i == numSessions) {
7645 /* Add new NCB for new session */
7646 char eventName[MAX_PATH];
7648 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
7650 InitNCBslot(numNCBs);
7652 thrd_SetEvent(NCBavails[0]);
7653 thrd_SetEvent(NCBevents[0]);
7654 for (j = 0; j < smb_NumServerThreads; j++)
7655 thrd_SetEvent(NCBreturns[j][0]);
7656 /* Also add new session event */
7657 sprintf(eventName, "SessionEvents[%d]", i);
7658 SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7659 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7660 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7662 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
7663 thrd_SetEvent(SessionEvents[0]);
7665 thrd_SetEvent(SessionEvents[i]);
7672 lock_ReleaseMutex(&smb_ListenerLock);
7673 } /* dispatch while loop */
7676 /* initialize Netbios */
7677 void smb_NetbiosInit()
7683 int i, lana, code, l;
7685 int delname_tried=0;
7688 OSVERSIONINFO Version;
7690 /* Get the version of Windows */
7691 memset(&Version, 0x00, sizeof(Version));
7692 Version.dwOSVersionInfoSize = sizeof(Version);
7693 GetVersionEx(&Version);
7695 /* setup the NCB system */
7698 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7702 if (smb_LANadapter == -1) {
7703 ncbp->ncb_command = NCBENUM;
7704 ncbp->ncb_buffer = (PUCHAR)&lana_list;
7705 ncbp->ncb_length = sizeof(lana_list);
7706 code = Netbios(ncbp);
7708 osi_Log1(smb_logp, "Netbios NCBENUM error code %d", code);
7709 osi_panic(s, __FILE__, __LINE__);
7713 lana_list.length = 1;
7714 lana_list.lana[0] = smb_LANadapter;
7717 for (i = 0; i < lana_list.length; i++) {
7718 /* reset the adaptor: in Win32, this is required for every process, and
7719 * acts as an init call, not as a real hardware reset.
7721 ncbp->ncb_command = NCBRESET;
7722 ncbp->ncb_callname[0] = 100;
7723 ncbp->ncb_callname[2] = 100;
7724 ncbp->ncb_lana_num = lana_list.lana[i];
7725 code = Netbios(ncbp);
7727 code = ncbp->ncb_retcode;
7729 osi_Log2(smb_logp, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
7730 lana_list.lana[i] = 255; /* invalid lana */
7732 osi_Log1(smb_logp, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
7736 /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset. so
7737 we will just fake the LANA list */
7738 if (smb_LANadapter == -1) {
7739 for (i = 0; i < 8; i++)
7740 lana_list.lana[i] = i;
7741 lana_list.length = 8;
7744 lana_list.length = 1;
7745 lana_list.lana[0] = smb_LANadapter;
7749 /* and declare our name so we can receive connections */
7750 memset(ncbp, 0, sizeof(*ncbp));
7751 len=lstrlen(smb_localNamep);
7752 memset(smb_sharename,' ',NCBNAMSZ);
7753 memcpy(smb_sharename,smb_localNamep,len);
7754 osi_Log1(smb_logp, "lana_list.length %d", lana_list.length);
7756 /* Keep the name so we can unregister it later */
7757 for (l = 0; l < lana_list.length; l++) {
7758 lana = lana_list.lana[l];
7760 ncbp->ncb_command = NCBADDNAME;
7761 ncbp->ncb_lana_num = lana;
7762 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7764 code = Netbios(ncbp);
7766 code = Netbios(ncbp, dos_ncb);
7769 osi_Log4(smb_logp, "Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
7770 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
7772 char name[NCBNAMSZ+1];
7774 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
7775 osi_Log1(smb_logp, "Netbios NCBADDNAME added new name >%s<",osi_LogSaveString(smb_logp, name));
7778 if (code == 0) code = ncbp->ncb_retcode;
7780 osi_Log1(smb_logp, "Netbios NCBADDNAME succeeded on lana %d\n", lana);
7782 /* we only use one LANA with djgpp */
7783 lana_list.lana[0] = lana;
7784 lana_list.length = 1;
7788 osi_Log2(smb_logp, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7789 if (code == NRC_BRIDGE) { /* invalid LANA num */
7790 lana_list.lana[l] = 255;
7793 else if (code == NRC_DUPNAME) {
7794 osi_Log0(smb_logp, "Name already exists; try to delete it");
7795 memset(ncbp, 0, sizeof(*ncbp));
7796 ncbp->ncb_command = NCBDELNAME;
7797 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7798 ncbp->ncb_lana_num = lana;
7800 code = Netbios(ncbp);
7802 code = Netbios(ncbp, dos_ncb);
7805 code = ncbp->ncb_retcode;
7807 osi_Log2(smb_logp, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
7809 if (code != 0 || delname_tried) {
7810 lana_list.lana[l] = 255;
7812 else if (code == 0) {
7813 if (!delname_tried) {
7821 osi_Log2(smb_logp, "Netbios NCBADDNAME lana %d error code %d", lana, code);
7822 lana_list.lana[l] = 255; /* invalid lana */
7823 osi_panic(s, __FILE__, __LINE__);
7827 lana_found = 1; /* at least one worked */
7834 osi_assert(lana_list.length >= 0);
7836 osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
7839 /* we're done with the NCB now */
7843 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
7860 EVENT_HANDLE retHandle;
7861 char eventName[MAX_PATH];
7864 smb_MBfunc = aMBfunc;
7868 smb_LANadapter = LANadapt;
7870 /* Initialize smb_localZero */
7871 myTime.tm_isdst = -1; /* compute whether on DST or not */
7872 myTime.tm_year = 70;
7878 smb_localZero = mktime(&myTime);
7880 #ifndef USE_NUMERIC_TIME_CONV
7881 /* Initialize kludge-GMT */
7882 smb_CalculateNowTZ();
7883 #endif /* USE_NUMERIC_TIME_CONV */
7884 #ifdef AFS_FREELANCE_CLIENT
7885 /* Make sure the root.afs volume has the correct time */
7886 cm_noteLocalMountPointChange();
7889 /* initialize the remote debugging log */
7892 /* remember the name */
7893 len = strlen(snamep);
7894 smb_localNamep = malloc(len+1);
7895 strcpy(smb_localNamep, snamep);
7896 afsi_log("smb_localNamep is >%s<", smb_localNamep);
7898 /* and the global lock */
7899 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
7900 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
7902 /* Raw I/O data structures */
7903 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
7905 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
7907 /* 4 Raw I/O buffers */
7909 smb_RawBufs = calloc(65536,1);
7910 *((char **)smb_RawBufs) = NULL;
7911 for (i=0; i<3; i++) {
7912 char *rawBuf = calloc(65536,1);
7913 *((char **)rawBuf) = smb_RawBufs;
7914 smb_RawBufs = rawBuf;
7917 npar = 65536 >> 4; /* number of paragraphs */
7918 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
7920 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7922 osi_panic("",__FILE__,__LINE__);
7925 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7928 smb_RawBufs = (seg * 16) + 0; /* DOS physical address */
7930 _farpokel(_dos_ds, smb_RawBufs, NULL);
7931 for (i=0; i<SMB_RAW_BUFS-1; i++) {
7932 npar = 65536 >> 4; /* number of paragraphs */
7933 seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
7935 afsi_log("Cannot allocate %d paragraphs of DOS memory",
7937 osi_panic("",__FILE__,__LINE__);
7940 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
7943 rawBuf = (seg * 16) + 0; /* DOS physical address */
7944 /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
7945 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
7946 smb_RawBufs = rawBuf;
7950 /* global free lists */
7951 smb_ncbFreeListp = NULL;
7952 smb_packetFreeListp = NULL;
7956 /* Initialize listener and server structures */
7958 memset(dead_sessions, 0, sizeof(dead_sessions));
7959 sprintf(eventName, "SessionEvents[0]");
7960 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7961 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7962 afsi_log("Event Object Already Exists: %s", eventName);
7964 smb_NumServerThreads = nThreads;
7965 sprintf(eventName, "NCBavails[0]");
7966 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7967 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7968 afsi_log("Event Object Already Exists: %s", eventName);
7969 sprintf(eventName, "NCBevents[0]");
7970 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7971 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7972 afsi_log("Event Object Already Exists: %s", eventName);
7973 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
7974 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
7975 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7976 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7977 afsi_log("Event Object Already Exists: %s", eventName);
7978 for (i = 0; i < smb_NumServerThreads; i++) {
7979 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
7980 NCBreturns[i][0] = retHandle;
7983 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
7984 for (i = 0; i < smb_NumServerThreads; i++) {
7985 sprintf(eventName, "smb_ServerShutdown[%d]", i);
7986 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
7987 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7988 afsi_log("Event Object Already Exists: %s", eventName);
7991 numNCBs = smb_NumServerThreads + 1;
7993 /* Initialize dispatch table */
7994 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
7995 /* Prepare the table for unknown operations */
7996 for(i=0; i<= SMB_NOPCODES; i++) {
7997 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
7999 /* Fill in the ones we do know */
8000 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8001 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8002 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8003 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8004 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8005 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8006 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8007 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8008 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8009 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8010 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8011 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8012 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8013 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8014 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8015 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8016 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8017 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8018 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8019 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8020 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8021 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8022 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8023 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8024 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8025 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8026 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8027 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8028 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8029 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8030 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8031 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8032 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8033 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8034 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8035 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8036 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8037 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8038 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8039 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8040 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8041 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8042 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8043 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8044 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8045 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8046 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8047 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8048 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8049 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8050 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8051 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8052 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8053 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8054 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8055 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8056 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8057 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8058 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8059 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8060 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8061 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8062 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8063 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8064 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8065 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8066 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8067 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8068 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8069 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8070 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8071 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8073 /* setup tran 2 dispatch table */
8074 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8075 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8076 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8077 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8078 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8079 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8080 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8081 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8082 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8083 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8084 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8085 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8086 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8087 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8088 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8089 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8090 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8092 /* setup the rap dispatch table */
8093 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8094 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8095 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8096 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8097 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8101 /* if we are doing SMB authentication we have register outselves as a logon process */
8102 if (smb_authType != SMB_AUTH_NONE) {
8103 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8104 LSA_STRING afsProcessName;
8105 LSA_OPERATIONAL_MODE dummy; /*junk*/
8107 afsProcessName.Buffer = "OpenAFSClientDaemon";
8108 afsProcessName.Length = strlen(afsProcessName.Buffer);
8109 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8111 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8113 if (nts == STATUS_SUCCESS) {
8114 LSA_STRING packageName;
8115 /* we are registered. Find out the security package id */
8116 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8117 packageName.Length = strlen(packageName.Buffer);
8118 packageName.MaximumLength = packageName.Length + 1;
8119 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8120 if (nts == STATUS_SUCCESS) {
8122 * This code forces Windows to authenticate against the Logon Cache
8123 * first instead of attempting to authenticate against the Domain
8124 * Controller. When the Windows logon cache is enabled this improves
8125 * performance by removing the network access and works around a bug
8126 * seen at sites which are using a MIT Kerberos principal to login
8127 * to machines joined to a non-root domain in a multi-domain forest.
8129 PVOID pResponse = NULL;
8130 ULONG cbResponse = 0;
8131 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8133 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8134 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8135 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8136 OptionsRequest.DisableOptions = FALSE;
8138 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8141 sizeof(OptionsRequest),
8147 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8149 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8151 OutputDebugString(message);
8152 osi_Log2(smb_logp,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8155 OutputDebugString("MsV1_0SetProcessOption success");
8156 osi_Log0(smb_logp,"MsV1_0SetProcessOption success");
8158 /* END - code from Larry */
8160 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8161 smb_lsaLogonOrigin.Length = strlen(smb_lsaLogonOrigin.Buffer);
8162 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8164 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%l]",nts);
8166 /* something went wrong. We report the error and revert back to no authentication
8167 because we can't perform any auth requests without a successful lsa handle
8168 or sec package id. */
8169 afsi_log("Reverting to NO SMB AUTH");
8170 smb_authType = SMB_AUTH_NONE;
8173 afsi_log("Can't register logon process!! NTSTATUS=[%l]",nts);
8175 /* something went wrong. We report the error and revert back to no authentication
8176 because we can't perform any auth requests without a successful lsa handle
8177 or sec package id. */
8178 afsi_log("Reverting to NO SMB AUTH");
8179 smb_authType = SMB_AUTH_NONE;
8183 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8184 * time prevents the failure of authentication when logged into Windows with an
8185 * external Kerberos principal mapped to a local account.
8187 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8188 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8189 * then the only option is NTLMSSP anyway; so just fallback.
8194 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8195 if (secBlobLength == 0) {
8196 smb_authType = SMB_AUTH_NTLM;
8197 afsi_log("Reverting to SMB AUTH NTLM");
8206 /* Now get ourselves a domain name. */
8207 /* For now we are using the local computer name as the domain name.
8208 * It is actually the domain for local logins, and we are acting as
8209 * a local SMB server.
8211 bufsize = sizeof(smb_ServerDomainName) - 1;
8212 GetComputerName(smb_ServerDomainName, &bufsize);
8213 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8214 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8217 /* Start listeners, waiters, servers, and daemons */
8219 for (i = 0; i < lana_list.length; i++) {
8220 if (lana_list.lana[i] == 255)
8222 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8223 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8224 osi_assert(phandle != NULL);
8225 thrd_CloseHandle(phandle);
8229 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8230 NULL, 0, &lpid, "smb_ClientWaiter");
8231 osi_assert(phandle != NULL);
8232 thrd_CloseHandle(phandle);
8235 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8236 NULL, 0, &lpid, "smb_ServerWaiter");
8237 osi_assert(phandle != NULL);
8238 thrd_CloseHandle(phandle);
8240 for (i=0; i<smb_NumServerThreads; i++) {
8241 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8242 (void *) i, 0, &lpid, "smb_Server");
8243 osi_assert(phandle != NULL);
8244 thrd_CloseHandle(phandle);
8247 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8248 NULL, 0, &lpid, "smb_Daemon");
8249 osi_assert(phandle != NULL);
8250 thrd_CloseHandle(phandle);
8252 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8253 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8254 osi_assert(phandle != NULL);
8255 thrd_CloseHandle(phandle);
8264 void smb_Shutdown(void)
8274 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8276 /* setup the NCB system */
8279 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
8282 /* Block new sessions by setting shutdown flag */
8283 smbShutdownFlag = 1;
8285 /* Hang up all sessions */
8286 memset((char *)ncbp, 0, sizeof(NCB));
8287 for (i = 1; i < numSessions; i++)
8289 if (dead_sessions[i])
8292 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8293 ncbp->ncb_command = NCBHANGUP;
8294 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8295 ncbp->ncb_lsn = LSNs[i];
8297 code = Netbios(ncbp);
8299 code = Netbios(ncbp, dos_ncb);
8301 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8302 if (code == 0) code = ncbp->ncb_retcode;
8304 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8305 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8309 /* Trigger the shutdown of all SMB threads */
8310 for (i = 0; i < smb_NumServerThreads; i++)
8311 thrd_SetEvent(NCBreturns[i][0]);
8313 thrd_SetEvent(NCBevents[0]);
8314 thrd_SetEvent(SessionEvents[0]);
8315 thrd_SetEvent(NCBavails[0]);
8317 for (i = 0;i < smb_NumServerThreads; i++) {
8318 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8319 if (code == WAIT_OBJECT_0) {
8322 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8323 thrd_SetEvent(NCBreturns[i--][0]);
8327 /* Delete Netbios name */
8328 memset((char *)ncbp, 0, sizeof(NCB));
8329 for (i = 0; i < lana_list.length; i++) {
8330 if (lana_list.lana[i] == 255) continue;
8331 ncbp->ncb_command = NCBDELNAME;
8332 ncbp->ncb_lana_num = lana_list.lana[i];
8333 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8335 code = Netbios(ncbp);
8337 code = Netbios(ncbp, dos_ncb);
8340 code = ncbp->ncb_retcode;
8342 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8343 ncbp->ncb_lana_num, code);
8348 /* Release the reference counts held by the VCs */
8349 lock_ObtainWrite(&smb_rctLock);
8350 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8355 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8357 if (fidp->scp != NULL) {
8360 lock_ObtainMutex(&fidp->mx);
8361 if (fidp->scp != NULL) {
8364 cm_ReleaseSCache(scp);
8366 lock_ReleaseMutex(&fidp->mx);
8370 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
8372 smb_ReleaseVCNoLock(tidp->vcp);
8374 cm_user_t *userp = tidp->userp;
8376 lock_ReleaseWrite(&smb_rctLock);
8377 cm_ReleaseUser(userp);
8378 lock_ObtainWrite(&smb_rctLock);
8382 lock_ReleaseWrite(&smb_rctLock);
8385 /* Get the UNC \\<servername>\<sharename> prefix. */
8386 char *smb_GetSharename()
8390 /* Make sure we have been properly initialized. */
8391 if (smb_localNamep == NULL)
8394 /* Allocate space for \\<servername>\<sharename>, plus the
8397 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
8398 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
8404 void smb_LogPacket(smb_packet_t *packet)
8407 unsigned length, paramlen, datalen, i, j;
8409 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
8411 if (!packet) return;
8413 osi_Log0(smb_logp, "*** SMB packet dump ***");
8415 vp = (BYTE *) packet->data;
8417 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
8418 length = paramlen + 2 + datalen;
8421 for (i=0;i < length; i+=16)
8423 memset( buf, ' ', 80 );
8428 buf[strlen(buf)] = ' ';
8430 cp = (BYTE*) buf + 7;
8432 for (j=0;j < 16 && (i+j)<length; j++)
8434 *(cp++) = hex[vp[i+j] >> 4];
8435 *(cp++) = hex[vp[i+j] & 0xf];
8445 for (j=0;j < 16 && (i+j)<length;j++)
8447 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
8458 osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
8461 osi_Log0(smb_logp, "*** End SMB packet dump ***");
8463 #endif /* LOG_PACKET */
8466 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
8474 lock_ObtainRead(&smb_rctLock);
8476 sprintf(output, "begin dumping smb_vc_t\n");
8477 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8479 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8483 sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
8484 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
8485 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8487 sprintf(output, "begin dumping smb_fid_t\n");
8488 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8490 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8492 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",
8493 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
8494 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
8495 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
8496 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8499 sprintf(output, "done dumping smb_fid_t\n");
8500 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8503 sprintf(output, "done dumping smb_vc_t\n");
8504 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
8507 lock_ReleaseRead(&smb_rctLock);